From a0b5ebccb814cbb12c5f40aa0c8894ebb3b322d6 Mon Sep 17 00:00:00 2001 From: Likitha Shetty Date: Thu, 11 Apr 2013 04:25:31 +0530 Subject: [PATCH 001/107] CLOUDSTACK-1988. Attempting to register a AWS API user fails with error code 401. Fix the code to refer to /usr/share/cloudstack-management/webapps7080/awsapi/WEB-INF/classes. --- awsapi/src/com/cloud/bridge/service/EC2RestServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java index 29a002cebaf..630e16fb5f3 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java @@ -209,7 +209,7 @@ public class EC2RestServlet extends HttpServlet { if (installedPath == null) installedPath = System.getProperty("catalina.home"); String webappPath = config.getServletContext().getRealPath("/"); //pathToKeystore = new String( installedPath + File.separator + "webapps" + File.separator + webappName + File.separator + "WEB-INF" + File.separator + "classes" + File.separator + keystore ); - pathToKeystore = new String( webappPath + File.separator + "\\WEB-INF" + File.separator + "classes" + File.separator + keystore ); + pathToKeystore = new String( webappPath + File.separator + "WEB-INF" + File.separator + "classes" + File.separator + keystore ); } } From 5cd3608529cd630a102345c1b49930e5844ccf4e Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 10 Apr 2013 16:50:42 +0200 Subject: [PATCH 002/107] 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 003/107] 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 004/107] 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 005/107] 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 006/107] 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 007/107] 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 008/107] 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 009/107] 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 010/107] 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 011/107] 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 012/107] 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 013/107] 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 014/107] 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 015/107] 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 016/107] 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 017/107] 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 018/107] 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 019/107] 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 020/107] 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 021/107] 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 022/107] 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 023/107] 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 024/107] 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 025/107] 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 026/107] 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 027/107] 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 028/107] 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 029/107] 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 030/107] 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 031/107] 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 032/107] 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 037/107] 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 038/107] 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 039/107] 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 040/107] 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 041/107] 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 042/107] 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 043/107] 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 044/107] 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 045/107] 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 046/107] 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; } }); From 69f49e76cf7315852caf9b8515cb457fef9f3852 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 14:50:14 -0700 Subject: [PATCH 047/107] Excluding this unit test for a while, since it fails because ComponentContext.initComponentsLifeCycle(); is failing when DB is unavailable --- .../affinity/AffinityApiUnitTest.java | 149 +++++++++--------- 1 file changed, 77 insertions(+), 72 deletions(-) diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java index 86cf0174579..ee241deb704 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java @@ -75,6 +75,9 @@ public class AffinityApiUnitTest { @Inject AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + AffinityGroupDao _affinityGroupDao; + @Inject EventUtils _eventUtils; @@ -91,84 +94,86 @@ public class AffinityApiUnitTest { @Before public void testSetUp() { - ComponentContext.initComponentsLifeCycle(); - 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"); - when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct); + // ComponentContext.initComponentsLifeCycle(); + /* + * 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"); + * when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct); + */ } @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); + /* + * 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); - } + /* + * @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); } + */ } From 4600bd4b99a73b5344d789b9e3db212a42422443 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 11 Apr 2013 15:26:37 -0700 Subject: [PATCH 048/107] CLOUDSTACK-1910: cloudstack UI - Regions menu - make Add/Delete/Edit Region action not available to regular-user/domain-admin. --- ui/scripts/regions.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 10057a62a4a..ec5e21b7d4c 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -55,6 +55,12 @@ actions: { add: { label: 'label.add.region', + preFilter: function(args) { + if(isAdmin()) + return true; + else + return false; + }, messages: { notification: function() { return 'label.add.region'; } }, @@ -98,10 +104,9 @@ $.ajax({ url: createURL('listRegions&listAll=true'), success: function(json) { - var regions = json.listregionsresponse.region - - args.response.success({ - data: regions ? regions : [] + var items = json.listregionsresponse.region; + args.response.success({ + data: items }); }, error: function(json) { @@ -193,6 +198,7 @@ var region = json.listregionsresponse.region args.response.success({ + actionFilter: regionActionfilter, data: region ? region[0] : {} }); }, @@ -382,4 +388,14 @@ } } }; + + var regionActionfilter = function(args) { + var allowedActions = []; + if(isAdmin()) { + allowedActions.push("edit"); + allowedActions.push("remove"); + } + return allowedActions; + } + })(cloudStack); From 4958070b90bc153d55d0201776a4d1c4579dc707 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 15:43:12 -0700 Subject: [PATCH 049/107] Reopening CLOUDSTACK-1884. Adding back the unit test, but still excluded due to component loading issue. --- server/pom.xml | 1 + .../affinity/AffinityApiUnitTest.java | 154 +++++++++--------- 2 files changed, 81 insertions(+), 74 deletions(-) diff --git a/server/pom.xml b/server/pom.xml index a3971954475..a4f315b4fa3 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -160,6 +160,7 @@ com/cloud/network/security/SecurityGroupManagerImpl2Test.java org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java + org/apache/cloudstack/affinity/AffinityApiUnitTest.java diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java index ee241deb704..a044611cc65 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java @@ -31,6 +31,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -94,86 +95,91 @@ public class AffinityApiUnitTest { @Before public void testSetUp() { - // ComponentContext.initComponentsLifeCycle(); - /* - * 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"); - * when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct); - */ + ComponentContext.initComponentsLifeCycle(); + 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"); + when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct); + + AffinityGroupVO group = new AffinityGroupVO("group1", "mock", "mock group", domainId, 200L); + Mockito.when(_affinityGroupDao.persist(Mockito.any(AffinityGroupVO.class))).thenReturn(group); + Mockito.when(_affinityGroupDao.findById(Mockito.anyLong())).thenReturn(group); + Mockito.when(_affinityGroupDao.findByAccountAndName(Mockito.anyLong(), Mockito.anyString())).thenReturn(group); + Mockito.when(_affinityGroupDao.lockRow(Mockito.anyLong(), anyBoolean())).thenReturn(group); + Mockito.when(_affinityGroupDao.expunge(Mockito.anyLong())).thenReturn(true); } @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); - */ + 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); } - */ + @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); + } } From 370a7fdfd66cefbd38c3bc8f2844d4f889bfee51 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Thu, 11 Apr 2013 17:23:49 -0700 Subject: [PATCH 050/107] CLOUDSTACK-1884: fix the unit test issue --- server/pom.xml | 3 --- .../affinity/AffinityApiTestConfiguration.java | 18 +++++++++++++++--- .../affinity/AffinityApiUnitTest.java | 10 ++++++---- .../ChildTestConfiguration.java | 7 ++++++- .../CreateNetworkOfferingTest.java | 1 - 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/server/pom.xml b/server/pom.xml index a4f315b4fa3..ca56851ec15 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -158,9 +158,6 @@ com/cloud/network/vpn/RemoteAccessVpnTest.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java - - org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java - org/apache/cloudstack/affinity/AffinityApiUnitTest.java diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java index c6a0755744c..fb294697cc6 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java @@ -42,6 +42,7 @@ 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.DataCenterLinkLocalIpAddressDao; import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDaoImpl; import com.cloud.dc.dao.DataCenterVnetDaoImpl; import com.cloud.dc.dao.DcDetailsDaoImpl; @@ -51,6 +52,7 @@ 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.EventDao; import com.cloud.event.dao.EventDaoImpl; import com.cloud.event.dao.UsageEventDaoImpl; import com.cloud.host.dao.HostDaoImpl; @@ -122,15 +124,15 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; 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, + DataCenterDaoImpl.class, DataCenterIpAddressDaoImpl.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, EventUtils.class, UserVmVO.class, - EventDaoImpl.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) + ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class + }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) public class AffinityApiTestConfiguration { @Bean @@ -308,6 +310,11 @@ public class AffinityApiTestConfiguration { public NetworkOfferingDao networkOfferingDao() { return Mockito.mock(NetworkOfferingDao.class); } + + @Bean + public EventDao eventDao() { + return Mockito.mock(EventDao.class); + } @Bean public NetworkDao networkDao() { @@ -319,6 +326,11 @@ public class AffinityApiTestConfiguration { return Mockito.mock(NetworkOfferingServiceMapDao.class); } + @Bean + public DataCenterLinkLocalIpAddressDao datacenterLinkLocalIpAddressDao() { + return Mockito.mock(DataCenterLinkLocalIpAddressDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java index a044611cc65..a5e6d15bf0b 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java @@ -21,9 +21,7 @@ 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; @@ -36,15 +34,15 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.cloud.event.EventUtils; +import com.cloud.event.EventVO; +import com.cloud.event.dao.EventDao; 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.user.dao.AccountDao; import com.cloud.utils.component.ComponentContext; import com.cloud.vm.UserVmVO; @@ -84,6 +82,9 @@ public class AffinityApiUnitTest { @Inject AccountDao _accountDao; + + @Inject + EventDao _eventDao; private static long domainId = 5L; @@ -113,6 +114,7 @@ public class AffinityApiUnitTest { Mockito.when(_affinityGroupDao.findByAccountAndName(Mockito.anyLong(), Mockito.anyString())).thenReturn(group); Mockito.when(_affinityGroupDao.lockRow(Mockito.anyLong(), anyBoolean())).thenReturn(group); Mockito.when(_affinityGroupDao.expunge(Mockito.anyLong())).thenReturn(true); + Mockito.when(_eventDao.persist(Mockito.any(EventVO.class))).thenReturn(new EventVO()); } @Test diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index 895a5d4416d..f1163ef35ee 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -41,6 +41,7 @@ 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.DataCenterLinkLocalIpAddressDao; import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDaoImpl; import com.cloud.dc.dao.DataCenterVnetDaoImpl; import com.cloud.dc.dao.DcDetailsDaoImpl; @@ -135,7 +136,6 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; DiskOfferingDaoImpl.class, DataCenterDaoImpl.class, DataCenterIpAddressDaoImpl.class, - DataCenterLinkLocalIpAddressDaoImpl.class, DataCenterVnetDaoImpl.class, PodVlanDaoImpl.class, DcDetailsDaoImpl.class, @@ -319,6 +319,11 @@ public class ChildTestConfiguration { return Mockito.mock(NetworkOfferingServiceMapDao.class); } + @Bean + public DataCenterLinkLocalIpAddressDao datacenterLinkLocalIpAddressDao() { + return Mockito.mock(DataCenterLinkLocalIpAddressDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 67fae3349c1..cbb6c00e397 100644 --- a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -49,7 +49,6 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; -import com.cloud.user.UserContextInitializer; import com.cloud.user.UserVO; import com.cloud.utils.component.ComponentContext; From c1a85401ae6f7387341c529f829fe5578a15ec5a Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 11 Apr 2013 17:18:24 -0700 Subject: [PATCH 051/107] Single AffinityGroupProcessor could process multiple groups of same type. --- .../affinity/HostAntiAffinityProcessor.java | 50 ++++++++++--------- .../affinity/dao/AffinityGroupVMMapDao.java | 2 +- .../dao/AffinityGroupVMMapDaoImpl.java | 4 +- 3 files changed, 29 insertions(+), 27 deletions(-) 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 430cf92659d..4c2c7f1c131 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 @@ -52,35 +52,37 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements ExcludeList avoid) throws AffinityConflictException { VirtualMachine vm = vmProfile.getVirtualMachine(); - AffinityGroupVMMapVO vmGroupMapping = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType()); + List vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType()); - if (vmGroupMapping != null) { - AffinityGroupVO group = _affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId()); + for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) { + 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()); - } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Processing affinity group " + group.getName() + " for VM Id: " + vm.getId()); + } - List groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId()); - groupVMIds.remove(vm.getId()); + List groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId()); + groupVMIds.remove(vm.getId()); + + for (Long groupVMId : groupVMIds) { + VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId); + if (groupVM != null && !groupVM.isRemoved()) { + if (groupVM.getHostId() != null) { + avoid.addHost(groupVM.getHostId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Added host " + groupVM.getHostId() + " to avoid set, since VM " + + groupVM.getId() + " is present on the host"); + } + } else if (VirtualMachine.State.Stopped.equals(groupVM.getState()) + && groupVM.getLastHostId() != null) { + avoid.addHost(groupVM.getLastHostId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Added host " + groupVM.getLastHostId() + " to avoid set, since VM " + + groupVM.getId() + " is present on the host, in Stopped state"); + } - for (Long groupVMId : groupVMIds) { - VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId); - if (groupVM != null && !groupVM.isRemoved()) { - if (groupVM.getHostId() != null) { - avoid.addHost(groupVM.getHostId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Added host " + groupVM.getHostId() + " to avoid set, since VM " - + groupVM.getId() + " is present on the host"); } - } else if (VirtualMachine.State.Stopped.equals(groupVM.getState()) - && groupVM.getLastHostId() != null) { - avoid.addHost(groupVM.getLastHostId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Added host " + groupVM.getLastHostId() + " to avoid set, since VM " - + groupVM.getId() + " is present on the host, in Stopped state"); - } - } } } diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java index a98ae0ff7bd..f2951bc8d91 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java @@ -41,7 +41,7 @@ public interface AffinityGroupVMMapDao extends GenericDao findByVmIdType(long instanceId, String type); void updateMap(Long vmId, List affinityGroupIds); } diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java index abc2a2bd59c..e03e73c6320 100644 --- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java +++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java @@ -140,11 +140,11 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase findByVmIdType(long instanceId, String type) { SearchCriteria sc = ListByVmIdType.create(); sc.setParameters("instanceId", instanceId); sc.setJoinParameters("groupSearch", "type", type); - return findOneBy(sc); + return listBy(sc); } @Override From 7fb63be6e1c2ed2b6d2de02dae3ec0f77f1748f3 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Wed, 10 Apr 2013 14:07:42 +0530 Subject: [PATCH 052/107] CLOUDSTACK-1993: fixed the issue of not sending syslog messages for alertType 0 Signed-off-by: Anshul Gangwar Signed-off-by: Sateesh Chodapuneedi --- .../org/apache/cloudstack/syslog/AlertsSyslogAppender.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java b/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java index d2f25654c7a..09563da2264 100644 --- a/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java +++ b/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java @@ -217,7 +217,7 @@ public class AlertsSyslogAppender extends AppenderSkeleton { message.append("unknown" + MESSAGE_DELIMITER_STRING); } - if (alertType > 0) { + if (alertType >= 0) { message.append("alertType").append(_keyValueDelimiter).append(" ").append(alertsMap.get(alertType)) .append(MESSAGE_DELIMITER_STRING); if (dataCenterId != 0) { @@ -333,4 +333,4 @@ public class AlertsSyslogAppender extends AppenderSkeleton { public void setKeyValueDelimiter(String keyValueDelimiter) { this._keyValueDelimiter = keyValueDelimiter; } -} \ No newline at end of file +} From cbcb83b086f4a87aa0703e18a03938b808ed044f Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Fri, 12 Apr 2013 14:57:56 +0800 Subject: [PATCH 053/107] fix CLOUDSTACK-1894 User is not able to deploy VMs in a project[permission denied to access the guest network) --- .../com/cloud/network/NetworkModelImpl.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) mode change 100644 => 100755 server/src/com/cloud/network/NetworkModelImpl.java diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java old mode 100644 new mode 100755 index 4c13c9179a0..b82f90c92dd --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -88,7 +88,9 @@ import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.projects.dao.ProjectAccountDao; import com.cloud.user.Account; +import com.cloud.user.AccountVO; import com.cloud.user.DomainManager; import com.cloud.user.dao.AccountDao; import com.cloud.utils.component.AdapterBase; @@ -178,7 +180,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { UserIpv6AddressDao _ipv6Dao; @Inject NicSecondaryIpDao _nicSecondaryIpDao;; - + @Inject + private ProjectAccountDao _projectAccountDao; private final HashMap _systemNetworks = new HashMap(5); static Long _privateOfferingId = null; @@ -1472,10 +1475,20 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { public void checkNetworkPermissions(Account owner, Network network) { // Perform account permission check if (network.getGuestType() != Network.GuestType.Shared) { - List networkMap = _networksDao.listBy(owner.getId(), network.getId()); - if (networkMap == null || networkMap.isEmpty()) { - throw new PermissionDeniedException("Unable to use network with id= " + network.getUuid() + ", permission denied"); + AccountVO networkOwner = _accountDao.findById(network.getAccountId()); + if(networkOwner == null) + throw new PermissionDeniedException("Unable to use network with id= " + network.getId() + ", network does not have an owner"); + if(owner.getType() != Account.ACCOUNT_TYPE_PROJECT && networkOwner.getType() == Account.ACCOUNT_TYPE_PROJECT){ + if(!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), network.getAccountId())){ + throw new PermissionDeniedException("Unable to use network with id= " + network.getId() + ", permission denied"); + } + }else{ + List networkMap = _networksDao.listBy(owner.getId(), network.getId()); + if (networkMap == null || networkMap.isEmpty()) { + throw new PermissionDeniedException("Unable to use network with id= " + network.getId() + ", permission denied"); + } } + } else { if (!isNetworkAvailableInDomain(network.getId(), owner.getDomainId())) { throw new PermissionDeniedException("Shared network id=" + network.getUuid() + " is not available in domain id=" + owner.getDomainId()); From 580731ccc0b03b54dde544ead30ae44eebc8f2f5 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Tue, 9 Apr 2013 10:27:05 +0530 Subject: [PATCH 054/107] CLOUDSTACK-1534 Disable/Enable-unmanaged/manage cluster is setting CPU overcommit and memory overcommit ratio to 1 (defalut value). Signed-off-by: Abhinandan Prateek --- .../admin/cluster/UpdateClusterCmd.java | 15 +++++++++---- .../cloud/resource/ResourceManagerImpl.java | 22 +++++-------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java index 95728dd184d..c5130587ec5 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java @@ -111,14 +111,14 @@ public class UpdateClusterCmd extends BaseCmd { if(cpuovercommitratio != null){ return Float.parseFloat(cpuovercommitratio); } - return 1.0f; + return null; } public Float getMemoryOvercommitRaito (){ if (memoryovercommitratio != null){ return Float.parseFloat(memoryovercommitratio); } - return 1.0f; + return null; } @Override @@ -127,9 +127,16 @@ public class UpdateClusterCmd extends BaseCmd { if (cluster == null) { throw new InvalidParameterValueException("Unable to find the cluster by id=" + getId()); } + if (getMemoryOvercommitRaito() !=null){ + if ((getMemoryOvercommitRaito().compareTo(1f) < 0)) { + throw new InvalidParameterValueException("Memory overcommit ratio should be greater than or equal to one"); + } + } - if ((getMemoryOvercommitRaito().compareTo(1f) < 0) | (getCpuOvercommitRatio().compareTo(1f) < 0)) { - throw new InvalidParameterValueException("Cpu and ram overcommit ratios should be greater than one"); + if (getCpuOvercommitRatio() !=null){ + if (getCpuOvercommitRatio().compareTo(1f) < 0) { + throw new InvalidParameterValueException("Cpu overcommit ratio should be greater than or equal to one"); + } } Cluster result = _resourceService.updateCluster(cluster, getClusterType(), getHypervisor(), getAllocationState(), getManagedstate(), getMemoryOvercommitRaito(), getCpuOvercommitRatio()); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 82bca5194bf..c9c3f9c3722 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -1181,29 +1181,17 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } - ClusterDetailsVO memory_detail = _clusterDetailsDao.findDetail(cluster.getId(),"memoryOvercommitRatio"); - if( memory_detail == null){ - if (memoryovercommitratio.compareTo(1f) > 0){ - memory_detail = new ClusterDetailsVO(cluster.getId(),"memoryOvercommitRatio",Float.toString(memoryovercommitratio)); - _clusterDetailsDao.persist(memory_detail); - } - } - else { + if (memoryovercommitratio != null) { + ClusterDetailsVO memory_detail = _clusterDetailsDao.findDetail(cluster.getId(),"memoryOvercommitRatio"); memory_detail.setValue(Float.toString(memoryovercommitratio)); _clusterDetailsDao.update(memory_detail.getId(),memory_detail); } - ClusterDetailsVO cpu_detail = _clusterDetailsDao.findDetail(cluster.getId(),"cpuOvercommitRatio"); - if( cpu_detail == null){ - if (cpuovercommitratio.compareTo(1f) > 0){ - cpu_detail = new ClusterDetailsVO(cluster.getId(),"cpuOvercommitRatio",Float.toString(cpuovercommitratio)); - _clusterDetailsDao.persist(cpu_detail); - } - } - else { + if (cpuovercommitratio != null) { + ClusterDetailsVO cpu_detail = _clusterDetailsDao.findDetail(cluster.getId(),"cpuOvercommitRatio"); cpu_detail.setValue(Float.toString(cpuovercommitratio)); _clusterDetailsDao.update(cpu_detail.getId(),cpu_detail); - } + } if (doUpdate) { From 4ae3e5de7f98147abf6f72f7b102c56125071035 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Fri, 12 Apr 2013 16:31:34 +0530 Subject: [PATCH 055/107] scalevm test: adjust the tags to suit the environment scalevm works with the xenserver hypervisortype only. Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_ScaleVm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/smoke/test_ScaleVm.py b/test/integration/smoke/test_ScaleVm.py index 710d2add7b6..64fe4dc9aa4 100644 --- a/test/integration/smoke/test_ScaleVm.py +++ b/test/integration/smoke/test_ScaleVm.py @@ -91,7 +91,7 @@ class Services: "sleep": 60, "timeout": 10, #Migrate VM to hostid - "ostype": 'CentOS 5.6 (64-bit)', + "ostype": 'CentOS 5.3 (64-bit)', # CentOS 5.3 (64-bit) } @@ -164,7 +164,7 @@ class TestScaleVm(cloudstackTestCase): cleanup_resources(self.apiclient, self.cleanup) return - @attr(tags = ["advanced", "basic", "multicluster", "storagemotion", "xenserver"]) + @attr(tags = ["xenserver", "advanced", "basic"]) def test_01_scale_vm(self): """Test scale virtual machine """ From c0419791ede331fff7151a5cee9a358c0400c272 Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Fri, 12 Apr 2013 16:44:03 +0530 Subject: [PATCH 056/107] CLOUDSTACK-1934: NPE with listSupportedNetworkServices For 'connectivity' network service current set of providers (MidoNet, NiciraNcp) not necessarily part of OSS builds. So handle the case where there are no providers for a service --- server/src/com/cloud/network/NetworkModelImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index b82f90c92dd..c5930d9315c 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -1013,7 +1013,10 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { Set supportedProviders = new HashSet(); if (service != null) { - supportedProviders.addAll(s_serviceToImplementedProvidersMap.get(service)); + List providers = s_serviceToImplementedProvidersMap.get(service); + if (providers != null && !providers.isEmpty()) { + supportedProviders.addAll(providers); + } } else { for (List pList : s_serviceToImplementedProvidersMap.values()) { supportedProviders.addAll(pList); From accfccd83e11d0b12eccebde940c705e49eec913 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Fri, 12 Apr 2013 12:54:57 +0200 Subject: [PATCH 057/107] Summary: Add support for nested hypervisors to the VmWare resource. Add a flag VmDetailConstants.NESTED_VIRTUALIZATION_FLAG Add an advanced config uption VmwareEnableNestedVirtualization Depending on the settings of the flags and the capabilities of the target hypervisor the nested virtualization option will be set on guest VMs. It's a global setting intended only for developers to support cloud-in-a-cloud deployments. --- core/src/com/cloud/vm/VmDetailConstants.java | 1 + .../com/cloud/hypervisor/guru/VMwareGuru.java | 19 ++++++++++++++++++- .../vmware/resource/VmwareResource.java | 18 ++++++++++++++++++ .../src/com/cloud/configuration/Config.java | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/core/src/com/cloud/vm/VmDetailConstants.java b/core/src/com/cloud/vm/VmDetailConstants.java index 90068d1b72b..5ff3ce02fe4 100644 --- a/core/src/com/cloud/vm/VmDetailConstants.java +++ b/core/src/com/cloud/vm/VmDetailConstants.java @@ -20,4 +20,5 @@ public interface VmDetailConstants { public static final String KEYBOARD = "keyboard"; public static final String NIC_ADAPTER = "nicAdapter"; public static final String ROOK_DISK_CONTROLLER = "rootDiskController"; + public static final String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag"; } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index 20146970daa..f6f0923c7ae 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -27,6 +27,7 @@ import java.util.Map; import javax.ejb.Local; import javax.inject.Inject; +import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -40,6 +41,8 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.cluster.ClusterManager; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -84,6 +87,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject VmwareManager _vmwareMgr; @Inject SecondaryStorageVmManager _secStorageMgr; @Inject NetworkModel _networkMgr; + @Inject ConfigurationDao _configDao; protected VMwareGuru() { super(); @@ -212,8 +216,21 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); String bootArgs = to.getBootArgs(); to.setBootArgs(bootArgs + " nic_macs=" + sbMacSequence.toString()); + + } + + // Don't do this if the virtual machine is one of the special types + // Should only be done on user machines + if(!(vm.getVirtualMachine() instanceof DomainRouterVO || vm.getVirtualMachine() instanceof ConsoleProxyVO + || vm.getVirtualMachine() instanceof SecondaryStorageVmVO)) { + String nestedVirt = _configDao.getValue(Config.VmwareEnableNestedVirtualization.key()); + if (nestedVirt != null) { + s_logger.debug("Nested virtualization requested, adding flag to vm configuration"); + details.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, nestedVirt); + to.setDetails(details); + + } } - // Determine the VM's OS description GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId()); to.setOs(guestOS.getDisplayName()); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 634827b6468..f569595b8b0 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -232,6 +232,7 @@ import com.vmware.vim25.ClusterDasConfigInfo; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.HostCapability; import com.vmware.vim25.HostFirewallInfo; import com.vmware.vim25.HostFirewallRuleset; import com.vmware.vim25.HostNetworkTrafficShapingPolicy; @@ -2147,6 +2148,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), vmSpec.getLimitCpuUse()); + + if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) { + s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); + ManagedObjectReference hostMor = vmMo.getRunningHost().getMor(); + ManagedObjectReference computeMor = context.getVimClient().getMoRefProp(hostMor, "parent"); + ManagedObjectReference environmentBrowser = + context.getVimClient().getMoRefProp(computeMor, "environmentBrowser"); + HostCapability hostCapability = context.getService().queryTargetCapabilities(environmentBrowser, hostMor); + if (hostCapability.isNestedHVSupported()) { + s_logger.debug("Hypervisor supports nested virtualization, enabling for VM " + vmSpec.getName()); + vmConfigSpec.setNestedHVEnabled(true); + } + else { + s_logger.warn("Hypervisor doesn't support nested virtualization, unable to set config for VM " +vmSpec.getName()); + vmConfigSpec.setNestedHVEnabled(false); + } + } VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[totalChangeDevices]; int i = 0; diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 2137c003912..e3e305350b1 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -276,6 +276,7 @@ public enum Config { VmwareRootDiskControllerType("Advanced", ManagementServer.class, String.class, "vmware.root.disk.controller", "ide", "Specify the default disk controller for root volumes, valid values are scsi, ide", null), VmwareSystemVmNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.systemvm.nic.device.type", "E1000", "Specify the default network device type for system VMs, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null), VmwareRecycleHungWorker("Advanced", ManagementServer.class, Boolean.class, "vmware.recycle.hung.wokervm", "false", "Specify whether or not to recycle hung worker VMs", null), + VmwareEnableNestedVirtualization("Advanced", ManagementServer.class, Boolean.class, "vmware.nested.virtualization", "false", "When set to true this will enable nested virtualization when this is supported by the hypervisor", null), // Midonet MidoNetAPIServerAddress("Network", ManagementServer.class, String.class, "midonet.apiserver.address", "http://localhost:8081", "Specify the address at which the Midonet API server can be contacted (if using Midonet)", null), From 38df62865d905aeac49fac7c32b66c7099036867 Mon Sep 17 00:00:00 2001 From: Ryan Dietrich Date: Fri, 12 Apr 2013 14:00:41 +0100 Subject: [PATCH 058/107] CLOUDSTACK-1989: Without this fix you can't query service offerings that don't have a domain id set (null). Tested via: Called "listServiceOfferings" using a simple perl script, once with an ID, and once without an ID specified. Signed-off-by: Chip Childers --- server/src/com/cloud/api/query/QueryManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index a498c183af5..ea58427b3c8 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -2119,7 +2119,11 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { domainRecord = _domainDao.findById(domainRecord.getParent()); domainIds.add(domainRecord.getId()); } - sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray()); + SearchCriteria spc = _srvOfferingJoinDao.createSearchCriteria(); + + spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); + spc.addOr("domainId", SearchCriteria.Op.NULL); + sc.addAnd("domainId", SearchCriteria.Op.SC, spc); // include also public offering if no keyword, name and id specified if ( keyword == null && name == null && id == null ){ From 6d4b035f2cf2d5ee9d1e7c6def9b802d74ed6d6b Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Fri, 12 Apr 2013 13:50:08 +0200 Subject: [PATCH 059/107] tools: A small fix for the script to build the docs with --- tools/build/build_docs.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/build/build_docs.sh b/tools/build/build_docs.sh index 8bb63e30e87..c1b1f1389fd 100755 --- a/tools/build/build_docs.sh +++ b/tools/build/build_docs.sh @@ -48,6 +48,11 @@ if [ ! -x "$publican_path" ]; then exit 1 fi +if [ ! -d "$sourcedir/docs" ]; then + echo "$sourcedir/docs doesn't seem to exist? Maybe set -s?" + exit 1 +fi + cd $sourcedir/docs cp -R /usr/share/publican/Common_Content . ln -s $sourcedir/docs/publican-cloudstack Common_Content/cloudstack From 7753275b3777a3ae69d083d7e1df430f34b7f936 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Fri, 12 Apr 2013 15:02:53 +0200 Subject: [PATCH 060/107] CLOUDSTACK-574: Add Ceph RBD documentation This commit also add some extra information about NFS and iSCSI Primary Storage on a KVM hypervisor. --- ...ypervisor-host-install-primary-storage.xml | 62 +++++++++++++++++++ docs/en-US/hypervisor-kvm-install-flow.xml | 1 + docs/en-US/primary-storage-add.xml | 5 ++ 3 files changed, 68 insertions(+) create mode 100644 docs/en-US/hypervisor-host-install-primary-storage.xml diff --git a/docs/en-US/hypervisor-host-install-primary-storage.xml b/docs/en-US/hypervisor-host-install-primary-storage.xml new file mode 100644 index 00000000000..3e76bfbf3ba --- /dev/null +++ b/docs/en-US/hypervisor-host-install-primary-storage.xml @@ -0,0 +1,62 @@ + + +%BOOK_ENTITIES; +]> + + + +
+ Adding Primary Storage to a KVM hypervisor + For most Primary Storages there are no special requirements to add primary storage, + it's all done via the management server. + The follow subchapters however describe a couple of prerequisites for adding primary storage to a KVM cluster/hypervisor. + +
+ Requirements for NFS primary storage + &PRODUCT; will handle the mounting of the NFS storage, no manual intervention is required. + Before adding the Primary Storage make sure the NFS client packages are installed. It's always useful to do a manual mount on one or + more hypervisors prior to adding the primary storage to make sure the mountpoint works. +
+ +
+ Requirements for iSCSI primary storage + When adding iSCSI Primary Storage the management server of &PRODUCT; will configure the iSCSI initiator. The requirement however is that + Open-iSCSI is installed on all hypervisors. +
+ +
+ Requirements for Ceph primary storage + Support for RBD Primary Storage was added in &PRODUCT; 4.0 and requires a special version of libvirt. + With the KVM hypervisor &PRODUCT; relies on libvirt for handling it's storage pools. Most versions of libvirt + don't have the RBD storage pool support yet, so a manual compile of libvirt is required. + To use RBD primary storage make sure you hypervisors meet the following requirements + + Make sure librbd is installed on your system. + A RBD-enabled Qemu version is installed + Libivrt (>= 0.9.13) with RBD storage pool support enabled is installed + No /etc/ceph/ceph.conf configuration file is present on your hypervisors. + + After meeting these requirements you can add the RBD storage pool via the WebUI. + Hint: Ubuntu 13.04 meets all these requirements by default. + &PRODUCT; doesn't support multiple hostnames when adding a Primary Storage pool. If you have multiple Ceph monitor daemons + it's best to create a Round Robin-DNS record and use that as the hostname for the storage pool. +
+ +
\ No newline at end of file diff --git a/docs/en-US/hypervisor-kvm-install-flow.xml b/docs/en-US/hypervisor-kvm-install-flow.xml index 6cc73e4fdfa..7dfd47d2e52 100644 --- a/docs/en-US/hypervisor-kvm-install-flow.xml +++ b/docs/en-US/hypervisor-kvm-install-flow.xml @@ -34,4 +34,5 @@ + diff --git a/docs/en-US/primary-storage-add.xml b/docs/en-US/primary-storage-add.xml index 067cf7114dc..ddae418d925 100644 --- a/docs/en-US/primary-storage-add.xml +++ b/docs/en-US/primary-storage-add.xml @@ -37,6 +37,11 @@ Primary storage cannot be added until a host has been added to the cluster. If you do not provision shared primary storage, you must set the global configuration parameter system.vm.local.storage.required to true, or else you will not be able to start VMs. + There are some differences between hypervisors regarding Primary Storage. See the list below for more information per hypervisor. + + + +
Adding Primary Stroage From 0f8a46c5802be6534d8d38cca3eb7b06568738ce Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Fri, 12 Apr 2013 15:07:24 +0200 Subject: [PATCH 061/107] tools: Allow setting the output format for the docs --- tools/build/build_docs.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/build/build_docs.sh b/tools/build/build_docs.sh index c1b1f1389fd..62617a3df9d 100755 --- a/tools/build/build_docs.sh +++ b/tools/build/build_docs.sh @@ -19,22 +19,25 @@ sourcedir=~/incubator-cloudstack/ common_content_dir=/usr/share/publican/Common_Content publican_path=/usr/bin/publican +output_format="html,pdf" usage(){ echo "usage: $0 [-s source dir] [-c publican common content] [-p path to publican]" echo " -s sets the source directory (defaults to $sourcedir)" echo " -c sets the public common content directory (defaults to $common_content_dir)" echo " -p sets the path to the publican binary (defaults to $publican_path)" + echo " -f sets the output format (defaults to $output_format)" echo " -h" } -while getopts v:s:c:p:h opt +while getopts v:s:c:p:f:h opt do case "$opt" in v) version="$OPTARG";; s) sourcedir="$OPTARG";; c) common_content_dir="$OPTARG";; p) publican_path="$OPTARG";; + f) output_format="$OPTARG";; h) usage exit 0;; \?) @@ -56,5 +59,5 @@ fi cd $sourcedir/docs cp -R /usr/share/publican/Common_Content . ln -s $sourcedir/docs/publican-cloudstack Common_Content/cloudstack -publican build --config=publican-installation.cfg --formats html,pdf --langs en-US --common_content=$sourcedir/docs/Common_Content +publican build --config=publican-installation.cfg --formats $output_format --langs en-US --common_content=$sourcedir/docs/Common_Content rm -r Common_Content \ No newline at end of file From 4e5a8a0f8adcc665755229ee3d18f40913d15913 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Fri, 12 Apr 2013 03:53:51 +0000 Subject: [PATCH 062/107] Fixed Primary typo Conflicts: client/WEB-INF/classes/resources/messages_de_DE.properties --- .../org/apache/cloudstack/storage/test/DirectAgentTest.java | 4 ++-- .../storage/command/CreateVolumeFromBaseImageCommand.java | 6 +++--- .../cloudstack/storage/to/ImageOnPrimayDataStoreTO.java | 4 ++-- .../hypervisor/xen/resource/XenServerStorageResource.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java index 2d6b94fdfaf..fc4aea85822 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java @@ -23,7 +23,7 @@ import java.util.UUID; import javax.inject.Inject; import org.apache.cloudstack.storage.to.ImageDataStoreTO; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.TemplateTO; import org.mockito.Mockito; @@ -126,7 +126,7 @@ public class DirectAgentTest extends CloudStackTestNGBase { @Test public void testDownloadTemplate() { - ImageOnPrimayDataStoreTO image = Mockito.mock(ImageOnPrimayDataStoreTO.class); + ImageOnPrimaryDataStoreTO image = Mockito.mock(ImageOnPrimaryDataStoreTO.class); PrimaryDataStoreTO primaryStore = Mockito.mock(PrimaryDataStoreTO.class); Mockito.when(primaryStore.getUuid()).thenReturn(this.getLocalStorageUuid()); Mockito.when(image.getPrimaryDataStore()).thenReturn(primaryStore); diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java index f4be0676b9b..1734bc409cc 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java @@ -18,14 +18,14 @@ */ package org.apache.cloudstack.storage.command; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import com.cloud.agent.api.Command; public class CreateVolumeFromBaseImageCommand extends Command implements StorageSubSystemCommand { private final VolumeTO volume; - private final ImageOnPrimayDataStoreTO image; + private final ImageOnPrimaryDataStoreTO image; public CreateVolumeFromBaseImageCommand(VolumeTO volume, String image) { this.volume = volume; @@ -36,7 +36,7 @@ public class CreateVolumeFromBaseImageCommand extends Command implements Storage return this.volume; } - public ImageOnPrimayDataStoreTO getImage() { + public ImageOnPrimaryDataStoreTO getImage() { return this.image; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java index 18743d70bf2..a9a3cc43c0e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java @@ -20,11 +20,11 @@ package org.apache.cloudstack.storage.to; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -public class ImageOnPrimayDataStoreTO { +public class ImageOnPrimaryDataStoreTO { private final String pathOnPrimaryDataStore; private PrimaryDataStoreTO dataStore; private final TemplateTO template; - public ImageOnPrimayDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { + public ImageOnPrimaryDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { this.pathOnPrimaryDataStore = template.getPath(); //this.dataStore = template.getPrimaryDataStore().getDataStoreTO(); this.template = new TemplateTO(template.getTemplate()); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 9c291491114..7e0ccbed39c 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -39,7 +39,7 @@ import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -207,7 +207,7 @@ public class XenServerStorageResource { protected Answer execute(CreateVolumeFromBaseImageCommand cmd) { VolumeTO volume = cmd.getVolume(); - ImageOnPrimayDataStoreTO baseImage = cmd.getImage(); + ImageOnPrimaryDataStoreTO baseImage = cmd.getImage(); Connection conn = hypervisorResource.getConnection(); try { From 85b1519fe5d09e7f0fa51c914ac725c5d928800f Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Fri, 12 Apr 2013 19:16:36 +0530 Subject: [PATCH 063/107] GlobalLoadBalancerResponse should contain the service type details and GSLB rule is defaulted to have source IP as sticky method --- .../region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java | 3 +++ .../api/response/GlobalLoadBalancerResponse.java | 8 ++++++++ server/src/com/cloud/api/ApiResponseHelper.java | 2 ++ 3 files changed, 13 insertions(+) diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java index cd559d8c470..b08b6aeff17 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java @@ -93,6 +93,9 @@ public class CreateGlobalLoadBalancerRuleCmd extends BaseAsyncCreateCmd { } public String getStickyMethod() { + if (stickyMethod == null) { + return "sourceip"; + } return stickyMethod; } diff --git a/api/src/org/apache/cloudstack/api/response/GlobalLoadBalancerResponse.java b/api/src/org/apache/cloudstack/api/response/GlobalLoadBalancerResponse.java index 0fd064f41b5..38e080bd28a 100644 --- a/api/src/org/apache/cloudstack/api/response/GlobalLoadBalancerResponse.java +++ b/api/src/org/apache/cloudstack/api/response/GlobalLoadBalancerResponse.java @@ -50,6 +50,10 @@ public class GlobalLoadBalancerResponse extends BaseResponse implements Controll @Param(description = "session persistence method used for the global load balancer") private String stickyMethod; + @SerializedName(ApiConstants.GSLB_SERVICE_TYPE) + @Param(description = "GSLB service type") + private String serviceType; + @SerializedName(ApiConstants.REGION_ID) @Param(description = "Region Id in which global load balancer is created") private Integer regionId; @@ -96,6 +100,10 @@ public class GlobalLoadBalancerResponse extends BaseResponse implements Controll this.stickyMethod = stickyMethod; } + public void setServiceType(String serviceType) { + this.serviceType = serviceType; + } + public void setServiceDomainName(String domainName) { this.gslbDomainName = domainName; } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 651a8bed110..50c137ae81f 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -768,11 +768,13 @@ public class ApiResponseHelper implements ResponseGenerator { GlobalLoadBalancerResponse response = new GlobalLoadBalancerResponse(); response.setAlgorithm(globalLoadBalancerRule.getAlgorithm()); response.setStickyMethod(globalLoadBalancerRule.getPersistence()); + response.setServiceType(globalLoadBalancerRule.getServiceType()); response.setServiceDomainName(globalLoadBalancerRule.getGslbDomain()); response.setName(globalLoadBalancerRule.getName()); response.setDescription(globalLoadBalancerRule.getDescription()); response.setRegionIdId(globalLoadBalancerRule.getRegion()); response.setId(globalLoadBalancerRule.getUuid()); + response.setObjectName("globalloadbalancer"); return response; } From 3b35063adf1b7ddf70b226358c58c64f08c7d538 Mon Sep 17 00:00:00 2001 From: Chip Childers Date: Fri, 12 Apr 2013 15:18:02 +0100 Subject: [PATCH 064/107] Revert "Fixed Primary typo" This reverts commit 4e5a8a0f8adcc665755229ee3d18f40913d15913. --- .../org/apache/cloudstack/storage/test/DirectAgentTest.java | 4 ++-- .../storage/command/CreateVolumeFromBaseImageCommand.java | 6 +++--- .../cloudstack/storage/to/ImageOnPrimayDataStoreTO.java | 4 ++-- .../hypervisor/xen/resource/XenServerStorageResource.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java index fc4aea85822..2d6b94fdfaf 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java @@ -23,7 +23,7 @@ import java.util.UUID; import javax.inject.Inject; import org.apache.cloudstack.storage.to.ImageDataStoreTO; -import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.TemplateTO; import org.mockito.Mockito; @@ -126,7 +126,7 @@ public class DirectAgentTest extends CloudStackTestNGBase { @Test public void testDownloadTemplate() { - ImageOnPrimaryDataStoreTO image = Mockito.mock(ImageOnPrimaryDataStoreTO.class); + ImageOnPrimayDataStoreTO image = Mockito.mock(ImageOnPrimayDataStoreTO.class); PrimaryDataStoreTO primaryStore = Mockito.mock(PrimaryDataStoreTO.class); Mockito.when(primaryStore.getUuid()).thenReturn(this.getLocalStorageUuid()); Mockito.when(image.getPrimaryDataStore()).thenReturn(primaryStore); diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java index 1734bc409cc..f4be0676b9b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java @@ -18,14 +18,14 @@ */ package org.apache.cloudstack.storage.command; -import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import com.cloud.agent.api.Command; public class CreateVolumeFromBaseImageCommand extends Command implements StorageSubSystemCommand { private final VolumeTO volume; - private final ImageOnPrimaryDataStoreTO image; + private final ImageOnPrimayDataStoreTO image; public CreateVolumeFromBaseImageCommand(VolumeTO volume, String image) { this.volume = volume; @@ -36,7 +36,7 @@ public class CreateVolumeFromBaseImageCommand extends Command implements Storage return this.volume; } - public ImageOnPrimaryDataStoreTO getImage() { + public ImageOnPrimayDataStoreTO getImage() { return this.image; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java index a9a3cc43c0e..18743d70bf2 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java @@ -20,11 +20,11 @@ package org.apache.cloudstack.storage.to; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -public class ImageOnPrimaryDataStoreTO { +public class ImageOnPrimayDataStoreTO { private final String pathOnPrimaryDataStore; private PrimaryDataStoreTO dataStore; private final TemplateTO template; - public ImageOnPrimaryDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { + public ImageOnPrimayDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { this.pathOnPrimaryDataStore = template.getPath(); //this.dataStore = template.getPrimaryDataStore().getDataStoreTO(); this.template = new TemplateTO(template.getTemplate()); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 7e0ccbed39c..9c291491114 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -39,7 +39,7 @@ import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; -import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -207,7 +207,7 @@ public class XenServerStorageResource { protected Answer execute(CreateVolumeFromBaseImageCommand cmd) { VolumeTO volume = cmd.getVolume(); - ImageOnPrimaryDataStoreTO baseImage = cmd.getImage(); + ImageOnPrimayDataStoreTO baseImage = cmd.getImage(); Connection conn = hypervisorResource.getConnection(); try { From 69b0c149d832be6554e4c5d53bb647d26ff69bd7 Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Fri, 12 Apr 2013 09:32:17 -0500 Subject: [PATCH 065/107] Revert "CLOUDSTACK-574: Add Ceph RBD documentation" This reverts commit 7753275b3777a3ae69d083d7e1df430f34b7f936. --- ...ypervisor-host-install-primary-storage.xml | 62 ------------------- docs/en-US/hypervisor-kvm-install-flow.xml | 1 - docs/en-US/primary-storage-add.xml | 5 -- 3 files changed, 68 deletions(-) delete mode 100644 docs/en-US/hypervisor-host-install-primary-storage.xml diff --git a/docs/en-US/hypervisor-host-install-primary-storage.xml b/docs/en-US/hypervisor-host-install-primary-storage.xml deleted file mode 100644 index 3e76bfbf3ba..00000000000 --- a/docs/en-US/hypervisor-host-install-primary-storage.xml +++ /dev/null @@ -1,62 +0,0 @@ - - -%BOOK_ENTITIES; -]> - - - -
- Adding Primary Storage to a KVM hypervisor - For most Primary Storages there are no special requirements to add primary storage, - it's all done via the management server. - The follow subchapters however describe a couple of prerequisites for adding primary storage to a KVM cluster/hypervisor. - -
- Requirements for NFS primary storage - &PRODUCT; will handle the mounting of the NFS storage, no manual intervention is required. - Before adding the Primary Storage make sure the NFS client packages are installed. It's always useful to do a manual mount on one or - more hypervisors prior to adding the primary storage to make sure the mountpoint works. -
- -
- Requirements for iSCSI primary storage - When adding iSCSI Primary Storage the management server of &PRODUCT; will configure the iSCSI initiator. The requirement however is that - Open-iSCSI is installed on all hypervisors. -
- -
- Requirements for Ceph primary storage - Support for RBD Primary Storage was added in &PRODUCT; 4.0 and requires a special version of libvirt. - With the KVM hypervisor &PRODUCT; relies on libvirt for handling it's storage pools. Most versions of libvirt - don't have the RBD storage pool support yet, so a manual compile of libvirt is required. - To use RBD primary storage make sure you hypervisors meet the following requirements - - Make sure librbd is installed on your system. - A RBD-enabled Qemu version is installed - Libivrt (>= 0.9.13) with RBD storage pool support enabled is installed - No /etc/ceph/ceph.conf configuration file is present on your hypervisors. - - After meeting these requirements you can add the RBD storage pool via the WebUI. - Hint: Ubuntu 13.04 meets all these requirements by default. - &PRODUCT; doesn't support multiple hostnames when adding a Primary Storage pool. If you have multiple Ceph monitor daemons - it's best to create a Round Robin-DNS record and use that as the hostname for the storage pool. -
- -
\ No newline at end of file diff --git a/docs/en-US/hypervisor-kvm-install-flow.xml b/docs/en-US/hypervisor-kvm-install-flow.xml index 7dfd47d2e52..6cc73e4fdfa 100644 --- a/docs/en-US/hypervisor-kvm-install-flow.xml +++ b/docs/en-US/hypervisor-kvm-install-flow.xml @@ -34,5 +34,4 @@ -
diff --git a/docs/en-US/primary-storage-add.xml b/docs/en-US/primary-storage-add.xml index ddae418d925..067cf7114dc 100644 --- a/docs/en-US/primary-storage-add.xml +++ b/docs/en-US/primary-storage-add.xml @@ -37,11 +37,6 @@ Primary storage cannot be added until a host has been added to the cluster. If you do not provision shared primary storage, you must set the global configuration parameter system.vm.local.storage.required to true, or else you will not be able to start VMs. - There are some differences between hypervisors regarding Primary Storage. See the list below for more information per hypervisor. - - - -
Adding Primary Stroage From 95cbb790f3e65d42182a52032a4ad6827391e57e Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Fri, 12 Apr 2013 15:06:11 +0000 Subject: [PATCH 066/107] Fixed Primary typo --- .../org/apache/cloudstack/storage/test/DirectAgentTest.java | 4 ++-- .../storage/command/CreateVolumeFromBaseImageCommand.java | 6 +++--- .../datastore/provider/DataStoreProviderManagerImpl.java | 4 ++-- ...rimayDataStoreTO.java => ImageOnPrimaryDataStoreTO.java} | 4 ++-- .../hypervisor/xen/resource/XenServerStorageResource.java | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) rename engine/storage/src/org/apache/cloudstack/storage/to/{ImageOnPrimayDataStoreTO.java => ImageOnPrimaryDataStoreTO.java} (92%) diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java index 2d6b94fdfaf..fc4aea85822 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentTest.java @@ -23,7 +23,7 @@ import java.util.UUID; import javax.inject.Inject; import org.apache.cloudstack.storage.to.ImageDataStoreTO; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.TemplateTO; import org.mockito.Mockito; @@ -126,7 +126,7 @@ public class DirectAgentTest extends CloudStackTestNGBase { @Test public void testDownloadTemplate() { - ImageOnPrimayDataStoreTO image = Mockito.mock(ImageOnPrimayDataStoreTO.class); + ImageOnPrimaryDataStoreTO image = Mockito.mock(ImageOnPrimaryDataStoreTO.class); PrimaryDataStoreTO primaryStore = Mockito.mock(PrimaryDataStoreTO.class); Mockito.when(primaryStore.getUuid()).thenReturn(this.getLocalStorageUuid()); Mockito.when(image.getPrimaryDataStore()).thenReturn(primaryStore); diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java index f4be0676b9b..1734bc409cc 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeFromBaseImageCommand.java @@ -18,14 +18,14 @@ */ package org.apache.cloudstack.storage.command; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import com.cloud.agent.api.Command; public class CreateVolumeFromBaseImageCommand extends Command implements StorageSubSystemCommand { private final VolumeTO volume; - private final ImageOnPrimayDataStoreTO image; + private final ImageOnPrimaryDataStoreTO image; public CreateVolumeFromBaseImageCommand(VolumeTO volume, String image) { this.volume = volume; @@ -36,7 +36,7 @@ public class CreateVolumeFromBaseImageCommand extends Command implements Storage return this.volume; } - public ImageOnPrimayDataStoreTO getImage() { + public ImageOnPrimaryDataStoreTO getImage() { return this.image; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 91b6c6329bb..40a65dcf07f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -64,7 +64,7 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto return null; } - public List getPrimayrDataStoreProviders() { + public List getPrimaryDataStoreProviders() { List providers = new ArrayList(); for (DataStoreProvider provider : providerMap.values()) { if (provider instanceof PrimaryDataStoreProvider) { @@ -138,7 +138,7 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto throw new InvalidParameterValueException("Invalid parameter, need to specify type: either primary or image"); } if (type.equalsIgnoreCase(DataStoreProvider.DataStoreProviderType.PRIMARY.toString())) { - return this.getPrimayrDataStoreProviders(); + return this.getPrimaryDataStoreProviders(); } else if (type.equalsIgnoreCase(DataStoreProvider.DataStoreProviderType.IMAGE.toString())) { return this.getImageDataStoreProviders(); } else { diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimaryDataStoreTO.java similarity index 92% rename from engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java rename to engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimaryDataStoreTO.java index 18743d70bf2..a9a3cc43c0e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimayDataStoreTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/ImageOnPrimaryDataStoreTO.java @@ -20,11 +20,11 @@ package org.apache.cloudstack.storage.to; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -public class ImageOnPrimayDataStoreTO { +public class ImageOnPrimaryDataStoreTO { private final String pathOnPrimaryDataStore; private PrimaryDataStoreTO dataStore; private final TemplateTO template; - public ImageOnPrimayDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { + public ImageOnPrimaryDataStoreTO(TemplateOnPrimaryDataStoreInfo template) { this.pathOnPrimaryDataStore = template.getPath(); //this.dataStore = template.getPrimaryDataStore().getDataStoreTO(); this.template = new TemplateTO(template.getTemplate()); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 9c291491114..7e0ccbed39c 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -39,7 +39,7 @@ import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; -import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; +import org.apache.cloudstack.storage.to.ImageOnPrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -207,7 +207,7 @@ public class XenServerStorageResource { protected Answer execute(CreateVolumeFromBaseImageCommand cmd) { VolumeTO volume = cmd.getVolume(); - ImageOnPrimayDataStoreTO baseImage = cmd.getImage(); + ImageOnPrimaryDataStoreTO baseImage = cmd.getImage(); Connection conn = hypervisorResource.getConnection(); try { From 8f865c5a901d1fb066709e1809fd5538af3eea11 Mon Sep 17 00:00:00 2001 From: Likitha Shetty Date: Mon, 8 Apr 2013 22:44:45 +0530 Subject: [PATCH 067/107] Dedicate Public IP address range to an account --- .../configuration/ConfigurationService.java | 6 + api/src/com/cloud/event/EventTypes.java | 4 + .../admin/vlan/DedicatePublicIpRangeCmd.java | 108 +++++ .../admin/vlan/ReleasePublicIpRangeCmd.java | 77 ++++ client/tomcatconf/commands.properties.in | 2 + .../configuration/ConfigurationManager.java | 5 +- .../ConfigurationManagerImpl.java | 173 +++++++- .../com/cloud/network/NetworkManagerImpl.java | 45 +- .../com/cloud/network/NetworkServiceImpl.java | 9 - .../cloud/server/ManagementServerImpl.java | 3 + .../com/cloud/user/AccountManagerImpl.java | 6 +- .../ConfigurationManagerTest.java | 413 ++++++++++++++++++ .../vpc/MockConfigurationManagerImpl.java | 23 +- .../component/test_public_ip_range.py | 173 ++++++++ tools/marvin/marvin/integration/lib/base.py | 19 +- 15 files changed, 1017 insertions(+), 49 deletions(-) create mode 100755 api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java mode change 100644 => 100755 server/src/com/cloud/configuration/ConfigurationManager.java create mode 100755 server/test/com/cloud/configuration/ConfigurationManagerTest.java mode change 100644 => 100755 server/test/com/cloud/vpc/MockConfigurationManagerImpl.java create mode 100755 test/integration/component/test_public_ip_range.py mode change 100644 => 100755 tools/marvin/marvin/integration/lib/base.py diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java index e63fcece525..6937d0b64de 100644 --- a/api/src/com/cloud/configuration/ConfigurationService.java +++ b/api/src/com/cloud/configuration/ConfigurationService.java @@ -35,7 +35,9 @@ import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; 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.UpdateZoneCmd; @@ -234,6 +236,10 @@ public interface ConfigurationService { boolean deleteVlanIpRange(DeleteVlanIpRangeCmd cmd); + Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd) throws ResourceAllocationException; + + boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd); + NetworkOffering createNetworkOffering(CreateNetworkOfferingCmd cmd); NetworkOffering updateNetworkOffering(UpdateNetworkOfferingCmd cmd); diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 6a26212ecc7..0ee7f402fd7 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -226,6 +226,8 @@ public class EventTypes { // VLANs/IP ranges public static final String EVENT_VLAN_IP_RANGE_CREATE = "VLAN.IP.RANGE.CREATE"; public static final String EVENT_VLAN_IP_RANGE_DELETE = "VLAN.IP.RANGE.DELETE"; + public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE"; + public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE"; public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE"; public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE"; @@ -545,6 +547,8 @@ public class EventTypes { // VLANs/IP ranges entityEventDetails.put(EVENT_VLAN_IP_RANGE_CREATE, Vlan.class.getName()); entityEventDetails.put(EVENT_VLAN_IP_RANGE_DELETE,Vlan.class.getName()); + entityEventDetails.put(EVENT_VLAN_IP_RANGE_DEDICATE, Vlan.class.getName()); + entityEventDetails.put(EVENT_VLAN_IP_RANGE_RELEASE,Vlan.class.getName()); entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class.getName()); entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class.getName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java new file mode 100755 index 00000000000..e7b1105af94 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.vlan; + +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.ProjectResponse; +import org.apache.cloudstack.api.response.VlanIpRangeResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.log4j.Logger; + +import com.cloud.dc.Vlan; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; + +@APICommand(name = "dedicatePublicIpRange", description="Dedicates a Public IP range to an account", responseObject=VlanIpRangeResponse.class) +public class DedicatePublicIpRangeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DedicatePublicIpRangeCmd.class.getName()); + + private static final String s_name = "dedicatepubliciprangeresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = VlanIpRangeResponse.class, + required=true, description="the id of the VLAN IP range") + private Long id; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true, + description="account who will own the VLAN") + private String accountName; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="project who will own the VLAN") + private Long projectId; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + required=true, description="domain ID of the account owning a VLAN") + private Long domainId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getProjectId() { + return projectId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException { + Vlan result = _configService.dedicatePublicIpRange(this); + if (result != null) { + VlanIpRangeResponse response = _responseGenerator.createVlanIpRangeResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to dedicate vlan ip range"); + } + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java new file mode 100644 index 00000000000..91cc7d33da9 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java @@ -0,0 +1,77 @@ +// 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.vlan; + +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.SuccessResponse; +import org.apache.cloudstack.api.response.VlanIpRangeResponse; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; + +@APICommand(name = "releasePublicIpRange", description="Releases a Public IP range back to the system pool", responseObject=SuccessResponse.class) +public class ReleasePublicIpRangeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ReleasePublicIpRangeCmd.class.getName()); + + private static final String s_name = "releasepubliciprangeresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = VlanIpRangeResponse.class, + required=true, description="the id of the Public IP range") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + boolean result = _configService.releasePublicIpRange(this); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release public ip range"); + } + } +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 4ce9fd3af5c..798d226ca96 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -124,6 +124,8 @@ listDiskOfferings=15 createVlanIpRange=1 deleteVlanIpRange=1 listVlanIpRanges=1 +dedicatePublicIpRange=1 +releasePublicIpRange=1 #### address commands associateIpAddress=15 diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java old mode 100644 new mode 100755 index c5f65e9d0fc..d7faf19fd28 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -30,6 +30,7 @@ import com.cloud.dc.Vlan; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -150,6 +151,8 @@ public interface ConfigurationManager extends ConfigurationService, Manager { */ boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller); + boolean releasePublicIpRange(long userId, long vlanDbId, Account caller); + /** * Converts a comma separated list of tags to a List * @@ -211,7 +214,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { ClusterVO getCluster(long id); - boolean deleteAccountSpecificVirtualRanges(long accountId); + boolean releaseAccountSpecificVirtualRanges(long accountId); /** * Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system. diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index ceeae1ee910..fce3c010df4 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -56,7 +56,9 @@ import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; 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.UpdateZoneCmd; @@ -2306,9 +2308,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Gateway, netmask and zoneId have to be passed in for virtual and direct untagged networks"); } - // if it's an account specific range, associate ip address list to the account - boolean associateIpRangeToAccount = false; - if (forVirtualNetwork) { if (vlanOwner != null) { @@ -2316,8 +2315,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati //check resource limits _resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountIpRange); - - associateIpRangeToAccount = true; } } @@ -2332,21 +2329,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati endIP, vlanGateway, vlanNetmask, vlanId, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); txn.commit(); - if (associateIpRangeToAccount) { - _networkMgr.associateIpAddressListToAccount(userId, vlanOwner.getId(), zoneId, vlan.getId(), null); - } - - // Associate ips to the network - if (associateIpRangeToAccount) { - if (network.getState() == Network.State.Implemented) { - s_logger.debug("Applying ip associations for vlan id=" + vlanId + " in network " + network); - if (!_networkMgr.applyIpAssociations(network, false)) { - s_logger.warn("Failed to apply ip associations for vlan id=1 as a part of add vlan range for account id=" + vlanOwner.getId()); - } - } else { - s_logger.trace("Network id=" + network.getId() + " is not Implemented, no need to apply ipAssociations"); - } - } return vlan; } @@ -2698,6 +2680,149 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_DEDICATE, eventDescription = "dedicating vlan ip range", async = false) + public Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd) throws ResourceAllocationException { + Long vlanDbId = cmd.getId(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Long projectId = cmd.getProjectId(); + + // Check if account is valid + Account vlanOwner = null; + if (projectId != null) { + if (accountName != null) { + throw new InvalidParameterValueException("accountName and projectId are mutually exclusive"); + } + Project project = _projectMgr.getProject(projectId); + if (project == null) { + throw new InvalidParameterValueException("Unable to find project by id " + projectId); + } + vlanOwner = _accountMgr.getAccount(project.getProjectAccountId()); + } + + if ((accountName != null) && (domainId != null)) { + vlanOwner = _accountDao.findActiveAccount(accountName, domainId); + if (vlanOwner == null) { + throw new InvalidParameterValueException("Please specify a valid account"); + } + } + + // Check if range is valid + VlanVO vlan = _vlanDao.findById(vlanDbId); + if (vlan == null) { + throw new InvalidParameterValueException("Please specify a valid Public IP range id"); + } + + // Check if range has already been dedicated + List maps = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanDbId); + if (maps != null && !maps.isEmpty()) { + throw new InvalidParameterValueException("Specified Public IP range has already been dedicated"); + } + + // Verify that zone exists and is advanced + Long zoneId = vlan.getDataCenterId(); + DataCenterVO zone = _zoneDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); + } + if (zone.getNetworkType() == NetworkType.Basic) { + throw new InvalidParameterValueException("Public IP range can be dedicated to an account only in the zone of type " + NetworkType.Advanced); + } + + // Check Public IP resource limits + int accountPublicIpRange = _publicIpAddressDao.countIPs(zoneId, vlanDbId, false); + _resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountPublicIpRange); + + // Check if any of the Public IP addresses is allocated to another account + List ips = _publicIpAddressDao.listByVlanId(vlanDbId); + for (IPAddressVO ip : ips) { + Long allocatedToAccountId = ip.getAllocatedToAccountId(); + if (allocatedToAccountId != null) { + Account accountAllocatedTo = _accountMgr.getActiveAccountById(allocatedToAccountId); + if (!accountAllocatedTo.getAccountName().equalsIgnoreCase(accountName)) + throw new InvalidParameterValueException("Public IP address in range is already allocated to another account"); + } + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + // Create an AccountVlanMapVO entry + AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId()); + _accountVlanMapDao.persist(accountVlanMapVO); + + txn.commit(); + + return vlan; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_RELEASE, eventDescription = "releasing a public ip range", async = false) + public boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd) { + Long vlanDbId = cmd.getId(); + + VlanVO vlan = _vlanDao.findById(vlanDbId); + if (vlan == null) { + throw new InvalidParameterValueException("Please specify a valid IP range id."); + } + + return releasePublicIpRange(vlanDbId, UserContext.current().getCallerUserId(), UserContext.current().getCaller()); + } + + @Override + @DB + public boolean releasePublicIpRange(long vlanDbId, long userId, Account caller) { + VlanVO vlan = _vlanDao.findById(vlanDbId); + + List acctVln = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanDbId); + // Verify range is dedicated + if (acctVln == null || acctVln.isEmpty()) { + throw new InvalidParameterValueException("Can't release Public IP range " + vlanDbId + " as it not dedicated to any account"); + } + + // Check if range has any allocated public IPs + long allocIpCount = _publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true); + boolean success = true; + if (allocIpCount > 0) { + try { + vlan = _vlanDao.acquireInLockTable(vlanDbId, 30); + if (vlan == null) { + throw new CloudRuntimeException("Unable to acquire vlan configuration: " + vlanDbId); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("lock vlan " + vlanDbId + " is acquired"); + } + List ips = _publicIpAddressDao.listByVlanId(vlanDbId); + for (IPAddressVO ip : ips) { + // Disassociate allocated IP's that are not in use + if ( !ip.isOneToOneNat() && !(ip.isSourceNat() && _networkModel.getNetwork(ip.getAssociatedWithNetworkId()) != null) && + !(_firewallDao.countRulesByIpId(ip.getId()) > 0) ) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing Public IP addresses" + ip +" of vlan " + vlanDbId + " as part of Public IP" + + " range release to the system pool"); + } + success = success && _networkMgr.disassociatePublicIpAddress(ip.getId(), userId, caller); + } + } + if (!success) { + s_logger.warn("Some Public IP addresses that were not in use failed to be released as a part of" + + " vlan " + vlanDbId + "release to the system pool"); + } + } finally { + _vlanDao.releaseFromLockTable(vlanDbId); + } + } + + // A Public IP range can only be dedicated to one account at a time + if (_accountVlanMapDao.remove(acctVln.get(0).getId())) { + return true; + } else { + return false; + } + } + @Override public List csvTagsToList(String tags) { List tagsList = new ArrayList(); @@ -3957,14 +4082,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB - public boolean deleteAccountSpecificVirtualRanges(long accountId) { + public boolean releaseAccountSpecificVirtualRanges(long accountId) { List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(accountId); boolean result = true; if (maps != null && !maps.isEmpty()) { Transaction txn = Transaction.currentTxn(); txn.start(); for (AccountVlanMapVO map : maps) { - if (!deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), map.getVlanDbId(), + if (!releasePublicIpRange(map.getVlanDbId(), _accountMgr.getSystemUser().getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM))) { result = false; } @@ -3972,10 +4097,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (result) { txn.commit(); } else { - s_logger.error("Failed to delete account specific virtual ip ranges for account id=" + accountId); + s_logger.error("Failed to release account specific virtual ip ranges for account id=" + accountId); } } else { - s_logger.trace("Account id=" + accountId + " has no account specific virtual ip ranges, nothing to delete"); + s_logger.trace("Account id=" + accountId + " has no account specific virtual ip ranges, nothing to release"); } return result; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index a97f2ce13e4..5b604667585 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -348,7 +348,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } @DB - public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, + public PublicIp fetchNewPublicIp(long dcId, Long podId, List vlanDbIds, Account owner, VlanType vlanUse, Long guestNetworkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem, Long vpcId) throws InsufficientAddressCapacityException { StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); @@ -364,9 +364,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L errorMessage.append(" zone id=" + dcId); } - if (vlanDbId != null) { - sc.addAnd("vlanId", SearchCriteria.Op.EQ, vlanDbId); - errorMessage.append(", vlanId id=" + vlanDbId); + if ( vlanDbIds != null && !vlanDbIds.isEmpty() ) { + sc.setParameters("vlanId", vlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + vlanDbIds.toArray()); } sc.setParameters("dc", dcId); @@ -526,14 +526,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } // If account has Account specific ip ranges, try to allocate ip from there - Long vlanId = null; + List vlanIds = new ArrayList(); List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ownerId); if (maps != null && !maps.isEmpty()) { - vlanId = maps.get(0).getVlanDbId(); + vlanIds.add(maps.get(0).getVlanDbId()); } - ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, guestNtwkId, + ip = fetchNewPublicIp(dcId, null, vlanIds, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId); IPAddressVO publicIp = ip.ip(); @@ -669,6 +669,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L VlanType vlanType = VlanType.VirtualNetwork; boolean assign = false; + boolean allocateFromDedicatedRange = false; if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { // zone is of type DataCenter. See DataCenterVO.java. @@ -702,8 +703,32 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L txn.start(); - ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, - false, assign, null, isSystem, null); + // If account has dedicated Public IP ranges, allocate IP from the dedicated range + List vlanDbIds = new ArrayList(); + List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ipOwner.getId()); + for (AccountVlanMapVO map : maps) { + vlanDbIds.add(map.getVlanDbId()); + } + if (vlanDbIds != null && !vlanDbIds.isEmpty()) { + allocateFromDedicatedRange = true; + } + + try { + if (allocateFromDedicatedRange) { + ip = fetchNewPublicIp(zone.getId(), null, vlanDbIds, ipOwner, vlanType, null, + false, assign, null, isSystem, null); + } + } catch(InsufficientAddressCapacityException e) { + s_logger.warn("All IPs dedicated to account " + ipOwner.getId() + " has been acquired." + + " Now acquiring from the system pool"); + txn.close(); + allocateFromDedicatedRange = false; + } + + if (!allocateFromDedicatedRange) { + ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, + isSystem, null); + } if (ip == null) { @@ -1082,7 +1107,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L AssignIpAddressSearch = _ipAddressDao.createSearchBuilder(); AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ); AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL); - AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.EQ); + AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN); SearchBuilder vlanSearch = _vlanDao.createSearchBuilder(); vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ); vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 4eb620c4243..a8cbaa75017 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -697,15 +697,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new IllegalArgumentException("only ip addresses that belong to a virtual network may be disassociated."); } - // Check for account wide pool. It will have an entry for account_vlan_map. - if (_accountVlanMapDao.findAccountVlanMap(ipVO.getAllocatedToAccountId(), ipVO.getVlanId()) != null) { - //see IPaddressVO.java - InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to" + - " Account wide IP pool and cannot be disassociated"); - ex.addProxyObject("user_ip_address", ipAddressId, "ipAddressId"); - throw ex; - } - // don't allow releasing system ip address if (ipVO.getSystem()) { InvalidParameterValueException ex = new InvalidParameterValueException("Can't release system IP address with specified id"); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index b869d1e21b3..d9a4317d097 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -59,6 +59,7 @@ import org.apache.cloudstack.api.command.admin.storage.*; import org.apache.cloudstack.api.command.admin.systemvm.*; 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.vpc.*; import org.apache.cloudstack.api.command.user.autoscale.*; import org.apache.cloudstack.api.command.user.firewall.*; @@ -2037,6 +2038,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(CreateVlanIpRangeCmd.class); cmdList.add(DeleteVlanIpRangeCmd.class); cmdList.add(ListVlanIpRangesCmd.class); + cmdList.add(DedicatePublicIpRangeCmd.class); + cmdList.add(ReleasePublicIpRangeCmd.class); cmdList.add(AssignVMCmd.class); cmdList.add(MigrateVMCmd.class); cmdList.add(RecoverVMCmd.class); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index fe714c530b9..e74c49124f7 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -690,13 +690,13 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M accountCleanupNeeded = true; } - // delete account specific Virtual vlans (belong to system Public Network) - only when networks are cleaned + // release account specific Virtual vlans (belong to system Public Network) - only when networks are cleaned // up successfully if (networksDeleted) { - if (!_configMgr.deleteAccountSpecificVirtualRanges(accountId)) { + if (!_configMgr.releaseAccountSpecificVirtualRanges(accountId)) { accountCleanupNeeded = true; } else { - s_logger.debug("Account specific Virtual IP ranges " + " are successfully deleted as a part of account id=" + accountId + " cleanup."); + s_logger.debug("Account specific Virtual IP ranges " + " are successfully released as a part of account id=" + accountId + " cleanup."); } } diff --git a/server/test/com/cloud/configuration/ConfigurationManagerTest.java b/server/test/com/cloud/configuration/ConfigurationManagerTest.java new file mode 100755 index 00000000000..ee98d53c922 --- /dev/null +++ b/server/test/com/cloud/configuration/ConfigurationManagerTest.java @@ -0,0 +1,413 @@ +// 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.configuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.lang.reflect.Field; + +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.cloud.configuration.Resource.ResourceType; +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.VlanVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.projects.ProjectManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.net.Ip; + +import junit.framework.Assert; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doNothing; + +public class ConfigurationManagerTest { + + private static final Logger s_logger = Logger.getLogger(ConfigurationManagerTest.class); + + ConfigurationManagerImpl configurationMgr = new ConfigurationManagerImpl(); + + DedicatePublicIpRangeCmd dedicatePublicIpRangesCmd = new DedicatePublicIpRangeCmdExtn(); + Class _dedicatePublicIpRangeClass = dedicatePublicIpRangesCmd.getClass().getSuperclass(); + + ReleasePublicIpRangeCmd releasePublicIpRangesCmd = new ReleasePublicIpRangeCmdExtn(); + Class _releasePublicIpRangeClass = releasePublicIpRangesCmd.getClass().getSuperclass(); + + @Mock AccountManager _accountMgr; + @Mock ProjectManager _projectMgr; + @Mock ResourceLimitService _resourceLimitMgr; + @Mock NetworkManager _networkMgr; + @Mock AccountDao _accountDao; + @Mock VlanDao _vlanDao; + @Mock AccountVlanMapDao _accountVlanMapDao; + @Mock IPAddressDao _publicIpAddressDao; + @Mock DataCenterDao _zoneDao; + @Mock FirewallRulesDao _firewallDao; + + VlanVO vlan = new VlanVO(Vlan.VlanType.VirtualNetwork, "vlantag", "vlangateway","vlannetmask", 1L, "iprange", 1L, 1L, null, null, null); + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + configurationMgr._accountMgr = _accountMgr; + configurationMgr._projectMgr = _projectMgr; + configurationMgr._resourceLimitMgr = _resourceLimitMgr; + configurationMgr._networkMgr = _networkMgr; + configurationMgr._accountDao = _accountDao; + configurationMgr._vlanDao = _vlanDao; + configurationMgr._accountVlanMapDao = _accountVlanMapDao; + configurationMgr._publicIpAddressDao = _publicIpAddressDao; + configurationMgr._zoneDao = _zoneDao; + configurationMgr._firewallDao = _firewallDao; + + Account account = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(configurationMgr._accountMgr.getAccount(anyLong())).thenReturn(account); + when(configurationMgr._accountDao.findActiveAccount(anyString(), anyLong())).thenReturn(account); + when(configurationMgr._accountMgr.getActiveAccountById(anyLong())).thenReturn(account); + + when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(1); + + doNothing().when(configurationMgr._resourceLimitMgr).checkResourceLimit(any(Account.class), + any(ResourceType.class), anyLong()); + + when(configurationMgr._accountVlanMapDao.persist(any(AccountVlanMapVO.class))).thenReturn(new AccountVlanMapVO()); + + when(configurationMgr._vlanDao.acquireInLockTable(anyLong(), anyInt())).thenReturn(vlan); + + UserContext.registerContext(1, account, null, true); + + Field dedicateIdField = _dedicatePublicIpRangeClass.getDeclaredField("id"); + dedicateIdField.setAccessible(true); + dedicateIdField.set(dedicatePublicIpRangesCmd, 1L); + + Field accountNameField = _dedicatePublicIpRangeClass.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(dedicatePublicIpRangesCmd, "accountname"); + + Field projectIdField = _dedicatePublicIpRangeClass.getDeclaredField("projectId"); + projectIdField.setAccessible(true); + projectIdField.set(dedicatePublicIpRangesCmd, null); + + Field domainIdField = _dedicatePublicIpRangeClass.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(dedicatePublicIpRangesCmd, 1L); + + Field releaseIdField = _releasePublicIpRangeClass.getDeclaredField("id"); + releaseIdField.setAccessible(true); + releaseIdField.set(releasePublicIpRangesCmd, 1L); + } + + @Test + public void testDedicatePublicIpRange() throws Exception { + + s_logger.info("Running tests for DedicatePublicIpRange API"); + + /* + * TEST 1: given valid parameters DedicatePublicIpRange should succeed + */ + runDedicatePublicIpRangePostiveTest(); + + /* + * TEST 2: given invalid public ip range DedicatePublicIpRange should fail + */ + runDedicatePublicIpRangeInvalidRange(); + /* + * TEST 3: given public IP range that is already dedicated to a different account DedicatePublicIpRange should fail + */ + runDedicatePublicIpRangeDedicatedRange(); + + /* + * TEST 4: given zone is of type Basic DedicatePublicIpRange should fail + */ + runDedicatePublicIpRangeInvalidZone(); + + /* + * TEST 5: given range is already allocated to a different account DedicatePublicIpRange should fail + */ + runDedicatePublicIpRangeIPAdressAllocated(); + } + + @Test + public void testReleasePublicIpRange() throws Exception { + + s_logger.info("Running tests for DedicatePublicIpRange API"); + + /* + * TEST 1: given valid parameters and no allocated public ip's in the range ReleasePublicIpRange should succeed + */ + runReleasePublicIpRangePostiveTest1(); + + /* + * TEST 2: given valid parameters ReleasePublicIpRange should succeed + */ + runReleasePublicIpRangePostiveTest2(); + + /* + * TEST 3: given range doesn't exist + */ + runReleasePublicIpRangeInvalidIpRange(); + + /* + * TEST 4: given range is not dedicated to any account + */ + runReleaseNonDedicatedPublicIpRange(); + } + + void runDedicatePublicIpRangePostiveTest() throws Exception { + Transaction txn = Transaction.open("runDedicatePublicIpRangePostiveTest"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByAccount(anyLong())).thenReturn(null); + + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + null, null, NetworkType.Advanced, null, null, true, true, null, null); + when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc); + + List ipAddressList = new ArrayList(); + IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false); + ipAddressList.add(ipAddress); + when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList); + + try { + Vlan result = configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd); + Assert.assertNotNull(result); + } catch (Exception e) { + s_logger.info("exception in testing runDedicatePublicIpRangePostiveTest message: " + e.toString()); + } finally { + txn.close("runDedicatePublicIpRangePostiveTest"); + } + } + + void runDedicatePublicIpRangeInvalidRange() throws Exception { + Transaction txn = Transaction.open("runDedicatePublicIpRangeInvalidRange"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(null); + try { + configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Please specify a valid Public IP range id")); + } finally { + txn.close("runDedicatePublicIpRangeInvalidRange"); + } + } + + void runDedicatePublicIpRangeDedicatedRange() throws Exception { + Transaction txn = Transaction.open("runDedicatePublicIpRangeDedicatedRange"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + // public ip range is already dedicated + List accountVlanMaps = new ArrayList(); + AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1); + accountVlanMaps.add(accountVlanMap); + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps); + + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + null, null, NetworkType.Advanced, null, null, true, true, null, null); + when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc); + + List ipAddressList = new ArrayList(); + IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false); + ipAddressList.add(ipAddress); + when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList); + + try { + configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Public IP range has already been dedicated")); + } finally { + txn.close("runDedicatePublicIpRangePublicIpRangeDedicated"); + } + } + + void runDedicatePublicIpRangeInvalidZone() throws Exception { + Transaction txn = Transaction.open("runDedicatePublicIpRangeInvalidZone"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(null); + + // public ip range belongs to zone of type basic + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + null, null, NetworkType.Basic, null, null, true, true, null, null); + when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc); + + List ipAddressList = new ArrayList(); + IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false); + ipAddressList.add(ipAddress); + when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList); + + try { + configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Public IP range can be dedicated to an account only in the zone of type Advanced")); + } finally { + txn.close("runDedicatePublicIpRangeInvalidZone"); + } + } + + void runDedicatePublicIpRangeIPAdressAllocated() throws Exception { + Transaction txn = Transaction.open("runDedicatePublicIpRangeIPAdressAllocated"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByAccount(anyLong())).thenReturn(null); + + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + null, null, NetworkType.Advanced, null, null, true, true, null, null); + when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc); + + // one of the ip addresses of the range is allocated to different account + List ipAddressList = new ArrayList(); + IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false); + ipAddress.setAllocatedToAccountId(1L); + ipAddressList.add(ipAddress); + when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList); + + try { + configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Public IP address in range is already allocated to another account")); + } finally { + txn.close("runDedicatePublicIpRangeIPAdressAllocated"); + } + } + + void runReleasePublicIpRangePostiveTest1() throws Exception { + Transaction txn = Transaction.open("runReleasePublicIpRangePostiveTest1"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + List accountVlanMaps = new ArrayList(); + AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1); + accountVlanMaps.add(accountVlanMap); + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps); + + // no allocated ip's + when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(0); + + when(configurationMgr._accountVlanMapDao.remove(anyLong())).thenReturn(true); + try { + Boolean result = configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd); + Assert.assertTrue(result); + } catch (Exception e) { + s_logger.info("exception in testing runReleasePublicIpRangePostiveTest1 message: " + e.toString()); + } finally { + txn.close("runReleasePublicIpRangePostiveTest1"); + } + } + + void runReleasePublicIpRangePostiveTest2() throws Exception { + Transaction txn = Transaction.open("runReleasePublicIpRangePostiveTest2"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + List accountVlanMaps = new ArrayList(); + AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1); + accountVlanMaps.add(accountVlanMap); + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps); + + when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(1); + + List ipAddressList = new ArrayList(); + IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false); + ipAddressList.add(ipAddress); + when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList); + + when(configurationMgr._firewallDao.countRulesByIpId(anyLong())).thenReturn(0L); + + when(configurationMgr._networkMgr.disassociatePublicIpAddress(anyLong(), anyLong(), any(Account.class))).thenReturn(true); + + when(configurationMgr._vlanDao.releaseFromLockTable(anyLong())).thenReturn(true); + + when(configurationMgr._accountVlanMapDao.remove(anyLong())).thenReturn(true); + try { + Boolean result = configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd); + Assert.assertTrue(result); + } catch (Exception e) { + s_logger.info("exception in testing runReleasePublicIpRangePostiveTest2 message: " + e.toString()); + } finally { + txn.close("runReleasePublicIpRangePostiveTest2"); + } + } + + void runReleasePublicIpRangeInvalidIpRange() throws Exception { + Transaction txn = Transaction.open("runReleasePublicIpRangeInvalidIpRange"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(null); + try { + configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Please specify a valid IP range id")); + } finally { + txn.close("runReleasePublicIpRangeInvalidIpRange"); + } + } + + void runReleaseNonDedicatedPublicIpRange() throws Exception { + Transaction txn = Transaction.open("runReleaseNonDedicatedPublicIpRange"); + + when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan); + + when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(null); + try { + configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("as it not dedicated to any account")); + } finally { + txn.close("runReleaseNonDedicatedPublicIpRange"); + } + } + + + public class DedicatePublicIpRangeCmdExtn extends DedicatePublicIpRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } + + public class ReleasePublicIpRangeCmdExtn extends ReleasePublicIpRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } +} diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java old mode 100644 new mode 100755 index b0063fa2e2e..a03e361d8c1 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -40,7 +40,9 @@ import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; 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.UpdateZoneCmd; @@ -544,7 +546,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationManager#deleteAccountSpecificVirtualRanges(long) */ @Override - public boolean deleteAccountSpecificVirtualRanges(long accountId) { + public boolean releaseAccountSpecificVirtualRanges(long accountId) { // TODO Auto-generated method stub return false; } @@ -613,5 +615,24 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return null; } + @Override + public Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd) + throws ResourceAllocationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean releasePublicIpRange(long userId, long vlanDbId, + Account caller) { + // TODO Auto-generated method stub + return false; + } } diff --git a/test/integration/component/test_public_ip_range.py b/test/integration/component/test_public_ip_range.py new file mode 100755 index 00000000000..f2c967f8d57 --- /dev/null +++ b/test/integration/component/test_public_ip_range.py @@ -0,0 +1,173 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" P1 tests for Dedicating Public IP addresses +""" +#Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +import datetime + +class Services: + """Test Dedicating Public IP addresses + """ + + def __init__(self): + self.services = { + "domain": { + "name": "Domain", + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + "password": "password", + }, + "gateway": "10.102.197.1", + "netmask": "255.255.255.0", + "forvirtualnetwork": "true", + "startip": "10.102.197.70", + "endip": "10.102.197.73", + "zoneid": "1", + "podid": "", + "vlan": "101", + } + +class TesDedicatePublicIPRange(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TesDedicatePublicIPRange, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + # Create Account + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup = [ + cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags = ["publiciprange", "dedicate", "release"]) + def test_dedicatePublicIpRange(self): + """Test public IP range dedication + """ + + # Validate the following: + # 1. Create a Public IP range + # 2. Created IP range should be present, verify with listVlanIpRanges + # 3. Dedicate the created IP range to user account + # 4. Verify IP range is dedicated, verify with listVlanIpRanges + # 5. Release the dedicated Public IP range back to the system + # 6. Verify IP range has been released, verify with listVlanIpRanges + # 7. Delete the Public IP range + + self.debug("Creating Public IP range") + self.public_ip_range = PublicIpRange.create( + self.api_client, + self.services + ) + list_public_ip_range_response = PublicIpRange.list( + self.apiclient, + id=self.public_ip_range.vlan.id + ) + self.debug( + "Verify listPublicIpRanges response for public ip ranges: %s" \ + % self.public_ip_range.vlan.id + ) + self.assertEqual( + isinstance(list_public_ip_range_response, list), + True, + "Check for list Public IP range response" + ) + public_ip_response = list_public_ip_range_response[0] + self.assertEqual( + public_ip_response.id, + self.public_ip_range.vlan.id, + "Check public ip range response id is in listVlanIpRanges" + ) + + self.debug("Dedicating Public IP range"); + dedicate_public_ip_range_response = PublicIpRange.dedicate( + self.apiclient, + self.public_ip_range.vlan.id, + account=self.account.account.name, + domainid=self.account.account.domainid + ) + list_public_ip_range_response = PublicIpRange.list( + self.apiclient, + id=self.public_ip_range.vlan.id + ) + public_ip_response = list_public_ip_range_response[0] + self.assertEqual( + public_ip_response.account, + self.account.account.name, + "Check account name is in listVlanIpRanges as the account public ip range is dedicated to" + ) + + self.debug("Releasing Public IP range"); + self.public_ip_range.release(self.apiclient) + list_public_ip_range_response = PublicIpRange.list( + self.apiclient, + id=self.public_ip_range.vlan.id + ) + public_ip_response = list_public_ip_range_response[0] + self.assertEqual( + public_ip_response.account, + "system", + "Check account name is system account in listVlanIpRanges" + ) + + self.debug("Deleting Public IP range"); + self.public_ip_range.delete(self.apiclient) + + return + diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py old mode 100644 new mode 100755 index d27ab3b2903..3df68ab7853 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -1873,7 +1873,7 @@ class PublicIpRange: """Delete VlanIpRange""" cmd = deleteVlanIpRange.deleteVlanIpRangeCmd() - cmd.id = self.id + cmd.id = self.vlan.id apiclient.deleteVlanIpRange(cmd) @classmethod @@ -1884,6 +1884,23 @@ class PublicIpRange: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVlanIpRanges(cmd)) + @classmethod + def dedicate(cls, apiclient, id, account=None, domainid=None, projectid=None): + """Dedicate VLAN IP range""" + + cmd = dedicatePublicIpRange.dedicatePublicIpRangeCmd() + cmd.id = id + cmd.account = account + cmd.domainid = domainid + cmd.projectid = projectid + return PublicIpRange(apiclient.dedicatePublicIpRange(cmd).__dict__) + + def release(self, apiclient): + """Release VLAN IP range""" + + cmd = releasePublicIpRange.releasePublicIpRangeCmd() + cmd.id = self.vlan.id + return apiclient.releasePublicIpRange(cmd) class SecondaryStorage: """Manage Secondary storage""" From fd84c56bf96aba134fa2656cf2de525ad4fc2f25 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 10 Apr 2013 16:22:29 +0530 Subject: [PATCH 068/107] moving the integration test to the smoke folder The smoke folder is for the bvts and that's where maven+marvin will pick up the tests tagged for the simulator run. Signed-off-by: Prasanna Santhanam --- test/integration/{component => smoke}/test_public_ip_range.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/integration/{component => smoke}/test_public_ip_range.py (98%) diff --git a/test/integration/component/test_public_ip_range.py b/test/integration/smoke/test_public_ip_range.py similarity index 98% rename from test/integration/component/test_public_ip_range.py rename to test/integration/smoke/test_public_ip_range.py index f2c967f8d57..a7aad6b795c 100755 --- a/test/integration/component/test_public_ip_range.py +++ b/test/integration/smoke/test_public_ip_range.py @@ -96,7 +96,7 @@ class TesDedicatePublicIPRange(cloudstackTestCase): raise Exception("Warning: Exception during cleanup : %s" % e) return - @attr(tags = ["publiciprange", "dedicate", "release"]) + @attr(tags = ["simulator", "publiciprange", "dedicate", "release"]) def test_dedicatePublicIpRange(self): """Test public IP range dedication """ From 0b17b624dbfa517e48cbcb09fb695370d4a8ac03 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 10 Apr 2013 16:32:19 +0530 Subject: [PATCH 069/107] Fixing the apidoc for the new api dedicatePublicIpRange Signed-off-by: Prasanna Santhanam --- tools/apidoc/gen_toc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 2d5292b8426..5403adb99df 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -83,6 +83,7 @@ known_categories = { 'Configuration': 'Configuration', 'Capabilities': 'Configuration', 'Pod': 'Pod', + 'PublicIpRange': 'Network', 'Zone': 'Zone', 'NetworkOffering': 'Network Offering', 'NetworkACL': 'Network ACL', From 45f852bec261c9a05e04c3424bf408859268fef3 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 10 Apr 2013 17:15:47 +0530 Subject: [PATCH 070/107] nose won't discover the test if it is executable. Changing test_public_ip_range.py to 644 Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_public_ip_range.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 test/integration/smoke/test_public_ip_range.py diff --git a/test/integration/smoke/test_public_ip_range.py b/test/integration/smoke/test_public_ip_range.py old mode 100755 new mode 100644 From 7b4e1953d87555d432386ea34aebd15bce257f16 Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Fri, 12 Apr 2013 12:08:01 -0700 Subject: [PATCH 071/107] QuickCloud: accidental commit, removing --- .../AgentBasedConsoleProxyManager.java.orig | 298 ------------------ 1 file changed, 298 deletions(-) delete mode 100755 server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java.orig diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java.orig b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java.orig deleted file mode 100755 index 134d59d0065..00000000000 --- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java.orig +++ /dev/null @@ -1,298 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.consoleproxy; - -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.GetVncPortAnswer; -import com.cloud.agent.api.GetVncPortCommand; -import com.cloud.agent.api.StartupProxyCommand; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.info.ConsoleProxyInfo; -import com.cloud.keystore.KeystoreManager; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.component.ManagerBase; -import com.cloud.vm.ConsoleProxyVO; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.dao.ConsoleProxyDao; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; - -@Local(value = { ConsoleProxyManager.class }) -public class AgentBasedConsoleProxyManager extends ManagerBase implements ConsoleProxyManager { - private static final Logger s_logger = Logger.getLogger(AgentBasedConsoleProxyManager.class); - - @Inject - protected HostDao _hostDao; - @Inject - protected UserVmDao _userVmDao; - private String _instance; - protected String _consoleProxyUrlDomain; - @Inject - private VMInstanceDao _instanceDao; - private ConsoleProxyListener _listener; - protected int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; - protected int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT; - protected boolean _sslEnabled = false; - @Inject - AgentManager _agentMgr; - @Inject - VirtualMachineManager _itMgr; - @Inject - protected ConsoleProxyDao _cpDao; - @Inject - protected KeystoreManager _ksMgr; - - @Inject ConfigurationDao _configDao; - - public class AgentBasedAgentHook extends AgentHookBase { - - public AgentBasedAgentHook(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao cfgDao, - KeystoreManager ksMgr, AgentManager agentMgr) { - super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr); - } - - @Override - protected HostVO findConsoleProxyHost(StartupProxyCommand cmd) { - return _hostDao.findByGuid(cmd.getGuid()); - } - - } - - public int getVncPort(VMInstanceVO vm) { - if (vm.getHostId() == null) { - return -1; - } - GetVncPortAnswer answer = (GetVncPortAnswer) _agentMgr.easySend(vm.getHostId(), new GetVncPortCommand(vm.getId(), vm.getHostName())); - return (answer == null || !answer.getResult()) ? -1 : answer.getPort(); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - - if (s_logger.isInfoEnabled()) { - s_logger.info("Start configuring AgentBasedConsoleProxyManager"); - } - - Map configs = _configDao.getConfiguration("management-server", params); - String value = configs.get("consoleproxy.url.port"); - if (value != null) { - _consoleProxyUrlPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); - } - - value = configs.get("consoleproxy.port"); - if (value != null) { - _consoleProxyPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT); - } - - value = configs.get("consoleproxy.sslEnabled"); - if (value != null && value.equalsIgnoreCase("true")) { - _sslEnabled = true; - } - - _instance = configs.get("instance.name"); - - _consoleProxyUrlDomain = configs.get("consoleproxy.url.domain"); - - _listener = - new ConsoleProxyListener(new AgentBasedAgentHook(_instanceDao, _hostDao, _configDao, _ksMgr, _agentMgr)); - _agentMgr.registerForHostEvents(_listener, true, true, false); - - if (s_logger.isInfoEnabled()) { - s_logger.info("AgentBasedConsoleProxyManager has been configured. SSL enabled: " + _sslEnabled); - } - return true; - } - - HostVO findHost(VMInstanceVO vm) { - return _hostDao.findById(vm.getHostId()); - } - - @Override - public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { - UserVmVO userVm = _userVmDao.findById(userVmId); - if (userVm == null) { - s_logger.warn("User VM " + userVmId + " no longer exists, return a null proxy for user vm:" + userVmId); - return null; - } - - HostVO host = findHost(userVm); - if (host != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Assign embedded console proxy running at " + host.getName() + " to user vm " + userVmId + " with public IP " - + host.getPublicIpAddress()); - } - - // only private IP, public IP, host id have meaningful values, rest - // of all are place-holder values - String publicIp = host.getPublicIpAddress(); - if (publicIp == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Host " + host.getName() + "/" + host.getPrivateIpAddress() - + " does not have public interface, we will return its private IP for cosole proxy."); - } - publicIp = host.getPrivateIpAddress(); - } - - int urlPort = _consoleProxyUrlPort; - - if (host.getProxyPort() != null && host.getProxyPort().intValue() > 0) { - urlPort = host.getProxyPort().intValue(); - } - - return new ConsoleProxyInfo(_sslEnabled, publicIp, _consoleProxyPort, urlPort, _consoleProxyUrlDomain); - } else { - s_logger.warn("Host that VM is running is no longer available, console access to VM " + userVmId + " will be temporarily unavailable."); - } - return null; - } - - - - - @Override - public ConsoleProxyVO startProxy(long proxyVmId) { - return null; - } - - @Override - public boolean destroyProxy(long proxyVmId) { - return false; - } - - @Override - public boolean rebootProxy(long proxyVmId) { - return false; - } - - @Override - public boolean stopProxy(long proxyVmId) { - return false; - } - - @Override - public void setManagementState(ConsoleProxyManagementState state) { - } - - @Override - public ConsoleProxyManagementState getManagementState() { - return null; - } - - @Override - public void resumeLastManagementState() { - } - - @Override - public String getName() { - return _name; - } -<<<<<<< HEAD - - @Override - public Long convertToId(String vmName) { - if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) { - return null; - } - return VirtualMachineName.getConsoleProxyId(vmName); - } - - @Override - public ConsoleProxyVO findByName(String name) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ConsoleProxyVO findById(long id) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ConsoleProxyVO persist(ConsoleProxyVO vm) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile profile) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { - // TODO Auto-generated method stub - } - - @Override - public void finalizeExpunge(ConsoleProxyVO proxy) { - } - - @Override - public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, - ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, - InsufficientCapacityException { - //not supported - throw new UnsupportedOperationException("Plug nic is not supported for vm of type " + vm.getType()); - } - - - @Override - public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, - ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException { - //not supported - throw new UnsupportedOperationException("Unplug nic is not supported for vm of type " + vm.getType()); - } - - @Override - public void prepareStop(VirtualMachineProfile profile) { - } -} -======= -} ->>>>>>> QuickCloud: refactor to avoid copy paste of authentication and startup code From 4b1a9f146c7316ba885d0889bd10ae09074e1169 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Fri, 12 Apr 2013 11:29:16 -0700 Subject: [PATCH 072/107] Fix CLOUDSTACK-1987: Deleted service offering still shows for domain users. Also extend this fix for Disk offering as well. --- .../com/cloud/api/query/QueryManagerImpl.java | 65 ++++++------------- 1 file changed, 19 insertions(+), 46 deletions(-) diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index ea58427b3c8..5ffc2db995c 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -1941,7 +1941,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); isAscending = (isAscending == null ? true : isAscending); Filter searchFilter = new Filter(DiskOfferingJoinVO.class, "sortKey", isAscending, cmd.getStartIndex(), cmd.getPageSizeVal()); - SearchBuilder sb = _diskOfferingJoinDao.createSearchBuilder(); + SearchCriteria sc = _diskOfferingJoinDao.createSearchCriteria(); Account account = UserContext.current().getCaller(); @@ -1956,9 +1956,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { if (account.getType() == Account.ACCOUNT_TYPE_ADMIN || isPermissible(account.getDomainId(), domainId) ) { // check if the user's domain == do's domain || user's domain is // a child of so's domain for non-root users - sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ); - SearchCriteria sc = sb.create(); - sc.setParameters("domainId", domainId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); return _diskOfferingJoinDao.searchAndCount(sc, searchFilter); } else { throw new PermissionDeniedException("The account:" + account.getAccountName() @@ -1966,11 +1964,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { } } - sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); - sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); - - boolean includePublicOfferings = false; List domainIds = null; // For non-root users, only return all offerings for the user's domain, and everything above till root if ((account.getType() == Account.ACCOUNT_TYPE_NORMAL || account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) @@ -1987,16 +1981,17 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { domainRecord = _domainDao.findById(domainRecord.getParent()); domainIds.add(domainRecord.getId()); } - sb.and("domainIdIn", sb.entity().getDomainId(), SearchCriteria.Op.IN); + + SearchCriteria spc = _diskOfferingJoinDao.createSearchCriteria(); - // include also public offering if no keyword, name and id specified - if ( keyword == null && name == null && id == null ){ - includePublicOfferings = true; - } + spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); + spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as where + sc.addAnd("domainId", SearchCriteria.Op.SC, spc); + sc.addAnd("systemUse", SearchCriteria.Op.EQ, false); // non-root users should not see system offering at all + } - SearchCriteria sc = sb.create(); - if (keyword != null) { + if (keyword != null) { SearchCriteria ssc = _diskOfferingJoinDao.createSearchCriteria(); ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%"); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); @@ -2004,26 +1999,14 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sc.addAnd("name", SearchCriteria.Op.SC, ssc); } - if (name != null) { - sc.setParameters("name", "%" + name + "%"); - } - if (id != null) { - sc.setParameters("id", id); + sc.addAnd("id", SearchCriteria.Op.EQ, id); } - if (domainIds != null ){ - sc.setParameters("domainIdIn", domainIds.toArray()); + if (name != null) { + sc.addAnd("name", SearchCriteria.Op.EQ, name); } - - if (includePublicOfferings){ - SearchCriteria spc = _diskOfferingJoinDao.createSearchCriteria(); - spc.addAnd("domainId", SearchCriteria.Op.NULL); - spc.addAnd("systemUse", SearchCriteria.Op.EQ, false); - - sc.addOr("systemUse", SearchCriteria.Op.SC, spc); - } - + // FIXME: disk offerings should search back up the hierarchy for // available disk offerings... /* @@ -2100,10 +2083,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { } } - boolean includePublicOfferings = false; + // boolean includePublicOfferings = false; if ((caller.getType() == Account.ACCOUNT_TYPE_NORMAL || caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { - // For non-root users + // For non-root users. if (isSystem) { throw new InvalidParameterValueException("Only root admins can access system's offering"); } @@ -2122,13 +2105,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { SearchCriteria spc = _srvOfferingJoinDao.createSearchCriteria(); spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); - spc.addOr("domainId", SearchCriteria.Op.NULL); + spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as where sc.addAnd("domainId", SearchCriteria.Op.SC, spc); - // include also public offering if no keyword, name and id specified - if ( keyword == null && name == null && id == null ){ - includePublicOfferings = true; - } } else { // for root users @@ -2171,24 +2150,18 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { } if (isSystem != null) { + // note that for non-root users, isSystem is always false when control comes to here sc.addAnd("systemUse", SearchCriteria.Op.EQ, isSystem); } if (name != null) { - sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + name + "%"); + sc.addAnd("name", SearchCriteria.Op.EQ, name); } if (vmTypeStr != null) { sc.addAnd("vm_type", SearchCriteria.Op.EQ, vmTypeStr); } - if (includePublicOfferings){ - SearchCriteria spc = _srvOfferingJoinDao.createSearchCriteria(); - spc.addAnd("domainId", SearchCriteria.Op.NULL); - spc.addAnd("systemUse", SearchCriteria.Op.EQ, false); - sc.addOr("systemUse", SearchCriteria.Op.SC, spc); - } - return _srvOfferingJoinDao.searchAndCount(sc, searchFilter); } From e354807e05312ba9d586544964ae99371803d145 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Fri, 12 Apr 2013 15:31:16 -0700 Subject: [PATCH 073/107] Added the AffinityGroupProcessor definition to nonossComponentContext.xml.in to avoid auto-wiring failure for non-oss build --- client/tomcatconf/nonossComponentContext.xml.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index fc8a9cd5409..3ede2634285 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -339,5 +339,13 @@ + + + + + + From 15c26195c52e3cd0f276bbdf5c0a990b8a917af7 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Thu, 11 Apr 2013 10:25:46 +0200 Subject: [PATCH 074/107] debian: Package the AWSAPI bridge --- debian/cloudstack-awsapi.install | 10 +++++++++- debian/rules | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/debian/cloudstack-awsapi.install b/debian/cloudstack-awsapi.install index 02ba66829ef..675b84def74 100644 --- a/debian/cloudstack-awsapi.install +++ b/debian/cloudstack-awsapi.install @@ -15,4 +15,12 @@ # specific language governing permissions and limitations # under the License. -/var/log/cloudstack/awsapi \ No newline at end of file +/etc/cloudstack/management/cloud-bridge.properties +/etc/cloudstack/management/commons-logging.properties +/etc/cloudstack/management/crypto.properties +/etc/cloudstack/management/xes.keystore +/etc/cloudstack/management/ec2-service.properties +/var/log/cloudstack/awsapi +/usr/bin/cloudstack-setup-bridge +/usr/bin/cloudstack-aws-api-register +/usr/share/cloudstack-bridge \ No newline at end of file diff --git a/debian/rules b/debian/rules index 4e55c71048c..f5f68aba03d 100755 --- a/debian/rules +++ b/debian/rules @@ -34,7 +34,7 @@ build: build-indep build-indep: build-indep-stamp build-indep-stamp: configure - mvn package -DskipTests -Dsystemvm \ + mvn -Pawsapi package -DskipTests -Dsystemvm \ -Dcs.replace.properties=replace.properties.tmp touch $@ @@ -147,7 +147,25 @@ install: install -D packaging/debian/init/cloud-usage $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-usage # cloudstack-awsapi + mkdir $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/awsapi mkdir $(DESTDIR)/var/log/$(PACKAGE)/awsapi + mkdir $(DESTDIR)/usr/share/$(PACKAGE)-bridge + mkdir -p $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi + mkdir $(DESTDIR)/usr/share/$(PACKAGE)-bridge/setup + cp -r awsapi/target/cloud-awsapi-$(VERSION)-SNAPSHOT/* $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi + install -D awsapi-setup/setup/cloud-setup-bridge $(DESTDIR)/usr/bin/cloudstack-setup-bridge + install -D awsapi-setup/setup/cloudstack-aws-api-register $(DESTDIR)/usr/bin/cloudstack-aws-api-register + cp -r awsapi-setup/db/mysql/* $(DESTDIR)/usr/share/$(PACKAGE)-bridge/setup + for i in applicationContext.xml cloud-bridge.properties commons-logging.properties crypto.properties xes.keystore ec2-service.properties; do \ + mv $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/$$i $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/management/; \ + done + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/log4j-vmops.xml + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/log4j.properties + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/db.properties + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/LICENSE.txt + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/NOTICE.txt + rm $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/services.xml + rm -rf $(DESTDIR)/usr/share/$(PACKAGE)-bridge/webapps/awsapi/WEB-INF/classes/META-INF dh_installdirs dh_install From c5b10a71df67cd03b02ae9eb69fc17f9c7161a0b Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sat, 13 Apr 2013 11:13:01 +0200 Subject: [PATCH 075/107] tools: Add option to specify publican configuration file for building the docs --- tools/build/build_docs.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/build/build_docs.sh b/tools/build/build_docs.sh index 62617a3df9d..11b24141d95 100755 --- a/tools/build/build_docs.sh +++ b/tools/build/build_docs.sh @@ -20,6 +20,7 @@ sourcedir=~/incubator-cloudstack/ common_content_dir=/usr/share/publican/Common_Content publican_path=/usr/bin/publican output_format="html,pdf" +config="publican-adminguide.cfg" usage(){ echo "usage: $0 [-s source dir] [-c publican common content] [-p path to publican]" @@ -27,10 +28,11 @@ usage(){ echo " -c sets the public common content directory (defaults to $common_content_dir)" echo " -p sets the path to the publican binary (defaults to $publican_path)" echo " -f sets the output format (defaults to $output_format)" - echo " -h" + echo " -g sets the publican config file (defaults to $config)" + echo " -h show this help" } -while getopts v:s:c:p:f:h opt +while getopts v:s:c:p:f:g:h opt do case "$opt" in v) version="$OPTARG";; @@ -38,6 +40,7 @@ do c) common_content_dir="$OPTARG";; p) publican_path="$OPTARG";; f) output_format="$OPTARG";; + g) config="$OPTARG";; h) usage exit 0;; \?) @@ -59,5 +62,5 @@ fi cd $sourcedir/docs cp -R /usr/share/publican/Common_Content . ln -s $sourcedir/docs/publican-cloudstack Common_Content/cloudstack -publican build --config=publican-installation.cfg --formats $output_format --langs en-US --common_content=$sourcedir/docs/Common_Content -rm -r Common_Content \ No newline at end of file +publican build --config=$config --formats $output_format --langs en-US --common_content=$sourcedir/docs/Common_Content +rm -r Common_Content From ed2aa9f9da2afcb6c28eff1ebbf79baa5a2e25dd Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sat, 13 Apr 2013 11:13:26 +0200 Subject: [PATCH 076/107] CLOUDSTACK-574: Add Ceph RBD documentation This commit also add some extra information about NFS and iSCSI Primary Storage on a KVM hypervisor. --- docs/en-US/hypervisor-kvm-install-flow.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en-US/hypervisor-kvm-install-flow.xml b/docs/en-US/hypervisor-kvm-install-flow.xml index 6cc73e4fdfa..7dfd47d2e52 100644 --- a/docs/en-US/hypervisor-kvm-install-flow.xml +++ b/docs/en-US/hypervisor-kvm-install-flow.xml @@ -34,4 +34,5 @@ +
From 20614598bfd91f09c0d4407265df0701896c26a1 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Sat, 13 Apr 2013 00:09:15 +0000 Subject: [PATCH 077/107] Fixed typos Signed-off-by: Milamber --- api/src/com/cloud/vm/DiskProfile.java | 2 +- client/tomcatconf/applicationContext.xml.in | 6 +++--- .../engine/subsystem/api/storage/CommandResult.java | 2 +- .../api/storage/ObjectInDataStoreStateMachine.java | 2 +- .../image/motion/DefaultImageMotionStrategy.java | 4 ++-- ...java => MockHypervisorHostEndPointRpcServer.java} | 4 ++-- .../integration-test/test/resource/component.xml | 2 +- ...ver.java => HypervisorHostEndPointRpcServer.java} | 12 ++++++------ .../allocator/AbstractStoragePoolAllocator.java | 2 +- .../allocator/ZoneWideStoragePoolAllocator.java | 2 +- .../storage/datastore/DataObjectManagerImpl.java | 6 +++--- .../driver/DefaultPrimaryDataStoreDriverImpl.java | 4 ++-- .../DefaultPrimaryDatastoreProviderImpl.java | 6 +++--- .../storage/volume/TemplateInstallStrategyImpl.java | 6 +++--- .../dns-notifier/resources/components-example.xml | 2 +- .../CloudStackPrimaryDataStoreProviderImpl.java | 6 +++--- ...llocator.java => ExternalIpAddressAllocator.java} | 6 +++--- server/src/com/cloud/network/IpAddrAllocator.java | 2 +- .../src/com/cloud/template/TemplateManagerImpl.java | 2 +- server/test/resources/network-mgr-component.xml | 2 +- .../com/cloud/utils/component/ComponentContext.java | 4 ++-- 21 files changed, 42 insertions(+), 42 deletions(-) rename engine/storage/integration-test/test/org/apache/cloudstack/storage/test/{MockHypervsiorHostEndPointRpcServer.java => MockHypervisorHostEndPointRpcServer.java} (95%) rename engine/storage/src/org/apache/cloudstack/storage/{HypervsiorHostEndPointRpcServer.java => HypervisorHostEndPointRpcServer.java} (92%) rename server/src/com/cloud/network/{ExteralIpAddressAllocator.java => ExternalIpAddressAllocator.java} (96%) diff --git a/api/src/com/cloud/vm/DiskProfile.java b/api/src/com/cloud/vm/DiskProfile.java index e34a3340e9e..e3a3386d1e5 100644 --- a/api/src/com/cloud/vm/DiskProfile.java +++ b/api/src/com/cloud/vm/DiskProfile.java @@ -139,7 +139,7 @@ public class DiskProfile { this.hyperType = hyperType; } - public HypervisorType getHypersorType() { + public HypervisorType getHypervisorType() { return this.hyperType; } diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 0d13877b49b..15cd6fe0f13 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -454,11 +454,11 @@ - + - + @@ -733,7 +733,7 @@ - + diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CommandResult.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CommandResult.java index 6b6139b937d..cc45914dc41 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CommandResult.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CommandResult.java @@ -34,7 +34,7 @@ public class CommandResult { return !this.success; } - public void setSucess(boolean success) { + public void setSuccess(boolean success) { this.success = success; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java index 726ce0821c5..f619ef4e976 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java @@ -26,7 +26,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject - + diff --git a/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPointRpcServer.java similarity index 92% rename from engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java rename to engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPointRpcServer.java index f441f39ddfa..bc217769d91 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/HypervsiorHostEndPointRpcServer.java +++ b/engine/storage/src/org/apache/cloudstack/storage/HypervisorHostEndPointRpcServer.java @@ -36,16 +36,16 @@ import com.cloud.agent.api.Command; import com.cloud.utils.exception.CloudRuntimeException; @Component -public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { - private static final Logger s_logger = Logger.getLogger(HypervsiorHostEndPointRpcServer.class); +public class HypervisorHostEndPointRpcServer implements HostEndpointRpcServer { + private static final Logger s_logger = Logger.getLogger(HypervisorHostEndPointRpcServer.class); @Inject private RpcProvider rpcProvider; - public HypervsiorHostEndPointRpcServer() { + public HypervisorHostEndPointRpcServer() { } - public HypervsiorHostEndPointRpcServer(RpcProvider rpcProvider) { + public HypervisorHostEndPointRpcServer(RpcProvider rpcProvider) { rpcProvider = rpcProvider; rpcProvider.registerRpcServiceEndpoint(RpcServiceDispatcher.getDispatcher(this)); } @@ -91,7 +91,7 @@ public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { @Override public Answer sendCommand(HypervisorHostEndPoint host, Command command) { SendCommandContext context = new SendCommandContext(null); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().sendCommandCallback(null, null)) .setContext(context); @@ -109,7 +109,7 @@ public class HypervsiorHostEndPointRpcServer implements HostEndpointRpcServer { return context.getAnswer(); } - protected Object sendCommandCallback(AsyncCallbackDispatcher callback, SendCommandContext context) { + protected Object sendCommandCallback(AsyncCallbackDispatcher callback, SendCommandContext context) { context.setAnswer((Answer)callback.getResult()); synchronized(context) { context.notify(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 6334ca7f2dc..3a66b859b39 100755 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -176,7 +176,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement Long clusterId = pool.getClusterId(); ClusterVO cluster = _clusterDao.findById(clusterId); - if (!(cluster.getHypervisorType() == dskCh.getHypersorType())) { + if (!(cluster.getHypervisorType() == dskCh.getHypervisorType())) { if (s_logger.isDebugEnabled()) { s_logger.debug("StoragePool's Cluster does not have required hypervisorType, skipping this pool"); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index 7c6c946765f..1d3cd819d70 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -57,7 +57,7 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool"); List suitablePools = new ArrayList(); - HypervisorType hypervisor = dskCh.getHypersorType(); + HypervisorType hypervisor = dskCh.getHypervisorType(); if (hypervisor != null) { if (hypervisor != HypervisorType.KVM) { s_logger.debug("Only kvm supports zone wide storage"); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java index 218f9013a17..9d1afbeacad 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java @@ -109,7 +109,7 @@ public class DataObjectManagerImpl implements DataObjectManager { if (obj == null) { CreateCmdResult result = new CreateCmdResult( null, null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return; @@ -124,7 +124,7 @@ public class DataObjectManagerImpl implements DataObjectManager { data, store); } catch (Exception e) { CreateCmdResult result = new CreateCmdResult(null, null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return; @@ -153,7 +153,7 @@ public class DataObjectManagerImpl implements DataObjectManager { s_logger.debug("state transation failed", e1); } CreateCmdResult result = new CreateCmdResult(null, null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index 6d0c2c6862b..e5ee742f5ba 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -144,12 +144,12 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver CreateVolumeAnswer answer = (CreateVolumeAnswer)callback.getResult(); CommandResult result = new CommandResult(); if (answer == null || answer.getDetails() != null) { - result.setSucess(false); + result.setSuccess(false); if (answer != null) { result.setResult(answer.getDetails()); } } else { - result.setSucess(true); + result.setSuccess(true); VolumeObject volume = context.getVolume(); volume.setPath(answer.getVolumeUuid()); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java index 46fa738e294..8c674dc0444 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java @@ -42,7 +42,7 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv @Inject PrimaryDataStoreProviderManager storeMgr; - protected DataStoreLifeCycle lifecyle; + protected DataStoreLifeCycle lifecycle; protected String uuid; protected long id; @Override @@ -52,12 +52,12 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv @Override public DataStoreLifeCycle getDataStoreLifeCycle() { - return this.lifecyle; + return this.lifecycle; } @Override public boolean configure(Map params) { - lifecyle = ComponentContext.inject(DefaultPrimaryDataStoreLifeCycleImpl.class); + lifecycle = ComponentContext.inject(DefaultPrimaryDataStoreLifeCycleImpl.class); driver = ComponentContext.inject(DefaultPrimaryDataStoreDriverImpl.class); listener = ComponentContext.inject(DefaultHostListener.class); return true; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java index 5f1735c180a..e09961913de 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java @@ -107,7 +107,7 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { if (obj == null) { CreateBaseImageResult result = new CreateBaseImageResult( null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return null; @@ -122,7 +122,7 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { template, store); } catch (Exception e) { CreateBaseImageResult result = new CreateBaseImageResult(null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return null; @@ -145,7 +145,7 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { s_logger.debug("state transation failed", e1); } CreateBaseImageResult result = new CreateBaseImageResult(null); - result.setSucess(false); + result.setSuccess(false); result.setResult(e.toString()); callback.complete(result); return null; diff --git a/plugins/network-elements/dns-notifier/resources/components-example.xml b/plugins/network-elements/dns-notifier/resources/components-example.xml index 6493e748fae..2e9c5bedc63 100755 --- a/plugins/network-elements/dns-notifier/resources/components-example.xml +++ b/plugins/network-elements/dns-notifier/resources/components-example.xml @@ -86,7 +86,7 @@ under the License. - + diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/provider/CloudStackPrimaryDataStoreProviderImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/provider/CloudStackPrimaryDataStoreProviderImpl.java index 4d46d99fab3..826f07ae07e 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/provider/CloudStackPrimaryDataStoreProviderImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/provider/CloudStackPrimaryDataStoreProviderImpl.java @@ -37,7 +37,7 @@ public class CloudStackPrimaryDataStoreProviderImpl implements private final String providerName = "ancient primary data store provider"; protected PrimaryDataStoreDriver driver; protected HypervisorHostListener listener; - protected DataStoreLifeCycle lifecyle; + protected DataStoreLifeCycle lifecycle; CloudStackPrimaryDataStoreProviderImpl() { @@ -50,12 +50,12 @@ public class CloudStackPrimaryDataStoreProviderImpl implements @Override public DataStoreLifeCycle getDataStoreLifeCycle() { - return this.lifecyle; + return this.lifecycle; } @Override public boolean configure(Map params) { - lifecyle = ComponentContext.inject(CloudStackPrimaryDataStoreLifeCycleImpl.class); + lifecycle = ComponentContext.inject(CloudStackPrimaryDataStoreLifeCycleImpl.class); driver = ComponentContext.inject(CloudStackPrimaryDataStoreDriverImpl.class); listener = ComponentContext.inject(DefaultHostListener.class); return true; diff --git a/server/src/com/cloud/network/ExteralIpAddressAllocator.java b/server/src/com/cloud/network/ExternalIpAddressAllocator.java similarity index 96% rename from server/src/com/cloud/network/ExteralIpAddressAllocator.java rename to server/src/com/cloud/network/ExternalIpAddressAllocator.java index 2b78712b86f..f24fa2d29b9 100644 --- a/server/src/com/cloud/network/ExteralIpAddressAllocator.java +++ b/server/src/com/cloud/network/ExternalIpAddressAllocator.java @@ -37,8 +37,8 @@ import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; @Local(value=IpAddrAllocator.class) -public class ExteralIpAddressAllocator extends AdapterBase implements IpAddrAllocator{ - private static final Logger s_logger = Logger.getLogger(ExteralIpAddressAllocator.class); +public class ExternalIpAddressAllocator extends AdapterBase implements IpAddrAllocator{ + private static final Logger s_logger = Logger.getLogger(ExternalIpAddressAllocator.class); String _name; @Inject ConfigurationDao _configDao = null; @Inject IPAddressDao _ipAddressDao = null; @@ -135,7 +135,7 @@ public class ExteralIpAddressAllocator extends AdapterBase implements IpAddrAllo } @Override - public boolean exteralIpAddressAllocatorEnabled() { + public boolean externalIpAddressAllocatorEnabled() { return _isExternalIpAllocatorEnabled; } diff --git a/server/src/com/cloud/network/IpAddrAllocator.java b/server/src/com/cloud/network/IpAddrAllocator.java index d79125b3741..6cdf5972080 100644 --- a/server/src/com/cloud/network/IpAddrAllocator.java +++ b/server/src/com/cloud/network/IpAddrAllocator.java @@ -52,5 +52,5 @@ public interface IpAddrAllocator extends Adapter { public IpAddr getPrivateIpAddress(String macAddr, long dcId, long podId); public boolean releasePublicIpAddress(String ip, long dcId, long podId); public boolean releasePrivateIpAddress(String ip, long dcId, long podId); - public boolean exteralIpAddressAllocatorEnabled(); + public boolean externalIpAddressAllocatorEnabled(); } diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 2892e0081c2..576440a2ce7 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -273,7 +273,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (type == HypervisorType.BareMetal) { adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.BareMetal.getName()); } else { - // see HyervisorTemplateAdapter + // see HypervisorTemplateAdapter adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.Hypervisor.getName()); } diff --git a/server/test/resources/network-mgr-component.xml b/server/test/resources/network-mgr-component.xml index 42d3c2ebdb1..b55a68b0fcf 100644 --- a/server/test/resources/network-mgr-component.xml +++ b/server/test/resources/network-mgr-component.xml @@ -78,7 +78,7 @@ under the License. - + diff --git a/utils/src/com/cloud/utils/component/ComponentContext.java b/utils/src/com/cloud/utils/component/ComponentContext.java index 796d4ec0282..5c5194cca2d 100644 --- a/utils/src/com/cloud/utils/component/ComponentContext.java +++ b/utils/src/com/cloud/utils/component/ComponentContext.java @@ -71,14 +71,14 @@ public class ComponentContext implements ApplicationContextAware { beanFactory.configureBean(bean, entry.getKey()); } - Map lifecyleComponents = getApplicationContext().getBeansOfType(ComponentLifecycle.class); + Map lifecycleComponents = getApplicationContext().getBeansOfType(ComponentLifecycle.class); Map[] classifiedComponents = new Map[ComponentLifecycle.MAX_RUN_LEVELS]; for(int i = 0; i < ComponentLifecycle.MAX_RUN_LEVELS; i++) { classifiedComponents[i] = new HashMap(); } - for(Map.Entry entry : lifecyleComponents.entrySet()) { + for(Map.Entry entry : lifecycleComponents.entrySet()) { classifiedComponents[entry.getValue().getRunLevel()].put(entry.getKey(), entry.getValue()); } From 886fe0128ecd13ceac0ae928ce7d45b70a65964c Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Sat, 13 Apr 2013 16:18:22 -0500 Subject: [PATCH 078/107] Removing DISCLAIMER as we're no longer in the Incubator. --- DISCLAIMER | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 DISCLAIMER diff --git a/DISCLAIMER b/DISCLAIMER deleted file mode 100644 index fa1e9261a36..00000000000 --- a/DISCLAIMER +++ /dev/null @@ -1,7 +0,0 @@ -Apache CloudStack is an effort undergoing incubation at The Apache Software Foundation (ASF), -sponsored by the Apache Incubator. Incubation is required of all newly accepted -projects until a further review indicates that the infrastructure, communications, and -decision making process have stabilized in a manner consistent with other successful ASF -projects. While incubation status is not necessarily a reflection of the completeness or -stability of the code, it does indicate that the project has yet to be fully endorsed by -the ASF. From bc3e184b7273da605177b0ac4ed7186f7fa36fbd Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Sun, 14 Apr 2013 17:50:15 +0530 Subject: [PATCH 079/107] CLOUDSTACK-312: enable L4-L7 network services in the shared network in the advanced zone Squashed commit of the following: commit 3021cb917b2446f6a04f6cbb01bc56ebc5484bff Merge: 77c6991 886fe01 Author: Murali Reddy Date: Sun Apr 14 17:22:05 2013 +0530 Merge branch 'master' into sharednetworkservices commit 77c69918be5f15656a95fc325da9f0c99a08e782 Author: Murali Reddy Date: Tue Apr 9 17:16:57 2013 +0530 Trying to fit both isolated and shared network life cycle with single state machine may need addtional work. So set network state for shared network explicitly now. commit 365ed73a0c10a5e445be34b6e6c5d99e1224a537 Author: Murali Reddy Date: Tue Apr 2 17:14:11 2013 +0530 - associateIpAddress API to associate a public IP with shared network - shared network with services to go through the implement and shutwdon phases --- api/src/com/cloud/network/NetworkService.java | 2 +- .../user/address/AssociateIPAddrCmd.java | 31 +- .../F5ExternalLoadBalancerElement.java | 15 +- .../JuniperSRXExternalFirewallElement.java | 58 +--- .../network/element/NetscalerElement.java | 3 +- .../com/cloud/network/NetworkManagerImpl.java | 272 ++++++++---------- .../com/cloud/network/NetworkServiceImpl.java | 100 ++++--- .../cloud/network/MockNetworkManagerImpl.java | 38 +-- .../com/cloud/vpc/MockNetworkManagerImpl.java | 54 ++-- 9 files changed, 242 insertions(+), 331 deletions(-) diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index ab6d7bfd882..066009b8b75 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -46,7 +46,7 @@ public interface NetworkService { List getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner); - IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, + IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; diff --git a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java index 406f782da51..28fbae4437a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java @@ -16,38 +16,21 @@ // under the License. package org.apache.cloudstack.api.command.user.address; -import java.util.List; - -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.BaseAsyncCreateCmd; -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.IPAddressResponse; -import org.apache.cloudstack.api.response.NetworkResponse; -import org.apache.cloudstack.api.response.ProjectResponse; -import org.apache.cloudstack.api.response.VpcResponse; -import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.log4j.Logger; - import com.cloud.async.AsyncJob; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.event.EventTypes; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.*; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.vpc.Vpc; import com.cloud.user.Account; import com.cloud.user.UserContext; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.util.List; @APICommand(name = "associateIpAddress", description="Acquires and associates a public IP to an account.", responseObject=IPAddressResponse.class) public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { @@ -213,7 +196,7 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - IpAddress ip = _networkService.allocateIP(_accountService.getAccount(getEntityOwnerId()), false, getZoneId()); + IpAddress ip = _networkService.allocateIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNetworkId()); if (ip != null) { this.setEntityId(ip.getId()); diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index 77f6b60bfe8..e384e3cfd0d 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -16,19 +16,6 @@ // under the License. package com.cloud.network.element; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.cloudstack.api.response.ExternalLoadBalancerResponse; -import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; -import org.apache.log4j.Logger; - import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.api.ApiDBUtils; import com.cloud.api.commands.*; @@ -101,7 +88,7 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan ConfigurationDao _configDao; private boolean canHandle(Network config) { - if (config.getGuestType() != Network.GuestType.Isolated || config.getTrafficType() != TrafficType.Guest) { + if ((config.getGuestType() != Network.GuestType.Isolated && config.getGuestType() != Network.GuestType.Shared) || config.getTrafficType() != TrafficType.Guest) { s_logger.trace("Not handling network with Type " + config.getGuestType() + " and traffic type " + config.getTrafficType()); return false; } diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index 64b0f5aa37d..a429306a680 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -16,28 +16,8 @@ // under the License. package com.cloud.network.element; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.cloudstack.api.response.ExternalFirewallResponse; -import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; -import org.apache.log4j.Logger; - import com.cloud.api.ApiDBUtils; -import com.cloud.api.commands.AddExternalFirewallCmd; -import com.cloud.api.commands.AddSrxFirewallCmd; -import com.cloud.api.commands.ConfigureSrxFirewallCmd; -import com.cloud.api.commands.DeleteExternalFirewallCmd; -import com.cloud.api.commands.DeleteSrxFirewallCmd; -import com.cloud.api.commands.ListExternalFirewallsCmd; -import com.cloud.api.commands.ListSrxFirewallNetworksCmd; -import com.cloud.api.commands.ListSrxFirewallsCmd; +import com.cloud.api.commands.*; import com.cloud.api.response.SrxFirewallResponse; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -47,35 +27,16 @@ import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientNetworkCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; -import com.cloud.network.ExternalFirewallDeviceManagerImpl; -import com.cloud.network.Network; +import com.cloud.network.*; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; -import com.cloud.network.PhysicalNetwork; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.network.PublicIpAddress; -import com.cloud.network.RemoteAccessVpn; -import com.cloud.network.VpnUser; -import com.cloud.network.dao.ExternalFirewallDeviceDao; -import com.cloud.network.dao.ExternalFirewallDeviceVO; -import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkExternalFirewallDao; -import com.cloud.network.dao.NetworkExternalFirewallVO; -import com.cloud.network.dao.NetworkServiceMapDao; -import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.PhysicalNetworkDao; -import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.*; import com.cloud.network.dao.ExternalFirewallDeviceVO.FirewallDeviceState; import com.cloud.network.resource.JuniperSrxResource; import com.cloud.network.rules.FirewallRule; @@ -89,6 +50,13 @@ import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.api.response.ExternalFirewallResponse; +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.util.*; @Local(value = {NetworkElement.class, FirewallServiceProvider.class, PortForwardingServiceProvider.class, IpDeployer.class, @@ -129,7 +97,9 @@ PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, Junip private boolean canHandle(Network network, Service service) { DataCenter zone = _configMgr.getZone(network.getDataCenterId()); - if ((zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() != Network.GuestType.Isolated) || (zone.getNetworkType() == NetworkType.Basic && network.getGuestType() != Network.GuestType.Shared)) { + if ((zone.getNetworkType() == NetworkType.Advanced && !(network.getGuestType() == Network.GuestType.Isolated || + network.getGuestType() == Network.GuestType.Shared )) || + (zone.getNetworkType() == NetworkType.Basic && network.getGuestType() != Network.GuestType.Shared)) { s_logger.trace("Element " + getProvider().getName() + "is not handling network type = " + network.getGuestType()); return false; } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index 17bb7cc1b6a..2bbdb0450be 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -124,7 +124,8 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl private boolean canHandle(Network config, Service service) { DataCenter zone = _dcDao.findById(config.getDataCenterId()); - boolean handleInAdvanceZone = (zone.getNetworkType() == NetworkType.Advanced && config.getGuestType() == Network.GuestType.Isolated && config.getTrafficType() == TrafficType.Guest); + boolean handleInAdvanceZone = (zone.getNetworkType() == NetworkType.Advanced && + (config.getGuestType() == Network.GuestType.Isolated || config.getGuestType() == Network.GuestType.Shared) && config.getTrafficType() == TrafficType.Guest); boolean handleInBasicZone = (zone.getNetworkType() == NetworkType.Basic && config.getGuestType() == Network.GuestType.Shared && config.getTrafficType() == TrafficType.Guest); if (!(handleInAdvanceZone || handleInBasicZone)) { diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 5b604667585..7332ef3e9cf 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -16,42 +16,9 @@ // under the License. package com.cloud.network; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; -import com.cloud.agent.api.AgentControlAnswer; -import com.cloud.agent.api.AgentControlCommand; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.CheckNetworkAnswer; -import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.*; import com.cloud.agent.api.to.NicTO; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; @@ -59,15 +26,9 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.AccountVlanMapVO; -import com.cloud.dc.DataCenter; +import com.cloud.dc.*; import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.Pod; -import com.cloud.dc.PodVlanMapVO; -import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.PodVlanMapDao; @@ -80,66 +41,25 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.AccountLimitException; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.ConnectionException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientVirtualNetworkCapcityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.UnsupportedServiceException; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress.State; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.Event; -import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; +import com.cloud.network.Network.*; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; -import com.cloud.network.dao.FirewallRulesDao; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.dao.LoadBalancerDao; -import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkDomainDao; -import com.cloud.network.dao.NetworkServiceMapDao; -import com.cloud.network.dao.NetworkServiceMapVO; -import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.PhysicalNetworkDao; -import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; -import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; -import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; -import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.network.dao.UserIpv6AddressDao; -import com.cloud.network.element.DhcpServiceProvider; -import com.cloud.network.element.IpDeployer; -import com.cloud.network.element.IpDeployingRequester; -import com.cloud.network.element.LoadBalancingServiceProvider; -import com.cloud.network.element.NetworkElement; -import com.cloud.network.element.StaticNatServiceProvider; -import com.cloud.network.element.UserDataServiceProvider; +import com.cloud.network.dao.*; +import com.cloud.network.element.*; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; -import com.cloud.network.rules.FirewallManager; -import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; -import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.PortForwardingRuleVO; -import com.cloud.network.rules.RulesManager; -import com.cloud.network.rules.StaticNat; -import com.cloud.network.rules.StaticNatRule; -import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; import com.cloud.network.vpc.VpcManager; @@ -152,49 +72,40 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; -import com.cloud.user.UserVO; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; +import com.cloud.utils.db.*; 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.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.Nic; +import com.cloud.vm.*; import com.cloud.vm.Nic.ReservationStrategy; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.ReservationContextImpl; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.NicDao; -import com.cloud.vm.dao.NicSecondaryIpDao; -import com.cloud.vm.dao.NicSecondaryIpVO; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.dao.*; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.net.URI; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * NetworkManagerImpl implements NetworkManager. @@ -663,7 +574,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @DB @Override - public IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerUserId, DataCenter zone) + public IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerUserId, DataCenter zone) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException { @@ -788,7 +699,22 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId); if (ipToAssoc != null) { - _accountMgr.checkAccess(caller, null, true, ipToAssoc); + Network network = _networksDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); + if (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced) { + if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { + _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network); + } else { + throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " + + "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network"); + } + } else { + _accountMgr.checkAccess(caller, null, true, ipToAssoc); + } owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId()); } else { s_logger.debug("Unable to find ip address by id: " + ipId); @@ -815,16 +741,21 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + TrafficType.Guest); } - // Check that network belongs to IP owner - skip this check for Basic zone as there is just one guest network, - // and it belongs to the system - if (zone.getNetworkType() != NetworkType.Basic && network.getAccountId() != owner.getId()) { - throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); + // Check that network belongs to IP owner - skip this check + // - if zone is basic zone as there is just one guest network, + // - if shared network in Advanced zone + // - and it belongs to the system + if (network.getAccountId() != owner.getId()) { + if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) { + throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); + } } - // In Advance zone only allow to do IP assoc for Isolated networks with source nat service enabled + // In Advance zone only allow to do IP assoc + // - for Isolated networks with source nat service enabled + // - for shared networks with source nat service enabled if (zone.getNetworkType() == NetworkType.Advanced && - !(network.getGuestType() == GuestType.Isolated && _networkModel.areServicesSupportedInNetwork(network.getId(), - Service.SourceNat))) { + !(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat))) { throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + " ip address can be associated only to the network of guest type " + GuestType.Isolated + " with the " + Service.SourceNat.getName() + " enabled"); @@ -1496,12 +1427,21 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L try { NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); Network.State state = network.getState(); - if (state == Network.State.Implemented || state == Network.State.Setup || state == Network.State.Implementing) { + if (state == Network.State.Implemented || state == Network.State.Implementing) { s_logger.debug("Network id=" + networkId + " is already implemented"); implemented.set(guru, network); return implemented; } + if (state == Network.State.Setup) { + DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); + if (!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) || (zone.getNetworkType() == NetworkType.Basic)) { + s_logger.debug("Network id=" + networkId + " is already implemented"); + implemented.set(guru, network); + return implemented; + } + } + if (s_logger.isDebugEnabled()) { s_logger.debug("Asking " + guru.getName() + " to implement " + network); } @@ -1509,7 +1449,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); network.setReservationId(context.getReservationId()); - stateTransitTo(network, Event.ImplementNetwork); + if (isSharedNetworkWithServices(network)) { + network.setState(Network.State.Implementing); + } else { + stateTransitTo(network, Event.ImplementNetwork); + } Network result = guru.implement(network, offering, dest, context); network.setCidr(result.getCidr()); @@ -1522,7 +1466,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // implement network elements and re-apply all the network rules implementNetworkElementsAndResources(dest, context, network, offering); - stateTransitTo(network,Event.OperationSucceeded); + if (isSharedNetworkWithServices(network)) { + network.setState(Network.State.Implemented); + } else { + stateTransitTo(network,Event.OperationSucceeded); + } network.setRestartRequired(false); _networksDao.update(network.getId(), network); @@ -1535,7 +1483,12 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (implemented.first() == null) { s_logger.debug("Cleaning up because we're unable to implement the network " + network); try { - stateTransitTo(network,Event.OperationFailed); + if (isSharedNetworkWithServices(network)) { + network.setState(Network.State.Shutdown); + _networksDao.update(networkId, network); + } else { + stateTransitTo(network,Event.OperationFailed); + } } catch (NoTransitionException e) { s_logger.error(e.getMessage()); } @@ -1560,14 +1513,17 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L NetworkVO network, NetworkOfferingVO offering) throws ConcurrentOperationException, InsufficientAddressCapacityException, ResourceUnavailableException, InsufficientCapacityException { - // If this is a 1) guest virtual network 2) network has sourceNat service 3) network offering does not support a - // Shared source NAT rule, - // associate a source NAT IP (if one isn't already associated with the network) + // Associate a source NAT IP (if one isn't already associated with the network) if this is a + // 1) 'Isolated' or 'Shared' guest virtual network in the advance zone + // 2) network has sourceNat service + // 3) network offering does not support a shared source NAT rule boolean sharedSourceNat = offering.getSharedSourceNat(); - if (network.getGuestType() == Network.GuestType.Isolated - && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat) - && !sharedSourceNat) { + DataCenter zone = _dcDao.findById(network.getDataCenterId()); + + if (!sharedSourceNat && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat) + && (network.getGuestType() == Network.GuestType.Isolated || + (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { List ips = null; if (network.getVpcId() != null) { @@ -2031,10 +1987,12 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); } } else { - //don't allow to create Shared network with Vlan that already exists in the zone for Isolated networks - if (_networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Isolated) > 0) { - throw new InvalidParameterValueException("Isolated network with vlan " + vlanId + " already exists " + - "in zone " + zoneId); + // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or + // shared network with same Vlan ID in the zone + if (_networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Isolated) > 0 || + _networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Shared) > 0) { + throw new InvalidParameterValueException("There is a isolated/shared network with vlan id: " + + vlanId + " already exists " + "in zone " + zoneId); } } } @@ -2166,6 +2124,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @DB public boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements) { boolean result = false; + Transaction txn = Transaction.currentTxn(); NetworkVO network = _networksDao.lockRow(networkId, true); if (network == null) { @@ -2176,16 +2135,23 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L s_logger.debug("Network is not implemented: " + network); return false; } - try { - stateTransitTo(network, Event.DestroyNetwork); - } catch (NoTransitionException e) { + + txn.start(); + if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Shutdown); _networksDao.update(network.getId(), network); + } else { + try { + stateTransitTo(network, Event.DestroyNetwork); + } catch (NoTransitionException e) { + network.setState(Network.State.Shutdown); + _networksDao.update(network.getId(), network); + } } + txn.commit(); boolean success = shutdownNetworkElementsAndResources(context, cleanupElements, network); - Transaction txn = Transaction.currentTxn(); txn.start(); if (success) { if (s_logger.isDebugEnabled()) { @@ -2196,11 +2162,16 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guru.shutdown(profile, _networkOfferingDao.findById(network.getNetworkOfferingId())); applyProfileToNetwork(network, profile); - try { - stateTransitTo(network, Event.OperationSucceeded); - } catch (NoTransitionException e) { - network.setState(Network.State.Allocated); - network.setRestartRequired(false); + DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); + if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && (zone.getNetworkType() == NetworkType.Advanced)) { + network.setState(Network.State.Setup); + } else { + try { + stateTransitTo(network, Event.OperationSucceeded); + } catch (NoTransitionException e) { + network.setState(Network.State.Allocated); + network.setRestartRequired(false); + } } _networksDao.update(network.getId(), network); _networksDao.clearCheckForGc(networkId); @@ -2816,6 +2787,17 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(SSHKeyProvider); } + protected boolean isSharedNetworkWithServices(Network network) { + assert(network != null); + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); + if (network.getGuestType() == Network.GuestType.Shared && + zone.getNetworkType() == NetworkType.Advanced && + isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) { + return true; + } + return false; + } + protected boolean isSharedNetworkOfferingWithServices(long networkOfferingId) { NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId); if ( (networkOffering.getGuestType() == Network.GuestType.Shared) && ( diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index a8cbaa75017..70d1d0d432c 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -16,44 +16,13 @@ // under the License. package com.cloud.network; -import java.net.InetAddress; -import java.net.Inet6Address; -import java.net.UnknownHostException; -import java.security.InvalidParameterException; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; -import org.bouncycastle.util.IPAddress; - import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; -import com.cloud.dc.Pod; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; @@ -70,10 +39,8 @@ import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.*; -import com.cloud.host.Host; import com.cloud.host.dao.HostDao; import com.cloud.network.IpAddress.State; -import com.cloud.vm.Nic; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; @@ -89,10 +56,10 @@ import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VpcVirtualRouterElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule.Purpose; -import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.PrivateIpVO; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; @@ -114,19 +81,33 @@ import com.cloud.utils.AnnotationHelper; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; 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.*; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.*; -import com.cloud.vm.dao.NicDao; -import com.cloud.vm.dao.NicSecondaryIpDao; -import com.cloud.vm.dao.NicSecondaryIpVO; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.dao.*; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidParameterException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.*; /** @@ -433,7 +414,40 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Override @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true) - public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) + public IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId) + throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { + + if (networkId != null) { + Network network = _networksDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + if (network.getGuestType() == Network.GuestType.Shared) { + DataCenter zone = _configMgr.getZone(zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Invalid zone Id is given"); + } + + // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork' + if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) { + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); + } + return _networkMgr.allocateIp(ipOwner, false, caller, callerUserId, zone); + } else { + throw new InvalidParameterValueException("Associate IP address can only be called on the shared networks in the advanced zone" + + " with Firewall/Source Nat/Static Nat/Port Forwarding/Load balancing services enabled"); + } + } + } + + return allocateIP(ipOwner, false, zoneId); + } + + public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); // check permissions diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 18eae085879..9042f03d4a7 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -16,33 +16,13 @@ // under the License. package com.cloud.network; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; -import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; - import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientVirtualNetworkCapcityException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.*; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; @@ -62,7 +42,6 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -74,6 +53,19 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfileImpl; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.List; +import java.util.Map; +import java.util.Set; @Component @Local(value = { NetworkManager.class, NetworkService.class }) @@ -824,7 +816,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage * @see com.cloud.network.NetworkService#allocateIP(com.cloud.user.Account, boolean, long) */ @Override - public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, + public IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index bd4fd678d48..3a585ce708a 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -16,49 +16,17 @@ // under the License. package com.cloud.vpc; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; -import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientVirtualNetworkCapcityException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.IpAddress; -import com.cloud.network.Network; +import com.cloud.exception.*; +import com.cloud.network.*; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkManager; -import com.cloud.network.NetworkProfile; -import com.cloud.network.NetworkRuleApplier; -import com.cloud.network.NetworkService; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetwork; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.network.PhysicalNetworkTrafficType; -import com.cloud.network.PublicIpAddress; -import com.cloud.network.UserIpv6Address; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkServiceMapDao; @@ -78,7 +46,6 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -90,6 +57,21 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfileImpl; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Component @Local(value = { NetworkManager.class, NetworkService.class }) @@ -188,7 +170,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage * @see com.cloud.network.NetworkService#allocateIP(com.cloud.user.Account, long, java.lang.Long) */ @Override - public IpAddress allocateIP(Account ipOwner, boolean isSystem, long networkId) throws ResourceAllocationException, + public IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { // TODO Auto-generated method stub return null; From b0bbffb79ebb169355fbce499397a2a1c4f83af2 Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Sun, 14 Apr 2013 23:08:08 -0500 Subject: [PATCH 080/107] Adding issues fixed in 4.1.0 --- docs/en-US/Release_Notes.xml | 4176 ++++++++++++++++++++++++++++++++-- 1 file changed, 3954 insertions(+), 222 deletions(-) diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml index b8c5c01fb0b..5b9571e7909 100644 --- a/docs/en-US/Release_Notes.xml +++ b/docs/en-US/Release_Notes.xml @@ -27,6 +27,3942 @@ under the License. This document contains information specific to this release of &PRODUCT;, including upgrade instructions from prior releases, new features added to &PRODUCT;, API changes, and issues fixed in the release. For installation instructions, please see the Installation Guide. For usage and administration instructions, please see the &PRODUCT; Administrator's Guide. Developers and users who wish to work with the API will find instruction in the &PRODUCT; API Developer's Guide If you find any errors or problems in this guide, please see . We hope you enjoy working with &PRODUCT;! + + Version 4.1.0 +
+ What’s New in 4.1 + Apache CloudStack 4.1.0 includes many new features. This section covers the most prominent new features and changes. +
+ Localization + The 4.1.0 release adds partial User Interface (UI) support for Catalan, Chinese, French, German, Italian, Japanese, Korean, Norwegian, Portuguese, Russian, and Spanish. Not all languages are complete. + The 4.1.0 release also adds documentation translations for Chinese, Chinese (Taiwan), Italian, Japanese, Korean, and Portuguese. +
+
+
+ Issues Fixed in 4.1.0 + Apache CloudStack uses Jira + to track its issues. All new features and bugs for 4.1.0 have been tracked in Jira, and have + a standard naming convention of "CLOUDSTACK-NNNN" where "NNNN" is the issue number. + This section includes a summary of known issues against 4.0.0 that were fixed in 4.1.0. Approximately 470 bugs were resolved or closed in the 4.1.0 cycle. + + + + + + + + Defect + + + Description + + + + + + + CLOUDSTACK-46 + + + Remnants of mycloud remain. + + + + + CLOUDSTACK-70 + + + Improve Network Restart Behaviour for Basic Zone: Restarting Network Fail + + + + + CLOUDSTACK-94 + + + "API command, listIsos documentation clarity + + + + + CLOUDSTACK-95 + + + IP address allocation not working when a user tries to allocate IP addresses in a Project + + + + + CLOUDSTACK-97 + + + Vmware network labels are ignored when creating a Zone using basic networkin + + + + + CLOUDSTACK-108 + + + VM should not be allowed to be deployed on two Isolated Networks of an Account that were created from DefaultNetworkOfferingwithSourceNATService + + + + + CLOUDSTACK-118 + + + "Status of host resorce stuck in ""ErrorInMaintenance"" + + + + + CLOUDSTACK-119 + + + Move Agent-Simulator in to the hypervisor plugin mode + + + + + CLOUDSTACK-130 + + + Clarify docs on tags parameter in API referenc + + + + + CLOUDSTACK-152 + + + Routes on the User VM are programmed incorrectly on a VM present on both Isolated and Shared Guest Network + + + + + CLOUDSTACK-178 + + + Expose name parameter of VM in list Vm view + + + + + CLOUDSTACK-198 + + + vpn:failto add VPN Users deletes all the existing Vpn use + + + + + CLOUDSTACK-222 + + + Admin UI prompts to restart Management server with cancel edit operatio + + + + + CLOUDSTACK-225 + + + API Docs: Request params repeated with different description + + + + + CLOUDSTACK-226 + + + UpdatePhysicalNetworkcommand failed due to java.sql.BatchUpdateException ; Tried to extend the existing Guest VLAN Range of one physical network into the Guest VLAN range of the other physical networ + + + + + CLOUDSTACK-227 + + + ReconnectHostCmd: NullPointerException: Unable to get host Information for XenServer 6.0.2 host - on intentionally changing the traffic labels on the physical networ + + + + + CLOUDSTACK-228 + + + UI provides an option to reconnect a disconnected host - ServerApiException is thrown on an attemp + + + + + CLOUDSTACK-232 + + + Zone infrastructure chart -- disable resource total displa + + + + + CLOUDSTACK-235 + + + Network rate can be set in 2 places. Clarify docs on how this works + + + + + CLOUDSTACK-249 + + + Add host id to failed VM deploy alert + + + + + CLOUDSTACK-250 + + + Incorrect description of maintenance mode in admin guid + + + + + CLOUDSTACK-256 + + + "vpn:As an admin user, not able to delete VPN user which is present in a regular user's network. + + + + + CLOUDSTACK-271 + + + updatePhysicalNetwork dies with an NPE when the vlan range is empt + + + + + CLOUDSTACK-274 + + + Two error codes mapped to same value in AP + + + + + CLOUDSTACK-275 + + + hostid not always a UUI + + + + + CLOUDSTACK-277 + + + Message during CloudStack management server Installation: cannot access /usr/share/cloud/bridge/lib: No such file or director + + + + + CLOUDSTACK-279 + + + deleteProject fails when executed by the regular user (works fine for root/domain admin + + + + + CLOUDSTACK-284 + + + listVirtualMachines does not return deleted machines when zone is specifie + + + + + CLOUDSTACK-290 + + + 3.0.0 template also needed for 2.2.14 to 3.0.5 direct upgrade + + + + + CLOUDSTACK-293 + + + "We do awful, hacky things in our spec file for client + + + + + CLOUDSTACK-304 + + + Add synchronization for createSnapshot command per host basi + + + + + CLOUDSTACK-309 + + + iptables rules being deleted from wrong VM after a migratio + + + + + CLOUDSTACK-318 + + + Adding XenServer Host Fails - 6.0.2 fails with 4.0. + + + + + CLOUDSTACK-320 + + + "sessionKey query parameter should be case-insensitive, now only sessionkey is accepted + + + + + CLOUDSTACK-322 + + + During upgrade displays error - a foreign key constraint fails (`cloud/#sql-f34_6e`.. + + + + + CLOUDSTACK-332 + + + """count"" property in list* API response should be equal to how many entries in database, not how many objects in API response + + + + + CLOUDSTACK-333 + + + When Datacenter name in VCenter has spaces Primary Storage (VMFS) discovery will fai + + + + + CLOUDSTACK-335 + + + KVM VPC load balancer not workin + + + + + CLOUDSTACK-336 + + + listZones doesn't honour pagin + + + + + CLOUDSTACK-343 + + + "Document what tools and packages are required to build, package and install CloudStack 4.0 + + + + + CLOUDSTACK-346 + + + Cannot add Vmware cluster with class loader conflict exceptio + + + + + CLOUDSTACK-347 + + + listNetworks API: return vlan information only when the caller is ROOT admi + + + + + CLOUDSTACK-348 + + + deleteNetwork does not clean up network resource count correctl + + + + + CLOUDSTACK-354 + + + Display of storage statistics is wrong + + + + + CLOUDSTACK-355 + + + "Fix ""count"" in a bunch of API commands + + + + + CLOUDSTACK-357 + + + "ISOs can be deleted while still attached to a running VM, and they subsequently cannot be detached from a running VM + + + + + CLOUDSTACK-359 + + + PropagateResourceEventCommand failes in cluster configuratio + + + + + CLOUDSTACK-361 + + + Wrong creation of guest networks on a KVM host in Multiple Physical Networks with guest traffi + + + + + CLOUDSTACK-364 + + + Docs point to download.cloud.com for AWS API scrip + + + + + CLOUDSTACK-368 + + + OVM - cannot create guest V + + + + + CLOUDSTACK-369 + + + ASF 4.0 - unable to support XenServer 6.1 hos + + + + + CLOUDSTACK-373 + + + "static NAT and Firewall is not working on external firewall device SRX, it needs to be implemented + + + + + CLOUDSTACK-377 + + + provide deployment config access to marvin's testcas + + + + + CLOUDSTACK-378 + + + mavenize marvin on maste + + + + + CLOUDSTACK-390 + + + Install Guide: Section 4.5.7 (Prepare the System VM Template): Links go to cloud.co + + + + + CLOUDSTACK-397 + + + Install Guide: Section 11.1 (Guest Traffic): Diagram is the wrong diagra + + + + + CLOUDSTACK-398 + + + Install Guide: Section 11.17.3 (Using VPN with Mac OSX): Not complete + + + + + CLOUDSTACK-404 + + + Update docs on the usage of cloud-setup-database + + + + + CLOUDSTACK-412 + + + Data truncation: Out of range value for column 'ram' at row + + + + + CLOUDSTACK-415 + + + restartNetwork call causes VM to be unreachable when Nicira based SDN is used + + + + + CLOUDSTACK-416 + + + XCP 1.6beta2 (61002c) - can't add a hos + + + + + CLOUDSTACK-417 + + + Handle password server securely to run on port 8080 on V + + + + + CLOUDSTACK-424 + + + Updated userdata not propagating to the VR + + + + + CLOUDSTACK-427 + + + Change hardcoded step number references to dynamic link + + + + + CLOUDSTACK-428 + + + Storage capacity shown in UI is incorrec + + + + + CLOUDSTACK-435 + + + Vmware network labels are ignored when creating a Zone using basic networkin + + + + + CLOUDSTACK-441 + + + Running mgmt server using jetty fails to start api serve + + + + + CLOUDSTACK-446 + + + "Host going to alert state, if you are adding already added host + + + + + CLOUDSTACK-448 + + + SSVM bootstrap failure on XenServer hosts with E3 CP + + + + + CLOUDSTACK-456 + + + License tag in SPEC isn't what RPM is expectin + + + + + CLOUDSTACK-459 + + + [Optional Public IP assignment for EIP with Basic Zone] Associate IP Checkbox in Create Network Offering Dialog is Displayed When Elastic LB is Selecte + + + + + CLOUDSTACK-462 + + + A few corrections to make to the 4.0.0 installation guid + + + + + CLOUDSTACK-464 + + + "Regression in AWSAPI docs, entire sections removed + + + + + CLOUDSTACK-465 + + + French language file quotes are dropping javascript syntax error + + + + + CLOUDSTACK-467 + + + Developer's Guide points to cloud.com for API referenc + + + + + CLOUDSTACK-479 + + + UpdateVirtualMachine api fails to propagate userdata to dom + + + + + CLOUDSTACK-481 + + + Installation Guide Doc Erro + + + + + CLOUDSTACK-493 + + + 2.2.x-3.0 DB upgrade support for Advance SG enabled network + + + + + CLOUDSTACK-499 + + + cloudmonkey CLI can't accept complex parameter + + + + + CLOUDSTACK-500 + + + Passwd-server iptables rules are dropped on domr on fresh start or on reboot. + + + + + CLOUDSTACK-501 + + + Apidocs and marvin does not know how to handle Autoscaling docs. + + + + + CLOUDSTACK-504 + + + Duplicate guest password scripts in codebase. + + + + + CLOUDSTACK-507 + + + fix api docs for listSSHKeyPair + + + + + CLOUDSTACK-508 + + + CLVM copies template to primary storage unnecessarily. + + + + + CLOUDSTACK-510 + + + Add button not visible when adding public IPs to physical network. + + + + + CLOUDSTACK-514 + + + Marvin and Cloudmonkey don't work when an API target uses https or an alternate path. + + + + + CLOUDSTACK-518 + + + API refactoring -- change @Parameter annotation and remove the @IdentityMapper annotation. + + + + + CLOUDSTACK-520 + + + Dependency jar names mismatch with install-non-oss.s + + + + + CLOUDSTACK-521 + + + Build will hung up when doing test for TestAgentShel + + + + + CLOUDSTACK-522 + + + Log requests in cloudmonkey's log file. + + + + + CLOUDSTACK-527 + + + List API performance optimization by using DB views and removing UUID conversion + + + + + CLOUDSTACK-534 + + + Failed to add hos + + + + + CLOUDSTACK-536 + + + remove citrix cloudpatform from 4.0 build - CloudStack is ASF project. + + + + + CLOUDSTACK-539 + + + Cropped Text in UI under Quick View. + + + + + CLOUDSTACK-552 + + + ]Quick view details for a volume displays scroll bar in place of name of the volume when the name of the volume has more no of characters. + + + + + CLOUDSTACK-553 + + + "SRX - When adding SRX device make "Public Network" - default to "untrusted" and "Private Network" - default to "trusted" as un-editable fields. + + + + + CLOUDSTACK-556 + + + Erratic window behavior in Quick View tooltip. + + + + + CLOUDSTACK-559 + + + source code import problem + + + + + CLOUDSTACK-560 + + + Usage server doesn't work in 4.0.0 due to missing db changes + + + + + CLOUDSTACK-572 + + + SG Enabled Advanced Zone - Not able to deploy a VM in an account specific shared network + + + + + CLOUDSTACK-573 + + + "NPE at ""com.cloud.network.NetworkManagerImpl.networkOfferingIsConfiguredForExternalNetworking(NetworkManagerImpl.java:4345)"" when create network from the network offering having NULL provider for the service + + + + + CLOUDSTACK-578 + + + The already deleted same hostname is not deleted from /etc/hosts of vRouter + + + + + CLOUDSTACK-584 + + + "typos in ""Apache_CloudStack-4.0.0-incubating-CloudStack_Nicira_NVP_Guide-en-US"" + + + + + CLOUDSTACK-590 + + + Incorrect Network Gateways Assigned to System VM + + + + + CLOUDSTACK-592 + + + "API bloat, unknown apis cmd classes + + + + + CLOUDSTACK-593 + + + "2 guest network, auto create vlan error + + + + + CLOUDSTACK-596 + + + DeployVM command takes a lot of time to return job id. + + + + + CLOUDSTACK-599 + + + DhcpEntryCommand fails on Router VM on CS4.0 and vSphere5 with Advanced Network Zone. + + + + + CLOUDSTACK-600 + + + When rebooting KVM local storage VM host, libvirt definitions deleted + + + + + CLOUDSTACK-605 + + + Host physical CPU is incorrectly calculated for Vmware host + + + + + CLOUDSTACK-606 + + + Starting VM fails with 'ConcurrentOperationException' in a clustered MS scenari + + + + + CLOUDSTACK-614 + + + "ListTemplates API is not returning ""Enable SSH Key"" attribute for any given template + + + + + CLOUDSTACK-617 + + + Unable to edit a Sub domai + + + + + CLOUDSTACK-639 + + + API Refactoring: Adapters for AC + + + + + CLOUDSTACK-648 + + + The normal users could change their own login password. + + + + + CLOUDSTACK-660 + + + Network Traffic Labels are not functional in Marvin + + + + + CLOUDSTACK-683 + + + Image Is Missing in the Accessing VM Section + + + + + CLOUDSTACK-689 + + + RVR: Stop pending flag is not cleared when user start the disconnected router from another hos + + + + + CLOUDSTACK-691 + + + A warning dialog box shows after reloading the welcome page. + + + + + CLOUDSTACK-693 + + + Adding a VPC virtual router to a NiciraNVP enabled network fails. + + + + + CLOUDSTACK-694 + + + "Create a new VPC network offering with "connectivity" option needed for SDN networking) is not allowed / VPC support for SDN networks + + + + + CLOUDSTACK-717 + + + cloudmonkey fails to parse/print response. + + + + + CLOUDSTACK-720 + + + Fail to load a png image when accessing the web console. + + + + + CLOUDSTACK-721 + + + Bytes sent/received in user statistics is empty (CloudStack 4.0) + + + + + CLOUDSTACK-725 + + + UI: Error when the Egress rules tab is selected for a network. + + + + + CLOUDSTACK-734 + + + api_refactoring: CreateAccountCmd fails to send response due to NPE in service layer + + + + + CLOUDSTACK-735 + + + Integration smoke tests: Fix expunge vm test on api_refactoring + + + + + CLOUDSTACK-736 + + + Integration smoke tests: Fix check for vm name for the deployvm smoke test. + + + + + CLOUDSTACK-793 + + + "Create cloudmonkey-helper, a plugin that helps autodiscover and sync api info via an api over some endpoint + + + + + CLOUDSTACK-798 + + + Move usage related cmd classes from cloud-server to cloud-api + + + + + CLOUDSTACK-799 + + + [Load Test] Check router statistics falls behind in gathering stats by more than 2 times the set value + + + + + CLOUDSTACK-819 + + + Create Account/User API logging password in access log + + + + + CLOUDSTACK-863 + + + Non-printable characters (ASCII control character) such as %00 or %0025 are getting stored in raw/non encoded form in the database + + + + + CLOUDSTACK-870 + + + Client UI: Wrong character encoding for some language + + + + + CLOUDSTACK-928 + + + [Simulator] Latency for Agent Commands - change unit of wait from seconds to millisecond + + + + + CLOUDSTACK-938 + + + s2s VPN trouble + + + + + CLOUDSTACK-959 + + + Missing sub-sections in document section System Service Offering + + + + + CLOUDSTACK-968 + + + marvin: vlan should be an attribute of the physical_network and not the zon + + + + + CLOUDSTACK-977 + + + Document how to use openvswitch with KVM hypervisor + + + + + CLOUDSTACK-978 + + + TypeError: instance.displayname is undefined while adding VM's to the LB rule + + + + + CLOUDSTACK-985 + + + Different MAC address for RvR caused issue in short term network outrag + + + + + CLOUDSTACK-987 + + + Sections missing in Working With Snapshot + + + + + CLOUDSTACK-993 + + + "admin"" user is not getting created when management server is started. + + + + + CLOUDSTACK-995 + + + Not able to add the KVM host + + + + + CLOUDSTACK-1002 + + + Not able to start VM + + + + + CLOUDSTACK-1006 + + + need to disable service libvirt-guests in CentOS packaging RPMs, or in installation docs + + + + + CLOUDSTACK-1008 + + + "Egress"" tab should not be presented in the UI for Shared Networks + + + + + CLOUDSTACK-1010 + + + Host count and Secondary storage count always shows 1 in UI + + + + + CLOUDSTACK-1011 + + + KVM host getting disconnected in cluster environment + + + + + CLOUDSTACK-1013 + + + running cloudstack overwrites default public/private ssh key + + + + + CLOUDSTACK-1014 + + + Merge ManagementServer and ManagementServerEx + + + + + CLOUDSTACK-1016 + + + Not able to deploy VM + + + + + CLOUDSTACK-1021 + + + the vlan is not creat to right nic. when i creat multi guest network + + + + + CLOUDSTACK-1024 + + + Regression: Unable to add Xenserver host with latest build. + + + + + CLOUDSTACK-1027 + + + "Update SSL certificate" button should properly reflect its functionality + + + + + CLOUDSTACK-1029 + + + Enter the token to specified project is malfunctioned + + + + + CLOUDSTACK-1037 + + + "Make cloudmonkey awesome-er: Online help docs and api discovery, better colored output, parameter value autocompletion + + + + + CLOUDSTACK-1050 + + + No Documentation on Adding a Load Balancer Rule + + + + + CLOUDSTACK-1051 + + + API dispatcher unable to find objectVO corresponding to DeleteTemplatecm + + + + + CLOUDSTACK-1055 + + + "The overlay still exists when the ""Recurring Snapshots"" dialog is canceled by pressing esc key. + + + + + CLOUDSTACK-1056 + + + S3 secondary storage fails to upload systemvm template due to KVMHA director + + + + + CLOUDSTACK-1057 + + + regression of changeServiceForVirtualMachine API - fails to find service offering by serviceOfferingId parameter + + + + + CLOUDSTACK-1063 + + + "SG Enabled Advanced Zone - "Add Guest Networks" - When user tries to add a guest Network with scope as "Account" he should NOT be presented with ""Offering for shared security group enabled"" + + + + + CLOUDSTACK-1064 + + + A type error occurs when trying to add account/register template... + + + + + CLOUDSTACK-1068 + + + Names in VR list is useles + + + + + CLOUDSTACK-1070 + + + javelin: NPE on executing registerIso AP + + + + + CLOUDSTACK-1071 + + + Netscaler element is not getting loaded as part of LoadBalancing Service Providers + + + + + CLOUDSTACK-1078 + + + Not able to start System Vms on Rhel 6.3 KVM hos + + + + + CLOUDSTACK-1079 + + + Deploying AWSAPI with mvn -pl :cloud-awsapi jetty:run fail + + + + + CLOUDSTACK-1082 + + + UI doesn't throw any error message when trying to delete ip range from a network that is in use. + + + + + CLOUDSTACK-1083 + + + listUsageRecords api: removed project results in NP + + + + + CLOUDSTACK-1087 + + + Update the Developer Guide for ASFCS 4.1 Releas + + + + + CLOUDSTACK-1088 + + + EnableStaticNat error will clear the data in databas + + + + + CLOUDSTACK-1094 + + + Ipv6 - hostname/hostname --fqdn does not return the name of the VM. But i am able to reach the Vm using their names + + + + + CLOUDSTACK-1095 + + + Ipv6 - dhclient command needs to be run manually on the Vms to get the Ipv6 address + + + + + CLOUDSTACK-1100 + + + Expunge thread is not kicked off based on global configuration if the global setting is less than 60 second + + + + + CLOUDSTACK-1103 + + + "IpV6 - listNetwork() command does not retrun gateway,netmask,cidr + + + + + CLOUDSTACK-1104 + + + Ipv6 - listVlanIpRanges() returns error 530 + + + + + CLOUDSTACK-1105 + + + "IpV6 - listVirtualMachines() does not return netmask, gateway,ipaddress. + + + + + CLOUDSTACK-1107 + + + Ipv6 - Unable to extend Ip range for a Ipv6 network using craeteVlanIpRange() command - Error code 530 returned + + + + + CLOUDSTACK-1108 + + + Ipv6 - Not able to restart Networks + + + + + CLOUDSTACK-1109 + + + "Ipv6 - Unable to expunge User Vms that are ""Destroyed"". + + + + + CLOUDSTACK-1111 + + + Ipv6 - listRouters() does not return guestipaddress + + + + + CLOUDSTACK-1112 + + + "Errors in ""Prepare the System VM Template"" + + + + + CLOUDSTACK-1113 + + + "Ipv6 - Not able to deploy a new VM in this network because of ""Unable to allocate Unique Ipv6 address"" + + + + + CLOUDSTACK-1114 + + + unable to execute listegressfirewallrules API due invalid value i + + + + + CLOUDSTACK-1115 + + + In multiple shared network unable to login with default nic - KV + + + + + CLOUDSTACK-1123 + + + ListStoragePools API broken by refacto + + + + + CLOUDSTACK-1138 + + + "Providing invalid values for gateway, netmask etc in the zoneWizard blocks the VLAN container to load, throwing an error + + + + + CLOUDSTACK-1139 + + + "After the Vm is "Expunged" we see the entry still being present in the router in /etc/dhcphosts.txt + + + + + CLOUDSTACK-1141 + + + "Ipv6 - After network restart (and reboot router), we do not see the existing vms dnsentries not being programmed in the router. + + + + + CLOUDSTACK-1152 + + + Missing tag in host-add.xm + + + + + CLOUDSTACK-1153 + + + "Ipv6 - Vm deployment fails with "n must be positive" error. + + + + + CLOUDSTACK-1154 + + + Account/Users related API failed due to RegionService inject exception. + + + + + CLOUDSTACK-1157 + + + No API Documentation on Listing Custom User Templates Using CS4 API + + + + + CLOUDSTACK-1160 + + + References to version=3.0.3|4|5|6 in API classes needs to be removed. + + + + + CLOUDSTACK-1161 + + + Differences between 4.1 and master in ongoing-config-of-external-firewalls-lb.xml + + + + + CLOUDSTACK-1163 + + + Failed with NPE while creating firewall rule + + + + + CLOUDSTACK-1168 + + + Create firewall rule broke + + + + + CLOUDSTACK-1173 + + + ConsoleProxyResource instantiation exception. + + + + + CLOUDSTACK-1174 + + + Snapshots related SQL error. + + + + + CLOUDSTACK-1176 + + + Issue with snapshots(create/list + + + + + CLOUDSTACK-1181 + + + mvn deploy db failing with NP + + + + + CLOUDSTACK-1190 + + + Make APIChecker interface throw a single sensible exception. + + + + + CLOUDSTACK-1200 + + + "Unknown column 'vm_instance.disk_offering_id' in table vm_instance, db exception shown in MS log + + + + + CLOUDSTACK-1201 + + + "Failed to create ssh key for user "cloud" /var/lib/cloud/management/.ssh/id_rsa and failed to start management server + + + + + CLOUDSTACK-1202 + + + Fail to install KVM cloud-agent. + + + + + CLOUDSTACK-1203 + + + Fail to create advance zone with SG enabled when UI allows SG enabled option. + + + + + CLOUDSTACK-1204 + + + Fail to create advance zone due to fail to add host + + + + + CLOUDSTACK-1205 + + + Ipv6 - Ubuntu 12.10 guest Vms loses default route (after it expiration time ~ 30 mts) when ipv6.autoconfig parameters are disabled except for net.ipv6.conf.lo.autoconf which is enabled. + + + + + CLOUDSTACK-1206 + + + Failure in Copy of System template + + + + + CLOUDSTACK-1210 + + + Make all pluggable services return list of api cmd classes + + + + + CLOUDSTACK-1216 + + + UUID is null for admin and failed to register user key with 4.0 + + + + + CLOUDSTACK-1218 + + + "IPv6: Shared Network - After network restart with clean option, router is assigned a different address. Name resolution for the existing guest Vms in the network fails. + + + + + CLOUDSTACK-1219 + + + Ipv6 - Provide better error messages when deploying a Vm with Ip an address that is outside the network's ip range / if the ip address already is assigned to another Vm + + + + + CLOUDSTACK-1220 + + + Ipv6 - Better error message when deploy Vm fails to get a free Ip address + + + + + CLOUDSTACK-1222 + + + API rate limit configs: removed double quote in upgrade script + + + + + CLOUDSTACK-1223 + + + Exception while starting jetty server: org.springframework.beans.factory.BeanCreationException Error creating bean with name 'apiServer' + + + + + CLOUDSTACK-1224 + + + Volume snapshot creation failing + + + + + CLOUDSTACK-1226 + + + Error while running Cloudstack-setup-database + + + + + CLOUDSTACK-1228 + + + Unable to Create System Vm's in the VMware Hypervisor setup + + + + + CLOUDSTACK-1229 + + + Incorrect SQL syntax to insert api limit related configuration items in upgrade path script. + + + + + CLOUDSTACK-1231 + + + cloud-install-sys-tmplt failed due to missing path + + + + + CLOUDSTACK-1232 + + + "Ipv6 - Guest Vms are not able to get Ipaddress when executing dhclient command when using ""/96"" network. + + + + + CLOUDSTACK-1233 + + + Veewee configuration files are inappropriately identified as ASLv2 licensed file + + + + + CLOUDSTACK-1234 + + + Unable to start KVM agent with 4.1 build. + + + + + CLOUDSTACK-1237 + + + "Register Template fails with ""Cannot find template adapter for XenServer"" + + + + + CLOUDSTACK-1239 + + + Unable to registerISO :unhandled exception executing api command: registerIs + + + + + CLOUDSTACK-1240 + + + Unable to registerTemplate : Cannot find template adapter for XenServer. + + + + + CLOUDSTACK-1241 + + + Network apply rules logic is broken. + + + + + CLOUDSTACK-1242 + + + [F5-SRX-InlineMode] Failed to create LB rule with F5-SRX inlinemode deployemen + + + + + CLOUDSTACK-1243 + + + Failed to cleanup account :java.lang.NullPointerException + + + + + CLOUDSTACK-1244 + + + fail to push sysmvm.iso onto xen host + + + + + CLOUDSTACK-1246 + + + "[ ALU beta CS 4.1 build2] ""Guest network"" missing in Add Zone wizard ( step 3, Setup Network \ Physical Network) + + + + + CLOUDSTACK-1251 + + + Baremetal zone doesn't need primary/secondary storage in UI wizard. + + + + + CLOUDSTACK-1252 + + + Failed to download default template in VMware. + + + + + CLOUDSTACK-1260 + + + Failed to register template: Unable to find template adapter + + + + + CLOUDSTACK-1261 + + + Cannot find template adapter for XenServer. + + + + + CLOUDSTACK-1262 + + + "Failed to Prepare Secondary Storage in VMware, + + + + + CLOUDSTACK-1265 + + + logrotate dnsmasq configuration is wrong + + + + + CLOUDSTACK-1267 + + + KVM's cloudstack-agent service doesn't log (log4j) + + + + + CLOUDSTACK-1269 + + + Failed to start CPVM java.lang.NullPointerException Unable to start SSVM + + + + + CLOUDSTACK-1272 + + + Autoscale: createAutoScaleVmProfile fails due to unable to retrieve Service Offering ip + + + + + CLOUDSTACK-1274 + + + UpdateNetworkCmd throws NP + + + + + CLOUDSTACK-1276 + + + Remove autoscanning for 4.1 + + + + + CLOUDSTACK-1277 + + + ApiResponseHelper.createUserVmResponse failed to populate password field set from UserVm object + + + + + CLOUDSTACK-1278 + + + Improper permissions on injectkeys.s + + + + + CLOUDSTACK-1288 + + + [F5-SRX-InlineMode] classCastException during network restart with cleanup option true + + + + + CLOUDSTACK-1289 + + + [F5-SRX-InlineMode] Usage stats are not generated for Juniper SRX Firewall in inlinemod + + + + + CLOUDSTACK-1290 + + + listNetoworks API takes too long to respond + + + + + CLOUDSTACK-1292 + + + "[F5-SRX-InlineMode] Update network from SRX,F5 as service provideds to VR as service provider does not delete firewall rules from SRX + + + + + CLOUDSTACK-1295 + + + NPE in usage parsers due to missing @Component inject + + + + + CLOUDSTACK-1299 + + + Errors in 4.5.5 section of installation guide + + + + + CLOUDSTACK-1300 + + + section in wrong order in installation guide + + + + + CLOUDSTACK-1303 + + + Ipv6 - java.lang.NullPointerException when executing listnetworks() and deployVirtualMachine() after extending the Ipv4 range of a dual stack network + + + + + CLOUDSTACK-1307 + + + Noticed NPE when we put host in maintenance mode in clustered management setup + + + + + CLOUDSTACK-1310 + + + ASF-build-master-nonoss-rhel63 - create advance zone FAIL - CreatePhysicalNetworkCmd FAIL - MySQLIntegrityConstraintViolationException: Duplicate entry '200-Public' for key 'physical_network_id + + + + + CLOUDSTACK-1312 + + + "Fix rolling upgrades from 4.0 to 4.1 in 4.1 release, fix db schemas to be same as 4.0 + + + + + CLOUDSTACK-1313 + + + Working with Volumes Section Is Missing + + + + + CLOUDSTACK-1315 + + + [F5-SRX-InlineMode] Network implement failed with Run time Exception during network upgrade from VR to SRX-F + + + + + CLOUDSTACK-1319 + + + createCustomerVpnGateway response gives TypeError: json.createvpncustomergatewayresponse is undefined + + + + + CLOUDSTACK-1320 + + + Routers naming convention is changed to hostname. + + + + + CLOUDSTACK-1321 + + + [Site-to-Site VPN] No events are generated in case of status change in site to site vpn connection + + + + + CLOUDSTACK-1326 + + + KVM - Failed to start cloud agent from SSVM + + + + + CLOUDSTACK-1328 + + + console view unable to connect - CPVM SSVM guest VM + + + + + CLOUDSTACK-1329 + + + "API listRouters response returns hostname instead of Virtual Routers, UI displays host entry for each VR + + + + + CLOUDSTACK-1330 + + + ec2-run-instances - When -n option is used to deploy multiple Vms API returns error even though few of the Vms have been deployed successfully + + + + + CLOUDSTACK-1331 + + + Upgrade fails for a 2.2.14 Zone having multiple guest networks using network_tags and Public Vlan + + + + + CLOUDSTACK-1332 + + + IPV6 - Router and guest Vms should be able to use an IPV6 address for external DNS entry + + + + + CLOUDSTACK-1334 + + + vmware.root.disk.controller doesn't work + + + + + CLOUDSTACK-1337 + + + Zone to zone template/ISO copy fails and template/ISO download also fail + + + + + CLOUDSTACK-1338 + + + Deploy VM failed using IS + + + + + CLOUDSTACK-1339 + + + ASF 4.1: Management server becomes unresponsive + + + + + CLOUDSTACK-1341 + + + URL for the KEYs file is wrong in the installation guide + + + + + CLOUDSTACK-1342 + + + Document installation and usage of cloudmonkey for 4.1 docs + + + + + CLOUDSTACK-1343 + + + Porting Baremetal related UI changes to ACS + + + + + CLOUDSTACK-1344 + + + Typo in use.external.dns setting description + + + + + CLOUDSTACK-1345 + + + BigSwitch plugin introduces 'VNS' isolation in UI without backend implementation + + + + + CLOUDSTACK-1346 + + + "Check to see if external devices are used in the network, is hardcoded for specific devices + + + + + CLOUDSTACK-1347 + + + "Not able to delete network. Error - ""Unable to insert queue item into database, DB is full?"" + + + + + CLOUDSTACK-1348 + + + API/UI: zoneObj is undefined. + + + + + CLOUDSTACK-1349 + + + "VPC network Adding Network ACls, PF rules - Unable to insert queue item into database, DB is full? PF rules and NW Acls in Add state in DB + + + + + CLOUDSTACK-1350 + + + Management server Stop and start causes previously downloaded ISOs and templates to redownload & reinstall. + + + + + CLOUDSTACK-1353 + + + KVM 6.3 snapshot Scheduling snapshot failed due to java.lang.NullPointerExceptio + + + + + CLOUDSTACK-1357 + + + "Autoscale: Provisioned VMs from Netscaler not being added to lb vserver, provserver fails with provserver_err_asynctaskpoll + + + + + CLOUDSTACK-1360 + + + The clusterid field of the createStoragePool API command should be documented as required. + + + + + CLOUDSTACK-1367 + + + NPE noticed in logs while AgentMonitor is monitoring the host ping interval + + + + + CLOUDSTACK-1368 + + + Shared network - Not able to delete network because of java.lang.NullPointerException + + + + + CLOUDSTACK-1369 + + + "Ipv6 - In dual Stack network, guest VM does not have the Ipv6 address of the router programmed in /etc/resolv.conf for DNS resolution. + + + + + CLOUDSTACK-1370 + + + DeployVM Fail - VPC or non-VPC network + + + + + CLOUDSTACK-1375 + + + deploydb failing with acs master + + + + + CLOUDSTACK-1376 + + + Unable to migrate VM due to internal error process exited while connecting to monitor + + + + + CLOUDSTACK-1377 + + + HA fail - when host is shutdown, VMs and SSVMs are not failover to second host in cluster. + + + + + CLOUDSTACK-1382 + + + vm deploy fails with Error "cannot find DeployPlannerSelector for vm" + + + + + CLOUDSTACK-1383 + + + Deploying basic zone on 4.1 fails in NP + + + + + CLOUDSTACK-1386 + + + BASIC zone SSVM fail to start due to exception + + + + + CLOUDSTACK-1388 + + + UI - ListUsers doesnt display any User except the Default Root Admin User + + + + + CLOUDSTACK-1391 + + + EventBus is not getting injected after javelin merge + + + + + CLOUDSTACK-1394 + + + [F5-SRX-InlineMode] Failure in static nat configuration on SRX does not result in LB configuration error in CS during LB rule configuratio + + + + + CLOUDSTACK-1397 + + + Static Nat configuration is failing with NP + + + + + CLOUDSTACK-1399 + + + Unhandled exception executing api command: stopVirtualMachine + + + + + CLOUDSTACK-1402 + + + listRouters API response doesn't return linklocal IP and public IP detail + + + + + CLOUDSTACK-1403 + + + Storage and console-proxy related error + + + + + CLOUDSTACK-1411 + + + Issues with VMWare Hypervisor host_ids not updated when ESX(i) crashes in instance table + + + + + CLOUDSTACK-1414 + + + Redundant router: BACKUP switch cancelled due to lock timeout after a glitch in network. + + + + + CLOUDSTACK-1417 + + + When invalid values are passed to createNetwork(), error message does not indicate the parameter name that has invalid values. + + + + + CLOUDSTACK-1418 + + + As regular user, we are not allowed to deploy VM on a shared network. + + + + + CLOUDSTACK-1419 + + + Apache-ify and apply trademark logos in the UI + + + + + CLOUDSTACK-1420 + + + Ensure trademarks are properly attributed in publican brand + + + + + CLOUDSTACK-1423 + + + Unable to launch UI [HTTP Status 404]. + + + + + CLOUDSTACK-1425 + + + unhandled exception executing api command: migrateVirtualMachine & recoverVirtualMachine + + + + + CLOUDSTACK-1427 + + + Failed to delete Guestnetwork which has LB with Netscaler + + + + + CLOUDSTACK-1428 + + + [UI] Instance which are created without display name are not visible when added to LB + + + + + CLOUDSTACK-1429 + + + single account is unable to use same vnet across multiple physical network + + + + + CLOUDSTACK-1436 + + + 4.1 management server fails to start from RPM build artifact + + + + + CLOUDSTACK-1443 + + + As domain admin we are allowed to create shared network + + + + + CLOUDSTACK-1446 + + + [UI]VPC Router type should be of type vpc and not syste + + + + + CLOUDSTACK-1447 + + + [UI]Persistent Status is not displayed for VPC Tier + + + + + CLOUDSTACK-1449 + + + listAccounts and listProjectAccounts API lists all the users not account-specific users for each account returne + + + + + CLOUDSTACK-1451 + + + Getting EntityExistsException while creating more than one project in CS 4. + + + + + CLOUDSTACK-1452 + + + Public IP's are assigned to private interface with VPC Restart [PF/LB rules are not functional + + + + + CLOUDSTACK-1461 + + + "Ipv6 - From a Vm that that is part of 2 networks, non default network router's details should not get programmed in the DNS entries of the guest VM. + + + + + CLOUDSTACK-1463 + + + IPV6 - Ubuntu 12.10 - Multiple Nic - IPV6 address is assigned automatically for 1 nic only. Need to do a manual dhclient request to get the ipv6 for other nic + + + + + CLOUDSTACK-1464 + + + "IPV6 - Multi nic - Ubuntu 1210 -When Vm is stopped and started/ rebooted, i get multiple global IPV6 addresses being allocated for one of the nics. + + + + + CLOUDSTACK-1465 + + + List Zones returns null under create instance when logged is as use + + + + + CLOUDSTACK-1467 + + + Failed to create Volume for the System Vm's + + + + + CLOUDSTACK-1469 + + + kvm agent: agent service fails to start u + + + + + CLOUDSTACK-1470 + + + unhandled exception executing api command: deployVirtualMachin + + + + + CLOUDSTACK-1472 + + + AssignVirtualMachine API with wrong Virtual Instance ID failed with NP + + + + + CLOUDSTACK-1473 + + + deleteDomain is failing with NP + + + + + CLOUDSTACK-1481 + + + "IPV6 - When Vm is part of 1 dual network and 1 ipv6 network, name resolution using fqdn fails for the ipv6 network. + + + + + CLOUDSTACK-1482 + + + IPV6 - We are not allowed to create a shared IPV6 network with a VLAN which already is associated with a IPV4 network + + + + + CLOUDSTACK-1484 + + + "API Throttling : api.throttling.enabled, Global setting missing + + + + + CLOUDSTACK-1485 + + + Add Baremetal Provider back to 4.1 branc + + + + + CLOUDSTACK-1487 + + + cloudstack-setup-agent fails to set private.network.device on KVM host ad + + + + + CLOUDSTACK-1488 + + + "Ipv6 - When Vm is deployed as part of multiple networks, one of the IPV6 address assigned to guest VM is lost. + + + + + CLOUDSTACK-1490 + + + 4.1 deb management fails to start due to tomcat dep problem + + + + + CLOUDSTACK-1496 + + + List API Performance: listAccounts failing with OOME for high values of pagesize (>1000 + + + + + CLOUDSTACK-1499 + + + ListAPI Performance for few APIs not as good as it was before API optimizatio + + + + + CLOUDSTACK-1503 + + + listHypervisor API not getting fired when logged in as Use + + + + + CLOUDSTACK-1505 + + + Unknown column 'domain.region_id' in 'field list + + + + + CLOUDSTACK-1509 + + + Failed to implement network elements and resources while provisioning for persistent network(createVlanIpRange to an account + + + + + CLOUDSTACK-1511 + + + [UI] Instances NIC details does not have Network Nam + + + + + CLOUDSTACK-1512 + + + [UI] Wrong message[message.configure.all.traffic.types] when trying to create zone with mulitple physical networks without providing the traffic labe + + + + + CLOUDSTACK-1515 + + + None of the cloudstack packges are marked for upgrade when tried to upgrade from.4.0/4.0.1 to 4. + + + + + CLOUDSTACK-1516 + + + Create documentation in languages that have translations availabl + + + + + CLOUDSTACK-1517 + + + Check UI in languages availabl + + + + + CLOUDSTACK-1521 + + + Redundant router: Services are not stopped when switch to BACKUP stat + + + + + CLOUDSTACK-1526 + + + Template registration fails in the VMware Setup + + + + + CLOUDSTACK-1531 + + + vmware create volume from snapshot will missing dat + + + + + CLOUDSTACK-1537 + + + Restart network with clean up set to true causes Autoscaled LB rule to get mangled and unusabl + + + + + CLOUDSTACK-1541 + + + NPE while deleting snapshot :Unexpected exception while executing org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotCm + + + + + CLOUDSTACK-1542 + + + unhandled exception while creating projec + + + + + CLOUDSTACK-1544 + + + The description and the response format for the deleteUser command are incorrec + + + + + CLOUDSTACK-1550 + + + createaccountresponse returns more than the user you requested for creation + + + + + CLOUDSTACK-1553 + + + AWS Regions-Not able to list accounts from the 2nd region after user/account/domain details have been manually synced up from first region + + + + + CLOUDSTACK-1555 + + + "AWS Regions - userapikey and usersecretkey parameters are not returned in the response of addRegion, updateRegion listRegion api calls.. + + + + + CLOUDSTACK-1557 + + + EC2 REST API : cloudbridge database is missing on the CloudStack Installatio + + + + + CLOUDSTACK-1562 + + + Replace the short-cut solution of supportting @DB with the formal on + + + + + CLOUDSTACK-1565 + + + "Used Master Branch System VM Template: Default Route on the System VMs (SSVM,CPVM and VR) is missing + + + + + CLOUDSTACK-1566 + + + Baremetal API addBaremetalPxePingServer fail to add PXE PING server to deployment causing create instance with PING style image to fai + + + + + CLOUDSTACK-1569 + + + "AWS Regions - Not able to Edit domain/account/user from a region that is not the owner region.""The content of elements must consist of well-formed character data or markup."" - error message presented to the user. + + + + + CLOUDSTACK-1571 + + + "AWS Regions - When deleting domain/account/user from a region that is not the owner, the request is not being forwarded to the owner region. + + + + + CLOUDSTACK-1574 + + + updateResourceCount API is failed saying to specify valida resource type even after parsing the valid resource typ + + + + + CLOUDSTACK-1583 + + + AWS Regions - RabbitMQ Server did not recieve any event notification during account creation + + + + + CLOUDSTACK-1587 + + + "Basic zone - CPVM fail to go to running state, Exception while trying to start secondary storage vm + + + + + CLOUDSTACK-1588 + + + "AWS Regions - When registerUserKeys() is called for a user from a region that is not the owner, it is handled by this region. + + + + + CLOUDSTACK-1600 + + + Typo in dpkg-buildpackage comman + + + + + CLOUDSTACK-1604 + + + "deploy VM failed when global setting ""vm.allocation.algorithm"" is set to ""userdispersing"" + + + + + CLOUDSTACK-1615 + + + "VMware Cluster discovery fails with if ESXi version is 5.0 Update 1, build 721882 + + + + + CLOUDSTACK-1620 + + + Cannot provision CentOS 6 VMs on XenServer 6. + + + + + CLOUDSTACK-1621 + + + listProjectInvitations fails with NPE for valid request + + + + + CLOUDSTACK-1624 + + + API is not returning response in details:UI is also not returning any outpu + + + + + CLOUDSTACK-1625 + + + NPE with updateResourceCount when && is passed thru AP + + + + + CLOUDSTACK-1630 + + + 4.0.x cloud-aws-api not properly obsoleted + + + + + CLOUDSTACK-1631 + + + 4.1 RPM packaging broke + + + + + CLOUDSTACK-1636 + + + AWS Regions - Remove the concept of having an owner region for domain/account/user objects + + + + + CLOUDSTACK-1642 + + + Add support CentOS 6. + + + + + CLOUDSTACK-1648 + + + Unable to add KVM hos + + + + + CLOUDSTACK-1649 + + + vmware vm os type erro + + + + + CLOUDSTACK-1651 + + + agent scripts still pointing to /var/log/cloud + + + + + CLOUDSTACK-1656 + + + NicResponses in a UserVmResponse are not preseving the natural order + + + + + CLOUDSTACK-1663 + + + AWS Regions - Events - There are no events being generated when a new domain is added/edited + + + + + CLOUDSTACK-1664 + + + Action Events are not logged due to spring change + + + + + CLOUDSTACK-1665 + + + AWS Regions - Events - There are no events being generated when a new user is added/edited/enabled/deleted/password changes/api & secret keys are generated + + + + + CLOUDSTACK-1666 + + + KVM VPC NetworkUsage doesnot wor + + + + + CLOUDSTACK-1668 + + + IP conflict in VPC tie + + + + + CLOUDSTACK-1671 + + + AWS Regions - Events - Domain Delete event does not include the UUID of the domain that was deleted + + + + + CLOUDSTACK-1674 + + + AWS Regions - Events - Account Deletion event does not include the UUID of the account deleted + + + + + CLOUDSTACK-1681 + + + Upgrade instructions mention incorrect name and description of systemvm-vmware template in registering template section + + + + + CLOUDSTACK-1684 + + + "api.throttling.enabled configuration setting should be set to ""false"" in Config.java + + + + + CLOUDSTACK-1688 + + + AWS Regions - Domain admin user is not able to use getUser() command to fetch user details + + + + + CLOUDSTACK-1690 + + + NPE from API server when starting mgmt serve + + + + + CLOUDSTACK-1694 + + + Issues to start/access Management Server after upgrade from 4.0 to 4. + + + + + CLOUDSTACK-1697 + + + Six DB tables are not available with upgraded setup(4.0 to 4.1) when compare to 4.1 newly installatio + + + + + CLOUDSTACK-1706 + + + "Failed to deploy VM with error ""cannot find DeployPlannerSelector"" + + + + + CLOUDSTACK-1709 + + + "AWS Regions - As part of adding a new region, project related entries should not be synced from accounts table. + + + + + CLOUDSTACK-1710 + + + "AWS Regions - As part of adding a new region,default_zone_id column for the account entries should not be synced. + + + + + CLOUDSTACK-1711 + + + AWS Regions - Include all the details of the API call made in the Events payload when changes in Admin/Account/User objects are made. + + + + + CLOUDSTACK-1713 + + + EC2 REST API: AWS API Installation Problem + + + + + CLOUDSTACK-1714 + + + Doc section has wrong title: Setting Zone VLAN and Running VM Maximum + + + + + CLOUDSTACK-1715 + + + "Missing ""host"" config setting in docs on management server load balancing + + + + + CLOUDSTACK-1716 + + + "AWS Regions - listRegions(),removeRegions(),updateRegions() should accept UUID value instead of id. + + + + + CLOUDSTACK-1718 + + + AWS Regions - removeRegion() response returns updateregionresponse + + + + + CLOUDSTACK-1719 + + + EC2 REST API: AWS APIs are not getting translated on the CloudStack Management Serve + + + + + CLOUDSTACK-1720 + + + Have an upgrade path from 4.0.x to 4.1 and 4.0.x to 4.2. + + + + + CLOUDSTACK-1729 + + + Ensure adapter execution order in runtim + + + + + CLOUDSTACK-1733 + + + [ACS41][UI] Add guest network is missing ip range fields and missing network offering + + + + + CLOUDSTACK-1736 + + + Ubuntu 12.04 cloud-setup-management Failed to configure CloudStack Management Serve + + + + + CLOUDSTACK-1738 + + + StatsCollector is not runnin + + + + + CLOUDSTACK-1740 + + + Failed to view consol + + + + + CLOUDSTACK-1746 + + + Cloudstack Usage Server won't star + + + + + CLOUDSTACK-1747 + + + "mvn deploydb only creates 4.0 DB, not 4.1 + + + + + CLOUDSTACK-1750 + + + injectkeys script fails on OSX because cp does not have a -b option (backup of destination file + + + + + CLOUDSTACK-1761 + + + Available local storage disk capacity incorrectly reported in KVM to manager + + + + + CLOUDSTACK-1764 + + + ListTemplateCommand failed with java.lang.NumberFormatException and failed to create default template. + + + + + CLOUDSTACK-1772 + + + the change in vnc listening port will cause live migration doesn't work. + + + + + CLOUDSTACK-1773 + + + Disable baremetal functionality + + + + + CLOUDSTACK-1776 + + + NPE on listSecondaryStorageHostsInAllZones in Upgraded setup from 4.0 to 4.1.0 + + + + + CLOUDSTACK-1785 + + + Redundant Router test cases failing during automation run. + + + + + CLOUDSTACK-1789 + + + Unable to download templates to Primary Storage if a host is in maintenance. + + + + + CLOUDSTACK-1791 + + + Volumes with storage tags can't be attached. + + + + + CLOUDSTACK-1792 + + + "AWS Regions - RuntimeException while executing listAccounts(), when the encryption keys are set to different values between regions. + + + + + CLOUDSTACK-1793 + + + L10n docs don't build in chinese, portuguese and japanese + + + + + CLOUDSTACK-1795 + + + Customize AOP to fully support legacy CloudStack @DB and @ActionEvent semantics. + + + + + CLOUDSTACK-1796 + + + Japanese docs don't build. + + + + + CLOUDSTACK-1802 + + + Upgrade 4.0 -> 4.1 - Not able to start management server becasue of missing /etc/cloudstack/management/tomcat6.conf file + + + + + CLOUDSTACK-1804 + + + Upgrade 4.0 -> 4.1 - DB upgrade fails + + + + + CLOUDSTACK-1805 + + + com.mysql.jdbc.exceptions.jdbc4.CommunicationsException seen after long time of inactivity resulting in not being able to log in to the management server + + + + + CLOUDSTACK-1810 + + + listTemplate API with templatefilter=featured|community is not returning any lists + + + + + CLOUDSTACK-1811 + + + "Upgrade 4.0->4.1 - When upgrade scripts fail, component loading continues and management server starts. + + + + + CLOUDSTACK-1812 + + + create physical network fails while creating basic zon + + + + + CLOUDSTACK-1825 + + + EC2 REST API: AWS APIs fail to execute due to BeanCreationException: Error creating bean with name 'SAclDaoImpl + + + + + CLOUDSTACK-1826 + + + "Storage migration not working, seemingly due to uuid vs id + + + + + CLOUDSTACK-1827 + + + Redundant router - When VR Master was stopped failover to VR Backup did not occur. + + + + + CLOUDSTACK-1834 + + + "Events are not generated for registerUserKeys(), Enabling account and Editing account. + + + + + CLOUDSTACK-1836 + + + License header failures for ja-JP .po translation file + + + + + CLOUDSTACK-1839 + + + Upgrade 4.0 -> 4.1 - Upgraded DB has lot more keys and indexes for many tables compare to the fresh installed 4.1 DB + + + + + CLOUDSTACK-1841 + + + ASF 4.0 to 4.1 Upgrade: Missing Few Global Configuration parameters on the Upgraded Setup. + + + + + CLOUDSTACK-1842 + + + ASF 4.0 to 4.1 Upgrade: Missing Ubuntu 12.04 Guest OS Types on the Upgraded Setup. + + + + + CLOUDSTACK-1844 + + + Upgrade 4.0 -> 4.1 - KVM host agent.properties is not restored as part of upgrading the binaries from 4.0 to 4.1. + + + + + CLOUDSTACK-1845 + + + KVM - storage migration often fail. + + + + + CLOUDSTACK-1846 + + + "KVM - storage pools can silently fail to be unregistered, leading to failure to register later. + + + + + CLOUDSTACK-1848 + + + Cloudstack Packages are not got updated with scenario 4.0 to 4.1 upgrade where MS is on Ubuntu 12.04. + + + + + CLOUDSTACK-1856 + + + Upgrade 4.0 -> 4.1 - Fresh install of 4.1 has 3 parameters missing in db.properties compared to an upgraded 4.0 set up + + + + + CLOUDSTACK-1873 + + + "Installation : JasyptPBEStringDecryptionCLI missing, failed to decrypt db password + + + + + CLOUDSTACK-1874 + + + AWS Regions - Account table in cloud_usage DB has region_id + + + + + CLOUDSTACK-1876 + + + External Devices - network offering for external devices is not returned in API listNetworkOfferings when creating instances. + + + + + CLOUDSTACK-1877 + + + Failed to connect to DB while starting Ubuntu management server after upgrading the packages from 4.0 to 4.1.0 + + + + + CLOUDSTACK-1882 + + + “HTTP Status 404 。 The requested resource () is not available. + + + + + CLOUDSTACK-1890 + + + listProjects is not listing state in the respons + + + + + CLOUDSTACK-1900 + + + "Upgrade 4.0 -> 4.1, We do not have a copy of db.properties that comes from a 4.1 installation saved anywhere. + + + + + CLOUDSTACK-1929 + + + ASF 4.1 cloudstack agent fail to install in KVM host CENTOS 6.3 OS: qemu-kvm-0.12.1.2-3.295.el6.10.x86_64 requires libusbredirparser.so. + + + + + CLOUDSTACK-1934 + + + NPE with listSupportedNetworkServices after upgrade from 4.0 to 4.1 (Ubuntu MS + + + + + CLOUDSTACK-1935 + + + Cloud utilities are not renamed to Cloudstack after upgrade from 4.0 to 4.1 [Ubutnu MS + + + + + CLOUDSTACK-1936 + + + On CentOS, after a upgrade from 4.0.1 to 4.1 on a cloud node (cloud-agent), the new cloustack-agent isn't add as a service (chkconfig) + + + + + CLOUDSTACK-1951 + + + centos packaging: cloud-install-sys-tmplt can't find jasypt jar. + + + + + CLOUDSTACK-1971 + + + VM deployed to incorrect primary storage. + + + + + CLOUDSTACK-1972 + + + VM deployed to incorrect primary storage. + + + + + CLOUDSTACK-1978 + + + openvswitch - unable to start console session for SSVM CPVM user VM + + + + + CLOUDSTACK-1980 + + + "[4.1]cloudstack-setup-bridge, cloudstack-setup-encryption & cloudstack-sysvmadm utilities are not available in Ubuntu 12.04 Management Server. + + + + + CLOUDSTACK-1987 + + + Deleted service offerings owned by a domain show up to domain user. + + + + + CLOUDSTACK-1988 + + + AWS API using SOAP client - User Registeration fails + + + + + CLOUDSTACK-1989 + + + "Query service offering by ID returns no result, but querying all returns service offering + + + + + CLOUDSTACK-2003 + + + Deleting domain while deleted account is cleaning up leaves VMs expunging forever due to 'Failed to update resource count + + + + + CLOUDSTACK-2007 + + + Release Notes failing to build on jenkins.cs. + + + + CS-16135 + Creating volumes after upgrading from snapshot taken in 2.2.14 no longer deletes the snapshot physically from the secondary storage. + + + + +
+
+ Known Issues in 4.1.0 + + + + + + + + Issue ID + + + Description + + + + + + CLOUDSTACK-1747 + mvn deploydb only creates 4.0 DB, not 4.1 + Due to tooling changes between 4.1 and 4.2, CloudStack's database is created using the 4.0 schema and updated to the 4.1 schema when the management server starts for the first time. It's OK to see the same schema if the management server has not started yet. + + + + CLOUDSTACK-1824 + Service CloudStack-Management is being displayed as cloud-management service + Many scripts and text entries have references to cloud-management rather than cloudstack-management due to the changeover between 4.0 and 4.1 to rename services. This is a minor issue and should be corrected by 4.2. + + + + + CLOUDSTACK-1824 + Service CloudStack-Management is being displayed as cloud-management service + + + + + CLOUDSTACK-1510 + + + NPE when primary storage is added with wrong path + + + + + CLOUDSTACK-1428 + + + [UI] Instance which are created without display name are not visible when added to LB + + + + + CLOUDSTACK-1306 + + + Better Error message when trying to deploy Vm by passing static Ipv4 addresses that are assigned to another VM/IP4 address is outside the iprange. + + + + + CLOUDSTACK-1236 + + + Warning while adding Xen 6.1 host [Unable to create local link network] + + + + + CLOUDSTACK-969 + + + api: zone response lists vlan in it as "vlan range of zone" but the vlan belongs to physical network + + + + + CLOUDSTACK-963 + + + [cloud.utils.AnnotationHelper] class java.lang.Stringdoes not have a Table annotation + + + + + CLOUDSTACK-458 + + + xen:snapshots:Storage gc fail to clean the failed snapshot images from secondarystorage + + + + + CLOUDSTACK-315 + + + Infrastructure view does not show capacity values + + + + + CLOUDSTACK-300 + + + Creation of compute offering allow combination of local storage + HA + + + + + CLOUDSTACK-282 + + + Virtual Routers do not properly resolve DNS SRV Records + + + + + CLOUDSTACK-276 + + + SSVM ID is exposed in the Error Message thrown by AddTrafficType API + + + + + CLOUDSTACK-270 + + + Ui should not ask for a vlan range if the physical network isolation type is not VLAN + + + + + CLOUDSTACK-245 + + + VPC ACLs are not stored and programmed consistently + + + + + CLOUDSTACK-231 + + + Tag creation using special charecters + + + + + CLOUDSTACK-124 + + + NetworkGarbageCollector not cleaning up networks + + + + + CLOUDSTACK-62 + + + console proxy does not support any keymaps besides us, jp + + + + + +
+
Upgrade Instructions This section contains upgrade instructions from prior versions of CloudStack to Apache CloudStack 4.1.0. We include instructions on upgrading to Apache CloudStack from pre-Apache versions of Citrix CloudStack (last version prior to Apache is 3.0.2) and from the releases made while CloudStack was in the Apache Incubator. @@ -102,17 +4038,17 @@ under the License. Restart the agent: -service cloud-agent stop -killall jsvc -service cloudstack-agent start + service cloud-agent stop + killall jsvc + service cloudstack-agent start During the upgrade, log4j-cloud.xml was simply copied over, so the logs will continue to be added to /var/log/cloud/agent/agent.log. There's nothing wrong with this, but if you prefer to be consistent, you can change this by copying over the sample configuration file: -cd /etc/cloudstack/agent -mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml -service cloudstack-agent restart + cd /etc/cloudstack/agent + mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml + service cloudstack-agent restart @@ -132,12 +4068,12 @@ service cloudstack-agent restart # tail -f sysvm.log The output to sysvm.log will look something like this: -Stopping and starting 1 secondary storage vm(s)... -Done stopping and starting secondary storage vm(s) -Stopping and starting 1 console proxy vm(s)... -Done stopping and starting console proxy vm(s). -Stopping and starting 4 running routing vm(s)... -Done restarting router(s). + Stopping and starting 1 secondary storage vm(s)... + Done stopping and starting secondary storage vm(s) + Stopping and starting 1 console proxy vm(s)... + Done stopping and starting console proxy vm(s). + Stopping and starting 4 running routing vm(s)... + Done restarting router(s). @@ -886,12 +4822,12 @@ Done restarting router(s). # tail -f sysvm.log The content should be like the following: -Stopping and starting 1 secondary storage vm(s)... -Done stopping and starting secondary storage vm(s) -Stopping and starting 1 console proxy vm(s)... -Done stopping and starting console proxy vm(s). -Stopping and starting 4 running routing vm(s)... -Done restarting router(s). + Stopping and starting 1 secondary storage vm(s)... + Done stopping and starting secondary storage vm(s) + Stopping and starting 1 console proxy vm(s)... + Done stopping and starting console proxy vm(s). + Stopping and starting 4 running routing vm(s)... + Done restarting router(s). @@ -1083,210 +5019,6 @@ Done restarting router(s). - - Version 4.1.0 -
- What’s New in 4.1 - Apache CloudStack 4.1.0 includes many new features. This section covers the most prominent new features and changes. -
-
- Issues Fixed in 4.1.0 - Apache CloudStack uses Jira - to track its issues. All new features and bugs for 4.1.0 have been tracked in Jira, and have - a standard naming convention of "CLOUDSTACK-NNNN" where "NNNN" is the issue number. - This section includes a summary of known issues against 4.0.0 that were fixed in 4.1.0. - - - - - - - - Defect - - - Description - - - - - - CS-16135 - Creating volumes after upgrading from snapshot taken in 2.2.14 no longer - deletes the snapshot physically from the secondary storage. - - - - -
-
- Known Issues in 4.1.0 - - - - - - - - Issue ID - - - Description - - - - - - CLOUDSTACK-1747 - mvn deploydb only creates 4.0 DB, not 4.1 - Due to tooling changes between 4.1 and 4.2, CloudStack's database is created using the 4.0 schema and updated to the 4.1 schema when the management server starts for the first time. It's OK to see the same schema if the management server has not started yet. - - - - CLOUDSTACK-1824 - Service CloudStack-Management is being displayed as cloud-management service - Many scripts and text entries have references to cloud-management rather than cloudstack-management due to the changeover between 4.0 and 4.1 to rename services. This is a minor issue and should be corrected by 4.2. - - - - - CLOUDSTACK-1824 - Service CloudStack-Management is being displayed as cloud-management service - - - - - CLOUDSTACK-1510 - - - NPE when primary storage is added with wrong path - - - - - CLOUDSTACK-1428 - - - [UI] Instance which are created without display name are not visible when added to LB - - - - - CLOUDSTACK-1306 - - - Better Error message when trying to deploy Vm by passing static Ipv4 addresses that are assigned to another VM/IP4 address is outside the iprange. - - - - - CLOUDSTACK-1236 - - - Warning while adding Xen 6.1 host [Unable to create local link network] - - - - - CLOUDSTACK-969 - - - api: zone response lists vlan in it as "vlan range of zone" but the vlan belongs to physical network - - - - - CLOUDSTACK-963 - - - [cloud.utils.AnnotationHelper] class java.lang.Stringdoes not have a Table annotation - - - - - CLOUDSTACK-458 - - - xen:snapshots:Storage gc fail to clean the failed snapshot images from secondarystorage - - - - - CLOUDSTACK-315 - - - Infrastructure view does not show capacity values - - - - - CLOUDSTACK-300 - - - Creation of compute offering allow combination of local storage + HA - - - - - CLOUDSTACK-282 - - - Virtual Routers do not properly resolve DNS SRV Records - - - - - CLOUDSTACK-276 - - - SSVM ID is exposed in the Error Message thrown by AddTrafficType API - - - - - CLOUDSTACK-270 - - - Ui should not ask for a vlan range if the physical network isolation type is not VLAN - - - - - CLOUDSTACK-245 - - - VPC ACLs are not stored and programmed consistently - - - - - CLOUDSTACK-231 - - - Tag creation using special charecters - - - - - CLOUDSTACK-124 - - - NetworkGarbageCollector not cleaning up networks - - - - - CLOUDSTACK-62 - - - console proxy does not support any keymaps besides us, jp - - - - - -
-
From 48c1c008913b0db7e4fde96dadd119a8ad263a6e Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 15 Apr 2013 11:01:59 +0530 Subject: [PATCH 081/107] Scale UP VM form functionality for choosing a service offering --- ui/scripts/instances.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 1c4c38c75fd..21b58aee039 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -1082,9 +1082,36 @@ scaleUp:{ label:'scaleUp VM', + createForm:{ + title:'Scale UP Virtual Machine', + label:'Scale UP Virtual Machine', + fields:{ + serviceOffering: { + label: 'label.compute.offering', + select: function(args) { + $.ajax({ + url: createURL("listServiceOfferings&VirtualMachineId=" + args.context.instances[0].id), + dataType: "json", + async: true, + success: function(json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items = []; + $(serviceofferings).each(function() { + items.push({id: this.id, description: this.displaytext}); + }); + args.response.success({data: items}); + } + }); + } + } + + + } + }, + action: function(args) { $.ajax({ - url: createURL("scaleVirtualMachine&id=" + args.context.instances[0].id + "&serviceofferingid=" + args.context.instances[0].serviceofferingid), + url: createURL("scaleVirtualMachine&id=" + args.context.instances[0].id + "&serviceofferingid=" + args.data.serviceOffering), dataType: "json", async: true, success: function(json) { From 0abfe240c31e410e286169ac1f75aa564f267280 Mon Sep 17 00:00:00 2001 From: Talluri Date: Mon, 15 Apr 2013 16:47:34 +0530 Subject: [PATCH 082/107] CLOUDSTACK-1995: Enhance resize volume tests to support xenserver hypervisor and fix few test flow errors Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_volumes.py | 55 +++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py index 36eb5ded263..7d910d48eca 100644 --- a/test/integration/smoke/test_volumes.py +++ b/test/integration/smoke/test_volumes.py @@ -78,13 +78,13 @@ class Services: "password": "password", "ssh_port": 22, "diskname": "TestDiskServ", - "hypervisor": 'XenServer', + "hypervisor": 'KVM', "privateport": 22, "publicport": 22, "protocol": 'TCP', "diskdevice": "/dev/xvdb", - "ostype": 'CentOS 5.3 (64-bit)', - "mode": 'basic', + "ostype": 'CentOS 5.5 (64-bit)', + "mode": 'advanced', "sleep": 10, "timeout": 600, } @@ -358,6 +358,12 @@ class TestVolumes(cloudstackTestCase): def setUp(self): self.apiClient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created volumes + cleanup_resources(self.apiClient, self.cleanup) + return @attr(tags = ["advanced", "advancedns", "smoke"]) def test_02_attach_volume(self): @@ -535,9 +541,13 @@ class TestVolumes(cloudstackTestCase): try: response = self.apiClient.resizeVolume(cmd) except Exception as ex: - if str(ex) == "HTTP Error 431: 431": + #print str(ex) + if "HTTP Error 431:" in str(ex): success = True - self.assertEqual(success, True, "ResizeVolume - verify invalid id is handled appropriately") + self.assertEqual( + success, + True, + "ResizeVolume - verify invalid id is handled appropriately") # Next, we'll try an invalid disk offering id cmd.id = self.volume.id @@ -546,16 +556,29 @@ class TestVolumes(cloudstackTestCase): try: response = self.apiClient.resizeVolume(cmd) except Exception as ex: - if "need to specify a disk offering" in str(ex): + if "HTTP Error 431:" in str(ex): success = True - self.assertEqual(success, True, "ResizeVolume - verify disk offering is handled appropriately") - + self.assertEqual( + success, + True, + "ResizeVolume - verify disk offering is handled appropriately") # Ok, now let's try and resize a volume that is not custom. cmd.id = self.volume.id cmd.diskofferingid = self.services['diskofferingid'] cmd.size = 4 currentSize = self.volume.size + self.debug( + "Attaching volume (ID: %s) to VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id) + ) + #attach the volume + self.virtual_machine.attach_volume(self.apiClient, self.volume) + #stop the vm if it is on xenserver + if self.services['hypervisor'].lower() == "xenserver": + self.virtual_machine.stop(self.apiClient) + self.apiClient.resizeVolume(cmd) count = 0 success = True @@ -566,7 +589,7 @@ class TestVolumes(cloudstackTestCase): type='DATADISK' ) for vol in list_volume_response: - if vol.id == self.volume.id and vol.size != currentSize: + if vol.id == self.volume.id and vol.size != currentSize and vol.state != "Resizing": success = False if success: break @@ -579,12 +602,21 @@ class TestVolumes(cloudstackTestCase): True, "Verify the volume did not resize" ) - + self.virtual_machine.detach_volume(self.apiClient, self.volume) + self.cleanup.append(self.volume) @attr(tags = ["advanced", "advancedns", "smoke"]) def test_08_resize_volume(self): """Resize a volume""" # Verify the size is the new size is what we wanted it to be. + self.debug( + "Attaching volume (ID: %s) to VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id + )) + self.virtual_machine.attach_volume(self.apiClient, self.volume) + if self.services['hypervisor'].lower() == "xenserver": + self.virtual_machine.stop(self.apiClient) self.debug("Resize Volume ID: %s" % self.volume.id) cmd = resizeVolume.resizeVolumeCmd() @@ -616,6 +648,9 @@ class TestVolumes(cloudstackTestCase): "Check if the volume resized appropriately" ) + self.virtual_machine.detach_volume(self.apiClient, self.volume) + self.cleanup.append(self.volume) + @attr(tags = ["advanced", "advancedns", "smoke"]) def test_09_delete_detached_volume(self): """Delete a Volume unattached to an VM From e05defc0732541eba117909211e455ecb6ac8b23 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 15 Apr 2013 12:38:18 +0530 Subject: [PATCH 083/107] CLOUDSTACK-1984:Wrong mapping of resource names to the capacity function on the dashboard --- ui/scripts/dashboard.js | 2 +- ui/scripts/sharedFunctions.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ui/scripts/dashboard.js b/ui/scripts/dashboard.js index 845ae52259b..e8ab6c531f9 100644 --- a/ui/scripts/dashboard.js +++ b/ui/scripts/dashboard.js @@ -238,7 +238,7 @@ return { zoneID: capacity.zoneid, // Temporary fix for dashboard zoneName: capacity.zonename, - type: cloudStack.converters.toAlertType(capacity.type), + type: cloudStack.converters.toCapacityCountType(capacity.type), percent: parseInt(capacity.percentused), used: cloudStack.converters.convertByType(capacity.type, capacity.capacityused), total: cloudStack.converters.convertByType(capacity.type, capacity.capacitytotal) diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 86fe7f6416c..19e16119845 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -425,6 +425,31 @@ cloudStack.converters = { case 26 : return "Resource Limit Exceeded"; } }, + + toCapacityCountType:function(capacityCode){ + switch(capacityCode){ + case 0 : return _l('label.memory'); + case 1 : return _l('label.cpu'); + case 2 : return _l('label.storage'); + case 3 : return _l('label.primary.storage'); + case 4 : return _l('label.public.ips'); + case 5 : return _l('label.management.ips'); + case 6 : return _l('label.secondary.storage'); + case 7 : return _l('label.vlan'); + case 8 : return _l('label.direct.ips'); + case 9 : return _l('label.local.storage'); + case 10 : return "Routing Host"; + case 11 : return "Storage"; + case 12 : return "Usage Server"; + case 13 : return "Management Server"; + case 14 : return "Domain Router"; + case 15 : return "Console Proxy"; + case 16 : return "User VM"; + case 17 : return "VLAN"; + case 18 : return "Secondary Storage VM"; + } + }, + convertByType: function(alertCode, value) { switch(alertCode) { case 0: return cloudStack.converters.convertBytes(value); From 97911e9fe6ba110b25a9b52a443e31ebfb42a4c8 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 15 Apr 2013 16:28:45 +0530 Subject: [PATCH 084/107] CLOUDSTACK-779:Enabling Egress rules feature for SRX --- ui/scripts/network.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index b6ed0fe9904..a759fb29211 100755 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -923,7 +923,7 @@ hiddenTabs.push("addloadBalancer"); } - if (isVPC || isAdvancedSGZone || hasSRXFirewall) { + if (isVPC || isAdvancedSGZone ) { hiddenTabs.push('egressRules'); } From e7090e6933f7fa2731c817ead10dfafd650a8e85 Mon Sep 17 00:00:00 2001 From: Srikanteswararao Talluri Date: Mon, 15 Apr 2013 16:47:40 +0530 Subject: [PATCH 085/107] CLOUDSTACK-2032: populate mode in the services dict from the list zones instead of hard coding Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_iso.py | 3 +-- test/integration/smoke/test_network.py | 4 +--- test/integration/smoke/test_routers.py | 2 +- test/integration/smoke/test_templates.py | 3 +-- test/integration/smoke/test_vm_life_cycle.py | 2 +- test/integration/smoke/test_volumes.py | 2 +- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/test/integration/smoke/test_iso.py b/test/integration/smoke/test_iso.py index 5bd7bb358be..3f8f11abdf9 100644 --- a/test/integration/smoke/test_iso.py +++ b/test/integration/smoke/test_iso.py @@ -79,8 +79,6 @@ class Services: "timeout": 10, "ostype": "CentOS 5.3 (64-bit)", # CentOS 5.3 (64 bit) - "mode": 'advanced' - # Networking mode: Basic or Advanced } @@ -93,6 +91,7 @@ class TestCreateIso(cloudstackTestCase): # Get Zone, Domain and templates self.domain = get_domain(self.apiclient, self.services) self.zone = get_zone(self.apiclient, self.services) + self.services['mode'] = zone.networktype self.services["domainid"] = self.domain.id self.services["iso_2"]["zoneid"] = self.zone.id diff --git a/test/integration/smoke/test_network.py b/test/integration/smoke/test_network.py index e78cc43fe33..e2c63a4b5b4 100644 --- a/test/integration/smoke/test_network.py +++ b/test/integration/smoke/test_network.py @@ -38,8 +38,6 @@ class Services: self.services = { "ostype": "CentOS 5.3 (64-bit)", # Cent OS 5.3 (64 bit) - "mode": 'advanced', - # Networking mode: Basic or advanced "lb_switch_wait": 10, # Time interval after which LB switches the requests "sleep": 60, @@ -120,7 +118,7 @@ class TestPublicIP(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.services['mode'] = zone.networktype # Create Accounts & networks cls.account = Account.create( cls.api_client, diff --git a/test/integration/smoke/test_routers.py b/test/integration/smoke/test_routers.py index 435c7e41a43..93116bfd58a 100644 --- a/test/integration/smoke/test_routers.py +++ b/test/integration/smoke/test_routers.py @@ -64,7 +64,6 @@ class Services: "ostype": "CentOS 5.3 (64-bit)", "sleep": 60, "timeout": 10, - "mode": 'advanced', #Networking mode: Basic, Advanced } @@ -81,6 +80,7 @@ class TestRouterServices(cloudstackTestCase): # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client, cls.services) cls.zone = get_zone(cls.api_client, cls.services) + self.services['mode'] = zone.networktype template = get_template( cls.api_client, cls.zone.id, diff --git a/test/integration/smoke/test_templates.py b/test/integration/smoke/test_templates.py index 663b174ed78..2b0e2f5ce97 100644 --- a/test/integration/smoke/test_templates.py +++ b/test/integration/smoke/test_templates.py @@ -93,8 +93,6 @@ class Services: "bootable": True, "passwordenabled": True, "ostype": "CentOS 5.3 (64-bit)", - "mode": 'advanced', - # Networking mode: Advanced, basic "sleep": 30, "timeout": 10, } @@ -126,6 +124,7 @@ class TestCreateTemplate(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.services['mode'] = zone.networktype cls.disk_offering = DiskOffering.create( cls.api_client, cls.services["disk_offering"] diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 564f6e854a5..cf9fd7530f1 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -1038,4 +1038,4 @@ class TestVMLifeCycle(cloudstackTestCase): False, "Check if ISO is detached from virtual machine" ) - return \ No newline at end of file + return diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py index 7d910d48eca..9aa44eb6f1f 100644 --- a/test/integration/smoke/test_volumes.py +++ b/test/integration/smoke/test_volumes.py @@ -84,7 +84,6 @@ class Services: "protocol": 'TCP', "diskdevice": "/dev/xvdb", "ostype": 'CentOS 5.5 (64-bit)', - "mode": 'advanced', "sleep": 10, "timeout": 600, } @@ -100,6 +99,7 @@ class TestCreateVolume(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.services['mode'] = zone.networktype cls.disk_offering = DiskOffering.create( cls.api_client, cls.services["disk_offering"] From ae16f332132a5eb1e3ff85a0c435dbe25a1d6299 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Mon, 15 Apr 2013 15:00:47 +0200 Subject: [PATCH 086/107] Fix a problem where usage server did not start because of a missing db.properties and log4j-cloud.xml --- packaging/centos63/cloud.spec | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 9ce46c97c42..c2c6fe734cd 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -278,6 +278,8 @@ cp plugins/hypervisors/kvm/target/dependencies/* ${RPM_BUILD_ROOT}%{_datadir}/% mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib install -D usage/target/cloud-usage-%{_maventag}.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/cloud-usage-%{_maventag}.jar +install -D usage/target/transformed/db.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage/db.properties +install -D usage/target/transformed/log4j-cloud_usage.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage/log4j-cloud.xml cp usage/target/dependencies/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib/ install -D packaging/centos63/cloud-usage.rc ${RPM_BUILD_ROOT}/%{_sysconfdir}/init.d/%{name}-usage mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/usage/ @@ -438,6 +440,20 @@ if [ -f "%{_sysconfdir}/cloud.rpmsave/agent/agent.properties" ]; then mv %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/cloud.rpmsave/agent/agent.properties.rpmsave fi +%post usage +if [ -f "%{_sysconfdir}/%{name}/management/db.properties" ]; then + echo Replacing db.properties with management server db.properties + rm -f %{_sysconfdir}/%{name}/usage/db.properties + ln -s %{_sysconfdir}/%{name}/management/db.properties %{_sysconfdir}/%{name}/usage/db.properties +fi + +if [ -f "%{_sysconfdir}/%{name}/management/log4j-cloud.xml" ]; then + echo Replacing log4j-cloud.xml with management server log4j-cloud.xml + rm -f %{_sysconfdir}/%{name}/usage/log4j-cloud.xml + ln -s %{_sysconfdir}/%{name}/management/log4j-cloud.xml %{_sysconfdir}/%{name}/usage/log4j-cloud.xml +fi + + #%post awsapi #if [ -d "%{_datadir}/%{name}-management" ] ; then # ln -s %{_datadir}/%{name}-bridge/webapps %{_datadir}/%{name}-management/webapps7080 @@ -533,7 +549,8 @@ fi %attr(0644,root,root) %{_datadir}/%{name}-usage/*.jar %attr(0644,root,root) %{_datadir}/%{name}-usage/lib/*.jar %dir /var/log/%{name}/usage -%dir %{_sysconfdir}/%{name}/usage +%attr(0644,root,root) %{_sysconfdir}/%{name}/usage/db.properties +%attr(0644,root,root) %{_sysconfdir}/%{name}/usage/log4j-cloud.xml %{_defaultdocdir}/%{name}-usage-%{version}/LICENSE %{_defaultdocdir}/%{name}-usage-%{version}/NOTICE From e94c70254be7a593b9c30931948621a86b35455f Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Mon, 15 Apr 2013 18:58:43 +0530 Subject: [PATCH 087/107] Squashed commit of the following: commit 7ce45ea1087407b87ff14d0f9ae5a7647c3f3ccc Author: Koushik Das Date: Mon Apr 15 18:36:33 2013 +0530 Fixed indentation and line ending commit 0232048f904b850700899d65ded089d8d7e7ab83 Merge: 735c4c8 97911e9 Author: Koushik Das Date: Mon Apr 15 17:05:59 2013 +0530 Merge branch 'master' into cisco-vnmc-api-integration Conflicts: api/src/org/apache/cloudstack/api/ApiConstants.java client/tomcatconf/commands.properties.in setup/db/db/schema-410to420.sql tools/marvin/marvin/integration/lib/base.py commit 735c4c895515a7d3acd59c97d98de95cc5935353 Author: Koushik Das Date: Mon Apr 15 15:20:37 2013 +0530 Fixed unit tests based on recent changes in the Vnmc resource code commit f166f2d0bf9e341316c74ef8de4b52b3d5e14f4d Author: Koushik Das Date: Mon Apr 15 14:50:25 2013 +0530 added tests to register vnmc and asa appliance in cloudstack commit f38be4810e2e1349260ee262b85db81f60252d9e Author: Koushik Das Date: Mon Apr 8 18:42:06 2013 +0530 Removed unwanted files commit 902ce426c1ebba2d826744123edd971819f73763 Author: Koushik Das Date: Mon Apr 8 17:59:30 2013 +0530 Fixed auto-wiring of components for Cisco Vnmc commit 08467ee30709268b536e649b24ad029db792934c Author: Koushik Das Date: Mon Apr 8 16:04:54 2013 +0530 Fixed compilation issues, incorrect merges from last commit commit 67f11d46ad8c13f371fe94c57fb287cb9d6005d1 Merge: 3422cee c9c68e1 Author: Koushik Das Date: Mon Apr 8 15:11:10 2013 +0530 Merge branch 'master' into cisco-vnmc-api-integration commit 3422ceefb6d1f5a92ec0868c1261a22e2cfbc54e Author: Koushik Das Date: Mon Apr 8 14:42:32 2013 +0530 Correctly associating nat, acl policy sets to edge security profile in VNMC commit 9c1e193fca6f5e7687634fe27a98616362267fbf Author: Koushik Das Date: Sun Apr 7 21:22:22 2013 +0530 Passing correct subnet mask while creating edge firewall in VNMC commit 05e3d04b55549ef098a769509171b24ca4a62957 Author: Koushik Das Date: Tue Apr 2 17:50:57 2013 +0530 Added changes related to icmp commit bcecb589de84caa570754c246565dfaa1cb1c2bf Author: Koushik Das Date: Mon Apr 1 13:57:21 2013 +0530 Some xml file renames commit 9c1ee93f2e74ea785ca06cb25f62fad4ad10c69e Author: Koushik Das Date: Sat Mar 30 15:54:25 2013 +0530 Fixed PF and static NAT rule creation in VNMC commit 7e6159fa054ec13c8f70fb58af2fdae2f55a0c70 Author: Koushik Das Date: Wed Mar 27 18:53:49 2013 +0530 Added more unit tests for Cisco Vnmc element commit fc0ed9adb6eaecbe5abbce1088eb80b98953f5cf Author: Koushik Das Date: Wed Mar 27 16:48:28 2013 +0530 Cleaning up VNMC config as part of network shutdown commit 5a427d48e20f50260b80c57f6e4c3bc6d9057c3f Author: Koushik Das Date: Wed Mar 27 02:22:54 2013 +0530 Added unit test for Vnmc network element implement() method commit 48cbf34d3bf44a5601842fa8bbc41be6beea3b07 Author: Koushik Das Date: Wed Mar 27 02:20:45 2013 +0530 Passing correct gateway ip while creating vservice node and guest port profile in Nexus commit 2c386c61ef48a7cf9b282952152ecb7cedd21977 Author: Koushik Das Date: Fri Mar 22 13:50:52 2013 +0530 Nexus 1000v fix commit 4d2168bfa980f1fa4b8a0d10aaf4bdd2395de7cf Author: Koushik Das Date: Fri Mar 22 00:30:01 2013 +0530 Egress firewall rule commit e81ab3a2f443cf0c032a1fae6ed8e0697865b69e Author: Koushik Das Date: Thu Mar 21 10:50:29 2013 +0530 More tests for VnmcResource class commit 9e9c179212e8c0896972c1f19a3327f97832697e Author: Koushik Das Date: Thu Mar 21 00:25:10 2013 +0530 Fixed build issue from master merge commit f0c1af2b5c037bf49bfc2775108600e2fbdc720f Merge: 4f305c2 873ec27 Author: Koushik Das Date: Wed Mar 20 16:20:10 2013 +0530 Merge branch 'master' into cisco-vnmc-api-integration Conflicts: api/src/com/cloud/network/Network.java api/src/org/apache/cloudstack/api/ApiConstants.java client/tomcatconf/components-nonoss.xml.in client/tomcatconf/nonossComponentContext.xml.in plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java setup/db/db/schema-410to420.sql vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java commit 4f305c2beb02f836b5ece4e897bf812cd1e03751 Author: Koushik Das Date: Wed Mar 20 15:09:34 2013 +0530 Initial set of tests, will add more in subsequent commits commit 50bfcc1f752e9ca9b8330d2c4e3b8c5c9dd33155 Author: Koushik Das Date: Wed Mar 20 15:02:14 2013 +0530 Updated pom to copy xmls to target location during build commit 45bc92b8262e715fdead9411666cbe3274d3ee02 Author: Koushik Das Date: Wed Mar 20 14:58:59 2013 +0530 Fixed cpmpilation issue as missed out adding this file commit 2ce7cdc756bd43adec006b877cb41da6f3e9dd57 Author: Koushik Das Date: Sun Mar 17 17:02:25 2013 +0530 Creating vservice node and associating it with port profile in nexus for guest VMs commit 387545caff60541bda5eb67e7fd91e61df5fde3e Author: Koushik Das Date: Sat Mar 16 11:14:43 2013 +0530 Added license headers to XML files commit 43e29974215a73788b249f246d7e62825cf8b4e6 Author: Koushik Das Date: Wed Mar 13 11:51:59 2013 +0530 Changes related to instantiating the dao components commit 99e88ecbf9980abe86fce89807b089a8c1a1a549 Author: Koushik Das Date: Tue Mar 12 23:40:35 2013 +0530 Fix build errors after merge from master commit 7c20b120c294fec4456a7052b630207eb0383458 Author: Koushik Das Date: Tue Mar 12 23:31:46 2013 +0530 Fixing poms and other xmls commit ee868759a8817ec66364ddd9f87b37b3fb8efd08 Merge: 9c94b6d a1b33ca Author: Koushik Das Date: Tue Mar 12 14:44:59 2013 +0530 Merge branch 'master' into cisco-vnmc-api-integration Conflicts: api/src/com/cloud/network/Network.java api/src/org/apache/cloudstack/api/ApiConstants.java plugins/pom.xml setup/db/create-schema.sql commit 9c94b6d231d851c24e6605b6645931f39caff548 Author: Koushik Das Date: Fri Mar 8 22:20:23 2013 +0530 Fixed XML to create static route in VNMC correctly commit ef069b33235c9d9864749fcfec878c2c255b8c10 Author: Koushik Das Date: Fri Mar 8 15:26:26 2013 +0530 Added logic for revoking ACL, PF and Static NAT rules commit 4c65b70668bf994adc8c55096dfefde98eb18180 Author: Koushik Das Date: Fri Mar 8 13:51:37 2013 +0530 Renamed delete-acl-rule -> delete-rule commit aa94eca516836949da40f1c0672c0aad9699c759 Author: Koushik Das Date: Fri Mar 8 00:38:52 2013 +0530 - Creating static routes in VNMC as part of edge firewall configuration - Passing order parameter while creating rules so that they are evaluated in a specific order - Added methods in VnmcResource for listing acl policies and rules belonging to variouos policies. This is used to compute order while creation of various rules in VNMC commit cc824e8585dc011843125f070f9bbf8dbf985384 Author: Koushik Das Date: Thu Mar 7 12:16:29 2013 +0530 Adding appropriate ACL rules for PF and static NAT commit fb23c503655b29d33c6206dbf4df1ed7f64ff5e2 Author: Koushik Das Date: Fri Mar 1 17:21:45 2013 +0530 Added logic for deleting various VNMC artifacts. Added/updated relevant xmls as well. commit 970c21a9a335a86c495553db3e1f86c3379bdb8e Author: Koushik Das Date: Fri Mar 1 01:54:10 2013 +0530 Added implementation for delete of asa and vnmc apis commit 22e1455142690acd7d5c5faed443cfb263d09dd9 Author: Koushik Das Date: Fri Mar 1 01:19:43 2013 +0530 List asa api to return guest network if associated. From this it can be inferred if asa is available or not commit 32223736c9a52a73a3e401c301cf7dc3534639d2 Author: Koushik Das Date: Fri Mar 1 00:50:55 2013 +0530 Added Vmware cluster info along with asa1kv appliance. This is used to select the correct n1kv vsm for configuring the guest network commit deed3cc9510fee58a02d4f485e3625335f038a57 Author: Koushik Das Date: Mon Feb 25 18:03:59 2013 +0530 Added support for static NAT rules. - Xmls for creating static nat rules in VNMC - applyStaticNats implementation in VNMC network element - handler for static nat in resource class commit 681f0b7b509446d32fb326cd425cd6a8618fc45d Author: Koushik Das Date: Mon Feb 25 10:44:13 2013 +0530 Added implementation for firewall and port forwarding rules in Cisco VNMC element class commit 66b01a6589e0577ff6ba2a14f8df4f32f8c400fb Author: Koushik Das Date: Fri Feb 22 19:19:44 2013 +0530 VNMC xml for deleting NAT policy commit 5d9868676868c9f9555aa0e706a6f2f2430cd5cf Author: Koushik Das Date: Fri Feb 22 19:16:41 2013 +0530 Added support for PF/DNAT rules. Created methods in VNMCConnection class to create PF rules. Also moved out common code for PF and source NAT in methods. Updated the corresponding VNMC resource class. commit 8db2fbeb8f04b81399f0932a1f8fd782264fb181 Author: Koushik Das Date: Fri Feb 22 18:21:45 2013 +0530 Added xml for creating NAT policy set in VNMC commit f2da0d50caf49efeb903b9abde9a4f996cf6cc1b Author: Koushik Das Date: Fri Feb 22 18:17:53 2013 +0530 Added VNMC XMLs for supporting PF/DNAT rules. Also moved out some XMLs related to source NAT to common files so that these can be used for both source NAT and DNAT commit 124a48819d34547d5355396c151279a23899ff65 Author: Koushik Das Date: Thu Feb 21 17:53:12 2013 +0530 Separated out creation of ACL policy set and policy in VNMC commit 1e38515f35f6e567e0118fbea1cdc0dc5ebf9965 Author: Koushik Das Date: Thu Feb 21 11:54:44 2013 +0530 Added changes to create ingress fw rules in VNMC commit cb2fba9e7c331634893b4597841ea13784844a84 Author: Koushik Das Date: Thu Feb 14 16:23:05 2013 +0530 Source NAT in VNMC commit 720fe2f908895f2102c1cb00698568f4ddd4b8cd Author: Koushik Das Date: Wed Feb 13 14:16:47 2013 +0530 Fix Vnmc test file commit d6dbe790c6a569dceff1a598bec2522760695bdc Author: Koushik Das Date: Wed Feb 13 12:07:03 2013 +0530 Added db. tables for asa1kv devices and their mapping with guest network commit 3fd7e30f6e84adb607c3d61be32ecb889cfa73b3 Author: Koushik Das Date: Wed Feb 13 11:52:12 2013 +0530 Changes: - Added implementation for add/list asa1kv APIs - Added agent command for associating asa1kv appliance with logical edge firewall in VNMC - Added handler for the above agent command in VNMC resource class - Updated VNMC element class to support the above commit d08e2a1fafdc68ea1c7d6327829aee5aa4c2c38d Author: Koushik Das Date: Wed Feb 13 11:40:58 2013 +0530 Added lifecycle APIs for Cisco Asa 1000v appliance. Added corresponding Dao and VO classes. Also added mapping Dao and VO for guest netwok and asa appliance commit 6b999ec867bee2cd31aff5d495470b25af6d45f8 Author: Koushik Das Date: Tue Feb 12 00:05:39 2013 +0530 Changes: a. Added handlers for CreateLogicalEdgeFirewall and ConfigureNexusVSMForASA commands b. Logic for add/list vnmc device API c. Partial implementation for network element implement() commit 0656250308f3dd8a6991ee124a0fa3781214b327 Author: Koushik Das Date: Mon Feb 11 23:48:19 2013 +0530 Moved VNMC provider creation to Network.java. The plugin code would have been the ideal place to keep it but current state of the code doesn't allow it. commit dc402eaa7a67c1b457ccf2243a0e53371a0bcfa9 Author: Koushik Das Date: Mon Feb 11 23:35:19 2013 +0530 Added new commands for the following: a. Logical edge firewall creation in VNMC b. Asa1kv vservice node creation and updating asa1kv inside port profile with guest network vlan id in n1kv VSM commit d6cdfe35f8bdb5a22759678da1cf6f1835debecc Author: Koushik Das Date: Mon Feb 11 23:06:36 2013 +0530 Added helper method to create port profile in n1kv VSM with additional parameters VDC tenant and edge security profile Added helper method to create a vservice node in n1kv VSM commit db42da17e9d3cf7466e0f755d5046d710a5f5356 Author: Koushik Das Date: Mon Feb 11 22:44:01 2013 +0530 Added database table for storing VNMC devices commit f991436335254eae4dc11a9f089a5c6e94403cd3 Author: Koushik Das Date: Fri Feb 8 16:00:15 2013 +0530 Added support for network offering creation with VNMC as provider for firewall, port forwarding, source nat commit 74de210359396b1ac880aa0ffa3a38df6574e07d Author: Koushik Das Date: Fri Feb 8 15:06:11 2013 +0530 Added name attribute for the VNMC lifecycle commands commit 6ce25ef11dd7eb98b0ae999f9748e7ea907b7e10 Author: Chiradeep Vittal Date: Wed Jan 16 16:44:28 2013 -0800 Fix licensing commit 392cd8ed631009590c0001e88a82b17294af2c3e Author: Chiradeep Vittal Date: Wed Jan 16 16:38:19 2013 -0800 cisco-vnmc: Fix api to use new conventions commit 6b142bbaabc1a00c94ec598bbd8e257274372d42 Author: Chiradeep Vittal Date: Wed Jan 16 15:33:33 2013 -0800 WIP: configure ASA port profile Signed-off-by: Chiradeep Vittal commit 1ae21ea49a5535a3e839aba0ccfe95c7e9d9abbd Author: Chiradeep Vittal Date: Wed Jan 16 15:33:01 2013 -0800 WIP rename device to resource to better reflect nature of VNMC Signed-off-by: Chiradeep Vittal commit 84d218f972e48d5f92e6659282d6d1762070b108 Author: Chiradeep Vittal Date: Wed Jan 16 15:32:54 2013 -0800 WIP: fixes for associating ASA1000v to tenant Signed-off-by: Chiradeep Vittal commit d74c6a9ac2efc939aa98c466bf0cd9bcf5e5563c Author: Chiradeep Vittal Date: Wed Jan 16 15:32:45 2013 -0800 WIP: fixes for associating ASA1000v to tenant Signed-off-by: Chiradeep Vittal commit 9350d10849015c3bc710efff48045ca7bd9513f4 Author: Chiradeep Vittal Date: Wed Jan 16 15:32:29 2013 -0800 WIP: admin commands for adding / listing VNMC Signed-off-by: Chiradeep Vittal commit a8031a0cfed08f59b9e22f5b914f7bc205e04104 Author: Chiradeep Vittal Date: Wed Jan 16 15:30:41 2013 -0800 WIP ASA 1000v listing" Signed-off-by: Chiradeep Vittal commit f9cc674b9ce5a04f4cf1c17882c597fcc336b121 Author: Chiradeep Vittal Date: Wed Jan 16 15:30:36 2013 -0800 WIP : edge firewall Signed-off-by: Chiradeep Vittal commit 6a0964af00437e2175c95f76e913683393ee8988 Author: Chiradeep Vittal Date: Wed Jan 16 15:30:30 2013 -0800 WIP : edge security policy Signed-off-by: Chiradeep Vittal commit e32295e8cf3baacb154b2a6cecf48dc3be74f505 Author: Chiradeep Vittal Date: Wed Jan 16 15:30:24 2013 -0800 WIP : dhcp server policy Signed-off-by: Chiradeep Vittal commit 446a9b84919e8e3d0ed9f131c675726c42ed6a4f Author: Chiradeep Vittal Date: Wed Jan 16 15:30:18 2013 -0800 WIP : dhcp server policy Signed-off-by: Chiradeep Vittal commit e35e0eb59ba3e011cad68155b06e96eaf257e91e Author: Chiradeep Vittal Date: Wed Jan 16 15:30:14 2013 -0800 Move unit test Signed-off-by: Chiradeep Vittal commit 2b43a3e74ef0e448eb407d3a967f9d8cf2a1d71b Author: Chiradeep Vittal Date: Wed Jan 16 15:30:08 2013 -0800 Move unit test Signed-off-by: Chiradeep Vittal commit 11b804a8940c17e105b25ac7f9dfd87651e4c55a Author: Chiradeep Vittal Date: Wed Jan 16 15:29:54 2013 -0800 WIP: XML control of VNMC Signed-off-by: Chiradeep Vittal --- api/src/com/cloud/network/Network.java | 1 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../network/ExternalNetworkDeviceManager.java | 1 + client/pom.xml | 10 + client/tomcatconf/commands.properties.in | 11 + .../tomcatconf/nonossComponentContext.xml.in | 11 + .../com/cloud/hypervisor/guru/VMwareGuru.java | 18 +- .../vmware/manager/VmwareManagerImpl.java | 3 +- .../vmware/resource/VmwareResource.java | 13 +- plugins/network-elements/cisco-vnmc/pom.xml | 42 + .../scripts/network/cisco/assoc-asa1000v.xml | 34 + .../cisco/associate-acl-policy-set.xml | 37 + .../network/cisco/associate-dhcp-policy.xml | 34 + .../network/cisco/associate-dhcp-server.xml | 32 + .../cisco/associate-nat-policy-set.xml | 35 + .../network/cisco/associate-route-policy.xml | 33 + .../network/cisco/create-acl-policy-ref.xml | 38 + .../network/cisco/create-acl-policy-set.xml | 36 + .../network/cisco/create-acl-policy.xml | 35 + .../cisco/create-acl-rule-for-dnat.xml | 82 + .../network/cisco/create-acl-rule-for-pf.xml | 156 ++ .../network/cisco/create-dhcp-policy.xml | 72 + .../network/cisco/create-dnat-rule.xml | 91 ++ .../cisco/create-edge-device-profile.xml | 32 + .../cisco/create-edge-device-route-policy.xml | 30 + .../cisco/create-edge-device-route.xml | 35 + .../network/cisco/create-edge-firewall.xml | 89 ++ .../cisco/create-edge-security-profile.xml | 41 + .../network/cisco/create-egress-acl-rule.xml | 201 +++ .../cisco/create-generic-egress-acl-rule.xml | 122 ++ .../cisco/create-generic-ingress-acl-rule.xml | 121 ++ .../network/cisco/create-ingress-acl-rule.xml | 201 +++ .../scripts/network/cisco/create-ip-pool.xml | 58 + .../network/cisco/create-nat-policy-ref.xml | 38 + .../network/cisco/create-nat-policy-set.xml | 37 + .../network/cisco/create-nat-policy.xml | 33 + .../scripts/network/cisco/create-pf-rule.xml | 166 ++ .../network/cisco/create-port-pool.xml | 72 + .../network/cisco/create-source-nat-pool.xml | 58 + .../network/cisco/create-source-nat-rule.xml | 103 ++ .../scripts/network/cisco/create-tenant.xml | 29 + .../scripts/network/cisco/create-vdc.xml | 30 + .../network/cisco/delete-acl-policy-set.xml | 30 + .../network/cisco/delete-acl-policy.xml | 33 + .../network/cisco/delete-edge-firewall.xml | 30 + .../cisco/delete-edge-security-profile.xml | 38 + .../network/cisco/delete-nat-policy-set.xml | 30 + .../network/cisco/delete-nat-policy.xml | 33 + .../scripts/network/cisco/delete-rule.xml | 31 + .../scripts/network/cisco/delete-tenant.xml | 30 + .../scripts/network/cisco/delete-vdc.xml | 30 + .../network/cisco/disassoc-asa1000v.xml | 30 + .../network/cisco/list-acl-policies.xml | 31 + .../scripts/network/cisco/list-children.xml | 27 + .../network/cisco/list-nat-policies.xml | 31 + .../cisco/list-policyrefs-in-policyset.xml | 31 + .../scripts/network/cisco/list-tenants.xml | 26 + .../cisco/list-unassigned-asa1000v.xml | 39 + .../scripts/network/cisco/login.xml | 20 + ...iateAsaWithLogicalEdgeFirewallCommand.java | 53 + .../CleanupLogicalEdgeFirewallCommand.java | 43 + .../api/ConfigureNexusVsmForAsaCommand.java | 95 ++ .../api/CreateLogicalEdgeFirewallCommand.java | 94 ++ .../commands/AddCiscoAsa1000vResourceCmd.java | 116 ++ .../api/commands/AddCiscoVnmcResourceCmd.java | 115 ++ .../DeleteCiscoAsa1000vResourceCmd.java | 93 ++ .../commands/DeleteCiscoVnmcResourceCmd.java | 93 ++ .../ListCiscoAsa1000vResourcesCmd.java | 110 ++ .../commands/ListCiscoVnmcResourcesCmd.java | 106 ++ .../CiscoAsa1000vResourceResponse.java | 88 + .../response/CiscoVnmcResourceResponse.java | 75 + .../network/cisco/CiscoAsa1000vDevice.java | 39 + .../network/cisco/CiscoAsa1000vDeviceVO.java | 101 ++ .../network/cisco/CiscoVnmcConnection.java | 196 +++ .../cisco/CiscoVnmcConnectionImpl.java | 1415 +++++++++++++++++ .../network/cisco/CiscoVnmcController.java | 40 + .../network/cisco/CiscoVnmcControllerVO.java | 102 ++ .../network/cisco/NetworkAsa1000vMap.java | 31 + .../network/cisco/NetworkAsa1000vMapVO.java | 73 + .../cloud/network/dao/CiscoAsa1000vDao.java | 33 + .../network/dao/CiscoAsa1000vDaoImpl.java | 63 + .../com/cloud/network/dao/CiscoVnmcDao.java | 32 + .../cloud/network/dao/CiscoVnmcDaoImpl.java | 51 + .../network/dao/NetworkAsa1000vMapDao.java | 28 + .../dao/NetworkAsa1000vMapDaoImpl.java | 61 + .../network/element/CiscoAsa1000vService.java | 43 + .../network/element/CiscoVnmcElement.java | 928 +++++++++++ .../element/CiscoVnmcElementService.java | 42 + .../network/resource/CiscoVnmcResource.java | 780 +++++++++ .../ssl/EasySSLProtocolSocketFactory.java | 232 +++ .../contrib/ssl/EasyX509TrustManager.java | 114 ++ .../cisco/CiscoVnmcConnectionTest.java | 248 +++ .../network/element/CiscoVnmcElementTest.java | 401 +++++ .../resource/CiscoVnmcResourceTest.java | 285 ++++ plugins/pom.xml | 1 + .../src/com/cloud/api/ApiResponseHelper.java | 4 +- .../ConfigurationManagerImpl.java | 4 +- setup/db/db/schema-410to420.sql | 38 +- .../integration/component/test_asa1000v_fw.py | 134 ++ tools/marvin/marvin/integration/lib/base.py | 65 +- .../utils/cisco/n1kv/vsm/NetconfHelper.java | 22 + .../utils/cisco/n1kv/vsm/VsmCommand.java | 213 +++ .../vmware/mo/HypervisorHostHelper.java | 45 +- 103 files changed, 9751 insertions(+), 36 deletions(-) create mode 100644 plugins/network-elements/cisco-vnmc/pom.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/assoc-asa1000v.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-acl-policy-set.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-policy.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-server.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-nat-policy-set.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-route-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-ref.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-set.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-dnat.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-pf.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dhcp-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dnat-rule.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-profile.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route-policy.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-firewall.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-security-profile.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-ingress-acl-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ip-pool.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-ref.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-set.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-pf-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-port-pool.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-pool.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-rule.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-tenant.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-vdc.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy-set.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-firewall.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-security-profile.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy-set.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-rule.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-tenant.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-vdc.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/disassoc-asa1000v.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-acl-policies.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-children.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-nat-policies.xml create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-policyrefs-in-policyset.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-tenants.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-unassigned-asa1000v.xml create mode 100644 plugins/network-elements/cisco-vnmc/scripts/network/cisco/login.xml create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/AssociateAsaWithLogicalEdgeFirewallCommand.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CleanupLogicalEdgeFirewallCommand.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/ConfigureNexusVsmForAsaCommand.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CreateLogicalEdgeFirewallCommand.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoAsa1000vResourceCmd.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoVnmcResourceCmd.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoAsa1000vResourceCmd.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoVnmcResourceCmd.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDevice.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDeviceVO.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcController.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcControllerVO.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMap.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMapVO.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDao.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDaoImpl.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDao.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDaoImpl.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDao.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDaoImpl.java create mode 100755 plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoAsa1000vService.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElementService.java create mode 100644 plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java create mode 100644 plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java create mode 100644 plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java create mode 100644 plugins/network-elements/cisco-vnmc/test/com/cloud/network/cisco/CiscoVnmcConnectionTest.java create mode 100755 plugins/network-elements/cisco-vnmc/test/com/cloud/network/element/CiscoVnmcElementTest.java create mode 100755 plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java create mode 100755 test/integration/component/test_asa1000v_fw.py diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index c0b0117fc7e..ffe70d19dc0 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -137,6 +137,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider None = new Provider("None", false); // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking public static final Provider NiciraNvp = new Provider("NiciraNvp", false); + public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); private String name; private boolean isExternal; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index b08e992abd2..37cb59f3758 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -476,6 +476,7 @@ public class ApiConstants { public static final String AFFINITY_GROUP_IDS = "affinitygroupids"; public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; public static final String DEPLOYMENT_PLANNER = "deploymentplanner"; + public static final String ASA_INSIDE_PORT_PROFILE = "insideportprofile"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java index aeed81d2011..29ce2e3971d 100644 --- a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java +++ b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java @@ -43,6 +43,7 @@ public interface ExternalNetworkDeviceManager extends Manager { public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName()); public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName()); public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName()); + public static final NetworkDevice CiscoVnmc = new NetworkDevice("CiscoVnmc", Network.Provider.CiscoVnmc.getName()); public NetworkDevice(String deviceName, String ntwkServiceprovider) { _name = deviceName; diff --git a/client/pom.xml b/client/pom.xml index 08946b6d905..743cd363005 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -455,6 +455,11 @@ file="${basedir}/target/generated-webapp/WEB-INF/web.xml" match="classpath:componentContext.xml" replace="classpath:nonossComponentContext.xml" byline="true" /> + + + + + @@ -639,6 +644,11 @@ cloud-vmware-base ${project.version} + + org.apache.cloudstack + cloud-plugin-network-cisco-vnmc + ${project.version} + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 798d226ca96..10fcfe3f687 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -577,3 +577,14 @@ deleteAffinityGroup=15 listAffinityGroups=15 updateVMAffinityGroup=15 listAffinityGroupTypes=15 + +#### Cisco Vnmc commands +addCiscoVnmcResource=1 +deleteCiscoVnmcResource=1 +listCiscoVnmcResources=1 + +#### Cisco Asa1000v commands +addCiscoAsa1000vResource=1 +deleteCiscoAsa1000vResource=1 +listCiscoAsa1000vResources=1 + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 3ede2634285..aac3b893a8a 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -136,6 +136,16 @@
+ + + + + + + + @@ -324,6 +334,7 @@ + diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index f6f0923c7ae..122ba3b9dba 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -52,7 +52,9 @@ import com.cloud.hypervisor.HypervisorGuru; import com.cloud.hypervisor.HypervisorGuruBase; import com.cloud.hypervisor.vmware.manager.VmwareManager; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; +import com.cloud.network.Network.Provider; import com.cloud.network.NetworkModel; +import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; @@ -143,13 +145,23 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { details.put(VmDetailConstants.ROOK_DISK_CONTROLLER, _vmwareMgr.getRootDiskController()); } } - + + List nicProfiles = vm.getNics(); + + for(NicProfile nicProfile : nicProfiles) { + if(nicProfile.getTrafficType() == TrafficType.Guest) { + if(_networkMgr.isProviderSupportServiceInNetwork(nicProfile.getNetworkId(), Service.Firewall, Provider.CiscoVnmc)) { + details.put("ConfigureVServiceInNexus", Boolean.TRUE.toString()); + } + break; + } + } + to.setDetails(details); if(vm.getVirtualMachine() instanceof DomainRouterVO) { - List nicProfiles = vm.getNics(); - NicProfile publicNicProfile = null; + NicProfile publicNicProfile = null; for(NicProfile nicProfile : nicProfiles) { if(nicProfile.getTrafficType() == TrafficType.Public) { publicNicProfile = nicProfile; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index b2e37685d17..eb09af0d67e 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -317,8 +317,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw } s_logger.info("Preparing network on host " + hostMo.getContext().toString() + " for " + privateTrafficLabel); - HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false); - + HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false); } @Override diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index f569595b8b0..3dc23ccb060 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1329,7 +1329,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO nicTo = cmd.getNic(); VirtualDevice nic; - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false); if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -1571,7 +1571,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, true); } else { networkInfo = HypervisorHostHelper.prepareNetwork(this._publicTrafficInfo.getVirtualSwitchName(), "cloud.public", - vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup); + vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false); } int nicIndex = allocPublicNicIndex(vmMo); @@ -2304,7 +2304,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa for (NicTO nicTo : sortNicsByDeviceId(nics)) { s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo)); - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo); + boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus); if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -2504,7 +2505,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return defaultVlan; } - private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo) throws Exception { + private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus) throws Exception { Pair switchName; TrafficType trafficType; VirtualSwitchType switchType; @@ -2534,7 +2535,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } else { networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), - nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup); + nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus); } return networkInfo; @@ -3024,7 +3025,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO[] nics = vm.getNics(); for (NicTO nic : nics) { // prepare network on the host - prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic); + prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false); } String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml new file mode 100644 index 00000000000..1ac6bd8d8c9 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + cloud-plugin-network-cisco-vnmc + Apache CloudStack Plugin - Cisco VNMC + + org.apache.cloudstack + cloudstack-plugins + 4.2.0-SNAPSHOT + ../../pom.xml + + + + org.apache.cloudstack + cloud-plugin-hypervisor-vmware + ${project.version} + + + org.apache.cloudstack + cloud-vmware-base + ${project.version} + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/assoc-asa1000v.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/assoc-asa1000v.xml new file mode 100644 index 00000000000..b0249db741b --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/assoc-asa1000v.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-acl-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-acl-policy-set.xml new file mode 100755 index 00000000000..e3113ae22c7 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-acl-policy-set.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-policy.xml new file mode 100644 index 00000000000..e866f51e366 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-policy.xml @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-server.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-server.xml new file mode 100644 index 00000000000..930e4ec77a2 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-dhcp-server.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-nat-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-nat-policy-set.xml new file mode 100644 index 00000000000..6d67c31c5d6 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-nat-policy-set.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-route-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-route-policy.xml new file mode 100644 index 00000000000..8884a1b9686 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/associate-route-policy.xml @@ -0,0 +1,33 @@ + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-ref.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-ref.xml new file mode 100755 index 00000000000..c534c327194 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-ref.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-set.xml new file mode 100755 index 00000000000..b475d2ca564 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy-set.xml @@ -0,0 +1,36 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy.xml new file mode 100755 index 00000000000..e71cd429858 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-policy.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-dnat.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-dnat.xml new file mode 100755 index 00000000000..5b6aaa3f59b --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-dnat.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-pf.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-pf.xml new file mode 100755 index 00000000000..1a1d9cbf3e2 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-acl-rule-for-pf.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dhcp-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dhcp-policy.xml new file mode 100644 index 00000000000..5bb4abcd8e1 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dhcp-policy.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dnat-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dnat-rule.xml new file mode 100755 index 00000000000..bd8dbff6d32 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-dnat-rule.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-profile.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-profile.xml new file mode 100644 index 00000000000..c4bdd026186 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-profile.xml @@ -0,0 +1,32 @@ + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route-policy.xml new file mode 100644 index 00000000000..69f4a5f7bfd --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route-policy.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route.xml new file mode 100644 index 00000000000..126c188f979 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-device-route.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-firewall.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-firewall.xml new file mode 100644 index 00000000000..e5447e39e63 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-firewall.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-security-profile.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-security-profile.xml new file mode 100644 index 00000000000..e2f5eaf0686 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-edge-security-profile.xml @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml new file mode 100755 index 00000000000..930272ed8ee --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml new file mode 100755 index 00000000000..92c25043dad --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-ingress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-ingress-acl-rule.xml new file mode 100755 index 00000000000..7c1164138bc --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-ingress-acl-rule.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml new file mode 100755 index 00000000000..1af30b44416 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ip-pool.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ip-pool.xml new file mode 100755 index 00000000000..4cf0451c33d --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ip-pool.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-ref.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-ref.xml new file mode 100755 index 00000000000..450d40c9d6d --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-ref.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-set.xml new file mode 100644 index 00000000000..090caf15cb4 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy-set.xml @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy.xml new file mode 100755 index 00000000000..0b556f42a84 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-nat-policy.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-pf-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-pf-rule.xml new file mode 100755 index 00000000000..a8a631f5d7f --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-pf-rule.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-port-pool.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-port-pool.xml new file mode 100755 index 00000000000..e1b7be024f7 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-port-pool.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-pool.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-pool.xml new file mode 100644 index 00000000000..2ad1e8798a5 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-pool.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-rule.xml new file mode 100644 index 00000000000..a3ee9875e19 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-source-nat-rule.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-tenant.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-tenant.xml new file mode 100644 index 00000000000..085b7a2e533 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-tenant.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-vdc.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-vdc.xml new file mode 100644 index 00000000000..4cb805ecf7e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-vdc.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy-set.xml new file mode 100755 index 00000000000..2c5578659c7 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy-set.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy.xml new file mode 100755 index 00000000000..b1a27650419 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-acl-policy.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-firewall.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-firewall.xml new file mode 100755 index 00000000000..992d6a1ab62 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-firewall.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-security-profile.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-security-profile.xml new file mode 100755 index 00000000000..f394fe91d9e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-edge-security-profile.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy-set.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy-set.xml new file mode 100755 index 00000000000..3f4c08d747f --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy-set.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy.xml new file mode 100755 index 00000000000..6c3ed7b9f48 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-nat-policy.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-rule.xml new file mode 100755 index 00000000000..e56e9190496 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-rule.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-tenant.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-tenant.xml new file mode 100755 index 00000000000..05bef9a2906 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-tenant.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-vdc.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-vdc.xml new file mode 100755 index 00000000000..fbc2312c208 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/delete-vdc.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/disassoc-asa1000v.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/disassoc-asa1000v.xml new file mode 100755 index 00000000000..448b65f0d53 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/disassoc-asa1000v.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-acl-policies.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-acl-policies.xml new file mode 100755 index 00000000000..aec800e9f4a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-acl-policies.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-children.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-children.xml new file mode 100755 index 00000000000..f272999a76c --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-children.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-nat-policies.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-nat-policies.xml new file mode 100755 index 00000000000..720ced06d8a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-nat-policies.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-policyrefs-in-policyset.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-policyrefs-in-policyset.xml new file mode 100755 index 00000000000..c53af90369d --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-policyrefs-in-policyset.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-tenants.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-tenants.xml new file mode 100644 index 00000000000..63ae848b3e1 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-tenants.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-unassigned-asa1000v.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-unassigned-asa1000v.xml new file mode 100644 index 00000000000..539f330da8a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/list-unassigned-asa1000v.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/login.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/login.xml new file mode 100644 index 00000000000..8e1c435ea15 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/login.xml @@ -0,0 +1,20 @@ + + + diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/AssociateAsaWithLogicalEdgeFirewallCommand.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/AssociateAsaWithLogicalEdgeFirewallCommand.java new file mode 100755 index 00000000000..a438cbc0e59 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/AssociateAsaWithLogicalEdgeFirewallCommand.java @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api; + +/** + * Associates an ASA 1000v appliance with logical edge firewall in VNMC + */ +public class AssociateAsaWithLogicalEdgeFirewallCommand extends Command { + private long _vlanId; + private String _asaMgmtIp; + + public AssociateAsaWithLogicalEdgeFirewallCommand(long vlanId, String asaMgmtIp) { + super(); + this._vlanId = vlanId; + this._asaMgmtIp = asaMgmtIp; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public long getVlanId() { + return _vlanId; + } + + public void setVlanId(long vlanId) { + this._vlanId = vlanId; + } + + public String getAsaMgmtIp() { + return _asaMgmtIp; + } + + public void setAsaMgmtIp(String asaMgmtIp) { + this._asaMgmtIp = asaMgmtIp; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CleanupLogicalEdgeFirewallCommand.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CleanupLogicalEdgeFirewallCommand.java new file mode 100755 index 00000000000..c9f7f8c4c83 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CleanupLogicalEdgeFirewallCommand.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 com.cloud.agent.api; + +/** + * Command for cleaning up logical edge firewall in VNMC + */ +public class CleanupLogicalEdgeFirewallCommand extends Command { + private long _vlanId; + + public CleanupLogicalEdgeFirewallCommand(long vlanId) { + super(); + this._vlanId = vlanId; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public long getVlanId() { + return _vlanId; + } + + public void setVlanId(long vlanId) { + this._vlanId = vlanId; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/ConfigureNexusVsmForAsaCommand.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/ConfigureNexusVsmForAsaCommand.java new file mode 100755 index 00000000000..b20ad1f2df6 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/ConfigureNexusVsmForAsaCommand.java @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api; + +/** + * Command for configuring n1kv VSM for asa1kv device. It does the following in VSM: + * a. creating vservice node for asa1kv + * b. updating vlan of inside port profile associated with asa1kv + */ +public class ConfigureNexusVsmForAsaCommand extends Command { + private long _vlanId; + private String _ipAddress; + private String _vsmUsername; + private String _vsmPassword; + private String _vsmIp; + private String _asaInPortProfile; + + public ConfigureNexusVsmForAsaCommand(long vlanId, String ipAddress, + String vsmUsername, String vsmPassword, String vsmIp, String asaInPortProfile) { + super(); + this._vlanId = vlanId; + this._ipAddress = ipAddress; + this._vsmUsername = vsmUsername; + this._vsmPassword = vsmPassword; + this._vsmIp = vsmIp; + this._asaInPortProfile = asaInPortProfile; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public long getVlanId() { + return _vlanId; + } + + public void setVlanId(long _vlanId) { + this._vlanId = _vlanId; + } + + public String getIpAddress() { + return _ipAddress; + } + + public void setIpAddress(String _ipAddress) { + this._ipAddress = _ipAddress; + } + + public String getVsmUsername() { + return _vsmUsername; + } + + public void setVsmUsername(String _vsmUsername) { + this._vsmUsername = _vsmUsername; + } + + public String getVsmPassword() { + return _vsmPassword; + } + + public void setVsmPassword(String _vsmPassword) { + this._vsmPassword = _vsmPassword; + } + + public String getVsmIp() { + return _vsmIp; + } + + public void setVsmIp(String _vsmIp) { + this._vsmIp = _vsmIp; + } + + public String getAsaInPortProfile() { + return _asaInPortProfile; + } + + public void setAsaInPortProfile(String _asaInPortProfile) { + this._asaInPortProfile = _asaInPortProfile; + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CreateLogicalEdgeFirewallCommand.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CreateLogicalEdgeFirewallCommand.java new file mode 100755 index 00000000000..def8225acf1 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/agent/api/CreateLogicalEdgeFirewallCommand.java @@ -0,0 +1,94 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api; + +import java.util.ArrayList; +import java.util.List; + +/** + * Command for creating a logical edge firewall in VNMC + */ +public class CreateLogicalEdgeFirewallCommand extends Command { + private long _vlanId; + private String _publicIp; + private String _internalIp; + private String _publicSubnet; + private String _internalSubnet; + private List _publicGateways; + + public CreateLogicalEdgeFirewallCommand(long vlanId, + String publicIp, String internalIp, + String publicSubnet, String internalSubnet) { + super(); + this._vlanId = vlanId; + this._publicIp = publicIp; + this._internalIp = internalIp; + this._publicSubnet = publicSubnet; + this.setInternalSubnet(internalSubnet); + _publicGateways = new ArrayList(); + } + + @Override + public boolean executeInSequence() { + return false; + } + + public long getVlanId() { + return _vlanId; + } + + public void setVlanId(long vlanId) { + this._vlanId = vlanId; + } + + public String getPublicIp() { + return _publicIp; + } + + public void setPublicIp(String publicIp) { + this._publicIp = publicIp; + } + + public String getInternalIp() { + return _internalIp; + } + + public void setInternalIp(String internalIp) { + this._internalIp = internalIp; + } + + public String getPublicSubnet() { + return _publicSubnet; + } + + public void setPublicSubnet(String publicSubnet) { + this._publicSubnet = publicSubnet; + } + + public String getInternalSubnet() { + return _internalSubnet; + } + + public void setInternalSubnet(String _internalSubnet) { + this._internalSubnet = _internalSubnet; + } + + public List getPublicGateways() { + return _publicGateways; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoAsa1000vResourceCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoAsa1000vResourceCmd.java new file mode 100755 index 00000000000..c880199f5c4 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoAsa1000vResourceCmd.java @@ -0,0 +1,116 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import javax.inject.Inject; + +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.ClusterResponse; +import org.apache.cloudstack.api.response.PhysicalNetworkResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoAsa1000vResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.cisco.CiscoAsa1000vDevice; +import com.cloud.network.element.CiscoAsa1000vService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="addCiscoAsa1000vResource", responseObject=CiscoAsa1000vResourceResponse.class, description="Adds a Cisco Asa 1000v appliance") +public class AddCiscoAsa1000vResourceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(AddCiscoAsa1000vResourceCmd.class.getName()); + private static final String s_name = "addCiscoAsa1000vResource"; + @Inject CiscoAsa1000vService _ciscoAsa1000vService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, required=true, description="the Physical Network ID") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, required = true, description="Hostname or ip address of the Cisco ASA 1000v appliance.") + private String host; + + @Parameter(name=ApiConstants.ASA_INSIDE_PORT_PROFILE, type=CommandType.STRING, required = true, description="Nexus port profile associated with inside interface of ASA 1000v") + private String inPortProfile; + + @Parameter(name=ApiConstants.CLUSTER_ID, type=CommandType.UUID, entityType = ClusterResponse.class, required=true, description="the Cluster ID") + private Long clusterId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public String getManagementIp() { + return host; + } + + public String getInPortProfile() { + return inPortProfile; + } + + public Long getClusterId() { + return clusterId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + CiscoAsa1000vDevice ciscoAsa1000v = _ciscoAsa1000vService.addCiscoAsa1000vResource(this); + if (ciscoAsa1000v != null) { + CiscoAsa1000vResourceResponse response = _ciscoAsa1000vService.createCiscoAsa1000vResourceResponse(ciscoAsa1000v); + response.setObjectName("CiscoAsa1000vResource"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Cisco ASA 1000v appliance due to internal error."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoVnmcResourceCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoVnmcResourceCmd.java new file mode 100644 index 00000000000..bfd6db95434 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/AddCiscoVnmcResourceCmd.java @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import javax.inject.Inject; + +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.PhysicalNetworkResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoVnmcResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.cisco.CiscoVnmcController; +import com.cloud.network.element.CiscoVnmcElementService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="addCiscoVnmcResource", responseObject=CiscoVnmcResourceResponse.class, description="Adds a Cisco Vnmc Controller") +public class AddCiscoVnmcResourceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(AddCiscoVnmcResourceCmd.class.getName()); + private static final String s_name = "addCiscoVnmcResource"; + @Inject CiscoVnmcElementService _ciscoVnmcElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, required=true, description="the Physical Network ID") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, required = true, description="Hostname or ip address of the Cisco VNMC Controller.") + private String host; + + @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to access the Cisco VNMC Controller API") + private String username; + + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to access the Cisco VNMC Controller API") + private String password; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public String getHost() { + return host; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + CiscoVnmcController CiscoVnmcResourceVO = _ciscoVnmcElementService.addCiscoVnmcResource(this); + if (CiscoVnmcResourceVO != null) { + CiscoVnmcResourceResponse response = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(CiscoVnmcResourceVO); + response.setObjectName("CiscoVnmcResource"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Cisco VNMC controller due to internal error."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoAsa1000vResourceCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoAsa1000vResourceCmd.java new file mode 100755 index 00000000000..d4f86fa527a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoAsa1000vResourceCmd.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import javax.inject.Inject; + +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.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoAsa1000vResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.element.CiscoAsa1000vService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="deleteCiscoAsa1000vResource", responseObject=SuccessResponse.class, description="Deletes a Cisco ASA 1000v appliance") +public class DeleteCiscoAsa1000vResourceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(DeleteCiscoAsa1000vResourceCmd.class.getName()); + private static final String s_name = "deleteCiscoAsa1000vResource"; + @Inject CiscoAsa1000vService _ciscoAsa1000vService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.UUID, required=true, entityType=CiscoAsa1000vResourceResponse.class, description="Cisco ASA 1000v resource ID") + private Long ciscoAsa1000vResourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getCiscoAsa1000vResourceId() { + return ciscoAsa1000vResourceId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + boolean result = _ciscoAsa1000vService.deleteCiscoAsa1000vResource(this); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete Cisco ASA 1000v appliance."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoVnmcResourceCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoVnmcResourceCmd.java new file mode 100644 index 00000000000..d2a37202f0a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/DeleteCiscoVnmcResourceCmd.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import javax.inject.Inject; + +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.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoVnmcResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.element.CiscoVnmcElementService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="deleteCiscoVnmcResource", responseObject=SuccessResponse.class, description="Deletes a Cisco Vnmc controller") +public class DeleteCiscoVnmcResourceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(DeleteCiscoVnmcResourceCmd.class.getName()); + private static final String s_name = "deleteCiscoVnmcResource"; + @Inject CiscoVnmcElementService _ciscoVnmcElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.UUID, required=true, entityType=CiscoVnmcResourceResponse.class, description="Cisco Vnmc resource ID") + private Long ciscoVnmcResourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getCiscoVnmcResourceId() { + return ciscoVnmcResourceId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + boolean result = _ciscoVnmcElementService.deleteCiscoVnmcResource(this); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete Cisco Vnmc resource."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java new file mode 100755 index 00000000000..509d39fb5f9 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +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.PhysicalNetworkResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoAsa1000vResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.cisco.CiscoAsa1000vDevice; +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.network.element.CiscoAsa1000vService; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="listCiscoAsa1000vResources", responseObject=CiscoAsa1000vResourceResponse.class, description="Lists Cisco ASA 1000v appliances") +public class ListCiscoAsa1000vResourcesCmd extends BaseListCmd { + private static final Logger s_logger = Logger.getLogger(ListCiscoAsa1000vResourcesCmd.class.getName()); + private static final String s_name = "listCiscoAsa1000vResources"; + @Inject CiscoAsa1000vService _ciscoAsa1000vService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, description="the Physical Network ID") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.UUID, entityType=CiscoAsa1000vResourceResponse.class, description="Cisco ASA 1000v resource ID") + private Long ciscoAsa1000vResourceId; + + @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, description="Hostname or ip address of the Cisco ASA 1000v appliance.") + private String host; + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getCiscoAsa1000vResourceId() { + return ciscoAsa1000vResourceId; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public String getManagementIp() { + return host; + } + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + List ciscoAsa1000vDevices = _ciscoAsa1000vService.listCiscoAsa1000vResources(this); + ListResponse response = new ListResponse(); + List ciscoAsa1000vResourcesResponse = new ArrayList(); + + if (ciscoAsa1000vDevices != null && !ciscoAsa1000vDevices.isEmpty()) { + for (CiscoAsa1000vDevice ciscoAsa1000vDeviceVO : ciscoAsa1000vDevices) { + CiscoAsa1000vResourceResponse ciscoAsa1000vResourceResponse = _ciscoAsa1000vService.createCiscoAsa1000vResourceResponse(ciscoAsa1000vDeviceVO); + ciscoAsa1000vResourcesResponse.add(ciscoAsa1000vResourceResponse); + } + } + + response.setResponses(ciscoAsa1000vResourcesResponse); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java new file mode 100644 index 00000000000..ab553ee94ac --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +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.PhysicalNetworkResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.response.CiscoVnmcResourceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.cisco.CiscoVnmcController; +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.network.element.CiscoVnmcElementService; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name="listCiscoVnmcResources", responseObject=CiscoVnmcResourceResponse.class, description="Lists Cisco VNMC controllers") +public class ListCiscoVnmcResourcesCmd extends BaseListCmd { + private static final Logger s_logger = Logger.getLogger(ListCiscoVnmcResourcesCmd.class.getName()); + private static final String s_name = "listCiscoVnmcResources"; + @Inject CiscoVnmcElementService _ciscoVnmcElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, description="the Physical Network ID") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.UUID, entityType=CiscoVnmcResourceResponse.class, description="Cisco VNMC resource ID") + private Long ciscoVnmcResourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getCiscoVnmcResourceId() { + return ciscoVnmcResourceId; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + List CiscoVnmcResources = _ciscoVnmcElementService.listCiscoVnmcResources(this); + ListResponse response = new ListResponse(); + List CiscoVnmcResourcesResponse = new ArrayList(); + + if (CiscoVnmcResources != null && !CiscoVnmcResources.isEmpty()) { + for (CiscoVnmcController CiscoVnmcResourceVO : CiscoVnmcResources) { + CiscoVnmcResourceResponse CiscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(CiscoVnmcResourceVO); + CiscoVnmcResourcesResponse.add(CiscoVnmcResourceResponse); + } + } + + response.setResponses(CiscoVnmcResourcesResponse); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java new file mode 100755 index 00000000000..9cd87da66a1 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java @@ -0,0 +1,88 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.response; + + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.PhysicalNetworkResponse; + +import com.cloud.network.cisco.CiscoAsa1000vDevice; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = CiscoAsa1000vDevice.class) +public class CiscoAsa1000vResourceResponse extends BaseResponse { + public static final String RESOURCE_NAME = "resourcename"; + + @SerializedName(ApiConstants.RESOURCE_ID) @Parameter(description="resource id of the Cisco ASA 1000v appliance") + private String id; + + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) + @Parameter(description="the physical network to which this ASA 1000v belongs to", entityType = PhysicalNetworkResponse.class) + private Long physicalNetworkId ; + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + @SerializedName(ApiConstants.HOST_NAME) + @Parameter(description="management ip address of ASA 1000v") + private String managementIp; + + public String getManagementIp() { + return managementIp; + } + + @SerializedName(ApiConstants.ASA_INSIDE_PORT_PROFILE) + @Parameter(description="management ip address of ASA 1000v") + private String inPortProfile; + + public String getInPortProfile() { + return inPortProfile; + } + + @SerializedName(ApiConstants.NETWORK_ID) + @Parameter(description="the guest network to which ASA 1000v is associated", entityType = NetworkResponse.class) + private Long guestNetworkId; + + public Long getGuestNetworkId() { + return guestNetworkId; + } + + public void setId(String ciscoAsa1000vResourceId) { + this.id = ciscoAsa1000vResourceId; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + public void setManagementIp(String managementIp) { + this.managementIp = managementIp; + } + + public void setInPortProfile(String inPortProfile) { + this.inPortProfile = inPortProfile; + } + + public void setGuestNetworkId(Long guestNetworkId) { + this.guestNetworkId = guestNetworkId; + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java new file mode 100644 index 00000000000..f5c9b727f8f --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java @@ -0,0 +1,75 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.response; + + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.PhysicalNetworkResponse; + +import com.cloud.network.cisco.CiscoVnmcController; +import com.google.gson.annotations.SerializedName; +@EntityReference(value = CiscoVnmcController.class) +public class CiscoVnmcResourceResponse extends BaseResponse { + public static final String RESOURCE_NAME = "resourcename"; + + @SerializedName(ApiConstants.RESOURCE_ID) + @Parameter(description="resource id of the Cisco VNMC controller") + private String id; + + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) + @Parameter(description="the physical network to which this VNMC belongs to", entityType = PhysicalNetworkResponse.class) + private Long physicalNetworkId; + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public String getProviderName() { + return providerName; + } + + public String getResourceName() { + return resourceName; + } + + @SerializedName(ApiConstants.PROVIDER) @Parameter(description="name of the provider") + private String providerName; + + @SerializedName(RESOURCE_NAME) + @Parameter(description="Cisco VNMC resource name") + private String resourceName; + + public void setId(String ciscoVnmcResourceId) { + this.id = ciscoVnmcResourceId; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDevice.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDevice.java new file mode 100755 index 00000000000..3c5f6827718 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDevice.java @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +import com.cloud.org.Grouping; + +public interface CiscoAsa1000vDevice extends Grouping, InternalIdentity, Identity { + + long getId(); + + String getUuid(); + + void setUuid(String uuid); + + long getPhysicalNetworkId(); + + String getManagementIp(); + + String getInPortProfile(); + + long getClusterId(); +} \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDeviceVO.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDeviceVO.java new file mode 100755 index 00000000000..ba85fb105c8 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoAsa1000vDeviceVO.java @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +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="external_cisco_asa1000v_devices") +public class CiscoAsa1000vDeviceVO implements CiscoAsa1000vDevice { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="physical_network_id") + private long physicalNetworkId; + + @Column(name="management_ip") + private String managementIp; + + @Column(name="in_Port_profile") + private String inPortProfile; + + @Column(name="cluster_id") + private long clusterId; + + public CiscoAsa1000vDeviceVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public CiscoAsa1000vDeviceVO(long physicalNetworkId, + String managementIp, String inPortProfile, long clusterId) { + super(); + this.physicalNetworkId = physicalNetworkId; + this.managementIp = managementIp; + this.inPortProfile = inPortProfile; + this.uuid = UUID.randomUUID().toString(); + this.clusterId = clusterId; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public long getPhysicalNetworkId() { + return physicalNetworkId; + } + + @Override + public String getManagementIp() { + return managementIp; + } + + @Override + public String getInPortProfile() { + return inPortProfile; + } + + @Override + public long getClusterId() { + return clusterId; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java new file mode 100644 index 00000000000..f137148ab48 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java @@ -0,0 +1,196 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import java.util.Map; + +import com.cloud.utils.exception.ExecutionException; + +public interface CiscoVnmcConnection { + + public boolean createTenant(String tenantName) throws ExecutionException; + + public boolean deleteTenant(String tenantName) throws ExecutionException; + + public boolean createTenantVDC(String tenantName) throws ExecutionException; + + public boolean deleteTenantVDC(String tenantName) throws ExecutionException; + + public boolean createTenantVDCEdgeDeviceProfile(String tenantName) + throws ExecutionException; + + public boolean createTenantVDCEdgeStaticRoutePolicy(String tenantName) + throws ExecutionException; + + public boolean createTenantVDCEdgeStaticRoute(String tenantName, + String nextHopIp, String destination, String netmask) throws ExecutionException; + + public boolean associateTenantVDCEdgeStaticRoutePolicy(String tenantName) + throws ExecutionException; + + public boolean associateTenantVDCEdgeDhcpPolicy(String tenantName, + String intfName) throws ExecutionException; + + public boolean createTenantVDCEdgeDhcpPolicy(String tenantName, + String startIp, String endIp, String subnet, String nameServerIp, + String domain) throws ExecutionException; + + public boolean associateTenantVDCEdgeDhcpServerPolicy(String tenantName, + String intfName) throws ExecutionException; + + public boolean createTenantVDCEdgeSecurityProfile(String tenantName) + throws ExecutionException; + + public boolean deleteTenantVDCEdgeSecurityProfile(String tenantName) + throws ExecutionException; + + public boolean createTenantVDCSourceNatIpPool(String tenantName, String identifier, + String publicIp) throws ExecutionException; + + public boolean createTenantVDCSourceNatRule(String tenantName, String identifier, + String startSourceIp, String endSourceIp) throws ExecutionException; + + public boolean createTenantVDCSourceNatPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCSourceNatPolicyRef(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCDNatIpPool(String tenantName, String identifier, + String ipAddress) throws ExecutionException; + + public boolean createTenantVDCDNatRule(String tenantName, + String identifier, String policyIdentifier, + String publicIp) + throws ExecutionException; + + public boolean deleteTenantVDCDNatRule(String tenantName, + String identifier, String policyIdentifier) + throws ExecutionException; + + public boolean createTenantVDCAclRuleForDNat(String tenantName, + String identifier, String policyIdentifier, + String ipAddress) + throws ExecutionException; + + public boolean createTenantVDCDNatPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean deleteTenantVDCDNatPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCDNatPolicyRef(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCPFPortPool(String tenantName, String identifier, + String startPort, String endPort) + throws ExecutionException; + + public boolean createTenantVDCPFIpPool(String tenantName, String identifier, + String ipAddress) throws ExecutionException; + + public boolean createTenantVDCPFRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String publicIp, + String startPort, String endPort) + throws ExecutionException; + + public boolean deleteTenantVDCPFRule(String tenantName, + String identifier, String policyIdentifier) + throws ExecutionException; + + public boolean createTenantVDCAclRuleForPF(String tenantName, + String identifier, String policyIdentifier, + String protocol, String ipAddress, + String startPort, String endPort) + throws ExecutionException; + + public boolean createTenantVDCPFPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean deleteTenantVDCPFPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCPFPolicyRef(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCNatPolicySet(String tenantName) + throws ExecutionException; + + public boolean deleteTenantVDCNatPolicySet(String tenantName) + throws ExecutionException; + + public boolean associateNatPolicySet(String tenantName) + throws ExecutionException; + + public boolean createTenantVDCIngressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartIp, String sourceEndIp, + String destStartPort, String destEndPort, String destIp) + throws ExecutionException; + + public boolean createTenantVDCIngressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartIp, String sourceEndIp, String destIp) + throws ExecutionException; + + public boolean createTenantVDCEgressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, + String destStartIp, String destEndIp) + throws ExecutionException; + + public boolean createTenantVDCEgressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceIp, String destStartIp, String destEndIp) + throws ExecutionException; + + public boolean deleteTenantVDCAclRule(String tenantName, + String identifier, String policyIdentifier) throws ExecutionException; + + public boolean createTenantVDCAclPolicy(String tenantName, + String identifier) throws ExecutionException; + + public boolean createTenantVDCAclPolicyRef(String tenantName, String identifier, + boolean ingress) throws ExecutionException; + + public boolean deleteTenantVDCAclPolicy(String tenantName, String identifier) + throws ExecutionException; + + public boolean createTenantVDCAclPolicySet(String tenantName, boolean ingress) + throws ExecutionException; + + public boolean deleteTenantVDCAclPolicySet(String tenantName, boolean ingress) + throws ExecutionException; + + public boolean associateAclPolicySet(String tenantName) + throws ExecutionException; + + public boolean createEdgeFirewall(String tenantName, String publicIp, + String insideIp, String publicSubnet, String insideSubnet) + throws ExecutionException; + + public boolean deleteEdgeFirewall(String tenantName) throws ExecutionException; + + public Map listUnAssocAsa1000v() throws ExecutionException; + + public boolean assignAsa1000v(String tenantName, String firewallDn) + throws ExecutionException; + + public boolean unassignAsa1000v(String tenantName, String firewallDn) + throws ExecutionException; +} \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java new file mode 100644 index 00000000000..527fb04698e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java @@ -0,0 +1,1415 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.cloud.utils.exception.ExecutionException; +import com.cloud.utils.script.Script; + +public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { + + private String _ip; + private String _username; + private String _password; + private String _cookie; + + private final Logger s_logger = Logger.getLogger(CiscoVnmcConnectionImpl.class); + + private enum VnmcXml { + LOGIN("login.xml", "mgmt-controller"), + + CREATE_TENANT("create-tenant.xml", "service-reg"), + DELETE_TENANT("delete-tenant.xml", "service-reg"), + CREATE_VDC("create-vdc.xml", "service-reg"), + DELETE_VDC("delete-vdc.xml", "service-reg"), + + CREATE_EDGE_DEVICE_PROFILE("create-edge-device-profile.xml", "policy-mgr"), + CREATE_EDGE_ROUTE_POLICY("create-edge-device-route-policy.xml", "policy-mgr"), + CREATE_EDGE_ROUTE("create-edge-device-route.xml", "policy-mgr"), + RESOLVE_EDGE_ROUTE_POLICY("associate-route-policy.xml", "policy-mgr"), + + CREATE_DHCP_POLICY("create-dhcp-policy.xml", "policy-mgr"), + RESOLVE_EDGE_DHCP_POLICY("associate-dhcp-policy.xml", "policy-mgr"), + RESOLVE_EDGE_DHCP_SERVER_POLICY("associate-dhcp-server.xml", "policy-mgr"), + + CREATE_EDGE_SECURITY_PROFILE("create-edge-security-profile.xml", "policy-mgr"), + DELETE_EDGE_SECURITY_PROFILE("delete-edge-security-profile.xml", "policy-mgr"), + + CREATE_NAT_POLICY_SET("create-nat-policy-set.xml", "policy-mgr"), + DELETE_NAT_POLICY_SET("delete-nat-policy-set.xml", "policy-mgr"), + RESOLVE_NAT_POLICY_SET("associate-nat-policy-set.xml", "policy-mgr"), + CREATE_NAT_POLICY("create-nat-policy.xml", "policy-mgr"), + DELETE_NAT_POLICY("delete-nat-policy.xml", "policy-mgr"), + LIST_NAT_POLICIES("list-nat-policies.xml", "policy-mgr"), + CREATE_NAT_POLICY_REF("create-nat-policy-ref.xml", "policy-mgr"), + CREATE_PORT_POOL("create-port-pool.xml", "policy-mgr"), + CREATE_IP_POOL("create-ip-pool.xml", "policy-mgr"), + + CREATE_PF_RULE("create-pf-rule.xml", "policy-mgr"), + CREATE_ACL_RULE_FOR_PF("create-acl-rule-for-pf.xml", "policy-mgr"), + CREATE_DNAT_RULE("create-dnat-rule.xml", "policy-mgr"), + CREATE_ACL_RULE_FOR_DNAT("create-acl-rule-for-dnat.xml", "policy-mgr"), + CREATE_SOURCE_NAT_RULE("create-source-nat-rule.xml", "policy-mgr"), + + CREATE_ACL_POLICY_SET("create-acl-policy-set.xml", "policy-mgr"), + DELETE_ACL_POLICY_SET("delete-acl-policy-set.xml", "policy-mgr"), + RESOLVE_ACL_POLICY_SET("associate-acl-policy-set.xml", "policy-mgr"), + CREATE_ACL_POLICY("create-acl-policy.xml", "policy-mgr"), + DELETE_ACL_POLICY("delete-acl-policy.xml", "policy-mgr"), + LIST_ACL_POLICIES("list-acl-policies.xml", "policy-mgr"), + CREATE_ACL_POLICY_REF("create-acl-policy-ref.xml", "policy-mgr"), + CREATE_INGRESS_ACL_RULE("create-ingress-acl-rule.xml", "policy-mgr"), + CREATE_EGRESS_ACL_RULE("create-egress-acl-rule.xml", "policy-mgr"), + CREATE_GENERIC_INGRESS_ACL_RULE("create-generic-ingress-acl-rule.xml", "policy-mgr"), + CREATE_GENERIC_EGRESS_ACL_RULE("create-generic-egress-acl-rule.xml", "policy-mgr"), + + DELETE_RULE("delete-rule.xml", "policy-mgr"), + + LIST_CHILDREN("list-children.xml", "policy-mgr"), + + CREATE_EDGE_FIREWALL("create-edge-firewall.xml", "resource-mgr"), + DELETE_EDGE_FIREWALL("delete-edge-firewall.xml", "resource-mgr"), + + LIST_UNASSOC_ASA1000V("list-unassigned-asa1000v.xml", "resource-mgr"), + ASSIGN_ASA1000V("assoc-asa1000v.xml", "resource-mgr"), + UNASSIGN_ASA1000V("disassoc-asa1000v.xml", "resource-mgr"); + + private String scriptsDir = "scripts/network/cisco"; + private String xml; + private String service; + private final Logger s_logger = Logger.getLogger(CiscoVnmcConnectionImpl.class); + + + private VnmcXml(String filename, String service) { + this.xml = getXml(filename); + this.service = service; + } + + public String getXml() { + return xml; + } + + private String getXml(String filename) { + try { + String xmlFilePath = Script.findScript(scriptsDir, filename); + + if (xmlFilePath == null) { + throw new Exception("Failed to find Cisco VNMC XML file: " + filename); + } + + FileReader fr = new FileReader(xmlFilePath); + BufferedReader br = new BufferedReader(fr); + + String xml = ""; + String line; + while ((line = br.readLine()) != null) { + //xml += line.replaceAll("\n"," "); + xml += line; + } + + return xml; + } catch (Exception e) { + s_logger.debug(e); + return null; + } + } + + public String getService() { + return service; + } + } + + public CiscoVnmcConnectionImpl(String hostIp, String userName, String password) { + this._ip = hostIp; + this._username = userName; + this._password = password; + + } + + public boolean login() throws ExecutionException { + String xml = VnmcXml.LOGIN.getXml(); + String service = VnmcXml.LOGIN.getService(); + xml = replaceXmlValue(xml, "username", _username); + xml = replaceXmlValue(xml, "password", _password); + String response = sendRequest(service, xml); + Map checked = checkResponse(response, "outCookie", "errorCode", "response"); + + if (checked.get("errorCode") != null) + return false; + _cookie = checked.get("outCookie"); + if (_cookie == null) { + return false; + } + return true; + } + + private String getDnForTenant(String tenantName) { + return "org-root/org-" + tenantName; + } + + private String getDnForTenantVDC(String tenantName) { + return getDnForTenant(tenantName) + "/org-VDC-" + tenantName; + } + + private String getDnForTenantVDCEdgeDeviceProfile(String tenantName) { + return getDnForTenantVDC(tenantName) + "/edsp-" + getNameForEdgeDeviceServiceProfile(tenantName); + } + + private String getDnForTenantVDCEdgeSecurityProfile(String tenantName) { + return getDnForTenantVDC(tenantName) + "/vnep-" + getNameForEdgeDeviceSecurityProfile(tenantName); + } + + private String getDnForEdgeDeviceRoutingPolicy(String tenantName) { + return getDnForTenantVDC(tenantName) + "/routing-policy-" + getNameForEdgeDeviceRoutePolicy(tenantName); + //FIXME: any other construct is unreliable. why? + } + + private String getDnForDhcpPolicy(String tenantName, String intfName) { + return getDnForTenantVDCEdgeDeviceProfile(tenantName) + "/dhcp-" + intfName; + } + + private String getNameForDhcpPolicy(String tenantName) { + return tenantName + "-Dhcp-Policy"; + } + + private String getNameForDhcpServer(String tenantName) { + return tenantName + "-Dhcp-Server"; + } + + private String getDnForDhcpServerPolicy(String tenantName) { + return getDnForTenantVDC(tenantName) + "/dhcp-server-" + getNameForDhcpPolicy(tenantName); + } + + private String getNameForIpRange() { + return "iprange"; + } + + private String getDnForDhcpIpRange(String tenantName) { + return getDnForDhcpServerPolicy(tenantName) + "/ip-range-" + getNameForIpRange(); + } + + private String getNameForDNSService(String tenantName) { + return tenantName + "-DNS"; + } + + private String getDnForDnsService(String tenantName) { + return getDnForDhcpServerPolicy(tenantName) + "/dns-svc-" + getNameForDNSService(tenantName); + } + + private String getDnForDnsServer(String tenantName, String dnsip) { + return getDnForDnsService(tenantName) + "/dns-" + dnsip; + } + + private String getNameForTenantVDC(String tenantName) { + return "VDC-" + tenantName; + } + + private String getNameForEdgeDeviceServiceProfile(String tenantName) { + return "EDSP-" + tenantName; + } + + private String getNameForEdgeDeviceSecurityProfile(String tenantName) { + return "ESP-" + tenantName; + } + + private String getNameForEdgeDeviceRoutePolicy(String tenantName) { + return "EDSP-" + tenantName + "-Routes"; + } + + @Override + public boolean createTenant(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_TENANT.getXml(); + String service = VnmcXml.CREATE_TENANT.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "Tenant for account " + tenantName); + xml = replaceXmlValue(xml, "name", tenantName); + xml = replaceXmlValue(xml, "dn", getDnForTenant(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenant(String tenantName) throws ExecutionException { + String xml = VnmcXml.DELETE_TENANT.getXml(); + String service = VnmcXml.DELETE_TENANT.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "name", tenantName); + xml = replaceXmlValue(xml, "dn", getDnForTenant(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDC(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_VDC.getXml(); + String service = VnmcXml.CREATE_VDC.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "VDC for Tenant" + tenantName); + xml = replaceXmlValue(xml, "name", getNameForTenantVDC(tenantName)); + xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDC(String tenantName) throws ExecutionException { + String xml = VnmcXml.DELETE_VDC.getXml(); + String service = VnmcXml.DELETE_VDC.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "name", getNameForTenantVDC(tenantName)); + xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEdgeDeviceProfile(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getXml(); + String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceServiceProfile(tenantName)); + xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEdgeStaticRoutePolicy(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_EDGE_ROUTE_POLICY.getXml(); + String service = VnmcXml.CREATE_EDGE_ROUTE_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceRoutePolicy(tenantName)); + xml = replaceXmlValue(xml, "routepolicydn", getDnForEdgeDeviceRoutingPolicy(tenantName)); + xml = replaceXmlValue(xml, "descr", "Routing Policy for Edge Device for Tenant " + tenantName); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEdgeStaticRoute(String tenantName, + String nextHopIp, String destination, String netmask) throws ExecutionException { + String xml = VnmcXml.CREATE_EDGE_ROUTE.getXml(); + String service = VnmcXml.CREATE_EDGE_ROUTE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "routepolicydn", getDnForEdgeDeviceRoutingPolicy(tenantName)); + xml = replaceXmlValue(xml, "nexthop", nextHopIp); + xml = replaceXmlValue(xml, "nexthopintf", getNameForEdgeOutsideIntf(tenantName)); + xml = replaceXmlValue(xml, "destination", destination); + xml = replaceXmlValue(xml, "netmask", netmask); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean associateTenantVDCEdgeStaticRoutePolicy(String tenantName) throws ExecutionException { + String xml = VnmcXml.RESOLVE_EDGE_ROUTE_POLICY.getXml(); + String service = VnmcXml.RESOLVE_EDGE_ROUTE_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceServiceProfile(tenantName)); + xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(tenantName)); + xml = replaceXmlValue(xml, "routepolicyname", getNameForEdgeDeviceRoutePolicy(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean associateTenantVDCEdgeDhcpPolicy(String tenantName, String intfName) throws ExecutionException { + String xml = VnmcXml.RESOLVE_EDGE_DHCP_POLICY.getXml(); + String service = VnmcXml.RESOLVE_EDGE_DHCP_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "dhcpdn", getDnForDhcpPolicy(tenantName, intfName)); + xml = replaceXmlValue(xml, "insideintf", intfName); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEdgeDhcpPolicy(String tenantName, + String startIp, String endIp, String subnet, String nameServerIp, String domain) throws ExecutionException { + String xml = VnmcXml.CREATE_DHCP_POLICY.getXml(); + String service = VnmcXml.CREATE_DHCP_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "dhcpserverdn", getDnForDhcpServerPolicy(tenantName)); + xml = replaceXmlValue(xml, "dhcpserverdescr", "DHCP server for " + tenantName); + xml = replaceXmlValue(xml, "dhcpservername", getNameForDhcpPolicy(tenantName)); + xml = replaceXmlValue(xml, "iprangedn", getDnForDhcpIpRange(tenantName)); + xml = replaceXmlValue(xml, "startip", startIp); + xml = replaceXmlValue(xml, "endip", endIp); + xml = replaceXmlValue(xml, "subnet", subnet); + xml = replaceXmlValue(xml, "domain", domain); + xml = replaceXmlValue(xml, "dnsservicedn", getDnForDnsService(tenantName)); + xml = replaceXmlValue(xml, "dnsservicename", getNameForDNSService(tenantName)); + xml = replaceXmlValue(xml, "nameserverip", nameServerIp); + xml = replaceXmlValue(xml, "nameserverdn", getDnForDnsServer(tenantName, nameServerIp)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean associateTenantVDCEdgeDhcpServerPolicy(String tenantName, String intfName) throws ExecutionException { + String xml = VnmcXml.RESOLVE_EDGE_DHCP_SERVER_POLICY.getXml(); + String service = VnmcXml.RESOLVE_EDGE_DHCP_SERVER_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "dhcpdn", getDnForDhcpPolicy(tenantName, intfName)); + xml = replaceXmlValue(xml, "insideintf", intfName); + xml = replaceXmlValue(xml, "dhcpserverpolicyname", getNameForDhcpServer(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEdgeSecurityProfile(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getXml(); + String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "egressref", "default-egress"); + xml = replaceXmlValue(xml, "ingressref", "default-ingress"); //FIXME: allows everything + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCEdgeSecurityProfile(String tenantName) throws ExecutionException { + String xml = VnmcXml.DELETE_EDGE_SECURITY_PROFILE.getXml(); + String service = VnmcXml.DELETE_EDGE_SECURITY_PROFILE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private String getNameForSourceNatIpPool(String tenantName) { + return "SNATIp-" + tenantName; + } + + private String getDnForSourceNatPool(String tenantName) { + return getDnForTenantVDC(tenantName) + "/objgrp-" + getNameForSourceNatIpPool(tenantName); + } + + @Override + public boolean createTenantVDCSourceNatIpPool(String tenantName, String identifier, + String publicIp) throws ExecutionException { + return createTenantVDCIpPool( + getDnForSourceNatPool(tenantName), + getNameForSourceNatIpPool(tenantName), + "Source NAT ip pool for Tenant VDC " + tenantName, + publicIp); + } + + private String getNameForSourceNatPolicy(String tenantName) { + return "SNAT-Policy-" + tenantName; + } + + private String getDnForSourceNatPolicy(String tenantName) { + return getDnForTenantVDC(tenantName) + "/natpol-" + getNameForSourceNatPolicy(tenantName); + } + + private String getNameForSourceNatRule(String tenantName) { + return "SNAT-Rule-" + tenantName; + } + + private String getDnForSourceNatRule(String tenantName) { + return getDnForSourceNatPolicy(tenantName) + "/rule-" + getNameForSourceNatRule(tenantName); + } + + private String getNameForNatPolicySet(String tenantName) { + return "NAT-PolicySet-" + tenantName; + } + + private String getDnForNatPolicySet(String tenantName) { + return getDnForTenantVDC(tenantName) + "/natpset-" + getNameForNatPolicySet(tenantName) ; + } + + private String getDnForSourceNatPolicyRef(String tenantName) { + return getDnForNatPolicySet(tenantName) + "/polref-" + getNameForSourceNatPolicy(tenantName) ; + } + + @Override + public boolean createTenantVDCSourceNatRule(String tenantName, String identifier, + String startSourceIp, String endSourceIp) throws ExecutionException { + + String xml = VnmcXml.CREATE_SOURCE_NAT_RULE.getXml(); + String service = VnmcXml.CREATE_SOURCE_NAT_RULE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natruledn", getDnForSourceNatRule(tenantName)); + xml = replaceXmlValue(xml, "natrulename", getNameForSourceNatRule(tenantName)); + xml = replaceXmlValue(xml, "descr", "Source NAT rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "srcstartip", startSourceIp); + xml = replaceXmlValue(xml, "srcendip", endSourceIp); + xml = replaceXmlValue(xml, "ippoolname", getNameForSourceNatIpPool(tenantName)); + + List rules = listChildren(getDnForSourceNatPolicy(tenantName)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCSourceNatPolicyRef(String tenantName, String identifier) throws ExecutionException { + return createTenantVDCNatPolicyRef( + getDnForSourceNatPolicyRef(tenantName), + getNameForSourceNatPolicy(tenantName), + tenantName); + } + + @Override + public boolean createTenantVDCSourceNatPolicy(String tenantName, String identifier) throws ExecutionException { + return createTenantVDCNatPolicy( + getDnForSourceNatPolicy(tenantName), + getNameForSourceNatPolicy(tenantName)); + } + + @Override + public boolean createTenantVDCNatPolicySet(String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_NAT_POLICY_SET.getXml(); + String service = VnmcXml.CREATE_NAT_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "NAT policy set for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); + xml = replaceXmlValue(xml, "natpolicysetdn", getDnForNatPolicySet(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCNatPolicySet(String tenantName) throws ExecutionException { + String xml = VnmcXml.DELETE_NAT_POLICY_SET.getXml(); + String service = VnmcXml.DELETE_NAT_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); + xml = replaceXmlValue(xml, "natpolicysetdn", getDnForNatPolicySet(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean associateNatPolicySet(String tenantName) throws ExecutionException { + String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml(); + String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private String getNameForAclPolicySet(String tenantName, boolean ingress) { + return (ingress ? "Ingress-" : "Egress-") + "ACL-PolicySet-" + tenantName; + } + + private String getDnForAclPolicySet(String tenantName, boolean ingress) { + return getDnForTenantVDC(tenantName) + "/pset-" + getNameForAclPolicySet(tenantName, ingress) ; + } + + private String getNameForAclPolicy(String tenantName, String identifier) { + return "ACL-" + tenantName + "-" + identifier; + } + + private String getDnForAclPolicy(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/pol-" + getNameForAclPolicy(tenantName, identifier); + } + + private String getDnForAclPolicyRef(String tenantName, String identifier, boolean ingress) { + return getDnForAclPolicySet(tenantName, ingress) + "/polref-" + getNameForAclPolicy(tenantName, identifier); + } + + private String getNameForAclRule(String tenantName, String identifier) { + return "Rule-" + tenantName + "-" + identifier; + } + + private String getDnForAclRule(String tenantName, String identifier, String policyIdentifier) { + return getDnForAclPolicy(tenantName, policyIdentifier) + "/rule-" + getNameForAclRule(tenantName, identifier); + } + + @Override + public boolean createTenantVDCAclPolicy(String tenantName, String identifier) throws ExecutionException { + String xml = VnmcXml.CREATE_ACL_POLICY.getXml(); + String service = VnmcXml.CREATE_ACL_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclpolicyname", getNameForAclPolicy(tenantName, identifier)); + xml = replaceXmlValue(xml, "aclpolicydn", getDnForAclPolicy(tenantName, identifier)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCAclPolicy(String tenantName, String identifier) throws ExecutionException { + String xml = VnmcXml.DELETE_ACL_POLICY.getXml(); + String service = VnmcXml.DELETE_ACL_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclpolicyname", getNameForAclPolicy(tenantName, identifier)); + xml = replaceXmlValue(xml, "aclpolicydn", getDnForAclPolicy(tenantName, identifier)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCAclPolicyRef(String tenantName, String identifier, boolean ingress) throws ExecutionException { + String xml = VnmcXml.CREATE_ACL_POLICY_REF.getXml(); + String service = VnmcXml.CREATE_ACL_POLICY_REF.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclpolicyname", getNameForAclPolicy(tenantName, identifier)); + xml = replaceXmlValue(xml, "aclpolicydn", getDnForAclPolicy(tenantName, identifier)); + xml = replaceXmlValue(xml, "aclpolicyrefdn", getDnForAclPolicyRef(tenantName, identifier, ingress)); + + List policies = listAclPolicies(tenantName); + int order = 100; + if (policies != null) { + order += policies.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCAclPolicySet(String tenantName, boolean ingress) throws ExecutionException { + String xml = VnmcXml.CREATE_ACL_POLICY_SET.getXml(); + String service = VnmcXml.CREATE_ACL_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "ACL policy set for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "aclpolicysetname", getNameForAclPolicySet(tenantName, ingress)); + xml = replaceXmlValue(xml, "aclpolicysetdn", getDnForAclPolicySet(tenantName, ingress)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCAclPolicySet(String tenantName, boolean ingress) throws ExecutionException { + String xml = VnmcXml.DELETE_ACL_POLICY_SET.getXml(); + String service = VnmcXml.DELETE_ACL_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclpolicysetname", getNameForAclPolicySet(tenantName, ingress)); + xml = replaceXmlValue(xml, "aclpolicysetdn", getDnForAclPolicySet(tenantName, ingress)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean associateAclPolicySet(String tenantName) throws ExecutionException { + String xml = VnmcXml.RESOLVE_ACL_POLICY_SET.getXml(); + String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); + //xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); + xml = replaceXmlValue(xml, "egresspolicysetname", "default-egress"); + xml = replaceXmlValue(xml, "ingresspolicysetname", getNameForAclPolicySet(tenantName, true)); + xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCIngressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartIp, String sourceEndIp, + String destStartPort, String destEndPort, String destIp) throws ExecutionException { + String xml = VnmcXml.CREATE_INGRESS_ACL_RULE.getXml(); + String service = VnmcXml.CREATE_INGRESS_ACL_RULE.getService(); + + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "Ingress ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + xml = replaceXmlValue(xml, "sourcestartip", sourceStartIp); + xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); + xml = replaceXmlValue(xml, "deststartport", destStartPort); + xml = replaceXmlValue(xml, "destendport", destEndPort); + xml = replaceXmlValue(xml, "destip", destIp); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCIngressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartIp, String sourceEndIp, + String destIp) throws ExecutionException { + String xml = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getXml(); + String service = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getService(); + + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "Ingress ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + xml = replaceXmlValue(xml, "sourcestartip", sourceStartIp); + xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEgressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, + String destStartIp, String destEndIp) throws ExecutionException { + String xml = VnmcXml.CREATE_EGRESS_ACL_RULE.getXml(); + String service = VnmcXml.CREATE_EGRESS_ACL_RULE.getService(); + + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "Egress ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + xml = replaceXmlValue(xml, "deststartip", destStartIp); + xml = replaceXmlValue(xml, "destendip", destEndIp); + xml = replaceXmlValue(xml, "sourcestartport", sourceStartPort); + xml = replaceXmlValue(xml, "sourceendport", sourceEndPort); + xml = replaceXmlValue(xml, "sourceip", sourceIp); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCEgressAclRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String sourceIp, + String destStartIp, String destEndIp) throws ExecutionException { + String xml = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getXml(); + String service = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getService(); + + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "Egress ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + xml = replaceXmlValue(xml, "deststartip", destStartIp); + xml = replaceXmlValue(xml, "destendip", destEndIp); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCAclRule(String tenantName, String identifier, String policyIdentifier) throws ExecutionException { + return deleteTenantVDCRule( + getDnForAclRule(tenantName, identifier, policyIdentifier), + getNameForAclRule(tenantName, identifier)); + } + + private String getNameForPFPortPool(String tenantName, String identifier) { + return "PFPort-" + tenantName + "-" + identifier; + } + + private String getDnForPFPortPool(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/objgrp-" + getNameForPFPortPool(tenantName, identifier); + } + + private String getNameForPFIpPool(String tenantName, String identifier) { + return "PFIp-" + tenantName + "-" + identifier; + } + + private String getDnForPFIpPool(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/objgrp-" + getNameForPFIpPool(tenantName, identifier); + } + + private boolean createTenantVDCPortPool(String poolDn, String name, + String description, String startPort, String endPort) throws ExecutionException { + String xml = VnmcXml.CREATE_PORT_POOL.getXml(); + String service = VnmcXml.CREATE_PORT_POOL.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "portpooldn", poolDn); + xml = replaceXmlValue(xml, "portpoolname", name); + xml = replaceXmlValue(xml, "descr", description); + xml = replaceXmlValue(xml, "startport", startPort); + xml = replaceXmlValue(xml, "endport", endPort); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private boolean createTenantVDCIpPool(String poolDn, String name, + String description, String ipAddress) throws ExecutionException { + String xml = VnmcXml.CREATE_IP_POOL.getXml(); + String service = VnmcXml.CREATE_IP_POOL.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "ippooldn", poolDn); + xml = replaceXmlValue(xml, "ippoolname", name); + xml = replaceXmlValue(xml, "descr", description); + xml = replaceXmlValue(xml, "ipvalue", ipAddress); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName) throws ExecutionException { + String xml = VnmcXml.CREATE_NAT_POLICY_REF.getXml(); + String service = VnmcXml.CREATE_NAT_POLICY_REF.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn); + xml = replaceXmlValue(xml, "natpolicyname", name); + + List policies = listNatPolicies(tenantName); + int order = 100; + if (policies != null) { + order += policies.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private boolean createTenantVDCNatPolicy(String policyDn, String name) throws ExecutionException { + String xml = VnmcXml.CREATE_NAT_POLICY.getXml(); + String service = VnmcXml.CREATE_NAT_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natpolicydn", policyDn); + xml = replaceXmlValue(xml, "natpolicyname", name); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private boolean deleteTenantVDCNatPolicy(String policyDn, String name) throws ExecutionException { + String xml = VnmcXml.DELETE_NAT_POLICY.getXml(); + String service = VnmcXml.DELETE_NAT_POLICY.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natpolicydn", policyDn); + xml = replaceXmlValue(xml, "natpolicyname", name); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private boolean deleteTenantVDCRule(String ruledn, String ruleName) throws ExecutionException { + String xml = VnmcXml.DELETE_RULE.getXml(); + String service = VnmcXml.DELETE_RULE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "ruledn", ruledn); + xml = replaceXmlValue(xml, "rulename", ruleName); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private List listNatPolicies(String tenantName) throws ExecutionException { + + String xml = VnmcXml.LIST_NAT_POLICIES.getXml(); + String service = VnmcXml.LIST_NAT_POLICIES.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "vdcdn", getDnForTenantVDC(tenantName)); + + String response = sendRequest(service, xml); + + List result = new ArrayList(); + Document xmlDoc = getDocument(response); + xmlDoc.normalize(); + NodeList policyList = xmlDoc.getElementsByTagName("pair"); + for (int i=0; i < policyList.getLength(); i++) { + Node policyNode = policyList.item(i); + result.add(policyNode.getAttributes().getNamedItem("key").getNodeValue()); + } + + return result; + } + + private List listAclPolicies(String tenantName) throws ExecutionException { + + String xml = VnmcXml.LIST_ACL_POLICIES.getXml(); + String service = VnmcXml.LIST_ACL_POLICIES.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "vdcdn", getDnForTenantVDC(tenantName)); + + String response = sendRequest(service, xml); + + List result = new ArrayList(); + Document xmlDoc = getDocument(response); + xmlDoc.normalize(); + NodeList policyList = xmlDoc.getElementsByTagName("pair"); + for (int i=0; i < policyList.getLength(); i++) { + Node policyNode = policyList.item(i); + result.add(policyNode.getAttributes().getNamedItem("key").getNodeValue()); + } + + return result; + } + + private List listChildren(String dn) throws ExecutionException { + + String xml = VnmcXml.LIST_CHILDREN.getXml(); + String service = VnmcXml.LIST_CHILDREN.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "dn", dn); + + String response = sendRequest(service, xml); + + List result = new ArrayList(); + Document xmlDoc = getDocument(response); + xmlDoc.normalize(); + NodeList policyList = xmlDoc.getElementsByTagName("policyRule"); + for (int i=0; i < policyList.getLength(); i++) { + Node policyNode = policyList.item(i); + result.add(policyNode.getAttributes().getNamedItem("name").getNodeValue()); + } + + return result; + } + + @Override + public boolean createTenantVDCPFPortPool(String tenantName, String identifier, + String startPort, String endPort) throws ExecutionException { + return createTenantVDCPortPool( + getDnForPFPortPool(tenantName, identifier), + getNameForPFPortPool(tenantName, identifier), + "PF port pool for " + getNameForPFPortPool(tenantName, identifier), + startPort, endPort); + } + + @Override + public boolean createTenantVDCPFIpPool(String tenantName, String identifier, + String ipAddress) throws ExecutionException { + return createTenantVDCIpPool( + getDnForPFIpPool(tenantName, identifier), + getNameForPFIpPool(tenantName, identifier), + "PF ip pool for " + getNameForPFIpPool(tenantName, identifier), + ipAddress); + } + + private String getNameForPFPolicy(String tenantName, String identifier) { + return "PF-" + tenantName + "-" + identifier; + } + + private String getDnForPFPolicy(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/natpol-" + getNameForPFPolicy(tenantName, identifier); + } + + private String getDnForPFPolicyRef(String tenantName, String identifier) { + return getDnForNatPolicySet(tenantName) + "/polref-" + getNameForPFPolicy(tenantName, identifier); + } + + private String getNameForPFRule(String tenantName, String identifier) { + return "Rule-" + tenantName + "-" + identifier; + } + + private String getDnForPFRule(String tenantName, String identifier, String policyIdentifier) { + return getDnForPFPolicy(tenantName, policyIdentifier) + "/rule-" + getNameForPFRule(tenantName, identifier); + } + + @Override + public boolean createTenantVDCPFRule(String tenantName, + String identifier, String policyIdentifier, + String protocol, String publicIp, + String startPort, String endPort) throws ExecutionException { + String xml = VnmcXml.CREATE_PF_RULE.getXml(); + String service = VnmcXml.CREATE_PF_RULE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natruledn", getDnForPFRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "natrulename", getNameForPFRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "PF rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "ippoolname", getNameForPFIpPool(tenantName, policyIdentifier + "-" + identifier)); + xml = replaceXmlValue(xml, "portpoolname", getNameForPFPortPool(tenantName, policyIdentifier + "-" + identifier)); + xml = replaceXmlValue(xml, "ip", publicIp); + xml = replaceXmlValue(xml, "startport", startPort); + xml = replaceXmlValue(xml, "endport", endPort); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + + List rules = listChildren(getDnForPFPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCPFRule(String tenantName, String identifier, + String policyIdentifier) throws ExecutionException { + return deleteTenantVDCRule( + getDnForPFRule(tenantName, identifier, policyIdentifier), + getNameForPFRule(tenantName, identifier)); + } + + @Override + public boolean createTenantVDCAclRuleForPF(String tenantName, + String identifier, String policyIdentifier, String protocol, + String ipAddress, String startPort, String endPort) + throws ExecutionException { + String xml = VnmcXml.CREATE_ACL_RULE_FOR_PF.getXml(); + String service = VnmcXml.CREATE_ACL_RULE_FOR_PF.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "protocolvalue", protocol); + xml = replaceXmlValue(xml, "ip", ipAddress); + xml = replaceXmlValue(xml, "startport", startPort); + xml = replaceXmlValue(xml, "endport", endPort); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCPFPolicyRef(String tenantName, String identifier) throws ExecutionException { + return createTenantVDCNatPolicyRef( + getDnForPFPolicyRef(tenantName, identifier), + getNameForPFPolicy(tenantName, identifier), + tenantName); + } + + @Override + public boolean createTenantVDCPFPolicy(String tenantName, String identifier) throws ExecutionException { + return createTenantVDCNatPolicy( + getDnForPFPolicy(tenantName, identifier), + getNameForPFPolicy(tenantName, identifier)); + } + + @Override + public boolean deleteTenantVDCPFPolicy(String tenantName, String identifier) throws ExecutionException { + return deleteTenantVDCNatPolicy( + getDnForPFPolicy(tenantName, identifier), + getNameForPFPolicy(tenantName, identifier)); + } + + private String getNameForDNatIpPool(String tenantName, String identifier) { + return "DNATIp-" + tenantName + "-" + identifier; + } + + private String getDnForDNatIpPool(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/objgrp-" + getNameForDNatIpPool(tenantName, identifier); + } + + @Override + public boolean createTenantVDCDNatIpPool(String tenantName, + String identifier, String ipAddress) throws ExecutionException { + return createTenantVDCIpPool( + getDnForDNatIpPool(tenantName, identifier), + getNameForDNatIpPool(tenantName, identifier), + "DNAT ip pool for " + getNameForDNatIpPool(tenantName, identifier), + ipAddress); + } + + private String getNameForDNatRule(String tenantName, String identifier) { + return "Rule-" + tenantName + "-" + identifier; + } + + private String getDnForDNatRule(String tenantName, String identifier, String policyIdentifier) { + return getDnForDNatPolicy(tenantName, policyIdentifier) + "/rule-" + getNameForDNatRule(tenantName, identifier); + } + + private String getNameForDNatPolicy(String tenantName, String identifier) { + return "DNAT-" + tenantName + "-" + identifier; + } + + private String getDnForDNatPolicy(String tenantName, String identifier) { + return getDnForTenantVDC(tenantName) + "/natpol-" + getNameForDNatPolicy(tenantName, identifier); + } + + private String getDnForDNatPolicyRef(String tenantName, String identifier) { + return getDnForNatPolicySet(tenantName) + "/polref-" + getNameForDNatPolicy(tenantName, identifier); + } + + @Override + public boolean createTenantVDCDNatRule(String tenantName, + String identifier, String policyIdentifier, String publicIp) + throws ExecutionException { + String xml = VnmcXml.CREATE_DNAT_RULE.getXml(); + String service = VnmcXml.CREATE_DNAT_RULE.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "natruledn", getDnForDNatRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "natrulename", getNameForDNatRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "DNAT rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "ippoolname", getNameForDNatIpPool(tenantName, policyIdentifier + "-" + identifier)); + xml = replaceXmlValue(xml, "ip", publicIp); + + List rules = listChildren(getDnForDNatPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteTenantVDCDNatRule(String tenantName, + String identifier, String policyIdentifier) + throws ExecutionException { + return deleteTenantVDCRule( + getDnForDNatRule(tenantName, identifier, policyIdentifier), + getNameForDNatRule(tenantName, identifier)); + } + + @Override + public boolean createTenantVDCAclRuleForDNat(String tenantName, + String identifier, String policyIdentifier, String ipAddress) + throws ExecutionException { + String xml = VnmcXml.CREATE_ACL_RULE_FOR_DNAT.getXml(); + String service = VnmcXml.CREATE_ACL_RULE_FOR_DNAT.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); + xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); + xml = replaceXmlValue(xml, "descr", "ACL rule for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "actiontype", "permit"); + xml = replaceXmlValue(xml, "ip", ipAddress); + + List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); + int order = 100; + if (rules != null) { + order += rules.size(); + } + xml = replaceXmlValue(xml, "order", Integer.toString(order)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean createTenantVDCDNatPolicyRef(String tenantName, + String identifier) throws ExecutionException { + return createTenantVDCNatPolicyRef( + getDnForDNatPolicyRef(tenantName, identifier), + getNameForDNatPolicy(tenantName, identifier), + tenantName); + } + + @Override + public boolean createTenantVDCDNatPolicy(String tenantName, + String identifier) throws ExecutionException { + return createTenantVDCNatPolicy( + getDnForDNatPolicy(tenantName, identifier), + getNameForDNatPolicy(tenantName, identifier)); + } + + @Override + public boolean deleteTenantVDCDNatPolicy(String tenantName, + String identifier) throws ExecutionException { + return deleteTenantVDCNatPolicy( + getDnForDNatPolicy(tenantName, identifier), + getNameForDNatPolicy(tenantName, identifier)); + } + + private String getNameForEdgeFirewall(String tenantName) { + return "ASA-1000v-" + tenantName; + } + + private String getDnForEdgeFirewall(String tenantName) { + return getDnForTenantVDC(tenantName) + "/efw-" + getNameForEdgeFirewall(tenantName); + } + + private String getNameForEdgeInsideIntf(String tenantName) { + return "Edge_Inside"; //TODO: make this configurable + } + + private String getNameForEdgeOutsideIntf(String tenantName) { + return "Edge_Outside"; //TODO: make this configurable + } + + private String getDnForOutsideIntf(String tenantName) { + return getDnForEdgeFirewall(tenantName) + "/interface-" + getNameForEdgeOutsideIntf(tenantName); + } + + private String getDnForInsideIntf(String tenantName) { + return getDnForEdgeFirewall(tenantName) + "/interface-" + getNameForEdgeInsideIntf(tenantName); + } + + @Override + public boolean createEdgeFirewall(String tenantName, String publicIp, String insideIp, + String publicSubnet, String insideSubnet) throws ExecutionException { + String xml = VnmcXml.CREATE_EDGE_FIREWALL.getXml(); + String service = VnmcXml.CREATE_EDGE_FIREWALL.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "edgefwdescr", "Edge Firewall for Tenant VDC " + tenantName); + xml = replaceXmlValue(xml, "edgefwname", getNameForEdgeFirewall(tenantName)); + xml = replaceXmlValue(xml, "edgefwdn", getDnForEdgeFirewall(tenantName)); + xml = replaceXmlValue(xml, "insideintfname", getNameForEdgeInsideIntf(tenantName)); + xml = replaceXmlValue(xml, "outsideintfname", getNameForEdgeOutsideIntf(tenantName)); + + xml = replaceXmlValue(xml, "insideintfdn", getDnForInsideIntf(tenantName)); + xml = replaceXmlValue(xml, "outsideintfdn", getDnForOutsideIntf(tenantName)); + + xml = replaceXmlValue(xml, "deviceserviceprofiledn", getDnForEdgeFirewall(tenantName) + "/device-service-profile"); + xml = replaceXmlValue(xml, "outsideintfsp", getDnForOutsideIntf(tenantName) + "/interface-service-profile"); + + xml = replaceXmlValue(xml, "secprofileref", getNameForEdgeDeviceSecurityProfile(tenantName)); + xml = replaceXmlValue(xml, "deviceserviceprofile", getNameForEdgeDeviceServiceProfile(tenantName)); + + xml = replaceXmlValue(xml, "insideip", insideIp); + xml = replaceXmlValue(xml, "publicip", publicIp); + xml = replaceXmlValue(xml, "insidesubnet", insideSubnet); + xml = replaceXmlValue(xml, "outsidesubnet", publicSubnet); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean deleteEdgeFirewall(String tenantName) throws ExecutionException { + String xml = VnmcXml.DELETE_EDGE_FIREWALL.getXml(); + String service = VnmcXml.DELETE_EDGE_FIREWALL.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "edgefwname", getNameForEdgeFirewall(tenantName)); + xml = replaceXmlValue(xml, "edgefwdn", getDnForEdgeFirewall(tenantName)); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public Map listUnAssocAsa1000v() throws ExecutionException { + String xml = VnmcXml.LIST_UNASSOC_ASA1000V.getXml(); + String service = VnmcXml.LIST_UNASSOC_ASA1000V.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + + String response = sendRequest(service, xml); + + Map result = new HashMap(); + Document xmlDoc = getDocument(response); + xmlDoc.normalize(); + NodeList fwList = xmlDoc.getElementsByTagName("fwInstance"); + for (int j=0; j < fwList.getLength(); j++) { + Node fwNode = fwList.item(j); + result.put(fwNode.getAttributes().getNamedItem("mgmtIp").getNodeValue(), + fwNode.getAttributes().getNamedItem("dn").getNodeValue()); + } + + return result; + } + + @Override + public boolean assignAsa1000v(String tenantName, String firewallDn) throws ExecutionException { + String xml = VnmcXml.ASSIGN_ASA1000V.getXml(); + String service = VnmcXml.ASSIGN_ASA1000V.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "binddn", getDnForEdgeFirewall(tenantName) + "/binding"); + xml = replaceXmlValue(xml, "fwdn", firewallDn); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + @Override + public boolean unassignAsa1000v(String tenantName, String firewallDn) throws ExecutionException { + String xml = VnmcXml.UNASSIGN_ASA1000V.getXml(); + String service = VnmcXml.UNASSIGN_ASA1000V.getService(); + xml = replaceXmlValue(xml, "cookie", _cookie); + xml = replaceXmlValue(xml, "binddn", getDnForEdgeFirewall(tenantName) + "/binding"); + xml = replaceXmlValue(xml, "fwdn", firewallDn); + + String response = sendRequest(service, xml); + return verifySuccess(response); + } + + private String sendRequest(String service, String xmlRequest) throws ExecutionException { + org.apache.commons.httpclient.protocol.Protocol myhttps = + new org.apache.commons.httpclient.protocol.Protocol("https", new EasySSLProtocolSocketFactory(), 443); + HttpClient client = new HttpClient(); + client.getHostConfiguration().setHost(_ip, 443, myhttps); + byte[] response = null; + PostMethod method = new PostMethod("/xmlIM/" + service); + + method.setRequestBody(xmlRequest); + + try{ + int statusCode = client.executeMethod(method); + + if (statusCode != HttpStatus.SC_OK) { + throw new Exception("Error code : " + statusCode); + } + response = method.getResponseBody(); + }catch(Exception e){ + System.out.println(e.getMessage()); + throw new ExecutionException(e.getMessage()); + } + System.out.println(new String(response)); + return new String(response); + } + + private Map checkResponse(String xmlResponse, String... keys) throws ExecutionException { + Document xmlDoc = getDocument(xmlResponse); + Map result = new HashMap(); + Node topElement = xmlDoc.getChildNodes().item(0); + if (topElement != null) { + for (String key: keys){ + Node valueNode = topElement.getAttributes().getNamedItem(key); + result.put(key, valueNode==null?null:valueNode.getNodeValue()); + } + } + return result; + } + + private boolean verifySuccess(String xmlResponse) throws ExecutionException { + Map checked = checkResponse(xmlResponse, "errorCode", "errorDescr"); + + if (checked.get("errorCode") != null) { + String errorCode = checked.get("errorCode"); + if (errorCode.equals("103")) { + //tenant already exists + return true; + } + String errorDescr = checked.get("errorDescr"); + throw new ExecutionException(errorDescr); + } + return true; + } + + /* + * XML utils + */ + + private Document getDocument(String xml) throws ExecutionException { + StringReader xmlReader = new StringReader(" \n" + xml.trim()); + InputSource xmlSource = new InputSource(xmlReader); + Document doc = null; + + try { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlSource); + + } catch (Exception e) { + s_logger.error(e); + throw new ExecutionException(e.getMessage()); + } + + if (doc == null) { + throw new ExecutionException("Failed to parse xml " + xml); + } else { + return doc; + } + } + + private String replaceXmlTag(String xml, String oldTag, String newTag) { + return xml.replaceAll(oldTag, newTag); + } + + private String replaceXmlValue(String xml, String marker, String value) { + marker = "\\s*%" + marker + "%\\s*"; + + if (value == null) { + value = ""; + } + + return xml.replaceAll(marker, value); + } + + private String extractXml(String xml, String marker) { + String startMarker = "<" + marker + ">"; + String endMarker = ""; + if (xml.contains(startMarker) && xml.contains(endMarker)) { + return xml.substring(xml.indexOf(startMarker) + startMarker.length(), xml.indexOf(endMarker)); + } else { + return null; + } + + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcController.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcController.java new file mode 100644 index 00000000000..e756165bdaa --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcController.java @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +import com.cloud.org.Grouping; + +public interface CiscoVnmcController extends Grouping, InternalIdentity, Identity { + + long getId(); + + String getUuid(); + + void setUuid(String uuid); + + long getPhysicalNetworkId(); + + long getHostId(); + + String getProviderName(); + + String getDeviceName(); + +} \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcControllerVO.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcControllerVO.java new file mode 100644 index 00000000000..4207f1dac4c --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcControllerVO.java @@ -0,0 +1,102 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +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="external_cisco_vnmc_devices") +public class CiscoVnmcControllerVO implements CiscoVnmcController { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="host_id") + private long hostId; + + @Column(name="physical_network_id") + private long physicalNetworkId; + + @Column(name="provider_name") + private String providerName; + + @Column(name="device_name") + private String deviceName; + + + public CiscoVnmcControllerVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public CiscoVnmcControllerVO(long hostId, long physicalNetworkId, + String providerName, String deviceName) { + super(); + this.hostId = hostId; + this.physicalNetworkId = physicalNetworkId; + this.providerName = providerName; + this.deviceName = deviceName; + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public long getPhysicalNetworkId() { + return physicalNetworkId; + } + + @Override + public long getHostId() { + return hostId; + } + + @Override + public String getProviderName() { + return providerName; + } + + @Override + public String getDeviceName() { + return deviceName; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMap.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMap.java new file mode 100755 index 00000000000..2e004dccd41 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMap.java @@ -0,0 +1,31 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import org.apache.cloudstack.api.InternalIdentity; + +import com.cloud.org.Grouping; + +public interface NetworkAsa1000vMap extends Grouping, InternalIdentity { + + long getId(); + + long getNetworkId(); + + long getAsa1000vId(); + +} \ No newline at end of file diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMapVO.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMapVO.java new file mode 100755 index 00000000000..9638b6f8ae2 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/NetworkAsa1000vMapVO.java @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +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="network_asa1000v_map") +public class NetworkAsa1000vMapVO implements NetworkAsa1000vMap { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="network_id") + private long networkId; + + @Column(name="asa1000v_id") + private long asa1000vId; + + public NetworkAsa1000vMapVO() { + } + + public NetworkAsa1000vMapVO(long networkId, long asa1000vId) { + super(); + this.networkId = networkId; + this.asa1000vId = asa1000vId; + } + + @Override + public long getId() { + return id; + } + + @Override + public long getAsa1000vId() { + return asa1000vId; + } + + public void setAsa1000vId(long asa1000vId) { + this.asa1000vId = asa1000vId; + } + + @Override + public long getNetworkId() { + return networkId; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDao.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDao.java new file mode 100755 index 00000000000..1a380b13691 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDao.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.utils.db.GenericDao; + +public interface CiscoAsa1000vDao extends GenericDao{ + /** + * list all the Cisco Asa 1000v devices added in to this physical network + * @param physicalNetworkId physical Network Id + * @return list of CiscoAsa1000vDeviceVO for this physical network. + */ + List listByPhysicalNetwork(long physicalNetworkId); + + CiscoAsa1000vDeviceVO findByManagementIp(String managementIp); +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDaoImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDaoImpl.java new file mode 100755 index 00000000000..a5820dea48b --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoAsa1000vDaoImpl.java @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; + +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Component +@Local(value=CiscoAsa1000vDao.class) +public class CiscoAsa1000vDaoImpl extends GenericDaoBase + implements CiscoAsa1000vDao { + + protected final SearchBuilder physicalNetworkIdSearch; + protected final SearchBuilder managementIpSearch; + + public CiscoAsa1000vDaoImpl() { + physicalNetworkIdSearch = createSearchBuilder(); + physicalNetworkIdSearch.and("physicalNetworkId", physicalNetworkIdSearch.entity().getPhysicalNetworkId(), Op.EQ); + physicalNetworkIdSearch.done(); + + managementIpSearch = createSearchBuilder(); + managementIpSearch.and("managementIp", managementIpSearch.entity().getManagementIp(), Op.EQ); + managementIpSearch.done(); + } + + @Override + public List listByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = physicalNetworkIdSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return search(sc, null); + } + + @Override + public CiscoAsa1000vDeviceVO findByManagementIp(String managementIp) { + SearchCriteria sc = managementIpSearch.create(); + sc.setParameters("managementIp", managementIp); + return findOneBy(sc); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDao.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDao.java new file mode 100644 index 00000000000..f0b394834a0 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDao.java @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.utils.db.GenericDao; + +public interface CiscoVnmcDao extends GenericDao{ + /** + * list all the Cisco VNMC devices added in to this physical network + * @param physicalNetworkId physical Network Id + * @return list of CiscoVnmcDeviceVO for this physical network. + */ + List listByPhysicalNetwork(long physicalNetworkId); + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDaoImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDaoImpl.java new file mode 100644 index 00000000000..89518104851 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/CiscoVnmcDaoImpl.java @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; + +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Component +@Local(value=CiscoVnmcDao.class) +public class CiscoVnmcDaoImpl extends GenericDaoBase + implements CiscoVnmcDao { + + protected final SearchBuilder physicalNetworkIdSearch; + + public CiscoVnmcDaoImpl() { + physicalNetworkIdSearch = createSearchBuilder(); + physicalNetworkIdSearch.and("physicalNetworkId", physicalNetworkIdSearch.entity().getPhysicalNetworkId(), Op.EQ); + physicalNetworkIdSearch.done(); + } + + @Override + public List listByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = physicalNetworkIdSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return search(sc, null); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDao.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDao.java new file mode 100755 index 00000000000..053f4afef54 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDao.java @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import com.cloud.network.cisco.NetworkAsa1000vMapVO; +import com.cloud.utils.db.GenericDao; + +public interface NetworkAsa1000vMapDao extends GenericDao{ + + NetworkAsa1000vMapVO findByNetworkId(long networkId); + + NetworkAsa1000vMapVO findByAsa1000vId(long asa1000vId); + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDaoImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDaoImpl.java new file mode 100755 index 00000000000..692b3d6fda6 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/dao/NetworkAsa1000vMapDaoImpl.java @@ -0,0 +1,61 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; + +import com.cloud.network.cisco.NetworkAsa1000vMapVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Component +@Local(value=NetworkAsa1000vMapDao.class) +public class NetworkAsa1000vMapDaoImpl extends GenericDaoBase + implements NetworkAsa1000vMapDao { + + protected final SearchBuilder networkSearch; + protected final SearchBuilder asa1000vSearch; + + public NetworkAsa1000vMapDaoImpl() { + networkSearch = createSearchBuilder(); + networkSearch.and("networkId", networkSearch.entity().getNetworkId(), Op.EQ); + networkSearch.done(); + + asa1000vSearch = createSearchBuilder(); + asa1000vSearch.and("asa1000vId", asa1000vSearch.entity().getAsa1000vId(), Op.EQ); + asa1000vSearch.done(); + } + + @Override + public NetworkAsa1000vMapVO findByNetworkId(long networkId) { + SearchCriteria sc = networkSearch.create(); + sc.setParameters("networkId", networkId); + return findOneBy(sc); + } + + @Override + public NetworkAsa1000vMapVO findByAsa1000vId(long asa1000vId) { + SearchCriteria sc = asa1000vSearch.create(); + sc.setParameters("asa1000vId", asa1000vId); + return findOneBy(sc); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoAsa1000vService.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoAsa1000vService.java new file mode 100755 index 00000000000..dff9288b0ff --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoAsa1000vService.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 com.cloud.network.element; + +import java.util.List; + +import com.cloud.api.commands.AddCiscoAsa1000vResourceCmd; +import com.cloud.api.commands.DeleteCiscoAsa1000vResourceCmd; +import com.cloud.api.commands.ListCiscoAsa1000vResourcesCmd; +import com.cloud.api.response.CiscoAsa1000vResourceResponse; +import com.cloud.network.Network; +import com.cloud.network.cisco.CiscoAsa1000vDevice; +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.utils.component.PluggableService; + +public interface CiscoAsa1000vService extends PluggableService { + + public CiscoAsa1000vDevice addCiscoAsa1000vResource(AddCiscoAsa1000vResourceCmd cmd); + + public CiscoAsa1000vResourceResponse createCiscoAsa1000vResourceResponse( + CiscoAsa1000vDevice ciscoAsa1000vDeviceVO); + + boolean deleteCiscoAsa1000vResource(DeleteCiscoAsa1000vResourceCmd cmd); + + List listCiscoAsa1000vResources(ListCiscoAsa1000vResourcesCmd cmd); + + CiscoAsa1000vDevice assignAsa1000vToNetwork(Network network); + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java new file mode 100644 index 00000000000..443bb40f57f --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java @@ -0,0 +1,928 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.element; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AssociateAsaWithLogicalEdgeFirewallCommand; +import com.cloud.agent.api.CleanupLogicalEdgeFirewallCommand; +import com.cloud.agent.api.ConfigureNexusVsmForAsaCommand; +import com.cloud.agent.api.CreateLogicalEdgeFirewallCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupExternalFirewallCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.to.FirewallRuleTO; +import com.cloud.agent.api.to.IpAddressTO; +import com.cloud.agent.api.to.PortForwardingRuleTO; +import com.cloud.agent.api.to.StaticNatRuleTO; +import com.cloud.api.commands.AddCiscoAsa1000vResourceCmd; +import com.cloud.api.commands.AddCiscoVnmcResourceCmd; +import com.cloud.api.commands.DeleteCiscoAsa1000vResourceCmd; +import com.cloud.api.commands.DeleteCiscoVnmcResourceCmd; +import com.cloud.api.commands.ListCiscoAsa1000vResourcesCmd; +import com.cloud.api.commands.ListCiscoVnmcResourcesCmd; +import com.cloud.api.response.CiscoAsa1000vResourceResponse; +import com.cloud.api.response.CiscoVnmcResourceResponse; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.ClusterVSMMapVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.Vlan; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.ClusterVSMMapDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.DetailVO; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.CiscoNexusVSMDeviceVO; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.cisco.CiscoAsa1000vDevice; +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.network.cisco.CiscoVnmcController; +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.network.cisco.NetworkAsa1000vMapVO; +import com.cloud.network.dao.CiscoAsa1000vDao; +import com.cloud.network.dao.CiscoNexusVSMDeviceDao; +import com.cloud.network.dao.CiscoVnmcDao; +import com.cloud.network.dao.NetworkAsa1000vMapDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.resource.CiscoVnmcResource; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.user.Account; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value = NetworkElement.class) +public class CiscoVnmcElement extends AdapterBase implements SourceNatServiceProvider, FirewallServiceProvider, + PortForwardingServiceProvider, IpDeployer, StaticNatServiceProvider, ResourceStateAdapter, NetworkElement, + CiscoVnmcElementService, CiscoAsa1000vService { + private static final Logger s_logger = Logger.getLogger(CiscoVnmcElement.class); + private static final Map> capabilities = setCapabilities(); + + @Inject + AgentManager _agentMgr; + @Inject + ResourceManager _resourceMgr; + @Inject + ConfigurationManager _configMgr; + @Inject + NetworkManager _networkMgr; + @Inject + NetworkModel _networkModel; + + @Inject + PhysicalNetworkDao _physicalNetworkDao; + @Inject + PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; + @Inject + HostDetailsDao _hostDetailsDao; + @Inject + HostDao _hostDao; + @Inject + NetworkDao _networkDao; + @Inject + ClusterDao _clusterDao; + @Inject + VlanDao _vlanDao; + @Inject + ClusterVSMMapDao _clusterVsmMapDao; + @Inject + CiscoNexusVSMDeviceDao _vsmDeviceDao; + @Inject + CiscoVnmcDao _ciscoVnmcDao; + @Inject + CiscoAsa1000vDao _ciscoAsa1000vDao; + @Inject + NetworkAsa1000vMapDao _networkAsa1000vMapDao; + + protected boolean canHandle(Network network) { + if (network.getBroadcastDomainType() != BroadcastDomainType.Vlan) { + return false; //TODO: should handle VxLAN as well + } + + return true; + } + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + super.configure(name, params); + _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); + return true; + } + + private static Map> setCapabilities() { + Map> capabilities = new HashMap>(); + capabilities.put(Service.Gateway, null); + + Map firewallCapabilities = new HashMap(); + firewallCapabilities.put(Capability.TrafficStatistics, "per public ip"); + firewallCapabilities.put(Capability.SupportedTrafficDirection, "ingress,egress"); + firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp"); + firewallCapabilities.put(Capability.SupportedEgressProtocols, "tcp,udp,icmp"); + firewallCapabilities.put(Capability.MultipleIps, "true"); + capabilities.put(Service.Firewall, firewallCapabilities); + + capabilities.put(Service.StaticNat, null); + capabilities.put(Service.PortForwarding, null); + + Map sourceNatCapabilities = new HashMap(); + sourceNatCapabilities.put(Capability.SupportedSourceNatTypes, "peraccount"); + sourceNatCapabilities.put(Capability.RedundantRouter, "false"); //TODO: + capabilities.put(Service.SourceNat, sourceNatCapabilities); + return capabilities; + } + + @Override + public Map> getCapabilities() { + return capabilities; + } + + @Override + public Provider getProvider() { + return Provider.CiscoVnmc; + } + + private boolean createLogicalEdgeFirewall(long vlanId, + String gateway, String gatewayNetmask, + String publicIp, String publicNetmask, + List publicGateways, long hostId) { + CreateLogicalEdgeFirewallCommand cmd = new CreateLogicalEdgeFirewallCommand(vlanId, publicIp, gateway, publicNetmask, gatewayNetmask); + for (String publicGateway : publicGateways) { + cmd.getPublicGateways().add(publicGateway); + } + Answer answer = _agentMgr.easySend(hostId, cmd); + return answer.getResult(); + } + + private boolean configureNexusVsmForAsa(long vlanId, String gateway, + String vsmUsername, String vsmPassword, String vsmIp, + String asaInPortProfile, long hostId) { + ConfigureNexusVsmForAsaCommand cmd = new ConfigureNexusVsmForAsaCommand(vlanId, gateway, vsmUsername, vsmPassword, vsmIp, asaInPortProfile); + Answer answer = _agentMgr.easySend(hostId, cmd); + return answer.getResult(); + } + + private boolean configureSourceNat(long vlanId, String guestCidr, + PublicIp sourceNatIp, long hostId) { + boolean add = (sourceNatIp.getState() == IpAddress.State.Releasing ? false : true); + IpAddressTO ip = new IpAddressTO(sourceNatIp.getAccountId(), sourceNatIp.getAddress().addr(), add, false, + sourceNatIp.isSourceNat(), sourceNatIp.getVlanTag(), sourceNatIp.getGateway(), sourceNatIp.getNetmask(), sourceNatIp.getMacAddress(), + null, sourceNatIp.isOneToOneNat()); + boolean addSourceNat = false; + if (sourceNatIp.isSourceNat()) { + addSourceNat = add; + } + + SetSourceNatCommand cmd = new SetSourceNatCommand(ip, addSourceNat); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId)); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, guestCidr); + Answer answer = _agentMgr.easySend(hostId, cmd); + return answer.getResult(); + } + + private boolean associateAsaWithLogicalEdgeFirewall(long vlanId, + String asaMgmtIp, long hostId) { + AssociateAsaWithLogicalEdgeFirewallCommand cmd = + new AssociateAsaWithLogicalEdgeFirewallCommand(vlanId, asaMgmtIp); + Answer answer = _agentMgr.easySend(hostId, cmd); + return answer.getResult(); + } + + @Override + public boolean implement(Network network, NetworkOffering offering, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); + + if (zone.getNetworkType() == NetworkType.Basic) { + s_logger.debug("Not handling network implement in zone of type " + NetworkType.Basic); + return false; + } + + if (!canHandle(network)) { + return false; + } + + List devices = _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No Cisco Vnmc device on network " + network.getName()); + return false; + } + + List asaList = _ciscoAsa1000vDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (asaList.isEmpty()) { + s_logger.debug("No Cisco ASA 1000v device on network " + network.getName()); + return false; + } + + NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (asaForNetwork != null) { + s_logger.debug("Cisco ASA 1000v device already associated with network " + network.getName()); + return true; + } + + if (!_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.CiscoVnmc)) { + s_logger.error("SourceNat service is not provided by Cisco Vnmc device on network " + network.getName()); + return false; + } + + Transaction txn = Transaction.currentTxn(); + boolean status = false; + try { + txn.start(); + + // ensure that there is an ASA 1000v assigned to this network + CiscoAsa1000vDevice assignedAsa = assignAsa1000vToNetwork(network); + if (assignedAsa == null) { + s_logger.error("Unable to assign ASA 1000v device to network " + network.getName()); + return false; + } + + ClusterVO asaCluster = _clusterDao.findById(assignedAsa.getClusterId()); + ClusterVSMMapVO clusterVsmMap = _clusterVsmMapDao.findByClusterId(assignedAsa.getClusterId()); + if (clusterVsmMap == null) { + s_logger.error("Vmware cluster " + asaCluster.getName() + " has no Cisco Nexus VSM device associated with it"); + return false; + } + + CiscoNexusVSMDeviceVO vsmDevice = _vsmDeviceDao.findById(clusterVsmMap.getVsmId()); + if (vsmDevice == null) { + s_logger.error("Unable to load details of Cisco Nexus VSM device associated with cluster " + asaCluster.getName()); + return false; + } + + CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0); + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId()); + _hostDao.loadDetails(ciscoVnmcHost); + Account owner = context.getAccount(); + PublicIp sourceNatIp = _networkMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + String vlan = network.getBroadcastUri().getHost(); + long vlanId = Long.parseLong(vlan); + + List vlanVOList = _vlanDao.listVlansByPhysicalNetworkId(network.getPhysicalNetworkId()); + List publicGateways = new ArrayList(); + for (VlanVO vlanVO : vlanVOList) { + publicGateways.add(vlanVO.getVlanGateway()); + } + + // create logical edge firewall in VNMC + String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr()); + if (!createLogicalEdgeFirewall(vlanId, network.getGateway(), gatewayNetmask, + sourceNatIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) { + s_logger.error("Failed to create logical edge firewall in Cisco VNMC device for network " + network.getName()); + return false; + } + + // create stuff in VSM for ASA device + if (!configureNexusVsmForAsa(vlanId, network.getGateway(), + vsmDevice.getUserName(), vsmDevice.getPassword(), vsmDevice.getipaddr(), + assignedAsa.getInPortProfile(), ciscoVnmcHost.getId())) { + s_logger.error("Failed to configure Cisco Nexus VSM " + vsmDevice.getipaddr() + + " for ASA device for network " + network.getName()); + return false; + } + + // configure source NAT + //if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { + // s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); + // return false; + //} + + // associate Asa 1000v instance with logical edge firewall + if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) { + s_logger.error("Failed to associate Cisco ASA 1000v (" + assignedAsa.getManagementIp() + + ") with logical edge firewall in VNMC for network " + network.getName()); + return false; + } + + status = true; + txn.commit(); + } finally { + if (!status) { + txn.rollback(); + //FIXME: also undo changes in VNMC, VSM if anything failed + } + } + + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, + VirtualMachineProfile vm, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + if (vm.getType() != Type.User) { + return false; + } + + // ensure that there is an ASA 1000v assigned to this network + NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (asaForNetwork == null) { + return false; + } + + return true; + } + + @Override + public boolean release(Network network, NicProfile nic, + VirtualMachineProfile vm, + ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException { + return true; + } + + private boolean cleanupLogicalEdgeFirewall(long vlanId, long hostId) { + CleanupLogicalEdgeFirewallCommand cmd = new CleanupLogicalEdgeFirewallCommand(vlanId); + Answer answer = _agentMgr.easySend(hostId, cmd); + return answer.getResult(); + } + + @Override + public boolean shutdown(Network network, ReservationContext context, + boolean cleanup) throws ConcurrentOperationException, + ResourceUnavailableException { + + unassignAsa1000vFromNetwork(network); + + String vlan = network.getBroadcastUri().getHost(); + long vlanId = Long.parseLong(vlan); + List devices = _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (!devices.isEmpty()) { + CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0); + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId()); + cleanupLogicalEdgeFirewall(vlanId, ciscoVnmcHost.getId()); + } + + return true; + } + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean shutdownProviderInstances( + PhysicalNetworkServiceProvider provider, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + @Override + public boolean verifyServicesCombination(Set services) { + if (!services.contains(Service.Firewall)) { + s_logger.warn("CiscoVnmc must be used as Firewall Service Provider in the network"); + return false; + } + return true; + } + + @Override + public boolean destroy(Network network, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + cmdList.add(AddCiscoVnmcResourceCmd.class); + cmdList.add(DeleteCiscoVnmcResourceCmd.class); + cmdList.add(ListCiscoVnmcResourcesCmd.class); + cmdList.add(AddCiscoAsa1000vResourceCmd.class); + cmdList.add(DeleteCiscoAsa1000vResourceCmd.class); + cmdList.add(ListCiscoAsa1000vResourcesCmd.class); + return cmdList; + } + + @Override + public CiscoVnmcController addCiscoVnmcResource(AddCiscoVnmcResourceCmd cmd) { + String deviceName = Provider.CiscoVnmc.getName(); + NetworkDevice networkDevice = NetworkDevice.getNetworkDevice(deviceName); + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + CiscoVnmcController ciscoVnmcResource = null; + + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); + } + long zoneId = physicalNetwork.getDataCenterId(); + + PhysicalNetworkServiceProviderVO ntwkSvcProvider = _physicalNetworkServiceProviderDao.findByServiceProvider(physicalNetwork.getId(), networkDevice.getNetworkServiceProvder()); + if (ntwkSvcProvider == null) { + throw new CloudRuntimeException("Network Service Provider: " + networkDevice.getNetworkServiceProvder() + + " is not enabled in the physical network: " + physicalNetworkId + "to add this device"); + } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) { + throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() + + " is in shutdown state in the physical network: " + physicalNetworkId + "to add this device"); + } + + if (_ciscoVnmcDao.listByPhysicalNetwork(physicalNetworkId).size() != 0) { + throw new CloudRuntimeException("A Cisco Vnmc device is already configured on this physical network"); + } + + Map params = new HashMap(); + params.put("guid", UUID.randomUUID().toString()); + params.put("zoneId", String.valueOf(physicalNetwork.getDataCenterId())); + params.put("physicalNetworkId", String.valueOf(physicalNetwork.getId())); + params.put("name", "Cisco VNMC Controller - " + cmd.getHost()); + params.put("ip", cmd.getHost()); + params.put("username", cmd.getUsername()); + params.put("password", cmd.getPassword()); + params.put("transportzoneisotype", physicalNetwork.getIsolationMethods().get(0).toLowerCase()); // FIXME What to do with multiple isolation types + + Map hostdetails = new HashMap(); + hostdetails.putAll(params); + + ServerResource resource = new CiscoVnmcResource(); + Transaction txn = Transaction.currentTxn(); + try { + resource.configure(cmd.getHost(), hostdetails); + + Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, params); + if (host != null) { + txn.start(); + + ciscoVnmcResource = new CiscoVnmcControllerVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), deviceName); + _ciscoVnmcDao.persist((CiscoVnmcControllerVO)ciscoVnmcResource); + + DetailVO detail = new DetailVO(host.getId(), "deviceid", String.valueOf(ciscoVnmcResource.getId())); + _hostDetailsDao.persist(detail); + + txn.commit(); + return ciscoVnmcResource; + } else { + throw new CloudRuntimeException("Failed to add Cisco Vnmc device due to internal error."); + } + } catch (ConfigurationException e) { + txn.rollback(); + throw new CloudRuntimeException(e.getMessage()); + } + } + + @Override + public CiscoVnmcResourceResponse createCiscoVnmcResourceResponse( + CiscoVnmcController ciscoVnmcResourceVO) { + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcResourceVO.getHostId()); + + CiscoVnmcResourceResponse response = new CiscoVnmcResourceResponse(); + response.setId(ciscoVnmcResourceVO.getUuid()); + response.setPhysicalNetworkId(ciscoVnmcResourceVO.getPhysicalNetworkId()); + response.setProviderName(ciscoVnmcResourceVO.getProviderName()); + response.setResourceName(ciscoVnmcHost.getName()); + + return response; + } + + @Override + public boolean deleteCiscoVnmcResource(DeleteCiscoVnmcResourceCmd cmd) { + Long vnmcResourceId = cmd.getCiscoVnmcResourceId(); + CiscoVnmcControllerVO vnmcResource = _ciscoVnmcDao.findById(vnmcResourceId); + if (vnmcResource == null) { + throw new InvalidParameterValueException( + "Could not find a Cisco VNMC appliance with id " + vnmcResourceId); + } + + // Check if there any ASA 1000v appliances + Long physicalNetworkId = vnmcResource.getPhysicalNetworkId(); + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork != null) { + List responseList = _ciscoAsa1000vDao.listByPhysicalNetwork(physicalNetworkId); + if (responseList.size() > 0) { + throw new CloudRuntimeException( + "Cisco VNMC appliance with id " + vnmcResourceId + + " cannot be deleted as there Cisco ASA 1000v appliances using it"); + } + } + + HostVO vnmcHost = _hostDao.findById(vnmcResource.getHostId()); + Long hostId = vnmcHost.getId(); + vnmcHost.setResourceState(ResourceState.Maintenance); + _hostDao.update(hostId, vnmcHost); + _resourceMgr.deleteHost(hostId, false, false); + _ciscoVnmcDao.remove(vnmcResourceId); + + return true; + } + + @Override + public List listCiscoVnmcResources( + ListCiscoVnmcResourcesCmd cmd) { + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + Long ciscoVnmcResourceId = cmd.getCiscoVnmcResourceId(); + List responseList = new ArrayList(); + + if (physicalNetworkId == null && ciscoVnmcResourceId == null) { + throw new InvalidParameterValueException("Either physical network Id or vnmc device Id must be specified"); + } + + if (ciscoVnmcResourceId != null) { + CiscoVnmcControllerVO ciscoVnmcResource = _ciscoVnmcDao.findById(ciscoVnmcResourceId); + if (ciscoVnmcResource == null) { + throw new InvalidParameterValueException("Could not find Cisco Vnmc device with id: " + ciscoVnmcResource); + } + responseList.add(ciscoVnmcResource); + } + else { + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId); + } + responseList = _ciscoVnmcDao.listByPhysicalNetwork(physicalNetworkId); + } + + return responseList; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + @Override + public boolean applyFWRules(Network network, + List rules) + throws ResourceUnavailableException { + + if (!_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, Provider.CiscoVnmc)) { + s_logger.error("Firewall service is not provided by Cisco Vnmc device on network " + network.getName()); + return false; + } + + // Find VNMC host for physical network + List devices = _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No Cisco Vnmc device on network " + network.getName()); + return true; + } + + // Find if ASA 1000v is associated with network + NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (asaForNetwork == null) { + s_logger.debug("Cisco ASA 1000v device is not associated with network " + network.getName()); + return true; + } + + if (network.getState() == Network.State.Allocated) { + s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); + return true; + } + + CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0); + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId()); + + List rulesTO = new ArrayList(); + for (FirewallRule rule : rules) { + IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr(), rule.getPurpose(), rule.getTrafficType()); + rulesTO.add(ruleTO); + } + + if (!rulesTO.isEmpty()) { + SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, network.getBroadcastUri().getHost()); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, network.getCidr()); + Answer answer = _agentMgr.easySend(ciscoVnmcHost.getId(), cmd); + if (answer == null || !answer.getResult()) { + String details = (answer != null) ? answer.getDetails() : "details unavailable"; + String msg = "Unable to apply firewall rules to Cisco ASA 1000v appliance due to: " + details + "."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + } + + return true; + } + + @Override + public boolean applyPFRules(Network network, List rules) + throws ResourceUnavailableException { + + if (!_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.PortForwarding, Provider.CiscoVnmc)) { + s_logger.error("Port forwarding service is not provided by Cisco Vnmc device on network " + network.getName()); + return false; + } + + // Find VNMC host for physical network + List devices = _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No Cisco Vnmc device on network " + network.getName()); + return true; + } + + // Find if ASA 1000v is associated with network + NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (asaForNetwork == null) { + s_logger.debug("Cisco ASA 1000v device is not associated with network " + network.getName()); + return true; + } + + if (network.getState() == Network.State.Allocated) { + s_logger.debug("External firewall was asked to apply port forwarding rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); + return true; + } + + CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0); + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId()); + + List rulesTO = new ArrayList(); + for (PortForwardingRule rule : rules) { + IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); + Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); + PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); + rulesTO.add(ruleTO); + } + + if (!rulesTO.isEmpty()) { + SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(rulesTO); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, network.getBroadcastUri().getHost()); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, network.getCidr()); + Answer answer = _agentMgr.easySend(ciscoVnmcHost.getId(), cmd); + if (answer == null || !answer.getResult()) { + String details = (answer != null) ? answer.getDetails() : "details unavailable"; + String msg = "Unable to apply port forwarding rules to Cisco ASA 1000v appliance due to: " + details + "."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + } + + return true; + } + + @Override + public boolean applyStaticNats(Network network, + List rules) + throws ResourceUnavailableException { + if (!_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.StaticNat, Provider.CiscoVnmc)) { + s_logger.error("Static NAT service is not provided by Cisco Vnmc device on network " + network.getName()); + return false; + } + + // Find VNMC host for physical network + List devices = _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No Cisco Vnmc device on network " + network.getName()); + return true; + } + + // Find if ASA 1000v is associated with network + NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (asaForNetwork == null) { + s_logger.debug("Cisco ASA 1000v device is not associated with network " + network.getName()); + return true; + } + + if (network.getState() == Network.State.Allocated) { + s_logger.debug("External firewall was asked to apply static NAT rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); + return true; + } + + CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0); + HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId()); + + List rulesTO = new ArrayList(); + for (StaticNat rule : rules) { + IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(0, sourceIp.getAddress().addr(), null, + null, rule.getDestIpAddress(), null, null, null, rule.isForRevoke(), false); + rulesTO.add(ruleTO); + } + + if (!rulesTO.isEmpty()) { + SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rulesTO, null); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, network.getBroadcastUri().getHost()); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, network.getCidr()); + Answer answer = _agentMgr.easySend(ciscoVnmcHost.getId(), cmd); + if (answer == null || !answer.getResult()) { + String details = (answer != null) ? answer.getDetails() : "details unavailable"; + String msg = "Unable to apply static NAT rules to Cisco ASA 1000v appliance due to: " + details + "."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + } + + return true; + } + + @Override + public boolean applyIps(Network network, + List ipAddress, Set services) + throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, + StartupCommand[] cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, + StartupCommand[] startup, ServerResource resource, + Map details, List hostTags) { + if (!(startup[0] instanceof StartupExternalFirewallCommand)) { + return null; + } + host.setType(Host.Type.ExternalFirewall); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, + boolean isForceDeleteStorage) throws UnableDeleteHostException { + if (host.getType() != com.cloud.host.Host.Type.ExternalFirewall) { + return null; + } + return new DeleteHostAnswer(true); + } + + @Override + public CiscoAsa1000vDevice addCiscoAsa1000vResource( + AddCiscoAsa1000vResourceCmd cmd) { + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + CiscoAsa1000vDevice ciscoAsa1000vResource = null; + + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); + } + + ciscoAsa1000vResource = new CiscoAsa1000vDeviceVO(physicalNetworkId, cmd.getManagementIp(), cmd.getInPortProfile(), cmd.getClusterId()); + _ciscoAsa1000vDao.persist((CiscoAsa1000vDeviceVO)ciscoAsa1000vResource); + + return ciscoAsa1000vResource; + } + + @Override + public CiscoAsa1000vResourceResponse createCiscoAsa1000vResourceResponse( + CiscoAsa1000vDevice ciscoAsa1000vDeviceVO) { + CiscoAsa1000vResourceResponse response = new CiscoAsa1000vResourceResponse(); + response.setId(ciscoAsa1000vDeviceVO.getUuid()); + response.setManagementIp(ciscoAsa1000vDeviceVO.getManagementIp()); + response.setInPortProfile(ciscoAsa1000vDeviceVO.getInPortProfile()); + + NetworkAsa1000vMapVO networkAsaMap = _networkAsa1000vMapDao.findByAsa1000vId(ciscoAsa1000vDeviceVO.getId()); + if (networkAsaMap != null) { + response.setGuestNetworkId(networkAsaMap.getNetworkId()); + } + + return response; + } + + @Override + public boolean deleteCiscoAsa1000vResource( + DeleteCiscoAsa1000vResourceCmd cmd) { + Long asaResourceId = cmd.getCiscoAsa1000vResourceId(); + CiscoAsa1000vDeviceVO asaResource = _ciscoAsa1000vDao.findById(asaResourceId); + if (asaResource == null) { + throw new InvalidParameterValueException( + "Could not find a Cisco ASA 1000v appliance with id " + asaResourceId); + } + + NetworkAsa1000vMapVO networkAsaMap = _networkAsa1000vMapDao.findByAsa1000vId(asaResource.getId()); + if (networkAsaMap != null) { + throw new CloudRuntimeException( + "Cisco ASA 1000v appliance with id " + asaResourceId + + " cannot be deleted as it is associated with guest network"); + } + + _ciscoAsa1000vDao.remove(asaResourceId); + + return true; + } + + @Override + public List listCiscoAsa1000vResources( + ListCiscoAsa1000vResourcesCmd cmd) { + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + Long ciscoAsa1000vResourceId = cmd.getCiscoAsa1000vResourceId(); + List responseList = new ArrayList(); + + if (physicalNetworkId == null && ciscoAsa1000vResourceId == null) { + throw new InvalidParameterValueException("Either physical network Id or Asa 1000v device Id must be specified"); + } + + if (ciscoAsa1000vResourceId != null) { + CiscoAsa1000vDeviceVO ciscoAsa1000vResource = _ciscoAsa1000vDao.findById(ciscoAsa1000vResourceId); + if (ciscoAsa1000vResource == null) { + throw new InvalidParameterValueException("Could not find Cisco Asa 1000v device with id: " + ciscoAsa1000vResourceId); + } + responseList.add(ciscoAsa1000vResource); + } else { + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId); + } + responseList = _ciscoAsa1000vDao.listByPhysicalNetwork(physicalNetworkId); + } + + return responseList; + } + + @Override + public CiscoAsa1000vDevice assignAsa1000vToNetwork(Network network) { + List asaList = _ciscoAsa1000vDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + for (CiscoAsa1000vDeviceVO asa : asaList) { + NetworkAsa1000vMapVO assignedToNetwork = _networkAsa1000vMapDao.findByAsa1000vId(asa.getId()); + if (assignedToNetwork == null) { + NetworkAsa1000vMapVO networkAsaMap = new NetworkAsa1000vMapVO(network.getId(), asa.getId()); + _networkAsa1000vMapDao.persist(networkAsaMap); + return asa; + } + } + return null; + } + + private void unassignAsa1000vFromNetwork(Network network) { + NetworkAsa1000vMapVO networkAsaMap = _networkAsa1000vMapDao.findByNetworkId(network.getId()); + if (networkAsaMap != null) { + _networkAsa1000vMapDao.remove(networkAsaMap.getId()); + } + } +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElementService.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElementService.java new file mode 100644 index 00000000000..e8eb473154a --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElementService.java @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.element; + +import java.util.List; + +import com.cloud.api.commands.AddCiscoVnmcResourceCmd; +import com.cloud.api.commands.DeleteCiscoVnmcResourceCmd; +import com.cloud.api.commands.ListCiscoVnmcResourcesCmd; +import com.cloud.api.response.CiscoVnmcResourceResponse; +import com.cloud.network.cisco.CiscoVnmcController; +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.utils.component.PluggableService; + +public interface CiscoVnmcElementService extends PluggableService { + + //public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); + + public CiscoVnmcController addCiscoVnmcResource(AddCiscoVnmcResourceCmd cmd); + + public CiscoVnmcResourceResponse createCiscoVnmcResourceResponse( + CiscoVnmcController CiscoVnmcResourceVO); + + boolean deleteCiscoVnmcResource(DeleteCiscoVnmcResourceCmd cmd); + + List listCiscoVnmcResources(ListCiscoVnmcResourcesCmd cmd); + +} diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java new file mode 100644 index 00000000000..91559782304 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java @@ -0,0 +1,780 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.resource; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AssociateAsaWithLogicalEdgeFirewallCommand; +import com.cloud.agent.api.CleanupLogicalEdgeFirewallCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ConfigureNexusVsmForAsaCommand; +import com.cloud.agent.api.CreateLogicalEdgeFirewallCommand; +import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; +import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; +import com.cloud.agent.api.MaintainAnswer; +import com.cloud.agent.api.MaintainCommand; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupExternalFirewallCommand; +import com.cloud.agent.api.routing.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.to.FirewallRuleTO; +import com.cloud.agent.api.to.PortForwardingRuleTO; +import com.cloud.agent.api.to.StaticNatRuleTO; +import com.cloud.host.Host; +import com.cloud.network.cisco.CiscoVnmcConnectionImpl; +import com.cloud.network.rules.FirewallRule.TrafficType; +import com.cloud.resource.ServerResource; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper; +import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.OperationType; +import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode; +import com.cloud.utils.exception.ExecutionException; +import com.cloud.utils.net.NetUtils; + +public class CiscoVnmcResource implements ServerResource { + + private String _name; + private String _zoneId; + private String _physicalNetworkId; + private String _ip; + private String _username; + private String _password; + private String _guid; + private Integer _numRetries; + + private CiscoVnmcConnectionImpl _connection; + + public void setConnection(CiscoVnmcConnectionImpl connection) { + this._connection = connection; + } + + private final Logger s_logger = Logger.getLogger(CiscoVnmcResource.class); + + public Answer executeRequest(Command cmd) { + if (cmd instanceof ReadyCommand) { + return execute((ReadyCommand) cmd); + } else if (cmd instanceof MaintainCommand) { + return execute((MaintainCommand) cmd); + } else if (cmd instanceof IpAssocCommand) { + return execute((IpAssocCommand) cmd); + } else if (cmd instanceof SetSourceNatCommand) { + return execute((SetSourceNatCommand) cmd); + } else if (cmd instanceof SetFirewallRulesCommand) { + return execute((SetFirewallRulesCommand) cmd); + } else if (cmd instanceof SetStaticNatRulesCommand) { + return execute((SetStaticNatRulesCommand) cmd); + } else if (cmd instanceof SetPortForwardingRulesCommand) { + return execute((SetPortForwardingRulesCommand) cmd); + } else if (cmd instanceof ExternalNetworkResourceUsageCommand) { + return execute((ExternalNetworkResourceUsageCommand) cmd); + } else if (cmd instanceof CreateLogicalEdgeFirewallCommand) { + return execute((CreateLogicalEdgeFirewallCommand)cmd); + } else if (cmd instanceof CleanupLogicalEdgeFirewallCommand) { + return execute((CleanupLogicalEdgeFirewallCommand)cmd); + } else if (cmd instanceof ConfigureNexusVsmForAsaCommand) { + return execute((ConfigureNexusVsmForAsaCommand)cmd); + } else if (cmd instanceof AssociateAsaWithLogicalEdgeFirewallCommand) { + return execute((AssociateAsaWithLogicalEdgeFirewallCommand)cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } + } + + public boolean configure(String name, Map params) throws ConfigurationException { + try { + _name = (String) params.get("name"); + if (_name == null) { + throw new ConfigurationException("Unable to find name"); + } + + _zoneId = (String) params.get("zoneId"); + if (_zoneId == null) { + throw new ConfigurationException("Unable to find zone"); + } + + _physicalNetworkId = (String) params.get("physicalNetworkId"); + if (_physicalNetworkId == null) { + throw new ConfigurationException("Unable to find physical network id in the configuration parameters"); + } + + _ip = (String) params.get("ip"); + if (_ip == null) { + throw new ConfigurationException("Unable to find IP"); + } + + _username = (String) params.get("username"); + if (_username == null) { + throw new ConfigurationException("Unable to find username"); + } + + _password = (String) params.get("password"); + if (_password == null) { + throw new ConfigurationException("Unable to find password"); + } + + _guid = (String)params.get("guid"); + if (_guid == null) { + throw new ConfigurationException("Unable to find the guid"); + } + + _numRetries = NumbersUtil.parseInt((String) params.get("numretries"), 1); + + NumbersUtil.parseInt((String) params.get("timeout"), 300); + + // Open a socket and login + _connection = new CiscoVnmcConnectionImpl(_ip, _username, _password); + //if (!refreshVnmcConnection()) { + // throw new ConfigurationException("Unable to open a connection to the VNMC."); + //} + + return true; + } catch (Exception e) { + throw new ConfigurationException(e.getMessage()); + } + + } + + public StartupCommand[] initialize() { + StartupExternalFirewallCommand cmd = new StartupExternalFirewallCommand(); + cmd.setName(_name); + cmd.setDataCenter(_zoneId); + cmd.setPod(""); + cmd.setPrivateIpAddress(_ip); + cmd.setStorageIpAddress(""); + cmd.setVersion(""); + cmd.setGuid(_guid); + return new StartupCommand[] { cmd }; + } + + public Host.Type getType() { + return Host.Type.ExternalFirewall; + } + + @Override + public String getName() { + return _name; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public PingCommand getCurrentStatus(final long id) { + if (!refreshVnmcConnection()) { + return null; + } + return new PingCommand(Host.Type.ExternalFirewall, id); + } + + @Override + public void disconnected() { + } + + public IAgentControl getAgentControl() { + return null; + } + + public void setAgentControl(IAgentControl agentControl) { + return; + } + + private Answer execute(ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + private Answer execute(MaintainCommand cmd) { + return new MaintainAnswer(cmd); + } + + private ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) { + return new ExternalNetworkResourceUsageAnswer(cmd); + } + + /* + * Login + */ + private boolean refreshVnmcConnection() { + boolean ret = false; + try { + ret = _connection.login(); + } catch (ExecutionException ex) { + s_logger.error("Login to Vnmc failed", ex); + } + return ret; + } + + private synchronized Answer execute(IpAssocCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(IpAssocCommand cmd, int numRetries) { + String[] results = new String[cmd.getIpAddresses().length]; + return new IpAssocAnswer(cmd, results); + } + + private String[] getIpRangeFromCidr(String cidr) { + String[] result = new String[2]; + String[] cidrData = cidr.split("\\/"); + assert (cidrData.length == 2) : "Something is wrong with source cidr " + cidr; + long size = Long.valueOf(cidrData[1]); + result[0] = cidrData[0]; + result[1] = cidrData[0]; + if (size < 32) { + result[0] = NetUtils.getIpRangeStartIpFromCidr(cidrData[0], size); + result[1] = NetUtils.getIpRangeEndIpFromCidr(cidrData[0], size); + } + return result; + } + + /* + * Source NAT + */ + private synchronized Answer execute(SetSourceNatCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(SetSourceNatCommand cmd, int numRetries) { + String vlanId = cmd.getContextParam(NetworkElementCommand.GUEST_VLAN_TAG); + String tenant = "vlan-" + vlanId; + String policyIdentifier = cmd.getIpAddress().getPublicIp().replace('.', '-'); + try { + if (!_connection.createTenantVDCNatPolicySet(tenant)) { + throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCSourceNatPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create source NAT policy in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCSourceNatPolicyRef(tenant, policyIdentifier)) { + throw new Exception("Failed to associate source NAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCSourceNatIpPool(tenant, policyIdentifier, cmd.getIpAddress().getPublicIp())) { + throw new Exception("Failed to create source NAT ip pool in VNMC for guest network with vlan " + vlanId); + } + + String[] ipRange = getIpRangeFromCidr(cmd.getContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR)); + if (!_connection.createTenantVDCSourceNatRule(tenant, policyIdentifier, ipRange[0], ipRange[1])) { + throw new Exception("Failed to create source NAT rule in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.associateNatPolicySet(tenant)) { + throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + } + } catch (Throwable e) { + String msg = "SetSourceNatCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Firewall rule + */ + private synchronized Answer execute(SetFirewallRulesCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(SetFirewallRulesCommand cmd, int numRetries) { + String vlanId = cmd.getContextParam(NetworkElementCommand.GUEST_VLAN_TAG); + String tenant = "vlan-" + vlanId; + + FirewallRuleTO[] rules = cmd.getRules(); + Map> publicIpRulesMap = new HashMap>(); + for (FirewallRuleTO rule : rules) { + String publicIp = rule.getSrcIp(); + if (!publicIpRulesMap.containsKey(publicIp)) { + List publicIpRulesList = new ArrayList(); + publicIpRulesMap.put(publicIp, publicIpRulesList); + } + publicIpRulesMap.get(publicIp).add(rule); + } + + try { + if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { + throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { + throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (String publicIp : publicIpRulesMap.keySet()) { + String policyIdentifier = publicIp.replace('.', '-'); + + if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { + throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { + throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (FirewallRuleTO rule : publicIpRulesMap.get(publicIp)) { + if (rule.revoked()) { + if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { + throw new Exception("Failed to delete ACL rule in VNMC for guest network with vlan " + vlanId); + } + } else { + String[] externalIpRange = getIpRangeFromCidr(rule.getSourceCidrList().get(0)); + if (rule.getTrafficType() == TrafficType.Ingress) { + if (!rule.getProtocol().equalsIgnoreCase("icmp")) { + if (!_connection.createTenantVDCIngressAclRule(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp)) { + throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); + } + } else { + if (!_connection.createTenantVDCIngressAclRule(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], publicIp)) { + throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); + } + } + } else { + if (!rule.getProtocol().equalsIgnoreCase("icmp")) { + if (!_connection.createTenantVDCEgressAclRule(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp, + externalIpRange[0], externalIpRange[1])) { + throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); + } + } else { + if (!_connection.createTenantVDCEgressAclRule(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), publicIp, externalIpRange[0], externalIpRange[1])) { + throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); + } + } + } + } + } + } + + if (!_connection.associateAclPolicySet(tenant)) { + throw new Exception("Failed to associate ACL policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + } + } catch (Throwable e) { + String msg = "SetFirewallRulesCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Static NAT + */ + private synchronized Answer execute(SetStaticNatRulesCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) { + String vlanId = cmd.getContextParam(NetworkElementCommand.GUEST_VLAN_TAG); + String tenant = "vlan-" + vlanId; + + StaticNatRuleTO[] rules = cmd.getRules(); + Map> publicIpRulesMap = new HashMap>(); + for (StaticNatRuleTO rule : rules) { + String publicIp = rule.getSrcIp(); + if (!publicIpRulesMap.containsKey(publicIp)) { + List publicIpRulesList = new ArrayList(); + publicIpRulesMap.put(publicIp, publicIpRulesList); + } + publicIpRulesMap.get(publicIp).add(rule); + } + + try { + if (!_connection.createTenantVDCNatPolicySet(tenant)) { + throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { + throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { + throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (String publicIp : publicIpRulesMap.keySet()) { + String policyIdentifier = publicIp.replace('.', '-'); + + if (!_connection.createTenantVDCDNatPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create DNAT policy in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCDNatPolicyRef(tenant, policyIdentifier)) { + throw new Exception("Failed to associate DNAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { + throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { + throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (StaticNatRuleTO rule : publicIpRulesMap.get(publicIp)) { + if (rule.revoked()) { + if (!_connection.deleteTenantVDCDNatRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { + throw new Exception("Failed to delete DNAT rule in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { + throw new Exception("Failed to delete ACL ingress rule for DNAT in VNMC for guest network with vlan " + vlanId); + } + } else { + if (!_connection.createTenantVDCDNatIpPool(tenant, policyIdentifier + "-" + rule.getId(), rule.getDstIp())) { + throw new Exception("Failed to create DNAT ip pool in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCDNatRule(tenant, + Long.toString(rule.getId()), policyIdentifier, rule.getSrcIp())) { + throw new Exception("Failed to create DNAT rule in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclRuleForDNat(tenant, + Long.toString(rule.getId()), policyIdentifier, rule.getDstIp())) { + throw new Exception("Failed to create ACL rule for DNAT in VNMC for guest network with vlan " + vlanId); + } + } + } + } + + if (!_connection.associateAclPolicySet(tenant)) { + throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + } + } catch (Throwable e) { + String msg = "SetSourceNatCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Destination NAT + */ + private synchronized Answer execute(SetPortForwardingRulesCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) { + String vlanId = cmd.getContextParam(NetworkElementCommand.GUEST_VLAN_TAG); + String tenant = "vlan-" + vlanId; + + PortForwardingRuleTO[] rules = cmd.getRules(); + Map> publicIpRulesMap = new HashMap>(); + for (PortForwardingRuleTO rule : rules) { + String publicIp = rule.getSrcIp(); + if (!publicIpRulesMap.containsKey(publicIp)) { + List publicIpRulesList = new ArrayList(); + publicIpRulesMap.put(publicIp, publicIpRulesList); + } + publicIpRulesMap.get(publicIp).add(rule); + } + + try { + if (!_connection.createTenantVDCNatPolicySet(tenant)) { + throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { + throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { + throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (String publicIp : publicIpRulesMap.keySet()) { + String policyIdentifier = publicIp.replace('.', '-'); + + if (!_connection.createTenantVDCPFPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create PF policy in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCPFPolicyRef(tenant, policyIdentifier)) { + throw new Exception("Failed to associate PF policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { + throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { + throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { + throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + } + + for (PortForwardingRuleTO rule : publicIpRulesMap.get(publicIp)) { + if (rule.revoked()) { + if (!_connection.deleteTenantVDCPFRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { + throw new Exception("Failed to delete PF rule in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { + throw new Exception("Failed to delete ACL ingress rule for PF in VNMC for guest network with vlan " + vlanId); + } + } else { + if (!_connection.createTenantVDCPFIpPool(tenant, policyIdentifier + "-" + rule.getId(), rule.getDstIp())) { + throw new Exception("Failed to create PF ip pool in VNMC for guest network with vlan " + vlanId); + } + if (!_connection.createTenantVDCPFPortPool(tenant, policyIdentifier + "-" + rule.getId(), + Integer.toString(rule.getDstPortRange()[0]), Integer.toString(rule.getDstPortRange()[1]))) { + throw new Exception("Failed to create PF port pool in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCPFRule(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), rule.getSrcIp(), + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { + throw new Exception("Failed to create PF rule in VNMC for guest network with vlan " + vlanId); + } + + if (!_connection.createTenantVDCAclRuleForPF(tenant, + Long.toString(rule.getId()), policyIdentifier, + rule.getProtocol().toUpperCase(), rule.getDstIp(), + Integer.toString(rule.getDstPortRange()[0]), Integer.toString(rule.getDstPortRange()[1]))) { + throw new Exception("Failed to create ACL rule for PF in VNMC for guest network with vlan " + vlanId); + } + } + } + } + + if (!_connection.associateAclPolicySet(tenant)) { + throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + } + } catch (Throwable e) { + String msg = "SetSourceNatCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Logical edge firewall + */ + private synchronized Answer execute(CreateLogicalEdgeFirewallCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private void createEdgeDeviceProfile(String tenant, List gateways, Long vlanId) throws Exception { + // create edge device profile + if (!_connection.createTenantVDCEdgeDeviceProfile(tenant)) + throw new Exception("Failed to create tenant edge device profile in VNMC for guest network with vlan " + vlanId); + + // create edge static route policy + if (!_connection.createTenantVDCEdgeStaticRoutePolicy(tenant)) + throw new Exception("Failed to create tenant edge static route policy in VNMC for guest network with vlan " + vlanId); + + // create edge static route for all gateways + for (String gateway : gateways) { + if (!_connection.createTenantVDCEdgeStaticRoute(tenant, gateway, "0.0.0.0", "0.0.0.0")) + throw new Exception("Failed to create tenant edge static route in VNMC for guest network with vlan " + vlanId); + } + + // associate edge + if (!_connection.associateTenantVDCEdgeStaticRoutePolicy(tenant)) + throw new Exception("Failed to associate edge static route policy with edge device profile in VNMC for guest network with vlan " + vlanId); + } + + private Answer execute(CreateLogicalEdgeFirewallCommand cmd, int numRetries) { + String tenant = "vlan-" + cmd.getVlanId(); + try { + // create tenant + if (!_connection.createTenant(tenant)) + throw new Exception("Failed to create tenant in VNMC for guest network with vlan " + cmd.getVlanId()); + + // create tenant VDC + if (!_connection.createTenantVDC(tenant)) + throw new Exception("Failed to create tenant VDC in VNMC for guest network with vlan " + cmd.getVlanId()); + + // create edge security profile + if (!_connection.createTenantVDCEdgeSecurityProfile(tenant)) + throw new Exception("Failed to create tenant edge security profile in VNMC for guest network with vlan " + cmd.getVlanId()); + + // create edge device profile and associated route + createEdgeDeviceProfile(tenant, cmd.getPublicGateways(), cmd.getVlanId()); + + // create logical edge firewall + if (!_connection.createEdgeFirewall(tenant, cmd.getPublicIp(), cmd.getInternalIp(), cmd.getPublicSubnet(), cmd.getInternalSubnet())) + throw new Exception("Failed to create edge firewall in VNMC for guest network with vlan " + cmd.getVlanId()); + } catch (Throwable e) { + String msg = "CreateLogicalEdgeFirewallCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Create vservice node and update inside port profile for ASA appliance in VSM + */ + private synchronized Answer execute(ConfigureNexusVsmForAsaCommand cmd) { + return execute(cmd, _numRetries); + } + + private Answer execute(ConfigureNexusVsmForAsaCommand cmd, int numRetries) { + String vlanId = Long.toString(cmd.getVlanId()); + NetconfHelper helper = null; + List> params = new ArrayList>(); + params.add(new Pair(OperationType.addvlanid, vlanId)); + try { + helper = new NetconfHelper(cmd.getVsmIp(), cmd.getVsmUsername(), cmd.getVsmPassword()); + s_logger.debug("Connected to Cisco VSM " + cmd.getVsmIp()); + helper.addVServiceNode(vlanId, cmd.getIpAddress()); + s_logger.debug("Created vservice node for ASA appliance in Cisco VSM for vlan " + vlanId); + helper.updatePortProfile(cmd.getAsaInPortProfile(), SwitchPortMode.access, params); + s_logger.debug("Updated inside port profile for ASA appliance in Cisco VSM with new vlan " + vlanId); + } catch (Throwable e) { + String msg = "ConfigureVSMForASACommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } finally { + helper.disconnect(); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Associates ASA 1000v with logical edge firewall in VNMC + */ + private synchronized Answer execute(AssociateAsaWithLogicalEdgeFirewallCommand cmd) { + return execute(cmd, _numRetries); + } + + private Answer execute(AssociateAsaWithLogicalEdgeFirewallCommand cmd, int numRetries) { + String tenant = "vlan-" + cmd.getVlanId(); + try { + Map availableAsaAppliances = _connection.listUnAssocAsa1000v(); + if (availableAsaAppliances.isEmpty()) { + throw new Exception("No ASA 1000v available to associate with logical edge firewall for guest vlan " + cmd.getVlanId()); + } + + String asaInstanceDn = availableAsaAppliances.get(cmd.getAsaMgmtIp()); + if (asaInstanceDn == null) { + throw new Exception("Requested ASA 1000v (" + cmd.getAsaMgmtIp() + ") is not available"); + } + + if (!_connection.assignAsa1000v(tenant, asaInstanceDn)) { + throw new Exception("Failed to associate ASA 1000v (" + cmd.getAsaMgmtIp() + ") with logical edge firewall for guest vlan " + cmd.getVlanId()); + } + } catch (Throwable e) { + String msg = "AssociateAsaWithLogicalEdgeFirewallCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + /* + * Cleanup + */ + private synchronized Answer execute(CleanupLogicalEdgeFirewallCommand cmd) { + refreshVnmcConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(CleanupLogicalEdgeFirewallCommand cmd, int numRetries) { + String tenant = "vlan-" + cmd.getVlanId(); + try { + _connection.deleteTenant(tenant); + } catch (Throwable e) { + String msg = "CleanupLogicalEdgeFirewallCommand failed due to " + e.getMessage(); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); + } + + return new Answer(cmd, true, "Success"); + } + + @Override + public void setName(String name) { + // TODO Auto-generated method stub + } + + @Override + public void setConfigParams(Map params) { + // TODO Auto-generated method stub + } + + @Override + public Map getConfigParams() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getRunLevel() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void setRunLevel(int level) { + // TODO Auto-generated method stub + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java b/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java new file mode 100644 index 00000000000..52f0ea66f50 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java @@ -0,0 +1,232 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * 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 software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.httpclient.contrib.ssl; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; + +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.HttpClientError; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + *

+ * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s + * that accept self-signed certificates. + *

+ *

+ * This socket factory SHOULD NOT be used for productive systems + * due to security reasons, unless it is a concious decision and + * you are perfectly aware of security implications of accepting + * self-signed certificates + *

+ * + *

+ * Example of using custom protocol socket factory for a specific host: + *

+ *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ *
+ *     URI uri = new URI("https://localhost/", true);
+ *     // use relative url only
+ *     GetMethod httpget = new GetMethod(uri.getPathQuery());
+ *     HostConfiguration hc = new HostConfiguration();
+ *     hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
+ *     HttpClient client = new HttpClient();
+ *     client.executeMethod(hc, httpget);
+ *     
+ *

+ *

+ * Example of using custom protocol socket factory per default instead of the standard one: + *

+ *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ *     Protocol.registerProtocol("https", easyhttps);
+ *
+ *     HttpClient client = new HttpClient();
+ *     GetMethod httpget = new GetMethod("https://localhost/");
+ *     client.executeMethod(httpget);
+ *     
+ *

+ * + * @author Oleg Kalnichevski + * + *

+ * DISCLAIMER: HttpClient developers DO NOT actively support this component. + * The component is provided as a reference material, which may be inappropriate + * for use without additional customization. + *

+ */ + +public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); + + private SSLContext sslcontext = null; + + /** + * Constructor for EasySSLProtocolSocketFactory. + */ + public EasySSLProtocolSocketFactory() { + super(); + } + + private static SSLContext createEasySSLContext() { + try { + SSLContext context = SSLContext.getInstance("SSL"); + context.init( + null, + new TrustManager[] {new EasyX509TrustManager(null)}, + null); + return context; + } catch (Exception e) { + LOG.error(e.getMessage(), e); + throw new HttpClientError(e.toString()); + } + } + + private SSLContext getSSLContext() { + if (this.sslcontext == null) { + this.sslcontext = createEasySSLContext(); + } + return this.sslcontext; + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) + */ + public Socket createSocket( + String host, + int port, + InetAddress clientHost, + int clientPort) + throws IOException, UnknownHostException { + + return getSSLContext().getSocketFactory().createSocket( + host, + port, + clientHost, + clientPort + ); + } + + /** + * Attempts to get a new socket connection to the given host within the given time limit. + *

+ * To circumvent the limitations of older JREs that do not support connect timeout a + * controller thread is executed. The controller thread attempts to create a new socket + * within the given limit of time. If socket constructor does not return until the + * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} + *

+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort the port on the local machine + * @param params {@link HttpConnectionParams Http connection parameters} + * + * @return Socket a new socket + * + * @throws IOException if an I/O error occurs while creating the socket + * @throws UnknownHostException if the IP address of the host cannot be + * determined + */ + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + SocketFactory socketfactory = getSSLContext().getSocketFactory(); + if (timeout == 0) { + return socketfactory.createSocket(host, port, localAddress, localPort); + } else { + Socket socket = socketfactory.createSocket(); + SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); + SocketAddress remoteaddr = new InetSocketAddress(host, port); + socket.bind(localaddr); + socket.connect(remoteaddr, timeout); + return socket; + } + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) + */ + public Socket createSocket(String host, int port) + throws IOException, UnknownHostException { + return getSSLContext().getSocketFactory().createSocket( + host, + port + ); + } + + /** + * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) + */ + public Socket createSocket( + Socket socket, + String host, + int port, + boolean autoClose) + throws IOException, UnknownHostException { + return getSSLContext().getSocketFactory().createSocket( + socket, + host, + port, + autoClose + ); + } + + public boolean equals(Object obj) { + return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); + } + + public int hashCode() { + return EasySSLProtocolSocketFactory.class.hashCode(); + } + +} diff --git a/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java b/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java new file mode 100644 index 00000000000..ae9f9380b31 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/src/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java @@ -0,0 +1,114 @@ +/* + * ==================================================================== + * + * 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 software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.httpclient.contrib.ssl; + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + *

+ * EasyX509TrustManager unlike default {@link X509TrustManager} accepts + * self-signed certificates. + *

+ *

+ * This trust manager SHOULD NOT be used for productive systems + * due to security reasons, unless it is a concious decision and + * you are perfectly aware of security implications of accepting + * self-signed certificates + *

+ * + * @author Adrian Sutton + * @author Oleg Kalnichevski + * + *

+ * DISCLAIMER: HttpClient developers DO NOT actively support this component. + * The component is provided as a reference material, which may be inappropriate + * for use without additional customization. + *

+ */ + +public class EasyX509TrustManager implements X509TrustManager +{ + private X509TrustManager standardTrustManager = null; + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(EasyX509TrustManager.class); + + /** + * Constructor for EasyX509TrustManager. + */ + public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException { + super(); + TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + factory.init(keystore); + TrustManager[] trustmanagers = factory.getTrustManagers(); + if (trustmanagers.length == 0) { + throw new NoSuchAlgorithmException("no trust manager found"); + } + this.standardTrustManager = (X509TrustManager)trustmanagers[0]; + } + + /** + * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) + */ + public void checkClientTrusted(X509Certificate[] certificates,String authType) throws CertificateException { + standardTrustManager.checkClientTrusted(certificates,authType); + } + + /** + * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) + */ + public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException { + if ((certificates != null) && LOG.isDebugEnabled()) { + LOG.debug("Server certificate chain:"); + for (int i = 0; i < certificates.length; i++) { + LOG.debug("X509Certificate[" + i + "]=" + certificates[i]); + } + } + if ((certificates != null) && (certificates.length == 1)) { + certificates[0].checkValidity(); + } else { + standardTrustManager.checkServerTrusted(certificates,authType); + } + } + + /** + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + public X509Certificate[] getAcceptedIssuers() { + return this.standardTrustManager.getAcceptedIssuers(); + } +} diff --git a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/cisco/CiscoVnmcConnectionTest.java b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/cisco/CiscoVnmcConnectionTest.java new file mode 100644 index 00000000000..bf52356779e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/cisco/CiscoVnmcConnectionTest.java @@ -0,0 +1,248 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.cisco; + +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import com.cloud.network.cisco.CiscoVnmcConnectionImpl; +import com.cloud.utils.exception.ExecutionException; + + +@Ignore("Requires actual VNMC to connect to") +public class CiscoVnmcConnectionTest { + static CiscoVnmcConnectionImpl connection; + static String tenantName = "TenantE"; + static Map fwDns = null; + + @BeforeClass + public static void setUpClass() throws Exception { + connection = new CiscoVnmcConnectionImpl("10.223.56.5", "admin", "C1sco123"); + try { + boolean response = connection.login(); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + @Test + public void testLogin() { + //fail("Not yet implemented"); + try { + boolean response = connection.login(); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + @Test + public void testCreateTenant() { + //fail("Not yet implemented"); + try { + boolean response = connection.createTenant(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDC() { + //fail("Not yet implemented"); + try { + boolean response = connection.createTenantVDC(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCEdgeDeviceProfile() { + //fail("Not yet implemented"); + try { + boolean response = connection.createTenantVDCEdgeDeviceProfile(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCEdgeDeviceRoutePolicy() { + try { + boolean response = connection.createTenantVDCEdgeStaticRoutePolicy(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCEdgeDeviceRoute() { + try { + boolean response = connection.createTenantVDCEdgeStaticRoute(tenantName, + "10.223.136.1", "0.0.0.0", "0.0.0.0"); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testAssociateRoutePolicyWithEdgeProfile() { + try { + boolean response = connection.associateTenantVDCEdgeStaticRoutePolicy(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testAssociateTenantVDCEdgeDhcpPolicy() { + try { + boolean response = connection.associateTenantVDCEdgeDhcpPolicy(tenantName, "Edge_Inside"); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCEdgeDhcpPolicy() { + try { + boolean response = connection.createTenantVDCEdgeDhcpPolicy(tenantName, + "10.1.1.2", "10.1.1.254", "255.255.255.0","4.4.4.4", tenantName+ ".net"); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCEdgeSecurityProfile() { + try { + boolean response = connection.createTenantVDCEdgeSecurityProfile(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCSourceNatIpPool() { + try { + boolean response = connection.createTenantVDCSourceNatIpPool(tenantName, "1", "10.223.136.10"); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCSourceNatPolicy() { + try { + boolean response = connection.createTenantVDCSourceNatPolicy(tenantName, "1"); + assertTrue(response); + response = connection.createTenantVDCSourceNatPolicyRef(tenantName, "1"); + assertTrue(response); + response = connection.createTenantVDCSourceNatRule(tenantName, "1", "10.1.1.2", "10.1.1.254"); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateTenantVDCNatPolicySet() { + try { + boolean response = connection.createTenantVDCNatPolicySet(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testAssociateNatPolicySet() { + try { + boolean response = connection.associateNatPolicySet(tenantName); + assertTrue(response); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testCreateEdgeFirewall() { + try { + boolean response = connection.createEdgeFirewall(tenantName, + "44.44.44.44", "192.168.1.1", "255.255.255.0", "255.255.255.192"); + assertTrue(response); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + @Test + public void testListUnassocAsa1000v() { + try { + Map response = connection.listUnAssocAsa1000v(); + assertTrue(response.size() >=0); + fwDns = response; + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void assocAsa1000v() { + try { + boolean result = connection.assignAsa1000v(tenantName, fwDns.get(0)); + assertTrue(result); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/element/CiscoVnmcElementTest.java b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/element/CiscoVnmcElementTest.java new file mode 100755 index 00000000000..a16733b5135 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/element/CiscoVnmcElementTest.java @@ -0,0 +1,401 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.element; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.naming.ConfigurationException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.internal.matchers.Any; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AssociateAsaWithLogicalEdgeFirewallCommand; +import com.cloud.agent.api.CleanupLogicalEdgeFirewallCommand; +import com.cloud.agent.api.ConfigureNexusVsmForAsaCommand; +import com.cloud.agent.api.CreateLogicalEdgeFirewallCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.ClusterVSMMapVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.VlanVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.ClusterVSMMapDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.Domain; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.network.Network; +import com.cloud.network.Network.GuestType; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.CiscoNexusVSMDeviceVO; +import com.cloud.network.IpAddress; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.cisco.CiscoAsa1000vDeviceVO; +import com.cloud.network.cisco.CiscoVnmcControllerVO; +import com.cloud.network.cisco.NetworkAsa1000vMapVO; +import com.cloud.network.dao.CiscoAsa1000vDao; +import com.cloud.network.dao.CiscoNexusVSMDeviceDao; +import com.cloud.network.dao.CiscoVnmcDao; +import com.cloud.network.dao.NetworkAsa1000vMapDao; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.rules.StaticNatRule; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.user.Account; +import com.cloud.utils.net.Ip; +import com.cloud.vm.ReservationContext; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class CiscoVnmcElementTest { + + CiscoVnmcElement _element = new CiscoVnmcElement(); + AgentManager _agentMgr = mock(AgentManager.class); + NetworkManager _networkMgr = mock(NetworkManager.class); + NetworkModel _networkModel = mock(NetworkModel.class); + HostDao _hostDao = mock(HostDao.class); + NetworkServiceMapDao _ntwkSrvcDao = mock(NetworkServiceMapDao.class); + ConfigurationManager _configMgr = mock(ConfigurationManager.class); + CiscoVnmcDao _ciscoVnmcDao = mock(CiscoVnmcDao.class); + CiscoAsa1000vDao _ciscoAsa1000vDao = mock(CiscoAsa1000vDao.class); + NetworkAsa1000vMapDao _networkAsa1000vMapDao = mock(NetworkAsa1000vMapDao.class); + ClusterVSMMapDao _clusterVsmMapDao = mock(ClusterVSMMapDao.class); + CiscoNexusVSMDeviceDao _vsmDeviceDao = mock(CiscoNexusVSMDeviceDao.class); + VlanDao _vlanDao = mock(VlanDao.class); + + @Before + public void setUp() throws ConfigurationException { + _element._resourceMgr = mock(ResourceManager.class); + _element._agentMgr = _agentMgr; + _element._networkMgr = _networkMgr; + _element._networkModel = _networkModel; + _element._hostDao = _hostDao; + _element._configMgr = _configMgr; + _element._ciscoVnmcDao = _ciscoVnmcDao; + _element._ciscoAsa1000vDao = _ciscoAsa1000vDao; + _element._networkAsa1000vMapDao = _networkAsa1000vMapDao; + _element._clusterVsmMapDao = _clusterVsmMapDao; + _element._vsmDeviceDao = _vsmDeviceDao; + _element._vlanDao = _vlanDao; + + // Standard responses + when(_networkModel.isProviderForNetwork(Provider.CiscoVnmc, 1L)).thenReturn(true); + + _element.configure("CiscoVnmcTestElement", Collections. emptyMap()); + } + + @Test + public void canHandleTest() { + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + assertTrue(_element.canHandle(network)); + + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.UnDecided); + assertFalse(_element.canHandle(network)); + } + + @Test + public void implementTest() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + URI uri = URI.create("vlan://123"); + + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getGateway()).thenReturn("1.1.1.1"); + when(network.getBroadcastUri()).thenReturn(uri); + when(network.getCidr()).thenReturn("1.1.1.0/24"); + + NetworkOffering offering = mock(NetworkOffering.class); + when(offering.getId()).thenReturn(1L); + when(offering.getTrafficType()).thenReturn(TrafficType.Guest); + when(offering.getGuestType()).thenReturn(GuestType.Isolated); + + DeployDestination dest = mock(DeployDestination.class); + + Domain dom = mock(Domain.class); + when(dom.getName()).thenReturn("d1"); + Account acc = mock(Account.class); + when(acc.getAccountName()).thenReturn("a1"); + ReservationContext context = mock(ReservationContext.class); + when(context.getDomain()).thenReturn(dom); + when(context.getAccount()).thenReturn(acc); + + DataCenter dc = mock(DataCenter.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(_configMgr.getZone(network.getDataCenterId())).thenReturn(dc); + + List devices = new ArrayList(); + devices.add(mock(CiscoVnmcControllerVO.class)); + when(_ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(devices); + + CiscoAsa1000vDeviceVO asaVO = mock(CiscoAsa1000vDeviceVO.class); + when(asaVO.getInPortProfile()).thenReturn("foo"); + when(asaVO.getManagementIp()).thenReturn("1.2.3.4"); + + List asaList = new ArrayList(); + asaList.add(asaVO); + when(_ciscoAsa1000vDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(asaList); + + when(_networkAsa1000vMapDao.findByNetworkId(network.getId())).thenReturn(mock(NetworkAsa1000vMapVO.class)); + when(_networkAsa1000vMapDao.findByAsa1000vId(anyLong())).thenReturn(null); + when(_networkAsa1000vMapDao.persist(any(NetworkAsa1000vMapVO.class))).thenReturn(mock(NetworkAsa1000vMapVO.class)); + + when(_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.CiscoVnmc)).thenReturn(true); + + ClusterVSMMapVO clusterVsmMap = mock(ClusterVSMMapVO.class); + when(_clusterVsmMapDao.findByClusterId(anyLong())).thenReturn(clusterVsmMap); + + CiscoNexusVSMDeviceVO vsmDevice = mock(CiscoNexusVSMDeviceVO.class); + when(vsmDevice.getUserName()).thenReturn("foo"); + when(vsmDevice.getPassword()).thenReturn("bar"); + when(vsmDevice.getipaddr()).thenReturn("1.2.3.4"); + when(_vsmDeviceDao.findById(anyLong())).thenReturn(vsmDevice); + + HostVO hostVO = mock(HostVO.class); + when(hostVO.getId()).thenReturn(1L); + when(_hostDao.findById(anyLong())).thenReturn(hostVO); + + Ip ip = mock(Ip.class); + when(ip.addr()).thenReturn("1.2.3.4"); + + PublicIp publicIp = mock(PublicIp.class); + when(publicIp.getAddress()).thenReturn(ip); + when(publicIp.getState()).thenReturn(IpAddress.State.Releasing); + when(publicIp.getAccountId()).thenReturn(1L); + when(publicIp.isSourceNat()).thenReturn(true); + when(publicIp.getVlanTag()).thenReturn("123"); + when(publicIp.getGateway()).thenReturn("1.1.1.1"); + when(publicIp.getNetmask()).thenReturn("1.1.1.1"); + when(publicIp.getMacAddress()).thenReturn(null); + when(publicIp.isOneToOneNat()).thenReturn(true); + when(_networkMgr.assignSourceNatIpAddressToGuestNetwork(acc, network)).thenReturn(publicIp); + + VlanVO vlanVO = mock(VlanVO.class); + when(vlanVO.getVlanGateway()).thenReturn("1.1.1.1"); + List vlanVOList = new ArrayList(); + when(_vlanDao.listVlansByPhysicalNetworkId(network.getPhysicalNetworkId())).thenReturn(vlanVOList); + + Answer answer = mock(Answer.class); + when(answer.getResult()).thenReturn(true); + + when(_agentMgr.easySend(anyLong(), any(CreateLogicalEdgeFirewallCommand.class))).thenReturn(answer); + when(_agentMgr.easySend(anyLong(), any(ConfigureNexusVsmForAsaCommand.class))).thenReturn(answer); + when(_agentMgr.easySend(anyLong(), any(SetSourceNatCommand.class))).thenReturn(answer); + when(_agentMgr.easySend(anyLong(), any(AssociateAsaWithLogicalEdgeFirewallCommand.class))).thenReturn(answer); + + assertTrue(_element.implement(network, offering, dest, context)); + } + + @Test + public void shutdownTest() throws ConcurrentOperationException, ResourceUnavailableException { + URI uri = URI.create("vlan://123"); + + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getBroadcastUri()).thenReturn(uri); + + ReservationContext context = mock(ReservationContext.class); + + when(_networkAsa1000vMapDao.findByNetworkId(network.getId())).thenReturn(mock(NetworkAsa1000vMapVO.class)); + + List devices = new ArrayList(); + devices.add(mock(CiscoVnmcControllerVO.class)); + when(_ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(devices); + + HostVO hostVO = mock(HostVO.class); + when(hostVO.getId()).thenReturn(1L); + when(_hostDao.findById(anyLong())).thenReturn(hostVO); + + Answer answer = mock(Answer.class); + when(answer.getResult()).thenReturn(true); + + when(_agentMgr.easySend(anyLong(), any(CleanupLogicalEdgeFirewallCommand.class))).thenReturn(answer); + + assertTrue(_element.shutdown(network, context, true)); + } + + @Test + public void applyFWRulesTest() throws ResourceUnavailableException { + URI uri = URI.create("vlan://123"); + + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getBroadcastUri()).thenReturn(uri); + when(network.getCidr()).thenReturn("1.1.1.0/24"); + when(network.getState()).thenReturn(Network.State.Implemented); + + Ip ip = mock(Ip.class); + when(ip.addr()).thenReturn("1.2.3.4"); + + IpAddress ipAddress = mock(IpAddress.class); + when(ipAddress.getAddress()).thenReturn(ip); + + when(_networkModel.getIp(anyLong())).thenReturn(ipAddress); + when(_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, Provider.CiscoVnmc)).thenReturn(true); + + List devices = new ArrayList(); + devices.add(mock(CiscoVnmcControllerVO.class)); + when(_ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(devices); + + when(_networkAsa1000vMapDao.findByNetworkId(network.getId())).thenReturn(mock(NetworkAsa1000vMapVO.class)); + + HostVO hostVO = mock(HostVO.class); + when(hostVO.getId()).thenReturn(1L); + when(_hostDao.findById(anyLong())).thenReturn(hostVO); + + FirewallRule rule = mock(FirewallRule.class); + when(rule.getSourceIpAddressId()).thenReturn(1L); + List rules = new ArrayList(); + rules.add(rule); + + Answer answer = mock(Answer.class); + when(answer.getResult()).thenReturn(true); + + when(_agentMgr.easySend(anyLong(), any(SetFirewallRulesCommand.class))).thenReturn(answer); + + assertTrue(_element.applyFWRules(network, rules)); + } + + @Test + public void applyPRulesTest() throws ResourceUnavailableException { + URI uri = URI.create("vlan://123"); + + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getBroadcastUri()).thenReturn(uri); + when(network.getCidr()).thenReturn("1.1.1.0/24"); + when(network.getState()).thenReturn(Network.State.Implemented); + + Ip ip = mock(Ip.class); + when(ip.addr()).thenReturn("1.2.3.4"); + + IpAddress ipAddress = mock(IpAddress.class); + when(ipAddress.getAddress()).thenReturn(ip); + when(ipAddress.getVlanId()).thenReturn(1L); + + when(_networkModel.getIp(anyLong())).thenReturn(ipAddress); + when(_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.PortForwarding, Provider.CiscoVnmc)).thenReturn(true); + + List devices = new ArrayList(); + devices.add(mock(CiscoVnmcControllerVO.class)); + when(_ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(devices); + + when(_networkAsa1000vMapDao.findByNetworkId(network.getId())).thenReturn(mock(NetworkAsa1000vMapVO.class)); + + HostVO hostVO = mock(HostVO.class); + when(hostVO.getId()).thenReturn(1L); + when(_hostDao.findById(anyLong())).thenReturn(hostVO); + + VlanVO vlanVO = mock(VlanVO.class); + when(vlanVO.getVlanTag()).thenReturn(null); + when(_vlanDao.findById(anyLong())).thenReturn(vlanVO); + + PortForwardingRule rule = mock(PortForwardingRule.class); + when(rule.getSourceIpAddressId()).thenReturn(1L); + when(rule.getDestinationIpAddress()).thenReturn(ip); + List rules = new ArrayList(); + rules.add(rule); + + Answer answer = mock(Answer.class); + when(answer.getResult()).thenReturn(true); + + when(_agentMgr.easySend(anyLong(), any(SetPortForwardingRulesCommand.class))).thenReturn(answer); + + assertTrue(_element.applyPFRules(network, rules)); + } + + @Test + public void applyStaticNatsTest() throws ResourceUnavailableException { + URI uri = URI.create("vlan://123"); + + Network network = mock(Network.class); + when(network.getId()).thenReturn(1L); + when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); + when(network.getDataCenterId()).thenReturn(1L); + when(network.getBroadcastUri()).thenReturn(uri); + when(network.getCidr()).thenReturn("1.1.1.0/24"); + when(network.getState()).thenReturn(Network.State.Implemented); + + Ip ip = mock(Ip.class); + when(ip.addr()).thenReturn("1.2.3.4"); + + IpAddress ipAddress = mock(IpAddress.class); + when(ipAddress.getAddress()).thenReturn(ip); + when(ipAddress.getVlanId()).thenReturn(1L); + + when(_networkModel.getIp(anyLong())).thenReturn(ipAddress); + when(_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.StaticNat, Provider.CiscoVnmc)).thenReturn(true); + + List devices = new ArrayList(); + devices.add(mock(CiscoVnmcControllerVO.class)); + when(_ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId())).thenReturn(devices); + + when(_networkAsa1000vMapDao.findByNetworkId(network.getId())).thenReturn(mock(NetworkAsa1000vMapVO.class)); + + HostVO hostVO = mock(HostVO.class); + when(hostVO.getId()).thenReturn(1L); + when(_hostDao.findById(anyLong())).thenReturn(hostVO); + + VlanVO vlanVO = mock(VlanVO.class); + when(vlanVO.getVlanTag()).thenReturn(null); + when(_vlanDao.findById(anyLong())).thenReturn(vlanVO); + + StaticNat rule = mock(StaticNat.class); + when(rule.getSourceIpAddressId()).thenReturn(1L); + when(rule.getDestIpAddress()).thenReturn("1.2.3.4"); + when(rule.isForRevoke()).thenReturn(false); + List rules = new ArrayList(); + rules.add(rule); + + Answer answer = mock(Answer.class); + when(answer.getResult()).thenReturn(true); + + when(_agentMgr.easySend(anyLong(), any(SetStaticNatRulesCommand.class))).thenReturn(answer); + + assertTrue(_element.applyStaticNats(network, rules)); + } +} diff --git a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java new file mode 100755 index 00000000000..e814fdcd4d5 --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java @@ -0,0 +1,285 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.resource; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.junit.Before; +import org.junit.Test; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CreateLogicalEdgeFirewallCommand; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.to.FirewallRuleTO; +import com.cloud.agent.api.to.IpAddressTO; +import com.cloud.agent.api.to.PortForwardingRuleTO; +import com.cloud.agent.api.to.StaticNatRuleTO; +import com.cloud.dc.Vlan; +import com.cloud.host.Host; +import com.cloud.network.IpAddress; +import com.cloud.network.cisco.CiscoVnmcConnectionImpl; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.TrafficType; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.utils.exception.ExecutionException; + +public class CiscoVnmcResourceTest { + CiscoVnmcConnectionImpl _connection = mock(CiscoVnmcConnectionImpl.class); + CiscoVnmcResource _resource; + Map _parameters; + + @Before + public void setUp() throws ConfigurationException { + _resource = new CiscoVnmcResource(); + + _parameters = new HashMap(); + _parameters.put("name", "CiscoVnmc"); + _parameters.put("zoneId", "1"); + _parameters.put("physicalNetworkId", "100"); + _parameters.put("ip", "1.2.3.4"); + _parameters.put("username", "admin"); + _parameters.put("password", "pass"); + _parameters.put("guid", "e8e13097-0a08-4e82-b0af-1101589ec3b8"); + _parameters.put("numretries", "3"); + _parameters.put("timeout", "300"); + } + + @Test(expected=ConfigurationException.class) + public void resourceConfigureFailure() throws ConfigurationException { + _resource.configure("CiscoVnmcResource", Collections.emptyMap()); + } + + @Test + public void resourceConfigure() throws ConfigurationException { + _resource.configure("CiscoVnmcResource", _parameters); + assertTrue("CiscoVnmc".equals(_resource.getName())); + assertTrue(_resource.getType() == Host.Type.ExternalFirewall); + } + + @Test + public void testInitialization() throws ConfigurationException { + _resource.configure("CiscoVnmcResource", _parameters); + StartupCommand[] sc = _resource.initialize(); + assertTrue(sc.length ==1); + assertTrue("e8e13097-0a08-4e82-b0af-1101589ec3b8".equals(sc[0].getGuid())); + assertTrue("CiscoVnmc".equals(sc[0].getName())); + assertTrue("1".equals(sc[0].getDataCenter())); + } + + @Test + public void testPingCommandStatusOk() throws ConfigurationException, ExecutionException { + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.login()).thenReturn(true); + PingCommand ping = _resource.getCurrentStatus(1); + assertTrue(ping != null); + assertTrue(ping.getHostId() == 1); + assertTrue(ping.getHostType() == Host.Type.ExternalFirewall); + } + + @Test + public void testPingCommandStatusFail() throws ConfigurationException, ExecutionException { + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.login()).thenReturn(false); + PingCommand ping = _resource.getCurrentStatus(1); + assertTrue(ping == null); + } + + @Test + public void testSourceNat() throws ConfigurationException, Exception { + long vlanId = 123; + IpAddressTO ip = new IpAddressTO(1, "1.2.3.4", true, false, + false, null, "1.2.3.1", "255.255.255.0", null, null, false); + SetSourceNatCommand cmd = new SetSourceNatCommand(ip, true); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId)); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "1.2.3.4/32"); + + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.login()).thenReturn(true); + when(_connection.createTenantVDCNatPolicySet(anyString())).thenReturn(true); + when(_connection.createTenantVDCSourceNatPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCSourceNatPolicyRef(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCSourceNatIpPool(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCSourceNatRule(anyString(), anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.associateNatPolicySet(anyString())).thenReturn(true); + + Answer answer = _resource.executeRequest(cmd); + System.out.println(answer.getDetails()); + assertTrue(answer.getResult()); + } + + @Test + public void testFirewall() throws ConfigurationException, Exception { + long vlanId = 123; + List rules = new ArrayList(); + List cidrList = new ArrayList(); + cidrList.add("2.3.2.3/32"); + FirewallRuleTO active = new FirewallRuleTO(1, + null, "1.2.3.4", "tcp", 22, 22, false, false, + FirewallRule.Purpose.Firewall, cidrList, null, null); + rules.add(active); + FirewallRuleTO revoked = new FirewallRuleTO(1, + null, "1.2.3.4", "tcp", 22, 22, true, false, + FirewallRule.Purpose.Firewall, null, null, null); + rules.add(revoked); + + SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rules); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId)); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "1.2.3.4/32"); + + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.createTenantVDCAclPolicySet(anyString(), anyBoolean())).thenReturn(true); + when(_connection.createTenantVDCAclPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicyRef(anyString(), anyString(), anyBoolean())).thenReturn(true); + when(_connection.deleteTenantVDCAclRule(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCIngressAclRule( + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCEgressAclRule( + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.associateAclPolicySet(anyString())).thenReturn(true); + + Answer answer = _resource.executeRequest(cmd); + System.out.println(answer.getDetails()); + assertTrue(answer.getResult()); + } + + @Test + public void testStaticNat() throws ConfigurationException, Exception { + long vlanId = 123; + List rules = new ArrayList(); + StaticNatRuleTO active = new StaticNatRuleTO(0, "1.2.3.4", null, + null, "5.6.7.8", null, null, null, false, false); + rules.add(active); + StaticNatRuleTO revoked = new StaticNatRuleTO(0, "1.2.3.4", null, + null, "5.6.7.8", null, null, null, true, false); + rules.add(revoked); + + SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rules, null); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId)); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "1.2.3.4/32"); + + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.createTenantVDCNatPolicySet(anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicySet(anyString(), anyBoolean())).thenReturn(true); + when(_connection.createTenantVDCDNatPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCDNatPolicyRef(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicyRef(anyString(), anyString(), anyBoolean())).thenReturn(true); + when(_connection.deleteTenantVDCDNatRule(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.deleteTenantVDCAclRule(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCDNatIpPool(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCDNatRule(anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclRuleForDNat(anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.associateAclPolicySet(anyString())).thenReturn(true); + + Answer answer = _resource.executeRequest(cmd); + System.out.println(answer.getDetails()); + assertTrue(answer.getResult()); + } + + @Test + public void testPortForwarding() throws ConfigurationException, Exception { + long vlanId = 123; + List rules = new ArrayList(); + PortForwardingRuleTO active = new PortForwardingRuleTO(1, "1.2.3.4", 22, 22, + "5.6.7.8", 22, 22, "tcp", false, false); + rules.add(active); + PortForwardingRuleTO revoked = new PortForwardingRuleTO(1, "1.2.3.4", 22, 22, + "5.6.7.8", 22, 22, "tcp", false, false); + rules.add(revoked); + + SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(rules); + cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId)); + cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "1.2.3.4/32"); + + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.createTenantVDCNatPolicySet(anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicySet(anyString(), anyBoolean())).thenReturn(true); + when(_connection.createTenantVDCPFPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCPFPolicyRef(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicy(anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclPolicyRef(anyString(), anyString(), anyBoolean())).thenReturn(true); + when(_connection.deleteTenantVDCPFRule(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.deleteTenantVDCAclRule(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCPFIpPool(anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCPFPortPool(anyString(), anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCPFRule(anyString(), + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.createTenantVDCAclRuleForPF(anyString(), + anyString(), anyString(), anyString(), + anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.associateAclPolicySet(anyString())).thenReturn(true); + + Answer answer = _resource.executeRequest(cmd); + System.out.println(answer.getDetails()); + assertTrue(answer.getResult()); + } + + @Test + public void testCreateEdgeFirewall() throws ConfigurationException, Exception { + long vlanId = 123; + CreateLogicalEdgeFirewallCommand cmd = new CreateLogicalEdgeFirewallCommand(vlanId, "1.2.3.4", "5.6.7.8", "255.255.255.0", "255.255.255.0"); + cmd.getPublicGateways().add("1.1.1.1"); + cmd.getPublicGateways().add("2.2.2.2"); + + _resource.configure("CiscoVnmcResource", _parameters); + _resource.setConnection(_connection); + when(_connection.createTenant(anyString())).thenReturn(true); + when(_connection.createTenantVDC(anyString())).thenReturn(true); + when(_connection.createTenantVDCEdgeSecurityProfile(anyString())).thenReturn(true); + when(_connection.createTenantVDCEdgeDeviceProfile(anyString())).thenReturn(true); + when(_connection.createTenantVDCEdgeStaticRoutePolicy(anyString())).thenReturn(true); + when(_connection.createTenantVDCEdgeStaticRoute(anyString(), anyString(), anyString(), anyString())).thenReturn(true); + when(_connection.associateTenantVDCEdgeStaticRoutePolicy(anyString())).thenReturn(true); + when(_connection.createEdgeFirewall(anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(true); + + Answer answer = _resource.executeRequest(cmd); + System.out.println(answer.getDetails()); + assertTrue(answer.getResult()); + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 12c85fff38b..471253f0728 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -138,6 +138,7 @@ hypervisors/vmware + network-elements/cisco-vnmc diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 50c137ae81f..cfe0e00d8ba 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2717,8 +2717,8 @@ public class ApiResponseHelper implements ResponseGenerator { List serviceProviders = ApiDBUtils.getProvidersForService(service); List serviceProvidersResponses = new ArrayList(); for (Network.Provider serviceProvider : serviceProviders) { - // return only Virtual Router/JuniperSRX as a provider for the firewall - if (service == Service.Firewall && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX)) { + // return only Virtual Router/JuniperSRX/CiscoVnmc as a provider for the firewall + if (service == Service.Firewall && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX || serviceProvider == Provider.CiscoVnmc)) { continue; } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index fce3c010df4..5b6d81e8df8 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -3302,8 +3302,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Invalid service provider: " + prvNameStr); } - if (provider == Provider.JuniperSRX) { - firewallProvider = Provider.JuniperSRX; + if (provider == Provider.JuniperSRX || provider == Provider.CiscoVnmc) { + firewallProvider = provider; } if ((service == Service.PortForwarding || service == Service.StaticNat) && provider == Provider.VirtualRouter){ diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 92b2d9c863c..fb760bf4824 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -680,7 +680,41 @@ CREATE VIEW `cloud`.`affinity_group_view` AS left join `cloud`.`vm_instance` ON vm_instance.id = affinity_group_vm_map.instance_id left join - `cloud`.`user_vm` ON user_vm.id = vm_instance.id; - + `cloud`.`user_vm` ON user_vm.id = vm_instance.id; + +CREATE TABLE `cloud`.`external_cisco_vnmc_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(255) UNIQUE, + `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which cisco vnmc device is added', + `provider_name` varchar(255) NOT NULL COMMENT 'Service Provider name corresponding to this cisco vnmc device', + `device_name` varchar(255) NOT NULL COMMENT 'name of the cisco vnmc device', + `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external cisco vnmc device', + PRIMARY KEY (`id`), + CONSTRAINT `fk_external_cisco_vnmc_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_external_cisco_vnmc_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`external_cisco_asa1000v_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(255) UNIQUE, + `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which cisco asa1kv device is added', + `management_ip` varchar(255) UNIQUE NOT NULL COMMENT 'mgmt. ip of cisco asa1kv device', + `in_port_profile` varchar(255) NOT NULL COMMENT 'inside port profile name of cisco asa1kv device', + `cluster_id` bigint unsigned NOT NULL COMMENT 'id of the Vmware cluster to which cisco asa1kv device is attached (cisco n1kv switch)', + PRIMARY KEY (`id`), + CONSTRAINT `fk_external_cisco_asa1000v_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_external_cisco_asa1000v_devices__cluster_id` FOREIGN KEY (`cluster_id`) REFERENCES `cluster`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`network_asa1000v_map` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `network_id` bigint unsigned NOT NULL UNIQUE COMMENT 'id of guest network', + `asa1000v_id` bigint unsigned NOT NULL UNIQUE COMMENT 'id of asa1000v device', + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_asa1000v_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_network_asa1000v_map__asa1000v_id` FOREIGN KEY (`asa1000v_id`) REFERENCES `external_cisco_asa1000v_devices`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1; + diff --git a/test/integration/component/test_asa1000v_fw.py b/test/integration/component/test_asa1000v_fw.py new file mode 100755 index 00000000000..0b66f971946 --- /dev/null +++ b/test/integration/component/test_asa1000v_fw.py @@ -0,0 +1,134 @@ +# 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. + +""" Cisco ASA1000v external firewall +""" +#Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from marvin.remoteSSHClient import remoteSSHClient +import datetime + + +class Services: + """Test Cisco ASA1000v services + """ + + def __init__(self): + self.services = { + "vnmc": { + "ipaddress": '10.147.28.236', + "username": 'admin', + "password": 'Password_123', + }, + "asa": { + "ipaddress": '10.147.28.238', + "insideportprofile": 'asa-in123', + }, + "network_offering": { + "name": 'CiscoVnmc', + "displaytext": 'CiscoVnmc', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Firewall,UserData,StaticNat', + "traffictype": 'GUEST', + "availability": 'Optional', + "serviceProviderList": { + "Dhcp": 'VirtualRouter', + "Dns": 'VirtualRouter', + "SourceNat": 'CiscoVnmc', + "PortForwarding": 'CiscoVnmc', + "Firewall": 'CiscoVnmc', + "UserData": 'VirtualRouter', + "StaticNat": 'CiscoVnmc', + }, + }, + "network": { + "name": "CiscoVnmc", + "displaytext": "CiscoVnmc", + }, + } + +class TestASASetup(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.apiclient = super( + TestASASetup, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + cls.network_offering = NetworkOffering.create( + cls.apiclient, + cls.services["network_offering"], + conservemode=True) + # Enable network offering + cls.network_offering.update(cls.apiclient, state='Enabled') + + cls._cleanup = [ + cls.network_offering, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + + self.zone = get_zone(self.apiclient, self.services) + self.physicalnetworks = PhysicalNetwork.list(self.apiclient, zoneid=self.zone.id) + self.assertNotEqual(len(self.physicalnetworks), 0, "Check if the list physical network API returns a non-empty response") + self.clusters = Cluster.list(self.apiclient, hypervisor='VMware') + self.assertNotEqual(len(self.clusters), 0, "Check if the list cluster API returns a non-empty response") + + return + + def tearDown(self): + try: + self.debug("Cleaning up the resources") + # Cleanup + cleanup_resources(self.apiclient, self._cleanup) + self.debug("Cleanup complete!") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def test_registerVnmc(self): + Vnmc = VNMC.create(self.apiclient, self.services["vnmc"]["ipaddress"], self.services["vnmc"]["username"], self.services["vnmc"]["password"], self.physicalnetworks[0].id) + self.debug("Cisco VNMC appliance with id %s deployed"%(Vnmc.id)) + VnmcList = VNMC.list(self.apiclient, physicalnetworkid = self.physicalnetworks[0].id) + self.assertNotEqual(len(VnmcList), 0, "List VNMC API returned an empty response") + Vnmc.delete(self.apiclient) + + def test_registerAsa1000v(self): + Asa = ASA1000V.create(self.apiclient, self.services["asa"]["ipaddress"], self.services["asa"]["insideportprofile"], self.clusters[0].id, self.physicalnetworks[0].id) + self.debug("Cisco ASA 1000v appliance with id %s deployed"%(Asa.id)) + AsaList = ASA1000V.list(self.apiclient, physicalnetworkid = self.physicalnetworks[0].id) + self.assertNotEqual(len(AsaList), 0, "List ASA 1000v API returned an empty response") + Asa.delete(self.apiclient) \ No newline at end of file diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 3df68ab7853..0185c87fed9 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -2444,7 +2444,6 @@ class VPC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) - class AffinityGroup: def __init__(self, items): self.__dict__.update(items) @@ -2467,9 +2466,71 @@ class AffinityGroup: cmd.id = self.id return apiclient.deleteVPC(cmd) - @classmethod def list(cls, apiclient, **kwargs): cmd = listAffinityGroups.listAffinityGroupsCmd() [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) + +class VNMC: + """Manage VNMC lifecycle""" + + def __init__(self, items): + self.__dict__.update(items) + + def create(cls, apiclient, hostname, username, password, physicalnetworkid): + """Registers VNMC appliance""" + + cmd = addCiscoVnmcResource.addCiscoVnmcResourceCmd() + cmd.hostname = hostname + cmd.username = username + cmd.password = password + cmd.physicalnetworkid = physicalnetworkid + return VNMC(apiclient.addCiscoVnmcResource(cmd)) + + def delete(self, apiclient): + """Removes VNMC appliance""" + + cmd = deleteCiscoVnmcResource.deleteCiscoVnmcResourceCmd() + cmd.resourceid = self.resourceid + return apiclient.deleteCiscoVnmcResource(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List VNMC appliances""" + + cmd = listCiscoVnmcResources.listCiscoVnmcResourcesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCiscoVnmcResources(cmd)) + +class ASA1000V: + """Manage ASA 1000v lifecycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, hostname, insideportprofile, clusterid, physicalnetworkid): + """Registers ASA 1000v appliance""" + + cmd = addCiscoAsa1000vResource.addCiscoAsa1000vResourceCmd() + cmd.hostname = hostname + cmd.insideportprofile = insideportprofile + cmd.clusterid = clusterid + cmd.physicalnetworkid = physicalnetworkid + return ASA1000V(apiclient.addCiscoAsa1000vResource(cmd)) + + def delete(self, apiclient): + """Removes ASA 1000v appliance""" + + cmd = deleteCiscoAsa1000vResource.deleteCiscoAsa1000vResourceCmd() + cmd.resourceid = self.resourceid + return apiclient.deleteCiscoAsa1000vResource(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List ASA 1000v appliances""" + + cmd = listCiscoAsa1000vResources.listCiscoAsa1000vResourcesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCiscoAsa1000vResources(cmd)) diff --git a/utils/src/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java b/utils/src/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java index be8d68a5648..06718d0f35e 100644 --- a/utils/src/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java +++ b/utils/src/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java @@ -79,6 +79,17 @@ public class NetconfHelper { parseOkReply(receive()); } + public void addPortProfile(String name, PortProfileType type, BindingType binding, + SwitchPortMode mode, int vlanid, String vdc, String espName) throws CloudRuntimeException { + String command = VsmCommand.getAddPortProfile(name, type, binding, mode, vlanid, vdc, espName); + if (command != null) { + command = command.concat(SSH_NETCONF_TERMINATOR); + parseOkReply(sendAndReceive(command)); + } else { + throw new CloudRuntimeException("Error generating rpc request for adding port profile."); + } + } + public void addPortProfile(String name, PortProfileType type, BindingType binding, SwitchPortMode mode, int vlanid) throws CloudRuntimeException { String command = VsmCommand.getAddPortProfile(name, type, binding, mode, vlanid); @@ -160,6 +171,17 @@ public class NetconfHelper { } } + public void addVServiceNode(String vlanId, String ipAddr) + throws CloudRuntimeException { + String command = VsmCommand.getVServiceNode(vlanId, ipAddr); + if (command != null) { + command = command.concat(SSH_NETCONF_TERMINATOR); + parseOkReply(sendAndReceive(command)); + } else { + throw new CloudRuntimeException("Error generating rpc request for adding vservice node for vlan " + vlanId); + } + } + public PortProfile getPortProfileByName(String name) throws CloudRuntimeException { String command = VsmCommand.getPortProfile(name); if (command != null) { diff --git a/utils/src/com/cloud/utils/cisco/n1kv/vsm/VsmCommand.java b/utils/src/com/cloud/utils/cisco/n1kv/vsm/VsmCommand.java index d1887f6417d..fdab390557d 100644 --- a/utils/src/com/cloud/utils/cisco/n1kv/vsm/VsmCommand.java +++ b/utils/src/com/cloud/utils/cisco/n1kv/vsm/VsmCommand.java @@ -69,6 +69,40 @@ public class VsmCommand { removevlanid } + public static String getAddPortProfile(String name, PortProfileType type, + BindingType binding, SwitchPortMode mode, int vlanid, String vdc, String espName) { + try { + // Create the document and root element. + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + DOMImplementation domImpl = docBuilder.getDOMImplementation(); + Document doc = createDocument(domImpl); + + // Edit configuration command. + Element editConfig = doc.createElement("nf:edit-config"); + doc.getDocumentElement().appendChild(editConfig); + + // Command to get into exec configure mode. + Element target = doc.createElement("nf:target"); + Element running = doc.createElement("nf:running"); + target.appendChild(running); + editConfig.appendChild(target); + + // Command to create the port profile with the desired configuration. + Element config = doc.createElement("nf:config"); + config.appendChild(configPortProfileDetails(doc, name, type, binding, mode, vlanid, vdc, espName)); + editConfig.appendChild(config); + + return serialize(domImpl, doc); + } catch (ParserConfigurationException e) { + s_logger.error("Error while creating add port profile message : " + e.getMessage()); + return null; + } catch (DOMException e) { + s_logger.error("Error while creating add port profile message : " + e.getMessage()); + return null; + } + } + public static String getAddPortProfile(String name, PortProfileType type, BindingType binding, SwitchPortMode mode, int vlanid) { try { @@ -366,6 +400,184 @@ public class VsmCommand { } } + public static String getVServiceNode(String vlanId, String ipAddr) { + try { + // Create the document and root element. + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + DOMImplementation domImpl = docBuilder.getDOMImplementation(); + Document doc = createDocument(domImpl); + + // Edit configuration command. + Element editConfig = doc.createElement("nf:edit-config"); + doc.getDocumentElement().appendChild(editConfig); + + // Command to get into exec configure mode. + Element target = doc.createElement("nf:target"); + Element running = doc.createElement("nf:running"); + target.appendChild(running); + editConfig.appendChild(target); + + // Command to create the port profile with the desired configuration. + Element config = doc.createElement("nf:config"); + config.appendChild(configVServiceNodeDetails(doc, vlanId, ipAddr)); + editConfig.appendChild(config); + + return serialize(domImpl, doc); + } catch (ParserConfigurationException e) { + s_logger.error("Error while adding vservice node for vlan " + vlanId + ", " + e.getMessage()); + return null; + } catch (DOMException e) { + s_logger.error("Error while adding vservice node for vlan " + vlanId + ", " + e.getMessage()); + return null; + } + } + + private static Element configVServiceNodeDetails(Document doc, String vlanId, String ipAddr) { + // In mode, exec_configure. + Element configure = doc.createElementNS(s_ciscons, "nxos:configure"); + Element modeConfigure = doc.createElement("nxos:" + s_configuremode); + configure.appendChild(modeConfigure); + + // vservice node %name% type asa + Element vservice = doc.createElement("vservice"); + vservice.appendChild(doc.createElement("node")) + .appendChild(doc.createElement("ASA_" + vlanId)) + .appendChild(doc.createElement("type")) + .appendChild(doc.createElement("asa")); + modeConfigure.appendChild(vservice); + + Element address = doc.createElement(s_paramvalue); + address.setAttribute("isKey", "true"); + address.setTextContent(ipAddr); + + // ip address %ipAddr% + modeConfigure.appendChild(doc.createElement("ip")) + .appendChild(doc.createElement("address")) + .appendChild(doc.createElement("value")) + .appendChild(address); + + Element vlan = doc.createElement(s_paramvalue); + vlan.setAttribute("isKey", "true"); + vlan.setTextContent(vlanId); + + // adjacency l2 vlan %vlanId% + modeConfigure.appendChild(doc.createElement("adjacency")) + .appendChild(doc.createElement("l2")) + .appendChild(doc.createElement("vlan")) + .appendChild(doc.createElement("value")) + .appendChild(vlan); + + // fail-mode close + modeConfigure.appendChild(doc.createElement("fail-mode")) + .appendChild(doc.createElement("close")); + + // Persist the configuration across reboots. + modeConfigure.appendChild(persistConfiguration(doc)); + + return configure; + } + + private static Element configPortProfileDetails(Document doc, String name, PortProfileType type, + BindingType binding, SwitchPortMode mode, int vlanid, String vdc, String espName) { + + // In mode, exec_configure. + Element configure = doc.createElementNS(s_ciscons, "nxos:configure"); + Element modeConfigure = doc.createElement("nxos:" + s_configuremode); + configure.appendChild(modeConfigure); + + // Port profile name and type configuration. + Element portProfile = doc.createElement("port-profile"); + modeConfigure.appendChild(portProfile); + + // Port profile type. + Element portDetails = doc.createElement("name"); + switch (type) { + case none: + portProfile.appendChild(portDetails); + break; + case ethernet: + { + Element typetag = doc.createElement("type"); + Element ethernettype = doc.createElement("ethernet"); + portProfile.appendChild(typetag); + typetag.appendChild(ethernettype); + ethernettype.appendChild(portDetails); + } + break; + case vethernet: + { + Element typetag = doc.createElement("type"); + Element ethernettype = doc.createElement("vethernet"); + portProfile.appendChild(typetag); + typetag.appendChild(ethernettype); + ethernettype.appendChild(portDetails); + } + break; + } + + // Port profile name. + Element value = doc.createElement(s_paramvalue); + value.setAttribute("isKey", "true"); + value.setTextContent(name); + portDetails.appendChild(value); + + // element for port prof mode. + Element portProf = doc.createElement(s_portprofmode); + portDetails.appendChild(portProf); + + // Binding type. + if (binding != BindingType.none) { + portProf.appendChild(getBindingType(doc, binding)); + } + + if (mode != SwitchPortMode.none) { + // Switchport mode. + portProf.appendChild(getSwitchPortMode(doc, mode)); + // Adding vlan details. + if (vlanid > 0) { + portProf.appendChild(getAddVlanDetails(doc, mode, Integer.toString(vlanid))); + } + } + + // Command "vmware port-group". + Element vmware = doc.createElement("vmware"); + Element portgroup = doc.createElement("port-group"); + vmware.appendChild(portgroup); + portProf.appendChild(vmware); + + // org root/%vdc% + // vservice node profile + Element org = doc.createElement("org"); + org.appendChild(doc.createElement(vdc)); + portProf.appendChild(org); + + String asaNodeName = "ASA_" + vlanid; + Element vservice = doc.createElement("vservice"); + vservice.appendChild(doc.createElement("node")) + .appendChild(doc.createElement(asaNodeName)) + .appendChild(doc.createElement("profile")) + .appendChild(doc.createElement(espName)); + portProf.appendChild(vservice); + + // no shutdown. + Element no = doc.createElement("no"); + Element shutdown = doc.createElement("shutdown"); + no.appendChild(shutdown); + portProf.appendChild(no); + + // Enable the port profile. + Element state = doc.createElement("state"); + Element enabled = doc.createElement("enabled"); + state.appendChild(enabled); + portProf.appendChild(state); + + // Persist the configuration across reboots. + modeConfigure.appendChild(persistConfiguration(doc)); + + return configure; + } + private static Element configPortProfileDetails(Document doc, String name, PortProfileType type, BindingType binding, SwitchPortMode mode, int vlanid) { @@ -433,6 +645,7 @@ public class VsmCommand { Element portgroup = doc.createElement("port-group"); vmware.appendChild(portgroup); portProf.appendChild(vmware); + // no shutdown. Element no = doc.createElement("no"); diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 621c091481a..7f323c5e400 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -163,7 +163,8 @@ public class HypervisorHostHelper { } public static void createPortProfile(VmwareContext context, String ethPortProfileName, String networkName, - Integer vlanId, Integer networkRateMbps, long peakBandwidth, long burstSize) throws Exception { + Integer vlanId, Integer networkRateMbps, long peakBandwidth, long burstSize, + String gateway, boolean configureVServiceInNexus) throws Exception { Map vsmCredentials = getValidatedVsmCredentials(context); String vsmIp = vsmCredentials.get("vsmip"); String vsmUserName = vsmCredentials.get("vsmusername"); @@ -233,8 +234,18 @@ public class HypervisorHostHelper { s_logger.info("Adding port profile configured over untagged VLAN."); netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, 0); } else { - s_logger.info("Adding port profile configured over VLAN : " + vlanId.toString()); - netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, vlanId.intValue()); + if (!configureVServiceInNexus) { + s_logger.info("Adding port profile configured over VLAN : " + vlanId.toString()); + netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, vlanId.intValue()); + } else { + String tenant = "vlan-" + vlanId.intValue(); + String vdc = "root/" + tenant + "/VDC-" + tenant; + String esp = "ESP-" + tenant; + s_logger.info("Adding vservice node in Nexus VSM for VLAN : " + vlanId.toString()); + netconfClient.addVServiceNode(vlanId.toString(), gateway); + s_logger.info("Adding port profile with vservice details configured over VLAN : " + vlanId.toString()); + netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, vlanId.intValue(), vdc, esp); + } } } catch (CloudRuntimeException e) { msg = "Failed to add vEthernet port profile " + networkName + "." + ". Exception: " + e.toString(); @@ -402,7 +413,7 @@ public class HypervisorHostHelper { public static Pair prepareNetwork(String physicalNetwork, String namePrefix, HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, - VirtualSwitchType vSwitchType, int numPorts) throws Exception { + VirtualSwitchType vSwitchType, int numPorts, String gateway, boolean configureVServiceInNexus) throws Exception { ManagedObjectReference morNetwork = null; VmwareContext context = hostMo.getContext(); ManagedObjectReference dcMor = hostMo.getHyperHostDatacenter(); @@ -504,22 +515,22 @@ public class HypervisorHostHelper { } else { s_logger.info("Found Ethernet port profile " + ethPortProfileName); } - long averageBandwidth = 0L; - if (networkRateMbps != null && networkRateMbps.intValue() > 0) { - averageBandwidth = (long) (networkRateMbps.intValue() * 1024L * 1024L); - } - // We chose 50% higher allocation than average bandwidth. + long averageBandwidth = 0L; + if (networkRateMbps != null && networkRateMbps.intValue() > 0) { + averageBandwidth = (long) (networkRateMbps.intValue() * 1024L * 1024L); + } + // We chose 50% higher allocation than average bandwidth. // TODO(sateesh): Optionally let user specify the peak coefficient - long peakBandwidth = (long) (averageBandwidth * 1.5); + long peakBandwidth = (long) (averageBandwidth * 1.5); // TODO(sateesh): Optionally let user specify the burst coefficient - long burstSize = 5 * averageBandwidth / 8; + long burstSize = 5 * averageBandwidth / 8; - if (!dataCenterMo.hasDvPortGroup(networkName)) { - s_logger.info("Port profile " + networkName + " not found."); - createPortProfile(context, physicalNetwork, networkName, vid, networkRateMbps, peakBandwidth, burstSize); - bWaitPortGroupReady = true; - } else { - s_logger.info("Port profile " + networkName + " found."); + if (!dataCenterMo.hasDvPortGroup(networkName)) { + s_logger.info("Port profile " + networkName + " not found."); + createPortProfile(context, physicalNetwork, networkName, vid, networkRateMbps, peakBandwidth, burstSize, gateway, configureVServiceInNexus); + bWaitPortGroupReady = true; + } else { + s_logger.info("Port profile " + networkName + " found."); updatePortProfile(context, physicalNetwork, networkName, vid, networkRateMbps, peakBandwidth, burstSize); } } From 1f0b804dd3972f373c196799fc48929a7bc3f473 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Mon, 15 Apr 2013 15:42:10 +0200 Subject: [PATCH 088/107] NiciraNvpElement is also implements IpDeployer. IpDeployer is required for the L3 components. --- client/tomcatconf/componentContext.xml.in | 1 + client/tomcatconf/nonossComponentContext.xml.in | 1 + 2 files changed, 2 insertions(+) diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 92838fd85d3..23284abc094 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -197,6 +197,7 @@ +
diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index aac3b893a8a..a2182d183b0 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -293,6 +293,7 @@ + From abbc7efd808a3b8da0548e8a1908fa42cdde2a28 Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Mon, 15 Apr 2013 09:19:36 -0500 Subject: [PATCH 089/107] More work on Release Notes. --- docs/en-US/Release_Notes.xml | 90 +++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml index 5b9571e7909..e701330a612 100644 --- a/docs/en-US/Release_Notes.xml +++ b/docs/en-US/Release_Notes.xml @@ -3982,6 +3982,92 @@ under the License. Create RPM or Debian packages (as appropriate) and a repository from the 4.1.0 source, or check the Apache CloudStack downloads page at http://cloudstack.apache.org/downloads.html for package repositories supplied by community members. You will need them for step or step . Instructions for creating packages from the &PRODUCT; source are in the Installation Guide. + + For VMware Only + This step is only required if you are using VMware. You can safely skip this step if you are using KVM and/or Xen only. + + In each zone that includes VMware hosts, you need to add a new system VM template. + + + While running the existing 3.0.2 system, log in to the UI as root administrator. + + + In the left navigation bar, click Templates. + + + In Select view, click Templates. + + + Click Register template. + The Register template dialog box is displayed. + + + In the Register template dialog box, specify the following values (do not change these): + + + + + + + Field + Value + + + + + Name + systemvm-vmware-4.1 + + + Description + systemvm-vmware-4.1 + + + URL + http://download.cloud.com/templates/burbank/burbank-systemvm-08012012.ova + + + Zone + Choose the zone where this hypervisor is used + + + Hypervisor + VMware + + + Format + OVA + + + OS Type + Debian GNU/Linux 5.0 (32-bit) + + + Extractable + no + + + Password Enabled + no + + + Public + no + + + Featured + no + + + + + + + Watch the screen to be sure that the template downloads successfully and enters + the READY state. Do not proceed until this is successful. + + + Stop your management server or servers. Run this on all management server hosts: # service cloud-management stop @@ -4132,11 +4218,11 @@ under the License. Name - systemvm-vmware-4.0 + systemvm-vmware-4.1 Description - systemvm-vmware-4.0 + systemvm-vmware-4.1 URL From e22a86f57ae0202134022627fe8156218d46fdd9 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Mon, 15 Apr 2013 20:53:04 +0530 Subject: [PATCH 090/107] CLOUDSTACK-1898: Incorrect time conversion on UI under Events and Alerts --- ui/scripts/sharedFunctions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 19e16119845..74675314040 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -325,7 +325,8 @@ cloudStack.converters = { if(g_timezoneoffset != null) localDate = disconnected.getTimePlusTimezoneOffset(g_timezoneoffset); else - localDate = disconnected.getTimePlusTimezoneOffset(0); + localDate = disconnected.toUTCString(); + // localDate = disconnected.getTimePlusTimezoneOffset(0); } return localDate; }, From 1f76d8bed7f765de8e5e2ea695995eef6e927b0d Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Mon, 15 Apr 2013 12:03:43 -0500 Subject: [PATCH 091/107] Added more to new features section, including API discovery service, CloudMonkey, Regions, and more. --- docs/en-US/Release_Notes.xml | 148 +++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml index e701330a612..718f38e7df9 100644 --- a/docs/en-US/Release_Notes.xml +++ b/docs/en-US/Release_Notes.xml @@ -37,6 +37,154 @@ under the License. The 4.1.0 release adds partial User Interface (UI) support for Catalan, Chinese, French, German, Italian, Japanese, Korean, Norwegian, Portuguese, Russian, and Spanish. Not all languages are complete. The 4.1.0 release also adds documentation translations for Chinese, Chinese (Taiwan), Italian, Japanese, Korean, and Portuguese. +
+ Added Region Support + CLOUDSTACK-241: This feature adds a "region" construct that spans several management servers. The objective of this feature is to add AWS EC2 like Regions implementation into CloudStack. Regions are dispersed and located in separate geographic areas. Availability Zones (or Zones in CloudStack) are distinct locations within a Region that are engineered to be isolated from failures in other Zones and provide inexpensive, low latency network connectivity to other Zones in the same Region. + Regions are expected to add the following benefits + + Higher availability of the services: users can deploy services across AZs and even if one of the AZ goes down the services are still available to the end-user through VMs deployed in other zones. + Higher availability of the Management Server (MS): Since each MS Cluster only manages a single Region, if that MS Cluster goes down, only that particular Region is impacted. Admin should be able to access all the other Regions. + Scalability: The scalability limit of CloudStack dramatically improves, as the scalability limit of MS Cluster is limited to a single Region. + Object Store: With Regions construct, CloudStack would also allow users to define Object Store (Secondary Storage) across AZs. This helps users easily deploy VMs in different AZs using the same template, offerings. + Geographical Grouping: Regions allow admins to group AZs (that have low latency and are geographically located nearby) into a broader region construct. + + Currently the Region feature is exposed in the API, but does not have a UI component. +
+
+ Support for EC2 Query API + CLOUDSTACK-197: This introduces a query API for the AWS APIs that are currently only supported by SOAP. The AWS Java SDK and AWS PHP SDK should now be supported by the AWSAPI in CloudStack. + Supported Query APIs in 4.1.0: + + AllocateAddress + AssociateAddress + AttachVolume + AuthorizeSecurityGroupIngress + CreateImage + CreateKeyPair + CreateSecurityGroup + CreateSnapshot + CreateTags + CreateVolume + DeleteKeyPair + DeleteSecurityGroup + DeleteSnapshot + DeleteTags + DeleteVolume + DeregisterImage + DescribeAddresses + DescribeAvailabilityZones + DescribeImageAttribute + DescribeImages + DescribeInstanceAttribute + DescribeInstances + DescribeKeyPairs + DescribeSecurityGroups + DescribeSnapshots + DescribeTags + DescribeVolumes + DetachVolume + DisassociateAddress + GetPasswordData + ImportkeyPair + ModifyImageAttribute + RebootInstances + RegisterImage + ReleaseAddress + ResetImageAttribute + RevokeSecurityGroupIngress + RunInstances + StartInstances + StopInstances + TerminateInstances + + See the Feature Specification for more information on the Query API support. +
+
+ Auto-Completing Shell for CloudStack (CloudMonkey) + CLOUDSTACK-132: Adds a auto-completing shell and command-line tool for &PRODUCT; written in Python, called CloudMonkey. + CloudMonkey includes the following features: + + Usable as a command line tool and interactive shell. + All commands are lowercase unlike API. + Api Discovery using sync feature, with build time api precaching for failsafe sync. + Raw api execution support. + Auto-completion via double tab. + Reverse search using Ctrl+R + Emacs compatible key bindings. + Output that's "pipeable" to other *nix programs. + Unix shell execution. + Support to handle asynchronous jobs using user defined blocking or non-blocking way. + Tabular or JSON output with filtering of table columns. + Colored output. + API parameter value completion (based on predication, fuzzy results may fail sometimes). + + CloudMonkey has a few requirements above and beyond CloudStack, and does not need to be run on the same machine as a management server. If you wish to run CloudMonkey you'll need Python 2.5 or later, readline, Pygments, and prettytable. CloudMonkey can be installed with pip: + $ pip install cloudmonkey + See the Developer's Guide and the CloudStack wiki for the latest information on CloudMonkey installation and use. +
+
+ API Discovery Service + CLOUDSTACK-926: CloudStack has more than 300 APIs and more are added in each major release. CloudStack admins can enable or disable APIs, or add plugins which provide more APIs. The API Discovery Service is a plugin which will help users discover the APIs available to them on a CloudStack Management Server. + The discovery service implements a method called listApis which will return information about APIs for a user. It currently accepts an apiName to list api information of that particular API. The method ensures that user can only list APIs they are entitled to. + All CloudStack APIs are implemented by annotated command class and PluggableService is a contract implemented by all the components such as the Management Server and all the plugins which provide an API. During load time, API discovery service asks all the pluggable services to return list of API cmd classes from whose fields and annotations it gathers information about each API, the information consists of name, description, parameter name, parameter description, etc. + For more information on the implementation of the API Discovery Service for 4.1.0, see the CloudStack wiki. +
+
+ Events Framework + CLOUDSTACK-820: The Events Framework provides a mechanism to publish and subscribe to events in &PRODUCT;. +
+
+ Additional VMX Settings + ### +
+
+ L3 Router Functionality in Nicira Nvp Plugin + ### +
+
+ Persistent Networks without Running VM + ### +
+
+ Add/Remove Network on VM + ### +
+
+ Resize Volumes Feature + ### +
+
+ Autoscale + ### +
+
+ API Request Throttling + ### +
+
+ Ceph RDB Setup + ### +
+
+ S3 Backed Secondary Storage + ### +
+
+ User and Domain Admin Can Create API Key and Secret + CLOUDSTACK-437: This feature adds the ability for domain admins and users to create their own API Key and Secret. Domain admins can create keys for themselves, subdomain admins, and for regular users, but not for other domain admins. +
+
+ Support Inline Mode for F5 and SRX + CLOUDSTACK-306: ### +
+
+ Egress Firewall Rules for Guest Networks + CLOUDSTACK-299: ### +
+
+ Reset SSH Key to Access VM + CLOUDSTACK-297: ### +
Issues Fixed in 4.1.0 From 794e653c1325f6ba78b700f62e75c5a7b502c4eb Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Fri, 12 Apr 2013 16:56:18 -0400 Subject: [PATCH 092/107] Fix command for executing injectkeys.sh Signed-off-by: Hugo Trippaers --- server/src/com/cloud/server/ConfigurationServerImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 596387f100e..404afecf2cd 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -729,7 +729,8 @@ 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("/bin/bash " + scriptPath, s_logger); + final Script command = new Script("/bin/bash", s_logger); + command.add(scriptPath); command.add(publicKeyPath); command.add(privKeyPath); command.add(systemVmIsoPath); From 719f254487e81c21216e8b8d8293f9e927713cea Mon Sep 17 00:00:00 2001 From: Chip Childers Date: Mon, 15 Apr 2013 16:05:26 -0400 Subject: [PATCH 093/107] CLOUDSTACK-1997: added correct download location for the experimental system vm Signed-off-by: Chip Childers --- docs/en-US/ipv6-support.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en-US/ipv6-support.xml b/docs/en-US/ipv6-support.xml index 7367ec9ad80..c7f7744393e 100644 --- a/docs/en-US/ipv6-support.xml +++ b/docs/en-US/ipv6-support.xml @@ -75,8 +75,8 @@ Use the System VM template exclusively designed to support IPv6. Download the System - VM template from http://nfs1.lab.vmops.com/templates/routing/debian/ipv6/. + VM template from http://cloudstack.apt-get.eu/systemvm/. The concept of Default Network applies to IPv6 networks. However, unlike IPv4 From 4cc1097aa53eb6c351c1272b3c59be0ff7540337 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Mon, 15 Apr 2013 14:06:42 -0700 Subject: [PATCH 094/107] Detail view: CSS fixes for edit mode -Fix scrollbars on select box -Fix apply/cancel buttons being hidden --- ui/css/cloudstack3.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 7ebda9b8f36..2b6d4976001 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1697,7 +1697,7 @@ div.list-view td.state.off span { } .detail-view .main-groups { - max-height: 455px; + max-height: 407px; overflow: auto; overflow-x: hidden; margin-right: 12px; @@ -1754,6 +1754,10 @@ div.list-view td.state.off span { width: 245px; } +.detail-group .main-groups table td.value > span select { + width: 100% !important; +} + .detail-group .main-groups table td.value .view-all { cursor: pointer; /*[empty]height:;*/ From f1b1480350c8ac5b747871885c1d92092cb438bd Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Mon, 15 Apr 2013 17:35:14 -0500 Subject: [PATCH 095/107] CLOUDSTACK-1102: Completed the What's New in 4.1 section of the release notes. Focused on features completed. May not reflect every single change. --- docs/en-US/Release_Notes.xml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml index 718f38e7df9..f449518401b 100644 --- a/docs/en-US/Release_Notes.xml +++ b/docs/en-US/Release_Notes.xml @@ -159,15 +159,13 @@ under the License.
API Request Throttling - ### -
-
- Ceph RDB Setup - ### + CLOUDSTACK-618: Limits the number of API requests per second that can be placed against a management server to avoid DoS attacks via API requests. + The throttling is controlled by the api.throttling.enabled, api.throttling.interval, and api.throttling.max configuration settings. Note that api.throttling.enabled is set to false by default.
S3 Backed Secondary Storage - ### + CLOUDSTACK-509: This enhancement backs NFS secondary storage with an S3-compatible object store. Periodically, a reaper thread synchronizes the templates, ISOs, and snapshots stored on a NFS secondary storage mount with a configured S3 object store. In addition to permitting the use of commodity or IaaS storage solutions for static assets, it provides a means of automatically synchronizing template and ISO assets across multiple zones. + See the &PRODUCT; wiki for more information on this feature, currently the documentation is incomplete.
User and Domain Admin Can Create API Key and Secret @@ -175,15 +173,16 @@ under the License.
Support Inline Mode for F5 and SRX - CLOUDSTACK-306: ### + CLOUDSTACK-306: For &PRODUCT; deployments using the Juniper SRX (firewall) and F5 Big IP (load balancer), &PRODUCT; 4.1.0 supports putting the firewall in front of the load balancer, making the firewall device the gateway and putting the load balancer behind the public network.
Egress Firewall Rules for Guest Networks - CLOUDSTACK-299: ### + CLOUDSTACK-299: This feature allows users to create egress (exit) traffic rules from private networks to public networks (e.g. from your internal network to the public Internet). By default all traffic is blocked from internal networks to the public networks, this allows you to open ports as necessary. + Egress traffic rules are suppored only on virtual routers at this time, physical devices are not supported.
Reset SSH Key to Access VM - CLOUDSTACK-297: ### + CLOUDSTACK-297: &PRODUCT; 4.1.0 introduces a new API resetSSHKeyForVirtualMachine, that can allow them to set or reset the SSH keypair assigned to a virtual machine.
From 8d33353b40f7599466a5175036c3021513cbdc81 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Mon, 15 Apr 2013 16:01:33 -0700 Subject: [PATCH 096/107] Removing the auto-wiring of AffinityGroupProcessors since this is an optional component --- client/tomcatconf/applicationContext.xml.in | 9 +++++++-- client/tomcatconf/componentContext.xml.in | 16 ++++++++++++---- .../tomcatconf/nonossComponentContext.xml.in | 16 ++++++++++++---- .../deploy/DeploymentPlanningManagerImpl.java | 14 ++++++++++++-- .../com/cloud/server/ManagementServerImpl.java | 18 ++++++++++++++---- 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 15cd6fe0f13..866e3ed3291 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -609,8 +609,10 @@ + + - + @@ -838,7 +840,10 @@ --> - + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 23284abc094..7a469816f82 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -253,9 +253,17 @@ - - - - + + + + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index a2182d183b0..2359ba80699 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -355,9 +355,17 @@ - - - - + + + + + + + + + + + + diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 92aac3775a1..c7162a2003f 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -50,11 +50,21 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; - @Inject protected List _planners; + public List getPlanners() { + return _planners; + } + public void setPlanners(List _planners) { + this._planners = _planners; + } - @Inject protected List _affinityProcessors; + public List getAffinityGroupProcessors() { + return _affinityProcessors; + } + public void setAffinityGroupProcessors(List affinityProcessors) { + this._affinityProcessors = affinityProcessors; + } @Override public DeployDestination planDeployment(VirtualMachineProfile vmProfile, diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index d9a4317d097..50b21ab27d1 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -390,8 +390,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private List _userAuthenticators; private List _userPasswordEncoders; - @Inject protected List _planners; + public List getPlanners() { + return _planners; + } + public void setPlanners(List _planners) { + this._planners = _planners; + } @Inject ClusterManager _clusterMgr; private String _hashKey = null; @@ -399,17 +404,22 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; - @Inject protected List _affinityProcessors; + public List getAffinityGroupProcessors() { + return _affinityProcessors; + } + public void setAffinityGroupProcessors(List affinityProcessors) { + this._affinityProcessors = affinityProcessors; + } public ManagementServerImpl() { setRunLevel(ComponentLifecycle.RUN_LEVEL_APPLICATION_MAINLOOP); } - + public List getUserAuthenticators() { return _userAuthenticators; } - + public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } From 34f8f795e15b89477f72aa6f1e69f7797c930db4 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Mon, 15 Apr 2013 16:51:50 -0700 Subject: [PATCH 097/107] CLOUDSTACK-2039: Improve console access security with 128-bit AES encryption and securely-randomized key generation --- .../src/com/cloud/configuration/Config.java | 2 + .../AgentBasedConsoleProxyManager.java | 8 +- .../com/cloud/consoleproxy/AgentHookBase.java | 50 +++- .../consoleproxy/ConsoleProxyManagerImpl.java | 21 +- .../com/cloud/server/ManagementServer.java | 3 + .../cloud/server/ManagementServerImpl.java | 63 ++++- .../ConsoleProxyPasswordBasedEncryptor.java | 99 +++++-- .../cloud/servlet/ConsoleProxyServlet.java | 16 +- .../ConsoleProxyPasswordBasedEncryptor.java | 253 +++++++++++------- 9 files changed, 358 insertions(+), 157 deletions(-) diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index e3e305350b1..e69ea19e979 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -305,6 +305,8 @@ public enum Config { SSOAuthTolerance("Advanced", ManagementServer.class, Long.class, "security.singlesignon.tolerance.millis", "300000", "The allowable clock difference in milliseconds between when an SSO login request is made and when it is received.", null), //NetworkType("Hidden", ManagementServer.class, String.class, "network.type", "vlan", "The type of network that this deployment will use.", "vlan,direct"), HashKey("Hidden", ManagementServer.class, String.class, "security.hash.key", null, "for generic key-ed hash", null), + EncryptionKey("Hidden", ManagementServer.class, String.class, "security.encryption.key", null, "base64 encoded key data", null), + EncryptionIV("Hidden", ManagementServer.class, String.class, "security.encryption.iv", null, "base64 encoded IV data", null), RouterRamSize("Hidden", NetworkManager.class, Integer.class, "router.ram.size", "128", "Default RAM for router VM (in MB).", null), VmOpWaitInterval("Advanced", ManagementServer.class, Integer.class, "vm.op.wait.interval", "120", "Time (in seconds) to wait before checking if a previous operation has succeeded", null), diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java index ff6e64eca94..df53e0d7d81 100755 --- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java @@ -33,6 +33,7 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.info.ConsoleProxyInfo; import com.cloud.keystore.KeystoreManager; +import com.cloud.server.ManagementServer; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.ConsoleProxyVO; @@ -69,12 +70,13 @@ public class AgentBasedConsoleProxyManager extends ManagerBase implements Consol protected KeystoreManager _ksMgr; @Inject ConfigurationDao _configDao; + @Inject ManagementServer _ms; public class AgentBasedAgentHook extends AgentHookBase { public AgentBasedAgentHook(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao cfgDao, - KeystoreManager ksMgr, AgentManager agentMgr) { - super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr); + KeystoreManager ksMgr, AgentManager agentMgr, ManagementServer ms) { + super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr, ms); } @Override @@ -120,7 +122,7 @@ public class AgentBasedConsoleProxyManager extends ManagerBase implements Consol _consoleProxyUrlDomain = configs.get("consoleproxy.url.domain"); _listener = - new ConsoleProxyListener(new AgentBasedAgentHook(_instanceDao, _hostDao, _configDao, _ksMgr, _agentMgr)); + new ConsoleProxyListener(new AgentBasedAgentHook(_instanceDao, _hostDao, _configDao, _ksMgr, _agentMgr, _ms)); _agentMgr.registerForHostEvents(_listener, true, true, false); if (s_logger.isInfoEnabled()) { diff --git a/server/src/com/cloud/consoleproxy/AgentHookBase.java b/server/src/com/cloud/consoleproxy/AgentHookBase.java index b969f6da2ce..2748a8cb68c 100644 --- a/server/src/com/cloud/consoleproxy/AgentHookBase.java +++ b/server/src/com/cloud/consoleproxy/AgentHookBase.java @@ -42,10 +42,14 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.keystore.KeystoreManager; +import com.cloud.server.ManagementServer; +import com.cloud.servlet.ConsoleProxyPasswordBasedEncryptor; import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.utils.Ternary; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.VMInstanceDao; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; /** * Utility class to manage interactions with agent-based console access @@ -60,28 +64,19 @@ public abstract class AgentHookBase implements AgentHook { ConfigurationDao _configDao; AgentManager _agentMgr; KeystoreManager _ksMgr; + ManagementServer _ms; final Random _random = new Random(System.currentTimeMillis()); private String _hashKey; public AgentHookBase(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao cfgDao, KeystoreManager ksMgr, - AgentManager agentMgr) { + AgentManager agentMgr, ManagementServer ms) { this._instanceDao = instanceDao; this._hostDao = hostDao; this._agentMgr = agentMgr; this._configDao = cfgDao; this._ksMgr = ksMgr; - } - - public String getHashKey() { - // although we may have race condition here, database transaction - // serialization should give us the same key - if (_hashKey == null) { - _hashKey = - _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), UUID - .randomUUID().toString()); - } - return _hashKey; + this._ms = ms; } public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { @@ -212,10 +207,10 @@ public abstract class AgentHookBase implements AgentHook { s_logger.error("Could not find and construct a valid SSL certificate"); } cmd = new StartConsoleProxyAgentHttpHandlerCommand(ksBits, storePassword); - cmd.setEncryptorPassword(getHashKey()); + cmd.setEncryptorPassword(getEncryptorPassword()); } else { cmd = new StartConsoleProxyAgentHttpHandlerCommand(); - cmd.setEncryptorPassword(getHashKey()); + cmd.setEncryptorPassword(getEncryptorPassword()); } try { @@ -246,6 +241,33 @@ public abstract class AgentHookBase implements AgentHook { + startupCmd.getProxyVmId(), e); } } + + private String getEncryptorPassword() { + String key; + String iv; + ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = null; + + // if we failed after reset, something is definitely wrong + for(int i = 0; i < 2; i++) { + key = _ms.getEncryptionKey(); + iv = _ms.getEncryptionIV(); + + keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv); + + if(keyIvPair.getIvBytes() == null || keyIvPair.getIvBytes().length != 16 || + keyIvPair.getKeyBytes() == null || keyIvPair.getKeyBytes().length != 16) { + + s_logger.warn("Console access AES KeyIV sanity check failed, reset and regenerate"); + _ms.resetEncryptionKeyIV(); + } else { + break; + } + } + + Gson gson = new GsonBuilder().create(); + return gson.toJson(keyIvPair); + } + protected abstract HostVO findConsoleProxyHost(StartupProxyCommand cmd); diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 9740d28a94f..c4ad8170d6d 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -95,8 +95,10 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.server.ManagementServer; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.servlet.ConsoleProxyPasswordBasedEncryptor; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.VMTemplateHostVO; @@ -220,6 +222,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy TemplateManager templateMgr; @Inject IPAddressDao _ipAddressDao; + @Inject + ManagementServer _ms; private ConsoleProxyListener _listener; @@ -254,7 +258,6 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy private Map _zoneProxyCountMap; // map private Map _zoneVmCountMap; // map - private String _hashKey; private String _staticPublicIp; private int _staticPort; @@ -448,8 +451,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy public class VmBasedAgentHook extends AgentHookBase { public VmBasedAgentHook(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao cfgDao, - KeystoreManager ksMgr, AgentManager agentMgr) { - super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr); + KeystoreManager ksMgr, AgentManager agentMgr, ManagementServer ms) { + super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr, ms); } @Override @@ -1439,7 +1442,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy _listener = new ConsoleProxyListener(new VmBasedAgentHook(_instanceDao, _hostDao, _configDao, _ksMgr, - _agentMgr)); + _agentMgr, _ms)); _agentMgr.registerForHostEvents(_listener, true, true, false); _itMgr.registerGuru(VirtualMachine.Type.ConsoleProxy, this); @@ -1884,15 +1887,6 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy return sc.find(); } - public String getHashKey() { - // although we may have race conditioning here, database transaction serialization should - // give us the same key - if (_hashKey == null) { - _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), UUID.randomUUID().toString()); - } - return _hashKey; - } - @Override public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, @@ -1912,4 +1906,5 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy @Override public void prepareStop(VirtualMachineProfile profile) { } + } diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java index 6773725f361..240464e4938 100755 --- a/server/src/com/cloud/server/ManagementServer.java +++ b/server/src/com/cloud/server/ManagementServer.java @@ -95,6 +95,9 @@ public interface ManagementServer extends ManagementService, PluggableService { Pair, Integer> searchForStoragePools(Criteria c); String getHashKey(); + String getEncryptionKey(); + String getEncryptionIV(); + void resetEncryptionKeyIV(); public void enableAdminUser(String password); } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 50b21ab27d1..5ed0c923cc0 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -22,6 +22,8 @@ import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.Calendar; import java.util.Comparator; @@ -400,7 +402,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject ClusterManager _clusterMgr; private String _hashKey = null; - + private String _encryptionKey = null; + private String _encryptionIV = null; + @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @@ -3000,15 +3004,66 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public String getHashKey() { - // although we may have race conditioning here, database transaction - // serialization should + // although we may have race conditioning here, database transaction serialization should // give us the same key if (_hashKey == null) { - _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), UUID.randomUUID().toString()); + _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), + getBase64EncodedRandomKey(128)); } return _hashKey; } + @Override + public String getEncryptionKey() { + if (_encryptionKey == null) { + _encryptionKey = _configDao.getValueAndInitIfNotExist(Config.EncryptionKey.key(), + Config.EncryptionKey.getCategory(), + getBase64EncodedRandomKey(128)); + } + return _encryptionKey; + } + + @Override + public String getEncryptionIV() { + if (_encryptionIV == null) { + _encryptionIV = _configDao.getValueAndInitIfNotExist(Config.EncryptionIV.key(), + Config.EncryptionIV.getCategory(), + getBase64EncodedRandomKey(128)); + } + return _encryptionIV; + } + + @Override + @DB + public void resetEncryptionKeyIV() { + + SearchBuilder sb = _configDao.createSearchBuilder(); + sb.and("name1", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.or("name2", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("name1", Config.EncryptionKey.key()); + sc.setParameters("name2", Config.EncryptionIV.key()); + + _configDao.expunge(sc); + _encryptionKey = null; + _encryptionIV = null; + } + + private static String getBase64EncodedRandomKey(int nBits) { + SecureRandom random; + try { + random = SecureRandom.getInstance("SHA1PRNG"); + byte[] keyBytes = new byte[nBits/8]; + random.nextBytes(keyBytes); + return Base64.encodeBase64URLSafeString(keyBytes); + } catch (NoSuchAlgorithmException e) { + s_logger.error("Unhandled exception: ", e); + } + return null; + } + @Override public SSHKeyPair createSSHKeyPair(CreateSSHKeyPairCmd cmd) { Account caller = UserContext.current().getCaller(); diff --git a/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java b/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java index 2638c8b31b9..7463ec097f3 100644 --- a/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java +++ b/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java @@ -16,13 +16,16 @@ // under the License. package com.cloud.servlet; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; @@ -35,26 +38,26 @@ import com.google.gson.GsonBuilder; public class ConsoleProxyPasswordBasedEncryptor { private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class); - private String password; private Gson gson; + // key/IV will be set in 128 bit strength + private KeyIVPair keyIvPair; + public ConsoleProxyPasswordBasedEncryptor(String password) { - this.password = password; gson = new GsonBuilder().create(); + keyIvPair = gson.fromJson(password, KeyIVPair.class); } public String encryptText(String text) { if(text == null || text.isEmpty()) return text; - assert(password != null); - assert(!password.isEmpty()); - try { - Cipher cipher = Cipher.getInstance("DES"); - int maxKeySize = 8; - SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES"); - cipher.init(Cipher.ENCRYPT_MODE, keySpec); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES"); + + cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes())); + byte[] encryptedBytes = cipher.doFinal(text.getBytes()); return Base64.encodeBase64URLSafeString(encryptedBytes); } catch (NoSuchAlgorithmException e) { @@ -72,6 +75,9 @@ public class ConsoleProxyPasswordBasedEncryptor { } catch (InvalidKeyException e) { s_logger.error("Unexpected exception ", e); return null; + } catch (InvalidAlgorithmParameterException e) { + s_logger.error("Unexpected exception ", e); + return null; } } @@ -79,14 +85,10 @@ public class ConsoleProxyPasswordBasedEncryptor { if(encryptedText == null || encryptedText.isEmpty()) return encryptedText; - assert(password != null); - assert(!password.isEmpty()); - try { - Cipher cipher = Cipher.getInstance("DES"); - int maxKeySize = 8; - SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES"); - cipher.init(Cipher.DECRYPT_MODE, keySpec); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes())); byte[] encryptedBytes = Base64.decodeBase64(encryptedText); return new String(cipher.doFinal(encryptedBytes)); @@ -105,6 +107,9 @@ public class ConsoleProxyPasswordBasedEncryptor { } catch (InvalidKeyException e) { s_logger.error("Unexpected exception ", e); return null; + } catch (InvalidAlgorithmParameterException e) { + s_logger.error("Unexpected exception ", e); + return null; } } @@ -125,13 +130,63 @@ public class ConsoleProxyPasswordBasedEncryptor { return (T)gson.fromJson(json, clz); } - private static byte[] normalizeKey(byte[] keyBytes, int keySize) { - assert(keySize > 0); - byte[] key = new byte[keySize]; + public static class KeyIVPair { + String base64EncodedKeyBytes; + String base64EncodedIvBytes; - for(int i = 0; i < keyBytes.length; i++) - key[i%keySize] ^= keyBytes[i]; + public KeyIVPair() { + } - return key; + public KeyIVPair(String base64EncodedKeyBytes, String base64EncodedIvBytes) { + this.base64EncodedKeyBytes = base64EncodedKeyBytes; + this.base64EncodedIvBytes = base64EncodedIvBytes; + } + + public byte[] getKeyBytes() { + return Base64.decodeBase64(base64EncodedKeyBytes); + } + + public void setKeyBytes(byte[] keyBytes) { + base64EncodedKeyBytes = Base64.encodeBase64URLSafeString(keyBytes); + } + + public byte[] getIvBytes() { + return Base64.decodeBase64(base64EncodedIvBytes); + } + + public void setIvBytes(byte[] ivBytes) { + base64EncodedIvBytes = Base64.encodeBase64URLSafeString(ivBytes); + } } + + public static void main(String[] args) { + SecureRandom random; + try { + random = SecureRandom.getInstance("SHA1PRNG"); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + + byte[] ivBytes = new byte[16]; + random.nextBytes(ivBytes); + + KeyIVPair keyIvPair = new KeyIVPair("8x/xUBgX0Up+3UEo39dSeG277JhVj31+ElHkN5+EC0Q=", "Y2SUiIN6JXTdKNK/ZMDyVtLB7gAM9MCCiyrP1xd3bSQ="); + //keyIvPair.setKeyBytes(keyBytes); + //keyIvPair.setIvBytes(ivBytes); + + Gson gson = new GsonBuilder().create(); + ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(gson.toJson(keyIvPair)); + + String encrypted = encryptor.encryptText("Hello, world"); + + System.out.println("Encrypted result: " + encrypted); + + String decrypted = encryptor.decryptText(encrypted); + + System.out.println("Decrypted result: " + decrypted); + + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } } + diff --git a/server/src/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/com/cloud/servlet/ConsoleProxyServlet.java index c4b93349080..ebb91746268 100644 --- a/server/src/com/cloud/servlet/ConsoleProxyServlet.java +++ b/server/src/com/cloud/servlet/ConsoleProxyServlet.java @@ -55,6 +55,8 @@ import com.cloud.utils.db.Transaction; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineManager; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; /** * Thumbnail access : /console?cmd=thumbnail&vm=xxx&w=xxx&h=xxx @@ -75,6 +77,8 @@ public class ConsoleProxyServlet extends HttpServlet { static ManagementServer s_ms; + private Gson _gson = new GsonBuilder().create(); + public ConsoleProxyServlet() { } @@ -327,6 +331,14 @@ public class ConsoleProxyServlet extends HttpServlet { return new Ternary(host, tunnelUrl, tunnelSession); } + private String getEncryptorPassword() { + String key = _ms.getEncryptionKey(); + String iv = _ms.getEncryptionIV(); + + ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv); + return _gson.toJson(keyIvPair); + } + private String composeThumbnailUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo, int w, int h) { StringBuffer sb = new StringBuffer(rootUrl); @@ -340,7 +352,7 @@ public class ConsoleProxyServlet extends HttpServlet { tag = _identityService.getIdentityUuid("vm_instance", tag); String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag); - ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey()); + ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword()); ConsoleProxyClientParam param = new ConsoleProxyClientParam(); param.setClientHostAddress(parsedHostInfo.first()); param.setClientHostPort(portInfo.second()); @@ -376,7 +388,7 @@ public class ConsoleProxyServlet extends HttpServlet { String tag = String.valueOf(vm.getId()); tag = _identityService.getIdentityUuid("vm_instance", tag); String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag); - ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey()); + ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword()); ConsoleProxyClientParam param = new ConsoleProxyClientParam(); param.setClientHostAddress(parsedHostInfo.first()); param.setClientHostPort(portInfo.second()); diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java index 29826f0ea92..5a7241ac7e5 100644 --- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java +++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java @@ -16,13 +16,16 @@ // under the License. package com.cloud.consoleproxy; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; @@ -33,110 +36,162 @@ import com.google.gson.GsonBuilder; /** * - * A simple password based encyrptor based on DES. It can serialize simple POJO object into URL safe string + * @author Kelven Yang + * A simple password based encyrptor based on AES/CBC. It can serialize simple POJO object into URL safe string * and deserialize it back. * */ public class ConsoleProxyPasswordBasedEncryptor { - private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class); - - private String password; - private Gson gson; - - public ConsoleProxyPasswordBasedEncryptor(String password) { - this.password = password; - gson = new GsonBuilder().create(); - } - - public String encryptText(String text) { - if(text == null || text.isEmpty()) - return text; - - assert(password != null); - assert(!password.isEmpty()); - - try { - Cipher cipher = Cipher.getInstance("DES"); - int maxKeySize = 8; - SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES"); - cipher.init(Cipher.ENCRYPT_MODE, keySpec); - byte[] encryptedBytes = cipher.doFinal(text.getBytes()); - return Base64.encodeBase64URLSafeString(encryptedBytes); - } catch (NoSuchAlgorithmException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (NoSuchPaddingException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (IllegalBlockSizeException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (BadPaddingException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (InvalidKeyException e) { - s_logger.error("Unexpected exception ", e); - return null; - } - } + private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class); + + private Gson gson; + + // key/IV will be set in 128 bit strength + private KeyIVPair keyIvPair; + + public ConsoleProxyPasswordBasedEncryptor(String password) { + gson = new GsonBuilder().create(); + keyIvPair = gson.fromJson(password, KeyIVPair.class); + } + + public String encryptText(String text) { + if(text == null || text.isEmpty()) + return text; + + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES"); - public String decryptText(String encryptedText) { - if(encryptedText == null || encryptedText.isEmpty()) - return encryptedText; + cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes())); + + byte[] encryptedBytes = cipher.doFinal(text.getBytes()); + return Base64.encodeBase64URLSafeString(encryptedBytes); + } catch (NoSuchAlgorithmException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (NoSuchPaddingException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (IllegalBlockSizeException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (BadPaddingException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (InvalidKeyException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (InvalidAlgorithmParameterException e) { + s_logger.error("Unexpected exception ", e); + return null; + } + } - assert(password != null); - assert(!password.isEmpty()); + public String decryptText(String encryptedText) { + if(encryptedText == null || encryptedText.isEmpty()) + return encryptedText; - try { - Cipher cipher = Cipher.getInstance("DES"); - int maxKeySize = 8; - SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize), "DES"); - cipher.init(Cipher.DECRYPT_MODE, keySpec); - - byte[] encryptedBytes = Base64.decodeBase64(encryptedText); - return new String(cipher.doFinal(encryptedBytes)); - } catch (NoSuchAlgorithmException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (NoSuchPaddingException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (IllegalBlockSizeException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (BadPaddingException e) { - s_logger.error("Unexpected exception ", e); - return null; - } catch (InvalidKeyException e) { - s_logger.error("Unexpected exception ", e); - return null; - } - } - - public String encryptObject(Class clz, T obj) { - if(obj == null) - return null; - - String json = gson.toJson(obj); - return encryptText(json); - } - - @SuppressWarnings("unchecked") - public T decryptObject(Class clz, String encrypted) { - if(encrypted == null || encrypted.isEmpty()) - return null; - - String json = decryptText(encrypted); - return (T)gson.fromJson(json, clz); - } - - private static byte[] normalizeKey(byte[] keyBytes, int keySize) { - assert(keySize > 0); - byte[] key = new byte[keySize]; - - for(int i = 0; i < keyBytes.length; i++) - key[i%keySize] ^= keyBytes[i]; - - return key; - } + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes())); + + byte[] encryptedBytes = Base64.decodeBase64(encryptedText); + return new String(cipher.doFinal(encryptedBytes)); + } catch (NoSuchAlgorithmException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (NoSuchPaddingException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (IllegalBlockSizeException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (BadPaddingException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (InvalidKeyException e) { + s_logger.error("Unexpected exception ", e); + return null; + } catch (InvalidAlgorithmParameterException e) { + s_logger.error("Unexpected exception ", e); + return null; + } + } + + public String encryptObject(Class clz, T obj) { + if(obj == null) + return null; + + String json = gson.toJson(obj); + return encryptText(json); + } + + @SuppressWarnings("unchecked") + public T decryptObject(Class clz, String encrypted) { + if(encrypted == null || encrypted.isEmpty()) + return null; + + String json = decryptText(encrypted); + return (T)gson.fromJson(json, clz); + } + + public static class KeyIVPair { + String base64EncodedKeyBytes; + String base64EncodedIvBytes; + + public KeyIVPair() { + } + + public KeyIVPair(String base64EncodedKeyBytes, String base64EncodedIvBytes) { + this.base64EncodedKeyBytes = base64EncodedKeyBytes; + this.base64EncodedIvBytes = base64EncodedIvBytes; + } + + public byte[] getKeyBytes() { + return Base64.decodeBase64(base64EncodedKeyBytes); + } + + public void setKeyBytes(byte[] keyBytes) { + base64EncodedKeyBytes = Base64.encodeBase64URLSafeString(keyBytes); + } + + public byte[] getIvBytes() { + return Base64.decodeBase64(base64EncodedIvBytes); + } + + public void setIvBytes(byte[] ivBytes) { + base64EncodedIvBytes = Base64.encodeBase64URLSafeString(ivBytes); + } + } + + public static void main(String[] args) { + SecureRandom random; + try { + random = SecureRandom.getInstance("SHA1PRNG"); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + + byte[] ivBytes = new byte[16]; + random.nextBytes(ivBytes); + + KeyIVPair keyIvPair = new KeyIVPair("8x/xUBgX0Up+3UEo39dSeG277JhVj31+ElHkN5+EC0Q=", "Y2SUiIN6JXTdKNK/ZMDyVtLB7gAM9MCCiyrP1xd3bSQ="); + //keyIvPair.setKeyBytes(keyBytes); + //keyIvPair.setIvBytes(ivBytes); + + Gson gson = new GsonBuilder().create(); + ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(gson.toJson(keyIvPair)); + + String encrypted = encryptor.encryptText("Hello, world"); + + System.out.println("Encrypted result: " + encrypted); + + String decrypted = encryptor.decryptText(encrypted); + + System.out.println("Decrypted result: " + decrypted); + + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } } From 23211d1483710682d3ae1862d29e6f1ca5cc7aef Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 15 Apr 2013 17:07:57 -0700 Subject: [PATCH 098/107] CLOUDSTACK-1974: cloudstack UI - Infrastructure menu - zone detail - public traffic type - IP Ranges tab - show new action "Release from account", "Add Account" action. --- ui/scripts/system.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index f74711d273d..a9054125774 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -597,7 +597,7 @@ }); } }, - /* + releaseFromAccount: { label: 'Release from Account', action: function(args) { @@ -622,6 +622,7 @@ }); } }, + addAccount: { label: 'Add Account', createForm: { @@ -675,7 +676,7 @@ }); } } - */ + }, dataProvider: function(args) { $.ajax({ From 51b4ee26ecff24ecf1690926161e085035e66a42 Mon Sep 17 00:00:00 2001 From: Joe Brockmeier Date: Mon, 15 Apr 2013 22:34:43 -0500 Subject: [PATCH 099/107] Updating build_asf.sh to remove incubating references. --- tools/build/build_asf.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/build/build_asf.sh b/tools/build/build_asf.sh index c652a20bf42..c692febb143 100755 --- a/tools/build/build_asf.sh +++ b/tools/build/build_asf.sh @@ -81,21 +81,21 @@ fi cd $sourcedir echo 'archiving' -git archive --format=tar --prefix=apache-cloudstack-$version-incubating-src/ $branch > $outputdir/apache-cloudstack-$version-incubating-src.tar -bzip2 $outputdir/apache-cloudstack-$version-incubating-src.tar +git archive --format=tar --prefix=apache-cloudstack-$version-src/ $branch > $outputdir/apache-cloudstack-$version-src.tar +bzip2 $outputdir/apache-cloudstack-$version-src.tar cd $outputdir echo 'armor' -gpg -v $keyid --armor --output apache-cloudstack-$version-incubating-src.tar.bz2.asc --detach-sig apache-cloudstack-$version-incubating-src.tar.bz2 +gpg -v $keyid --armor --output apache-cloudstack-$version-src.tar.bz2.asc --detach-sig apache-cloudstack-$version-src.tar.bz2 echo 'md5' -gpg -v --print-md MD5 apache-cloudstack-$version-incubating-src.tar.bz2 > apache-cloudstack-$version-incubating-src.tar.bz2.md5 +gpg -v --print-md MD5 apache-cloudstack-$version-src.tar.bz2 > apache-cloudstack-$version-src.tar.bz2.md5 echo 'sha' -gpg -v --print-md SHA512 apache-cloudstack-$version-incubating-src.tar.bz2 > apache-cloudstack-$version-incubating-src.tar.bz2.sha +gpg -v --print-md SHA512 apache-cloudstack-$version-src.tar.bz2 > apache-cloudstack-$version-src.tar.bz2.sha echo 'verify' -gpg -v --verify apache-cloudstack-$version-incubating-src.tar.bz2.asc apache-cloudstack-$version-incubating-src.tar.bz2 +gpg -v --verify apache-cloudstack-$version-src.tar.bz2.asc apache-cloudstack-$version-src.tar.bz2 if [ $tag == 'yes' ]; then echo 'tag' From 7bff1d08f4f331301fdefb0f70468e8436392b96 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 16 Apr 2013 10:40:02 +0530 Subject: [PATCH 100/107] CLOUDSTACK-2020: Make cli's requester unicode friendly Fixed list processing that uses lambdas to use x.lower() assuming x is string, and not forced/caster str.lower(obj) Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/requester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cli/cloudmonkey/requester.py b/tools/cli/cloudmonkey/requester.py index 88967fed74d..d2dae6dfc3f 100644 --- a/tools/cli/cloudmonkey/requester.py +++ b/tools/cli/cloudmonkey/requester.py @@ -61,11 +61,11 @@ def make_request(command, args, logger, host, port, args["apiKey"] = apikey args["response"] = "json" request = zip(args.keys(), args.values()) - request.sort(key=lambda x: str.lower(x[0])) + request.sort(key=lambda x: x[0].lower()) request_url = "&".join(["=".join([r[0], urllib.quote_plus(str(r[1]))]) for r in request]) - hashStr = "&".join(["=".join([str.lower(r[0]), + hashStr = "&".join(["=".join([r[0].lower(), str.lower(urllib.quote_plus(str(r[1]))).replace("+", "%20")]) for r in request]) From cbe021b8d2867a4c02d1797e722e38b322a17c06 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 16 Apr 2013 12:38:52 +0800 Subject: [PATCH 101/107] CLOUDSTACK-2040 VM with snapshot not getting destroyed during account delation --- .../cloud/agent/api/DeleteSnapshotBackupCommand.java | 6 ++++-- .../image/driver/AncientImageDataStoreDriverImpl.java | 10 +++++++--- .../cloud/storage/snapshot/SnapshotManagerImpl.java | 11 +++++------ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/api/src/com/cloud/agent/api/DeleteSnapshotBackupCommand.java b/api/src/com/cloud/agent/api/DeleteSnapshotBackupCommand.java index 6114148954f..128df84c729 100644 --- a/api/src/com/cloud/agent/api/DeleteSnapshotBackupCommand.java +++ b/api/src/com/cloud/agent/api/DeleteSnapshotBackupCommand.java @@ -19,6 +19,7 @@ package com.cloud.agent.api; import com.cloud.agent.api.LogLevel.Log4jLevel; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; +import com.cloud.storage.StoragePool; /** * This command encapsulates a primitive operation which enables coalescing the backed up VHD snapshots on the secondary server @@ -78,7 +79,8 @@ public class DeleteSnapshotBackupCommand extends SnapshotCommand { * @param backupUUID The VHD which has to be deleted * @param childUUID The child VHD file of the backup whose parent is reset to its grandparent. */ - public DeleteSnapshotBackupCommand(SwiftTO swift, + public DeleteSnapshotBackupCommand(StoragePool pool, + SwiftTO swift, S3TO s3, String secondaryStoragePoolURL, Long dcId, @@ -86,7 +88,7 @@ public class DeleteSnapshotBackupCommand extends SnapshotCommand { Long volumeId, String backupUUID, Boolean all) { - super(null, secondaryStoragePoolURL, backupUUID, null, dcId, accountId, volumeId); + super(pool, secondaryStoragePoolURL, backupUUID, null, dcId, accountId, volumeId); setSwift(swift); this.s3 = s3; setAll(all); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java index 97ea6c48c79..4c16f2fe4b1 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java @@ -33,6 +33,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; import org.apache.log4j.Logger; @@ -45,8 +47,8 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.storage.RegisterVolumePayload; -import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; @@ -80,6 +82,7 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver { @Inject SnapshotDao snapshotDao; @Inject AgentManager agentMgr; @Inject SnapshotManager snapshotMgr; + @Inject PrimaryDataStoreDao primaryDataStoreDao; @Inject private SwiftManager _swiftMgr; @Inject @@ -196,9 +199,10 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver { } SwiftTO swift = _swiftMgr.getSwiftTO(snapshot.getSwiftId()); S3TO s3 = _s3Mgr.getS3TO(); - + VolumeVO volume = volumeDao.findById(volumeId); + StoragePoolVO pool = primaryDataStoreDao.findById(volume.getPoolId()); DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId, + pool, swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId, backupOfSnapshot, false); Answer answer = agentMgr.sendToSSVM(dcId, cmd); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 3a453d50a72..490948ba5ae 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -181,9 +181,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private ResourceTagDao _resourceTagDao; @Inject private ConfigurationDao _configDao; - - @Inject - private VMSnapshotDao _vmSnapshotDao; + @Inject + private PrimaryDataStoreDao _primaryDataStoreDao; String _name; @Inject TemplateManager templateMgr; @@ -694,11 +693,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, S3TO s3 = _s3Mgr.getS3TO(); checkObjectStorageConfiguration(swift, s3); - + StoragePoolVO pool = _primaryDataStoreDao.findById(volume.getPoolId()); if (swift == null && s3 == null) { for (HostVO ssHost : ssHosts) { DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - null, null, ssHost.getStorageUrl(), dcId, + pool,null, null, ssHost.getStorageUrl(), dcId, accountId, volumeId, "", true); Answer answer = null; try { @@ -717,7 +716,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } else { DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - swift, s3, "", dcId, accountId, volumeId, "", true); + pool,swift, s3, "", dcId, accountId, volumeId, "", true); Answer answer = null; try { answer = _agentMgr.sendToSSVM(dcId, cmd); From ce3337cdd6a26285348b972d37647c36e956bc40 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 16 Apr 2013 11:14:50 +0800 Subject: [PATCH 102/107] CLOUDSTACK-1983 StackOverflowError while deleting snapshot --- .../org/apache/cloudstack/storage/snapshot/SnapshotObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java index d10dc778092..37238b72121 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java @@ -106,7 +106,7 @@ public class SnapshotObject implements SnapshotInfo { @Override public Long getSize() { - return this.getSize(); + return this.snapshot.getSize(); } @Override From 3f9ee4049a01bade256e28e1ff4015dff58fd7dc Mon Sep 17 00:00:00 2001 From: Jessica Tomechak Date: Mon, 15 Apr 2013 23:10:10 -0700 Subject: [PATCH 103/107] Docs. Remove "incubating" from software version number on title pages. --- docs/en-US/Admin_Guide.xml | 2 +- docs/en-US/Book_Info.xml | 2 +- docs/en-US/CloudStack_Nicira_NVP_Guide.xml | 2 +- docs/en-US/Developers_Guide.xml | 2 +- docs/en-US/Installation_Guide.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/en-US/Admin_Guide.xml b/docs/en-US/Admin_Guide.xml index 07f5e889fc8..d3b9706f84e 100644 --- a/docs/en-US/Admin_Guide.xml +++ b/docs/en-US/Admin_Guide.xml @@ -26,7 +26,7 @@ &PRODUCT; Administrator's Guide Apache CloudStack - 4.0.0-incubating + 4.2.0 1 diff --git a/docs/en-US/Book_Info.xml b/docs/en-US/Book_Info.xml index 0ab84c40d9b..327668dfc9d 100644 --- a/docs/en-US/Book_Info.xml +++ b/docs/en-US/Book_Info.xml @@ -27,7 +27,7 @@ &PRODUCT; Guide Revised August 9, 2012 10:48 pm Pacific Apache CloudStack - 4.0.0 + 4.2.0 1 diff --git a/docs/en-US/CloudStack_Nicira_NVP_Guide.xml b/docs/en-US/CloudStack_Nicira_NVP_Guide.xml index a4c367c26f7..7f156d5dc09 100644 --- a/docs/en-US/CloudStack_Nicira_NVP_Guide.xml +++ b/docs/en-US/CloudStack_Nicira_NVP_Guide.xml @@ -28,7 +28,7 @@ &PRODUCT; Plugin Guide for the Nicira NVP Plugin Apache CloudStack - 4.0.0-incubating + 4.2.0 1 diff --git a/docs/en-US/Developers_Guide.xml b/docs/en-US/Developers_Guide.xml index c86208b3271..87dc8a6675a 100644 --- a/docs/en-US/Developers_Guide.xml +++ b/docs/en-US/Developers_Guide.xml @@ -26,7 +26,7 @@ &PRODUCT; Developer's Guide Apache CloudStack - 4.1.0-incubating + 4.2.0 diff --git a/docs/en-US/Installation_Guide.xml b/docs/en-US/Installation_Guide.xml index 6ce5527e86c..e6a80318611 100644 --- a/docs/en-US/Installation_Guide.xml +++ b/docs/en-US/Installation_Guide.xml @@ -25,7 +25,7 @@ &PRODUCT; Installation Guide Apache CloudStack - 4.0.0 + 4.2.0 1 From 50b4c9cbdde70e040126a7cc2538937820fbd02d Mon Sep 17 00:00:00 2001 From: Jessica Tomechak Date: Mon, 15 Apr 2013 23:11:31 -0700 Subject: [PATCH 104/107] CLOUDSTACK-1561. Docs. Add new feature VM Snapshots. --- docs/en-US/images/VMSnapshotButton.png | Bin 0 -> 967 bytes docs/en-US/images/revert-vm.png | Bin 0 -> 860 bytes docs/en-US/virtual-machines.xml | 1 + docs/en-US/vm-snapshots.xml | 146 +++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 docs/en-US/images/VMSnapshotButton.png create mode 100644 docs/en-US/images/revert-vm.png create mode 100644 docs/en-US/vm-snapshots.xml diff --git a/docs/en-US/images/VMSnapshotButton.png b/docs/en-US/images/VMSnapshotButton.png new file mode 100644 index 0000000000000000000000000000000000000000..52177402198bcfae494b382ef49950147a3dfe33 GIT binary patch literal 967 zcmV;&133JNP)X0ssI2saFY200001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D16)Z&K~zXfy_4xq z8etSb=izE>(_c*!)7H9y3o4-Oivu#w0K+Wo?l!4yt*O?nZiosh3e{@eMLbv3smsq@S5K_a*K7D7&U8JUOx5>Wf~y%%*@*yZsa79+SrM3l$BQ&ye#Bb2;@qw&OqofBTT5M zURKJhC@e0$%ZtLIXU_{V4G?>#{a5Palhf~8VGi6xvJRIXGokt>@B;7$V8;myYj@JD z9THcnQKd!)z`0!2z$>rHG(bEt<+IwHNc=dtwz7Ng7??!0G0V%s$+VxFFXi264;<3qTmUSSp!+7Z1I!6;>rWl*m z?t)5#TBX%{eRE@;85o#XMI}&Kp;!`JUhC=oBvWW4GL=G&f;!Ux@$l#*#jr>;daxK; z;lKzJMO)!IX|+VIT38Hqzw0Tls!^yKqzZLed6jo|u77Yyrqn{>&=Q!UOasIN!(T{> z26b#Pw9Ii!Etbgp2ZkoSGb$|#{R9z)n--QrE$tnUb-EeX>OTgE2Zl$k)RAZ`5M1Vf zFClBI?WQ1bWtiyD@~X!>)7;hpbq@qXv;GB{LJgPT)R_i|KM#$NmiyEe+D0+quIi!(MAn?c|9Rgxw^QN55rq8m5apE zk}^K8LI5eJ7b;zltg@C!(qfe&5q; zXd;XxZKkXoCdx{X40Hi7k_jbv p%=O>19-r`%j5D{WQA|)R`VB!eA8@PBwo(89002ovPDHLkV1i^}yX0ssI2saFY200001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0`W;iK~zXf<&;@Z zT2T~*@4su)m!|1MHA+e4Szj^x(F@d$(J>ht!NApw3=JLtpDyZJLPhDQO6Hn!JdJ~>N8W@5hP?&KP z204Mn6J|8qd!W?O@+4Xv9;r+T-PD^uvxRmJbOzW69F9bj$aDsaOQtcgQ-l#X^3x!U z!&?kRlO0_x(Q0?E$rMoS<~EVex8w1L6{<}dV~#b)V{;aG{ADh0iArZpO_PRTqY{}i zlE`#40`csJOCps+)mkH-%C(csT;&R7v(>&R5YMvbcXqY@U|6}a1>S%_q##jPlf}`| z2t>2hxeB5y)p{(M?Z#!kE<$7?5h$PbX~53 zjq5=?l?C$}O=qAdnn-W&YC$w{h9;3Jy15Le7V(M%Di%xrP~;gFoAayo8%WU`OrR8w zC8CK`t4FR>gB>SRXTi;FH@1``!--HN2GQ64Q1}_z{lkI5;rAatj=~W-z2T_}JY*`P z6}`8A&~9ugM+W1+=tA+@7Yskc?eWj^mvHzmV~7b1W=grCIn?RZnr%Fuh{oaROb(AP zaJW3}#+LH^*tjh05*@gR*qv_ff`CF}qA-)-f{%=i4}Ts*qHz>Di^=95pPUB6(bq(K z0~g^~(&0K6t*lWQYyycgIZXsBcm@~TaAJ + diff --git a/docs/en-US/vm-snapshots.xml b/docs/en-US/vm-snapshots.xml new file mode 100644 index 00000000000..8d4bcf9bca1 --- /dev/null +++ b/docs/en-US/vm-snapshots.xml @@ -0,0 +1,146 @@ + + +%BOOK_ENTITIES; +]> + + +
+ Virtual Machine Snapshots for VMware + (VMware hosts only) + In addition to the existing &PRODUCT; ability to snapshot VM volumes, + you can now take a VM snapshot to preserve all of the VM's state and data. + This is useful for quick restore of a VM. + For example, you can snapshot a VM, then make changes such as software upgrades. + If anything goes wrong, simply restore the VM to its previous state using the previously saved VM snapshot. + + The snapshot is created using the VMware native snapshot facility. The VM snapshot + includes not only the data volumes, but optionally also whether the VM is running or + turned off (CPU state) and the memory contents. The snapshot is stored in &PRODUCT;'s + primary storage. + VM snapshots can have a parent/child relationship. + Each successive snapshot of the same VM is the child of the snapshot that came before it. + Each time you take an additional snapshot of the same VM, it saves only the differences + between the current state of the VM and the state stored in the most recent previous snapshot. + The previous snapshot becomes a parent, and the new snapshot is its child. + It is possible to create a long chain of these parent/child snapshots, + which amount to a "redo" record leading from the current state of the VM back to the + original. + If you need more information about VM snapshots, check out the VMware documentation + and the VMware Knowledge Base, especially + Understanding virtual machine snapshots. +
+ Limitations on VM Snapshots + + If a VM has some stored snapshots, you can't attach new volume to the VM + or delete any existing volumes. + If you change the volumes on the VM, it would become impossible to restore the VM snapshot + which was created with the previous volume structure. + VM snapshots which include both data volumes and memory can't be kept if you change the VM's + service offering. Any existing VM snapshots of this type will be discarded. + + You can't make a VM snapshot at the same time as you are taking a volume + snapshot. + + + The "quiesce" option is not supported. This option is provided by the underlying + VMware snapshot facility so that you can choose whether to quiesce the file system + on a running virtual machine before taking the snapshot. In &PRODUCT;, the quiesce option is always + set to false; the file system is not quiesced before taking a snapshot of a running VM. + + + You should use only &PRODUCT; to create VM snapshots on VMware hosts managed by &PRODUCT;. + Any snapshots that you make directly on vSphere will not be tracked in &PRODUCT;. + +
+
+ Configuring VM Snapshots + The cloud administrator can use global configuration variables to control the behavior of VM snapshots. + To set these variables, go through the Global Settings are of the UI. + + + + + Configuration Setting Name + Description + + + + + vmsnapshots.max + The maximum number of VM snapshots that can be saved for any given virtual machine in the cloud. + The total possible number of VM snapshots in the cloud is (number of VMs) * vmsnapshots.max. + If the number of snapshots for any VM ever hits the maximum, the older ones are removed + by the snapshot expunge job. + + + + vmsnapshot.create.wait + Number of seconds to wait for a snapshot job to succeed before declaring failure and issuing an error. + + + + +
+
+ Using VM Snapshots + To create a VM snapshot using the &PRODUCT; UI: + + Log in to the &PRODUCT; UI as a user or administrator. + Click Instances. + Click the name of the VM you want to snapshot. + Click the Take VM Snapshot button. + + + + + + If a snapshot is already in progress, then clicking this button will have no effect. + + Provide a name and description. These will be displayed in the VM Snapshots list. + (For running VMs only) If you want to include the VM's memory in the snapshot, click the + Memory checkbox. This saves the CPU and memory state of the virtual machine. If you + don't check this box, then only the current state of the VM disk is saved. Checking + this box makes the snapshot take longer. + Click OK. + + To delete a snapshot or restore a VM to the state saved in a particular snapshot: + + Navigate to the VM as described in the earlier steps. + Click View VM Snapshots. + In the list of snapshots, click the name of the snapshot you want to work with. + Depending on what you want to do: + To delete the snapshot, click the Delete button. + + + + + + To revert to the snapshot, click the Revert button. + + + + + + + + VM snapshots are deleted automatically when a VM is destroyed. + You don't have to manually delete the snapshots in this case. +
+
From 32c7e1d88007dc271eba8a3bf53877b2050cd30f Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 16 Apr 2013 13:54:16 +0530 Subject: [PATCH 105/107] fix up the hostaffinity processors from loading hostaffinity don't load by default anymore Signed-off-by: Prasanna Santhanam --- client/tomcatconf/simulatorComponentContext.xml.in | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in index 435b9e2fc62..9d8c6c0ce93 100644 --- a/client/tomcatconf/simulatorComponentContext.xml.in +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -218,12 +218,19 @@ class="org.apache.cloudstack.region.gslb.GlobalLoadBalancingRulesServiceImpl"/> + + + + + + + From 574e716352290f9c34bfa7bd3134a13e0caa8da2 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Tue, 16 Apr 2013 10:52:17 +0200 Subject: [PATCH 106/107] CLOUDSTACK-2033 Fix usage server startup and logging Properly implement the Daemon interface Initialize logging when the usage server is started as a daemon Fix a few minor startup and packaging items. --- build/replace.properties | 1 + packaging/centos63/cloud-usage.rc | 2 +- packaging/centos63/cloud.spec | 9 +-------- packaging/centos63/replace.properties | 2 +- usage/pom.xml | 5 +++++ usage/src/com/cloud/usage/UsageServer.java | 16 ++++++++++++---- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/build/replace.properties b/build/replace.properties index c9a93c2831c..265f3358724 100644 --- a/build/replace.properties +++ b/build/replace.properties @@ -27,3 +27,4 @@ MSMNTDIR=/mnt COMPONENTS-SPEC=components.xml AWSAPILOG=awsapi.log REMOTEHOST=localhost +COMMONLIBDIR=C:\Users\htrippaers\eclipse_workspace\cloudstack\client\target\cloud-client-ui-4.2.0-SNAPSHOT\WEB-INF\classes diff --git a/packaging/centos63/cloud-usage.rc b/packaging/centos63/cloud-usage.rc index 76f0e06fdfe..a9b60478875 100755 --- a/packaging/centos63/cloud-usage.rc +++ b/packaging/centos63/cloud-usage.rc @@ -58,7 +58,7 @@ export JAVA_HOME SCP="" DCP="" -UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar`":"`ls /usr/share/cloudstack-usage/lib/* | tr '\n' ':'` +UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar`":"`ls /usr/share/cloudstack-usage/lib/*.jar | tr '\n' ':'` JCP="/usr/share/java/commons-daemon.jar" # We need to append the JSVC daemon JAR to the classpath diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index c2c6fe734cd..a7cc20e8ab8 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -447,13 +447,6 @@ if [ -f "%{_sysconfdir}/%{name}/management/db.properties" ]; then ln -s %{_sysconfdir}/%{name}/management/db.properties %{_sysconfdir}/%{name}/usage/db.properties fi -if [ -f "%{_sysconfdir}/%{name}/management/log4j-cloud.xml" ]; then - echo Replacing log4j-cloud.xml with management server log4j-cloud.xml - rm -f %{_sysconfdir}/%{name}/usage/log4j-cloud.xml - ln -s %{_sysconfdir}/%{name}/management/log4j-cloud.xml %{_sysconfdir}/%{name}/usage/log4j-cloud.xml -fi - - #%post awsapi #if [ -d "%{_datadir}/%{name}-management" ] ; then # ln -s %{_datadir}/%{name}-bridge/webapps %{_datadir}/%{name}-management/webapps7080 @@ -548,7 +541,7 @@ fi %attr(0755,root,root) %{_sysconfdir}/init.d/%{name}-usage %attr(0644,root,root) %{_datadir}/%{name}-usage/*.jar %attr(0644,root,root) %{_datadir}/%{name}-usage/lib/*.jar -%dir /var/log/%{name}/usage +%dir %attr(0770,root,cloud) %{_localstatedir}/log/%{name}/usage %attr(0644,root,root) %{_sysconfdir}/%{name}/usage/db.properties %attr(0644,root,root) %{_sysconfdir}/%{name}/usage/log4j-cloud.xml %{_defaultdocdir}/%{name}-usage-%{version}/LICENSE diff --git a/packaging/centos63/replace.properties b/packaging/centos63/replace.properties index 211cc95449f..83458549570 100644 --- a/packaging/centos63/replace.properties +++ b/packaging/centos63/replace.properties @@ -56,5 +56,5 @@ SYSCONFDIR=/etc/sysconfig SYSTEMCLASSPATH= SYSTEMJARS= USAGECLASSPATH= -USAGELOG=/var/log/cloudstack/usage +USAGELOG=/var/log/cloudstack/usage/usage.log USAGESYSCONFDIR=/etc/sysconfig diff --git a/usage/pom.xml b/usage/pom.xml index 37501fe2744..0ad59b4cf70 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -37,6 +37,11 @@ ${cs.mysql.version} runtime + + commons-daemon + commons-daemon + 1.0.10 + install diff --git a/usage/src/com/cloud/usage/UsageServer.java b/usage/src/com/cloud/usage/UsageServer.java index 3f2b43e2bc9..8a7c852d9e9 100644 --- a/usage/src/com/cloud/usage/UsageServer.java +++ b/usage/src/com/cloud/usage/UsageServer.java @@ -19,6 +19,9 @@ package com.cloud.usage; import java.io.File; import java.io.FileNotFoundException; +import org.apache.commons.daemon.Daemon; +import org.apache.commons.daemon.DaemonContext; +import org.apache.commons.daemon.DaemonInitException; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.DOMConfigurator; @@ -29,7 +32,7 @@ import org.springframework.util.Log4jConfigurer; import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ComponentContext; -public class UsageServer { +public class UsageServer implements Daemon { private static final Logger s_logger = Logger.getLogger(UsageServer.class.getName()); public static final String Name = "usage-server"; @@ -39,15 +42,17 @@ public class UsageServer { * @param args */ public static void main(String[] args) { - initLog4j(); + initLog4j(); UsageServer usage = new UsageServer(); - usage.init(args); usage.start(); } - public void init(String[] args) { + @Override + public void init(DaemonContext arg0) throws DaemonInitException, Exception { + initLog4j(); } + @Override public void start() { ApplicationContext appContext = new ClassPathXmlApplicationContext("usageApplicationContext.xml"); @@ -66,10 +71,12 @@ public class UsageServer { } } + @Override public void stop() { } + @Override public void destroy() { } @@ -96,4 +103,5 @@ public class UsageServer { } } } + } From 90e8158db577e4978323510e1faa9ae01a0e7b11 Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Tue, 16 Apr 2013 17:45:27 +0530 Subject: [PATCH 107/107] re-merge optional public IP for EIP service feature Squashed commit of the following: commit 2dae394a42a364cd93a11b2c2f74b274b7c43315 Author: Murali Reddy Date: Tue Apr 16 17:35:28 2013 +0530 CLOUDSTACK-265: provide option to turn-off automatic public IP association for each VM when using EIP service. - introduces Capability in the network offering, which decides when EIP service is used, by defualt public IP should be assigned to the VM or not - default network offering with EIP/ELB service will still work with old EIP semantics, i.e) assign a public IP to each VM on start --- api/src/com/cloud/network/Network.java | 14 +----- .../com/cloud/offering/NetworkOffering.java | 2 + .../ConfigurationManagerImpl.java | 33 +++++++++++--- .../cloud/network/rules/RulesManagerImpl.java | 16 ++++--- .../cloud/offerings/NetworkOfferingVO.java | 12 ++++- .../cloud/server/ConfigurationServerImpl.java | 2 +- .../cloud/upgrade/dao/Upgrade410to420.java | 44 ++++++++++++++++--- .../src/com/cloud/vm/UserVmManagerImpl.java | 4 ++ setup/db/db/schema-410to420.sql | 3 ++ 9 files changed, 98 insertions(+), 32 deletions(-) diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index ffe70d19dc0..4472dbacc53 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -16,24 +16,11 @@ // under the License. package com.cloud.network; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -import com.cloud.network.Networks.BroadcastDomainType; -import com.cloud.network.Networks.Mode; -import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateObject; - import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -183,6 +170,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability AllowDnsSuffixModification = new Capability("AllowDnsSuffixModification"); public static final Capability RedundantRouter = new Capability("RedundantRouter"); public static final Capability ElasticIp = new Capability("ElasticIp"); + public static final Capability AssociatePublicIP = new Capability("AssociatePublicIP"); public static final Capability ElasticLb = new Capability("ElasticLb"); public static final Capability AutoScaleCounters = new Capability("AutoScaleCounters"); public static final Capability InlineMode = new Capability("InlineMode"); diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java index bd14acd4718..6f0b9937854 100644 --- a/api/src/com/cloud/offering/NetworkOffering.java +++ b/api/src/com/cloud/offering/NetworkOffering.java @@ -107,6 +107,8 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean getElasticIp(); + boolean getAssociatePublicIP(); + boolean getElasticLb(); boolean getSpecifyIpRanges(); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 5b6d81e8df8..c9ae854ee81 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -3433,20 +3433,34 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati void validateStaticNatServiceCapablities(Map staticNatServiceCapabilityMap) { if (staticNatServiceCapabilityMap != null && !staticNatServiceCapabilityMap.isEmpty()) { - if (staticNatServiceCapabilityMap.keySet().size() > 1) { - throw new InvalidParameterValueException("Only " + Capability.ElasticIp.getName() + " capability can be specified for static nat service"); + if (staticNatServiceCapabilityMap.keySet().size() > 2) { + throw new InvalidParameterValueException("Only " + Capability.ElasticIp.getName() + " and " + Capability.AssociatePublicIP.getName() + " capabilitiy can be sepcified for static nat service"); } + boolean eipEnabled = false; + boolean eipDisabled = false; + boolean associatePublicIP = true; for (Capability capability : staticNatServiceCapabilityMap.keySet()) { String value = staticNatServiceCapabilityMap.get(capability); if (capability == Capability.ElasticIp) { - boolean enabled = value.contains("true"); - boolean disabled = value.contains("false"); - if (!enabled && !disabled) { + eipEnabled = value.contains("true"); + eipDisabled = value.contains("false"); + if (!eipEnabled && !eipDisabled) { throw new InvalidParameterValueException("Unknown specified value for " + Capability.ElasticIp.getName()); } + } else if (capability == Capability.AssociatePublicIP) { + if (value.contains("true")) { + associatePublicIP = true; + } else if (value.contains("false")) { + associatePublicIP = false; + } else { + throw new InvalidParameterValueException("Unknown specified value for " + Capability.AssociatePublicIP.getName()); + } } else { - throw new InvalidParameterValueException("Only " + Capability.ElasticIp.getName() + " capability can be specified for static nat service"); + throw new InvalidParameterValueException("Only " + Capability.ElasticIp.getName() + " and " + Capability.AssociatePublicIP.getName() + " capabilitiy can be sepcified for static nat service"); + } + if (eipDisabled && associatePublicIP) { + throw new InvalidParameterValueException("Capability " + Capability.AssociatePublicIP.getName() + " can only be set when capability " + Capability.ElasticIp.getName() + " is true"); } } } @@ -3508,6 +3522,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati boolean sharedSourceNat = false; boolean redundantRouter = false; boolean elasticIp = false; + boolean associatePublicIp = false; boolean inline = false; if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) { Map lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb); @@ -3557,13 +3572,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati String param = staticNatServiceCapabilityMap.get(Capability.ElasticIp); if (param != null) { elasticIp = param.contains("true"); + String associatePublicIP = staticNatServiceCapabilityMap.get(Capability.AssociatePublicIP); + if (associatePublicIP != null) { + associatePublicIp = associatePublicIP.contains("true"); + } } } } NetworkOfferingVO offering = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, networkRate, multicastRate, isDefault, availability, tags, type, conserveMode, dedicatedLb, - sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent); + sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp); if (serviceOfferingId != null) { offering.setServiceOfferingId(serviceOfferingId); diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 29ed5f36d5e..8636d8503a3 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -1215,11 +1215,13 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules Network guestNetwork = _networkModel.getNetwork(ipAddress.getAssociatedWithNetworkId()); NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); if (offering.getElasticIp()) { - getSystemIpAndEnableStaticNatForVm(_vmDao.findById(vmId), true); - return true; - } else { - return disableStaticNat(ipId, caller, ctx.getCallerUserId(), false); + if (offering.getAssociatePublicIP()) { + getSystemIpAndEnableStaticNatForVm(_vmDao.findById(vmId), true); + return true; + } } + + return disableStaticNat(ipId, caller, ctx.getCallerUserId(), false); } @Override @@ -1410,6 +1412,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules Network guestNetwork = _networkModel.getNetwork(nic.getNetworkId()); NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); if (offering.getElasticIp()) { + boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm); + // for user VM's associate public IP only if offering is marked to associate a public IP by default on start of VM + if (!isSystemVM && !offering.getAssociatePublicIP()) { + continue; + } // check if there is already static nat enabled if (_ipAddressDao.findByAssociatedVmId(vm.getId()) != null && !getNewIp) { s_logger.debug("Vm " + vm + " already has ip associated with it in guest network " + guestNetwork); @@ -1424,7 +1431,6 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules s_logger.debug("Allocated system ip " + ip + ", now enabling static nat on it for vm " + vm); - boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm); try { success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId(), isSystemVM, null); } catch (NetworkRuleConflictException ex) { diff --git a/server/src/com/cloud/offerings/NetworkOfferingVO.java b/server/src/com/cloud/offerings/NetworkOfferingVO.java index 5de76a526b5..c015989c5c5 100755 --- a/server/src/com/cloud/offerings/NetworkOfferingVO.java +++ b/server/src/com/cloud/offerings/NetworkOfferingVO.java @@ -110,6 +110,9 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name = "elastic_ip_service") boolean elasticIp; + @Column(name = "eip_associate_public_ip") + boolean eipAssociatePublicIp; + @Column(name = "elastic_lb_service") boolean elasticLb; @@ -278,6 +281,7 @@ public class NetworkOfferingVO implements NetworkOffering { this.sharedSourceNat = false; this.redundantRouter = false; this.elasticIp = false; + this.eipAssociatePublicIp = true; this.elasticLb = false; this.inline = false; this.specifyIpRanges = specifyIpRanges; @@ -286,7 +290,7 @@ public class NetworkOfferingVO implements NetworkOffering { public NetworkOfferingVO(String name, String displayText, TrafficType trafficType, boolean systemOnly, boolean specifyVlan, Integer rateMbps, Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, boolean dedicatedLb, boolean sharedSourceNat, boolean redundantRouter, boolean elasticIp, boolean elasticLb, - boolean specifyIpRanges, boolean inline, boolean isPersistent) { + boolean specifyIpRanges, boolean inline, boolean isPersistent, boolean associatePublicIP) { this(name, displayText, trafficType, systemOnly, specifyVlan, rateMbps, multicastRateMbps, isDefault, availability, tags, guestType, conserveMode, specifyIpRanges, isPersistent); this.dedicatedLB = dedicatedLb; this.sharedSourceNat = sharedSourceNat; @@ -294,6 +298,7 @@ public class NetworkOfferingVO implements NetworkOffering { this.elasticIp = elasticIp; this.elasticLb = elasticLb; this.inline = inline; + this.eipAssociatePublicIp = associatePublicIP; } public NetworkOfferingVO() { @@ -355,6 +360,11 @@ public class NetworkOfferingVO implements NetworkOffering { return elasticIp; } + @Override + public boolean getAssociatePublicIP() { + return eipAssociatePublicIp; + } + @Override public boolean getElasticLb() { return elasticLb; diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 404afecf2cd..852c00b4c5d 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -1008,7 +1008,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false); + null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true); defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNetscalerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetscalerNetworkOffering); diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java index b43e494893b..05e2b49ffe4 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -17,6 +17,10 @@ package com.cloud.upgrade.dao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import org.apache.log4j.Logger; + import java.io.File; import java.sql.Connection; import java.sql.PreparedStatement; @@ -24,11 +28,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; -import org.apache.log4j.Logger; - -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.script.Script; - public class Upgrade410to420 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade410to420.class); @@ -66,6 +65,7 @@ public class Upgrade410to420 implements DbUpgrade { updateCluster_details(conn); updatePrimaryStore(conn); addEgressFwRulesForSRXGuestNw(conn); + upgradeEIPNetworkOfferings(conn); } private void updateSystemVmTemplates(Connection conn) { @@ -365,4 +365,38 @@ public class Upgrade410to420 implements DbUpgrade { } } } + + private void upgradeEIPNetworkOfferings(Connection conn) { + + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + pstmt = conn.prepareStatement("select id, elastic_ip_service from `cloud`.`network_offerings` where traffic_type='Guest'"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + // check if elastic IP service is enabled for network offering + if (rs.getLong(2) != 0) { + //update network offering with eip_associate_public_ip set to true + pstmt = conn.prepareStatement("UPDATE `cloud`.`network_offerings` set eip_associate_public_ip=? where id=?"); + pstmt.setBoolean(1, true); + pstmt.setLong(2, id); + pstmt.executeUpdate(); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to set elastic_ip_service for network offerings with EIP service enabled.", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index d281e5b4dc8..53a57c8e9cb 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2890,6 +2890,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (ip != null && ip.getSystem()) { UserContext ctx = UserContext.current(); try { + long networkId = ip.getAssociatedWithNetworkId(); + Network guestNetwork = _networkDao.findById(networkId); + NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); + assert (offering.getAssociatePublicIP() == true) : "User VM should not have system owned public IP associated with it when offering configured not to associate public IP."; _rulesMgr.disableStaticNat(ip.getId(), ctx.getCaller(), ctx.getCallerUserId(), true); } catch (Exception ex) { s_logger.warn( diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index fb760bf4824..79a2279eac1 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -715,6 +715,9 @@ CREATE TABLE `cloud`.`network_asa1000v_map` ( CONSTRAINT `fk_network_asa1000v_map__asa1000v_id` FOREIGN KEY (`asa1000v_id`) REFERENCES `external_cisco_asa1000v_devices`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `eip_associate_public_ip` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if public IP is associated with user VM creation by default when EIP service is enabled.' AFTER `elastic_ip_service`; + -- Re-enable foreign key checking, at the end of the upgrade path SET foreign_key_checks = 1;