From d623ee3deefcb4862f8a8205bc765fcbaff30bde Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 13:24:28 -0700 Subject: [PATCH 01/10] cloudstack 3.0 UI - network page - Guest Network section - create Guest Network - If selected network offering includes forvpc = true, show VPC dropdown. Otherwise, hide VPC dropdown. --- ui/scripts/network.js | 80 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 9a9facc9ad4..4e559acaae6 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -152,6 +152,8 @@ } }; + var networkOfferingObjs = []; + cloudStack.sections.network = { title: 'label.network', id: 'network', @@ -257,9 +259,9 @@ state: 'Enabled' }, success: function(json) { - var networkOfferings = json.listnetworkofferingsresponse.networkoffering; + networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; args.response.success({ - data: $.map(networkOfferings, function(zone) { + data: $.map(networkOfferingObjs, function(zone) { return { id: zone.id, description: zone.name @@ -270,24 +272,74 @@ }); } }, + vpcid: { + label: 'VPC', + dependsOn: 'networkOfferingId', + select: function(args) { + var networkOfferingObj; + $(networkOfferingObjs).each(function(key, value) { + if(value.id == args.networkOfferingId) { + networkOfferingObj = value; + return false; //break each loop + } + }); + if(networkOfferingObj.forvpc == true) { + args.$select.closest('.form-item').css('display', 'inline-block'); + $.ajax({ + url: createURL('listVPCs'), + data: { + listAll: true + }, + success: function(json) { + var items = json.listvpcsresponse.vpc; + var data; + if(items != null && items.length > 0) { + data = $.map(items, function(item) { + return { + id: item.id, + description: item.name + } + }); + } + args.response.success({ data: data }); + } + }); + } + else { + args.$select.closest('.form-item').hide(); + args.response.success({ data: null }); + } + } + }, guestGateway: { label: 'label.guest.gateway' }, guestNetmask: { label: 'label.guest.netmask' } } }, action: function(args) { - var array1 = []; - array1.push("&zoneId=" + args.data.zoneId); - array1.push("&name=" + todb(args.data.name)); - array1.push("&displayText=" + todb(args.data.displayText)); - array1.push("&networkOfferingId=" + args.data.networkOfferingId); - - if(args.data.guestGateway != null && args.data.guestGateway.length > 0) - array1.push("&gateway=" + args.data.guestGateway); - if(args.data.guestNetmask != null && args.data.guestNetmask.length > 0) - array1.push("&netmask=" + args.data.guestNetmask); - + var dataObj = { + zoneId: args.data.zoneId, + name: args.data.name, + displayText: args.data.displayText, + networkOfferingId: args.data.networkOfferingId + }; + if(args.data.guestGateway != null && args.data.guestGateway.length > 0) { + $.extend(dataObj, { + gateway: args.data.guestGateway + }); + } + if(args.data.guestNetmask != null && args.data.guestNetmask.length > 0) { + $.extend(dataObj, { + netmask: args.data.guestNetmask + }); + } + if(args.$form.find('.form-item[rel=vpcid]').css("display") != "none") { + $.extend(dataObj, { + vpcid: args.data.vpcid + }); + } $.ajax({ - url: createURL('createNetwork' + array1.join("")), + url: createURL('createNetwork'), + data: dataObj, success: function(json) { args.response.success({ data: json.createnetworkresponse.network From d7214db5ae84a6c03e2261afe2d7a3c2e007de91 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Mon, 16 Jul 2012 13:34:25 -0700 Subject: [PATCH 02/10] VPC: CS-15583 - hostName for the vm should be unique inside the network domain --- .../com/cloud/network/dao/NetworkDaoImpl.java | 3 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 31 ++++++++++++++++- .../src/com/cloud/vm/dao/VMInstanceDao.java | 8 +++++ .../com/cloud/vm/dao/VMInstanceDaoImpl.java | 34 ++++++++++++++++++- 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/server/src/com/cloud/network/dao/NetworkDaoImpl.java index ecb6a593eb9..90bb0166b6f 100644 --- a/server/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/server/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -67,8 +67,9 @@ public class NetworkDaoImpl extends GenericDaoBase implements N private final GenericSearchBuilder NetworksCount; final SearchBuilder SourceNATSearch; final GenericSearchBuilder CountByZoneAndURI; + + ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); - NetworkAccountDaoImpl _accountsDao = ComponentLocator.inject(NetworkAccountDaoImpl.class); NetworkDomainDaoImpl _domainsDao = ComponentLocator.inject(NetworkDomainDaoImpl.class); NetworkOpDaoImpl _opDao = ComponentLocator.inject(NetworkOpDaoImpl.class); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index fb1399b7abd..7c813591b4f 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2424,14 +2424,43 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager String instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); String uuidName = UUID.randomUUID().toString(); + + //verify hostname information if (hostName == null) { hostName = uuidName; } else { - // verify hostName (hostname doesn't have to be unique) + //1) check is hostName is RFC complient if (!NetUtils.verifyDomainNameLabel(hostName, true)) { throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit", null); } + //2) hostName has to be unique in the network domain + Map> ntwkDomains = new HashMap>(); + for (NetworkVO network : networkList) { + String ntwkDomain = network.getNetworkDomain(); + if (!ntwkDomains.containsKey(ntwkDomain)) { + List ntwkIds = new ArrayList(); + ntwkIds.add(network.getId()); + ntwkDomains.put(ntwkDomain, ntwkIds); + } else { + List ntwkIds = ntwkDomains.get(ntwkDomain); + ntwkIds.add(network.getId()); + ntwkDomains.put(ntwkDomain, ntwkIds); + } + } + + for (String ntwkDomain : ntwkDomains.keySet()) { + for (Long ntwkId : ntwkDomains.get(ntwkDomain)) { + //* get all vms hostNames in the network + List hostNames = _vmInstanceDao.listDistinctHostNames(ntwkId); + //* verify that there are no duplicates + if (hostNames.contains(hostName)) { + throw new InvalidParameterValueException("The vm with hostName " + hostName + + " already exists in the network domain: " + ntwkDomain + "; network=" + + _networkMgr.getNetwork(ntwkId)); + } + } + } } HypervisorType hypervisorType = null; diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/server/src/com/cloud/vm/dao/VMInstanceDao.java index e9a6daeb4e2..149849df7cf 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDao.java @@ -22,6 +22,7 @@ import com.cloud.utils.fsm.StateDao; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachine.Type; /* @@ -96,4 +97,11 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types); + /** + * @param networkId + * @param types + * @return + */ + List listDistinctHostNames(long networkId, VirtualMachine.Type... types); + } diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index 51e80fd65c1..b40d871e25d 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -74,7 +74,10 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected GenericSearchBuilder CountRunningByHost; protected GenericSearchBuilder CountRunningByAccount; protected SearchBuilder NetworkTypeSearch; + protected GenericSearchBuilder DistinctHostNameSearch; + ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); + NicDao _nicDao = ComponentLocator.inject(NicDaoImpl.class); protected final Attribute _updateTimeAttr; @@ -94,6 +97,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected final HostDaoImpl _hostDao = ComponentLocator.inject(HostDaoImpl.class); protected VMInstanceDaoImpl() { + IdStatesSearch = createSearchBuilder(); IdStatesSearch.and("id", IdStatesSearch.entity().getId(), Op.EQ); IdStatesSearch.and("states", IdStatesSearch.entity().getState(), Op.IN); @@ -529,7 +533,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem @Override public List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types) { if (NetworkTypeSearch == null) { - NicDao _nicDao = ComponentLocator.getLocator("management-server").getDao(NicDao.class); + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); @@ -550,6 +554,34 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return listBy(sc); } + + + @Override + public List listDistinctHostNames(long networkId, VirtualMachine.Type... types) { + if (DistinctHostNameSearch == null) { + + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); + nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + + DistinctHostNameSearch = createSearchBuilder(String.class); + DistinctHostNameSearch.selectField(DistinctHostNameSearch.entity().getHostName()); + + DistinctHostNameSearch.and("types", DistinctHostNameSearch.entity().getType(), SearchCriteria.Op.IN); + DistinctHostNameSearch.and("removed", DistinctHostNameSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), + nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); + DistinctHostNameSearch.done(); + } + + SearchCriteria sc = DistinctHostNameSearch.create(); + if (types != null && types.length != 0) { + sc.setParameters("types", (Object[]) types); + } + sc.setJoinParameters("nicSearch", "networkId", networkId); + + return customSearch(sc, null); + } + @Override @DB public boolean remove(Long id) { From dcea0a70f9842aecf643fb9f25844f5a73f98199 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 13:44:20 -0700 Subject: [PATCH 03/10] cloudstack 3.0 UI - listView widget - pass context from caller function. --- ui/scripts/ui/widgets/listView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index 87c3e421424..2f66b0495b1 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -1163,7 +1163,7 @@ var showAdd = listViewData.actions.add.preFilter ? listViewData.actions.add.preFilter({ context: listViewData.context ? - listViewData.context : cloudStack.context + listViewData.context : args.context }) : true; if (showAdd) { From a36fc7a9fa53836eff04cc3c0da7675bb7564b65 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 13:49:07 -0700 Subject: [PATCH 04/10] =?UTF-8?q?cloudstack=203.0=20UI=20-=20IP=20Address?= =?UTF-8?q?=20page=20=E2=80=93=20if=20it=20comes=20from=20Guest=20Network?= =?UTF-8?q?=20section=20and=20it=E2=80=99s=20a=20VPC=20network,=20remove?= =?UTF-8?q?=20=E2=80=9CAcquire=20IP=E2=80=9D=20button.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/scripts/network.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 4e559acaae6..a517c570f8a 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1050,7 +1050,18 @@ actions: { add: { label: 'label.acquire.new.ip', - addRow: 'true', + addRow: 'true', + preFilter: function(args) { + if('networks' in args.context) { //from Guest Network section + if(args.context.networks[0].vpcid == null) //if it's a non-VPC network, show Acquire IP button + return true; + else //if it's a VPC network, hide Acquire IP button + return false; + } + else { //from VPC section + return true; //show Acquire IP button + } + }, messages: { confirm: function(args) { return 'message.acquire.new.ip'; From 38e0c4b31a3d26e76df082dd1d2c0f0aa9d16192 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 14:07:42 -0700 Subject: [PATCH 05/10] cloudstack 3.0 UI - VPC - create VPC action - make it async instead of sync. --- ui/scripts/network.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index a517c570f8a..ada01629d28 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -3595,7 +3595,12 @@ ); } }); - } + }, + + notification: { + poll: pollAsyncJobResult + } + }, configureVpc: { label: 'Configure VPC', From 0fdf1a1d8a739a19f3533690c5f5be6db0c39067 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Mon, 16 Jul 2012 14:36:13 -0700 Subject: [PATCH 06/10] Resource tags: CS-15591 - delete tags for template/iso when corresponding vo object is removed --- server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index cae54bc265f..49453f7e539 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -851,8 +851,10 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem txn.start(); VMTemplateVO template = createForUpdate(); template.setRemoved(new Date()); - if (template != null) { - if (template.getFormat() == ImageFormat.ISO) { + + VMTemplateVO vo = findById(id); + if (vo != null) { + if (vo.getFormat() == ImageFormat.ISO) { _tagsDao.removeByIdAndType(id, TaggedResourceType.ISO); } else { _tagsDao.removeByIdAndType(id, TaggedResourceType.Template); From 845569b121308b3be1bebfe544246ee4fd2a8328 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 15:17:23 -0700 Subject: [PATCH 07/10] cloudstack 3.0 UI - VPC - create private gateway action - make it async instead of sync. --- ui/scripts/vpc.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 8192c908a8e..f411d1108a0 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -439,7 +439,12 @@ return true; else return false; - }, + }, + messages: { + notification: function(args) { + return 'Add new gateway'; + } + }, createForm: { title: 'Add new gateway', desc: 'Please specify the information to add a new gateway to this VPC.', @@ -476,10 +481,10 @@ args.response.error(parseXMLHttpResponse(json)); } }); - }, - messages: { - notification: function() { return 'Add gateway to VPC'; } - } + }, + notification: { + poll: pollAsyncJobResult + } } }, dataProvider: function(args) { From 13fd9c97742049b1138386f1da1d119575beaa21 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 16:00:53 -0700 Subject: [PATCH 08/10] cloudstack 3.0 UI - VPC - private gateway - only root-admin is allowed to delete a private gateway. --- ui/scripts/vpc.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index f411d1108a0..ac101afc2e4 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -561,7 +561,16 @@ }, success: function(json) { var item = json.listprivategatewaysresponse.privategateway[0]; - args.response.success({ data: item }); + args.response.success({ + data: item, + actionFilter: function(args) { + var allowedActions = []; + if(isAdmin()) { + allowedActions.push("remove"); + } + return allowedActions; + } + }); } }); } From b3aad47570d6aedaf3ba958e3eccd65f4882ad10 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 16:06:57 -0700 Subject: [PATCH 09/10] cloudstack 3.0 UI - VPC - private gateway - make root-admin able to see private gateways created by other people. --- ui/scripts/vpc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index ac101afc2e4..40828b16f46 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -557,7 +557,8 @@ $.ajax({ url: createURL('listPrivateGateways'), data: { - id: args.context.vpcGateways[0].id + id: args.context.vpcGateways[0].id, + listAll: true }, success: function(json) { var item = json.listprivategatewaysresponse.privategateway[0]; From d4f8d3b3a4d2d17e37ecee771ea7b9ec5c366f73 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 16 Jul 2012 17:05:39 -0700 Subject: [PATCH 10/10] cloudstack 3.0 UI - network page - Guest Network section - select a VPC network - IP Address' configuration chart will be the same as the one from VPC section. --- ui/scripts/network.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index ada01629d28..a0cde663062 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1693,7 +1693,7 @@ var havingLbService = false; var havingVpnService = false; - if('networks' in args.context) { //from Guest Network section + if('networks' in args.context && args.context.networks[0].vpcid == null) { //a non-VPC network from Guest Network section $.ajax({ url: createURL("listNetworkOfferings&id=" + args.context.networks[0].networkofferingid), dataType: "json", @@ -1714,7 +1714,7 @@ } }); } - else { //from VPC section + else { //a VPC network from Guest Network section or from VPC section havingFirewallService = false; //firewall is not supported in IP from VPC section (because ACL has already supported in tier from VPC section) havingVpnService = false; //VPN is not supported in IP from VPC section