From 50ffa95f63c100271e40fa11add3e440545db918 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Thu, 26 Jul 2012 10:10:18 -0700 Subject: [PATCH 1/6] ifix CS-15609 Volumes can be created as a part of VM creation when un-allocated space is insufficient on primary storage check the availability of un-allocated primary storage space during planning stage, for multiple-volume VM creation scenario modification in StorageManagerImpl.java and StorageManager.java: add a new method storagePoolHasEnoughSpace(List, StoragePool), check if storagePool has enough space for all requested volumes modification in FirstfitPlanner.findPotentialDeploymentResources: handle multiple volume case, keep track of allocated volumes for pools and call storagePoolHasEnoughSpace to check space availability modification in AbstractStoragePoolAllocator.java: extract capacity computation logic and make a new method in StorageManagerImpl RB: https://reviews.apache.org/r/6028/ Send-by: mice_xia@tcloudcomputing.com --- .../src/com/cloud/deploy/FirstFitPlanner.java | 43 ++++++++- .../src/com/cloud/storage/StorageManager.java | 4 +- .../com/cloud/storage/StorageManagerImpl.java | 96 +++++++++++++++++++ .../AbstractStoragePoolAllocator.java | 79 ++------------- 4 files changed, 147 insertions(+), 75 deletions(-) diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index eb82c75d823..e70ea4de308 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -17,10 +17,12 @@ package com.cloud.deploy; import java.util.ArrayList; +import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeSet; import javax.ejb.Local; import javax.naming.ConfigurationException; @@ -55,6 +57,7 @@ import com.cloud.org.Cluster; import com.cloud.org.Grouping; import com.cloud.resource.ResourceState; import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolVO; @@ -98,6 +101,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Inject protected StoragePoolDao _storagePoolDao; @Inject protected CapacityDao _capacityDao; @Inject protected AccountManager _accountMgr; + @Inject protected StorageManager _storageMgr; @Inject(adapter=StoragePoolAllocator.class) protected Adapters _storagePoolAllocators; @@ -638,25 +642,56 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { s_logger.debug("Trying to find a potenial host and associated storage pools from the suitable host/pool lists for this VM"); boolean hostCanAccessPool = false; + boolean haveEnoughSpace = false; Map storage = new HashMap(); + TreeSet volumesOrderBySizeDesc = new TreeSet(new Comparator() { + @Override + public int compare(Volume v1, Volume v2) { + if(v1.getSize() < v2.getSize()) + return 1; + else + return -1; + } + }); + volumesOrderBySizeDesc.addAll(suitableVolumeStoragePools.keySet()); + boolean multipleVolume = volumesOrderBySizeDesc.size() > 1; for(Host potentialHost : suitableHosts){ - for(Volume vol : suitableVolumeStoragePools.keySet()){ + Map> volumeAllocationMap = new HashMap>(); + for(Volume vol : volumesOrderBySizeDesc){ + haveEnoughSpace = false; s_logger.debug("Checking if host: "+potentialHost.getId() +" can access any suitable storage pool for volume: "+ vol.getVolumeType()); List volumePoolList = suitableVolumeStoragePools.get(vol); hostCanAccessPool = false; for(StoragePool potentialSPool : volumePoolList){ if(hostCanAccessSPool(potentialHost, potentialSPool)){ - storage.put(vol, potentialSPool); hostCanAccessPool = true; + if(multipleVolume){ + List requestVolumes = null; + if(volumeAllocationMap.containsKey(potentialSPool)) + requestVolumes = volumeAllocationMap.get(potentialSPool); + else + requestVolumes = new ArrayList(); + requestVolumes.add(vol); + + if(!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool)) + continue; + volumeAllocationMap.put(potentialSPool,requestVolumes); + } + storage.put(vol, potentialSPool); + haveEnoughSpace = true; break; } } if(!hostCanAccessPool){ break; } + if(!haveEnoughSpace) { + s_logger.warn("insufficient capacity to allocate all volumes"); + break; + } } - if(hostCanAccessPool){ - s_logger.debug("Found a potential host " + "id: "+potentialHost.getId() + " name: " +potentialHost.getName()+ " and associated storage pools for this VM"); + if(hostCanAccessPool && haveEnoughSpace){ + s_logger.debug("Found a potential host " + "id: "+potentialHost.getId() + " name: " +potentialHost.getName() + " and associated storage pools for this VM"); return new Pair>(potentialHost, storage); } } diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 67ad97c204b..59a02210d86 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -235,4 +235,6 @@ public interface StorageManager extends StorageService, Manager { String getSupportedImageFormatForCluster(Long clusterId); HypervisorType getHypervisorTypeFromFormat(ImageFormat format); -} + + boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); +} diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index d94bada2866..ed9df3069ff 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -80,6 +80,7 @@ import com.cloud.api.commands.UpdateStoragePoolCmd; import com.cloud.api.commands.UploadVolumeCmd; import com.cloud.async.AsyncJobManager; import com.cloud.capacity.Capacity; +import com.cloud.capacity.CapacityManager; import com.cloud.capacity.CapacityState; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; @@ -133,6 +134,7 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.server.ManagementServer; import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.server.StatsCollector; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; @@ -274,6 +276,8 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag @Inject protected CapacityDao _capacityDao; @Inject + protected CapacityManager _capacityMgr; + @Inject protected DiskOfferingDao _diskOfferingDao; @Inject protected AccountDao _accountDao; @@ -352,6 +356,9 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag private StateMachine2 _volStateMachine; private int _customDiskOfferingMinSize = 1; private int _customDiskOfferingMaxSize = 1024; + private double _storageUsedThreshold = 1.0d; + private double _storageAllocatedThreshold = 1.0d; + protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); public boolean share(VMInstanceVO vm, List vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException { @@ -955,6 +962,19 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag String time = configs.get("storage.cleanup.interval"); _storageCleanupInterval = NumbersUtil.parseInt(time, 86400); + String storageUsedThreshold = configDao.getValue(Config.StorageCapacityDisableThreshold.key()); + if (storageUsedThreshold != null) { + _storageUsedThreshold = Double.parseDouble(storageUsedThreshold); + } + + String storageAllocatedThreshold = configDao.getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); + if (storageAllocatedThreshold != null) { + _storageAllocatedThreshold = Double.parseDouble(storageAllocatedThreshold); + } + + String globalStorageOverprovisioningFactor = configs.get("storage.overprovisioning.factor"); + _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat(globalStorageOverprovisioningFactor, 2.0f)); + s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + ", interval: " + _storageCleanupInterval + ", template cleanup enabled: " + _templateCleanupEnabled); String workers = configs.get("expunge.workers"); @@ -3906,5 +3926,81 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag return HypervisorType.None; } } + + private boolean checkUsagedSpace(StoragePool pool){ + StatsCollector sc = StatsCollector.getInstance(); + if (sc != null) { + long totalSize = pool.getCapacityBytes(); + StorageStats stats = sc.getStoragePoolStats(pool.getId()); + if(stats == null){ + stats = sc.getStorageStats(pool.getId()); + } + if (stats != null) { + double usedPercentage = ((double)stats.getByteUsed() / (double)totalSize); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Checking pool " + pool.getId() + " for storage, totalSize: " + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", disable threshold: " + _storageUsedThreshold); + } + if (usedPercentage >= _storageUsedThreshold) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Insufficient space on pool: " + pool.getId() + " since its usage percentage: " +usedPercentage + " has crossed the pool.storage.capacity.disablethreshold: " + _storageUsedThreshold); + } + return false; + } + } + return true; + } + return false; + } + + @Override + public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { + if(volumes == null || volumes.isEmpty()) + return false; + + if(!checkUsagedSpace(pool)) + return false; + + // allocated space includes template of specified volume + StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); + long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + long totalAskingSize = 0; + for (Volume volume : volumes) { + if(volume.getTemplateId()!=null){ + VMTemplateVO tmpl = _templateDao.findById(volume.getTemplateId()); + if (tmpl.getFormat() != ImageFormat.ISO){ + allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); + } + } + if(volume.getState() != Volume.State.Ready) + totalAskingSize = totalAskingSize + volume.getSize(); + } + + long totalOverProvCapacity; + if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { + totalOverProvCapacity = _storageOverprovisioningFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. + }else { + totalOverProvCapacity = pool.getCapacityBytes(); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + _storageAllocatedThreshold); + } + + double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity); + if (usedPercentage > _storageAllocatedThreshold){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage: " +usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + _storageAllocatedThreshold + ", skipping this pool"); + } + return false; + } + + if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize); + } + return false; + } + return true; + } } diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index 0a0f66ebc42..87cb065e285 100755 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -17,6 +17,7 @@ package com.cloud.storage.allocator; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; @@ -27,7 +28,6 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityManager; -import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.dao.ClusterDao; @@ -41,13 +41,11 @@ import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.StorageStats; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; @@ -58,7 +56,6 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.swift.SwiftManager; import com.cloud.template.TemplateManager; import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; import com.cloud.vm.DiskProfile; @@ -83,8 +80,6 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement long _extraBytesPerVolume = 0; Random _rand; boolean _dontMatter; - double _storageUsedThreshold = 1.0d; - double _storageAllocatedThreshold = 1.0d; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -97,17 +92,6 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement _extraBytesPerVolume = 0; - - String storageUsedThreshold = _configDao.getValue(Config.StorageCapacityDisableThreshold.key()); - if (storageUsedThreshold != null) { - _storageUsedThreshold = Double.parseDouble(storageUsedThreshold); - } - - String storageAllocatedThreshold = _configDao.getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); - if (storageAllocatedThreshold != null) { - _storageAllocatedThreshold = Double.parseDouble(storageAllocatedThreshold); - } - _rand = new Random(System.currentTimeMillis()); _dontMatter = Boolean.parseBoolean(configs.get("storage.overwrite.provisioning")); @@ -192,60 +176,15 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement return false; } - // check the used size against the total size, skip this host if it's greater than the configured - // capacity check "storage.capacity.threshold" - if (sc != null) { - long totalSize = pool.getCapacityBytes(); - StorageStats stats = sc.getStoragePoolStats(pool.getId()); - if(stats == null){ - stats = sc.getStorageStats(pool.getId()); - } - if (stats != null) { - double usedPercentage = ((double)stats.getByteUsed() / (double)totalSize); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Attempting to look for pool " + pool.getId() + " for storage, totalSize: " + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", disable threshold: " + _storageUsedThreshold); - } - if (usedPercentage >= _storageUsedThreshold) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot allocate this pool " + pool.getId() + " for storage since its usage percentage: " +usedPercentage + " has crossed the pool.storage.capacity.disablethreshold: " + _storageUsedThreshold + ", skipping this pool"); - } - return false; - } - } - } - - long totalAllocatedSize = _capacityMgr.getAllocatedPoolCapacity(pool, null); - long askingSize = dskCh.getSize(); - - long totalOverProvCapacity; - if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { - totalOverProvCapacity = _storageOverprovisioningFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. - }else { - totalOverProvCapacity = pool.getCapacityBytes(); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Attempting to look for pool " + pool.getId() + " for storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + totalAllocatedSize + ", askingSize : " + askingSize + ", allocated disable threshold: " + _storageAllocatedThreshold); - } - - double usedPercentage = (totalAllocatedSize + askingSize) / (double)(totalOverProvCapacity); - if (usedPercentage > _storageAllocatedThreshold){ - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot allocate this pool " + pool.getId() + " for storage since its allocated percentage: " +usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + _storageAllocatedThreshold + ", skipping this pool"); - } - return false; - } - - if (totalOverProvCapacity < (totalAllocatedSize + askingSize)) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot allocate this pool " + pool.getId() + " for storage, not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + totalAllocatedSize + ", askingSize : " + askingSize); - } - - return false; - } - - return true; + // check capacity + Volume volume = _volumeDao.findById(dskCh.getVolumeId()); + List requestVolumes = new ArrayList(); + requestVolumes.add(volume); + return _storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); } + + @Override public String chooseStorageIp(VirtualMachine vm, Host host, Host storage) { From 764678f558d9a1aade2c10b8f57fb7ea93ecd5c6 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Thu, 26 Jul 2012 10:43:33 -0700 Subject: [PATCH 2/6] CS-15521 Xenserver based User VM failed to HA when vrouter runs on ESXi return false as an answer when executing PingTestCommand in VMwareResource RB:https://reviews.apache.org/r/5903/ Send-by: mice_xia@tcloudcomputing.com --- .../hypervisor/vmware/resource/VmwareResource.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 685a321bcca..208cbbea8ce 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2786,8 +2786,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource PingTestCommand: " + _gson.toJson(cmd)); } - - return new Answer(cmd); + String controlIp = cmd.getRouterIp(); + String args = " -c 1 -n -q " + cmd.getPrivateIp(); + try { + VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null, "/bin/ping" + args); + if(result.first()) + return new Answer(cmd); + } catch (Exception e) { + s_logger.error("Unable to execute ping command on DomR (" + controlIp + "), domR may not be ready yet. failure due to " + + VmwareHelper.getExceptionMessage(e), e); + } + return new Answer(cmd,false,"PingTestCommand failed"); } protected Answer execute(CheckOnHostCommand cmd) { From 406fd95d87bfcdbb282d65589ab1fb6e9fd0018a Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Fri, 29 Jun 2012 17:32:19 +0200 Subject: [PATCH 3/6] Add RBD support for primary storage This patch adds RBD (RADOS Block Device) support for primary storage in combination with KVM. To get this patch working you need: - libvirt-java 0.4.8 - libvirt with RBD storage pool support (>0.9.13) - Qemu with RBD support (>0.14) The primary storage does not support all the functions of CloudStack yet, for example snapshotting is disabled due to the fact that backupping up a RBD snapshot is not possible in the way CloudStack wants to do it. Creating templates from RBD volumes goes well, creating a VM from a template however is still a hit-and-miss. NFS primary storage is also still required, you are not able to run your System VM's from RBD, they will need to run on NFS. Other then these points you can run instances with RBD backed disks. --- .../computing/LibvirtComputingResource.java | 80 ++++-- .../resource/computing/LibvirtSecretDef.java | 106 ++++++++ .../computing/LibvirtStoragePoolDef.java | 80 +++++- .../LibvirtStoragePoolXMLParser.java | 33 ++- .../resource/computing/LibvirtVMDef.java | 66 ++++- .../cloud/agent/storage/KVMPhysicalDisk.java | 16 ++ .../cloud/agent/storage/KVMStoragePool.java | 10 + .../agent/storage/KVMStoragePoolManager.java | 21 +- .../agent/storage/LibvirtStorageAdaptor.java | 256 ++++++++++++++++-- .../agent/storage/LibvirtStoragePool.java | 50 ++++ .../cloud/agent/storage/StorageAdaptor.java | 4 +- .../cloud/agent/api/to/StorageFilerTO.java | 6 + api/src/com/cloud/storage/Storage.java | 1 + api/src/com/cloud/storage/StoragePool.java | 5 + core/src/com/cloud/storage/StoragePoolVO.java | 22 ++ .../com/cloud/storage/StorageManagerImpl.java | 12 +- .../FirstFitStoragePoolAllocator.java | 13 + .../storage/snapshot/SnapshotManagerImpl.java | 8 + setup/db/create-schema.sql | 1 + ui/index.jsp | 1 + ui/scripts/sharedFunctions.js | 25 ++ ui/scripts/system.js | 52 ++++ 22 files changed, 796 insertions(+), 72 deletions(-) create mode 100644 agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index 112ab61e50b..347ff87ac9d 100755 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -30,12 +30,15 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.text.DateFormat; import java.text.MessageFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -154,6 +157,7 @@ import com.cloud.agent.resource.computing.KVMHABase.NfsStoragePool; import com.cloud.agent.resource.computing.LibvirtVMDef.ConsoleDef; import com.cloud.agent.resource.computing.LibvirtVMDef.DevicesDef; import com.cloud.agent.resource.computing.LibvirtVMDef.DiskDef; +import com.cloud.agent.resource.computing.LibvirtVMDef.DiskDef.diskProtocol; import com.cloud.agent.resource.computing.LibvirtVMDef.FeaturesDef; import com.cloud.agent.resource.computing.LibvirtVMDef.GraphicDef; import com.cloud.agent.resource.computing.LibvirtVMDef.GuestDef; @@ -1298,6 +1302,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(cmd .getPool().getUuid()); + + if (primaryPool.getType() == StoragePoolType.RBD) { + s_logger.debug("Snapshots are not supported on RBD volumes"); + return new ManageSnapshotAnswer(cmd, false, + "Snapshots are not supported on RBD volumes"); + } + KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(cmd .getVolumePath()); if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING @@ -1644,16 +1655,43 @@ public class LibvirtComputingResource extends ServerResourceBase implements + templateInstallFolder; _storage.mkdirs(tmpltPath); - Script command = new Script(_createTmplPath, _cmdsTimeout, s_logger); - command.add("-f", disk.getPath()); - command.add("-t", tmpltPath); - command.add("-n", cmd.getUniqueName() + ".qcow2"); + if (primary.getType() != StoragePoolType.RBD) { + Script command = new Script(_createTmplPath, _cmdsTimeout, s_logger); + command.add("-f", disk.getPath()); + command.add("-t", tmpltPath); + command.add("-n", cmd.getUniqueName() + ".qcow2"); - String result = command.execute(); + String result = command.execute(); - if (result != null) { - s_logger.debug("failed to create template: " + result); - return new CreatePrivateTemplateAnswer(cmd, false, result); + if (result != null) { + s_logger.debug("failed to create template: " + result); + return new CreatePrivateTemplateAnswer(cmd, false, result); + } + } else { + s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + cmd.getUniqueName()); + Script.runSimpleBashScript("qemu-img convert" + + " -f raw -O qcow2 " + + KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(), + primary.getSourcePort(), + primary.getAuthUserName(), + primary.getAuthSecret(), + disk.getPath()) + + " " + tmpltPath + "/" + cmd.getUniqueName() + ".qcow2"); + File templateProp = new File(tmpltPath + "/template.properties"); + if (!templateProp.exists()) { + templateProp.createNewFile(); + } + + String templateContent = "filename=" + cmd.getUniqueName() + ".qcow2" + System.getProperty("line.separator"); + + DateFormat dateFormat = new SimpleDateFormat("MM_dd_yyyy"); + Date date = new Date(); + templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator"); + + FileOutputStream templFo = new FileOutputStream(templateProp); + templFo.write(templateContent.getBytes()); + templFo.flush(); + templFo.close(); } Map params = new HashMap(); @@ -1756,8 +1794,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements protected Answer execute(ModifyStoragePoolCommand cmd) { KVMStoragePool storagepool = _storagePoolMgr.createStoragePool(cmd - .getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool() - .getPath(), cmd.getPool().getType()); + .getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool().getPort(), + cmd.getPool().getPath(), cmd.getPool().getUserInfo(), cmd.getPool().getType()); if (storagepool == null) { return new Answer(cmd, false, " Failed to create storage pool"); } @@ -2624,10 +2662,19 @@ public class LibvirtComputingResource extends ServerResourceBase implements } else { int devId = (int) volume.getDeviceId(); - if (volume.getType() == Volume.Type.DATADISK) { - disk.defFileBasedDisk(physicalDisk.getPath(), devId, - DiskDef.diskBus.VIRTIO, - DiskDef.diskFmtType.QCOW2); + if (pool.getType() == StoragePoolType.RBD) { + /* + For RBD pools we use the secret mechanism in libvirt. + We store the secret under the UUID of the pool, that's why + we pass the pool's UUID as the authSecret + */ + disk.defNetworkBasedDisk(physicalDisk.getPath().replace("rbd:", ""), pool.getSourceHost(), pool.getSourcePort(), + pool.getAuthUserName(), pool.getUuid(), + devId, diskBusType, diskProtocol.RBD); + } else if (volume.getType() == Volume.Type.DATADISK) { + disk.defFileBasedDisk(physicalDisk.getPath(), devId, + DiskDef.diskBus.VIRTIO, + DiskDef.diskFmtType.QCOW2); } else { disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2); @@ -2982,8 +3029,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements try { KVMStoragePool localStoragePool = _storagePoolMgr - .createStoragePool(_localStorageUUID, "localhost", - _localStoragePath, StoragePoolType.Filesystem); + .createStoragePool(_localStorageUUID, "localhost", -1, + _localStoragePath, "", StoragePoolType.Filesystem); com.cloud.agent.api.StoragePoolInfo pi = new com.cloud.agent.api.StoragePoolInfo( localStoragePool.getUuid(), cmd.getPrivateIpAddress(), _localStoragePath, _localStoragePath, @@ -4083,5 +4130,4 @@ public class LibvirtComputingResource extends ServerResourceBase implements return new Answer(cmd, success, ""); } - } diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java new file mode 100644 index 00000000000..f7e10c38ddf --- /dev/null +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.resource.computing; + +public class LibvirtSecretDef { + + public enum usage { + VOLUME("volume"), CEPH("ceph"); + String _usage; + + usage(String usage) { + _usage = usage; + } + + @Override + public String toString() { + return _usage; + } + } + + private usage _usage; + private boolean _ephemeral; + private boolean _private; + private String _uuid; + private String _description; + private String _cephName; + private String _volumeVolume; + + public LibvirtSecretDef (usage usage, String uuid) { + _usage = usage; + _uuid = uuid; + } + + public LibvirtSecretDef (usage usage, String uuid, String description) { + _usage = usage; + _uuid = uuid; + _description = description; + } + + public boolean getEphemeral() { + return _ephemeral; + } + + public boolean getPrivate() { + return _private; + } + + public String getUuid() { + return _uuid; + } + + public String getDescription() { + return _description; + } + + public String getVolumeVolume() { + return _volumeVolume; + } + + public String getCephName() { + return _cephName; + } + + public void setVolumeVolume(String volume) { + _volumeVolume = volume; + } + + public void setCephName(String name) { + _cephName = name; + } + + @Override + public String toString() { + StringBuilder secretBuilder = new StringBuilder(); + secretBuilder.append("\n"); + secretBuilder.append("" + _uuid + "\n"); + if (_description != null) { + secretBuilder.append("" + _description + "\n"); + } + secretBuilder.append("\n"); + if (_usage == _usage.VOLUME) { + secretBuilder.append("" + _volumeVolume + "\n"); + } + if (_usage == _usage.CEPH) { + secretBuilder.append("" + _cephName + "\n"); + } + secretBuilder.append("\n"); + secretBuilder.append("\n"); + return secretBuilder.toString(); + } + +} diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java index 582cd2e2e6d..9c285284563 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java @@ -18,7 +18,7 @@ package com.cloud.agent.resource.computing; public class LibvirtStoragePoolDef { public enum poolType { - ISCSI("iscsi"), NETFS("netfs"), LOGICAL("logical"), DIR("dir"); + ISCSI("iscsi"), NETFS("netfs"), LOGICAL("logical"), DIR("dir"), RBD("rbd"); String _poolType; poolType(String poolType) { @@ -31,12 +31,41 @@ public class LibvirtStoragePoolDef { } } + public enum authType { + CHAP("chap"), CEPH("ceph"); + String _authType; + + authType(String authType) { + _authType = authType; + } + + @Override + public String toString() { + return _authType; + } + } + private poolType _poolType; private String _poolName; private String _uuid; private String _sourceHost; + private int _sourcePort; private String _sourceDir; private String _targetPath; + private String _authUsername; + private authType _authType; + private String _secretUuid; + + public LibvirtStoragePoolDef(poolType type, String poolName, String uuid, + String host, int port, String dir, String targetPath) { + _poolType = type; + _poolName = poolName; + _uuid = uuid; + _sourceHost = host; + _sourcePort = port; + _sourceDir = dir; + _targetPath = targetPath; + } public LibvirtStoragePoolDef(poolType type, String poolName, String uuid, String host, String dir, String targetPath) { @@ -48,6 +77,20 @@ public class LibvirtStoragePoolDef { _targetPath = targetPath; } + public LibvirtStoragePoolDef(poolType type, String poolName, String uuid, + String sourceHost, int sourcePort, String dir, String authUsername, + authType authType, String secretUuid) { + _poolType = type; + _poolName = poolName; + _uuid = uuid; + _sourceHost = sourceHost; + _sourcePort = sourcePort; + _sourceDir = dir; + _authUsername = authUsername; + _authType = authType; + _secretUuid = secretUuid; + } + public String getPoolName() { return _poolName; } @@ -60,6 +103,10 @@ public class LibvirtStoragePoolDef { return _sourceHost; } + public int getSourcePort() { + return _sourcePort; + } + public String getSourceDir() { return _sourceDir; } @@ -68,6 +115,18 @@ public class LibvirtStoragePoolDef { return _targetPath; } + public String getAuthUserName() { + return _authUsername; + } + + public String getSecretUUID() { + return _secretUuid; + } + + public authType getAuthType() { + return _authType; + } + @Override public String toString() { StringBuilder storagePoolBuilder = new StringBuilder(); @@ -81,9 +140,22 @@ public class LibvirtStoragePoolDef { storagePoolBuilder.append("\n"); storagePoolBuilder.append("\n"); } - storagePoolBuilder.append("\n"); - storagePoolBuilder.append("" + _targetPath + "\n"); - storagePoolBuilder.append("\n"); + if (_poolType == poolType.RBD) { + storagePoolBuilder.append("\n"); + storagePoolBuilder.append("\n"); + storagePoolBuilder.append("" + _sourceDir + "\n"); + if (_authUsername != null) { + storagePoolBuilder.append("\n"); + storagePoolBuilder.append("\n"); + storagePoolBuilder.append("\n"); + } + storagePoolBuilder.append("\n"); + } + if (_poolType != poolType.RBD) { + storagePoolBuilder.append("\n"); + storagePoolBuilder.append("" + _targetPath + "\n"); + storagePoolBuilder.append("\n"); + } storagePoolBuilder.append("\n"); return storagePoolBuilder.toString(); } diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java index 5c45d76e82d..cff4c2b74aa 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java @@ -51,15 +51,34 @@ public class LibvirtStoragePoolXMLParser { Element source = (Element) rootElement.getElementsByTagName( "source").item(0); String host = getAttrValue("host", "name", source); - String path = getAttrValue("dir", "path", source); - Element target = (Element) rootElement.getElementsByTagName( - "target").item(0); - String targetPath = getTagValue("path", target); + if (type.equalsIgnoreCase("rbd")) { + int port = Integer.parseInt(getAttrValue("host", "port", source)); + String pool = getTagValue("name", source); - return new LibvirtStoragePoolDef( - LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()), - poolName, uuid, host, path, targetPath); + Element auth = (Element) source.getElementsByTagName( + "auth").item(0); + + if (auth != null) { + String authUsername = auth.getAttribute("username"); + String authType = auth.getAttribute("type"); + return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()), + poolName, uuid, host, port, pool, authUsername, LibvirtStoragePoolDef.authType.valueOf(authType.toUpperCase()), uuid); + } else { + return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()), + poolName, uuid, host, port, pool, ""); + } + } else { + String path = getAttrValue("dir", "path", source); + + Element target = (Element) rootElement.getElementsByTagName( + "target").item(0); + String targetPath = getTagValue("path", target); + + return new LibvirtStoragePoolDef( + LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()), + poolName, uuid, host, path, targetPath); + } } catch (ParserConfigurationException e) { s_logger.debug(e.toString()); } catch (SAXException e) { diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java index 8fd7815bf69..3b07bcd16b7 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java @@ -338,7 +338,7 @@ public class LibvirtVMDef { } enum diskType { - FILE("file"), BLOCK("block"), DIRECTROY("dir"); + FILE("file"), BLOCK("block"), DIRECTROY("dir"), NETWORK("network"); String _diskType; diskType(String type) { @@ -351,6 +351,20 @@ public class LibvirtVMDef { } } + enum diskProtocol { + RBD("rbd"), SHEEPDOG("sheepdog"); + String _diskProtocol; + + diskProtocol(String protocol) { + _diskProtocol = protocol; + } + + @Override + public String toString() { + return _diskProtocol; + } + } + enum diskBus { IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML( "uml"), FDC("fdc"); @@ -382,7 +396,12 @@ public class LibvirtVMDef { private deviceType _deviceType; /* floppy, disk, cdrom */ private diskType _diskType; + private diskProtocol _diskProtocol; private String _sourcePath; + private String _sourceHost; + private int _sourcePort; + private String _authUserName; + private String _authSecretUUID; private String _diskLabel; private diskBus _bus; private diskFmtType _diskFmtType; /* qcow2, raw etc. */ @@ -461,6 +480,38 @@ public class LibvirtVMDef { _bus = bus; } + public void defNetworkBasedDisk(String diskName, String sourceHost, int sourcePort, + String authUserName, String authSecretUUID, + int devId, diskBus bus, diskProtocol protocol) { + _diskType = diskType.NETWORK; + _deviceType = deviceType.DISK; + _diskFmtType = diskFmtType.RAW; + _sourcePath = diskName; + _sourceHost = sourceHost; + _sourcePort = sourcePort; + _authUserName = authUserName; + _authSecretUUID = authSecretUUID; + _diskLabel = getDevLabel(devId, bus); + _bus = bus; + _diskProtocol = protocol; + } + + public void defNetworkBasedDisk(String diskName, String sourceHost, int sourcePort, + String authUserName, String authSecretUUID, + String diskLabel, diskBus bus, diskProtocol protocol) { + _diskType = diskType.NETWORK; + _deviceType = deviceType.DISK; + _diskFmtType = diskFmtType.RAW; + _sourcePath = diskName; + _sourceHost = sourceHost; + _sourcePort = sourcePort; + _authUserName = authUserName; + _authSecretUUID = authSecretUUID; + _diskLabel = diskLabel; + _bus = bus; + _diskProtocol = protocol; + } + public void setReadonly() { _readonly = true; } @@ -527,6 +578,18 @@ public class LibvirtVMDef { diskBuilder.append(" dev='" + _sourcePath + "'"); } diskBuilder.append("/>\n"); + } else if (_diskType == diskType.NETWORK) { + diskBuilder.append("\n"); + diskBuilder.append("\n"); + diskBuilder.append("\n"); + if (_authUserName != null) { + diskBuilder.append("\n"); + diskBuilder.append("\n"); + diskBuilder.append("\n"); + } } diskBuilder.append("', 'label.SharedMountPoint': '', 'label.clvm': '', +'label.rbd': '', 'label.volgroup': '', 'label.VMFS.datastore': '', 'label.network.device': '', diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 12d3498350c..c4cf58c86e5 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -475,6 +475,31 @@ function SharedMountPointURL(server, path) { return url; } +function rbdURL(monitor, pool, id, secret) { + var url; + + /* + Replace the + and / symbols by - and _ to have URL-safe base64 going to the API + It's hacky, but otherwise we'll confuse java.net.URI which splits the incoming URI + */ + secret = str.replace("+", "-"); + secret = str.replace("/", "_"); + + if (id != null && secret != null) { + monitor = id + ":" + secret + "@" + monitor; + } + + if(pool.substring(0,1) != "/") + pool = "/" + pool; + + if(monitor.indexOf("://")==-1) + url = "rbd://" + monitor + pool; + else + url = monitor + pool; + + return url; +} + function clvmURL(vgname) { var url; if(vgname.indexOf("://")==-1) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 712c122f68a..59d2d8703d9 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7494,6 +7494,7 @@ var items = []; items.push({id: "nfs", description: "nfs"}); items.push({id: "SharedMountPoint", description: "SharedMountPoint"}); + items.push({id: "rbd", description: "RBD"}); args.response.success({data: items}); } else if(selectedClusterObj.hypervisortype == "XenServer") { @@ -7677,6 +7678,27 @@ $form.find('.form-item[rel=vCenterDataCenter]').hide(); $form.find('.form-item[rel=vCenterDataStore]').hide(); } + else if(protocol == "rbd") { + $form.find('.form-item[rel=rbdmonitor]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdmonitor]').find(".name").find("label").text("RADOS Monitor:"); + + $form.find('.form-item[rel=rbdpool]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdpool]').find(".name").find("label").text("RADOS Pool:"); + + $form.find('.form-item[rel=rbdid]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdid]').find(".name").find("label").text("RADOS User:"); + + $form.find('.form-item[rel=rbdsecret]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdsecret]').find(".name").find("label").text("RADOS Secret:"); + + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + $form.find('.form-item[rel=volumegroup]').hide(); + $form.find('.form-item[rel=path]').hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + } else { //$dialogAddPool.find("#add_pool_server_container").show(); $form.find('.form-item[rel=server]').css('display', 'inline-block'); @@ -7744,6 +7766,28 @@ validation: { required: true }, isHidden: true }, + + // RBD + rbdmonitor: { + label: 'label.rbd.monitor', + validation: { required: true }, + isHidden: true + }, + rbdpool: { + label: 'label.rbd.pool', + validation: { required: true }, + isHidden: true + }, + rbdid: { + label: 'label.rbd.id', + validation: { required: false }, + isHidden: true + }, + rbdsecret: { + label: 'label.rbd.secret', + validation: { required: false }, + isHidden: true + }, //always appear (begin) storageTags: { @@ -7803,6 +7847,14 @@ vg = "/" + vg; url = clvmURL(vg); } + else if (args.data.protocol == "rbd") { + var rbdmonitor = args.data.rbdmonitor; + var rbdpool = args.data.rbdpool; + var rbdid = args.data.rbdid; + var rbdsecret = args.data.rbdsecret; + + url = rbdURL(rbdmonitor, rbdpool, rbdid, rbdsecret); + } else if (args.data.protocol == "vmfs") { //var path = trim($thisDialog.find("#add_pool_vmfs_dc").val()); var path = args.data.vCenterDataCenter; From 3f4b7602f45b7cd2b797ae9826aac5deb81b6ed6 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 26 Jul 2012 13:30:37 -0700 Subject: [PATCH 4/6] CS-15628: ip address id is required by createFirewallRule command --- api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java index 81817dcfdf3..b437568311f 100644 --- a/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java @@ -52,7 +52,7 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal // /////////////////////////////////////////////////// @IdentityMapper(entityTableName="user_ip_address") - @Parameter(name = ApiConstants.IP_ADDRESS_ID, type = CommandType.LONG, description = "the IP address id of the port forwarding rule") + @Parameter(name = ApiConstants.IP_ADDRESS_ID, type = CommandType.LONG, required=true, description = "the IP address id of the port forwarding rule") private Long ipAddressId; @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, description = "the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.") From bf2e3d6ae1906ddeac82672232430b8d6c967a6b Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Thu, 26 Jul 2012 23:03:34 +0200 Subject: [PATCH 5/6] setup: Initiate SQL upgrade file from 3.0.3 to 4.0.0 This only adds the user_info column to the storage_pool table, but we'll probably have more SQL changes coming up. They can all go into this file. --- setup/db/db/schema-303to40.sql | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 setup/db/db/schema-303to40.sql diff --git a/setup/db/db/schema-303to40.sql b/setup/db/db/schema-303to40.sql new file mode 100644 index 00000000000..87dd1d3c789 --- /dev/null +++ b/setup/db/db/schema-303to40.sql @@ -0,0 +1,22 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +--; +-- Schema upgrade from 3.0.3 to 4.0.0; +--; + +ALTER TABLE `storage_pool` ADD `user_info` VARCHAR( 255 ) NULL COMMENT 'Authorization information for the storage pool. Used by network filesystems' AFTER `host_address`; From 7d406bf3d19cd88721a85e564c685a7d25c66322 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 26 Jul 2012 15:28:50 -0700 Subject: [PATCH 6/6] Added missing action events for enable/disable static nat --- server/src/com/cloud/network/rules/RulesManagerImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 666e2691844..b45443e467c 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -331,9 +331,11 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override + @ActionEvent(eventType = EventTypes.EVENT_ENABLE_STATIC_NAT, eventDescription = "enabling static nat") public boolean enableStaticNat(long ipId, long vmId, boolean isSystemVm) throws NetworkRuleConflictException, ResourceUnavailableException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); + UserContext.current().setEventDetails("Ip Id: " + ipId); IPAddressVO ipAddress = _ipAddressDao.findById(ipId); if (ipAddress == null) { @@ -1052,6 +1054,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override + @ActionEvent(eventType = EventTypes.EVENT_DISABLE_STATIC_NAT, eventDescription = "disabling static nat", async=true) public boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller();