From f2a927b9fa542b4008ed7cf82c26de98984efd80 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 Aug 2012 17:07:09 -0700 Subject: [PATCH 01/17] CS-15883: cloudstack 3.0 UI - VPC - VM Wizard - step 1 - zone dropdown - populate only one zone, the one that the VPC is under. --- ui/scripts/instanceWizard.js | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js index d96cbb87f43..f4e43adca29 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -29,28 +29,29 @@ // Data providers for each wizard step steps: [ - // Step 1: Setup - function(args) { - $.ajax({ - url: createURL("listZones&available=true"), - dataType: "json", - async: false, - success: function(json) { - zoneObjs = json.listzonesresponse.zone; - - var items; - if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart - items = $.grep(zoneObjs, function(zoneObj) { - return zoneObj.networktype == 'Advanced'; - }); + + // Step 1: Setup + function(args) { + if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart + //populate only one zone to the dropdown, the zone which the VPC is under. + zoneObjs = [{ + id: args.context.vpc[0].zoneid, + name: args.context.vpc[0].zonename, + networktype: 'Advanced' + }]; + args.response.success({ data: {zones: zoneObjs}}); + } + else { //from Instance page + $.ajax({ + url: createURL("listZones&available=true"), + dataType: "json", + async: false, + success: function(json) { + zoneObjs = json.listzonesresponse.zone; + args.response.success({ data: {zones: zoneObjs}}); } - else { //from Instance page - items = zoneObjs; - } - - args.response.success({ data: {zones: items}}); - } - }); + }); + } }, // Step 2: Select template From f49d7089d2153d53e65495bcd625e3d4f5850715 Mon Sep 17 00:00:00 2001 From: anthony Date: Thu, 9 Aug 2012 18:54:04 -0700 Subject: [PATCH 02/17] CS-15923 : only check result when "get" networkusage is called --- .../vmware/resource/VmwareResource.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 4099531df9b..38c5123dc08 100755 --- a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -536,23 +536,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } else { return new NetworkUsageAnswer(cmd, "success", 0L, 0L); } - try { if (s_logger.isTraceEnabled()) { s_logger.trace("Executing /opt/cloud/bin/vpc_netusage.sh " + args + " on DomR " + privateIp); } - VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); Pair resultPair = SshHelper.sshExecute(privateIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null, "/opt/cloud/bin/vpc_netusage.sh " + args); if (!resultPair.first()) { - return null; + throw new Exception(" vpc network usage plugin call failed "); } - - String result = resultPair.second(); if (option.equals("get")) { + String result = resultPair.second(); + if (result == null || result.isEmpty()) { + throw new Exception(" vpc network usage get returns empty "); + } long[] stats = new long[2]; if (result != null) { String[] splitResult = result.split(":"); @@ -564,16 +564,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return new NetworkUsageAnswer(cmd, "success", stats[0], stats[1]); } } - if (result == null || result.isEmpty()) { - throw new Exception(" vpc network usage plugin call failed "); - } return new NetworkUsageAnswer(cmd, "success", 0L, 0L); - - } catch (Throwable e) { + } catch (Throwable e) { s_logger.error("Unable to execute NetworkUsage command on DomR (" + privateIp + "), domR may not be ready yet. failure due to " + VmwareHelper.getExceptionMessage(e), e); } - return null; } From 9fc16802c77541931e8d86920220958446727351 Mon Sep 17 00:00:00 2001 From: kishan Date: Fri, 10 Aug 2012 09:52:54 +0530 Subject: [PATCH 03/17] bug CS-15852: Add vpn usage rules in iptables magle table status CS-15852: resolved fixed --- .../systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh b/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh index 9673b40a0d2..5f866596c19 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/vpc_netusage.sh @@ -70,8 +70,8 @@ get_usage () { # flush rules and remove chain iptables -F NETWORK_STATS_$i > /dev/null; iptables -X NETWORK_STATS_$i > /dev/null; - iptables -F VPN_STATS_$i > /dev/null; - iptables -X VPN_STATS_$i > /dev/null; + iptables -t mangle -F VPN_STATS_$i > /dev/null; + iptables -t mangle -X VPN_STATS_$i > /dev/null; fi done rm /root/removedVifs @@ -80,7 +80,7 @@ get_usage () { } get_vpn_usage () { - iptables -L VPN_STATS_$ethDev -n -v -x | awk '$1 ~ /^[0-9]+$/ { printf "%s:", $2}'; > /dev/null + iptables -t mangle -L VPN_STATS_$ethDev -n -v -x | awk '$1 ~ /^[0-9]+$/ { printf "%s:", $2}'; > /dev/null if [ $? -gt 0 ] then printf $? From b82fddd6296c3556f5e48ea39ab048471f844c1d Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Fri, 10 Aug 2012 10:28:25 +0530 Subject: [PATCH 04/17] bug CS-15919: added details parameter value can be a comma separated list of [all, vm, account, storage_type, disk_offering, min] --- api/src/com/cloud/api/ApiConstants.java | 4 + api/src/com/cloud/api/ResponseGenerator.java | 3 + .../cloud/api/commands/ListVolumesCmd.java | 29 ++- .../src/com/cloud/api/ApiResponseHelper.java | 209 ++++++++++-------- .../xen/discoverer/XcpServerDiscoverer.java | 9 +- 5 files changed, 155 insertions(+), 99 deletions(-) diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 7dd885cfe99..a44e70c1d49 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -409,6 +409,10 @@ public class ApiConstants { public enum VMDetails { all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min; } + + public enum VolumeDetails { + all, vm, account, storage_type, disk_offering, min; + } public enum LDAPParams { hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass; diff --git a/api/src/com/cloud/api/ResponseGenerator.java b/api/src/com/cloud/api/ResponseGenerator.java index d65d155433e..73a306416cf 100755 --- a/api/src/com/cloud/api/ResponseGenerator.java +++ b/api/src/com/cloud/api/ResponseGenerator.java @@ -18,6 +18,7 @@ import java.util.List; import com.cloud.api.ApiConstants.HostDetails; import com.cloud.api.ApiConstants.VMDetails; +import com.cloud.api.ApiConstants.VolumeDetails; import com.cloud.api.commands.QueryAsyncJobResultCmd; import com.cloud.api.response.AccountResponse; import com.cloud.api.response.AsyncJobResponse; @@ -198,6 +199,8 @@ public interface ResponseGenerator { ZoneResponse createZoneResponse(DataCenter dataCenter, Boolean showCapacities); VolumeResponse createVolumeResponse(Volume volume); + + VolumeResponse createVolumeResponse(Volume volume, EnumSet details); InstanceGroupResponse createInstanceGroupResponse(InstanceGroup group); diff --git a/api/src/com/cloud/api/commands/ListVolumesCmd.java b/api/src/com/cloud/api/commands/ListVolumesCmd.java index 454e4183997..094661cd408 100755 --- a/api/src/com/cloud/api/commands/ListVolumesCmd.java +++ b/api/src/com/cloud/api/commands/ListVolumesCmd.java @@ -13,6 +13,7 @@ package com.cloud.api.commands; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import org.apache.log4j.Logger; @@ -24,7 +25,9 @@ import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.response.ListResponse; import com.cloud.api.response.VolumeResponse; +import com.cloud.api.ApiConstants.VolumeDetails; import com.cloud.async.AsyncJob; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.storage.Volume; @Implementation(description="Lists all volumes.", responseObject=VolumeResponse.class) @@ -63,6 +66,10 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the ID of the availability zone") private Long zoneId; + @Parameter(name=ApiConstants.DETAILS, type=CommandType.LIST, collectionType=CommandType.STRING, description="comma separated list of volume details requested, " + + "value can be a comma separated list of [all, vm, account, storage_type, disk_offering, min]. If no parameter is passed in, the details will be defaulted to all" ) + private List viewDetails; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -96,6 +103,26 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { return zoneId; } + public EnumSet getDetails() throws InvalidParameterValueException { + EnumSet dv; + if (viewDetails==null || viewDetails.size() <=0){ + dv = EnumSet.of(VolumeDetails.all); + } + else { + try { + ArrayList dc = new ArrayList(); + for (String detail: viewDetails){ + dc.add(VolumeDetails.valueOf(detail)); + } + dv = EnumSet.copyOf(dc); + } + catch (IllegalArgumentException e){ + throw new InvalidParameterValueException("The details parameter contains a non permitted value. The allowed values are " + EnumSet.allOf(VolumeDetails.class), null); + } + } + return dv; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -117,7 +144,7 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { ListResponse response = new ListResponse(); List volResponses = new ArrayList(); for (Volume volume : volumes) { - VolumeResponse volResponse = _responseGenerator.createVolumeResponse(volume); + VolumeResponse volResponse = _responseGenerator.createVolumeResponse(volume, getDetails()); volResponse.setObjectName("volume"); volResponses.add(volResponse); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 5fdc3dd2be1..b78b989ad32 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -31,6 +31,7 @@ import com.cloud.acl.ControlledEntity; import com.cloud.acl.ControlledEntity.ACLType; import com.cloud.api.ApiConstants.HostDetails; import com.cloud.api.ApiConstants.VMDetails; +import com.cloud.api.ApiConstants.VolumeDetails; import com.cloud.api.commands.QueryAsyncJobResultCmd; import com.cloud.api.response.AccountResponse; import com.cloud.api.response.ApiResponseSerializer; @@ -1045,8 +1046,14 @@ public class ApiResponseHelper implements ResponseGenerator { return capacityResponses; } + @Override public VolumeResponse createVolumeResponse(Volume volume) { + return createVolumeResponse(volume, EnumSet.of(VolumeDetails.all)); + } + + @Override + public VolumeResponse createVolumeResponse(Volume volume, EnumSet details) { VolumeResponse volResponse = new VolumeResponse(); volResponse.setId(volume.getId()); @@ -1057,124 +1064,134 @@ public class ApiResponseHelper implements ResponseGenerator { } volResponse.setZoneId(volume.getDataCenterId()); - volResponse.setZoneName(ApiDBUtils.findZoneById(volume.getDataCenterId()).getName()); - volResponse.setVolumeType(volume.getVolumeType().toString()); volResponse.setDeviceId(volume.getDeviceId()); - - Long instanceId = volume.getInstanceId(); - if (instanceId != null && volume.getState() != Volume.State.Destroy) { - VMInstanceVO vm = ApiDBUtils.findVMInstanceById(instanceId); - if (vm != null) { - volResponse.setVirtualMachineId(vm.getId()); - volResponse.setVirtualMachineName(vm.getHostName()); - UserVm userVm = ApiDBUtils.findUserVmById(vm.getId()); - if (userVm != null) { - if (userVm.getDisplayName() != null) { - volResponse.setVirtualMachineDisplayName(userVm.getDisplayName()); - } else { - volResponse.setVirtualMachineDisplayName(userVm.getHostName()); - } - volResponse.setVirtualMachineState(vm.getState().toString()); - } else { - s_logger.error("User Vm with Id: " + instanceId + " does not exist for volume " + volume.getId()); - } - } else { - s_logger.error("Vm with Id: " + instanceId + " does not exist for volume " + volume.getId()); - } - } - // Show the virtual size of the volume volResponse.setSize(volume.getSize()); - volResponse.setCreated(volume.getCreated()); volResponse.setState(volume.getState().toString()); - if(volume.getState() == Volume.State.UploadOp){ - com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId()); - volResponse.setSize(volumeHostRef.getSize()); - volResponse.setCreated(volumeHostRef.getCreated()); - Account caller = UserContext.current().getCaller(); - if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) - volResponse.setHypervisor(ApiDBUtils.getHypervisorTypeFromFormat(volumeHostRef.getFormat()).toString()); - if (volumeHostRef.getDownloadState() != Status.DOWNLOADED) { - String volumeStatus = "Processing"; - if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { - if (volumeHostRef.getDownloadPercent() == 100) { - volumeStatus = "Checking Volume"; - } else { - volumeStatus = volumeHostRef.getDownloadPercent() + "% Uploaded"; - } - volResponse.setState("Uploading"); - } else { - volumeStatus = volumeHostRef.getErrorString(); - if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){ - volResponse.setState("UploadNotStarted"); - }else { - volResponse.setState("UploadError"); - } - } - volResponse.setStatus(volumeStatus); - } else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { - volResponse.setStatus("Upload Complete"); - volResponse.setState("Uploaded"); - } else { - volResponse.setStatus("Successfully Installed"); - } + volResponse.setAttached(volume.getAttached()); + volResponse.setDestroyed(volume.getState() == Volume.State.Destroy); + + if (details.contains(VolumeDetails.vm) || details.contains(VolumeDetails.all)){ + volResponse.setZoneName(ApiDBUtils.findZoneById(volume.getDataCenterId()).getName()); + Long instanceId = volume.getInstanceId(); + if (instanceId != null && volume.getState() != Volume.State.Destroy) { + VMInstanceVO vm = ApiDBUtils.findVMInstanceById(instanceId); + if (vm != null) { + volResponse.setVirtualMachineId(vm.getId()); + volResponse.setVirtualMachineName(vm.getHostName()); + UserVm userVm = ApiDBUtils.findUserVmById(vm.getId()); + if (userVm != null) { + if (userVm.getDisplayName() != null) { + volResponse.setVirtualMachineDisplayName(userVm.getDisplayName()); + } else { + volResponse.setVirtualMachineDisplayName(userVm.getHostName()); + } + volResponse.setVirtualMachineState(vm.getState().toString()); + } else { + s_logger.error("User Vm with Id: " + instanceId + " does not exist for volume " + volume.getId()); + } + } else { + s_logger.error("Vm with Id: " + instanceId + " does not exist for volume " + volume.getId()); + } + } } - populateOwner(volResponse, volume); + if (details.contains(VolumeDetails.all)){ + if(volume.getState() == Volume.State.UploadOp){ + com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId()); + volResponse.setSize(volumeHostRef.getSize()); + volResponse.setCreated(volumeHostRef.getCreated()); + Account caller = UserContext.current().getCaller(); + if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) + volResponse.setHypervisor(ApiDBUtils.getHypervisorTypeFromFormat(volumeHostRef.getFormat()).toString()); + if (volumeHostRef.getDownloadState() != Status.DOWNLOADED) { + String volumeStatus = "Processing"; + if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + if (volumeHostRef.getDownloadPercent() == 100) { + volumeStatus = "Checking Volume"; + } else { + volumeStatus = volumeHostRef.getDownloadPercent() + "% Uploaded"; + } + volResponse.setState("Uploading"); + } else { + volumeStatus = volumeHostRef.getErrorString(); + if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){ + volResponse.setState("UploadNotStarted"); + }else { + volResponse.setState("UploadError"); + } + } + volResponse.setStatus(volumeStatus); + } else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + volResponse.setStatus("Upload Complete"); + volResponse.setState("Uploaded"); + } else { + volResponse.setStatus("Successfully Installed"); + } + } + } + + if (details.contains(VolumeDetails.account) || details.contains(VolumeDetails.all)){ + populateOwner(volResponse, volume); + } if (volume.getVolumeType().equals(Volume.Type.ROOT)) { volResponse.setServiceOfferingId(volume.getDiskOfferingId()); } else { volResponse.setDiskOfferingId(volume.getDiskOfferingId()); } - - DiskOfferingVO diskOffering = ApiDBUtils.findDiskOfferingById(volume.getDiskOfferingId()); - if (volume.getVolumeType().equals(Volume.Type.ROOT)) { - volResponse.setServiceOfferingName(diskOffering.getName()); - volResponse.setServiceOfferingDisplayText(diskOffering.getDisplayText()); - } else { - volResponse.setDiskOfferingName(diskOffering.getName()); - volResponse.setDiskOfferingDisplayText(diskOffering.getDisplayText()); + + if (details.contains(VolumeDetails.disk_offering) || details.contains(VolumeDetails.all)){ + DiskOfferingVO diskOffering = ApiDBUtils.findDiskOfferingById(volume.getDiskOfferingId()); + if (volume.getVolumeType().equals(Volume.Type.ROOT)) { + volResponse.setServiceOfferingName(diskOffering.getName()); + volResponse.setServiceOfferingDisplayText(diskOffering.getDisplayText()); + } else { + volResponse.setDiskOfferingName(diskOffering.getName()); + volResponse.setDiskOfferingDisplayText(diskOffering.getDisplayText()); + } + volResponse.setStorageType(diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString()); + } + + if (details.contains(VolumeDetails.storage_type) || details.contains(VolumeDetails.all)){ + Long poolId = volume.getPoolId(); + String poolName = (poolId == null) ? "none" : ApiDBUtils.findStoragePoolById(poolId).getName(); + volResponse.setStoragePoolName(poolName); } - volResponse.setStorageType(diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString()); - - Long poolId = volume.getPoolId(); - String poolName = (poolId == null) ? "none" : ApiDBUtils.findStoragePoolById(poolId).getName(); - volResponse.setStoragePoolName(poolName); // volResponse.setSourceId(volume.getSourceId()); // if (volume.getSourceType() != null) { // volResponse.setSourceType(volume.getSourceType().toString()); // } - // return hypervisor for ROOT and Resource domain only - Account caller = UserContext.current().getCaller(); - if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) && volume.getState() != Volume.State.UploadOp) { - volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString()); + if (details.contains(VolumeDetails.all)){ + // return hypervisor for ROOT and Resource domain only + Account caller = UserContext.current().getCaller(); + if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) && volume.getState() != Volume.State.UploadOp) { + volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString()); + } + + boolean isExtractable = true; + if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont have any template dependence. + VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); + if (template != null) { // For ISO based volumes template = null and we allow extraction of all ISO based + // volumes + isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM; + } + } + volResponse.setExtractable(isExtractable); + + //set tag information + List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Volume, volume.getId()); + List tagResponses = new ArrayList(); + for (ResourceTag tag : tags) { + ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); + tagResponses.add(tagResponse); + } + volResponse.setTags(tagResponses); } - volResponse.setAttached(volume.getAttached()); - volResponse.setDestroyed(volume.getState() == Volume.State.Destroy); - boolean isExtractable = true; - if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont have any template dependence. - VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); - if (template != null) { // For ISO based volumes template = null and we allow extraction of all ISO based - // volumes - isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM; - } - } - - //set tag information - List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Volume, volume.getId()); - List tagResponses = new ArrayList(); - for (ResourceTag tag : tags) { - ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); - tagResponses.add(tagResponse); - } - volResponse.setTags(tagResponses); - - volResponse.setExtractable(isExtractable); volResponse.setObjectName("volume"); return volResponse; } diff --git a/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index 8a6c60546d0..7e596320c35 100755 --- a/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -415,6 +415,9 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.2")) return new XenServer602Resource(); + if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.9")) + return new XenServer602Resource(); + if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { String prodVersionTextShort = record.softwareVersion.get("product_version_text_short").trim(); if("5.6 SP2".equals(prodVersionTextShort)) { @@ -424,7 +427,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L } } - String msg = "Only support XCP 1.0.0, 1.1.0, 1.5 beta; XenServer 5.6, XenServer 5.6 FP1, XenServer 5.6 SP2, Xenserver 6.0, 6.0.2 but this one is " + prodBrand + " " + prodVersion; + String msg = "Only support XCP 1.0.0, 1.1.0, 1.5 beta; XenServer 5.6, XenServer 5.6 FP1, XenServer 5.6 SP2, Xenserver 6.0, 6.0.2, 6.0.9 but this one is " + prodBrand + " " + prodVersion; _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg); s_logger.debug(msg); throw new RuntimeException(msg); @@ -560,6 +563,8 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L resource = XenServer600Resource.class.getName(); } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.2")) { resource = XenServer602Resource.class.getName(); + } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.9")) { + resource = XenServer602Resource.class.getName(); } else if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { String prodVersionTextShort = details.get("product_version_text_short").trim(); if("5.6 SP2".equals(prodVersionTextShort)) { @@ -569,7 +574,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L } } if( resource == null ){ - String msg = "Only support XCP 1.0.0, 1.1.0, 1.5 beta; XenServer 5.6, 5.6 FP1, 5.6 SP2 and Xenserver 6.0 , 6.0.2 but this one is " + prodBrand + " " + prodVersion; + String msg = "Only support XCP 1.0.0, 1.1.0, 1.5 beta; XenServer 5.6, 5.6 FP1, 5.6 SP2 and Xenserver 6.0 , 6.0.2, 6.0.9 but this one is " + prodBrand + " " + prodVersion; s_logger.debug(msg); throw new RuntimeException(msg); } From 0bd667418e220925ae96b5452e9a3e560e850c43 Mon Sep 17 00:00:00 2001 From: Vijay Date: Fri, 10 Aug 2012 13:35:54 +0530 Subject: [PATCH 05/17] CS-15931 Delete Vm group not removing configs from NS. CS-15935 NetScaler sessions increase in case of errors in the NetScaler CS-15930 Save config not triggered to NS after create, update delete VM group CS-15934 Handling Resource Unavailable exception for AutoScale --- .../cloud/agent/api/to/LoadBalancerTO.java | 10 ++++- .../cloud/network/as/AutoScaleService.java | 3 +- .../cloud/network/lb/LoadBalancingRule.java | 8 +++- .../network/resource/NetscalerResource.java | 44 ++++++++++++++----- .../network/as/AutoScaleManagerImpl.java | 36 ++++++++------- .../network/lb/LoadBalancingRulesManager.java | 2 +- .../lb/LoadBalancingRulesManagerImpl.java | 24 +++++----- 7 files changed, 84 insertions(+), 43 deletions(-) diff --git a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java index e1833c48f5f..2f3fcdce237 100644 --- a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java @@ -356,8 +356,9 @@ public class LoadBalancerTO implements Serializable { private final List policies; private final AutoScaleVmProfileTO profile; private final String state; + private final String currentState; - AutoScaleVmGroupTO(int minMembers, int maxMembers, int memberPort, int interval, List policies, AutoScaleVmProfileTO profile, String state) + AutoScaleVmGroupTO(int minMembers, int maxMembers, int memberPort, int interval, List policies, AutoScaleVmProfileTO profile, String state, String currentState) { this.minMembers = minMembers; this.maxMembers = maxMembers; @@ -366,6 +367,7 @@ public class LoadBalancerTO implements Serializable { this.policies = policies; this.profile = profile; this.state = state; + this.currentState = currentState; } public int getMinMembers() { @@ -395,6 +397,10 @@ public class LoadBalancerTO implements Serializable { public String getState() { return state; } + + public String getCurrentState() { + return currentState; + } } public void setAutoScaleVmGroup(LbAutoScaleVmGroup lbAutoScaleVmGroup) @@ -426,7 +432,7 @@ public class LoadBalancerTO implements Serializable { AutoScaleVmGroup autoScaleVmGroup = lbAutoScaleVmGroup.getVmGroup(); autoScaleVmGroupTO = new AutoScaleVmGroupTO(autoScaleVmGroup.getMinMembers(), autoScaleVmGroup.getMaxMembers(), autoScaleVmGroup.getMemberPort(), - autoScaleVmGroup.getInterval(), autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState()); + autoScaleVmGroup.getInterval(), autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState(), lbAutoScaleVmGroup.getCurrentState()); } } diff --git a/api/src/com/cloud/network/as/AutoScaleService.java b/api/src/com/cloud/network/as/AutoScaleService.java index f4b9ddd1dc6..7636ca884f2 100644 --- a/api/src/com/cloud/network/as/AutoScaleService.java +++ b/api/src/com/cloud/network/as/AutoScaleService.java @@ -28,6 +28,7 @@ import com.cloud.api.commands.UpdateAutoScalePolicyCmd; import com.cloud.api.commands.UpdateAutoScaleVmGroupCmd; import com.cloud.api.commands.UpdateAutoScaleVmProfileCmd; import com.cloud.exception.ResourceInUseException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.as.AutoScalePolicy; import com.cloud.network.as.AutoScaleVmGroup; import com.cloud.network.as.AutoScaleVmProfile; @@ -54,7 +55,7 @@ public interface AutoScaleService { AutoScaleVmGroup createAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd); - boolean configureAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd); + boolean configureAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd) throws ResourceUnavailableException; boolean deleteAutoScaleVmGroup(long vmGroupId); diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 61ebfc0c03b..a2471fe1dd5 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -356,11 +356,13 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { AutoScaleVmGroup vmGroup; private final List policies; private final LbAutoScaleVmProfile profile; + private final String currentState; - public LbAutoScaleVmGroup(AutoScaleVmGroup vmGroup, List policies, LbAutoScaleVmProfile profile) { + public LbAutoScaleVmGroup(AutoScaleVmGroup vmGroup, List policies, LbAutoScaleVmProfile profile, String currentState) { this.vmGroup = vmGroup; this.policies = policies; this.profile = profile; + this.currentState = currentState; } public AutoScaleVmGroup getVmGroup() { @@ -374,6 +376,10 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { public LbAutoScaleVmProfile getProfile() { return profile; } + + public String getCurrentState() { + return currentState; + } } } diff --git a/core/src/com/cloud/network/resource/NetscalerResource.java b/core/src/com/cloud/network/resource/NetscalerResource.java index 2bbcdb20eef..a42b7074537 100644 --- a/core/src/com/cloud/network/resource/NetscalerResource.java +++ b/core/src/com/cloud/network/resource/NetscalerResource.java @@ -233,8 +233,25 @@ public class NetscalerResource implements ServerResource { } } + private void logout() throws ExecutionException { + try { + if (!_isSdx) { + if(_netscalerService != null) { + _netscalerService.logout(); + } + } else { + if(_netscalerSdxService != null) { + _netscalerSdxService.logout(); + } + } + } catch (Exception e) { + } + } + private void login() throws ExecutionException { try { + // If a previous session was open, log it out. + logout(); if (!_isSdx) { _netscalerService = new com.citrix.netscaler.nitro.service.nitro_service(_ip, "https"); _netscalerService.set_credential(_username, _password); @@ -246,9 +263,9 @@ public class NetscalerResource implements ServerResource { } else { _netscalerSdxService = new com.citrix.sdx.nitro.service.nitro_service(_ip, "https"); _netscalerSdxService.set_credential(_username, _password); - com.citrix.sdx.nitro.resource.base.login login = _netscalerSdxService.login(); + com.citrix.sdx.nitro.resource.base.login login = _netscalerSdxService.login(); if (login == null) { - throw new ExecutionException ("Failed to log in to Netscaler device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); + throw new ExecutionException ("Failed to log in to Netscaler SDX device at " + _ip + " due to error " + apiCallResult.errorcode + " and message " + apiCallResult.message); } } } catch (nitro_exception e) { @@ -1353,7 +1370,7 @@ public class NetscalerResource implements ServerResource { } private void addLBVirtualServer(String virtualServerName, String publicIp, int publicPort, String lbAlgorithm, String protocol, StickinessPolicyTO[] stickyPolicies, AutoScaleVmGroupTO vmGroupTO) - throws ExecutionException { + throws ExecutionException { try { String lbMethod; if ("roundrobin".equalsIgnoreCase(lbAlgorithm)) { @@ -1487,8 +1504,13 @@ public class NetscalerResource implements ServerResource { disableAutoScaleConfig(loadBalancer, false); } else { ///// This should never happen - throw new ExecutionException("Unknown vmGroup State :" + vmGroupTO.getState()); + throw new ExecutionException("Unknown AutoScale Vm Group State :" + vmGroupTO.getState()); } + saveConfiguration(); + if (s_logger.isInfoEnabled()) { + s_logger.info("Successfully executed resource AutoScaleConfig"); + } + } @SuppressWarnings("static-access") @@ -1551,7 +1573,7 @@ public class NetscalerResource implements ServerResource { String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort); String serviceGroupName = generateAutoScaleServiceGroupName(vmGroupIdentifier); - if(loadBalancerTO.getAutoScaleVmGroupTO().getState().equals("enabled")) { + if(loadBalancerTO.getAutoScaleVmGroupTO().getCurrentState().equals("enabled")) { disableAutoScaleConfig(loadBalancerTO, false); } @@ -1696,7 +1718,7 @@ public class NetscalerResource implements ServerResource { ApiConstants.SERVICE_OFFERING_ID + "=" + profileTO.getServiceOfferingId()+ "&" + ApiConstants.TEMPLATE_ID + "=" + profileTO.getTemplateId()+ "&" + ((profileTO.getOtherDeployParams() == null)? "" : (profileTO.getOtherDeployParams() + "&")) + - "lbruleid=" + loadBalancerTO.getUuid(); + "lbruleid=" + loadBalancerTO.getUuid(); scaleUpAction.set_parameters(scaleUpParameters); scaleUpAction.add(_netscalerService, scaleUpAction); } catch (Exception e) { @@ -1715,7 +1737,7 @@ public class NetscalerResource implements ServerResource { scaleDownAction.set_profilename(profileName); scaleDownAction.set_quiettime(scaleDownQuietTime); String scaleDownParameters = "command=destroyVirtualMachine" + "&" + - "lbruleid=" + loadBalancerTO.getUuid(); + "lbruleid=" + loadBalancerTO.getUuid(); scaleDownAction.set_parameters(scaleDownParameters); scaleDownAction.set_vmdestroygraceperiod(destroyVmGracePeriod); scaleDownAction.add(_netscalerService, scaleDownAction); @@ -1825,7 +1847,7 @@ public class NetscalerResource implements ServerResource { // bind lb monitor lb_metric_table_mon -metric cpu -metricThreshold 1 // lbmonitor_lbmetrictable_binding monitor_metrictable_binding = new -// lbmonitor_lbmetrictable_binding(); + // lbmonitor_lbmetrictable_binding(); lbmonitor_metric_binding monitor_metric_binding = new lbmonitor_metric_binding(); ; try { @@ -1841,7 +1863,7 @@ public class NetscalerResource implements ServerResource { } // SYS.VSERVER("abcd").SNMP_TABLE(0).AVERAGE_VALUE.GT(80) int counterIndex = snmpMetrics.get(counterName); // TODO: temporary fix. later on counter name -// will be added as a param to SNMP_TABLE. + // will be added as a param to SNMP_TABLE. formatter.format("SYS.VSERVER(\"%s\").SNMP_TABLE(%d).AVERAGE_VALUE.%s(%d)",nsVirtualServerName, counterIndex, operator, threshold); } else if (counterTO.getSource().equals("netscaler")) @@ -2047,7 +2069,7 @@ public class NetscalerResource implements ServerResource { // For now it is bound globally. // bind timer trigger lb_astimer -policyName lb_policy_scaleUp -vserver lb -priority 1 -samplesize 5 // TODO: later bind to lbvserver. bind timer trigger lb_astimer -policyName lb_policy_scaleUp -vserver lb -// -priority 1 -samplesize 5 + // -priority 1 -samplesize 5 // -thresholdsize 5 nstimer_autoscalepolicy_binding timer_policy_binding = new nstimer_autoscalepolicy_binding(); int sampleSize = duration/interval; @@ -2055,7 +2077,7 @@ public class NetscalerResource implements ServerResource { timer_policy_binding.set_name(timerName); timer_policy_binding.set_policyname(policyName); // timer_policy_binding.set_global("DEFAULT"); // vserver name is present in the expression, this is default -// now + // now timer_policy_binding.set_samplesize(sampleSize); timer_policy_binding.set_threshold(sampleSize); // We are not exposing this parameter as of now. // i.e. n(m) is not exposed to CS user. So thresholdSize == sampleSize diff --git a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java index efff14e7d96..0eefca09a6d 100644 --- a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java @@ -52,6 +52,7 @@ import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.LoadBalancerVO; import com.cloud.network.Network.Capability; import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao; @@ -711,20 +712,22 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { } @Override - public boolean configureAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd) { - return configureAutoScaleVmGroup(cmd.getEntityId()); + public boolean configureAutoScaleVmGroup(CreateAutoScaleVmGroupCmd cmd) throws ResourceUnavailableException { + return configureAutoScaleVmGroup(cmd.getEntityId(), AutoScaleVmGroup.State_New); } public boolean isLoadBalancerBasedAutoScaleVmGroup(AutoScaleVmGroup vmGroup) { return vmGroup.getLoadBalancerId() != null; } - private boolean configureAutoScaleVmGroup(long vmGroupid) throws InvalidParameterValueException { + private boolean configureAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException{ AutoScaleVmGroup vmGroup = _autoScaleVmGroupDao.findById(vmGroupid); if (isLoadBalancerBasedAutoScaleVmGroup(vmGroup)) { try { - return _lbRulesMgr.configureLbAutoScaleVmGroup(vmGroupid); + return _lbRulesMgr.configureLbAutoScaleVmGroup(vmGroupid, currentState); + } catch (ResourceUnavailableException re) { + throw re; } catch (Exception e) { s_logger.warn("Exception during configureLbAutoScaleVmGroup in lb rules manager", e); return false; @@ -751,12 +754,14 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { boolean success = false; try { - success = configureAutoScaleVmGroup(id); - } finally { + success = configureAutoScaleVmGroup(id, bakupState); + } catch (ResourceUnavailableException e) { + autoScaleVmGroupVO.setState(bakupState); + _autoScaleVmGroupDao.persist(autoScaleVmGroupVO); + } + finally { if (!success) { s_logger.warn("Could not delete AutoScale Vm Group id : " + id); - autoScaleVmGroupVO.setState(bakupState); - _autoScaleVmGroupDao.persist(autoScaleVmGroupVO); return false; } } @@ -945,12 +950,12 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { try { vmGroup.setState(AutoScaleVmGroup.State_Enabled); vmGroup = _autoScaleVmGroupDao.persist(vmGroup); - success = configureAutoScaleVmGroup(id); - + success = configureAutoScaleVmGroup(id, AutoScaleVmGroup.State_Disabled); + } catch (ResourceUnavailableException e) { + vmGroup.setState(AutoScaleVmGroup.State_Disabled); + _autoScaleVmGroupDao.persist(vmGroup); } finally { if (!success) { - vmGroup.setState(AutoScaleVmGroup.State_Disabled); - _autoScaleVmGroupDao.persist(vmGroup); s_logger.warn("Failed to enable AutoScale Vm Group id : " + id); return null; } @@ -972,11 +977,12 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { try { vmGroup.setState(AutoScaleVmGroup.State_Disabled); vmGroup = _autoScaleVmGroupDao.persist(vmGroup); - success = configureAutoScaleVmGroup(id); + success = configureAutoScaleVmGroup(id, AutoScaleVmGroup.State_Enabled); + } catch (ResourceUnavailableException e) { + vmGroup.setState(AutoScaleVmGroup.State_Enabled); + _autoScaleVmGroupDao.persist(vmGroup); } finally { if (!success) { - vmGroup.setState(AutoScaleVmGroup.State_Enabled); - _autoScaleVmGroupDao.persist(vmGroup); s_logger.warn("Failed to disable AutoScale Vm Group id : " + id); return null; } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java index 57b2f868b74..104bf449297 100644 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java @@ -42,5 +42,5 @@ public interface LoadBalancingRulesManager extends LoadBalancingRulesService { boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException; String getLBCapability(long networkid, String capabilityName); - boolean configureLbAutoScaleVmGroup(long vmGroupid); + boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 05b745f16a7..ee7fdd4d178 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -248,7 +248,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa return null; } - private LbAutoScaleVmGroup getLbAutoScaleVmGroup(AutoScaleVmGroup vmGroup) { + private LbAutoScaleVmGroup getLbAutoScaleVmGroup(AutoScaleVmGroup vmGroup, String currentState) { List vmGroupPolicyMapList = _autoScaleVmGroupPolicyMapDao.listByVmGroupId(vmGroup.getId()); List autoScalePolicies = new ArrayList(); for (AutoScaleVmGroupPolicyMapVO vmGroupPolicyMap : vmGroupPolicyMapList) { @@ -286,11 +286,11 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa } LbAutoScaleVmProfile lbAutoScaleVmProfile = new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey, csUrl, zoneId, domainId, serviceOfferingId, templateId); - return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile); + return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile, currentState); } - private boolean applyAutoScaleConfig(LoadBalancerVO lb, AutoScaleVmGroupVO vmGroup) throws ResourceUnavailableException { - LbAutoScaleVmGroup lbAutoScaleVmGroup = getLbAutoScaleVmGroup(vmGroup); + private boolean applyAutoScaleConfig(LoadBalancerVO lb, AutoScaleVmGroupVO vmGroup, String currentState) throws ResourceUnavailableException { + LbAutoScaleVmGroup lbAutoScaleVmGroup = getLbAutoScaleVmGroup(vmGroup, currentState); /* Regular config like destinations need not be packed for applying autoscale config as of today.*/ LoadBalancingRule rule = new LoadBalancingRule(lb, null, null); rule.setAutoScaleVmGroup(lbAutoScaleVmGroup); @@ -312,7 +312,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa @Override @DB - public boolean configureLbAutoScaleVmGroup(long vmGroupid) { + public boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException { AutoScaleVmGroupVO vmGroup = _autoScaleVmGroupDao.findById(vmGroupid); boolean success = false; @@ -331,17 +331,17 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa } try { - success = applyAutoScaleConfig(loadBalancer, vmGroup); + success = applyAutoScaleConfig(loadBalancer, vmGroup, currentState); } catch (ResourceUnavailableException e) { s_logger.warn("Unable to configure AutoScaleVmGroup to the lb rule: " + loadBalancer.getId() + " because resource is unavaliable:", e); + if (isRollBackAllowedForProvider(loadBalancer)) { + loadBalancer.setState(backupState); + _lbDao.persist(loadBalancer); + s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating AutoscaleVmGroup"); + } } finally { if (!success) { s_logger.warn("Failed to configure LB Auto Scale Vm Group with Id:" + vmGroupid); - if (isRollBackAllowedForProvider(loadBalancer)) { - loadBalancer.setState(backupState); - _lbDao.persist(loadBalancer); - s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " lb state rolback while creating AutoscaleVmGroup"); - } } } @@ -854,7 +854,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancerId)) { // Get the associated VmGroup AutoScaleVmGroupVO vmGroup = _autoScaleVmGroupDao.listByAll(loadBalancerId, null).get(0); - if (!applyAutoScaleConfig(lb, vmGroup)) { + if (!applyAutoScaleConfig(lb, vmGroup, vmGroup.getState())) { s_logger.warn("Unable to apply the autoscale config"); return false; } From 3aa0e9a352a83a2bea18a9754d0c2fd6a4112b0c Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Fri, 10 Aug 2012 16:15:25 +0530 Subject: [PATCH 06/17] bug CS-15278: For removing clusters crossing threshold find out the list of cluster through db instead of iteratting cluster one by one in the java code. Reviewed-by: Koushik --- .../com/cloud/deploy/DeploymentPlanner.java | 8 +++ .../com/cloud/capacity/dao/CapacityDao.java | 3 +- .../cloud/capacity/dao/CapacityDaoImpl.java | 54 +++++++++++++++- .../src/com/cloud/deploy/FirstFitPlanner.java | 63 +++++++++---------- 4 files changed, 93 insertions(+), 35 deletions(-) diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index b511a790f10..853b41c5386 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -12,6 +12,7 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.deploy; +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -176,6 +177,13 @@ public interface DeploymentPlanner extends Adapter { _clusterIds.add(clusterId); } + public void addClusterList(Collection clusterList) { + if (_clusterIds == null) { + _clusterIds = new HashSet(); + } + _clusterIds.addAll(clusterList); + } + public void addHost(long hostId) { if (_hostIds == null) { _hostIds = new HashSet(); diff --git a/server/src/com/cloud/capacity/dao/CapacityDao.java b/server/src/com/cloud/capacity/dao/CapacityDao.java index 0906952b8e0..4ac967035d3 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDao.java +++ b/server/src/com/cloud/capacity/dao/CapacityDao.java @@ -36,5 +36,6 @@ public interface CapacityDao extends GenericDao { Long podId, Long clusterId, String resourceState); List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); void updateCapacityState(Long dcId, Long podId, Long clusterId, - Long hostId, String capacityState); + Long hostId, String capacityState); + List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long computeRequested, Float overProvFactor); } diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java index 86da5ef4732..94ef67c6631 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -30,6 +30,7 @@ import com.cloud.storage.Storage; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.dao.StoragePoolDaoImpl; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -104,7 +105,12 @@ public class CapacityDaoImpl extends GenericDaoBase implements "WHERE total_capacity > 0 AND cluster_id is not null AND capacity_state='Enabled'"; private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART2 = " GROUP BY cluster_id, capacity_type order by percent desc limit "; private static final String UPDATE_CAPACITY_STATE = "UPDATE `cloud`.`op_host_capacity` SET capacity_state = ? WHERE "; - + private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT cluster_id " + + "FROM (SELECT cluster_id, ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(total_capacity) ) ratio "+ + "FROM `cloud`.`op_host_capacity` capacity "+ + "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 "+ + "GROUP BY cluster_id) tmp " + + "WHERE tmp.ratio > ? "; public CapacityDaoImpl() { @@ -128,6 +134,52 @@ public class CapacityDaoImpl extends GenericDaoBase implements _allFieldsSearch.done(); } + + @Override + public List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long compute_requested, Float overProvFactor){ + + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + List result = new ArrayList(); + StringBuilder sql = new StringBuilder(LIST_CLUSTERS_CROSSING_THRESHOLD); + + + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + pstmt.setLong(1, compute_requested); + pstmt.setLong(2, zoneId); + pstmt.setShort(3, capacityType); + pstmt.setFloat(4, disableThreshold*overProvFactor); + + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + result.add(rs.getLong(1)); + } + return result; + } catch (SQLException e) { + throw new CloudRuntimeException("DB Exception on: " + sql, e); + } catch (Throwable e) { + throw new CloudRuntimeException("Caught: " + sql, e); + } + } + + /*public static String preparePlaceHolders(int length) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length;) { + builder.append("?"); + if (++i < length) { + builder.append(","); + } + } + return builder.toString(); + } + + public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException { + for (int i = 0; i < values.length; i++) { + preparedStatement.setObject(i + 1, values[i]); + } + }*/ + @Override public List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, String resource_state){ diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 77c1007421d..8133f4be763 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -66,6 +66,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.user.AccountManager; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.component.Adapters; import com.cloud.utils.component.Inject; import com.cloud.vm.DiskProfile; @@ -447,7 +448,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return capacityList; } - private void removeClustersCrossingThreshold(List clusterList, ExcludeList avoid, VirtualMachineProfile vmProfile){ + private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan){ Map capacityThresholdMap = getCapacityThresholdMap(); List capacityList = getCapacitiesForCheckingThreshold(); @@ -457,37 +458,33 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; - // Iterate over the cluster List and check for each cluster whether it breaks disable threshold for any of the capacity types - for (Long clusterId : clusterList){ - for(short capacity : capacityList){ - - List summedCapacityList = _capacityDao.findCapacityBy(new Integer(capacity), null, null, clusterId); - if (summedCapacityList != null && summedCapacityList.size() != 0 && summedCapacityList.get(0).getTotalCapacity() != 0){ - - double used = (double)(summedCapacityList.get(0).getUsedCapacity() + summedCapacityList.get(0).getReservedCapacity()); - double total = summedCapacityList.get(0).getTotalCapacity(); - - if (capacity == Capacity.CAPACITY_TYPE_CPU){ - total = total * ApiDBUtils.getCpuOverprovisioningFactor(); - used = used + cpu_requested; - }else{ - used = used + ram_requested; - } - - double usedPercentage = used/total; - if ( usedPercentage > capacityThresholdMap.get(capacity)){ - avoid.addCluster(clusterId); - clustersCrossingThreshold.add(clusterId); - s_logger.debug("Cannot allocate cluster " + clusterId + " for vm creation since its allocated percentage: " +usedPercentage + - " will cross the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping this cluster"); - break; - } - } - } - } - - clusterList.removeAll(clustersCrossingThreshold); - + // For each capacity get the cluster list crossing the threshold and remove it from the clusterList that will be used for vm allocation. + for(short capacity : capacityList){ + + if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0){ + return; + } + + if (capacity == Capacity.CAPACITY_TYPE_CPU){ + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(Capacity.CAPACITY_TYPE_CPU, plan.getDataCenterId(), + capacityThresholdMap.get(capacity), cpu_requested, ApiDBUtils.getCpuOverprovisioningFactor()); + }else{ + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), + capacityThresholdMap.get(capacity), ram_requested, 1.0f);//Mem overprov not supported yet + } + + + if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0){ + // addToAvoid Set + avoid.addClusterList(clustersCrossingThreshold); + // Remove clusters crossing disabled threshold + clusterListForVmAllocation.removeAll(clustersCrossingThreshold); + + s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + + " crosses the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping these clusters"); + } + + } } private DeployDestination checkClustersforDestination(List clusterList, VirtualMachineProfile vmProfile, @@ -497,7 +494,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { s_logger.trace("ClusterId List to consider: " + clusterList); } - removeClustersCrossingThreshold(clusterList, avoid, vmProfile); + removeClustersCrossingThreshold(clusterList, avoid, vmProfile, plan); for(Long clusterId : clusterList){ Cluster clusterVO = _clusterDao.findById(clusterId); From cae5db1722bb97e718eca150cae7586d3e910c4e Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Fri, 10 Aug 2012 17:54:57 +0530 Subject: [PATCH 07/17] CS-15603 : CloudStack failing to stop vm's when destroyVM is called When a VM is force deleted and the host is not available then CS simply marks the state in db as "Destroyed/Expunging". The VM is still running on the host and once it becomes available again there is a discrepancy in state of the VM. In this scenario the VM is removed from the host when the next full cluster sync happens. Reviewed-by: Abhi --- .../com/cloud/vm/VirtualMachineManagerImpl.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 1931a36d0be..26f78b3fd50 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1746,7 +1746,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene set_vms.addAll(_vmDao.listLHByClusterId(clusterId)); for (VMInstanceVO vm : set_vms) { - if (vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging) continue; AgentVmInfo info = infos.remove(vm.getId()); VMInstanceVO castedVm = null; if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting)) @@ -1790,13 +1789,16 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene e.printStackTrace(); } } - else if (info != null && (vm.getState() == State.Stopped || vm.getState() == State.Stopping)) { + else if (info != null && (vm.getState() == State.Stopped || vm.getState() == State.Stopping + || vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging)) { Host host = _hostDao.findByGuid(info.getHostUuid()); - if (host != null){ - s_logger.warn("Stopping a VM which is stopped/stopping " + info.name); - vm.setState(State.Stopped); // set it as stop and clear it from host - vm.setHostId(null); - _vmDao.persist(vm); + if (host != null) { + s_logger.warn("Stopping a VM which is stopped/stopping/destroyed/expunging " + info.name); + if (vm.getState() == State.Stopped || vm.getState() == State.Stopping) { + vm.setState(State.Stopped); // set it as stop and clear it from host + vm.setHostId(null); + _vmDao.persist(vm); + } try { Answer answer = _agentMgr.send(host.getId(), cleanup(info.name)); if (!answer.getResult()) { @@ -1832,7 +1834,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } for (final AgentVmInfo left : infos.values()) { - if (VirtualMachineName.isValidVmName(left.name)) continue; // if the vm follows cloudstack naming ignore it for stopping try { Host host = _hostDao.findByGuid(left.getHostUuid()); if (host != null){ From eb1c94febaead1affa8ba00cc174ef13fa0a6c71 Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Fri, 10 Aug 2012 19:17:44 +0530 Subject: [PATCH 08/17] bug CS-15868: enable tampa pre-release --- .../cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index 7e596320c35..395468d70b9 100755 --- a/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -415,7 +415,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.2")) return new XenServer602Resource(); - if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.9")) + if (prodBrand.equals("XenServer") && prodVersion.startsWith("6.0.9")) return new XenServer602Resource(); if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { @@ -563,7 +563,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L resource = XenServer600Resource.class.getName(); } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.2")) { resource = XenServer602Resource.class.getName(); - } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.0.9")) { + } else if (prodBrand.equals("XenServer") && prodVersion.startsWith("6.0.9")) { resource = XenServer602Resource.class.getName(); } else if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) { String prodVersionTextShort = details.get("product_version_text_short").trim(); From 2e640b32314c66fe74d7c974b63a79dc74d0d1c4 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 10 Aug 2012 09:16:01 -0700 Subject: [PATCH 09/17] multiEdit: pass context to select handler --- ui/scripts/ui/widgets/multiEdit.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index c64b9fa0e2e..2ac0fd8e73c 100644 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -756,6 +756,7 @@ }); $select.appendTo($td); field.select({ + context: context, $select: $select, $form: $multiForm, response: { From 7450abf36fe93a5b4eb8d968673d2cf74985c2c9 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 10 Aug 2012 10:20:44 -0700 Subject: [PATCH 10/17] CS-15939: cloudstack 3.0 UI - VPC - create VPN connection - add error handling. --- ui/scripts/vpc.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 9959f2a2543..103948d449f 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -1000,7 +1000,7 @@ s2scustomergatewayid: args.data.vpncustomergatewayid }, success: function(json) { - var jid = json.createvpnconnectionresponse.jobid; + var jid = json.createvpnconnectionresponse.jobid; args.response.success( {_custom: { @@ -1011,7 +1011,10 @@ } } ); - } + }, + error: function(xmlHttpResponse) { + args.response.error(parseXMLHttpResponse(xmlHttpResponse)); + } }); }, notification: { From 0a0acfbf9e11a546ad7ab3e1d6978ae3cb864144 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 10 Aug 2012 10:40:33 -0700 Subject: [PATCH 11/17] multiEdit: Allow disabling fields per-row If _hideFields array is passed with row item data, then field IDs specified will be disabled, if they are custom button actions. --- ui/css/cloudstack3.css | 9 +++++++++ ui/scripts/ui/widgets/multiEdit.js | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index b8fc215d3f7..2f5afa747d7 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -6799,6 +6799,15 @@ div.panel.ui-dialog div.list-view div.fixed-header { text-shadow: 0px 1px #FFFFFF; } +.multi-edit .disabled .button.custom-action { + /*+opacity:50%;*/ + filter: alpha(opacity=50); + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50); + -moz-opacity: 0.5; + opacity: 0.5; + cursor: not-allowed; +} + .multi-edit .button.custom-action:hover { background: #808080 url(../images/bg-gradients.png); color: #FFFFFF; diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 2ac0fd8e73c..291820fed9f 100644 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -176,6 +176,8 @@ $button.html(data && data[fieldName] && data[fieldName]['_buttonLabel'] ? _l(data[fieldName]['_buttonLabel']) : _l(field.custom.buttonLabel)); $button.click(function() { + if ($td.hasClass('disabled')) return false; + var $button = $(this); var context = $.extend(true, {}, options.context ? @@ -196,6 +198,8 @@ } } }); + + return true; }); $button.appendTo($td); } @@ -210,6 +214,11 @@ var targetWidth = $multi.find('th.' + fieldName).width() + 5; $td.width(targetWidth); + if (data._hideFields && + $.inArray(fieldName, data._hideFields) > -1) { + $td.addClass('disabled'); + } + return true; }); From 064de72659e91c64a9dd8eebede7b1c381f8863a Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 10 Aug 2012 10:40:50 -0700 Subject: [PATCH 12/17] Add sample _hideFields to loadBalancer --- ui/scripts/network.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 0670c4e2422..88298990753 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -2536,6 +2536,9 @@ var stickyData = {}; var lbInstances = []; + // Passing _hideFields array will disable specified fields for this row + //item._hideFields = ['autoScale']; + // Get sticky data $.ajax({ url: createURL('listLBStickinessPolicies'), @@ -2610,8 +2613,7 @@ }); args.response.success({ - data: loadBalancerData, - //hideFields: ['autoScale'] + data: loadBalancerData }); } }); From 7fe710e75b7d5dda7bd51dfcae5c5115e26afef1 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 10 Aug 2012 10:52:28 -0700 Subject: [PATCH 13/17] CS-15945: cloudstack 3.0 UI - Infrastructure page - zone detail page - create guest network - make start IP, end IP field required. --- ui/scripts/system.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 8cb1e9e9ced..2ee9a21e3d3 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -1333,8 +1333,14 @@ guestGateway: { label: 'label.guest.gateway' }, guestNetmask: { label: 'label.guest.netmask' }, - guestStartIp: { label: 'label.guest.start.ip' }, - guestEndIp: { label: 'label.guest.end.ip' }, + guestStartIp: { + label: 'label.guest.start.ip', + validation: { required: true } + }, + guestEndIp: { + label: 'label.guest.end.ip', + validation: { required: true } + }, networkdomain: { label: 'label.network.domain' } } }, From f8182e855513272b48309e4bf3e8f9ac679c3851 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 10 Aug 2012 10:57:12 -0700 Subject: [PATCH 14/17] S2S VPN: Don't consider VPN is down if IPsec SA still existed Because ISAKMP SA wouldn't be updated after expiration if IPsec SA is still in affect. --- .../debian/config/opt/cloud/bin/checks2svpn.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/patches/systemvm/debian/config/opt/cloud/bin/checks2svpn.sh b/patches/systemvm/debian/config/opt/cloud/bin/checks2svpn.sh index e6bf9e52d31..cecc38af968 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/checks2svpn.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/checks2svpn.sh @@ -2,8 +2,8 @@ if [ -z $1 ] then - echo "Fail to find VPN peer address!" - exit 1 + echo "Fail to find VPN peer address!" + exit 1 fi ipsec auto --status | grep vpn-$1 > /tmp/vpn-$1.status @@ -12,19 +12,18 @@ cat /tmp/vpn-$1.status | grep "ISAKMP SA established" > /dev/null isakmpok=$? if [ $isakmpok -ne 0 ] then - echo -n "ISAKMP SA not found" - echo "Site-to-site VPN have not connected" - exit 12 + echo -n "ISAKMP SA NOT found but checking IPsec;" +else + echo -n "ISAKMP SA found;" fi -echo -n "ISAKMP SA found;" cat /tmp/vpn-$1.status | grep "IPsec SA established" > /dev/null ipsecok=$? if [ $ipsecok -ne 0 ] then - echo -n "IPsec SA not found;" - echo "Site-to-site VPN have not connected" - exit 11 + echo -n "IPsec SA not found;" + echo "Site-to-site VPN have not connected" + exit 11 fi echo -n "IPsec SA found;" echo "Site-to-site VPN have connected" From 727d0d60f41cf4301d016724966ae20c83755e59 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 10 Aug 2012 11:30:06 -0700 Subject: [PATCH 15/17] S2S VPN: CS-15936: Prevent user from connecting to different customer gateway with overlapped subnets --- .../network/vpn/Site2SiteVpnManagerImpl.java | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java index a5096057f2d..fdafb410e1d 100644 --- a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java @@ -137,6 +137,19 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { return gw; } + protected void checkCustomerGatewayCidrList(String guestCidrList) { + // Remote sub nets cannot overlap themselves + String[] cidrList = guestCidrList.split(","); + for (int i = 0; i < cidrList.length - 1; i ++) { + for (int j = i + 1; j < cidrList.length; j ++) { + if (NetUtils.isNetworksOverlap(cidrList[i], cidrList[j])) { + throw new InvalidParameterValueException("The subnet of customer gateway " + cidrList[i] + " is overlapped with another subnet " + + cidrList[j] + " of customer gateway!", null); + } + } + } + } + @Override @ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, eventDescription = "creating s2s customer gateway", create=true) public Site2SiteCustomerGateway createCustomerGateway(CreateVpnCustomerGatewayCmd cmd) { @@ -196,6 +209,9 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { if (_customerGatewayDao.findByName(name) != null) { throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!", null); } + + checkCustomerGatewayCidrList(guestCidrList); + Site2SiteCustomerGatewayVO gw = new Site2SiteCustomerGatewayVO(name, owner.getAccountId(), owner.getDomainId(), gatewayIp, guestCidrList, ipsecPsk, ikePolicy, espPolicy, ikeLifetime, espLifetime, dpd); _customerGatewayDao.persist(gw); @@ -244,15 +260,35 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { } String[] cidrList = customerGateway.getGuestCidrList().split(","); + + // Remote sub nets cannot overlap VPC's sub net String vpcCidr = _vpcDao.findById(vpnGateway.getVpcId()).getCidr(); for (String cidr : cidrList) { if (NetUtils.isNetworksOverlap(vpcCidr, cidr)) { List idList = new ArrayList(); idList.add(new IdentityProxy(customerGateway, customerGatewayId, "customerGatewayId")); - throw new InvalidParameterValueException("The subnet of customer gateway " + cidr + " is overlapped with VPC cidr " + + throw new InvalidParameterValueException("The subnets of customer gateway " + cidr + " is overlapped with VPC cidr " + vpcCidr + "!", idList); } } + + // We also need to check if the new connection's remote CIDR is overlapped with existed connections + List conns = _vpnConnectionDao.listByVpnGatewayId(vpnGatewayId); + for (Site2SiteVpnConnectionVO vc : conns) { + if (vc == null) { + continue; + } + Site2SiteCustomerGatewayVO gw = _customerGatewayDao.findById(vc.getCustomerGatewayId()); + String[] oldCidrList = gw.getGuestCidrList().split(","); + for (String oldCidr : oldCidrList) { + for (String cidr : cidrList) { + if (NetUtils.isNetworksOverlap(cidr, oldCidr)) { + throw new InvalidParameterValueException("The new connection's remote subnet " + cidr + " is overlapped with existed VPN connection to customer gateway " + + gw.getName() + "'s subnet " + oldCidr, null); + } + } + } + } Site2SiteVpnConnectionVO conn = new Site2SiteVpnConnectionVO(owner.getAccountId(), owner.getDomainId(), vpnGatewayId, customerGatewayId); conn.setState(State.Pending); @@ -424,6 +460,8 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { dpd = false; } + checkCustomerGatewayCidrList(guestCidrList); + gw.setName(name); gw.setGatewayIp(gatewayIp); gw.setGuestCidrList(guestCidrList); From 0bbefcecff5aedf700aeedb6ba245614500dd0f2 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 10 Aug 2012 11:50:21 -0700 Subject: [PATCH 16/17] S2S VPN: CS-15932: Allow user to update customer gateway when connection state is ERROR --- server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java index fdafb410e1d..64796fec266 100644 --- a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java @@ -409,10 +409,10 @@ public class Site2SiteVpnManagerImpl implements Site2SiteVpnManager, Manager { List conns = _vpnConnectionDao.listByCustomerGatewayId(id); if (conns != null) { for (Site2SiteVpnConnection conn : conns) { - if (conn.getState() != State.Disconnected || conn.getState() != State.Error) { + if (conn.getState() != State.Error) { List idList = new ArrayList(); idList.add(new IdentityProxy(conn, conn.getId(), "vpnConnectionId")); - throw new InvalidParameterValueException("Unable to update customer gateway because there is an active VPN connection with specified vpn connection id", idList); + throw new InvalidParameterValueException("Unable to update customer gateway with connections in non-Error state!", idList); } } } From 5ff964de72fe07eec2970ac7e68f7406dc60dfbd Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 10 Aug 2012 12:58:17 -0700 Subject: [PATCH 17/17] VPC UI: New ACL flow -Remove the ACL action from the tier chart item -Adds an ACL overview list view under the VPC configure menu which displays each tier and their total # of ACLs. -Add ACL edit to tier detail view - (misc) Also add IP address tab to tier detail view --- ui/css/cloudstack3.css | 37 ++++++ ui/scripts/ui-custom/vpc.js | 144 ++++++++++++++++++---- ui/scripts/ui/widgets/multiEdit.js | 1 + ui/scripts/vpc.js | 190 +++++++++++++++++++++++++---- 4 files changed, 324 insertions(+), 48 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 2f5afa747d7..65df2fc4f9c 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -9695,6 +9695,43 @@ div.panel.ui-dialog div.list-view div.fixed-header { max-width: 184px !important; } +div.ui-dialog div.acl div.multi-edit table.multi-edit thead tr th, +div.ui-dialog div.acl div.multi-edit table.multi-edit tbody tr td { + min-width: 75px; +} + +div.ui-dialog div.acl div.multi-edit div.data div.data-body div.data-item table tbody tr td { + width: 100%; + min-width: 77px; +} + +.detail-view .acl .multi-edit { +} + +.detail-view .acl .multi-edit th, +.detail-view .acl .multi-edit td { + padding-right: 0px !important; + min-width: 25px !important; +} + +.detail-view .acl .multi-edit th { + font-size: 10px; +} + +.detail-view .acl .multi-edit input { + width: 50px; +} + +.detail-view .acl .multi-edit .add-vm { + width: 51px; + text-indent: 0px; + padding-right: 0px; +} + +.detail-view .acl .multi-edit td.multi-actions { + width: 65px; +} + /*Autoscaler*/ .ui-dialog div.autoscaler { overflow: auto; diff --git a/ui/scripts/ui-custom/vpc.js b/ui/scripts/ui-custom/vpc.js index 5e4a5580f33..5d3a5dc5e11 100644 --- a/ui/scripts/ui-custom/vpc.js +++ b/ui/scripts/ui-custom/vpc.js @@ -10,21 +10,53 @@ // limitations under the License. (function($, cloudStack) { var elems = { + aclDialog: function(args) { + var isDialog = args.isDialog; + var actionArgs = args.actionArgs; + var context = args.context; + var $acl = $('
').addClass('acl').multiEdit( + $.extend(true, {}, actionArgs.multiEdit, { + context: context + }) + ); + + // Show ACL dialog + if (isDialog) { + $acl.dialog({ + title: 'Configure ACL', + dialogClass: 'configure-acl', + width: 900, + height: 600, + buttons: { + 'Done': function() { + $(':ui-dialog').remove(); + $('.overlay').remove(); + } + } + }); + } + + return $acl; + }, vpcConfigureTooltip: function(args) { + var context = args.context; var $browser = args.$browser; var $chart = args.$chart; var ipAddresses = args.ipAddresses; + var acl = args.acl; var gateways = args.gateways; var siteToSiteVPN = args.siteToSiteVPN; var links = { 'ip-addresses': 'IP Addresses', 'gateways': 'Private Gateway', - 'site-to-site-vpn': 'Site-to-site VPN' + 'site-to-site-vpn': 'Site-to-site VPN', + 'network-acls': 'ACLs' }; var $links = $('
    ').addClass('links'); var $tooltip = $('
    ').addClass('vpc-configure-tooltip').append( $('
    ').addClass('arrow') ); + var tierDetailView = args.tierDetailView; // Make links $.map(links, function(label, id) { @@ -37,6 +69,37 @@ // Link event $link.click(function() { switch (id) { + case 'network-acls': + $browser.cloudBrowser('addPanel', { + title: 'Network ACLs', + maximizeIfSelected: true, + complete: function($panel) { + $panel.listView( + $.extend(true, {}, acl.listView, { + listView: { + actions: { + add: { + label: 'Add network ACL', + action: { + custom: function() { + elems.aclDialog({ + isDialog: true, + actionArgs: acl, + context: context + }); + } + } + } + }, + detailView: tierDetailView + } + }), + { context: acl.context } + ); + } + }); + break; + case 'ip-addresses': $browser.cloudBrowser('addPanel', { title: 'IP Addresses', @@ -194,24 +257,30 @@ return $tooltip; }, vpcConfigureArea: function(args) { + var context = args.context; var $browser = args.$browser; var $chart = args.$chart; var ipAddresses = args.ipAddresses; + var acl = args.acl; var gateways = args.gateways; var siteToSiteVPN = args.siteToSiteVPN; var $config = $('
    ').addClass('config-area'); var $configIcon = $('').addClass('icon').html(' '); - + var tierDetailView = args.tierDetailView; + $config.append($configIcon); // Tooltip event $configIcon.mouseover(function() { var $tooltip = elems.vpcConfigureTooltip({ + context: context, $browser: $browser, $chart: $chart, ipAddresses: ipAddresses, gateways: gateways, - siteToSiteVPN: siteToSiteVPN + acl: acl, + siteToSiteVPN: siteToSiteVPN, + tierDetailView: tierDetailView }); // Make sure tooltip is center aligned with icon @@ -234,6 +303,8 @@ return $router; }, tier: function(args) { + var ipAddresses = args.ipAddresses; + var acl = args.acl; var name = args.name; var cidr = args.cidr; var context = args.context; @@ -310,7 +381,7 @@ if (isPlaceholder) { $tier.addClass('placeholder'); $title.html('Create Tier'); - } else { + } else { $title.html( cloudStack.concat(name, 8) ); @@ -379,6 +450,7 @@ }, chart: function(args) { var $browser = args.$browser; + var acl = args.acl; var ipAddresses = args.ipAddresses; var gateways = args.gateways; var siteToSiteVPN = args.siteToSiteVPN; @@ -398,11 +470,14 @@ ) .append( elems.vpcConfigureArea({ + context: context, $browser: $browser, $chart: $chart, ipAddresses: $.extend(ipAddresses, {context: context}), gateways: $.extend(gateways, {context: context}), - siteToSiteVPN: $.extend(siteToSiteVPN, {context: context}) + siteToSiteVPN: $.extend(siteToSiteVPN, {context: context}), + acl: $.extend(acl, {context: context}), + tierDetailView: tierDetailView }) ); @@ -412,9 +487,11 @@ } addTierDialog({ + ipAddresses: ipAddresses, $browser: $browser, tierDetailView: tierDetailView, $tiers: $tiers, + acl: acl, context: context, actions: actions, vmListView: vmListView, @@ -427,6 +504,8 @@ if (tiers != null && tiers.length > 0) { $(tiers).map(function(index, tier) { var $tier = elems.tier({ + ipAddresses: ipAddresses, + acl: acl, $browser: $browser, detailView: tierDetailView, name: tier.name, @@ -590,22 +669,10 @@ }); break; case 'acl': - // Show ACL dialog - $('
    ').addClass('acl').multiEdit( - $.extend(true, {}, actionArgs.multiEdit, { - context: context - }) - ).dialog({ - title: 'Configure ACL for tier: ' + $tier.find('.title').attr('title'), - dialogClass: 'configure-acl', - width: 900, - height: 600, - buttons: { - 'Done': function() { - $(':ui-dialog').remove(); - $('.overlay').remove(); - } - } + elems.aclDialog({ + isDialog: true, + actionArgs: actionArgs, + context: context }).closest('.ui-dialog').overlay(); break; default: @@ -623,6 +690,8 @@ // Appends a new tier to chart var addNewTier = function(args) { + var ipAddresses = args.ipAddresses; + var acl = args.acl; var actions = args.actions; var vmListView = args.vmListView; var actionPreFilter = args.actionPreFilter; @@ -630,12 +699,14 @@ var $browser = args.$browser; var tierDetailView = args.tierDetailView; var tier = $.extend(args.tier, { + ipAddresses: ipAddresses, $browser: $browser, detailView: tierDetailView, context: context, vmListView: vmListView, actions: actions, actionPreFilter: actionPreFilter, + acl: acl, virtualMachines: [] }); var $tiers = args.$tiers; @@ -650,6 +721,7 @@ // Renders the add tier form, in a dialog var addTierDialog = function(args) { + var ipAddresses = args.ipAddresses; var actions = args.actions; var context = args.context; var vmListView = args.vmListView; @@ -657,6 +729,7 @@ var $tiers = args.$tiers; var $browser = args.$browser; var tierDetailView = args.tierDetailView; + var acl = args.acl; cloudStack.dialog.createForm({ context: context, @@ -680,12 +753,14 @@ function(args) { $loading.remove(); addNewTier({ + ipAddresses: ipAddresses, $browser: $browser, tierDetailView: tierDetailView, context: $.extend(true, {}, context, { networks: [tier] }), tier: tier, + acl: acl, $tiers: $tiers, actions: actions, actionPreFilter: actionPreFilter, @@ -716,6 +791,7 @@ var tierArgs = args.tiers; var ipAddresses = args.ipAddresses; var gateways = args.gateways; + var acl = args.acl; var siteToSiteVPN = args.siteToSiteVPN; return function(args) { @@ -737,12 +813,36 @@ context: context, response: { success: function(args) { + // Setup detail view tabs + var tierDetailView = $.extend(true, {}, tierArgs.detailView, { + tabs: { + acl: { + custom: function(args) { + var $acl = elems.aclDialog({ + isDialog: false, + actionArgs: acl, + context: args.context + }); + + return $acl; + } + }, + ipAddresses: { + custom: function(args) { + return $('
    ').listView(ipAddresses.listView(), + {context: args.context}); + } + } + } + }); + var tiers = args.tiers; var $chart = elems.chart({ $browser: $browser, ipAddresses: ipAddresses, gateways: gateways, - tierDetailView: tierArgs.detailView, + acl: acl, + tierDetailView: tierDetailView, siteToSiteVPN: siteToSiteVPN, vmListView: vmListView, context: context, diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 291820fed9f..7868428f7a7 100644 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -913,6 +913,7 @@ context: context, data: data, itemData: itemData, + $multi: $multi, response: { success: function(successArgs) { var notification = successArgs ? successArgs.notification : null; diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 103948d449f..ce9b779a58d 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -59,6 +59,42 @@ }, 'startport': { edit: true, label: 'label.start.port' }, 'endport': { edit: true, label: 'label.end.port' }, + 'networkid': { + label: 'Select Tier', + select: function(args) { + var data = { + listAll: true, + vpcid: args.context.vpc[0].id + }; + + // Only show selected tier, if viewing from detail view + if (args.context.networks && + args.context.networks[0] && + args.context.networks[0].vpcid) { + $.extend(data, { + id: args.context.networks[0].id + }); + } + + // Ajax Call to display the Tiers + $.ajax({ + url: createURL('listNetworks'), + data: data, + success: function(json) { + var networks = json.listnetworksresponse.network; + + args.response.success({ + data: $(networks).map(function(index, network) { + return { + name: network.id, + description: network.name + }; + }) + }); + } + }); + } + }, 'icmptype': { edit: true, label: 'ICMP.type', isDisabled: true }, 'icmpcode': { edit: true, label: 'ICMP.code', isDisabled: true }, 'traffictype' : { @@ -83,16 +119,31 @@ add: { label: 'Add', action: function(args) { + var $multi = args.$multi; + $.ajax({ url: createURL('createNetworkACL'), data: $.extend(args.data, { - networkid: args.context.networks[0].id + networkid: args.data.networkid }), dataType: 'json', success: function(data) { args.response.success({ _custom: { - jobId: data.createnetworkaclresponse.jobid + jobId: data.createnetworkaclresponse.jobid, + getUpdatedItem: function(json) { + var networkName = $multi.find('select[name=networkid] option[value=' + args.data.networkid + ']').html(); + var data = $.extend(json.queryasyncjobresultresponse.jobresult.networkacl, { + networkid: networkName + }); + var aclRules = $multi.data('acl-rules'); + + aclRules.push(data); + $multi.data('acl-rules', aclRules); + $(window).trigger('cloudStack.fullRefresh'); + + return data; + } }, notification: { label: 'Add ACL', @@ -121,7 +172,10 @@ var jobID = data.deletenetworkaclresponse.jobid; args.response.success({ _custom: { - jobId: jobID + jobId: jobID, + getUpdatedItem: function() { + $(window).trigger('cloudStack.fullRefresh'); + } }, notification: { label: 'Remove ACL', @@ -137,23 +191,42 @@ } }, dataProvider: function(args) { - $.ajax({ - url: createURL('listNetworkACLs'), - data: { - listAll: true, - networkid: args.context.networks[0].id - }, - dataType: 'json', - async: true, - success: function(json) { - args.response.success({ - data: json.listnetworkaclsresponse.networkacl - }); - }, - error: function(XMLHttpResponse) { - args.response.error(parseXMLHttpResponse(XMLHttpResponse)); - } - }); + var $multi = args.$multi; + var data = { + vpcid: args.context.vpc[0].id, + listAll: true + }; + + if (!$multi.data('acl-rules')) { + $multi.data('acl-rules', []); + } + + if (args.context.networks && + args.context.networks[0] && + args.context.networks[0].vpcid) { + data.networkid = args.context.networks[0].id; + + $.ajax({ + url: createURL('listNetworkACLs'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + args.response.success({ + data: $(json.listnetworkaclsresponse.networkacl).map(function(index, acl) { + return $.extend(acl, { + networkid: args.context.networks[0].name + }); + }) + }); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } else { + args.response.success({ data: $multi.data('acl-rules') }); + } } }; @@ -437,6 +510,54 @@ return cloudStack.sections.network.sections.ipAddresses; } }, + acl: { + multiEdit: aclMultiEdit, + + listView: { + listView: { + id: 'networks', + fields: { + tierName: { label: 'Tier' }, + aclTotal: { label: 'ACL Total' } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listNetworks'), + data: { + listAll: true, + vpcid: args.context.vpc[0].id + }, + success: function(json) { + args.response.success({ + data: $.map(json.listnetworksresponse.network, function(tier) { + var aclTotal = 0; + + // Get ACL total + $.ajax({ + url: createURL('listNetworkACLs'), + async: false, + data: { + listAll: true, + networkid: tier.id + }, + success: function(json) { + aclTotal = json.listnetworkaclsresponse.networkacl ? + json.listnetworkaclsresponse.networkacl.length : 0; + } + }); + + return $.extend(tier, { + tierName: tier.name, + aclTotal: aclTotal + }); + }) + }); + } + }); + } + } + } + }, gateways: { add: { preCheck: function(args) { @@ -1427,7 +1548,7 @@ isMaximized: true, tabs: { details: { - title: 'label.tier.details', + title: 'Network Details', preFilter: function(args) { var hiddenFields = []; var zone; @@ -1569,6 +1690,22 @@ } }, + acl: { + title: 'Network ACL', + custom: function(args) { + // Widget renders ACL multi-edit, overriding this fn + return $('
    '); + } + }, + + ipAddresses: { + title: 'label.menu.ipaddresses', + custom: function(args) { + // Widget renders IP addresses, overriding this fn + return $('
    '); + } + }, + addloadBalancer: { title: 'label.add.load.balancer', custom: function(args) { @@ -1925,13 +2062,14 @@ poll: pollAsyncJobResult } }, - - acl: { + + // Removing ACL buttons from the tier chart + /* acl: { label: 'Configure ACL for tier', shortLabel: 'ACL', - multiEdit: aclMultiEdit - }, - + multiEdit: aclMultiEdit + }, */ + remove: { label: 'Remove tier', action: function(args) {