mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CS-14277
Support for local data disk. Currently enable/disable config is at zone level, in subsequent checkins it can be made more granular.
Following changes are made:
- Create disk offering API now takes an extra parameter to denote storage type (local or shared). This is similar to storage type in service offering.
- Create/delete of data volume on local storage
- Attach/detach for local data volumes. Re-attach is allowed as long as vm host and data volume storage pool host is same.
- Migration of VM instance is not supported if it uses local root or data volumes.
- Migrate is not supported for local volumes.
- Zone level config to enable/disable local storage usage for service and disk offerings.
- Local storage gets discovered when a host is added/reconnected if zone level config is enabled. When disabled existing local storages are not removed but any new local storage is not added.
- Deploy VM command validates service and disk offerings based on local storage config.
- Upgrade uses the global config 'use.local.storage' to set the zone level config for local storage.
(cherry picked from commit 62710aed37606168012a0ed255a876c8e7954010)
This commit is contained in:
parent
e7ff6ecd77
commit
65eeeaf071
@ -294,6 +294,7 @@ public class ApiConstants {
|
|||||||
public static final String DHCP_RANGE = "dhcprange";
|
public static final String DHCP_RANGE = "dhcprange";
|
||||||
public static final String UUID = "uuid";
|
public static final String UUID = "uuid";
|
||||||
public static final String SECURITY_GROUP_EANBLED = "securitygroupenabled";
|
public static final String SECURITY_GROUP_EANBLED = "securitygroupenabled";
|
||||||
|
public static final String LOCAL_STORAGE_ENABLED = "localstorageenabled";
|
||||||
public static final String GUEST_IP_TYPE = "guestiptype";
|
public static final String GUEST_IP_TYPE = "guestiptype";
|
||||||
public static final String XEN_NETWORK_LABEL = "xennetworklabel";
|
public static final String XEN_NETWORK_LABEL = "xennetworklabel";
|
||||||
public static final String KVM_NETWORK_LABEL = "kvmnetworklabel";
|
public static final String KVM_NETWORK_LABEL = "kvmnetworklabel";
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import com.cloud.api.Parameter;
|
|||||||
import com.cloud.api.ServerApiException;
|
import com.cloud.api.ServerApiException;
|
||||||
import com.cloud.api.response.DiskOfferingResponse;
|
import com.cloud.api.response.DiskOfferingResponse;
|
||||||
import com.cloud.offering.DiskOffering;
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
@Implementation(description="Creates a disk offering.", responseObject=DiskOfferingResponse.class)
|
@Implementation(description="Creates a disk offering.", responseObject=DiskOfferingResponse.class)
|
||||||
@ -57,6 +58,9 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
|||||||
@Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the ID of the containing domain, null for public offerings")
|
@Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the ID of the containing domain, null for public offerings")
|
||||||
private Long domainId;
|
private Long domainId;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the disk offering. Values are local and shared.")
|
||||||
|
private String storageType = ServiceOffering.StorageType.shared.toString();
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -84,6 +88,11 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
|||||||
public Long getDomainId(){
|
public Long getDomainId(){
|
||||||
return domainId;
|
return domainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getStorageType() {
|
||||||
|
return storageType;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -73,6 +73,9 @@ public class CreateZoneCmd extends BaseCmd {
|
|||||||
@Parameter(name=ApiConstants.SECURITY_GROUP_EANBLED, type=CommandType.BOOLEAN, description="true if network is security group enabled, false otherwise")
|
@Parameter(name=ApiConstants.SECURITY_GROUP_EANBLED, type=CommandType.BOOLEAN, description="true if network is security group enabled, false otherwise")
|
||||||
private Boolean securitygroupenabled;
|
private Boolean securitygroupenabled;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.LOCAL_STORAGE_ENABLED, type=CommandType.BOOLEAN, description="true if local storage offering enabled, false otherwise")
|
||||||
|
private Boolean localStorageEnabled;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -124,6 +127,12 @@ public class CreateZoneCmd extends BaseCmd {
|
|||||||
return securitygroupenabled;
|
return securitygroupenabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getLocalStorageEnabled() {
|
||||||
|
if (localStorageEnabled == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return localStorageEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
|
|||||||
@ -375,13 +375,23 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
|
|||||||
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiskOffering diskOffering = null;
|
||||||
if (diskOfferingId != null) {
|
if (diskOfferingId != null) {
|
||||||
DiskOffering diskOffering = _configService.getDiskOffering(diskOfferingId);
|
diskOffering = _configService.getDiskOffering(diskOfferingId);
|
||||||
if (diskOffering == null) {
|
if (diskOffering == null) {
|
||||||
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId);
|
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!zone.isLocalStorageEnabled()) {
|
||||||
|
if (serviceOffering.getUseLocalStorage()) {
|
||||||
|
throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it");
|
||||||
|
}
|
||||||
|
if (diskOffering != null && diskOffering.getUseLocalStorage()) {
|
||||||
|
throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserVm vm = null;
|
UserVm vm = null;
|
||||||
if (getHypervisor() == HypervisorType.BareMetal) {
|
if (getHypervisor() == HypervisorType.BareMetal) {
|
||||||
vm = _bareMetalVmService.createVirtualMachine(this);
|
vm = _bareMetalVmService.createVirtualMachine(this);
|
||||||
|
|||||||
@ -82,6 +82,9 @@ public class UpdateZoneCmd extends BaseCmd {
|
|||||||
@Parameter(name=ApiConstants.DNS_SEARCH_ORDER, type=CommandType.LIST, collectionType = CommandType.STRING, description="the dns search order list")
|
@Parameter(name=ApiConstants.DNS_SEARCH_ORDER, type=CommandType.LIST, collectionType = CommandType.STRING, description="the dns search order list")
|
||||||
private List<String> dnsSearchOrder;
|
private List<String> dnsSearchOrder;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.LOCAL_STORAGE_ENABLED, type=CommandType.BOOLEAN, description="true if local storage offering enabled, false otherwise")
|
||||||
|
private Boolean localStorageEnabled;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -137,6 +140,11 @@ public class UpdateZoneCmd extends BaseCmd {
|
|||||||
public List<String> getDnsSearchOrder() {
|
public List<String> getDnsSearchOrder() {
|
||||||
return dnsSearchOrder;
|
return dnsSearchOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getLocalStorageEnabled() {
|
||||||
|
return localStorageEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -51,6 +51,9 @@ public class DiskOfferingResponse extends BaseResponse {
|
|||||||
@SerializedName(ApiConstants.TAGS) @Param(description="the tags for the disk offering")
|
@SerializedName(ApiConstants.TAGS) @Param(description="the tags for the disk offering")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
|
@SerializedName("storagetype") @Param(description="the storage type for this disk offering")
|
||||||
|
private String storageType;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id.getValue();
|
return id.getValue();
|
||||||
}
|
}
|
||||||
@ -123,4 +126,11 @@ public class DiskOfferingResponse extends BaseResponse {
|
|||||||
this.customized = customized;
|
this.customized = customized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getStorageType() {
|
||||||
|
return storageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStorageType(String storageType) {
|
||||||
|
this.storageType = storageType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,6 +86,9 @@ public class ZoneResponse extends BaseResponse {
|
|||||||
@SerializedName("capacity") @Param(description="the capacity of the Zone", responseObject = CapacityResponse.class)
|
@SerializedName("capacity") @Param(description="the capacity of the Zone", responseObject = CapacityResponse.class)
|
||||||
private List<CapacityResponse> capacitites;
|
private List<CapacityResponse> capacitites;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.LOCAL_STORAGE_ENABLED) @Param(description="true if local storage offering enabled, false otherwise")
|
||||||
|
private boolean localStorageEnabled;
|
||||||
|
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id.setValue(id);
|
this.id.setValue(id);
|
||||||
}
|
}
|
||||||
@ -165,4 +168,8 @@ public class ZoneResponse extends BaseResponse {
|
|||||||
public void setDomainName(String domainName) {
|
public void setDomainName(String domainName) {
|
||||||
this.domainName = domainName;
|
this.domainName = domainName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLocalStorageEnabled(boolean localStorageEnabled) {
|
||||||
|
this.localStorageEnabled = localStorageEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,4 +75,5 @@ public interface DataCenter extends Grouping {
|
|||||||
|
|
||||||
String getZoneToken();
|
String getZoneToken();
|
||||||
|
|
||||||
|
boolean isLocalStorageEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1124,6 +1124,7 @@ label.linklocal.ip=Link Local IP Adddress
|
|||||||
label.load.balancer=Load Balancer
|
label.load.balancer=Load Balancer
|
||||||
label.loading=Loading
|
label.loading=Loading
|
||||||
label.local=Local
|
label.local=Local
|
||||||
|
label.local.storage.enabled=Local Storage Enabled
|
||||||
label.login=Login
|
label.login=Login
|
||||||
label.logout=Logout
|
label.logout=Logout
|
||||||
label.lun=LUN
|
label.lun=LUN
|
||||||
|
|||||||
@ -138,7 +138,7 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<!--plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
<version>1.2.1</version>
|
<version>1.2.1</version>
|
||||||
@ -163,7 +163,7 @@
|
|||||||
<argument>authorized_keys</argument>
|
<argument>authorized_keys</argument>
|
||||||
</arguments>
|
</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin-->
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -463,6 +463,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
}
|
}
|
||||||
diskOfferingResponse.setTags(offering.getTags());
|
diskOfferingResponse.setTags(offering.getTags());
|
||||||
diskOfferingResponse.setCustomized(offering.isCustomized());
|
diskOfferingResponse.setCustomized(offering.isCustomized());
|
||||||
|
diskOfferingResponse.setStorageType(offering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString());
|
||||||
diskOfferingResponse.setObjectName("diskoffering");
|
diskOfferingResponse.setObjectName("diskoffering");
|
||||||
return diskOfferingResponse;
|
return diskOfferingResponse;
|
||||||
}
|
}
|
||||||
@ -954,6 +955,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
zoneResponse.setId(dataCenter.getId());
|
zoneResponse.setId(dataCenter.getId());
|
||||||
zoneResponse.setName(dataCenter.getName());
|
zoneResponse.setName(dataCenter.getName());
|
||||||
zoneResponse.setSecurityGroupsEnabled(ApiDBUtils.isSecurityGroupEnabledInZone(dataCenter.getId()));
|
zoneResponse.setSecurityGroupsEnabled(ApiDBUtils.isSecurityGroupEnabledInZone(dataCenter.getId()));
|
||||||
|
zoneResponse.setLocalStorageEnabled(dataCenter.isLocalStorageEnabled());
|
||||||
|
|
||||||
if ((dataCenter.getDescription() != null) && !dataCenter.getDescription().equalsIgnoreCase("null")) {
|
if ((dataCenter.getDescription() != null) && !dataCenter.getDescription().equalsIgnoreCase("null")) {
|
||||||
zoneResponse.setDescription(dataCenter.getDescription());
|
zoneResponse.setDescription(dataCenter.getDescription());
|
||||||
@ -1121,24 +1123,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
|
|
||||||
populateOwner(volResponse, volume);
|
populateOwner(volResponse, volume);
|
||||||
|
|
||||||
String storageType;
|
|
||||||
try {
|
|
||||||
if (volume.getPoolId() == null) {
|
|
||||||
if (volume.getState() == Volume.State.Allocated || volume.getState() == Volume.State.UploadOp) {
|
|
||||||
/* set it as shared, so the UI can attach it to VM */
|
|
||||||
storageType = "shared";
|
|
||||||
} else {
|
|
||||||
storageType = "unknown";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
storageType = ApiDBUtils.volumeIsOnSharedStorage(volume.getId()) ? ServiceOffering.StorageType.shared.toString() : ServiceOffering.StorageType.local.toString();
|
|
||||||
}
|
|
||||||
} catch (InvalidParameterValueException e) {
|
|
||||||
s_logger.error(e.getMessage(), e);
|
|
||||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Volume " + volume.getName() + " does not have a valid ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
volResponse.setStorageType(storageType);
|
|
||||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||||
volResponse.setServiceOfferingId(volume.getDiskOfferingId());
|
volResponse.setServiceOfferingId(volume.getDiskOfferingId());
|
||||||
} else {
|
} else {
|
||||||
@ -1153,6 +1137,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
volResponse.setDiskOfferingName(diskOffering.getName());
|
volResponse.setDiskOfferingName(diskOffering.getName());
|
||||||
volResponse.setDiskOfferingDisplayText(diskOffering.getDisplayText());
|
volResponse.setDiskOfferingDisplayText(diskOffering.getDisplayText());
|
||||||
}
|
}
|
||||||
|
volResponse.setStorageType(diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString());
|
||||||
|
|
||||||
Long poolId = volume.getPoolId();
|
Long poolId = volume.getPoolId();
|
||||||
String poolName = (poolId == null) ? "none" : ApiDBUtils.findStoragePoolById(poolId).getName();
|
String poolName = (poolId == null) ? "none" : ApiDBUtils.findStoragePoolById(poolId).getName();
|
||||||
|
|||||||
@ -191,7 +191,6 @@ public enum Config {
|
|||||||
ManagementHostIPAdr("Advanced", ManagementServer.class, String.class, "host", "localhost", "The ip address of management server", null),
|
ManagementHostIPAdr("Advanced", ManagementServer.class, String.class, "host", "localhost", "The ip address of management server", null),
|
||||||
ManagementNetwork("Advanced", ManagementServer.class, String.class, "management.network.cidr", null, "The cidr of management server network", null),
|
ManagementNetwork("Advanced", ManagementServer.class, String.class, "management.network.cidr", null, "The cidr of management server network", null),
|
||||||
EventPurgeDelay("Advanced", ManagementServer.class, Integer.class, "event.purge.delay", "15", "Events older than specified number days will be purged. Set this value to 0 to never delete events", null),
|
EventPurgeDelay("Advanced", ManagementServer.class, Integer.class, "event.purge.delay", "15", "Events older than specified number days will be purged. Set this value to 0 to never delete events", null),
|
||||||
UseLocalStorage("Advanced", ManagementServer.class, Boolean.class, "use.local.storage", "false", "Should we use the local storage if it's available?", null),
|
|
||||||
SecStorageVmMTUSize("Advanced", AgentManager.class, Integer.class, "secstorage.vm.mtu.size", String.valueOf(SecondaryStorageVmManager.DEFAULT_SS_VM_MTUSIZE), "MTU size (in Byte) of storage network in secondary storage vms", null),
|
SecStorageVmMTUSize("Advanced", AgentManager.class, Integer.class, "secstorage.vm.mtu.size", String.valueOf(SecondaryStorageVmManager.DEFAULT_SS_VM_MTUSIZE), "MTU size (in Byte) of storage network in secondary storage vms", null),
|
||||||
MaxTemplateAndIsoSize("Advanced", ManagementServer.class, Long.class, "max.template.iso.size", "50", "The maximum size for a downloaded template or ISO (in GB).", null),
|
MaxTemplateAndIsoSize("Advanced", ManagementServer.class, Long.class, "max.template.iso.size", "50", "The maximum size for a downloaded template or ISO (in GB).", null),
|
||||||
SecStorageAllowedInternalDownloadSites("Advanced", ManagementServer.class, String.class, "secstorage.allowed.internal.sites", null, "Comma separated list of cidrs internal to the datacenter that can host template download servers, please note 0.0.0.0 is not a valid site", null),
|
SecStorageAllowedInternalDownloadSites("Advanced", ManagementServer.class, String.class, "secstorage.allowed.internal.sites", null, "Comma separated list of cidrs internal to the datacenter that can host template download servers, please note 0.0.0.0 is not a valid site", null),
|
||||||
|
|||||||
@ -93,7 +93,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
|
|||||||
* @param isCustomized
|
* @param isCustomized
|
||||||
* @return newly created disk offering
|
* @return newly created disk offering
|
||||||
*/
|
*/
|
||||||
DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized);
|
DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new pod
|
* Creates a new pod
|
||||||
@ -133,7 +133,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
|
|||||||
* @throws
|
* @throws
|
||||||
*/
|
*/
|
||||||
DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId, NetworkType zoneType, String allocationState,
|
DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId, NetworkType zoneType, String allocationState,
|
||||||
String networkDomain, boolean isSecurityGroupEnabled);
|
String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated
|
* Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated
|
||||||
|
|||||||
@ -1364,6 +1364,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
String dhcpProvider = cmd.getDhcpProvider();
|
String dhcpProvider = cmd.getDhcpProvider();
|
||||||
Map<?, ?> detailsMap = cmd.getDetails();
|
Map<?, ?> detailsMap = cmd.getDetails();
|
||||||
String networkDomain = cmd.getDomain();
|
String networkDomain = cmd.getDomain();
|
||||||
|
Boolean localStorageEnabled = cmd.getLocalStorageEnabled();
|
||||||
|
|
||||||
Map<String, String> newDetails = new HashMap<String, String>();
|
Map<String, String> newDetails = new HashMap<String, String>();
|
||||||
if (detailsMap != null) {
|
if (detailsMap != null) {
|
||||||
@ -1470,6 +1471,9 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
zone.setInternalDns1(internalDns1);
|
zone.setInternalDns1(internalDns1);
|
||||||
zone.setInternalDns2(internalDns2);
|
zone.setInternalDns2(internalDns2);
|
||||||
zone.setGuestNetworkCidr(guestCidr);
|
zone.setGuestNetworkCidr(guestCidr);
|
||||||
|
if (localStorageEnabled != null) {
|
||||||
|
zone.setLocalStorageEnabled(localStorageEnabled.booleanValue());
|
||||||
|
}
|
||||||
|
|
||||||
if (networkDomain != null) {
|
if (networkDomain != null) {
|
||||||
if (networkDomain.isEmpty()) {
|
if (networkDomain.isEmpty()) {
|
||||||
@ -1543,7 +1547,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
@Override
|
@Override
|
||||||
@DB
|
@DB
|
||||||
public DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId,
|
public DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId,
|
||||||
NetworkType zoneType, String allocationStateStr, String networkDomain, boolean isSecurityGroupEnabled) {
|
NetworkType zoneType, String allocationStateStr, String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled) {
|
||||||
|
|
||||||
// checking the following params outside checkzoneparams method as we do
|
// checking the following params outside checkzoneparams method as we do
|
||||||
// not use these params for updatezone
|
// not use these params for updatezone
|
||||||
@ -1569,7 +1573,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
try {
|
try {
|
||||||
txn.start();
|
txn.start();
|
||||||
// Create the new zone in the database
|
// Create the new zone in the database
|
||||||
DataCenterVO zone = new DataCenterVO(zoneName, null, dns1, dns2, internalDns1, internalDns2, guestCidr, domain, domainId, zoneType, zoneToken, networkDomain, isSecurityGroupEnabled);
|
DataCenterVO zone = new DataCenterVO(zoneName, null, dns1, dns2, internalDns1, internalDns2, guestCidr, domain, domainId, zoneType, zoneToken, networkDomain, isSecurityGroupEnabled, isLocalStorageEnabled);
|
||||||
if (allocationStateStr != null && !allocationStateStr.isEmpty()) {
|
if (allocationStateStr != null && !allocationStateStr.isEmpty()) {
|
||||||
Grouping.AllocationState allocationState = Grouping.AllocationState.valueOf(allocationStateStr);
|
Grouping.AllocationState allocationState = Grouping.AllocationState.valueOf(allocationStateStr);
|
||||||
zone.setAllocationState(allocationState);
|
zone.setAllocationState(allocationState);
|
||||||
@ -1649,6 +1653,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
String allocationState = cmd.getAllocationState();
|
String allocationState = cmd.getAllocationState();
|
||||||
String networkDomain = cmd.getDomain();
|
String networkDomain = cmd.getDomain();
|
||||||
boolean isSecurityGroupEnabled = cmd.getSecuritygroupenabled();
|
boolean isSecurityGroupEnabled = cmd.getSecuritygroupenabled();
|
||||||
|
boolean isLocalStorageEnabled = cmd.getLocalStorageEnabled();
|
||||||
|
|
||||||
if (allocationState == null) {
|
if (allocationState == null) {
|
||||||
allocationState = Grouping.AllocationState.Disabled.toString();
|
allocationState = Grouping.AllocationState.Disabled.toString();
|
||||||
@ -1682,7 +1687,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
}
|
}
|
||||||
|
|
||||||
return createZone(userId, zoneName, dns1, dns2, internalDns1, internalDns2, guestCidr, domainVO != null ? domainVO.getName() : null, domainId, zoneType, allocationState, networkDomain,
|
return createZone(userId, zoneName, dns1, dns2, internalDns1, internalDns2, guestCidr, domainVO != null ? domainVO.getName() : null, domainId, zoneType, allocationState, networkDomain,
|
||||||
isSecurityGroupEnabled);
|
isSecurityGroupEnabled, isLocalStorageEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1857,7 +1862,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_DISK_OFFERING_CREATE, eventDescription = "creating disk offering")
|
@ActionEvent(eventType = EventTypes.EVENT_DISK_OFFERING_CREATE, eventDescription = "creating disk offering")
|
||||||
public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized) {
|
public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired) {
|
||||||
long diskSize = 0;// special case for custom disk offerings
|
long diskSize = 0;// special case for custom disk offerings
|
||||||
if (numGibibytes != null && (numGibibytes <= 0)) {
|
if (numGibibytes != null && (numGibibytes <= 0)) {
|
||||||
throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb.");
|
throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb.");
|
||||||
@ -1875,6 +1880,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
|
|
||||||
tags = cleanupTags(tags);
|
tags = cleanupTags(tags);
|
||||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized);
|
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized);
|
||||||
|
newDiskOffering.setUseLocalStorage(localStorageRequired);
|
||||||
UserContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId());
|
UserContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId());
|
||||||
DiskOfferingVO offering = _diskOfferingDao.persist(newDiskOffering);
|
DiskOfferingVO offering = _diskOfferingDao.persist(newDiskOffering);
|
||||||
if (offering != null) {
|
if (offering != null) {
|
||||||
@ -1904,7 +1910,17 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
|||||||
throw new InvalidParameterValueException("Disksize is required for non-customized disk offering");
|
throw new InvalidParameterValueException("Disksize is required for non-customized disk offering");
|
||||||
}
|
}
|
||||||
|
|
||||||
return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized);
|
boolean localStorageRequired = false;
|
||||||
|
String storageType = cmd.getStorageType();
|
||||||
|
if (storageType != null) {
|
||||||
|
if (storageType.equalsIgnoreCase(ServiceOffering.StorageType.local.toString())) {
|
||||||
|
localStorageRequired = true;
|
||||||
|
} else if (!storageType.equalsIgnoreCase(ServiceOffering.StorageType.shared.toString())) {
|
||||||
|
throw new InvalidParameterValueException("Invalid storage type " + storageType + " specified, valid types are: 'local' and 'shared'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -127,6 +127,9 @@ public class DataCenterVO implements DataCenter, Identity {
|
|||||||
@Column(name="is_security_group_enabled")
|
@Column(name="is_security_group_enabled")
|
||||||
boolean securityGroupEnabled;
|
boolean securityGroupEnabled;
|
||||||
|
|
||||||
|
@Column(name="is_local_storage_enabled")
|
||||||
|
boolean localStorageEnabled;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDnsProvider() {
|
public String getDnsProvider() {
|
||||||
return dnsProvider;
|
return dnsProvider;
|
||||||
@ -173,13 +176,13 @@ public class DataCenterVO implements DataCenter, Identity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DataCenterVO(long id, String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken, String domainSuffix) {
|
public DataCenterVO(long id, String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken, String domainSuffix) {
|
||||||
this(name, description, dns1, dns2, dns3, dns4, guestCidr, domain, domainId, zoneType, zoneToken, domainSuffix, false);
|
this(name, description, dns1, dns2, dns3, dns4, guestCidr, domain, domainId, zoneType, zoneToken, domainSuffix, false, false);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.allocationState = Grouping.AllocationState.Enabled;
|
this.allocationState = Grouping.AllocationState.Enabled;
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataCenterVO(String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken, String domainSuffix, boolean securityGroupEnabled) {
|
public DataCenterVO(String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken, String domainSuffix, boolean securityGroupEnabled, boolean localStorageEnabled) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.dns1 = dns1;
|
this.dns1 = dns1;
|
||||||
@ -192,7 +195,7 @@ public class DataCenterVO implements DataCenter, Identity {
|
|||||||
this.networkType = zoneType;
|
this.networkType = zoneType;
|
||||||
this.allocationState = Grouping.AllocationState.Enabled;
|
this.allocationState = Grouping.AllocationState.Enabled;
|
||||||
this.securityGroupEnabled = securityGroupEnabled;
|
this.securityGroupEnabled = securityGroupEnabled;
|
||||||
|
this.localStorageEnabled = localStorageEnabled;
|
||||||
|
|
||||||
if (zoneType == NetworkType.Advanced) {
|
if (zoneType == NetworkType.Advanced) {
|
||||||
loadBalancerProvider = Provider.VirtualRouter.getName();
|
loadBalancerProvider = Provider.VirtualRouter.getName();
|
||||||
@ -345,6 +348,15 @@ public class DataCenterVO implements DataCenter, Identity {
|
|||||||
this.securityGroupEnabled = enabled;
|
this.securityGroupEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLocalStorageEnabled() {
|
||||||
|
return localStorageEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocalStorageEnabled(boolean enabled) {
|
||||||
|
this.localStorageEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getDetails() {
|
public Map<String, String> getDetails() {
|
||||||
return details;
|
return details;
|
||||||
|
|||||||
@ -31,6 +31,8 @@ import com.cloud.agent.api.StoragePoolInfo;
|
|||||||
import com.cloud.capacity.Capacity;
|
import com.cloud.capacity.Capacity;
|
||||||
import com.cloud.capacity.CapacityVO;
|
import com.cloud.capacity.CapacityVO;
|
||||||
import com.cloud.capacity.dao.CapacityDao;
|
import com.cloud.capacity.dao.CapacityDao;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.exception.ConnectionException;
|
import com.cloud.exception.ConnectionException;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
@ -48,6 +50,7 @@ public class LocalStoragePoolListener implements Listener {
|
|||||||
@Inject StoragePoolHostDao _storagePoolHostDao;
|
@Inject StoragePoolHostDao _storagePoolHostDao;
|
||||||
@Inject CapacityDao _capacityDao;
|
@Inject CapacityDao _capacityDao;
|
||||||
@Inject StorageManager _storageMgr;
|
@Inject StorageManager _storageMgr;
|
||||||
|
@Inject DataCenterDao _dcDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTimeout() {
|
public int getTimeout() {
|
||||||
@ -87,6 +90,11 @@ public class LocalStoragePoolListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataCenterVO dc = _dcDao.findById(host.getDataCenterId());
|
||||||
|
if (dc == null || !dc.isLocalStorageEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid());
|
StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid());
|
||||||
if(pool == null && host.getHypervisorType() == HypervisorType.VMware) {
|
if(pool == null && host.getHypervisorType() == HypervisorType.VMware) {
|
||||||
|
|||||||
@ -126,6 +126,7 @@ import com.cloud.host.dao.HostDao;
|
|||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||||
import com.cloud.network.NetworkManager;
|
import com.cloud.network.NetworkManager;
|
||||||
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.org.Grouping;
|
import com.cloud.org.Grouping;
|
||||||
import com.cloud.org.Grouping.AllocationState;
|
import com.cloud.org.Grouping.AllocationState;
|
||||||
import com.cloud.projects.Project.ListProjectResourcesCriteria;
|
import com.cloud.projects.Project.ListProjectResourcesCriteria;
|
||||||
@ -457,13 +458,13 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO dc, HostPodVO pod, Long clusterId, VMInstanceVO vm, final Set<StoragePool> avoid) {
|
protected StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, final Set<StoragePool> avoid) {
|
||||||
|
|
||||||
VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
|
VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
|
||||||
Enumeration<StoragePoolAllocator> en = _storagePoolAllocators.enumeration();
|
Enumeration<StoragePoolAllocator> en = _storagePoolAllocators.enumeration();
|
||||||
while (en.hasMoreElements()) {
|
while (en.hasMoreElements()) {
|
||||||
final StoragePoolAllocator allocator = en.nextElement();
|
final StoragePoolAllocator allocator = en.nextElement();
|
||||||
final List<StoragePool> poolList = allocator.allocateToPool(dskCh, profile, dc.getId(), pod.getId(), clusterId, avoid, 1);
|
final List<StoragePool> poolList = allocator.allocateToPool(dskCh, profile, dc.getId(), pod.getId(), clusterId, hostId, avoid, 1);
|
||||||
if (poolList != null && !poolList.isEmpty()) {
|
if (poolList != null && !poolList.isEmpty()) {
|
||||||
return (StoragePoolVO) poolList.get(0);
|
return (StoragePoolVO) poolList.get(0);
|
||||||
}
|
}
|
||||||
@ -571,7 +572,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
|
while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
|
||||||
podsToAvoid.add(pod.first().getId());
|
podsToAvoid.add(pod.first().getId());
|
||||||
// Determine what storage pool to store the volume in
|
// Determine what storage pool to store the volume in
|
||||||
while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, poolsToAvoid)) != null) {
|
while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) {
|
||||||
poolsToAvoid.add(pool);
|
poolsToAvoid.add(pool);
|
||||||
volumeFolder = pool.getPath();
|
volumeFolder = pool.getPath();
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
@ -741,7 +742,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
|
DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
|
||||||
dskCh.setHyperType(vm.getHypervisorType());
|
dskCh.setHyperType(vm.getHypervisorType());
|
||||||
// Find a suitable storage to create volume on
|
// Find a suitable storage to create volume on
|
||||||
StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, vm, avoidPools);
|
StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, null, vm, avoidPools);
|
||||||
|
|
||||||
// Copy the volume from secondary storage to the destination storage pool
|
// Copy the volume from secondary storage to the destination storage pool
|
||||||
stateTransitTo(volume, Event.CopyRequested);
|
stateTransitTo(volume, Event.CopyRequested);
|
||||||
@ -818,7 +819,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = findStoragePool(dskCh, dc, pod, clusterId, vm, avoidPools);
|
pool = findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools);
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
s_logger.warn("Unable to find storage poll when create volume " + volume.getName());
|
s_logger.warn("Unable to find storage poll when create volume " + volume.getName());
|
||||||
break;
|
break;
|
||||||
@ -988,10 +989,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
int wrks = NumbersUtil.parseInt(workers, 10);
|
int wrks = NumbersUtil.parseInt(workers, 10);
|
||||||
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("StorageManager-Scavenger"));
|
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("StorageManager-Scavenger"));
|
||||||
|
|
||||||
boolean localStorage = Boolean.parseBoolean(configs.get(Config.UseLocalStorage.key()));
|
|
||||||
if (localStorage) {
|
|
||||||
_agentMgr.registerForHostEvents(ComponentLocator.inject(LocalStoragePoolListener.class), true, false, false);
|
_agentMgr.registerForHostEvents(ComponentLocator.inject(LocalStoragePoolListener.class), true, false, false);
|
||||||
}
|
|
||||||
|
|
||||||
String maxVolumeSizeInGbString = configDao.getValue("storage.max.volume.size");
|
String maxVolumeSizeInGbString = configDao.getValue("storage.max.volume.size");
|
||||||
_maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, 2000);
|
_maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, 2000);
|
||||||
@ -1713,7 +1711,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
dskCh.setHyperType(dataDiskHyperType);
|
dskCh.setHyperType(dataDiskHyperType);
|
||||||
DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId);
|
DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId);
|
||||||
HostPodVO destPoolPod = _podDao.findById(destPoolPodId);
|
HostPodVO destPoolPod = _podDao.findById(destPoolPodId);
|
||||||
StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, new HashSet<StoragePool>());
|
StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, new HashSet<StoragePool>());
|
||||||
String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
|
String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
|
||||||
|
|
||||||
if (destPool == null) {
|
if (destPool == null) {
|
||||||
@ -1894,6 +1892,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
|
|
||||||
Long zoneId = cmd.getZoneId();
|
Long zoneId = cmd.getZoneId();
|
||||||
Long diskOfferingId = null;
|
Long diskOfferingId = null;
|
||||||
|
DiskOfferingVO diskOffering = null;
|
||||||
Long size = null;
|
Long size = null;
|
||||||
|
|
||||||
// validate input parameters before creating the volume
|
// validate input parameters before creating the volume
|
||||||
@ -1913,11 +1912,9 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
throw new InvalidParameterValueException("Disk size must be larger than 0");
|
throw new InvalidParameterValueException("Disk size must be larger than 0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diskOfferingId == null) {
|
|
||||||
throw new InvalidParameterValueException("Missing parameter(s),either a positive volume size or a valid disk offering id must be specified.");
|
|
||||||
}
|
|
||||||
// Check that the the disk offering is specified
|
// Check that the the disk offering is specified
|
||||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||||
if ((diskOffering == null) || diskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) {
|
if ((diskOffering == null) || diskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) {
|
||||||
throw new InvalidParameterValueException("Please specify a valid disk offering.");
|
throw new InvalidParameterValueException("Please specify a valid disk offering.");
|
||||||
}
|
}
|
||||||
@ -1959,7 +1956,8 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.Status.BackedUp + " state yet and can't be used for volume creation");
|
throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.Status.BackedUp + " state yet and can't be used for volume creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
diskOfferingId = (cmd.getDiskOfferingId() != null) ? cmd.getDiskOfferingId() : snapshotCheck.getDiskOfferingId();
|
diskOfferingId = snapshotCheck.getDiskOfferingId();
|
||||||
|
diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||||
zoneId = snapshotCheck.getDataCenterId();
|
zoneId = snapshotCheck.getDataCenterId();
|
||||||
size = snapshotCheck.getSize(); // ; disk offering is used for tags purposes
|
size = snapshotCheck.getSize(); // ; disk offering is used for tags purposes
|
||||||
|
|
||||||
@ -1988,12 +1986,27 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId);
|
throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is a shared primary storage pool in the specified zone
|
// If local storage is disabled then creation of volume with local disk offering not allowed
|
||||||
|
if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) {
|
||||||
|
throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there is appropriate primary storage pool in the specified zone
|
||||||
List<StoragePoolVO> storagePools = _storagePoolDao.listByDataCenterId(zoneId);
|
List<StoragePoolVO> storagePools = _storagePoolDao.listByDataCenterId(zoneId);
|
||||||
boolean sharedPoolExists = false;
|
boolean appropriatePoolExists = false;
|
||||||
|
if (!diskOffering.getUseLocalStorage()) {
|
||||||
for (StoragePoolVO storagePool : storagePools) {
|
for (StoragePoolVO storagePool : storagePools) {
|
||||||
if (storagePool.isShared()) {
|
if (storagePool.isShared()) {
|
||||||
sharedPoolExists = true;
|
appropriatePoolExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (StoragePoolVO storagePool : storagePools) {
|
||||||
|
if (storagePool.isLocal()) {
|
||||||
|
appropriatePoolExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2003,8 +2016,9 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
throw new InvalidParameterValueException("There is no workable host in data center id " + zoneId + ", please check hosts' agent status and see if they are disabled");
|
throw new InvalidParameterValueException("There is no workable host in data center id " + zoneId + ", please check hosts' agent status and see if they are disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sharedPoolExists) {
|
if (!appropriatePoolExists) {
|
||||||
throw new InvalidParameterValueException("Please specify a zone that has at least one shared primary storage pool.");
|
String storageType = diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString();
|
||||||
|
throw new InvalidParameterValueException("Volume's disk offering uses " + storageType + " storage, please specify a zone that has at least one " + storageType + " primary storage pool.");
|
||||||
}
|
}
|
||||||
|
|
||||||
String userSpecifiedName = cmd.getVolumeName();
|
String userSpecifiedName = cmd.getVolumeName();
|
||||||
@ -3047,7 +3061,11 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
|
|||||||
|
|
||||||
StoragePool destPool = _storagePoolDao.findById(storagePoolId);
|
StoragePool destPool = _storagePoolDao.findById(storagePoolId);
|
||||||
if (destPool == null) {
|
if (destPool == null) {
|
||||||
throw new InvalidParameterValueException("Faild to find the destination storage pool: " + storagePoolId);
|
throw new InvalidParameterValueException("Failed to find the destination storage pool: " + storagePoolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!volumeOnSharedStoragePool(vol)) {
|
||||||
|
throw new InvalidParameterValueException("Migration of volume from local storage pool is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Volume> vols = new ArrayList<Volume>();
|
List<Volume> vols = new ArrayList<Volume>();
|
||||||
|
|||||||
@ -193,14 +193,14 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, long dcId, long podId, Long clusterId, Set<? extends StoragePool> avoids, int returnUpTo) {
|
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, long dcId, long podId, Long clusterId, Long hostId, Set<? extends StoragePool> avoids, int returnUpTo) {
|
||||||
|
|
||||||
ExcludeList avoid = new ExcludeList();
|
ExcludeList avoid = new ExcludeList();
|
||||||
for(StoragePool pool : avoids){
|
for(StoragePool pool : avoids){
|
||||||
avoid.addPool(pool.getId());
|
avoid.addPool(pool.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
DataCenterDeployment plan = new DataCenterDeployment(dcId, podId, clusterId, null, null, null);
|
DataCenterDeployment plan = new DataCenterDeployment(dcId, podId, clusterId, hostId, null, null);
|
||||||
return allocateToPool(dskCh, vmProfile, plan, avoid, returnUpTo);
|
return allocateToPool(dskCh, vmProfile, plan, avoid, returnUpTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import org.apache.log4j.Logger;
|
|||||||
|
|
||||||
import com.cloud.deploy.DeploymentPlan;
|
import com.cloud.deploy.DeploymentPlan;
|
||||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||||
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.server.StatsCollector;
|
import com.cloud.server.StatsCollector;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.dao.DiskOfferingDao;
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
@ -85,7 +86,8 @@ public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
|||||||
List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags(), null);
|
List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags(), null);
|
||||||
if (pools.size() == 0) {
|
if (pools.size() == 0) {
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("No storage pools available for allocation, returning");
|
String storageType = dskCh.useLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString();
|
||||||
|
s_logger.debug("No storage pools available for " + storageType + " volume allocation, returning");
|
||||||
}
|
}
|
||||||
return suitablePools;
|
return suitablePools;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,8 @@ import com.cloud.offering.ServiceOffering;
|
|||||||
import com.cloud.service.dao.ServiceOfferingDao;
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
|
import com.cloud.storage.StoragePoolVO;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.utils.DateUtil;
|
import com.cloud.utils.DateUtil;
|
||||||
@ -101,6 +103,21 @@ public class LocalStoragePoolAllocator extends FirstFitStoragePoolAllocator {
|
|||||||
s_logger.debug("LocalStoragePoolAllocator trying to find storage pool to fit the vm");
|
s_logger.debug("LocalStoragePoolAllocator trying to find storage pool to fit the vm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data disk and host identified from deploying vm (attach volume case)
|
||||||
|
if (dskCh.getType() == Volume.Type.DATADISK && plan.getHostId() != null) {
|
||||||
|
List<StoragePoolHostVO> hostPools = _poolHostDao.listByHostId(plan.getHostId());
|
||||||
|
for (StoragePoolHostVO hostPool: hostPools) {
|
||||||
|
StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId());
|
||||||
|
if (pool != null && pool.isLocal()) {
|
||||||
|
s_logger.debug("Found suitable local storage pool " + pool.getId() + ", adding to list");
|
||||||
|
suitablePools.add(pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suitablePools.size() == returnUpTo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
List<StoragePool> availablePool;
|
List<StoragePool> availablePool;
|
||||||
while (!(availablePool = super.allocateToPool(dskCh, vmProfile, plan, myAvoids, 1)).isEmpty()) {
|
while (!(availablePool = super.allocateToPool(dskCh, vmProfile, plan, myAvoids, 1)).isEmpty()) {
|
||||||
StoragePool pool = availablePool.get(0);
|
StoragePool pool = availablePool.get(0);
|
||||||
@ -115,6 +132,7 @@ public class LocalStoragePoolAllocator extends FirstFitStoragePoolAllocator {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("LocalStoragePoolAllocator returning " + suitablePools.size() + " suitable storage pools");
|
s_logger.debug("LocalStoragePoolAllocator returning " + suitablePools.size() + " suitable storage pools");
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import com.cloud.vm.VirtualMachineProfile;
|
|||||||
public interface StoragePoolAllocator extends Adapter {
|
public interface StoragePoolAllocator extends Adapter {
|
||||||
|
|
||||||
//keeping since storageMgr is using this API for some existing functionalities
|
//keeping since storageMgr is using this API for some existing functionalities
|
||||||
List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, long dcId, long podId, Long clusterId, Set<? extends StoragePool> avoids, int returnUpTo);
|
List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, long dcId, long podId, Long clusterId, Long hostId, Set<? extends StoragePool> avoids, int returnUpTo);
|
||||||
|
|
||||||
String chooseStorageIp(VirtualMachine vm, Host host, Host storage);
|
String chooseStorageIp(VirtualMachine vm, Host host, Host storage);
|
||||||
|
|
||||||
|
|||||||
@ -24,23 +24,29 @@ import javax.naming.ConfigurationException;
|
|||||||
|
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.configuration.dao.ConfigurationDao;
|
import com.cloud.configuration.dao.ConfigurationDao;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.deploy.DeploymentPlan;
|
import com.cloud.deploy.DeploymentPlan;
|
||||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.Volume.Type;
|
import com.cloud.storage.Volume.Type;
|
||||||
import com.cloud.utils.component.ComponentLocator;
|
import com.cloud.utils.component.ComponentLocator;
|
||||||
|
import com.cloud.utils.component.Inject;
|
||||||
import com.cloud.vm.DiskProfile;
|
import com.cloud.vm.DiskProfile;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineProfile;
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
|
||||||
@Local(value=StoragePoolAllocator.class)
|
@Local(value=StoragePoolAllocator.class)
|
||||||
public class UseLocalForRootAllocator extends LocalStoragePoolAllocator implements StoragePoolAllocator {
|
public class UseLocalForRootAllocator extends LocalStoragePoolAllocator implements StoragePoolAllocator {
|
||||||
boolean _useLocalStorage;
|
|
||||||
|
@Inject
|
||||||
|
DataCenterDao _dcDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
|
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
|
||||||
if (!_useLocalStorage) {
|
DataCenterVO dc = _dcDao.findById(plan.getDataCenterId());
|
||||||
|
if (!dc.isLocalStorageEnabled()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,13 +61,6 @@ public class UseLocalForRootAllocator extends LocalStoragePoolAllocator implemen
|
|||||||
@Override
|
@Override
|
||||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||||
super.configure(name, params);
|
super.configure(name, params);
|
||||||
|
|
||||||
ComponentLocator locator = ComponentLocator.getCurrentLocator();
|
|
||||||
ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
|
|
||||||
Map<String, String> dbParams = configDao.getConfiguration(params);
|
|
||||||
|
|
||||||
_useLocalStorage = Boolean.parseBoolean(dbParams.get(Config.UseLocalStorage.toString()));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -205,8 +205,7 @@ public class DatabaseConfig {
|
|||||||
s_configurationDescriptions.put("expunge.interval", "the interval to wait before running the expunge thread");
|
s_configurationDescriptions.put("expunge.interval", "the interval to wait before running the expunge thread");
|
||||||
s_configurationDescriptions.put("network.throttling.rate", "default data transfer rate in megabits per second allowed per user");
|
s_configurationDescriptions.put("network.throttling.rate", "default data transfer rate in megabits per second allowed per user");
|
||||||
s_configurationDescriptions.put("multicast.throttling.rate", "default multicast rate in megabits per second allowed");
|
s_configurationDescriptions.put("multicast.throttling.rate", "default multicast rate in megabits per second allowed");
|
||||||
s_configurationDescriptions.put("use.local.storage", "Indicates whether to use local storage pools or shared storage pools for user VMs");
|
s_configurationDescriptions.put("system.vm.use.local.storage", "Indicates whether to use local storage pools or shared storage pools for system VMs.");
|
||||||
s_configurationDescriptions.put("use.local.storage", "Indicates whether to use local storage pools or shared storage pools for system VMs.");
|
|
||||||
s_configurationDescriptions.put("snapshot.poll.interval", "The time interval in seconds when the management server polls for snapshots to be scheduled.");
|
s_configurationDescriptions.put("snapshot.poll.interval", "The time interval in seconds when the management server polls for snapshots to be scheduled.");
|
||||||
s_configurationDescriptions.put("snapshot.max.hourly", "Maximum hourly snapshots for a volume");
|
s_configurationDescriptions.put("snapshot.max.hourly", "Maximum hourly snapshots for a volume");
|
||||||
s_configurationDescriptions.put("snapshot.max.daily", "Maximum daily snapshots for a volume");
|
s_configurationDescriptions.put("snapshot.max.daily", "Maximum daily snapshots for a volume");
|
||||||
@ -280,7 +279,6 @@ public class DatabaseConfig {
|
|||||||
s_configurationComponents.put("storage.overwrite.provisioning", "UserVmManager");
|
s_configurationComponents.put("storage.overwrite.provisioning", "UserVmManager");
|
||||||
s_configurationComponents.put("init", "none");
|
s_configurationComponents.put("init", "none");
|
||||||
s_configurationComponents.put("system.vm.use.local.storage", "ManagementServer");
|
s_configurationComponents.put("system.vm.use.local.storage", "ManagementServer");
|
||||||
s_configurationComponents.put("use.local.storage", "ManagementServer");
|
|
||||||
s_configurationComponents.put("snapshot.poll.interval", "SnapshotManager");
|
s_configurationComponents.put("snapshot.poll.interval", "SnapshotManager");
|
||||||
s_configurationComponents.put("snapshot.max.hourly", "SnapshotManager");
|
s_configurationComponents.put("snapshot.max.hourly", "SnapshotManager");
|
||||||
s_configurationComponents.put("snapshot.max.daily", "SnapshotManager");
|
s_configurationComponents.put("snapshot.max.daily", "SnapshotManager");
|
||||||
@ -334,7 +332,6 @@ public class DatabaseConfig {
|
|||||||
s_defaultConfigurationValues.put("event.purge.interval", "86400");
|
s_defaultConfigurationValues.put("event.purge.interval", "86400");
|
||||||
s_defaultConfigurationValues.put("account.cleanup.interval", "86400");
|
s_defaultConfigurationValues.put("account.cleanup.interval", "86400");
|
||||||
s_defaultConfigurationValues.put("system.vm.use.local.storage", "false");
|
s_defaultConfigurationValues.put("system.vm.use.local.storage", "false");
|
||||||
s_defaultConfigurationValues.put("use.local.storage", "false");
|
|
||||||
s_defaultConfigurationValues.put("init", "false");
|
s_defaultConfigurationValues.put("init", "false");
|
||||||
s_defaultConfigurationValues.put("cpu.overprovisioning.factor", "1");
|
s_defaultConfigurationValues.put("cpu.overprovisioning.factor", "1");
|
||||||
s_defaultConfigurationValues.put("mem.overprovisioning.factor", "1");
|
s_defaultConfigurationValues.put("mem.overprovisioning.factor", "1");
|
||||||
|
|||||||
@ -588,6 +588,15 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume.");
|
throw new InvalidParameterValueException("Please specify a VM that is in the same zone as the volume.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If local storage is disabled then attaching a volume with local disk offering not allowed
|
||||||
|
DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId());
|
||||||
|
if (!dataCenter.isLocalStorageEnabled()) {
|
||||||
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||||
|
if (diskOffering.getUseLocalStorage()) {
|
||||||
|
throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//permission check
|
//permission check
|
||||||
_accountMgr.checkAccess(caller, null, true, volume, vm);
|
_accountMgr.checkAccess(caller, null, true, volume, vm);
|
||||||
|
|
||||||
@ -601,11 +610,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the volume is Ready, check that the volume is stored on shared storage
|
|
||||||
if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.UploadOp.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) {
|
|
||||||
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp.equals(volume.getState())) ) {
|
if ( !(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp.equals(volume.getState())) ) {
|
||||||
throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state");
|
throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or in Uploaded state");
|
||||||
}
|
}
|
||||||
@ -700,10 +704,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
DiskOfferingVO volumeDiskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
DiskOfferingVO volumeDiskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||||
String[] volumeTags = volumeDiskOffering.getTagsArray();
|
String[] volumeTags = volumeDiskOffering.getTagsArray();
|
||||||
|
|
||||||
|
boolean isVolumeOnSharedPool = !volumeDiskOffering.getUseLocalStorage();
|
||||||
StoragePoolVO sourcePool = _storagePoolDao.findById(volume.getPoolId());
|
StoragePoolVO sourcePool = _storagePoolDao.findById(volume.getPoolId());
|
||||||
List<StoragePoolVO> sharedVMPools = _storagePoolDao.findPoolsByTags(vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), volumeTags, true);
|
List<StoragePoolVO> matchingVMPools = _storagePoolDao.findPoolsByTags(vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), volumeTags, isVolumeOnSharedPool);
|
||||||
boolean moveVolumeNeeded = true;
|
boolean moveVolumeNeeded = true;
|
||||||
if (sharedVMPools.size() == 0) {
|
if (matchingVMPools.size() == 0) {
|
||||||
String poolType;
|
String poolType;
|
||||||
if (vmRootVolumePool.getClusterId() != null) {
|
if (vmRootVolumePool.getClusterId() != null) {
|
||||||
poolType = "cluster";
|
poolType = "cluster";
|
||||||
@ -714,15 +719,20 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
}
|
}
|
||||||
throw new CloudRuntimeException("There are no storage pools in the VM's " + poolType + " with all of the volume's tags (" + volumeDiskOffering.getTags() + ").");
|
throw new CloudRuntimeException("There are no storage pools in the VM's " + poolType + " with all of the volume's tags (" + volumeDiskOffering.getTags() + ").");
|
||||||
} else {
|
} else {
|
||||||
|
long sourcePoolId = sourcePool.getId();
|
||||||
Long sourcePoolDcId = sourcePool.getDataCenterId();
|
Long sourcePoolDcId = sourcePool.getDataCenterId();
|
||||||
Long sourcePoolPodId = sourcePool.getPodId();
|
Long sourcePoolPodId = sourcePool.getPodId();
|
||||||
Long sourcePoolClusterId = sourcePool.getClusterId();
|
Long sourcePoolClusterId = sourcePool.getClusterId();
|
||||||
for (StoragePoolVO vmPool : sharedVMPools) {
|
for (StoragePoolVO vmPool : matchingVMPools) {
|
||||||
|
long vmPoolId = vmPool.getId();
|
||||||
Long vmPoolDcId = vmPool.getDataCenterId();
|
Long vmPoolDcId = vmPool.getDataCenterId();
|
||||||
Long vmPoolPodId = vmPool.getPodId();
|
Long vmPoolPodId = vmPool.getPodId();
|
||||||
Long vmPoolClusterId = vmPool.getClusterId();
|
Long vmPoolClusterId = vmPool.getClusterId();
|
||||||
|
|
||||||
if (sourcePoolDcId == vmPoolDcId && sourcePoolPodId == vmPoolPodId && sourcePoolClusterId == vmPoolClusterId) {
|
// Moving a volume is not required if storage pools belongs to same cluster in case of shared volume or
|
||||||
|
// identical storage pool in case of local
|
||||||
|
if (sourcePoolDcId == vmPoolDcId && sourcePoolPodId == vmPoolPodId && sourcePoolClusterId == vmPoolClusterId
|
||||||
|
&& (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) {
|
||||||
moveVolumeNeeded = false;
|
moveVolumeNeeded = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -730,12 +740,16 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (moveVolumeNeeded) {
|
if (moveVolumeNeeded) {
|
||||||
|
if (isVolumeOnSharedPool) {
|
||||||
// Move the volume to a storage pool in the VM's zone, pod, or cluster
|
// Move the volume to a storage pool in the VM's zone, pod, or cluster
|
||||||
try {
|
try {
|
||||||
volume = _storageMgr.moveVolume(volume, vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), dataDiskHyperType);
|
volume = _storageMgr.moveVolume(volume, vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), dataDiskHyperType);
|
||||||
} catch (ConcurrentOperationException e) {
|
} catch (ConcurrentOperationException e) {
|
||||||
throw new CloudRuntimeException(e.toString());
|
throw new CloudRuntimeException(e.toString());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw new CloudRuntimeException("Failed to attach local data volume " + volume.getName() + " to VM " + vm.getDisplayName() + " as migration of local data volume is not allowed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,11 +852,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
throw new InvalidParameterValueException("The specified volume is not attached to a VM.");
|
throw new InvalidParameterValueException("The specified volume is not attached to a VM.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the volume is stored on shared storage
|
|
||||||
if (volume.getState() != Volume.State.Allocated && !_storageMgr.volumeOnSharedStoragePool(volume)) {
|
|
||||||
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the VM is in the correct state
|
// Check that the VM is in the correct state
|
||||||
UserVmVO vm = _vmDao.findById(vmId);
|
UserVmVO vm = _vmDao.findById(vmId);
|
||||||
if (vm.getState() != State.Running && vm.getState() != State.Stopped && vm.getState() != State.Destroyed) {
|
if (vm.getState() != State.Running && vm.getState() != State.Stopped && vm.getState() != State.Destroyed) {
|
||||||
@ -3276,6 +3285,25 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isVMUsingLocalStorage(VMInstanceVO vm)
|
||||||
|
{
|
||||||
|
boolean usesLocalStorage = false;
|
||||||
|
ServiceOfferingVO svcOffering = _serviceOfferingDao.findById(vm.getServiceOfferingId());
|
||||||
|
if (svcOffering.getUseLocalStorage()) {
|
||||||
|
usesLocalStorage = true;
|
||||||
|
} else {
|
||||||
|
List<VolumeVO> volumes = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.DATADISK);
|
||||||
|
for (VolumeVO vol : volumes) {
|
||||||
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
|
||||||
|
if (diskOffering.getUseLocalStorage()) {
|
||||||
|
usesLocalStorage = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return usesLocalStorage;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
|
||||||
public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
|
public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
|
||||||
@ -3308,8 +3336,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||||||
throw new InvalidParameterValueException("Unsupported Hypervisor Type for VM migration, we support XenServer/VMware/KVM only");
|
throw new InvalidParameterValueException("Unsupported Hypervisor Type for VM migration, we support XenServer/VMware/KVM only");
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceOfferingVO svcOffering = _serviceOfferingDao.findById(vm.getServiceOfferingId());
|
if (isVMUsingLocalStorage(vm)) {
|
||||||
if (svcOffering.getUseLocalStorage()) {
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug(vm + " is using Local Storage, cannot migrate this VM.");
|
s_logger.debug(vm + " is using Local Storage, cannot migrate this VM.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -547,6 +547,7 @@ CREATE TABLE `cloud`.`data_center` (
|
|||||||
`allocation_state` varchar(32) NOT NULL DEFAULT 'Enabled' COMMENT 'Is this data center enabled for allocation for new resources',
|
`allocation_state` varchar(32) NOT NULL DEFAULT 'Enabled' COMMENT 'Is this data center enabled for allocation for new resources',
|
||||||
`zone_token` varchar(255),
|
`zone_token` varchar(255),
|
||||||
`is_security_group_enabled` tinyint NOT NULL DEFAULT 0 COMMENT '1: enabled, 0: not',
|
`is_security_group_enabled` tinyint NOT NULL DEFAULT 0 COMMENT '1: enabled, 0: not',
|
||||||
|
`is_local_storage_enabled` tinyint NOT NULL DEFAULT 0 COMMENT 'Is local storage offering enabled for this data center; 1: enabled, 0: not',
|
||||||
`removed` datetime COMMENT 'date removed if not null',
|
`removed` datetime COMMENT 'date removed if not null',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `fk_data_center__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`),
|
CONSTRAINT `fk_data_center__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`),
|
||||||
|
|||||||
@ -246,6 +246,10 @@ DEALLOCATE PREPARE stmt1;
|
|||||||
AlTER TABLE physical_network_service_providers ADD CONSTRAINT `fk_pnetwork_service_providers__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE;
|
AlTER TABLE physical_network_service_providers ADD CONSTRAINT `fk_pnetwork_service_providers__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE;
|
||||||
UPDATE `cloud`.`configuration` SET description='In second, timeout for creating volume from snapshot' WHERE name='create.volume.from.snapshot.wait';
|
UPDATE `cloud`.`configuration` SET description='In second, timeout for creating volume from snapshot' WHERE name='create.volume.from.snapshot.wait';
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`data_center` ADD COLUMN `is_local_storage_enabled` tinyint NOT NULL DEFAULT 0 COMMENT 'Is local storage offering enabled for this data center; 1: enabled, 0: not';
|
||||||
|
UPDATE `cloud`.`data_center` SET `is_local_storage_enabled` = IF ((SELECT `value` FROM `cloud`.`configuration` WHERE `name`='use.local.storage')='true', 1, 0) WHERE `removed` IS NULL;
|
||||||
|
DELETE FROM `cloud`.`configuration` where name='use.local.storage';
|
||||||
|
|
||||||
ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_data_volumes_limit` int unsigned DEFAULT 6 COMMENT 'Max. data volumes per VM supported by hypervisor';
|
ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_data_volumes_limit` int unsigned DEFAULT 6 COMMENT 'Max. data volumes per VM supported by hypervisor';
|
||||||
UPDATE `cloud`.`hypervisor_capabilities` SET `max_data_volumes_limit`=13 WHERE `hypervisor_type`='XenServer' AND (`hypervisor_version`='6.0' OR `hypervisor_version`='6.0.2');
|
UPDATE `cloud`.`hypervisor_capabilities` SET `max_data_volumes_limit`=13 WHERE `hypervisor_type`='XenServer' AND (`hypervisor_version`='6.0' OR `hypervisor_version`='6.0.2');
|
||||||
INSERT INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `value`, `description`) VALUES ('Advanced', 'DEFAULT', 'management-server', 'event.purge.interval', '86400', 'The interval (in seconds) to wait before running the event purge thread');
|
INSERT INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `value`, `description`) VALUES ('Advanced', 'DEFAULT', 'management-server', 'event.purge.interval', '86400', 'The interval (in seconds) to wait before running the event purge thread');
|
||||||
|
|||||||
@ -774,6 +774,15 @@
|
|||||||
label: 'label.description',
|
label: 'label.description',
|
||||||
validation: { required: true }
|
validation: { required: true }
|
||||||
},
|
},
|
||||||
|
storageType: {
|
||||||
|
label: 'label.storage.type',
|
||||||
|
select: function(args) {
|
||||||
|
var items = [];
|
||||||
|
items.push({id: 'shared', description: 'shared'});
|
||||||
|
items.push({id: 'local', description: 'local'});
|
||||||
|
args.response.success({data: items});
|
||||||
|
}
|
||||||
|
},
|
||||||
isCustomized: {
|
isCustomized: {
|
||||||
label: 'label.custom.disk.size',
|
label: 'label.custom.disk.size',
|
||||||
isBoolean: true,
|
isBoolean: true,
|
||||||
@ -822,6 +831,7 @@
|
|||||||
array1.push("&name=" + args.data.name);
|
array1.push("&name=" + args.data.name);
|
||||||
array1.push("&displaytext=" + todb(args.data.description));
|
array1.push("&displaytext=" + todb(args.data.description));
|
||||||
|
|
||||||
|
array1.push("&storageType=" + todb(args.data.storageType));
|
||||||
array1.push("&customized=" + (args.data.isCustomized=="on"));
|
array1.push("&customized=" + (args.data.isCustomized=="on"));
|
||||||
if(args.$form.find('.form-item[rel=disksize]').css("display") != "none")
|
if(args.$form.find('.form-item[rel=disksize]').css("display") != "none")
|
||||||
array1.push("&disksize=" + args.data.disksize);
|
array1.push("&disksize=" + args.data.disksize);
|
||||||
@ -941,7 +951,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
tags: { label: 'label.storage.tags' },
|
tags: { label: 'label.storage.tags' },
|
||||||
domain: { label: 'label.domain' }
|
domain: { label: 'label.domain' },
|
||||||
|
storagetype: { label: 'label.storage.type' }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@ -1327,21 +1327,19 @@
|
|||||||
}
|
}
|
||||||
else { //jsonObj.type == "DATADISK"
|
else { //jsonObj.type == "DATADISK"
|
||||||
if (jsonObj.virtualmachineid != null) {
|
if (jsonObj.virtualmachineid != null) {
|
||||||
if (jsonObj.storagetype == "shared" && (jsonObj.vmstate == "Running" || jsonObj.vmstate == "Stopped" || jsonObj.vmstate == "Destroyed")) {
|
if (jsonObj.vmstate == "Running" || jsonObj.vmstate == "Stopped" || jsonObj.vmstate == "Destroyed") {
|
||||||
allowedActions.push("detachDisk");
|
allowedActions.push("detachDisk");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // Disk not attached
|
else { // Disk not attached
|
||||||
allowedActions.push("remove");
|
allowedActions.push("remove");
|
||||||
if(jsonObj.state == "Ready" && isAdmin()) {
|
if(jsonObj.state == "Ready" && isAdmin() && jsonObj.storagetype == "shared") {
|
||||||
allowedActions.push("migrateToAnotherStorage");
|
allowedActions.push("migrateToAnotherStorage");
|
||||||
}
|
}
|
||||||
if (jsonObj.storagetype == "shared") {
|
|
||||||
allowedActions.push("attachDisk");
|
allowedActions.push("attachDisk");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return allowedActions;
|
return allowedActions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3973,6 +3973,7 @@
|
|||||||
array1.push("&internaldns1=" + todb(args.data.internaldns1));
|
array1.push("&internaldns1=" + todb(args.data.internaldns1));
|
||||||
array1.push("&internaldns2=" + todb(args.data.internaldns2)); //internaldns2 can be empty ("") when passed to API
|
array1.push("&internaldns2=" + todb(args.data.internaldns2)); //internaldns2 can be empty ("") when passed to API
|
||||||
array1.push("&domain=" + todb(args.data.domain));
|
array1.push("&domain=" + todb(args.data.domain));
|
||||||
|
array1.push("&localstorageenabled=" + todb(args.data.localstorageenabled));
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: createURL("updateZone&id=" + args.context.physicalResources[0].id + array1.join("")),
|
url: createURL("updateZone&id=" + args.context.physicalResources[0].id + array1.join("")),
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
@ -4016,6 +4017,16 @@
|
|||||||
domain: {
|
domain: {
|
||||||
label: 'label.network.domain',
|
label: 'label.network.domain',
|
||||||
isEditable: true
|
isEditable: true
|
||||||
|
},
|
||||||
|
localstorageenabled: {
|
||||||
|
label: 'label.local.storage.enabled',
|
||||||
|
converter: function(args) {
|
||||||
|
if(args)
|
||||||
|
return "true";
|
||||||
|
else
|
||||||
|
return "false";
|
||||||
|
},
|
||||||
|
isEditable: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user