From 880f98c023d314b171b1410ad54020ce7b0ce291 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 25 Apr 2013 13:20:52 -0700 Subject: [PATCH 01/17] Update affinity icon --- ui/images/icons.png | Bin 50708 -> 50052 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ui/images/icons.png b/ui/images/icons.png index f07ca838ee4647cb5d233216a336fe1f9a63eaaf..e2083da1969a1143fe90b21404e6689719c5faab 100644 GIT binary patch literal 50052 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,d70FLrU= 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

VAYfk?^x~`13$Lr9a(1gx@ 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 literal 50708 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 From f883b0f90489348b287b5425a83d6517c0ba092a Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 25 Apr 2013 14:24:44 -0700 Subject: [PATCH 02/17] CLOUDSTACK-2120: mixed zone management - UI: count total number of Primary Storages, Secondary Storages based on selected option in zone type dropdown on top menu. --- ui/scripts/system.js | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 312d5f4906e..fea76693b13 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -269,29 +269,40 @@ }, primaryStorageCount: function(data) { + var data2 = { + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } $.ajax({ url: createURL('listStoragePools'), - data: { - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { - dataFns.secondaryStorageCount($.extend(data, { - primaryStorageCount: json.liststoragepoolsresponse.count ? - json.liststoragepoolsresponse.count : 0 + dataFns.secondaryStorageCount($.extend(data, { + primaryStorageCount: json.liststoragepoolsresponse.count ? json.liststoragepoolsresponse.count : 0 })); } }); }, secondaryStorageCount: function(data) { + var data2 = { + type: 'SecondaryStorage', + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } $.ajax({ url: createURL('listHosts'), - data: { - type: 'SecondaryStorage', - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { dataFns.systemVmCount($.extend(data, { secondaryStorageCount: json.listhostsresponse.count ? From 232d44bf6e31898887b324bcdebbc659423917e4 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 25 Apr 2013 14:47:59 -0700 Subject: [PATCH 03/17] CLOUDSTACK-2158: 'userconcentratedpod_firstfit failed to find alternate host to run VM In the applicationContext .xml , the context of the 'UserConcentratedPodPlanner' needs to include the list of allocators. This will ensure that when this component is loaded by Spring, the allocators gets initialized. --- client/tomcatconf/applicationContext.xml.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index d2ea380ddab..1f5ab20333a 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -532,10 +532,14 @@ --> + + + + From 6f60833f9321bb1639372900bb625dd657006229 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 25 Apr 2013 15:09:45 -0700 Subject: [PATCH 04/17] CLOUDSTACK-2120: mixed zone management - (1) extend listRouters API to to take in zonetype. (2) UI: populate Routers list page with ones whose networktype matches selected option in zone type dropdown on top menu. (3) UI: count total number of Routers based on selected option in zone type dropdown on top menu. --- .../command/admin/router/ListRoutersCmd.java | 7 ++ .../com/cloud/api/query/QueryManagerImpl.java | 12 ++- ui/scripts/system.js | 93 ++++++++++++------- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java index d2b26c0ac8f..9fbc9401532 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java @@ -64,6 +64,9 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { description="the Zone ID of the router") private Long zoneId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class, description="list by network id") private Long networkId; @@ -103,6 +106,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public Long getNetworkId() { return networkId; } diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 67af7e4b684..2c003d31679 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -994,7 +994,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Long id = cmd.getId(); String name = cmd.getRouterName(); String state = cmd.getState(); - Long zone = cmd.getZoneId(); + Long zoneId = cmd.getZoneId(); + String zoneType = cmd.getZoneType(); Long pod = cmd.getPodId(); Long hostId = cmd.getHostId(); String keyword = cmd.getKeyword(); @@ -1027,6 +1028,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.IN); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); + sb.and("dataCenterType", sb.entity().getDataCenterType(), SearchCriteria.Op.EQ); sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("hostId", sb.entity().getHostId(), SearchCriteria.Op.EQ); sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ); @@ -1067,10 +1069,14 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sc.setParameters("state", state); } - if (zone != null) { - sc.setParameters("dataCenterId", zone); + if (zoneId != null) { + sc.setParameters("dataCenterId", zoneId); } + if (zoneType != null) { + sc.setParameters("dataCenterType", zoneType); + } + if (pod != null) { sc.setParameters("podId", pod); } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index fea76693b13..8c962fc2b7b 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -329,22 +329,35 @@ }, virtualRouterCount: function(data) { + var data2 = { + projectid: -1, + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } $.ajax({ url: createURL('listRouters'), - data: { - projectid: -1, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { - var total1 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; + var total1 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; + + var data3 = { + listAll: true, + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data3, { + zonetype: cloudStack.context.zoneType + }); + } $.ajax({ url: createURL('listRouters'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data3, success: function(json) { var total2 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; dataFns.capacity($.extend(data, { @@ -2317,12 +2330,18 @@ } } + var data2 = { + forvpc: false + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -2334,9 +2353,7 @@ // Get project routers $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -2798,13 +2815,19 @@ } } + var data2 = { + forvpc: true + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), dataType: 'json', - data: { - forvpc: true - }, + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router; @@ -2816,9 +2839,7 @@ $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), dataType: 'json', - data: { - forvpc: true - }, + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router; @@ -5754,10 +5775,16 @@ var searchByArgs = args.filterBy.search.value.length ? '&name=' + args.filterBy.search.value : ''; + var data2 = {}; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } var routers = []; $.ajax({ url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + searchByArgs), - dataType: 'json', + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router ? @@ -5770,7 +5797,7 @@ // Get project routers $.ajax({ url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + "&projectid=-1"), - dataType: 'json', + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router ? @@ -5854,12 +5881,18 @@ } } + var data2 = { + forvpc: false + }; + if(cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + $.extend(data2, { + zonetype: cloudStack.context.zoneType + }); + } var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -5870,9 +5903,7 @@ // Get project routers $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; From 64635abba5804767764e5d130ae6429c6b76b371 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 25 Apr 2013 16:03:02 -0700 Subject: [PATCH 05/17] CLOUDSTACK-1910: UI- Regions menu - GSLB - View assigned load balancing - refresh data. --- ui/scripts/regions.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 334eb267bd8..2bbbbeea672 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -461,18 +461,27 @@ id: 'lbUnderGSLB', label: 'assigned load balancing', fields: { - 'name': { label: 'label.name' }, + name: { label: 'label.name' }, publicport: { label: 'label.public.port' }, - privateport: { label: 'label.private.port' }, - algorithm: { label: 'label.algorithm' } + privateport: { label: 'label.private.port' }, + algorithm: { label: 'label.algorithm' } }, - dataProvider: function(args) { - var items = args.context.GSLB[0].loadbalancerrule; - args.response.success({ - data: items - }); + dataProvider: function(args) { + var data = { + id: args.context.GSLB[0].id + }; + $.ajax({ + url: createURL('listGlobalLoadBalancerRules'), + data: data, + success: function(json) { + var items = json.listgloballoadbalancerrulesresponse.globalloadbalancerrule[0].loadbalancerrule; + args.response.success({ + data: items + }); + } + }); }, - actions: { + actions: { add: { label: 'assign more load balancing', messages: { From efb4471dc9b8204fd97e2f053fca0dfe1e9d922b Mon Sep 17 00:00:00 2001 From: Min Chen Date: Thu, 25 Apr 2013 17:40:18 -0700 Subject: [PATCH 06/17] CLOUDSTACK-2196 and CLOUDSTACK-2126: fix missing async job status in listXXX api and incorrect async job status in other async api. Conflicts: server/src/com/cloud/api/query/vo/AccountJoinVO.java --- core/src/com/cloud/async/AsyncJobVO.java | 1 + server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java | 6 ++++-- .../com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java | 6 ++++-- server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java | 6 ++++-- .../com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java | 6 ++++-- .../src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java | 6 ++++-- .../src/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java | 6 ++++-- server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java | 6 ++++-- server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java | 6 ++++-- server/src/com/cloud/api/query/vo/AccountJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/HostJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/UserAccountJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/UserVmJoinVO.java | 6 +++--- server/src/com/cloud/api/query/vo/VolumeJoinVO.java | 6 +++--- 17 files changed, 57 insertions(+), 40 deletions(-) diff --git a/core/src/com/cloud/async/AsyncJobVO.java b/core/src/com/cloud/async/AsyncJobVO.java index ad482b03a9d..c40fc987a4a 100644 --- a/core/src/com/cloud/async/AsyncJobVO.java +++ b/core/src/com/cloud/async/AsyncJobVO.java @@ -133,6 +133,7 @@ public class AsyncJobVO implements AsyncJob { this.callbackType = CALLBACK_POLLING; this.uuid = UUID.randomUUID().toString(); this.instanceId = instanceId; + this.instanceType = instanceType; } public AsyncJobVO(long userId, long accountId, String cmd, String cmdInfo, diff --git a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java index 796ae54d52f..528bdacffda 100644 --- a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java @@ -203,8 +203,10 @@ public class AccountJoinDaoImpl extends GenericDaoBase impl accountResponse.setObjectName("account"); // set async job - accountResponse.setJobId(account.getJobUuid()); - accountResponse.setJobStatus(account.getJobStatus()); + if (account.getJobId() != null) { + accountResponse.setJobId(account.getJobUuid()); + accountResponse.setJobStatus(account.getJobStatus()); + } return accountResponse; } diff --git a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 25cd62faf7b..125db17c760 100644 --- a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -158,8 +158,10 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase implements hostResponse.setResourceState(host.getResourceState().toString()); // set async job - hostResponse.setJobId(host.getJobUuid()); - hostResponse.setJobStatus(host.getJobStatus()); + if (host.getJobId() != null) { + hostResponse.setJobId(host.getJobUuid()); + hostResponse.setJobStatus(host.getJobStatus()); + } hostResponse.setObjectName("host"); diff --git a/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java index 3e579c179e2..2a6afca231e 100644 --- a/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java @@ -117,8 +117,10 @@ public class SecurityGroupJoinDaoImpl extends GenericDaoBase implem } } userVmResponse.setPassword(userVm.getPassword()); - userVmResponse.setJobId(userVm.getJobUuid()); - userVmResponse.setJobStatus(userVm.getJobStatus()); + if (userVm.getJobId() != null) { + userVmResponse.setJobId(userVm.getJobUuid()); + userVmResponse.setJobStatus(userVm.getJobStatus()); + } //userVmResponse.setForVirtualNetwork(userVm.getForVirtualNetwork()); userVmResponse.setPublicIpId(userVm.getPublicIpUuid()); diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index a7a0bf0b435..a09c4a0c09b 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -197,8 +197,10 @@ public class VolumeJoinDaoImpl extends GenericDaoBase implem volResponse.setExtractable(isExtractable); // set async job - volResponse.setJobId(volume.getJobUuid()); - volResponse.setJobStatus(volume.getJobStatus()); + if (volume.getJobId() != null) { + volResponse.setJobId(volume.getJobUuid()); + volResponse.setJobStatus(volume.getJobStatus()); + } volResponse.setObjectName("volume"); return volResponse; diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 800da7803fd..fbcc9342b22 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -177,7 +177,7 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident private Long secondaryStorageTotal; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -645,12 +645,12 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java index 5f2b500fa57..83e15477287 100644 --- a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java +++ b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java @@ -210,7 +210,7 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti private String projectName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -781,14 +781,14 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/HostJoinVO.java b/server/src/com/cloud/api/query/vo/HostJoinVO.java index 4aa45e5f593..4b70cfcaa10 100644 --- a/server/src/com/cloud/api/query/vo/HostJoinVO.java +++ b/server/src/com/cloud/api/query/vo/HostJoinVO.java @@ -168,7 +168,7 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity private long cpuReservedCapacity; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -427,11 +427,11 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity this.osCategoryName = osCategoryName; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java b/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java index 922e130ed30..258b6136224 100644 --- a/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java +++ b/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java @@ -77,7 +77,7 @@ public class SecurityGroupJoinVO extends BaseViewVO implements ControlledViewEnt private String projectName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -269,11 +269,11 @@ public class SecurityGroupJoinVO extends BaseViewVO implements ControlledViewEnt this.projectName = projectName; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java index da06227ea66..d86726c3523 100644 --- a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -121,7 +121,7 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -342,11 +342,11 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I this.reservedCapacity = reservedCapacity; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java index d85392fb85a..c44027b8bc0 100644 --- a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java @@ -109,7 +109,7 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I private String domainPath = null; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -324,11 +324,11 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I this.loginAttempts = loginAttempts; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index a50906d9e3d..d7b516c312f 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -332,7 +332,7 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { private String keypairName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -1608,14 +1608,14 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index 8a4bfe5c0fa..2d7b1d5bb49 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -206,7 +206,7 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { private Storage.TemplateType templateType; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -817,13 +817,13 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } From f429c6687b713cbbe1ca7f78bbf4869a32fe39f4 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Thu, 25 Apr 2013 22:35:54 -0600 Subject: [PATCH 07/17] Don't allow success to be reported when we fail to stop vm due to no agent connection BUG-ID: CLOUDSTACK-2195 Bugfix-for: 4.2 Reviewed-by: Edison Su Signed-off-by: Marcus Sorensen 1366950954 -0600 --- server/src/com/cloud/vm/UserVmManagerImpl.java | 11 +++++++---- .../src/com/cloud/vm/VirtualMachineManagerImpl.java | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ebc5757770e..f58d6be5b2f 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2902,10 +2902,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } UserVO user = _userDao.findById(userId); - + boolean status = false; try { VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - vmEntity.stop(new Long(userId).toString()); + status = vmEntity.stop(new Long(userId).toString()); + if (status) { + return _vmDao.findById(vmId); + } else { + return null; + } } catch (ResourceUnavailableException e) { throw new CloudRuntimeException( "Unable to contact the agent to stop the virtual machine " @@ -2915,8 +2920,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use "Unable to contact the agent to stop the virtual machine " + vm, e); } - - return _vmDao.findById(vmId); } @Override diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 252fc99ca0d..b0d6378e9e5 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1136,7 +1136,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac vmGuru.finalizeStop(profile, answer); } catch (AgentUnavailableException e) { + s_logger.warn("Unable to stop vm, agent unavailable: " + e.toString()); } catch (OperationTimedoutException e) { + s_logger.warn("Unable to stop vm, operation timed out: " + e.toString()); } finally { if (!stopped) { if (!forced) { From 2f40a90c53067c3901cf9e5c9a33309907e48aab Mon Sep 17 00:00:00 2001 From: Ashutosh Kelkar Date: Wed, 24 Apr 2013 15:03:10 +0530 Subject: [PATCH 08/17] Multiple fixes to marvin framework 1. adding hypervisor information to configs TODO: support for multi-hypervisor zones? 2. CLOUDSTACK-601: Marvin unicode decode errors when running mysql queries via dbClient 3. adding keypair support for remotessh client Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/asyncJobMgr.py | 70 ++- tools/marvin/marvin/cloudstackConnection.py | 17 +- tools/marvin/marvin/cloudstackTestClient.py | 53 +- tools/marvin/marvin/dbConnection.py | 6 +- tools/marvin/marvin/deployDataCenter.py | 7 + tools/marvin/marvin/integration/lib/base.py | 600 +++++++++++++++++-- tools/marvin/marvin/integration/lib/utils.py | 17 +- tools/marvin/marvin/remoteSSHClient.py | 18 +- 8 files changed, 669 insertions(+), 119 deletions(-) diff --git a/tools/marvin/marvin/asyncJobMgr.py b/tools/marvin/marvin/asyncJobMgr.py index 40304fa4141..698462783bd 100644 --- a/tools/marvin/marvin/asyncJobMgr.py +++ b/tools/marvin/marvin/asyncJobMgr.py @@ -28,6 +28,8 @@ class job(object): def __init__(self): self.id = None self.cmd = None + + class jobStatus(object): def __init__(self): self.result = None @@ -37,8 +39,11 @@ class jobStatus(object): self.duration = None self.jobId = None self.responsecls = None + def __str__(self): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) + + class workThread(threading.Thread): def __init__(self, in_queue, outqueue, apiClient, db=None, lock=None): threading.Thread.__init__(self) @@ -47,11 +52,11 @@ class workThread(threading.Thread): self.connection = apiClient.connection.__copy__() self.db = None self.lock = lock - + def queryAsynJob(self, job): if job.jobId is None: return job - + try: self.lock.acquire() result = self.connection.poll(job.jobId, job.responsecls).jobresult @@ -59,10 +64,10 @@ class workThread(threading.Thread): result = str(e) finally: self.lock.release() - + job.result = result return job - + def executeCmd(self, job): cmd = job.cmd @@ -70,14 +75,15 @@ class workThread(threading.Thread): jobId = None try: self.lock.acquire() - + if cmd.isAsync == "false": jobstatus.startTime = datetime.datetime.now() - + result = self.connection.make_request(cmd) jobstatus.result = result jobstatus.endTime = datetime.datetime.now() - jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime(jobstatus.startTime.timetuple()) + jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime( + jobstatus.startTime.timetuple()) else: result = self.connection.make_request(cmd, None, True) if result is None: @@ -99,9 +105,9 @@ class workThread(threading.Thread): jobstatus.result = sys.exc_info() finally: self.lock.release() - + return jobstatus - + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -109,18 +115,20 @@ class workThread(threading.Thread): jobstatus = self.queryAsynJob(job) else: jobstatus = self.executeCmd(job) - + self.output.put(jobstatus) self.inqueue.task_done() - + '''release the resource''' self.connection.close() + class jobThread(threading.Thread): def __init__(self, inqueue, interval): threading.Thread.__init__(self) self.inqueue = inqueue self.interval = interval + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -130,23 +138,25 @@ class jobThread(threading.Thread): job.apiClient.connection.close() except: pass - + self.inqueue.task_done() time.sleep(self.interval) - + + class outputDict(object): def __init__(self): self.lock = threading.Condition() - self.dict = {} + self.dict = {} + class asyncJobMgr(object): def __init__(self, apiClient, db): self.inqueue = Queue.Queue() - self.output = outputDict() + self.output = outputDict() self.outqueue = Queue.Queue() self.apiClient = apiClient self.db = db - + def submitCmds(self, cmds): if not self.inqueue.empty(): return False @@ -160,11 +170,12 @@ class asyncJobMgr(object): id += 1 ids.append(id) return ids - + def updateTimeStamp(self, jobstatus): jobId = jobstatus.jobId if jobId is not None and self.db is not None: - result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) + result = self.db.execute( + "select job_status, created, last_updated from async_job where id='%s'" % str(jobId)) if result is not None and len(result) > 0: if result[0][0] == 1: jobstatus.status = True @@ -174,7 +185,7 @@ class asyncJobMgr(object): jobstatus.endTime = result[0][2] delta = jobstatus.endTime - jobstatus.startTime jobstatus.duration = delta.total_seconds() - + def waitForComplete(self, workers=10): self.inqueue.join() lock = threading.Lock() @@ -183,28 +194,30 @@ class asyncJobMgr(object): for i in range(workers): worker = workThread(self.outqueue, resultQueue, self.apiClient, self.db, lock) worker.start() - + self.outqueue.join() - + asyncJobResult = [] while resultQueue.qsize() > 0: jobstatus = resultQueue.get() self.updateTimeStamp(jobstatus) asyncJobResult.append(jobstatus) - + return asyncJobResult - + '''put commands into a queue at first, then start workers numbers threads to execute this commands''' + def submitCmdsAndWait(self, cmds, workers=10): self.submitCmds(cmds) lock = threading.Lock() for i in range(workers): worker = workThread(self.inqueue, self.outqueue, self.apiClient, self.db, lock) worker.start() - + return self.waitForComplete(workers) '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJobExecuteNtimes(self, job, ntimes=1, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() @@ -213,22 +226,23 @@ class asyncJobMgr(object): setattr(newjob, "apiClient", copy.copy(self.apiClient)) setattr(newjob, "lock", lock) inqueue1.put(newjob) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() inqueue1.join() - + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() - + for job in jobs: setattr(job, "apiClient", copy.copy(self.apiClient)) setattr(job, "lock", lock) inqueue1.put(job) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 5d30803d930..9a4c387a87a 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -33,13 +33,18 @@ from requests import RequestException class cloudConnection(object): """ Connections to make API calls to the cloudstack management server """ - def __init__(self, mgtSvr, port=8096, apiKey=None, securityKey=None, + def __init__(self, mgtSvr, port=8096, user=None, passwd=None, + apiKey=None, securityKey=None, asyncTimeout=3600, logging=None, scheme='http', path='client/api'): self.apiKey = apiKey self.securityKey = securityKey self.mgtSvr = mgtSvr self.port = port + if user: + self.user = user + if passwd: + self.passwd = passwd self.logging = logging self.path = path self.retries = 5 @@ -55,9 +60,10 @@ class cloudConnection(object): % (self.protocol, self.mgtSvr, self.port, self.path) def __copy__(self): - return cloudConnection(self.mgtSvr, self.port, self.apiKey, - self.securityKey, self.asyncTimeout, - self.logging, self.protocol, self.path) + return cloudConnection(self.mgtSvr, self.port, self.user, self.passwd, + self.apiKey, self.securityKey, + self.asyncTimeout, self.logging, self.protocol, + self.path) def poll(self, jobid, response): """ @@ -200,7 +206,8 @@ class cloudConnection(object): @return: """ cmdname, isAsync, payload = self.sanitize_command(cmd) - self.logging.debug("sending %s request: %s %s" % (method, cmdname, str(payload))) + self.logging.debug("sending %s request: %s %s" % (method, cmdname, + str(payload))) response = self.request( cmdname, self.auth, payload=payload, method=method) self.logging.debug("Request: %s Response: %s" % diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 85552ed5523..d85a61c4872 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -18,24 +18,29 @@ import cloudstackConnection import asyncJobMgr import dbConnection -from cloudstackAPI import * +from cloudstackAPI import * import random import string import hashlib class cloudstackTestClient(object): - def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, + def __init__(self, mgtSvr=None, port=8096, user=None, passwd=None, + apiKey=None, securityKey=None, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): - self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey, asyncTimeout, logging) + self.connection = \ + cloudstackConnection.cloudConnection( + mgtSvr, port, user, + passwd, apiKey, securityKey, + asyncTimeout, logging) self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection) self.dbConnection = None self.asyncJobMgr = None self.ssh = None self.defaultWorkerThreads = defaultWorkerThreads - + def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) - + def isAdminContext(self): """ A user is a regular user if he fails to listDomains; @@ -53,7 +58,7 @@ class cloudstackTestClient(object): return 2 #domain-admin except: return 0 #user - + def random_gen(self, size=6, chars=string.ascii_uppercase + string.digits): """Generate Random Strings of variable length""" return ''.join(random.choice(chars) for x in range(size)) @@ -61,7 +66,7 @@ class cloudstackTestClient(object): def createUserApiClient(self, UserName, DomainName, acctType=0): if not self.isAdminContext(): return self.apiClient - + listDomain = listDomains.listDomainsCmd() listDomain.listall = True listDomain.name = DomainName @@ -73,11 +78,11 @@ class cloudstackTestClient(object): cdomain.name = DomainName domain = self.apiClient.createDomain(cdomain) domId = domain.id - + mdf = hashlib.md5() mdf.update("password") mdf_pass = mdf.hexdigest() - + cmd = listAccounts.listAccountsCmd() cmd.name = UserName cmd.domainid = domId @@ -95,46 +100,47 @@ class cloudstackTestClient(object): createAcctCmd.username = UserName acct = self.apiClient.createAccount(createAcctCmd) acctId = acct.id - - listuser = listUsers.listUsersCmd() + + listuser = listUsers.listUsersCmd() listuser.username = UserName - + listuserRes = self.apiClient.listUsers(listuser) userId = listuserRes[0].id apiKey = listuserRes[0].apikey securityKey = listuserRes[0].secretkey - + if apiKey is None: registerUser = registerUserKeys.registerUserKeysCmd() registerUser.id = userId registerUserRes = self.apiClient.registerUserKeys(registerUser) apiKey = registerUserRes.apikey securityKey = registerUserRes.secretkey - + newUserConnection = cloudstackConnection.cloudConnection(self.connection.mgtSvr, self.connection.port, + self.connection.user, self.connection.passwd, apiKey, securityKey, self.connection.asyncTimeout, self.connection.logging) self.userApiClient = cloudstackAPIClient.CloudStackAPIClient(newUserConnection) self.userApiClient.connection = newUserConnection return self.userApiClient - + def close(self): if self.connection is not None: self.connection.close() - + def getDbConnection(self): return self.dbConnection def executeSql(self, sql=None): if sql is None or self.dbConnection is None: return None - + return self.dbConnection.execute() - + def executeSqlFromFile(self, sqlFile=None): if sqlFile is None or self.dbConnection is None: return None return self.dbConnection.executeSqlFromFile(sqlFile) - + def getApiClient(self): return self.apiClient @@ -151,18 +157,21 @@ class cloudstackTestClient(object): '''FixME, httplib has issue if more than one thread submitted''' + def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) - + '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJob(self, job, ntimes=1, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) self.asyncJobMgr.submitJobExecuteNtimes(job, ntimes, nums_threads, interval) - - '''submit n jobs, execute them with nums_threads of threads''' + + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) diff --git a/tools/marvin/marvin/dbConnection.py b/tools/marvin/marvin/dbConnection.py index 8fa86438ab0..958299aff2a 100644 --- a/tools/marvin/marvin/dbConnection.py +++ b/tools/marvin/marvin/dbConnection.py @@ -37,7 +37,11 @@ class dbConnection(object): return None resultRow = [] - with contextlib.closing(mysql.connector.connect(host=self.host, port=self.port, user=self.user, password=self.passwd, db=self.database)) as conn: + with contextlib.closing(mysql.connector.connect(host=str(self.host), + port=int(self.port), + user=str(self.user), + password=str(self.passwd), + db=str(self.database))) as conn: conn.autocommit = True with contextlib.closing(conn.cursor(buffered=True)) as cursor: cursor.execute(sql, params) diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index d358789d8da..5ca1ebfb4f8 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -402,6 +402,7 @@ class deployDataCenters(): self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, mgt.port, \ + mgt.user, mgt.passwd, \ mgt.apiKey, \ mgt.securityKey, \ logging=self.testClientLogger) @@ -409,6 +410,7 @@ class deployDataCenters(): apiKey, securityKey = self.registerApiKey() self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, 8080, \ + mgt.user, mgt.passwd, \ apiKey, securityKey, \ logging=self.testClientLogger) @@ -419,6 +421,11 @@ class deployDataCenters(): dbSvr.passwd, dbSvr.db) self.apiClient = self.testClient.getApiClient() + """set hypervisor""" + if mgt.hypervisor: + self.apiClient.hypervisor = mgt.hypervisor + else: + self.apiClient.hypervisor = "XenServer" #Defaults to Xenserver def updateConfiguration(self, globalCfg): if globalCfg is None: diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 6c285233a82..1d86c6c1599 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -5,9 +5,9 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,7 +22,7 @@ import marvin from utils import is_server_ssh_ready, random_gen from marvin.cloudstackAPI import * -#Import System modules +# Import System modules import time import hashlib import base64 @@ -54,8 +54,12 @@ class Domain: cmd.parentdomainid = parentdomainid elif "parentdomainid" in services: cmd.parentdomainid = services["parentdomainid"] - - return Domain(apiclient.createDomain(cmd).__dict__) + try: + domain = apiclient.createDomain(cmd) + if domain is not None: + return Domain(domain.__dict__) + except Exception as e: + raise e def delete(self, apiclient, cleanup=None): """Delete an domain""" @@ -83,7 +87,7 @@ class Account: """Creates an account""" cmd = createAccount.createAccountCmd() - #0 - User, 1 - Root Admin, 2 - Domain Admin + # 0 - User, 1 - Root Admin, 2 - Domain Admin cmd.accounttype = 2 if (admin and domainid) else int(admin) cmd.email = services["email"] @@ -213,14 +217,15 @@ class VirtualMachine: else: self.ssh_port = 22 self.ssh_client = None - #extract out the ipaddress + # extract out the ipaddress self.ipaddress = self.nic[0].ipaddress @classmethod 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, affinitygroupnames=None, hostid=None, mode='basic', method='GET'): + diskofferingid=None, affinitygroupnames=None, group=None, + hostid=None, keypair=None, mode='basic', method='GET'): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -234,7 +239,13 @@ class VirtualMachine: cmd.zoneid = zoneid elif "zoneid" in services: cmd.zoneid = services["zoneid"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor + + if "displayname" in services: + cmd.displayname = services["displayname"] + + if "name" in services: + cmd.name = services["name"] if accountid: cmd.account = accountid @@ -256,9 +267,16 @@ class VirtualMachine: elif "template" in services: cmd.templateid = services["template"] - if "diskoffering" in services: + if diskofferingid: + cmd.diskofferingid = diskofferingid + elif "diskoffering" in services: cmd.diskofferingid = services["diskoffering"] + if keypair: + cmd.keypair = keypair + elif "keypair" in services: + cmd.keypair = services["keypair"] + if securitygroupids: cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids] @@ -282,6 +300,15 @@ class VirtualMachine: virtual_machine = apiclient.deployVirtualMachine(cmd, method=method) + if group: + cmd.group = group + virtual_machine = apiclient.deployVirtualMachine(cmd) + + if startvm == False: + virtual_machine.ssh_ip = virtual_machine.nic[0].ipaddress + virtual_machine.public_ip = virtual_machine.nic[0].ipaddress + return VirtualMachine(virtual_machine.__dict__, services) + # VM should be in Running state after deploy timeout = 10 while True: @@ -308,14 +335,14 @@ class VirtualMachine: virtual_machine.domainid, services ) - fw_rule = FireWallRule.create( + FireWallRule.create( apiclient, ipaddressid=public_ip.ipaddress.id, protocol='TCP', cidrlist=['0.0.0.0/0'], startport=22, endport=22 - ) + ) nat_rule = NATRule.create( apiclient, virtual_machine, @@ -348,7 +375,13 @@ class VirtualMachine: cmd.id = self.id apiclient.rebootVirtualMachine(cmd) - def get_ssh_client(self, ipaddress=None, reconnect=False, port=None): + def recover(self, apiclient): + """Recover the instance""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.id = self.id + apiclient.recoverVirtualMachine(cmd) + + def get_ssh_client(self, ipaddress=None, reconnect=False, port=None, keyPairFileLocation=None): """Get SSH object of VM""" # If NAT Rules are not created while VM deployment in Advanced mode @@ -358,27 +391,56 @@ class VirtualMachine: if port: self.ssh_port = port + if keyPairFileLocation is not None: + self.password = None + if reconnect: self.ssh_client = is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) self.ssh_client = self.ssh_client or is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) return self.ssh_client + def resetSshKey(self, apiclient, **kwargs): + """Resets SSH key""" + + cmd = resetSSHKeyForVirtualMachine.resetSSHKeyForVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.resetSSHKeyForVirtualMachine(cmd)) + + def update(self, apiclient, **kwargs): + """Updates the VM data""" + + cmd = updateVirtualMachine.updateVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateVirtualMachine(cmd)) + def delete(self, apiclient): """Destroy an Instance""" cmd = destroyVirtualMachine.destroyVirtualMachineCmd() cmd.id = self.id apiclient.destroyVirtualMachine(cmd) + def migrate(self, apiclient, hostid=None): + """migrate an Instance""" + cmd = migrateVirtualMachine.migrateVirtualMachineCmd() + cmd.virtualmachineid = self.id + if hostid: + cmd.hostid = hostid + apiclient.migrateVirtualMachine(cmd) + def attach_volume(self, apiclient, volume): """Attach volume to instance""" cmd = attachVolume.attachVolumeCmd() @@ -394,7 +456,7 @@ class VirtualMachine: def add_nic(self, apiclient, networkId): """Add a NIC to a VM""" - cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd(); + cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd() cmd.virtualmachineid = self.id cmd.networkid = networkId return apiclient.addNicToVirtualMachine(cmd) @@ -413,6 +475,26 @@ class VirtualMachine: cmd.virtualmachineid = self.id return apiclient.updateDefaultNicForVirtualMachine(cmd) + def attach_iso(self, apiclient, iso): + """Attach ISO to instance""" + cmd = attachIso.attachIsoCmd() + cmd.id = iso.id + cmd.virtualmachineid = self.id + return apiclient.attachIso(cmd) + + def detach_iso(self, apiclient): + """Detach ISO to instance""" + cmd = detachIso.detachIsoCmd() + cmd.id = self.id + return apiclient.detachIso(cmd) + + def change_service_offering(self, apiclient, serviceOfferingId): + """Change service offering of the instance""" + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.id = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all VMs matching criteria""" @@ -428,16 +510,14 @@ class VirtualMachine: cmd.id = self.id try: response = apiclient.resetPasswordForVirtualMachine(cmd) - print response except Exception as e: raise Exception("Reset Password failed! - %s" % e) - print type(response) if isinstance(response, list): return response[0].password class Volume: - """Manage Volume Lifecycle + """Manage Volume Life cycle """ def __init__(self, items): self.__dict__.update(items) @@ -533,7 +613,7 @@ class Volume: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVolumes(cmd)) - def resize(cls, apiclient, **kwargs): + def resize(self, apiclient, **kwargs): """Resize a volume""" cmd = resizeVolume.resizeVolumeCmd() cmd.id = self.id @@ -541,6 +621,58 @@ class Volume: return(apiclient.resizeVolume(cmd)) @classmethod + def upload(cls, apiclient, services, zoneid=None, account=None, domainid=None, url=None): + """Uploads the volume to specified account""" + + cmd = uploadVolume.uploadVolumeCmd() + if zoneid: + cmd.zoneid = zoneid + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + cmd.format = services["format"] + cmd.name = services["diskname"] + if url: + cmd.url = url + else: + cmd.url = services["url"] + return Volume(apiclient.uploadVolume(cmd).__dict__) + + def wait_for_upload(self, apiclient, timeout=5, interval=60): + """Wait for upload""" + # Sleep to ensure template is in proper state before download + time.sleep(interval) + + while True: + volume_response = Volume.list( + apiclient, + id=self.id, + zoneid=self.zoneid, + ) + if isinstance(volume_response, list): + + volume = volume_response[0] + # If volume is ready, + # volume.state = Allocated + if volume.state == 'Uploaded': + break + + elif 'Uploading' in volume.state: + time.sleep(interval) + + elif 'Installing' not in volume.state: + raise Exception( + "Error in uploading volume: status - %s" % + volume.state) + elif timeout == 0: + break + + else: + time.sleep(interval) + timeout = timeout - 1 + return + def migrate(cls, apiclient, **kwargs): """Migrate a volume""" cmd = migrateVolume.migrateVolumeCmd() @@ -592,7 +724,7 @@ class Template: def create(cls, apiclient, services, volumeid=None, account=None, domainid=None, projectid=None): """Create template from Volume""" - #Create template from Virtual machine and Volume ID + # Create template from Virtual machine and Volume ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([services["name"], random_gen()]) @@ -617,7 +749,6 @@ class Template: cmd.ispublic = services["ispublic"] if "ispublic" in services else False cmd.isextractable = services["isextractable"] if "isextractable" in services else False cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False - cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False if volumeid: cmd.volumeid = volumeid @@ -637,12 +768,12 @@ class Template: account=None, domainid=None): """Create template from URL""" - #Create template from Virtual machine and Volume ID + # Create template from Virtual machine and Volume ID cmd = registerTemplate.registerTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([services["name"], random_gen()]) cmd.format = services["format"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor if "ostypeid" in services: cmd.ostypeid = services["ostypeid"] @@ -689,7 +820,7 @@ class Template: def create_from_snapshot(cls, apiclient, snapshot, services, random_name=True): """Create Template from snapshot""" - #Create template from Virtual machine and Snapshot ID + # Create template from Virtual machine and Snapshot ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([ @@ -726,7 +857,7 @@ class Template: def download(self, apiclient, timeout=5, interval=60): """Download Template""" - #Sleep to ensure template is in proper state before download + # Sleep to ensure template is in proper state before download time.sleep(interval) while True: @@ -789,7 +920,7 @@ class Iso: def create(cls, apiclient, services, account=None, domainid=None, projectid=None): """Create an ISO""" - #Create ISO from URL + # Create ISO from URL cmd = registerIso.registerIsoCmd() cmd.displaytext = services["displaytext"] cmd.name = services["name"] @@ -841,7 +972,7 @@ class Iso: def download(self, apiclient, timeout=5, interval=60): """Download an ISO""" - #Ensuring ISO is successfully downloaded + # Ensuring ISO is successfully downloaded while True: time.sleep(interval) @@ -853,7 +984,6 @@ class Iso: response = iso_response[0] # Again initialize timeout to avoid listISO failure timeout = 5 - print response.status # Check whether download is in progress(for Ex:10% Downloaded) # or ISO is 'Successfully Installed' if response.status == 'Successfully Installed': @@ -940,7 +1070,7 @@ class NATRule: @classmethod def create(cls, apiclient, virtual_machine, services, ipaddressid=None, - projectid=None, networkid=None): + projectid=None, openfirewall=False, networkid=None, vpcid=None): """Create Port forwarding rule""" cmd = createPortForwardingRule.createPortForwardingRuleCmd() @@ -951,15 +1081,24 @@ class NATRule: cmd.privateport = services["privateport"] cmd.publicport = services["publicport"] + if "privateendport" in services: + cmd.privateendport = services["privateendport"] + if "publicendport" in services: + cmd.publicendport = services["publicendport"] cmd.protocol = services["protocol"] cmd.virtualmachineid = virtual_machine.id if projectid: cmd.projectid = projectid + if openfirewall: + cmd.openfirewall = True + if networkid: cmd.networkid = networkid + if vpcid: + cmd.vpcid = vpcid return NATRule(apiclient.createPortForwardingRule(cmd).__dict__) def delete(self, apiclient): @@ -985,10 +1124,10 @@ class StaticNATRule: self.__dict__.update(items) @classmethod - def create(cls, apiclient, services, ipaddressid=None, vpcid=None): + def create(cls, apiclient, services, ipaddressid=None, networkid=None, vpcid=None): """Creates static ip forwarding rule""" - cmd = createIpForwardingRule.createIpForwardingRuleCmd() + cmd = createFirewallRule.createFirewallRuleCmd() cmd.protocol = services["protocol"] cmd.startport = services["startport"] @@ -1003,10 +1142,12 @@ class StaticNATRule: elif "ipaddressid" in services: cmd.ipaddressid = services["ipaddressid"] + if networkid: + cmd.networkid = networkid + if vpcid: cmd.vpcid = vpcid - - return StaticNATRule(apiclient.createIpForwardingRule(cmd).__dict__) + return StaticNATRule(apiclient.createFirewallRule(cmd).__dict__) def delete(self, apiclient): """Delete IP forwarding rule""" @@ -1024,12 +1165,14 @@ class StaticNATRule: return(apiclient.listIpForwardingRules(cmd)) @classmethod - def enable(cls, apiclient, ipaddressid, virtualmachineid): + def enable(cls, apiclient, ipaddressid, virtualmachineid, networkid=None): """Enables Static NAT rule""" cmd = enableStaticNat.enableStaticNatCmd() cmd.ipaddressid = ipaddressid cmd.virtualmachineid = virtualmachineid + if networkid: + cmd.networkid = networkid apiclient.enableStaticNat(cmd) return @@ -1105,6 +1248,14 @@ class ServiceOffering: if "storagetype" in services: cmd.storagetype = services["storagetype"] + if "systemvmtype" in services: + cmd.systemvmtype = services['systemvmtype'] + + if "issystem" in services: + cmd.issystem = services['issystem'] + + if "tags" in services: + cmd.tags = services["tags"] # Service Offering private to that domain if domainid: cmd.domainid = domainid @@ -1183,20 +1334,25 @@ class NetworkOffering: cmd.displaytext = "-".join([services["displaytext"], random_gen()]) cmd.name = "-".join([services["name"], random_gen()]) cmd.guestiptype = services["guestiptype"] - cmd.supportedservices = services["supportedservices"] + cmd.supportedservices = '' + if "supportedservices" in services: + cmd.supportedservices = services["supportedservices"] cmd.traffictype = services["traffictype"] + if "useVpc" in services: + cmd.useVpc = services["useVpc"] cmd.serviceProviderList = [] - for service, provider in services["serviceProviderList"].items(): - cmd.serviceProviderList.append({ + if "serviceProviderList" in services: + for service, provider in services["serviceProviderList"].items(): + cmd.serviceProviderList.append({ 'service': service, 'provider': provider }) if "servicecapabilitylist" in services: - cmd.servicecapabilitylist = [] + cmd.serviceCapabilityList = [] for service, capability in services["servicecapabilitylist"].items(): for ctype, value in capability.items(): - cmd.servicecapabilitylist.append({ + cmd.serviceCapabilityList.append({ 'service': service, 'capabilitytype': ctype, 'capabilityvalue': value @@ -1205,6 +1361,7 @@ class NetworkOffering: cmd.specifyVlan = services["specifyVlan"] if "specifyIpRanges" in services: cmd.specifyIpRanges = services["specifyIpRanges"] + cmd.availability = 'Optional' [setattr(cmd, k, v) for k, v in kwargs.items()] @@ -1275,7 +1432,7 @@ class LoadBalancerRule: @classmethod def create(cls, apiclient, services, ipaddressid=None, accountid=None, - networkid=None, projectid=None, domainid=None): + networkid=None, vpcid=None, projectid=None, domainid=None): """Create Load balancing Rule""" cmd = createLoadBalancerRule.createLoadBalancerRuleCmd() @@ -1293,6 +1450,8 @@ class LoadBalancerRule: if domainid: cmd.domainid = domainid + if vpcid: + cmd.vpcid = vpcid cmd.name = services["name"] cmd.algorithm = services["alg"] cmd.privateport = services["privateport"] @@ -1359,19 +1518,19 @@ class LoadBalancerRule: for name, value in param.items(): cmd.param.append({'name': name, 'value': value}) return apiclient.createLBStickinessPolicy(cmd) - + def deleteSticky(self, apiclient, id): """Deletes stickyness policy""" - + cmd = deleteLBStickinessPolicy.deleteLBStickinessPolicyCmd() cmd.id = id return apiclient.deleteLBStickinessPolicy(cmd) - + @classmethod def listStickyPolicies(cls, apiclient, lbruleid, **kwargs): """Lists stickiness policies for load balancing rule""" - - cmd= listLBStickinessPolicies.listLBStickinessPoliciesCmd() + + cmd = listLBStickinessPolicies.listLBStickinessPoliciesCmd() cmd.lbruleid = lbruleid [setattr(cmd, k, v) for k, v in kwargs.items()] return apiclient.listLBStickinessPolicies(cmd) @@ -1396,7 +1555,7 @@ class Cluster: """Create Cluster""" cmd = addCluster.addClusterCmd() cmd.clustertype = services["clustertype"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor if zoneid: cmd.zoneid = zoneid @@ -1446,7 +1605,7 @@ class Host: """Create Host in cluster""" cmd = addHost.addHostCmd() - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor cmd.url = services["url"] cmd.clusterid = cluster.id @@ -1493,6 +1652,29 @@ class Host: cmd.id = self.id return apiclient.prepareHostForMaintenance(cmd) + @classmethod + def enableMaintenance(cls, apiclient, id): + """enables maintainance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = id + return apiclient.prepareHostForMaintenance(cmd) + + def cancelMaintenance(self, apiclient): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = self.id + return apiclient.cancelHostMaintenance(cmd) + + @classmethod + def cancelMaintenance(cls, apiclient, id): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = id + return apiclient.cancelHostMaintenance(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all Hosts matching criteria""" @@ -1586,7 +1768,8 @@ class Network: @classmethod def create(cls, apiclient, services, accountid=None, domainid=None, - networkofferingid=None, projectid=None, zoneid=None, + networkofferingid=None, projectid=None, + subdomainaccess=None, zoneid=None, gateway=None, netmask=None, vpcid=None, guestcidr=None): """Create Network for account""" cmd = createNetwork.createNetworkCmd() @@ -1603,6 +1786,9 @@ class Network: elif "zoneid" in services: cmd.zoneid = services["zoneid"] + if subdomainaccess is not None: + cmd.subdomainaccess = subdomainaccess + if gateway: cmd.gateway = gateway elif "gateway" in services: @@ -1717,7 +1903,7 @@ class Vpn: @classmethod def create(cls, apiclient, publicipid, account=None, domainid=None, - projectid=None, vpcid=None): + projectid=None, networkid=None, vpcid=None): """Create VPN for Public IP address""" cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd() cmd.publicipid = publicipid @@ -1727,6 +1913,8 @@ class Vpn: cmd.domainid = domainid if projectid: cmd.projectid = projectid + if networkid: + cmd.networkid = networkid if vpcid: cmd.vpcid = vpcid return Vpn(apiclient.createRemoteAccessVpn(cmd).__dict__) @@ -1755,10 +1943,11 @@ class VpnUser: @classmethod def create(cls, apiclient, username, password, account=None, domainid=None, - projectid=None): + projectid=None, rand_name=True): """Create VPN user""" cmd = addVpnUser.addVpnUserCmd() - cmd.username = username + cmd.username = "-".join([username, + random_gen()]) if rand_name else username cmd.password = password if account: @@ -1997,6 +2186,7 @@ class PhysicalNetwork: [setattr(cmd, k, v) for k, v in kwargs.items()] return map(lambda pn : PhysicalNetwork(pn.__dict__), apiclient.listPhysicalNetworks(cmd)) + class SecurityGroup: """Manage Security Groups""" @@ -2364,6 +2554,104 @@ class NetworkServiceProvider: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listNetworkServiceProviders(cmd)) + +class Router: + """Manage router life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def start(cls, apiclient, id): + """Starts the router""" + cmd = startRouter.startRouterCmd() + cmd.id = id + return apiclient.startRouter(cmd) + + @classmethod + def stop(cls, apiclient, id, forced=None): + """Stops the router""" + cmd = stopRouter.stopRouterCmd() + cmd.id = id + if forced: + cmd.forced = forced + return apiclient.stopRouter(cmd) + + @classmethod + def reboot(cls, apiclient, id): + """Reboots the router""" + cmd = rebootRouter.rebootRouterCmd() + cmd.id = id + return apiclient.rebootRouter(cmd) + + @classmethod + def destroy(cls, apiclient, id): + """Destroy the router""" + cmd = destroyRouter.destroyRouterCmd() + cmd.id = id + return apiclient.destroyRouter(cmd) + + @classmethod + def change_service_offering(cls, apiclient, id, serviceofferingid): + """Change service offering of the router""" + cmd = changeServiceForRouter.changeServiceForRouterCmd() + cmd.id = id + cmd.serviceofferingid = serviceofferingid + return apiclient.changeServiceForRouter(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List routers""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRouters(cmd)) + + +class Tag: + """Manage tags""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, resourceIds, resourceType, tags): + """Create tags""" + + cmd = createTags.createTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + return Tag(apiclient.createTags(cmd).__dict__) + + def delete(self, apiclient, resourceIds, resourceType, tags): + """Delete tags""" + + cmd = deleteTags.deleteTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + apiclient.deleteTags(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all tags matching the criteria""" + + cmd = listTags.listTagsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTags(cmd)) + + class VpcOffering: """Manage VPC offerings""" @@ -2417,7 +2705,7 @@ class VPC: @classmethod def create(cls, apiclient, services, vpcofferingid, - zoneid, networkDomain=None, account=None, domainid=None): + zoneid, networkDomain=None, account=None, domainid=None): """Creates the virtual private connection (VPC)""" cmd = createVPC.createVPCCmd() @@ -2467,6 +2755,40 @@ class VPC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) + +class PrivateGateway: + """Manage private gateway lifecycle""" + def create(cls, apiclient, gateway, ipaddress, netmask, vlan, vpcid, + physicalnetworkid=None): + """Create private gateway""" + + cmd = createPrivateGateway.createPrivateGatewayCmd() + cmd.gateway = gateway + cmd.ipaddress = ipaddress + cmd.netmask = netmask + cmd.vlan = vlan + cmd.vpcid = vpcid + if physicalnetworkid: + cmd.physicalnetworkid = physicalnetworkid + + return PrivateGateway(apiclient.createPrivateGateway(cmd).__dict__) + + def delete(self, apiclient): + """Delete private gateway""" + + cmd = deletePrivateGateway.deletePrivateGatewayCmd() + cmd.id = self.id + return apiclient.deletePrivateGateway(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List private gateways""" + + cmd = listPrivateGateways.listPrivateGatewaysCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPrivateGateways(cmd)) + + class AffinityGroup: def __init__(self, items): self.__dict__.update(items) @@ -2495,9 +2817,35 @@ class AffinityGroup: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) +class StaticRoute: + """Manage static route lifecycle""" + @classmethod + def create(cls, apiclient, cidr, gatewayid): + """Create static route""" + + cmd = createStaticRoute.createStaticRouteCmd() + cmd.cidr = cidr + cmd.gatewayid = gatewayid + return StaticRoute(apiclient.createStaticRoute(cmd).__dict__) + + def delete(self, apiclient): + """Delete static route""" + + cmd = deleteStaticRoute.deleteStaticRouteCmd() + cmd.id = self.id + return apiclient.deleteStaticRoute(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List static route""" + + cmd = listStaticRoutes.listStaticRoutesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStaticRoutes(cmd)) + + class VNMC: """Manage VNMC lifecycle""" - def __init__(self, items): self.__dict__.update(items) @@ -2526,13 +2874,153 @@ class VNMC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listCiscoVnmcResources(cmd)) -class ASA1000V: - """Manage ASA 1000v lifecycle""" + +class SSHKeyPair: + """Manage SSH Key pairs""" + + def __init__(self, items, services): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, name=None, account=None, + domainid=None, projectid=None): + """Creates SSH keypair""" + cmd = createSSHKeyPair.createSSHKeyPairCmd() + cmd.name = name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + return (apiclient.createSSHKeyPair(cmd)) + + def delete(self, apiclient): + """Delete SSH key pair""" + cmd = deleteSSHKeyPair.deleteSSHKeyPairCmd() + cmd.name = self.name + apiclient.deleteSSHKeyPair(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all SSH key pairs""" + cmd = listSSHKeyPairs.listSSHKeyPairsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSSHKeyPairs(cmd)) + + +class Capacities: + """Manage Capacities""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists capacities""" + + cmd = listCapacity.listCapacityCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCapacity(cmd)) + + +class Alert: + """Manage alerts""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists alerts""" + + cmd = listAlerts.listAlertsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAlerts(cmd)) + + +class InstanceGroup: + """Manage VM instance groups""" def __init__(self, items): self.__dict__.update(items) @classmethod + def create(cls, apiclient, name=None, account=None, domainid=None, + projectid=None, networkid=None, rand_name=True): + """Creates instance groups""" + + cmd = createInstanceGroup.createInstanceGroupCmd() + cmd.name = "-".join([name, random_gen()]) if rand_name else name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + if networkid is not None: + cmd.networkid = networkid + return InstanceGroup(apiclient.createInstanceGroup(cmd).__dict__) + + def delete(self, apiclient): + """Delete instance group""" + cmd = deleteInstanceGroup.deleteInstanceGroupCmd() + cmd.id = self.id + apiclient.deleteInstanceGroup(cmd) + + def update(self, apiclient, **kwargs): + """Updates the instance groups""" + cmd = updateInstanceGroup.updateInstanceGroupCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.updateInstanceGroup(cmd)) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all instance groups""" + cmd = listInstanceGroups.listInstanceGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.listInstanceGroups(cmd)) + + def startInstances(self, apiclient): + """Starts all instances in a VM tier""" + + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.group = self.id + return apiclient.startVirtualMachine(cmd) + + def stopInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = stopVirtualMachine.stopVirtualMachineCmd() + cmd.group = self.id + return apiclient.stopVirtualMachine(cmd) + + def rebootInstances(self, apiclient): + """Reboot all instances in a VM tier""" + + cmd = rebootVirtualMachine.rebootVirtualMachineCmd() + cmd.group = self.id + return apiclient.rebootVirtualMachine(cmd) + + def deleteInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = destroyVirtualMachine.destroyVirtualMachineCmd() + cmd.group = self.id + return apiclient.destroyVirtualMachine(cmd) + + def changeServiceOffering(self, apiclient, serviceOfferingId): + """Change service offering of the vm tier""" + + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.group = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + + def recoverInstances(self, apiclient): + """Recover the instances from vm tier""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.group = self.id + apiclient.recoverVirtualMachine(cmd) + + +class ASA1000V: + """Manage ASA 1000v lifecycle""" def create(cls, apiclient, hostname, insideportprofile, clusterid, physicalnetworkid): """Registers ASA 1000v appliance""" diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index cff24a1b2d5..6892c41d1ec 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -106,12 +106,17 @@ def cleanup_resources(api_client, resources): obj.delete(api_client) -def is_server_ssh_ready(ipaddress, port, username, password, retries=50): +def is_server_ssh_ready(ipaddress, port, username, password, retries=50, keyPairFileLocation=None): """Return ssh handle else wait till sshd is running""" loop_cnt = retries while True: try: - ssh = remoteSSHClient(ipaddress, port, username, password) + ssh = remoteSSHClient( + host=ipaddress, + port=port, + user=username, + passwd=password, + keyPairFileLocation=keyPairFileLocation) except Exception as e: if loop_cnt == 0: raise e @@ -149,12 +154,16 @@ def fetch_api_client(config_file='datacenterCfg'): ) -def get_process_status(hostip, port, username, password, linklocalip, process): +def get_process_status(hostip, port, username, password, linklocalip, process, hypervisor=None): """Double hop and returns a process status""" #SSH to the machine ssh = remoteSSHClient(hostip, port, username, password) - ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + if str(hypervisor).lower() == 'vmware': + ssh_command = "ssh -i /var/lib/cloud/management/.ssh/id_rsa -ostricthostkeychecking=no " + else: + ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + ssh_command = ssh_command + \ "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" % ( linklocalip, diff --git a/tools/marvin/marvin/remoteSSHClient.py b/tools/marvin/marvin/remoteSSHClient.py index 4fb2f0de8f0..04450fdf0e2 100644 --- a/tools/marvin/marvin/remoteSSHClient.py +++ b/tools/marvin/marvin/remoteSSHClient.py @@ -23,11 +23,12 @@ import logging from contextlib import closing class remoteSSHClient(object): - def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO): + def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO, keyPairFileLocation=None): self.host = host self.port = port self.user = user self.passwd = passwd + self.keyPairFile = keyPairFileLocation self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.logger = logging.getLogger('sshClient') @@ -38,8 +39,19 @@ class remoteSSHClient(object): retry_count = retries while True: try: - self.ssh.connect(str(host),int(port), user, passwd) - self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + if keyPairFileLocation == None: + self.ssh.connect(str(host),int(port), user, passwd) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + else: + self.ssh.connect( + hostname=str(host), + port=int(port), + username=str(user), + key_filename=str(keyPairFileLocation), + look_for_keys=False + ) + self.logger.debug("connecting to server %s with user %s key %s"%(str(host), user, keyPairFileLocation)) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) except paramiko.SSHException, sshex: if retry_count == 0: raise cloudstackException.InvalidParameterException(repr(sshex)) From 0412c95ef845cb9b67d9fd4a3d89d11b2399b521 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Tue, 23 Apr 2013 15:05:20 +0200 Subject: [PATCH 09/17] CLOUDSTACK-2152 Fix rel number, needs to be present --- packaging/centos63/package.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/centos63/package.sh b/packaging/centos63/package.sh index faa089b73fa..c466f588776 100755 --- a/packaging/centos63/package.sh +++ b/packaging/centos63/package.sh @@ -44,7 +44,7 @@ if echo $VERSION | grep SNAPSHOT ; then else DEFVER="-D_ver $REALVER" DEFPRE= - DEFREL= + DEFREL="-D_rel 1" fi mkdir -p $RPMDIR/SPECS @@ -78,7 +78,7 @@ else REALVER=`echo $VERSION` DEFVER="-D_ver $REALVER" DEFPRE= - DEFREL= + DEFREL="-D_rel 1" fi mkdir -p $RPMDIR/SPECS From c34233d5b1091bda9cd6580351845f5c90dcff2f Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Fri, 26 Apr 2013 08:55:47 +0200 Subject: [PATCH 10/17] Fix small typo --- agent/conf/agent.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index e49afbf2aaf..7dc4ba8a18c 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -78,7 +78,7 @@ domr.scripts.dir=scripts/network/domr/kvm # a sensible default will be selected based on the network.bridge.type but can # be overridden here. # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver -# openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver +# openvswitch = com.cloud.hypervisor.kvm.resource.OvsVifDriver #libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver # set the hypervisor type, values are: kvm, lxc From c65ad6b8e80a90a535fded7e284dce8c74f94a98 Mon Sep 17 00:00:00 2001 From: Jayapal Date: Thu, 25 Apr 2013 15:19:31 +0530 Subject: [PATCH 11/17] CLOUDSTACK-2161 coping /etc/iptables/iptables-* to /etc/iptables/rules to work for old templates In 4.2 templates iptables-persistent is looking for /etc/iptables/rules.v4 file but the old templates 4.1 and earlier are looking for /etc/iptables/rules. So coping the file to both rules and rules.v4 Signed-off-by: Abhinandan Prateek --- .../systemvm/debian/config/etc/init.d/cloud-early-config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index 187ae25c40c..6ffd648faeb 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -520,6 +520,7 @@ setup_sshd(){ local eth=$2 [ -f /etc/ssh/sshd_config ] && sed -i -e "s/^[#]*ListenAddress.*$/ListenAddress $ip/" /etc/ssh/sshd_config sed -i "/3922/s/eth./$eth/" /etc/iptables/rules.v4 + sed -i "/3922/s/eth./$eth/" /etc/iptables/rules } @@ -692,6 +693,8 @@ setup_router() { enable_fwding 1 chkconfig nfs-common off cp /etc/iptables/iptables-router /etc/iptables/rules.v4 +#for old templates + cp /etc/iptables/iptables-router /etc/iptables/rules setup_sshd $ETH1_IP "eth1" } @@ -764,6 +767,7 @@ EOF disable_rpfilter enable_fwding 1 cp /etc/iptables/iptables-vpcrouter /etc/iptables/rules.v4 + cp /etc/iptables/iptables-vpcrouter /etc/iptables/rules setup_sshd $ETH0_IP "eth0" cp /etc/vpcdnsmasq.conf /etc/dnsmasq.conf cp /etc/cloud-nic.rules /etc/udev/rules.d/cloud-nic.rules @@ -790,6 +794,7 @@ setup_dhcpsrvr() { enable_fwding 0 chkconfig nfs-common off cp /etc/iptables/iptables-router /etc/iptables/rules.v4 + cp /etc/iptables/iptables-router /etc/iptables/rules if [ "$SSHONGUEST" == "true" ] then setup_sshd $ETH0_IP "eth0" @@ -825,6 +830,7 @@ setup_secstorage() { echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-secstorage /etc/iptables/rules.v4 + cp /etc/iptables/iptables-secstorage /etc/iptables/rules if [ "$hyp" == "vmware" ]; then setup_sshd $ETH1_IP "eth1" else @@ -849,6 +855,7 @@ setup_console_proxy() { sed -i /gateway/d /etc/hosts echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-consoleproxy /etc/iptables/rules.v4 + cp /etc/iptables/iptables-consoleproxy /etc/iptables/rules if [ "$hyp" == "vmware" ]; then setup_sshd $ETH1_IP "eth1" else @@ -874,6 +881,7 @@ setup_elbvm() { echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-elbvm /etc/iptables/rules.v4 + cp /etc/iptables/iptables-elbvm /etc/iptables/rules if [ "$SSHONGUEST" == "true" ] then setup_sshd $ETH0_IP "eth0" From 3a9001bfb6f44f322b55da41c67d748ac7528f89 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 26 Apr 2013 14:18:40 +0530 Subject: [PATCH 12/17] Correcting the case for secondary storage limit --- ui/scripts/domains.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/domains.js b/ui/scripts/domains.js index 8ee0ee6816a..e82f8ff44e8 100644 --- a/ui/scripts/domains.js +++ b/ui/scripts/domains.js @@ -530,7 +530,7 @@ case "10": domainObj["primaryStorageLimit"] = limit.max; break; - case "7": + case "11": domainObj["secondaryStorageLimit"] = limit.max; break; } From 318c7f2af0a664c057ec1ed057ccaad608339f62 Mon Sep 17 00:00:00 2001 From: Jayapal Date: Fri, 26 Apr 2013 14:28:02 +0530 Subject: [PATCH 13/17] CLOUDSTACK-1794 Throwing error when configuring egress rules for shared networks --- .../cloud/network/firewall/FirewallManagerImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 080f7b0edf6..4ad8868b86a 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.dao.*; import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -56,10 +57,6 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkRuleApplier; -import com.cloud.network.dao.FirewallRulesCidrsDao; -import com.cloud.network.dao.FirewallRulesDao; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; import com.cloud.network.element.FirewallServiceProvider; import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.PortForwardingServiceProvider; @@ -127,6 +124,8 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, @Inject ResourceTagDao _resourceTagDao; @Inject + NetworkDao _networkDao; + @Inject VpcManager _vpcMgr; @Inject List _firewallElements; @@ -150,6 +149,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, @Override public FirewallRule createEgressFirewallRule(FirewallRule rule) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); + + Network network = _networkDao.findById(rule.getNetworkId()); + if (network.getGuestType() == Network.GuestType.Shared) { + throw new InvalidParameterValueException("Egress firewall rules are not supported for " + network.getGuestType() + " networks"); + } return createFirewallRule(null, caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), From 93ef3ad55050657768703f22c0215427e09f544c Mon Sep 17 00:00:00 2001 From: Radhika PC Date: Fri, 26 Apr 2013 16:31:49 +0530 Subject: [PATCH 14/17] CLOUDSTACK-1567 ui and api changes --- docs/en-US/added-API-commands-4.2.xml | 24 ++++++++++++++++++++++++ docs/en-US/delete-event-alerts.xml | 12 ++++++++++++ docs/en-US/events.xml | 2 +- docs/en-US/images/eip-ns-basiczone.png | Bin 0 -> 55568 bytes 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 docs/en-US/images/eip-ns-basiczone.png diff --git a/docs/en-US/added-API-commands-4.2.xml b/docs/en-US/added-API-commands-4.2.xml index 4bec148ba96..34716240657 100644 --- a/docs/en-US/added-API-commands-4.2.xml +++ b/docs/en-US/added-API-commands-4.2.xml @@ -39,5 +39,29 @@ The response parameters are: id, ipaddress, secondaryips, gateway, netmask, macaddr, broadcasturi, isolationuri, isdefault, + + deleteAlerts + Deletes the specified alerts. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + archiveAlerts + Archives the specified alerts. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + deleteEvents + Deletes the specified events. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + archiveEvents + Archives the specified events. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + diff --git a/docs/en-US/delete-event-alerts.xml b/docs/en-US/delete-event-alerts.xml index 3eebcb727a0..ef39040c102 100644 --- a/docs/en-US/delete-event-alerts.xml +++ b/docs/en-US/delete-event-alerts.xml @@ -28,6 +28,18 @@ or by using the Details page. If you want to delete multiple alerts or events at the same time, you can use the respective context menu. You can delete alerts or events by category for a time period. + In order to support the delete or archive alerts, the following global parameters have been + added: + + + alert.purge.delay: The alerts older than specified + number of days are purged. Set the value to 0 to never purge alerts automatically. + + + alert.purge.interval: The interval in seconds to wait + before running the alert purge thread. The default is 86400 seconds (one day). + + Archived alerts or events cannot be viewed in the UI, or by using the API. They are maintained in the database for auditing or compliance purposes. diff --git a/docs/en-US/events.xml b/docs/en-US/events.xml index 4a1445873a4..3b93ee0451e 100644 --- a/docs/en-US/events.xml +++ b/docs/en-US/events.xml @@ -25,7 +25,7 @@ physical resources associated with a cloud environment. Events are used by monitoring systems, usage and billing systems, or any other event-driven workflow systems to discern a pattern and make the right business decision. In &PRODUCT; an event could be a state change of virtual or - psychical resources, an action performed by an user (action events), or policy based events + physical resources, an action performed by an user (action events), or policy based events (alerts). diff --git a/docs/en-US/images/eip-ns-basiczone.png b/docs/en-US/images/eip-ns-basiczone.png new file mode 100644 index 0000000000000000000000000000000000000000..315ff55dab9e4169559ab3d357ffc4486d8c25de GIT binary patch literal 55568 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 literal 0 HcmV?d00001 From 1adec812fad2fd58559d5b2e37b8b35d121486ce Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Fri, 26 Apr 2013 13:56:07 +0200 Subject: [PATCH 15/17] Please, please, pretty please try to stay away from the exec plugin whereever possible. It ussually ends up being non portable across developer operating systems. Most commands like cp have a perfectly usable equivalent in ant like the copy task. --- client/pom.xml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 743cd363005..a7c7009ffc2 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -450,16 +450,15 @@ - test - - - - - + + + + + From 7cf312a7707040c5f214b0c99c4189cf690c82b1 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 26 Apr 2013 11:18:42 -0700 Subject: [PATCH 16/17] CLOUDSTACK-2120: mixed zone management - API: extend listSnapshots API to to take in zonetype. --- .../user/snapshot/ListSnapshotsCmd.java | 7 +++++ .../storage/snapshot/SnapshotManagerImpl.java | 30 +++++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java index 17f20aeb0d0..d7e6bc87b7f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java @@ -58,6 +58,9 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.VOLUME_ID, type=CommandType.UUID, entityType = VolumeResponse.class, description="the ID of the disk volume") private Long volumeId; + + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -83,6 +86,10 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { return volumeId; } + public String getZoneType() { + return zoneType; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 490948ba5ae..7dafe4ac865 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; @@ -571,6 +572,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, String keyword = cmd.getKeyword(); String snapshotTypeStr = cmd.getSnapshotType(); String intervalTypeStr = cmd.getIntervalType(); + String zoneType = cmd.getZoneType(); Map tags = cmd.getTags(); Account caller = UserContext.current().getCaller(); @@ -602,17 +604,23 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); if (tags != null && !tags.isEmpty()) { - SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); - for (int count=0; count < tags.size(); count++) { - tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); - tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); - tagSearch.cp(); + SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); + for (int count=0; count < tags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); } - tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); - sb.groupBy(sb.entity().getId()); - sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); - } + if(zoneType != null) { + SearchBuilder zoneSb = _dcDao.createSearchBuilder(); + zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + sb.join("zoneSb", zoneSb, sb.entity().getDataCenterId(), zoneSb.entity().getId(), JoinBuilder.JoinType.INNER); + } + SearchCriteria sc = sb.create(); _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); @@ -630,6 +638,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + } + if (name != null) { sc.setParameters("name", "%" + name + "%"); } From 3e2eb59723f6aa58170e8650ca8ef03a8b2d6b45 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 26 Apr 2013 11:26:21 -0700 Subject: [PATCH 17/17] CLOUDSTACK-2120: mixed zone management - UI: make global function changeURL() to pass zonetype to API calls based on selected option in zone type dropdown on top menu. --- ui/scripts/sharedFunctions.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 74675314040..a01840637e3 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -114,6 +114,10 @@ function createURL(apiName, options) { if (cloudStack.context && cloudStack.context.projects && !options.ignoreProject) { urlString = urlString + '&projectid=' + cloudStack.context.projects[0].id; } + + if(cloudStack.context != null && cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + urlString = urlString + '&zonetype=' + cloudStack.context.zoneType; + } return urlString; }