mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
SolidFire plug-in and related changes
SolidFire plug-in SolidFire plug-in related
This commit is contained in:
parent
02ab2eb384
commit
99227f7b3e
@ -23,14 +23,16 @@ import com.cloud.storage.Volume;
|
||||
public class DiskTO {
|
||||
private DataTO data;
|
||||
private Long diskSeq;
|
||||
private String vdiUuid;
|
||||
private Volume.Type type;
|
||||
public DiskTO() {
|
||||
|
||||
}
|
||||
|
||||
public DiskTO(DataTO data, Long diskSeq, Volume.Type type) {
|
||||
public DiskTO(DataTO data, Long diskSeq, String vdiUuid, Volume.Type type) {
|
||||
this.data = data;
|
||||
this.diskSeq = diskSeq;
|
||||
this.vdiUuid = vdiUuid;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@ -50,6 +52,14 @@ public class DiskTO {
|
||||
this.diskSeq = diskSeq;
|
||||
}
|
||||
|
||||
public String getVdiUuid() {
|
||||
return vdiUuid;
|
||||
}
|
||||
|
||||
public void setVdiUuid(String vdiUuid) {
|
||||
this.vdiUuid = vdiUuid;
|
||||
}
|
||||
|
||||
public Volume.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -47,12 +47,24 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
|
||||
|
||||
Date getCreated();
|
||||
|
||||
long getDiskSize();
|
||||
|
||||
boolean isCustomized();
|
||||
|
||||
void setDiskSize(long diskSize);
|
||||
|
||||
long getDiskSize();
|
||||
|
||||
void setCustomizedIops(Boolean customizedIops);
|
||||
|
||||
Boolean isCustomizedIops();
|
||||
|
||||
void setMinIops(Long minIops);
|
||||
|
||||
Long getMinIops();
|
||||
|
||||
void setMaxIops(Long maxIops);
|
||||
|
||||
Long getMaxIops();
|
||||
|
||||
void setBytesReadRate(Long bytesReadRate);
|
||||
|
||||
Long getBytesReadRate();
|
||||
|
||||
@ -60,6 +60,8 @@ public interface StoragePool extends Identity, InternalIdentity {
|
||||
*/
|
||||
long getUsedBytes();
|
||||
|
||||
Long getCapacityIops();
|
||||
|
||||
Long getClusterId();
|
||||
|
||||
/**
|
||||
|
||||
@ -122,6 +122,12 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba
|
||||
*/
|
||||
Long getSize();
|
||||
|
||||
Long getMinIops();
|
||||
|
||||
Long getMaxIops();
|
||||
|
||||
String get_iScsiName();
|
||||
|
||||
/**
|
||||
* @return the vm instance id
|
||||
*/
|
||||
|
||||
@ -51,6 +51,9 @@ public class ApiConstants {
|
||||
public static final String CPU_OVERCOMMIT_RATIO="cpuovercommitratio";
|
||||
public static final String CREATED = "created";
|
||||
public static final String CUSTOMIZED = "customized";
|
||||
public static final String CUSTOMIZED_IOPS = "customizediops";
|
||||
public static final String MIN_IOPS = "miniops";
|
||||
public static final String MAX_IOPS = "maxiops";
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String DESTINATION_ZONE_ID = "destzoneid";
|
||||
public static final String DETAILS = "details";
|
||||
@ -326,6 +329,9 @@ public class ApiConstants {
|
||||
public static final String SERVICE_CAPABILITY_LIST = "servicecapabilitylist";
|
||||
public static final String CAN_CHOOSE_SERVICE_CAPABILITY = "canchooseservicecapability";
|
||||
public static final String PROVIDER = "provider";
|
||||
public static final String MANAGED = "managed";
|
||||
public static final String CAPACITY_BYTES = "capacitybytes";
|
||||
public static final String CAPACITY_IOPS = "capacityiops";
|
||||
public static final String NETWORK_SPEED = "networkspeed";
|
||||
public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange";
|
||||
public static final String ISOLATION_METHODS = "isolationmethods";
|
||||
|
||||
@ -52,7 +52,7 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.TAGS, type=CommandType.STRING, description="tags for the disk offering", length=4096)
|
||||
private String tags;
|
||||
|
||||
@Parameter(name=ApiConstants.CUSTOMIZED, type=CommandType.BOOLEAN, description="whether disk offering is custom or not")
|
||||
@Parameter(name=ApiConstants.CUSTOMIZED, type=CommandType.BOOLEAN, description="whether disk offering size is custom or not")
|
||||
private Boolean customized;
|
||||
|
||||
@Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType=DomainResponse.class,
|
||||
@ -62,6 +62,9 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
@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();
|
||||
|
||||
@Parameter(name=ApiConstants.DISPLAY_OFFERING, type=CommandType.BOOLEAN, description="an optional field, whether to display the offering to the end user or not.")
|
||||
private Boolean displayOffering;
|
||||
|
||||
@Parameter(name=ApiConstants.BYTES_READ_RATE, type=CommandType.LONG, required=false, description="bytes read rate of the disk offering")
|
||||
private Long bytesReadRate;
|
||||
|
||||
@ -74,8 +77,14 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.IOPS_WRITE_RATE, type=CommandType.LONG, required=false, description="io requests write rate of the disk offering")
|
||||
private Long iopsWriteRate;
|
||||
|
||||
@Parameter(name=ApiConstants.DISPLAY_OFFERING, type=CommandType.BOOLEAN, description="an optional field, whether to display the offering to the end user or not.")
|
||||
private Boolean displayOffering;
|
||||
@Parameter(name=ApiConstants.CUSTOMIZED_IOPS, type=CommandType.BOOLEAN, required=false, description="whether disk offering iops is custom or not")
|
||||
private Boolean customizedIops;
|
||||
|
||||
@Parameter(name=ApiConstants.MIN_IOPS, type=CommandType.LONG, required=false, description="min iops of the disk offering")
|
||||
private Long minIops;
|
||||
|
||||
@Parameter(name=ApiConstants.MAX_IOPS, type=CommandType.LONG, required=false, description="max iops of the disk offering")
|
||||
private Long maxIops;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
@ -101,6 +110,18 @@ public class CreateDiskOfferingCmd extends BaseCmd {
|
||||
return customized;
|
||||
}
|
||||
|
||||
public Boolean isCustomizedIops() {
|
||||
return customizedIops;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public Long getDomainId(){
|
||||
return domainId;
|
||||
}
|
||||
|
||||
@ -80,6 +80,18 @@ public class CreateStoragePoolCmd extends BaseCmd {
|
||||
required=false, description="the scope of the storage: cluster or zone")
|
||||
private String scope;
|
||||
|
||||
@Parameter(name=ApiConstants.MANAGED, type=CommandType.BOOLEAN,
|
||||
required=false, description="whether the storage should be managed by CloudStack")
|
||||
private Boolean managed;
|
||||
|
||||
@Parameter(name=ApiConstants.CAPACITY_IOPS, type=CommandType.LONG,
|
||||
required=false, description="IOPS CloudStack can provision from this storage pool")
|
||||
private Long capacityIops;
|
||||
|
||||
@Parameter(name=ApiConstants.CAPACITY_BYTES, type=CommandType.LONG,
|
||||
required=false, description="bytes CloudStack can provision from this storage pool")
|
||||
private Long capacityBytes;
|
||||
|
||||
@Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=false,
|
||||
description="hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.")
|
||||
private String hypervisor;
|
||||
@ -124,6 +136,18 @@ public class CreateStoragePoolCmd extends BaseCmd {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
public Boolean isManaged() {
|
||||
return managed;
|
||||
}
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return capacityIops;
|
||||
}
|
||||
|
||||
public Long getCapacityBytes() {
|
||||
return capacityBytes;
|
||||
}
|
||||
|
||||
public String getHypervisor() {
|
||||
return hypervisor;
|
||||
}
|
||||
|
||||
@ -68,6 +68,12 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd {
|
||||
@Parameter(name=ApiConstants.SIZE, type=CommandType.LONG, description="Arbitrary volume size")
|
||||
private Long size;
|
||||
|
||||
@Parameter(name=ApiConstants.MIN_IOPS, type=CommandType.LONG, description="min iops")
|
||||
private Long minIops;
|
||||
|
||||
@Parameter(name=ApiConstants.MAX_IOPS, type=CommandType.LONG, description="max iops")
|
||||
private Long maxIops;
|
||||
|
||||
@Parameter(name=ApiConstants.SNAPSHOT_ID, type=CommandType.UUID, entityType=SnapshotResponse.class,
|
||||
description="the snapshot ID for the disk volume. Either diskOfferingId or snapshotId must be passed in.")
|
||||
private Long snapshotId;
|
||||
@ -104,6 +110,14 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public Long getSnapshotId() {
|
||||
return snapshotId;
|
||||
}
|
||||
|
||||
@ -52,6 +52,15 @@ public class DiskOfferingResponse extends BaseResponse {
|
||||
@SerializedName("iscustomized") @Param(description="true if disk offering uses custom size, false otherwise")
|
||||
private Boolean customized;
|
||||
|
||||
@SerializedName("iscustomizediops") @Param(description="true if disk offering uses custom iops, false otherwise")
|
||||
private Boolean customizedIops;
|
||||
|
||||
@SerializedName(ApiConstants.MIN_IOPS) @Param(description="the min iops of the disk offering")
|
||||
private Long minIops;
|
||||
|
||||
@SerializedName(ApiConstants.MAX_IOPS) @Param(description="the max iops of the disk offering")
|
||||
private Long maxIops;
|
||||
|
||||
@SerializedName(ApiConstants.TAGS) @Param(description="the tags for the disk offering")
|
||||
private String tags;
|
||||
|
||||
@ -154,6 +163,30 @@ public class DiskOfferingResponse extends BaseResponse {
|
||||
this.customized = customized;
|
||||
}
|
||||
|
||||
public Boolean isCustomizedIops() {
|
||||
return customizedIops;
|
||||
}
|
||||
|
||||
public void setCustomizedIops(Boolean customizedIops) {
|
||||
this.customizedIops = customizedIops;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
public String getStorageType() {
|
||||
return storageType;
|
||||
}
|
||||
|
||||
@ -74,6 +74,9 @@ public class StoragePoolResponse extends BaseResponse {
|
||||
@SerializedName("disksizeused") @Param(description="the host's currently used disk size")
|
||||
private Long diskSizeUsed;
|
||||
|
||||
@SerializedName("capacityiops") @Param(description="IOPS CloudStack can provision from this storage pool")
|
||||
private Long capacityIops;
|
||||
|
||||
@SerializedName("tags") @Param(description="the tags for the storage pool")
|
||||
private String tags;
|
||||
|
||||
@ -237,6 +240,14 @@ public class StoragePoolResponse extends BaseResponse {
|
||||
this.diskSizeUsed = diskSizeUsed;
|
||||
}
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return capacityIops;
|
||||
}
|
||||
|
||||
public void setCapacityIops(Long capacityIops) {
|
||||
this.capacityIops = capacityIops;
|
||||
}
|
||||
|
||||
public String getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@ -76,6 +76,14 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity
|
||||
@Param(description = "size of the disk volume")
|
||||
private Long size;
|
||||
|
||||
@SerializedName(ApiConstants.MIN_IOPS)
|
||||
@Param(description = "min iops of the disk volume")
|
||||
private Long minIops;
|
||||
|
||||
@SerializedName(ApiConstants.MAX_IOPS)
|
||||
@Param(description = "max iops of the disk volume")
|
||||
private Long maxIops;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "the date the disk volume was created")
|
||||
private Date created;
|
||||
@ -241,6 +249,14 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
label.custom.disk.iops=Custom IOPS
|
||||
label.disk.iops.min=Min IOPS
|
||||
label.disk.iops.max=Max IOPS
|
||||
label.disk.iops.total=IOPS Total
|
||||
label.view.secondary.ips=View secondary IPs
|
||||
message.acquire.ip.nic=Please confirm that you would like to acquire a new secondary IP for this NIC.<br/>NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.
|
||||
message.select.affinity.groups=Please select any affinity groups you want this VM to belong to:
|
||||
@ -395,7 +399,7 @@ label.code=Code
|
||||
label.community=Community
|
||||
label.compute.and.storage=Compute and Storage
|
||||
label.compute.offering=Compute offering
|
||||
label.compute.offerings=Compute offerings
|
||||
label.compute.offerings=Compute Offerings
|
||||
label.compute=Compute
|
||||
label.configuration=Configuration
|
||||
label.configure.network.ACLs=Configure Network ACLs
|
||||
@ -1046,6 +1050,7 @@ label.stopped.vms=Stopped VMs
|
||||
label.storage.tags=Storage Tags
|
||||
label.storage.traffic=Storage Traffic
|
||||
label.storage.type=Storage Type
|
||||
label.qos.type=QoS Type
|
||||
label.storage=Storage
|
||||
label.subdomain.access=Subdomain Access
|
||||
label.submit=Submit
|
||||
|
||||
@ -20,6 +20,11 @@
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-plugin-storage-volume-solidfire</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-server</artifactId>
|
||||
|
||||
@ -806,6 +806,7 @@
|
||||
<bean id="cloudStackImageStoreProviderImpl" class="org.apache.cloudstack.storage.datastore.provider.CloudStackImageStoreProviderImpl" />
|
||||
<bean id="s3ImageStoreProviderImpl" class="org.apache.cloudstack.storage.datastore.provider.S3ImageStoreProviderImpl" />
|
||||
<bean id="swiftImageStoreProviderImpl" class="org.apache.cloudstack.storage.datastore.provider.SwiftImageStoreProviderImpl" />
|
||||
<bean id="solidFireDataStoreProvider" class="org.apache.cloudstack.storage.datastore.provider.SolidfirePrimaryDataStoreProvider" />
|
||||
<bean id="ApplicationLoadBalancerService" class="org.apache.cloudstack.network.lb.ApplicationLoadBalancerManagerImpl" />
|
||||
<bean id="InternalLoadBalancerVMManager" class="org.apache.cloudstack.network.lb.InternalLoadBalancerVMManagerImpl" />
|
||||
<bean id="StorageCacheReplacementAlgorithm" class="org.apache.cloudstack.storage.cache.manager.StorageCacheReplacementAlgorithmLRU" />
|
||||
|
||||
@ -19,35 +19,33 @@ package com.cloud.agent.api;
|
||||
|
||||
public class AttachVolumeAnswer extends Answer {
|
||||
private Long deviceId;
|
||||
private String vdiUuid;
|
||||
private String chainInfo;
|
||||
|
||||
protected AttachVolumeAnswer() {
|
||||
|
||||
}
|
||||
|
||||
public AttachVolumeAnswer(AttachVolumeCommand cmd, String result) {
|
||||
super(cmd, false, result);
|
||||
this.deviceId = null;
|
||||
}
|
||||
|
||||
public AttachVolumeAnswer(AttachVolumeCommand cmd, Long deviceId) {
|
||||
public AttachVolumeAnswer(AttachVolumeCommand cmd, Long deviceId, String vdiUuid) {
|
||||
super(cmd);
|
||||
this.deviceId = deviceId;
|
||||
this.vdiUuid = vdiUuid;
|
||||
}
|
||||
|
||||
|
||||
public AttachVolumeAnswer(AttachVolumeCommand cmd) {
|
||||
super(cmd);
|
||||
this.deviceId = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deviceId
|
||||
*/
|
||||
public Long getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public String getVdiUuid() {
|
||||
return vdiUuid;
|
||||
}
|
||||
|
||||
public void setChainInfo(String chainInfo) {
|
||||
this.chainInfo = chainInfo;
|
||||
}
|
||||
|
||||
@ -19,29 +19,37 @@ package com.cloud.agent.api;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class AttachVolumeCommand extends Command {
|
||||
|
||||
boolean attach;
|
||||
String vmName;
|
||||
StoragePoolType pooltype;
|
||||
String poolUuid;
|
||||
String volumeFolder;
|
||||
String volumePath;
|
||||
String volumeName;
|
||||
Long deviceId;
|
||||
String chainInfo;
|
||||
Long bytesReadRate;
|
||||
Long bytesWriteRate;
|
||||
Long iopsReadRate;
|
||||
Long iopsWriteRate;
|
||||
private boolean attach;
|
||||
private boolean _managed;
|
||||
private String vmName;
|
||||
private StoragePoolType pooltype;
|
||||
private String volumePath;
|
||||
private String volumeName;
|
||||
private Long deviceId;
|
||||
private String chainInfo;
|
||||
private String poolUuid;
|
||||
private String _storageHost;
|
||||
private int _storagePort;
|
||||
private String _iScsiName;
|
||||
private String _chapInitiatorUsername;
|
||||
private String _chapInitiatorPassword;
|
||||
private String _chapTargetUsername;
|
||||
private String _chapTargetPassword;
|
||||
private Long bytesReadRate;
|
||||
private Long bytesWriteRate;
|
||||
private Long iopsReadRate;
|
||||
private Long iopsWriteRate;
|
||||
|
||||
protected AttachVolumeCommand() {
|
||||
}
|
||||
|
||||
public AttachVolumeCommand(boolean attach, String vmName, StoragePoolType pooltype, String volumeFolder, String volumePath, String volumeName, Long deviceId, String chainInfo) {
|
||||
public AttachVolumeCommand(boolean attach, boolean managed, String vmName,
|
||||
StoragePoolType pooltype, String volumePath, String volumeName,
|
||||
Long deviceId, String chainInfo) {
|
||||
this.attach = attach;
|
||||
this._managed = managed;
|
||||
this.vmName = vmName;
|
||||
this.pooltype = pooltype;
|
||||
this.volumeFolder = volumeFolder;
|
||||
this.volumePath = volumePath;
|
||||
this.volumeName = volumeName;
|
||||
this.deviceId = deviceId;
|
||||
@ -54,7 +62,7 @@ public class AttachVolumeCommand extends Command {
|
||||
}
|
||||
|
||||
public boolean getAttach() {
|
||||
return attach;
|
||||
return attach;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
@ -69,16 +77,12 @@ public class AttachVolumeCommand extends Command {
|
||||
this.pooltype = pooltype;
|
||||
}
|
||||
|
||||
public String getVolumeFolder() {
|
||||
return volumeFolder;
|
||||
}
|
||||
|
||||
public String getVolumePath() {
|
||||
return volumePath;
|
||||
}
|
||||
|
||||
public String getVolumeName() {
|
||||
return volumeName;
|
||||
return volumeName;
|
||||
}
|
||||
|
||||
public Long getDeviceId() {
|
||||
@ -90,17 +94,77 @@ public class AttachVolumeCommand extends Command {
|
||||
}
|
||||
|
||||
public String getPoolUuid() {
|
||||
return poolUuid;
|
||||
return poolUuid;
|
||||
}
|
||||
|
||||
public void setPoolUuid(String poolUuid) {
|
||||
this.poolUuid = poolUuid;
|
||||
this.poolUuid = poolUuid;
|
||||
}
|
||||
|
||||
public String getChainInfo() {
|
||||
return chainInfo;
|
||||
return chainInfo;
|
||||
}
|
||||
|
||||
public void setStorageHost(String storageHost) {
|
||||
_storageHost = storageHost;
|
||||
}
|
||||
|
||||
public String getStorageHost() {
|
||||
return _storageHost;
|
||||
}
|
||||
|
||||
public void setStoragePort(int storagePort) {
|
||||
_storagePort = storagePort;
|
||||
}
|
||||
|
||||
public int getStoragePort() {
|
||||
return _storagePort;
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return _managed;
|
||||
}
|
||||
|
||||
public void set_iScsiName(String iScsiName) {
|
||||
this._iScsiName = iScsiName;
|
||||
}
|
||||
|
||||
public String get_iScsiName() {
|
||||
return _iScsiName;
|
||||
}
|
||||
|
||||
public void setChapInitiatorUsername(String chapInitiatorUsername) {
|
||||
_chapInitiatorUsername = chapInitiatorUsername;
|
||||
}
|
||||
|
||||
public String getChapInitiatorUsername() {
|
||||
return _chapInitiatorUsername;
|
||||
}
|
||||
|
||||
public void setChapInitiatorPassword(String chapInitiatorPassword) {
|
||||
_chapInitiatorPassword = chapInitiatorPassword;
|
||||
}
|
||||
|
||||
public String getChapInitiatorPassword() {
|
||||
return _chapInitiatorPassword;
|
||||
}
|
||||
|
||||
public void setChapTargetUsername(String chapTargetUsername) {
|
||||
_chapTargetUsername = chapTargetUsername;
|
||||
}
|
||||
|
||||
public String getChapTargetUsername() {
|
||||
return _chapTargetUsername;
|
||||
}
|
||||
|
||||
public void setChapTargetPassword(String chapTargetPassword) {
|
||||
_chapTargetPassword = chapTargetPassword;
|
||||
}
|
||||
|
||||
public String getChapTargetPassword() {
|
||||
return _chapTargetPassword;
|
||||
}
|
||||
|
||||
public void setBytesReadRate(Long bytesReadRate) {
|
||||
this.bytesReadRate = bytesReadRate;
|
||||
}
|
||||
|
||||
@ -26,14 +26,14 @@ import com.cloud.agent.api.AttachVolumeCommand;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class AttachVolumeAnswerTest {
|
||||
AttachVolumeCommand avc = new AttachVolumeCommand(true, "vmname",
|
||||
StoragePoolType.Filesystem, "vFolder", "vPath", "vName",
|
||||
AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
|
||||
StoragePoolType.Filesystem, "vPath", "vName",
|
||||
123456789L, "chainInfo");
|
||||
AttachVolumeAnswer ava1 = new AttachVolumeAnswer(avc);
|
||||
String results = "";
|
||||
AttachVolumeAnswer ava2 = new AttachVolumeAnswer(avc, results);
|
||||
Long deviceId = 10L;
|
||||
AttachVolumeAnswer ava3 = new AttachVolumeAnswer(avc, deviceId);
|
||||
AttachVolumeAnswer ava3 = new AttachVolumeAnswer(avc, deviceId, "");
|
||||
|
||||
@Test
|
||||
public void testGetDeviceId() {
|
||||
|
||||
@ -25,8 +25,8 @@ import com.cloud.agent.api.AttachVolumeCommand;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class AttachVolumeCommandTest {
|
||||
AttachVolumeCommand avc = new AttachVolumeCommand(true, "vmname",
|
||||
StoragePoolType.Filesystem, "vFolder", "vPath", "vName",
|
||||
AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
|
||||
StoragePoolType.Filesystem, "vPath", "vName",
|
||||
123456789L, "chainInfo");
|
||||
|
||||
@Test
|
||||
@ -65,12 +65,6 @@ public class AttachVolumeCommandTest {
|
||||
assertTrue(pt.equals(StoragePoolType.Iscsi));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetVolumeFolder() {
|
||||
String vFolder = avc.getVolumeFolder();
|
||||
assertTrue(vFolder.equals("vFolder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetVolumePath() {
|
||||
String vPath = avc.getVolumePath();
|
||||
|
||||
@ -87,6 +87,11 @@ public class BackupSnapshotCommandTest {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
@Override
|
||||
public Long getCapacityIops() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getClusterId() {
|
||||
return 0L;
|
||||
|
||||
@ -125,6 +125,11 @@ public class CheckNetworkAnswerTest {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
@Override
|
||||
public Long getCapacityIops() {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
@Override
|
||||
public Long getClusterId() {
|
||||
return 0L;
|
||||
|
||||
@ -78,6 +78,10 @@ public class SnapshotCommandTest {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
public Long getClusterId() {
|
||||
return 0L;
|
||||
};
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
|
||||
public interface ChapInfo {
|
||||
String getInitiatorUsername();
|
||||
String getInitiatorSecret();
|
||||
String getTargetUsername();
|
||||
String getTargetSecret();
|
||||
}
|
||||
@ -24,17 +24,11 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.storage.command.CommandResult;
|
||||
|
||||
public interface DataStoreDriver {
|
||||
void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
|
||||
void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback);
|
||||
|
||||
void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
|
||||
boolean canCopy(DataObject srcData, DataObject destData);
|
||||
|
||||
void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
|
||||
DataTO getTO(DataObject data);
|
||||
|
||||
DataStoreTO getStoreTO(DataStore store);
|
||||
void createAsync(DataStore store, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallback<CommandResult> callback);
|
||||
void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
|
||||
boolean canCopy(DataObject srcData, DataObject destData);
|
||||
void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.storage.command.CommandResult;
|
||||
|
||||
public interface PrimaryDataStoreDriver extends DataStoreDriver {
|
||||
void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
|
||||
void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback);
|
||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo);
|
||||
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||
public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback);
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
|
||||
public class PrimaryDataStoreParameters {
|
||||
@ -30,12 +31,17 @@ public class PrimaryDataStoreParameters {
|
||||
private Map<String, String> details;
|
||||
private String tags;
|
||||
private StoragePoolType type;
|
||||
private HypervisorType hypervisorType;
|
||||
private String host;
|
||||
private String path;
|
||||
private int port;
|
||||
private String uuid;
|
||||
private String name;
|
||||
private String userInfo;
|
||||
private long capacityBytes;
|
||||
private long usedBytes;
|
||||
private boolean managed;
|
||||
private Long capacityIops;
|
||||
|
||||
/**
|
||||
* @return the userInfo
|
||||
@ -187,6 +193,30 @@ public class PrimaryDataStoreParameters {
|
||||
this.providerName = providerName;
|
||||
}
|
||||
|
||||
public void setManaged(boolean managed) {
|
||||
this.managed = managed;
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return managed;
|
||||
}
|
||||
|
||||
public void setCapacityIops(Long capacityIops) {
|
||||
this.capacityIops = capacityIops;
|
||||
}
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return capacityIops;
|
||||
}
|
||||
|
||||
public void setHypervisorType(HypervisorType hypervisorType) {
|
||||
this.hypervisorType = hypervisorType;
|
||||
}
|
||||
|
||||
public HypervisorType getHypervisorType() {
|
||||
return hypervisorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clusterId
|
||||
*/
|
||||
@ -231,4 +261,24 @@ public class PrimaryDataStoreParameters {
|
||||
public void setZoneId(Long zoneId) {
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public long getCapacityBytes()
|
||||
{
|
||||
return capacityBytes;
|
||||
}
|
||||
|
||||
public void setCapacityBytes(long capacityBytes)
|
||||
{
|
||||
this.capacityBytes = capacityBytes;
|
||||
}
|
||||
|
||||
public long getUsedBytes()
|
||||
{
|
||||
return usedBytes;
|
||||
}
|
||||
|
||||
public void setUsedBytes(long usedBytes)
|
||||
{
|
||||
this.usedBytes = usedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,8 @@ public interface VolumeService {
|
||||
}
|
||||
}
|
||||
|
||||
ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore);
|
||||
|
||||
/**
|
||||
* Creates the volume based on the given criteria
|
||||
*
|
||||
|
||||
@ -24,6 +24,14 @@ import com.cloud.agent.api.to.DiskTO;
|
||||
public final class AttachCommand extends Command implements StorageSubSystemCommand {
|
||||
private DiskTO disk;
|
||||
private String vmName;
|
||||
private String _storageHost;
|
||||
private int _storagePort;
|
||||
private boolean _managed;
|
||||
private String _iScsiName;
|
||||
private String _chapInitiatorUsername;
|
||||
private String _chapInitiatorPassword;
|
||||
private String _chapTargetUsername;
|
||||
private String _chapTargetPassword;
|
||||
|
||||
public AttachCommand(DiskTO disk, String vmName) {
|
||||
super();
|
||||
@ -52,4 +60,67 @@ public final class AttachCommand extends Command implements StorageSubSystemComm
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public void setStorageHost(String storageHost) {
|
||||
_storageHost = storageHost;
|
||||
}
|
||||
|
||||
public String getStorageHost() {
|
||||
return _storageHost;
|
||||
}
|
||||
|
||||
public void setStoragePort(int storagePort) {
|
||||
_storagePort = storagePort;
|
||||
}
|
||||
|
||||
public int getStoragePort() {
|
||||
return _storagePort;
|
||||
}
|
||||
|
||||
public void setManaged(boolean managed) {
|
||||
_managed = managed;
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return _managed;
|
||||
}
|
||||
|
||||
public void set_iScsiName(String iScsiName) {
|
||||
this._iScsiName = iScsiName;
|
||||
}
|
||||
|
||||
public String get_iScsiName() {
|
||||
return _iScsiName;
|
||||
}
|
||||
|
||||
public void setChapInitiatorUsername(String chapInitiatorUsername) {
|
||||
_chapInitiatorUsername = chapInitiatorUsername;
|
||||
}
|
||||
|
||||
public String getChapInitiatorUsername() {
|
||||
return _chapInitiatorUsername;
|
||||
}
|
||||
|
||||
public void setChapInitiatorPassword(String chapInitiatorPassword) {
|
||||
_chapInitiatorPassword = chapInitiatorPassword;
|
||||
}
|
||||
|
||||
public String getChapInitiatorPassword() {
|
||||
return _chapInitiatorPassword;
|
||||
}
|
||||
|
||||
public void setChapTargetUsername(String chapTargetUsername) {
|
||||
_chapTargetUsername = chapTargetUsername;
|
||||
}
|
||||
|
||||
public String getChapTargetUsername() {
|
||||
return _chapTargetUsername;
|
||||
}
|
||||
|
||||
public void setChapTargetPassword(String chapTargetPassword) {
|
||||
_chapTargetPassword = chapTargetPassword;
|
||||
}
|
||||
|
||||
public String getChapTargetPassword() {
|
||||
return _chapTargetPassword;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@ import com.cloud.agent.api.to.DiskTO;
|
||||
public class DettachCommand extends Command implements StorageSubSystemCommand {
|
||||
private DiskTO disk;
|
||||
private String vmName;
|
||||
private boolean _managed;
|
||||
private String _iScsiName;
|
||||
|
||||
public DettachCommand(DiskTO disk, String vmName) {
|
||||
super();
|
||||
@ -52,4 +54,19 @@ public class DettachCommand extends Command implements StorageSubSystemCommand {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public void setManaged(boolean managed) {
|
||||
_managed = managed;
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return _managed;
|
||||
}
|
||||
|
||||
public void set_iScsiName(String iScsiName) {
|
||||
_iScsiName = iScsiName;
|
||||
}
|
||||
|
||||
public String get_iScsiName() {
|
||||
return _iScsiName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +103,12 @@ public class StoragePoolVO implements StoragePool {
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private ScopeType scope;
|
||||
|
||||
@Column(name = "managed")
|
||||
private boolean managed;
|
||||
|
||||
@Column(name = "capacity_iops", updatable = true, nullable = true)
|
||||
private Long capacityIops;
|
||||
|
||||
@Column(name = "hypervisor")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private HypervisorType hypervisor;
|
||||
@ -201,8 +207,24 @@ public class StoragePoolVO implements StoragePool {
|
||||
usedBytes = available;
|
||||
}
|
||||
|
||||
public void setCapacityBytes(long capacity) {
|
||||
capacityBytes = capacity;
|
||||
public void setCapacityBytes(long capacityBytes) {
|
||||
this.capacityBytes = capacityBytes;
|
||||
}
|
||||
|
||||
public void setManaged(boolean managed) {
|
||||
this.managed = managed;
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return managed;
|
||||
}
|
||||
|
||||
public void setCapacityIops(Long capacityIops) {
|
||||
this.capacityIops = capacityIops;
|
||||
}
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return capacityIops;
|
||||
}
|
||||
|
||||
public Long getClusterId() {
|
||||
|
||||
@ -94,6 +94,15 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
@Column(name = "uuid")
|
||||
private String uuid;
|
||||
|
||||
@Column(name="customized_iops")
|
||||
private Boolean customizedIops;
|
||||
|
||||
@Column(name="min_iops")
|
||||
Long minIops;
|
||||
|
||||
@Column(name="max_iops")
|
||||
Long maxIops;
|
||||
|
||||
@Column(name = "sort_key")
|
||||
int sortKey;
|
||||
|
||||
@ -116,8 +125,8 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags,
|
||||
boolean isCustomized) {
|
||||
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
|
||||
Boolean isCustomizedIops, Long minIops, Long maxIops) {
|
||||
this.domainId = domainId;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
@ -128,6 +137,9 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
this.useLocalStorage = false;
|
||||
this.customized = isCustomized;
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
this.customizedIops = isCustomizedIops;
|
||||
this.minIops = minIops;
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
public DiskOfferingVO(String name, String displayText, boolean mirrored, String tags, boolean recreatable,
|
||||
@ -175,6 +187,36 @@ public class DiskOfferingVO implements DiskOffering {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isCustomizedIops() {
|
||||
return customizedIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomizedIops(Boolean customizedIops) {
|
||||
this.customizedIops = customizedIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueName() {
|
||||
return uniqueName;
|
||||
}
|
||||
|
||||
@ -70,6 +70,12 @@ public class VolumeVO implements Volume {
|
||||
@Column(name = "size")
|
||||
Long size;
|
||||
|
||||
@Column(name = "min_iops")
|
||||
Long minIops;
|
||||
|
||||
@Column(name = "max_iops")
|
||||
Long maxIops;
|
||||
|
||||
@Column(name = "folder")
|
||||
String folder;
|
||||
|
||||
@ -141,25 +147,32 @@ public class VolumeVO implements Volume {
|
||||
@Column(name = "display_volume", updatable = true, nullable = false)
|
||||
protected boolean displayVolume;
|
||||
|
||||
@Column(name = "iscsi_name")
|
||||
private String _iScsiName;
|
||||
|
||||
@Transient
|
||||
// @Column(name="reservation")
|
||||
String reservationId;
|
||||
|
||||
// Real Constructor
|
||||
public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size) {
|
||||
public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size,
|
||||
Long minIops, Long maxIops, String iScsiName) {
|
||||
this.volumeType = type;
|
||||
this.name = name;
|
||||
this.dataCenterId = dcId;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.size = size;
|
||||
this.minIops = minIops;
|
||||
this.maxIops = maxIops;
|
||||
this._iScsiName = iScsiName;
|
||||
this.diskOfferingId = diskOfferingId;
|
||||
this.state = State.Allocated;
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public VolumeVO(String name, Long dcId, Long podId, long accountId, long domainId, Long instanceId, String folder,
|
||||
String path, long size, Volume.Type vType) {
|
||||
public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path,
|
||||
long size, Long minIops, Long maxIops, String iScsiName, Volume.Type vType) {
|
||||
this.name = name;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
@ -167,6 +180,9 @@ public class VolumeVO implements Volume {
|
||||
this.folder = folder;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.minIops = minIops;
|
||||
this.maxIops = maxIops;
|
||||
this._iScsiName = iScsiName;
|
||||
this.podId = podId;
|
||||
this.dataCenterId = dcId;
|
||||
this.volumeType = vType;
|
||||
@ -177,11 +193,15 @@ public class VolumeVO implements Volume {
|
||||
|
||||
// Copy Constructor
|
||||
public VolumeVO(Volume that) {
|
||||
this(that.getName(), that.getDataCenterId(), that.getPodId(), that.getAccountId(), that.getDomainId(), that
|
||||
.getInstanceId(), that.getFolder(), that.getPath(), that.getSize(), that.getVolumeType());
|
||||
this(that.getName(), that.getDataCenterId(), that.getPodId(), that.getAccountId(), that.getDomainId(), that.getInstanceId(),
|
||||
that.getFolder(), that.getPath(), that.getSize(), that.getMinIops(), that.getMaxIops(),
|
||||
that.get_iScsiName(), that.getVolumeType());
|
||||
this.recreatable = that.isRecreatable();
|
||||
this.state = that.getState();
|
||||
this.size = that.getSize();
|
||||
this.minIops = that.getMinIops();
|
||||
this.maxIops = that.getMaxIops();
|
||||
this._iScsiName = that.get_iScsiName();
|
||||
this.diskOfferingId = that.getDiskOfferingId();
|
||||
this.poolId = that.getPoolId();
|
||||
this.attached = that.getAttached();
|
||||
@ -274,6 +294,24 @@ public class VolumeVO implements Volume {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstanceId() {
|
||||
return instanceId;
|
||||
@ -464,6 +502,15 @@ public class VolumeVO implements Volume {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_iScsiName() {
|
||||
return this._iScsiName;
|
||||
}
|
||||
|
||||
public void set_iScsiName(String iScsiName) {
|
||||
this._iScsiName = iScsiName;
|
||||
}
|
||||
|
||||
public boolean isDisplayVolume() {
|
||||
return displayVolume;
|
||||
}
|
||||
|
||||
@ -58,6 +58,8 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
|
||||
|
||||
List<VolumeVO> findByPoolId(long poolId);
|
||||
|
||||
List<VolumeVO> findByPoolId(long poolId, Volume.Type volumeType);
|
||||
|
||||
List<VolumeVO> findByInstanceAndDeviceId(long instanceId, long deviceId);
|
||||
|
||||
List<VolumeVO> findUsableVolumesForInstance(long instanceId);
|
||||
|
||||
@ -109,6 +109,19 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
||||
sc.setParameters("poolId", poolId);
|
||||
sc.setParameters("notDestroyed", Volume.State.Destroy);
|
||||
sc.setParameters("vType", Volume.Type.ROOT.toString());
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VolumeVO> findByPoolId(long poolId, Volume.Type volumeType) {
|
||||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("poolId", poolId);
|
||||
sc.setParameters("notDestroyed", Volume.State.Destroy);
|
||||
|
||||
if (volumeType != null) {
|
||||
sc.setParameters("vType", volumeType.toString());
|
||||
}
|
||||
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
|
||||
@ -166,7 +166,7 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
|
||||
AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().createTemplateCallback(null, null)).setContext(context);
|
||||
store.getDriver().createAsync(templateOnStore, caller);
|
||||
store.getDriver().createAsync(store, templateOnStore, caller);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -511,7 +511,7 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<TemplateApiResult>(null, to, future);
|
||||
AsyncCallbackDispatcher<TemplateServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context);
|
||||
to.getDataStore().getDriver().deleteAsync(to, caller);
|
||||
to.getDataStore().getDriver().deleteAsync(to.getDataStore(), to, caller);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ public class ImageStoreImpl implements ImageStoreEntity {
|
||||
@Override
|
||||
public boolean delete(DataObject obj) {
|
||||
AsyncCallFuture<CommandResult> future = new AsyncCallFuture<CommandResult>();
|
||||
this.driver.deleteAsync(obj, future);
|
||||
this.driver.deleteAsync(obj.getDataStore(), obj, future);
|
||||
try {
|
||||
future.get();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
@ -148,7 +148,8 @@ public class StorageAllocatorTest {
|
||||
diskOffering = diskOfferingDao.persist(diskOffering);
|
||||
diskOfferingId = diskOffering.getId();
|
||||
|
||||
volume = new VolumeVO(Volume.Type.ROOT, "volume", dcId, 1, 1, diskOffering.getId(), diskOffering.getDiskSize());
|
||||
volume = new VolumeVO(Volume.Type.ROOT, "volume", dcId, 1, 1, diskOffering.getId(), diskOffering.getDiskSize(),
|
||||
diskOffering.getMinIops(), diskOffering.getMaxIops(), "");
|
||||
volume = volumeDao.persist(volume);
|
||||
volumeId = volume.getId();
|
||||
}
|
||||
|
||||
@ -347,7 +347,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
||||
|
||||
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
||||
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, "");
|
||||
volume.setDataCenterId(this.dcId);
|
||||
volume.setPoolId(dataStoreId);
|
||||
volume = volumeDao.persist(volume);
|
||||
|
||||
@ -317,7 +317,7 @@ public class VolumeTest extends CloudStackTestNGBase {
|
||||
}
|
||||
|
||||
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, "");
|
||||
;
|
||||
volume.setPoolId(dataStoreId);
|
||||
volume = volumeDao.persist(volume);
|
||||
|
||||
@ -317,7 +317,7 @@ public class VolumeTestVmware extends CloudStackTestNGBase {
|
||||
}
|
||||
|
||||
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, "");
|
||||
;
|
||||
volume.setPoolId(dataStoreId);
|
||||
volume = volumeDao.persist(volume);
|
||||
|
||||
@ -363,7 +363,7 @@ public class volumeServiceTest extends CloudStackTestNGBase {
|
||||
}
|
||||
|
||||
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000, 0L, 0L, "");
|
||||
volume.setPoolId(dataStoreId);
|
||||
volume = volumeDao.persist(volume);
|
||||
return volume;
|
||||
|
||||
@ -355,7 +355,7 @@ public class SnapshotServiceImpl implements SnapshotService {
|
||||
AsyncCallbackDispatcher<SnapshotServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().deleteSnapshotCallback(null, null)).setContext(context);
|
||||
DataStore store = snapInfo.getDataStore();
|
||||
store.getDriver().deleteAsync(snapInfo, caller);
|
||||
store.getDriver().deleteAsync(store, snapInfo, caller);
|
||||
|
||||
SnapshotResult result = null;
|
||||
try {
|
||||
|
||||
@ -49,26 +49,38 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
||||
Volume volume = _volumeDao.findById(dskCh.getVolumeId());
|
||||
List<Volume> requestVolumes = new ArrayList<Volume>();
|
||||
requestVolumes.add(volume);
|
||||
return storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool);
|
||||
|
||||
return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) &&
|
||||
storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<StoragePool> select(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile,
|
||||
DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
|
||||
s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool");
|
||||
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
|
||||
HypervisorType hypervisor = dskCh.getHypervisorType();
|
||||
if (hypervisor != null) {
|
||||
if (hypervisor != HypervisorType.KVM && hypervisor != HypervisorType.VMware) {
|
||||
s_logger.debug("Only kvm, VMware hypervisors are enabled to support zone wide storage");
|
||||
return suitablePools;
|
||||
@Override
|
||||
protected List<StoragePool> select(DiskProfile dskCh,
|
||||
VirtualMachineProfile<? extends VirtualMachine> vmProfile,
|
||||
DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
|
||||
s_logger.debug("ZoneWideStoragePoolAllocator to find storage pool");
|
||||
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
|
||||
|
||||
List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
|
||||
|
||||
if (storagePools == null) {
|
||||
storagePools = new ArrayList<StoragePoolVO>();
|
||||
}
|
||||
|
||||
List<StoragePoolVO> anyHypervisorStoragePools = new ArrayList<StoragePoolVO>();
|
||||
|
||||
for (StoragePoolVO storagePool : storagePools) {
|
||||
if (HypervisorType.Any.equals(storagePool.getHypervisor())) {
|
||||
anyHypervisorStoragePools.add(storagePool);
|
||||
}
|
||||
}
|
||||
|
||||
List<StoragePoolVO> storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
|
||||
List<StoragePoolVO> storagePoolsByHypervisor = _storagePoolDao.findZoneWideStoragePoolsByHypervisor(plan.getDataCenterId(), dskCh.getHypervisorType());
|
||||
|
||||
storagePools.retainAll(storagePoolsByHypervisor);
|
||||
|
||||
storagePools.addAll(anyHypervisorStoragePools);
|
||||
|
||||
// add remaining pools in zone, that did not match tags, to avoid set
|
||||
List<StoragePoolVO> allPools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null);
|
||||
allPools.removeAll(storagePools);
|
||||
|
||||
@ -162,7 +162,7 @@ public class DataObjectManagerImpl implements DataObjectManager {
|
||||
AsyncCallbackDispatcher<DataObjectManagerImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().createAsynCallback(null, null)).setContext(context);
|
||||
|
||||
store.getDriver().createAsync(objInStore, caller);
|
||||
store.getDriver().createAsync(store, objInStore, caller);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -321,7 +321,7 @@ public class DataObjectManagerImpl implements DataObjectManager {
|
||||
AsyncCallbackDispatcher<DataObjectManagerImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().deleteAsynCallback(null, null)).setContext(context);
|
||||
|
||||
data.getDataStore().getDriver().deleteAsync(data, caller);
|
||||
data.getDataStore().getDriver().deleteAsync(data.getDataStore(), data, caller);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -175,6 +175,12 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCapacityIops() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getClusterId() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
@ -81,7 +81,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
CreateContext<CreateCmdResult> context = new CreateContext<CreateCmdResult>(callback, data);
|
||||
AsyncCallbackDispatcher<BaseImageStoreDriverImpl, DownloadAnswer> caller = AsyncCallbackDispatcher
|
||||
.create(this);
|
||||
@ -184,7 +184,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
|
||||
public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
|
||||
DeleteCommand cmd = new DeleteCommand(data.getTO());
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
|
||||
@ -79,6 +79,11 @@ public class PrimaryDataStoreHelper {
|
||||
dataStoreVO.setClusterId(params.getClusterId());
|
||||
dataStoreVO.setStatus(StoragePoolStatus.Initialized);
|
||||
dataStoreVO.setUserInfo(params.getUserInfo());
|
||||
dataStoreVO.setManaged(params.isManaged());
|
||||
dataStoreVO.setCapacityIops(params.getCapacityIops());
|
||||
dataStoreVO.setCapacityBytes(params.getCapacityBytes());
|
||||
dataStoreVO.setUsedBytes(params.getUsedBytes());
|
||||
dataStoreVO.setHypervisor(params.getHypervisorType());
|
||||
|
||||
Map<String, String> details = params.getDetails();
|
||||
String tags = params.getTags();
|
||||
|
||||
@ -287,6 +287,11 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
||||
return this.pdsv.getUsedBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCapacityIops() {
|
||||
return this.pdsv.getCapacityIops();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getClusterId() {
|
||||
return this.pdsv.getClusterId();
|
||||
|
||||
@ -107,6 +107,11 @@ public class VolumeObject implements VolumeInfo {
|
||||
volumeVO.setUuid(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_iScsiName() {
|
||||
return volumeVO.get_iScsiName();
|
||||
}
|
||||
|
||||
public void setSize(Long size) {
|
||||
volumeVO.setSize(size);
|
||||
}
|
||||
@ -126,6 +131,16 @@ public class VolumeObject implements VolumeInfo {
|
||||
return volumeVO.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMinIops() {
|
||||
return volumeVO.getMinIops();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getMaxIops() {
|
||||
return volumeVO.getMaxIops();
|
||||
}
|
||||
|
||||
public long getVolumeId() {
|
||||
return volumeVO.getId();
|
||||
}
|
||||
|
||||
@ -35,8 +35,11 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
|
||||
@ -143,6 +146,16 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
|
||||
}
|
||||
|
||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore) {
|
||||
DataStoreDriver dataStoreDriver = dataStore.getDriver();
|
||||
|
||||
if (dataStoreDriver instanceof PrimaryDataStoreDriver) {
|
||||
return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(volumeInfo);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore dataStore) {
|
||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
||||
@ -154,7 +167,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context);
|
||||
|
||||
dataStore.getDriver().createAsync(volumeOnStore, caller);
|
||||
dataStore.getDriver().createAsync(dataStore, volumeOnStore, caller);
|
||||
return future;
|
||||
}
|
||||
|
||||
@ -238,7 +251,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)).setContext(context);
|
||||
|
||||
volume.getDataStore().getDriver().deleteAsync(volume, caller);
|
||||
volume.getDataStore().getDriver().deleteAsync(volume.getDataStore(), volume, caller);
|
||||
return future;
|
||||
}
|
||||
|
||||
@ -935,7 +948,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
caller.setCallback(caller.getTarget().registerVolumeCallback(null, null));
|
||||
caller.setContext(context);
|
||||
|
||||
store.getDriver().createAsync(volumeOnStore, caller);
|
||||
store.getDriver().createAsync(store, volumeOnStore, caller);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
@ -2573,7 +2573,7 @@ ServerResource {
|
||||
return new AttachVolumeAnswer(cmd, e.toString());
|
||||
}
|
||||
|
||||
return new AttachVolumeAnswer(cmd, cmd.getDeviceId());
|
||||
return new AttachVolumeAnswer(cmd, cmd.getDeviceId(), cmd.getVolumePath());
|
||||
}
|
||||
|
||||
private Answer execute(ReadyCommand cmd) {
|
||||
|
||||
@ -258,7 +258,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa
|
||||
}
|
||||
txn.commit();
|
||||
|
||||
return new AttachVolumeAnswer(cmd, cmd.getDeviceId());
|
||||
return new AttachVolumeAnswer(cmd, cmd.getDeviceId(), cmd.getVolumePath());
|
||||
} catch (Exception ex) {
|
||||
txn.rollback();
|
||||
throw new CloudRuntimeException("Error when attaching volume " + cmd.getVolumeName() + " to VM "
|
||||
|
||||
@ -36,6 +36,9 @@ import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
@ -216,6 +219,8 @@ import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
||||
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
|
||||
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
|
||||
import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
|
||||
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
|
||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||
import com.cloud.hypervisor.vmware.mo.VirtualSwitchType;
|
||||
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
||||
@ -229,7 +234,6 @@ import com.cloud.network.HAProxyConfigurator;
|
||||
import com.cloud.network.LoadBalancerConfigurator;
|
||||
import com.cloud.network.Networks;
|
||||
import com.cloud.network.Networks.BroadcastDomainType;
|
||||
import com.cloud.network.Networks.IsolationType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.VmwareTrafficLabel;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
@ -272,8 +276,16 @@ import com.vmware.vim25.GuestInfo;
|
||||
import com.vmware.vim25.HostCapability;
|
||||
import com.vmware.vim25.HostFirewallInfo;
|
||||
import com.vmware.vim25.HostFirewallRuleset;
|
||||
import com.vmware.vim25.HostNetworkTrafficShapingPolicy;
|
||||
import com.vmware.vim25.HostPortGroupSpec;
|
||||
import com.vmware.vim25.HostHostBusAdapter;
|
||||
import com.vmware.vim25.HostInternetScsiTargetTransport;
|
||||
import com.vmware.vim25.HostScsiTopology;
|
||||
import com.vmware.vim25.HostInternetScsiHba;
|
||||
import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties;
|
||||
import com.vmware.vim25.HostInternetScsiHbaStaticTarget;
|
||||
import com.vmware.vim25.HostScsiDisk;
|
||||
import com.vmware.vim25.HostScsiTopologyInterface;
|
||||
import com.vmware.vim25.HostScsiTopologyLun;
|
||||
import com.vmware.vim25.HostScsiTopologyTarget;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
import com.vmware.vim25.ObjectContent;
|
||||
import com.vmware.vim25.OptionValue;
|
||||
@ -304,10 +316,6 @@ import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
|
||||
import com.vmware.vim25.VirtualMachineRuntimeInfo;
|
||||
import com.vmware.vim25.VirtualSCSISharing;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService {
|
||||
private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
|
||||
|
||||
@ -593,7 +601,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
|
||||
ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter();
|
||||
// find VM through datacenter (VM is not at the target host yet)
|
||||
VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
|
||||
if (vmMo == null) {
|
||||
@ -3244,7 +3251,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
HashMap<String, State> newStates = getVmStates();
|
||||
|
||||
List<String> requestedVmNames = cmd.getVmNames();
|
||||
List<String> vmNames = new ArrayList();
|
||||
List<String> vmNames = new ArrayList<String>();
|
||||
|
||||
if (requestedVmNames != null) {
|
||||
for (String vmName : requestedVmNames) {
|
||||
@ -3750,8 +3757,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd));
|
||||
}
|
||||
|
||||
VmwareContext context = getServiceContext();
|
||||
VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
|
||||
final String vmName = volMgr.getVmNameFromVolumeId(cmd.getVolumeId());
|
||||
|
||||
VirtualMachineMO vmMo = null;
|
||||
@ -3903,6 +3908,45 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
}
|
||||
}
|
||||
|
||||
protected ManagedObjectReference handleDatastoreAndVmdk(AttachVolumeCommand cmd) throws Exception {
|
||||
ManagedObjectReference morDs = null;
|
||||
|
||||
VmwareContext context = getServiceContext();
|
||||
VmwareHypervisorHost hyperHost = getHyperHost(context);
|
||||
|
||||
String iqn = cmd.get_iScsiName();
|
||||
|
||||
if (cmd.getAttach()) {
|
||||
morDs = createVmfsDatastore(hyperHost, iqn,
|
||||
cmd.getStorageHost(), cmd.getStoragePort(), iqn,
|
||||
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
|
||||
cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
|
||||
|
||||
DatastoreMO dsMo = new DatastoreMO(context, morDs);
|
||||
|
||||
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
|
||||
|
||||
if (!dsMo.fileExists(volumeDatastorePath)) {
|
||||
String dummyVmName = getWorkerName(context, cmd, 0);
|
||||
|
||||
VirtualMachineMO vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName);
|
||||
|
||||
if (vmMo == null) {
|
||||
throw new Exception("Unable to create a dummy VM for volume creation");
|
||||
}
|
||||
|
||||
vmMo.createDisk(volumeDatastorePath, (int)(dsMo.getSummary().getFreeSpace() / (1024L * 1024L)),
|
||||
morDs, vmMo.getScsiDeviceControllerKey());
|
||||
vmMo.detachDisk(volumeDatastorePath, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
deleteVmfsDatastore(hyperHost, iqn, cmd.getStorageHost(), cmd.getStoragePort(), iqn);
|
||||
}
|
||||
|
||||
return morDs;
|
||||
}
|
||||
|
||||
protected Answer execute(AttachVolumeCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource AttachVolumeCommand: " + _gson.toJson(cmd));
|
||||
@ -3922,7 +3966,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
|
||||
ManagedObjectReference morDs = null;
|
||||
|
||||
if (cmd.getAttach() && cmd.isManaged()) {
|
||||
morDs = handleDatastoreAndVmdk(cmd);
|
||||
}
|
||||
else {
|
||||
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
|
||||
}
|
||||
|
||||
if (morDs == null) {
|
||||
String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + cmd.getVmName();
|
||||
s_logger.error(msg);
|
||||
@ -3933,12 +3985,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
|
||||
assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
|
||||
|
||||
AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId());
|
||||
AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId(), datastoreVolumePath);
|
||||
if (cmd.getAttach()) {
|
||||
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
|
||||
} else {
|
||||
vmMo.removeAllSnapshots();
|
||||
vmMo.detachDisk(datastoreVolumePath, false);
|
||||
|
||||
if (cmd.isManaged()) {
|
||||
handleDatastoreAndVmdk(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
return answer;
|
||||
@ -3954,6 +4010,198 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
}
|
||||
}
|
||||
|
||||
private ManagedObjectReference createVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
|
||||
int storagePortNumber, String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
|
||||
VmwareContext context = getServiceContext();
|
||||
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
||||
ClusterMO cluster = new ClusterMO(context, morCluster);
|
||||
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
|
||||
|
||||
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
|
||||
|
||||
target.setAddress(storageIpAddress);
|
||||
target.setPort(storagePortNumber);
|
||||
target.setIScsiName(iqn);
|
||||
|
||||
HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
|
||||
|
||||
String strAuthType = "chapRequired";
|
||||
|
||||
auth.setChapAuthEnabled(true);
|
||||
auth.setChapInherited(false);
|
||||
auth.setChapAuthenticationType(strAuthType);
|
||||
auth.setChapName(chapName);
|
||||
auth.setChapSecret(chapSecret);
|
||||
auth.setMutualChapInherited(false);
|
||||
auth.setMutualChapAuthenticationType(strAuthType);
|
||||
auth.setMutualChapName(mutualChapName);
|
||||
auth.setMutualChapSecret(mutualChapSecret);
|
||||
|
||||
target.setAuthenticationProperties(auth);
|
||||
|
||||
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
|
||||
|
||||
lstTargets.add(target);
|
||||
|
||||
HostDatastoreSystemMO hostDatastoreSystem = null;
|
||||
HostStorageSystemMO hostStorageSystem = null;
|
||||
|
||||
final List<Thread> threads = new ArrayList<Thread>();
|
||||
final List<Exception> exceptions = new ArrayList<Exception>();
|
||||
|
||||
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
|
||||
HostMO host = new HostMO(context, hostPair.first());
|
||||
hostDatastoreSystem = host.getHostDatastoreSystemMO();
|
||||
hostStorageSystem = host.getHostStorageSystemMO();
|
||||
|
||||
boolean iScsiHbaConfigured = false;
|
||||
|
||||
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
|
||||
if (hba instanceof HostInternetScsiHba) {
|
||||
// just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
|
||||
// at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
|
||||
iScsiHbaConfigured = true;
|
||||
|
||||
final String iScsiHbaDevice = hba.getDevice();
|
||||
|
||||
final HostStorageSystemMO hss = hostStorageSystem;
|
||||
|
||||
threads.add(new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
|
||||
|
||||
hss.rescanHba(iScsiHbaDevice);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
synchronized (exceptions) {
|
||||
exceptions.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!iScsiHbaConfigured) {
|
||||
throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
|
||||
}
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
if (exceptions.size() > 0) {
|
||||
throw new Exception(exceptions.get(0).getMessage());
|
||||
}
|
||||
|
||||
ManagedObjectReference morDs = hostDatastoreSystem.findDatastore(iqn);
|
||||
|
||||
if (morDs != null) {
|
||||
return morDs;
|
||||
}
|
||||
|
||||
List<HostScsiDisk> lstHostScsiDisks = hostDatastoreSystem.queryAvailableDisksForVmfs();
|
||||
|
||||
HostScsiDisk hostScsiDisk = getHostScsiDisk(hostStorageSystem.getStorageDeviceInfo().getScsiTopology(), lstHostScsiDisks, iqn);
|
||||
|
||||
if (hostScsiDisk == null) {
|
||||
throw new Exception("A relevant SCSI disk could not be located to use to create a datastore.");
|
||||
}
|
||||
|
||||
return hostDatastoreSystem.createVmfsDatastore(datastoreName, hostScsiDisk);
|
||||
}
|
||||
|
||||
// the purpose of this method is to find the HostScsiDisk in the passed-in array that exists (if any) because
|
||||
// we added the static iqn to an iSCSI HBA
|
||||
private static HostScsiDisk getHostScsiDisk(HostScsiTopology hst, List<HostScsiDisk> lstHostScsiDisks, String iqn) {
|
||||
for (HostScsiTopologyInterface adapter : hst.getAdapter()) {
|
||||
if (adapter.getTarget() != null) {
|
||||
for (HostScsiTopologyTarget target : adapter.getTarget()) {
|
||||
if (target.getTransport() instanceof HostInternetScsiTargetTransport) {
|
||||
String iScsiName = ((HostInternetScsiTargetTransport)target.getTransport()).getIScsiName();
|
||||
|
||||
if (iqn.equals(iScsiName)) {
|
||||
for (HostScsiDisk hostScsiDisk : lstHostScsiDisks) {
|
||||
for (HostScsiTopologyLun hstl : target.getLun()) {
|
||||
if (hstl.getScsiLun().contains(hostScsiDisk.getUuid())) {
|
||||
return hostScsiDisk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void deleteVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid,
|
||||
String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
|
||||
// hyperHost.unmountDatastore(volumeUuid);
|
||||
|
||||
VmwareContext context = getServiceContext();
|
||||
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
||||
ClusterMO cluster = new ClusterMO(context, morCluster);
|
||||
List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
|
||||
|
||||
HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
|
||||
|
||||
target.setAddress(storageIpAddress);
|
||||
target.setPort(storagePortNumber);
|
||||
target.setIScsiName(iqn);
|
||||
|
||||
final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
|
||||
|
||||
lstTargets.add(target);
|
||||
|
||||
final List<Thread> threads = new ArrayList<Thread>();
|
||||
final List<Exception> exceptions = new ArrayList<Exception>();
|
||||
|
||||
for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
|
||||
final HostMO host = new HostMO(context, hostPair.first());
|
||||
final HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
|
||||
|
||||
for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
|
||||
if (hba instanceof HostInternetScsiHba) {
|
||||
final String iScsiHbaDevice = hba.getDevice();
|
||||
|
||||
Thread thread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
hostStorageSystem.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
|
||||
|
||||
hostStorageSystem.rescanHba(iScsiHbaDevice);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
exceptions.add(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
threads.add(thread);
|
||||
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
if (exceptions.size() > 0) {
|
||||
throw new Exception(exceptions.get(0).getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer execute(AttachIsoCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd));
|
||||
|
||||
@ -4172,11 +4172,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
for (VIF vif : vifs) {
|
||||
networks.add(vif.getNetwork(conn));
|
||||
}
|
||||
List<VDI> vdis = getVdis(conn, vm);
|
||||
vm.destroy(conn);
|
||||
for( VDI vdi : vdis ){
|
||||
umount(conn, vdi);
|
||||
}
|
||||
state = State.Stopped;
|
||||
SR sr = getISOSRbyVmName(conn, cmd.getVmName());
|
||||
removeSR(conn, sr);
|
||||
@ -4479,7 +4475,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
throw new CloudRuntimeException("Could not find available VIF slot in VM with name: " + vmName);
|
||||
}
|
||||
|
||||
protected VDI mount(Connection conn, StoragePoolType pooltype, String volumeFolder, String volumePath) {
|
||||
protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFolder, String volumePath) {
|
||||
return getVDIbyUuid(conn, volumePath);
|
||||
}
|
||||
|
||||
@ -5549,7 +5545,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
if (pool.getType() == StoragePoolType.NetworkFilesystem) {
|
||||
getNfsSR(conn, pool);
|
||||
} else if (pool.getType() == StoragePoolType.IscsiLUN) {
|
||||
getIscsiSR(conn, pool);
|
||||
getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null, new Boolean[1]);
|
||||
} else if (pool.getType() == StoragePoolType.PreSetup) {
|
||||
} else {
|
||||
return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
|
||||
@ -6229,7 +6225,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
|
||||
public Answer execute(ResizeVolumeCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
StorageFilerTO pool = cmd.getPool();
|
||||
String volid = cmd.getPath();
|
||||
long newSize = cmd.getNewSize();
|
||||
|
||||
@ -6367,19 +6362,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
}
|
||||
}
|
||||
|
||||
protected SR getIscsiSR(Connection conn, StorageFilerTO pool) {
|
||||
synchronized (pool.getUuid().intern()) {
|
||||
protected SR getIscsiSR(Connection conn, String srNameLabel, String target, String path,
|
||||
String chapInitiatorUsername, String chapInitiatorPassword, Boolean[] created) {
|
||||
synchronized (srNameLabel.intern()) {
|
||||
Map<String, String> deviceConfig = new HashMap<String, String>();
|
||||
try {
|
||||
String target = pool.getHost();
|
||||
String path = pool.getPath();
|
||||
if (path.endsWith("/")) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
|
||||
String tmp[] = path.split("/");
|
||||
if (tmp.length != 3) {
|
||||
String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN";
|
||||
String msg = "Wrong iscsi path " + path + " it should be /targetIQN/LUN";
|
||||
s_logger.warn(msg);
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
@ -6387,7 +6381,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
String lunid = tmp[2].trim();
|
||||
String scsiid = "";
|
||||
|
||||
Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
|
||||
Set<SR> srs = SR.getByNameLabel(conn, srNameLabel);
|
||||
for (SR sr : srs) {
|
||||
if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
|
||||
continue;
|
||||
@ -6412,19 +6406,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
}
|
||||
if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
|
||||
throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ", targetIQN:"
|
||||
+ dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + _host.uuid);
|
||||
+ dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + srNameLabel + "on host:" + _host.uuid);
|
||||
}
|
||||
}
|
||||
deviceConfig.put("target", target);
|
||||
deviceConfig.put("targetIQN", targetiqn);
|
||||
|
||||
if (StringUtils.isNotBlank(chapInitiatorUsername) &&
|
||||
StringUtils.isNotBlank(chapInitiatorPassword)) {
|
||||
deviceConfig.put("chapuser", chapInitiatorUsername);
|
||||
deviceConfig.put("chappassword", chapInitiatorPassword);
|
||||
}
|
||||
|
||||
Host host = Host.getByUuid(conn, _host.uuid);
|
||||
Map<String, String> smConfig = new HashMap<String, String>();
|
||||
String type = SRType.LVMOISCSI.toString();
|
||||
String poolId = Long.toString(pool.getId());
|
||||
SR sr = null;
|
||||
try {
|
||||
sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
|
||||
sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
|
||||
smConfig);
|
||||
} catch (XenAPIException e) {
|
||||
String errmsg = e.toString();
|
||||
@ -6463,19 +6462,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
if( result.indexOf("<UUID>") != -1) {
|
||||
pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).trim();
|
||||
}
|
||||
if( pooluuid == null || pooluuid.length() != 36) {
|
||||
sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
|
||||
|
||||
if (pooluuid == null || pooluuid.length() != 36)
|
||||
{
|
||||
sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
|
||||
smConfig);
|
||||
|
||||
created[0] = true; // note that the SR was created (as opposed to introduced)
|
||||
} else {
|
||||
sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId,
|
||||
type, "user", true, smConfig);
|
||||
Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn);
|
||||
PBD.Record rec = new PBD.Record();
|
||||
rec.deviceConfig = deviceConfig;
|
||||
rec.host = pRec.master;
|
||||
rec.SR = sr;
|
||||
PBD pbd = PBD.create(conn, rec);
|
||||
pbd.plug(conn);
|
||||
sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel,
|
||||
type, "user", true, smConfig);
|
||||
|
||||
Set<Host> setHosts = Host.getAll(conn);
|
||||
|
||||
for (Host currentHost : setHosts) {
|
||||
PBD.Record rec = new PBD.Record();
|
||||
|
||||
rec.deviceConfig = deviceConfig;
|
||||
rec.host = currentHost;
|
||||
rec.SR = sr;
|
||||
|
||||
PBD pbd = PBD.create(conn, rec);
|
||||
|
||||
pbd.plug(conn);
|
||||
}
|
||||
}
|
||||
sr.scan(conn);
|
||||
return sr;
|
||||
@ -6636,6 +6646,52 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
}
|
||||
}
|
||||
|
||||
// for about 1 GiB of physical size, about 4 MiB seems to be used for metadata
|
||||
private long getMetadata(long physicalSize) {
|
||||
return (long)(physicalSize * 0.00390625); // 1 GiB / 4 MiB = 0.00390625
|
||||
}
|
||||
|
||||
protected VDI handleSrAndVdiAttach(String iqn, String storageHostName,
|
||||
String chapInitiatorName, String chapInitiatorPassword) throws Exception {
|
||||
VDI vdi = null;
|
||||
|
||||
Connection conn = getConnection();
|
||||
|
||||
Boolean[] created = { false };
|
||||
|
||||
SR sr = getIscsiSR(conn, iqn,
|
||||
storageHostName, iqn,
|
||||
chapInitiatorName, chapInitiatorPassword, created);
|
||||
|
||||
// if created[0] is true, this means the SR was actually created...as opposed to introduced
|
||||
if (created[0]) {
|
||||
VDI.Record vdir = new VDI.Record();
|
||||
|
||||
vdir.nameLabel = iqn;
|
||||
vdir.SR = sr;
|
||||
vdir.type = Types.VdiType.USER;
|
||||
vdir.virtualSize = sr.getPhysicalSize(conn) - sr.getPhysicalUtilisation(conn) - getMetadata(sr.getPhysicalSize(conn));
|
||||
|
||||
if (vdir.virtualSize < 0) {
|
||||
throw new Exception("VDI virtual size cannot be less than 0.");
|
||||
}
|
||||
|
||||
vdi = VDI.create(conn, vdir);
|
||||
}
|
||||
else {
|
||||
vdi = sr.getVDIs(conn).iterator().next();
|
||||
}
|
||||
|
||||
return vdi;
|
||||
}
|
||||
|
||||
protected void handleSrAndVdiDetach(String iqn) throws Exception {
|
||||
Connection conn = getConnection();
|
||||
|
||||
SR sr = getStorageRepository(conn, iqn);
|
||||
|
||||
removeSR(conn, sr);
|
||||
}
|
||||
|
||||
protected AttachVolumeAnswer execute(final AttachVolumeCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
@ -6652,7 +6708,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
|
||||
try {
|
||||
// Look up the VDI
|
||||
VDI vdi = mount(conn, cmd.getPooltype(), cmd.getVolumeFolder(),cmd.getVolumePath());
|
||||
VDI vdi = null;
|
||||
|
||||
if (cmd.getAttach() && cmd.isManaged()) {
|
||||
vdi = handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
|
||||
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
|
||||
}
|
||||
else {
|
||||
vdi = getVDIbyUuid(conn, cmd.getVolumePath());
|
||||
}
|
||||
|
||||
// Look up the VM
|
||||
VM vm = getVM(conn, vmName);
|
||||
/* For HVM guest, if no pv driver installed, no attach/detach */
|
||||
@ -6704,7 +6769,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
// Update the VDI's label to include the VM name
|
||||
vdi.setNameLabel(conn, vmName + "-DATA");
|
||||
|
||||
return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber));
|
||||
return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber), vdi.getUuid(conn));
|
||||
} else {
|
||||
// Look up all VBDs for this VDI
|
||||
Set<VBD> vbds = vdi.getVBDs(conn);
|
||||
@ -6723,7 +6788,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
// Update the VDI's label to be "detached"
|
||||
vdi.setNameLabel(conn, "detached");
|
||||
|
||||
umount(conn, vdi);
|
||||
if (cmd.isManaged()) {
|
||||
handleSrAndVdiDetach(cmd.get_iScsiName());
|
||||
}
|
||||
|
||||
return new AttachVolumeAnswer(cmd);
|
||||
}
|
||||
@ -7606,30 +7673,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
}
|
||||
}
|
||||
|
||||
protected SR getStorageRepository(Connection conn, String uuid) {
|
||||
protected SR getStorageRepository(Connection conn, String srNameLabel) {
|
||||
Set<SR> srs;
|
||||
try {
|
||||
srs = SR.getByNameLabel(conn, uuid);
|
||||
srs = SR.getByNameLabel(conn, srNameLabel);
|
||||
} catch (XenAPIException e) {
|
||||
throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.toString(), e);
|
||||
throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.toString(), e);
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.getMessage(), e);
|
||||
throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (srs.size() > 1) {
|
||||
throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + uuid);
|
||||
throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + srNameLabel);
|
||||
} else if (srs.size() == 1) {
|
||||
SR sr = srs.iterator().next();
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("SR retrieved for " + uuid);
|
||||
s_logger.debug("SR retrieved for " + srNameLabel);
|
||||
}
|
||||
|
||||
if (checkSR(conn, sr)) {
|
||||
return sr;
|
||||
}
|
||||
throw new CloudRuntimeException("SR check failed for storage pool: " + uuid + "on host:" + _host.uuid);
|
||||
throw new CloudRuntimeException("SR check failed for storage pool: " + srNameLabel + "on host:" + _host.uuid);
|
||||
} else {
|
||||
throw new CloudRuntimeException("Can not see storage pool: " + uuid + " from on host:" + _host.uuid);
|
||||
throw new CloudRuntimeException("Can not see storage pool: " + srNameLabel + " from on host:" + _host.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,6 @@ import org.apache.xmlrpc.XmlRpcException;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
||||
import com.cloud.agent.api.to.DataObjectType;
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
import com.cloud.agent.api.to.DataTO;
|
||||
@ -171,7 +170,16 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
||||
try {
|
||||
Connection conn = this.hypervisorResource.getConnection();
|
||||
// Look up the VDI
|
||||
VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
|
||||
VDI vdi = null;
|
||||
|
||||
if (cmd.isManaged()) {
|
||||
vdi = this.hypervisorResource.handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
|
||||
cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
|
||||
}
|
||||
else {
|
||||
vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
|
||||
}
|
||||
|
||||
// Look up the VM
|
||||
VM vm = this.hypervisorResource.getVM(conn, vmName);
|
||||
/* For HVM guest, if no pv driver installed, no attach/detach */
|
||||
@ -223,7 +231,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
||||
|
||||
// Update the VDI's label to include the VM name
|
||||
vdi.setNameLabel(conn, vmName + "-DATA");
|
||||
DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), disk.getType());
|
||||
DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType());
|
||||
return new AttachAnswer(newDisk);
|
||||
|
||||
} catch (XenAPIException e) {
|
||||
@ -350,6 +358,10 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
||||
|
||||
this.hypervisorResource.umount(conn, vdi);
|
||||
|
||||
if (cmd.isManaged()) {
|
||||
this.hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName());
|
||||
}
|
||||
|
||||
return new DettachAnswer(disk);
|
||||
} catch(Exception e) {
|
||||
s_logger.warn("Failed dettach volume: " + data.getPath());
|
||||
|
||||
@ -95,7 +95,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
String errMsg = null;
|
||||
Answer answer = null;
|
||||
if (data.getType() == DataObjectType.VOLUME) {
|
||||
@ -118,7 +123,7 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
|
||||
public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
|
||||
DeleteCommand cmd = new DeleteCommand(data.getTO());
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
|
||||
@ -54,6 +54,11 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class CreateVolumeContext<T> extends AsyncRpcConext<T> {
|
||||
private final DataObject volume;
|
||||
public CreateVolumeContext(AsyncCompletionCallback<T> callback, DataObject volume) {
|
||||
@ -77,7 +82,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAsync(DataObject vo, AsyncCompletionCallback<CommandResult> callback) {
|
||||
public void deleteAsync(DataStore dataStore, DataObject vo, AsyncCompletionCallback<CommandResult> callback) {
|
||||
/*
|
||||
* DeleteCommand cmd = new DeleteCommand(vo.getUri());
|
||||
*
|
||||
@ -146,7 +151,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void createAsync(DataObject vol, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
public void createAsync(DataStore dataStore, DataObject vol, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
EndPoint ep = selector.select(vol);
|
||||
CreateObjectCommand createCmd = new CreateObjectCommand(null);
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cloud-plugin-storage-volume-solidfire</artifactId>
|
||||
<name>Apache CloudStack Plugin - Storage Volume solidfire</name>
|
||||
<name>Apache CloudStack Plugin - Storage Volume SolidFire Provider</name>
|
||||
<parent>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloudstack-plugins</artifactId>
|
||||
@ -31,6 +31,11 @@
|
||||
<version>${cs.mysql.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${cs.gson.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
|
||||
@ -16,13 +16,46 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.storage.datastore.driver;
|
||||
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
import com.cloud.agent.api.to.DataTO;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.*;
|
||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.storage.command.CommandResult;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.to.DataObjectType;
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
import com.cloud.agent.api.to.DataTO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.AccountDetailsDao;
|
||||
import com.cloud.user.AccountDetailVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
|
||||
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
private static final Logger s_logger = Logger.getLogger(SolidfirePrimaryDataStoreDriver.class);
|
||||
|
||||
@Inject private PrimaryDataStoreDao _storagePoolDao;
|
||||
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||
@Inject private VolumeDao _volumeDao;
|
||||
@Inject private VolumeDetailsDao _volumeDetailsDao;
|
||||
@Inject private DataCenterDao _zoneDao;
|
||||
@Inject private AccountDao _accountDao;
|
||||
@Inject private AccountDetailsDao _accountDetailsDao;
|
||||
|
||||
@Override
|
||||
public DataTO getTO(DataObject data) {
|
||||
@ -34,12 +67,450 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
private static class SolidFireConnection {
|
||||
private final String _managementVip;
|
||||
private final int _managementPort;
|
||||
private final String _clusterAdminUsername;
|
||||
private final String _clusterAdminPassword;
|
||||
|
||||
public SolidFireConnection(String managementVip, int managementPort,
|
||||
String clusterAdminUsername, String clusterAdminPassword) {
|
||||
_managementVip = managementVip;
|
||||
_managementPort = managementPort;
|
||||
_clusterAdminUsername = clusterAdminUsername;
|
||||
_clusterAdminPassword = clusterAdminPassword;
|
||||
}
|
||||
|
||||
public String getManagementVip() {
|
||||
return _managementVip;
|
||||
}
|
||||
|
||||
public int getManagementPort() {
|
||||
return _managementPort;
|
||||
}
|
||||
|
||||
public String getClusterAdminUsername() {
|
||||
return _clusterAdminUsername;
|
||||
}
|
||||
|
||||
public String getClusterAdminPassword() {
|
||||
return _clusterAdminPassword;
|
||||
}
|
||||
}
|
||||
|
||||
private SolidFireConnection getSolidFireConnection(long storagePoolId) {
|
||||
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP);
|
||||
|
||||
String mVip = storagePoolDetail.getValue();
|
||||
|
||||
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT);
|
||||
|
||||
int mPort = Integer.parseInt(storagePoolDetail.getValue());
|
||||
|
||||
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME);
|
||||
|
||||
String clusterAdminUsername = storagePoolDetail.getValue();
|
||||
|
||||
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD);
|
||||
|
||||
String clusterAdminPassword = storagePoolDetail.getValue();
|
||||
|
||||
return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
|
||||
}
|
||||
|
||||
private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName,
|
||||
SolidFireConnection sfConnection) {
|
||||
try {
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort,
|
||||
clusterAdminUsername, clusterAdminPassword, sfAccountName);
|
||||
|
||||
return SolidFireUtil.getSolidFireAccountById(mVip, mPort,
|
||||
clusterAdminUsername, clusterAdminPassword, accountNumber);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
|
||||
AccountDetailVO accountDetails = new AccountDetailVO(csAccountId,
|
||||
SolidFireUtil.ACCOUNT_ID,
|
||||
String.valueOf(sfAccount.getId()));
|
||||
|
||||
_accountDetailsDao.persist(accountDetails);
|
||||
|
||||
accountDetails = new AccountDetailVO(csAccountId,
|
||||
SolidFireUtil.CHAP_INITIATOR_USERNAME,
|
||||
String.valueOf(sfAccount.getName()));
|
||||
|
||||
_accountDetailsDao.persist(accountDetails);
|
||||
|
||||
accountDetails = new AccountDetailVO(csAccountId,
|
||||
SolidFireUtil.CHAP_INITIATOR_SECRET,
|
||||
String.valueOf(sfAccount.getInitiatorSecret()));
|
||||
|
||||
_accountDetailsDao.persist(accountDetails);
|
||||
|
||||
accountDetails = new AccountDetailVO(csAccountId,
|
||||
SolidFireUtil.CHAP_TARGET_USERNAME,
|
||||
sfAccount.getName());
|
||||
|
||||
_accountDetailsDao.persist(accountDetails);
|
||||
|
||||
accountDetails = new AccountDetailVO(csAccountId,
|
||||
SolidFireUtil.CHAP_TARGET_SECRET,
|
||||
sfAccount.getTargetSecret());
|
||||
|
||||
_accountDetailsDao.persist(accountDetails);
|
||||
}
|
||||
|
||||
private class ChapInfoImpl implements ChapInfo {
|
||||
private final String _initiatorUsername;
|
||||
private final String _initiatorSecret;
|
||||
private final String _targetUsername;
|
||||
private final String _targetSecret;
|
||||
|
||||
public ChapInfoImpl(String initiatorUsername, String initiatorSecret,
|
||||
String targetUsername, String targetSecret) {
|
||||
_initiatorUsername = initiatorUsername;
|
||||
_initiatorSecret = initiatorSecret;
|
||||
_targetUsername = targetUsername;
|
||||
_targetSecret = targetSecret;
|
||||
}
|
||||
|
||||
public String getInitiatorUsername() {
|
||||
return _initiatorUsername;
|
||||
}
|
||||
|
||||
public String getInitiatorSecret() {
|
||||
return _initiatorSecret;
|
||||
}
|
||||
|
||||
public String getTargetUsername() {
|
||||
return _targetUsername;
|
||||
}
|
||||
|
||||
public String getTargetSecret() {
|
||||
return _targetSecret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
|
||||
public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
|
||||
long accountId = volumeInfo.getAccountId();
|
||||
|
||||
AccountDetailVO accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_USERNAME);
|
||||
|
||||
String chapInitiatorUsername = accountDetail.getValue();
|
||||
|
||||
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_SECRET);
|
||||
|
||||
String chapInitiatorSecret = accountDetail.getValue();
|
||||
|
||||
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME);
|
||||
|
||||
String chapTargetUsername = accountDetail.getValue();
|
||||
|
||||
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET);
|
||||
|
||||
String chapTargetSecret = accountDetail.getValue();
|
||||
|
||||
return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret,
|
||||
chapTargetUsername, chapTargetSecret);
|
||||
}
|
||||
|
||||
private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
|
||||
throws StorageUnavailableException, Exception
|
||||
{
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID);
|
||||
long sfAccountId = Long.parseLong(accountDetail.getValue());
|
||||
|
||||
final Iops iops;
|
||||
|
||||
Long minIops = volumeInfo.getMinIops();
|
||||
Long maxIops = volumeInfo.getMaxIops();
|
||||
|
||||
if (minIops == null || minIops <= 0 ||
|
||||
maxIops == null || maxIops <= 0) {
|
||||
iops = new Iops(100, 15000);
|
||||
}
|
||||
else {
|
||||
iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops());
|
||||
}
|
||||
|
||||
long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword,
|
||||
volumeInfo.getName(), sfAccountId, volumeInfo.getSize(), true,
|
||||
iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
|
||||
|
||||
return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
|
||||
}
|
||||
|
||||
private static class Iops
|
||||
{
|
||||
private final long _minIops;
|
||||
private final long _maxIops;
|
||||
private final long _burstIops;
|
||||
|
||||
public Iops(long minIops, long maxIops) throws Exception
|
||||
{
|
||||
if (minIops <= 0 || maxIops <= 0) {
|
||||
throw new Exception("The 'Min IOPS' and 'Max IOPS' values must be greater than 0.");
|
||||
}
|
||||
|
||||
if (minIops > maxIops) {
|
||||
throw new Exception("The 'Min IOPS' value cannot exceed the 'Max IOPS' value.");
|
||||
}
|
||||
|
||||
_minIops = minIops;
|
||||
_maxIops = maxIops;
|
||||
|
||||
_burstIops = getBurstIops(_maxIops);
|
||||
}
|
||||
|
||||
public long getMinIops()
|
||||
{
|
||||
return _minIops;
|
||||
}
|
||||
|
||||
public long getMaxIops()
|
||||
{
|
||||
return _maxIops;
|
||||
}
|
||||
|
||||
public long getBurstIops()
|
||||
{
|
||||
return _burstIops;
|
||||
}
|
||||
|
||||
private static long getBurstIops(long maxIops)
|
||||
{
|
||||
return (long)(maxIops * 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
|
||||
throws StorageUnavailableException, Exception
|
||||
{
|
||||
Long storagePoolId = volumeInfo.getPoolId();
|
||||
|
||||
if (storagePoolId == null) {
|
||||
return; // this volume was never assigned to a storage pool, so no SAN volume should exist for it
|
||||
}
|
||||
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
|
||||
|
||||
SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
|
||||
}
|
||||
|
||||
private String getSfAccountName(String csAccountUuid, long csAccountId) {
|
||||
return "CloudStack_" + csAccountUuid + "_" + getRandomNumber() + "_" + csAccountId;
|
||||
}
|
||||
|
||||
private static long getRandomNumber()
|
||||
{
|
||||
return Math.round(Math.random() * 1000000000);
|
||||
}
|
||||
|
||||
private boolean sfAccountExists(String sfAccountName, SolidFireConnection sfConnection) throws Exception {
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
try {
|
||||
SolidFireUtil.getSolidFireAccountByName(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAsync(DataStore dataStore, DataObject dataObject,
|
||||
AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
String iqn = null;
|
||||
String errMsg = null;
|
||||
|
||||
if (dataObject.getType() == DataObjectType.VOLUME) {
|
||||
try {
|
||||
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
|
||||
AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
|
||||
String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId());
|
||||
|
||||
long storagePoolId = dataStore.getId();
|
||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
||||
|
||||
if (!sfAccountExists(sfAccountName, sfConnection)) {
|
||||
SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName,
|
||||
sfConnection);
|
||||
|
||||
updateCsDbWithAccountInfo(account.getId(), sfAccount);
|
||||
}
|
||||
|
||||
SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection);
|
||||
|
||||
iqn = sfVolume.getIqn();
|
||||
|
||||
VolumeVO volume = this._volumeDao.findById(volumeInfo.getId());
|
||||
|
||||
volume.set_iScsiName(iqn);
|
||||
volume.setFolder(String.valueOf(sfVolume.getId()));
|
||||
volume.setPoolType(StoragePoolType.IscsiLUN);
|
||||
volume.setPoolId(storagePoolId);
|
||||
|
||||
_volumeDao.update(volume.getId(), volume);
|
||||
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());
|
||||
|
||||
long capacityBytes = storagePool.getCapacityBytes();
|
||||
long usedBytes = storagePool.getUsedBytes();
|
||||
|
||||
usedBytes += volumeInfo.getSize();
|
||||
|
||||
if (usedBytes > capacityBytes) {
|
||||
usedBytes = capacityBytes;
|
||||
}
|
||||
|
||||
storagePool.setUsedBytes(usedBytes);
|
||||
|
||||
_storagePoolDao.update(storagePoolId, storagePool);
|
||||
} catch (StorageUnavailableException e) {
|
||||
s_logger.error("Failed to create volume (StorageUnavailableException)", e);
|
||||
errMsg = e.toString();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Failed to create volume (Exception)", e);
|
||||
errMsg = e.toString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
|
||||
}
|
||||
|
||||
// path = iqn
|
||||
// size is pulled from DataObject instance, if errMsg is null
|
||||
CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
|
||||
|
||||
result.setResult(errMsg);
|
||||
|
||||
callback.complete(result);
|
||||
}
|
||||
|
||||
private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) throws Exception {
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
List<SolidFireUtil.SolidFireVolume> sfVolumes = SolidFireUtil.getDeletedVolumes(mVip, mPort,
|
||||
clusterAdminUsername, clusterAdminPassword);
|
||||
|
||||
// if there are volumes for this account in the trash, delete them (so the account can be deleted)
|
||||
if (sfVolumes != null) {
|
||||
for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) {
|
||||
if (sfVolume.getAccountId() == sfAccountId) {
|
||||
SolidFireUtil.purgeSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolume.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SolidFireUtil.deleteSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountId);
|
||||
}
|
||||
|
||||
private boolean sfAccountHasVolume(long sfAccountId, SolidFireConnection sfConnection) throws Exception {
|
||||
String mVip = sfConnection.getManagementVip();
|
||||
int mPort = sfConnection.getManagementPort();
|
||||
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
|
||||
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
|
||||
|
||||
List<SolidFireUtil.SolidFireVolume> sfVolumes = SolidFireUtil.getSolidFireVolumesForAccountId(mVip, mPort,
|
||||
clusterAdminUsername, clusterAdminPassword, sfAccountId);
|
||||
|
||||
if (sfVolumes != null) {
|
||||
for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) {
|
||||
if (sfVolume.isActive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAsync(DataStore dataStore, DataObject dataObject,
|
||||
AsyncCompletionCallback<CommandResult> callback) {
|
||||
String errMsg = null;
|
||||
|
||||
if (dataObject.getType() == DataObjectType.VOLUME) {
|
||||
try {
|
||||
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
|
||||
AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
|
||||
AccountDetailVO accountDetails = _accountDetailsDao.findDetail(account.getAccountId(), SolidFireUtil.ACCOUNT_ID);
|
||||
long sfAccountId = Long.parseLong(accountDetails.getValue());
|
||||
|
||||
long storagePoolId = dataStore.getId();
|
||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
||||
|
||||
deleteSolidFireVolume(volumeInfo, sfConnection);
|
||||
|
||||
_volumeDao.deleteVolumesByInstance(volumeInfo.getId());
|
||||
|
||||
if (!sfAccountHasVolume(sfAccountId, sfConnection)) {
|
||||
// delete the account from the SolidFire SAN
|
||||
deleteSolidFireAccount(sfAccountId, sfConnection);
|
||||
|
||||
// delete the info in the account_details table
|
||||
// that's related to the SolidFire account
|
||||
_accountDetailsDao.deleteDetails(account.getAccountId());
|
||||
}
|
||||
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
|
||||
|
||||
long usedBytes = storagePool.getUsedBytes();
|
||||
|
||||
usedBytes -= volumeInfo.getSize();
|
||||
|
||||
if (usedBytes < 0) {
|
||||
usedBytes = 0;
|
||||
}
|
||||
|
||||
storagePool.setUsedBytes(usedBytes);
|
||||
|
||||
_storagePoolDao.update(storagePoolId, storagePool);
|
||||
} catch (StorageUnavailableException e) {
|
||||
s_logger.error("Failed to create volume (StorageUnavailableException)", e);
|
||||
errMsg = e.toString();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Failed to create volume (Exception)", e);
|
||||
errMsg = e.toString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
|
||||
}
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
|
||||
result.setResult(errMsg);
|
||||
|
||||
callback.complete(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,5 +533,4 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
@Override
|
||||
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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 org.apache.cloudstack.storage.datastore.lifecycle;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
|
||||
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
||||
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.agent.api.StoragePoolInfo;
|
||||
import com.cloud.storage.StoragePoolAutomation;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
|
||||
@Inject PrimaryDataStoreDao storagePoolDao;
|
||||
@Inject PrimaryDataStoreHelper dataStoreHelper;
|
||||
@Inject StoragePoolAutomation storagePoolAutomation;
|
||||
@Inject StoragePoolDetailsDao storagePoolDetailsDao;
|
||||
@Inject DataCenterDao zoneDao;
|
||||
|
||||
private static final int DEFAULT_MANAGEMENT_PORT = 443;
|
||||
private static final int DEFAULT_STORAGE_PORT = 3260;
|
||||
|
||||
// invoked to add primary storage that is based on the SolidFire plug-in
|
||||
@Override
|
||||
public DataStore initialize(Map<String, Object> dsInfos) {
|
||||
String url = (String)dsInfos.get("url");
|
||||
Long zoneId = (Long)dsInfos.get("zoneId");
|
||||
String storagePoolName = (String) dsInfos.get("name");
|
||||
String providerName = (String)dsInfos.get("providerName");
|
||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
||||
String tags = (String)dsInfos.get("tags");
|
||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||
|
||||
String storageVip = getStorageVip(url);
|
||||
int storagePort = getStoragePort(url);
|
||||
|
||||
DataCenterVO zone = zoneDao.findById(zoneId);
|
||||
|
||||
String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip;
|
||||
|
||||
if (capacityBytes == null || capacityBytes <= 0) {
|
||||
throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0.");
|
||||
}
|
||||
|
||||
if (capacityIops == null || capacityIops <= 0) {
|
||||
throw new IllegalArgumentException("'capacityIops' must be present and greater than 0.");
|
||||
}
|
||||
|
||||
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
|
||||
|
||||
parameters.setHost(storageVip);
|
||||
parameters.setPort(storagePort);
|
||||
parameters.setPath(getModifiedUrl(url));
|
||||
parameters.setType(StoragePoolType.Iscsi);
|
||||
parameters.setUuid(uuid);
|
||||
parameters.setZoneId(zoneId);
|
||||
parameters.setName(storagePoolName);
|
||||
parameters.setProviderName(providerName);
|
||||
parameters.setManaged(true);
|
||||
parameters.setCapacityBytes(capacityBytes);
|
||||
parameters.setUsedBytes(0);
|
||||
parameters.setCapacityIops(capacityIops);
|
||||
parameters.setHypervisorType(HypervisorType.Any);
|
||||
parameters.setTags(tags);
|
||||
parameters.setDetails(details);
|
||||
|
||||
String managementVip = getManagementVip(url);
|
||||
int managementPort = getManagementPort(url);
|
||||
|
||||
details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
|
||||
details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
|
||||
|
||||
String clusterAdminUsername = getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
|
||||
String clusterAdminPassword = getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
|
||||
|
||||
details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
|
||||
details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
|
||||
|
||||
// this adds a row in the cloud.storage_pool table for this SolidFire cluster
|
||||
return dataStoreHelper.createPrimaryDataStore(parameters);
|
||||
}
|
||||
|
||||
// remove the clusterAdmin and password key/value pairs
|
||||
private String getModifiedUrl(String originalUrl)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
String delimiter = ";";
|
||||
|
||||
StringTokenizer st = new StringTokenizer(originalUrl, delimiter);
|
||||
|
||||
while (st.hasMoreElements()) {
|
||||
String token = st.nextElement().toString();
|
||||
|
||||
if (!token.startsWith(SolidFireUtil.CLUSTER_ADMIN_USERNAME) &&
|
||||
!token.startsWith(SolidFireUtil.CLUSTER_ADMIN_PASSWORD)) {
|
||||
sb.append(token).append(delimiter);
|
||||
}
|
||||
}
|
||||
|
||||
String modifiedUrl = sb.toString();
|
||||
int lastIndexOf = modifiedUrl.lastIndexOf(delimiter);
|
||||
|
||||
if (lastIndexOf == (modifiedUrl.length() - delimiter.length())) {
|
||||
return modifiedUrl.substring(0, lastIndexOf);
|
||||
}
|
||||
|
||||
return modifiedUrl;
|
||||
}
|
||||
|
||||
private String getManagementVip(String url)
|
||||
{
|
||||
return getVip(SolidFireUtil.MANAGEMENT_VIP, url);
|
||||
}
|
||||
|
||||
private String getStorageVip(String url)
|
||||
{
|
||||
return getVip(SolidFireUtil.STORAGE_VIP, url);
|
||||
}
|
||||
|
||||
private int getManagementPort(String url)
|
||||
{
|
||||
return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT);
|
||||
}
|
||||
|
||||
private int getStoragePort(String url)
|
||||
{
|
||||
return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT);
|
||||
}
|
||||
|
||||
private String getVip(String keyToMatch, String url)
|
||||
{
|
||||
String delimiter = ":";
|
||||
|
||||
String storageVip = getValue(keyToMatch, url);
|
||||
|
||||
int index = storageVip.indexOf(delimiter);
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
return storageVip.substring(0, index);
|
||||
}
|
||||
|
||||
return storageVip;
|
||||
}
|
||||
|
||||
private int getPort(String keyToMatch, String url, int defaultPortNumber)
|
||||
{
|
||||
String delimiter = ":";
|
||||
|
||||
String storageVip = getValue(keyToMatch, url);
|
||||
|
||||
int index = storageVip.indexOf(delimiter);
|
||||
|
||||
int portNumber = defaultPortNumber;
|
||||
|
||||
if (index != -1) {
|
||||
String port = storageVip.substring(index + delimiter.length());
|
||||
|
||||
try {
|
||||
portNumber = Integer.parseInt(port);
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new IllegalArgumentException("Invalid URL format (port is not an integer)");
|
||||
}
|
||||
}
|
||||
|
||||
return portNumber;
|
||||
}
|
||||
|
||||
private String getValue(String keyToMatch, String url)
|
||||
{
|
||||
String delimiter1 = ";";
|
||||
String delimiter2 = "=";
|
||||
|
||||
StringTokenizer st = new StringTokenizer(url, delimiter1);
|
||||
|
||||
while (st.hasMoreElements()) {
|
||||
String token = st.nextElement().toString();
|
||||
|
||||
int index = token.indexOf(delimiter2);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
throw new RuntimeException("Invalid URL format");
|
||||
}
|
||||
|
||||
String key = token.substring(0, index);
|
||||
|
||||
if (key.equalsIgnoreCase(keyToMatch)) {
|
||||
String valueToReturn = token.substring(index + delimiter2.length());
|
||||
|
||||
return valueToReturn;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Key not found in URL");
|
||||
}
|
||||
|
||||
// do not implement this method for SolidFire's plug-in
|
||||
@Override
|
||||
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
||||
return true; // should be ignored for zone-wide-only plug-ins like SolidFire's
|
||||
}
|
||||
|
||||
// do not implement this method for SolidFire's plug-in
|
||||
@Override
|
||||
public boolean attachCluster(DataStore store, ClusterScope scope) {
|
||||
return true; // should be ignored for zone-wide-only plug-ins like SolidFire's
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
|
||||
dataStoreHelper.attachZone(dataStore);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean maintain(DataStore dataStore) {
|
||||
storagePoolAutomation.maintain(dataStore);
|
||||
dataStoreHelper.maintain(dataStore);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelMaintain(DataStore store) {
|
||||
dataStoreHelper.cancelMaintain(store);
|
||||
storagePoolAutomation.cancelMaintain(store);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// invoked to delete primary storage that is based on the SolidFire plug-in
|
||||
@Override
|
||||
public boolean deleteDataStore(DataStore store) {
|
||||
return dataStoreHelper.deletePrimaryDataStore(store);
|
||||
}
|
||||
}
|
||||
@ -1,62 +1,91 @@
|
||||
// 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.
|
||||
/*
|
||||
* 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 org.apache.cloudstack.storage.datastore.provider;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider;
|
||||
import org.apache.cloudstack.storage.datastore.driver.SolidfirePrimaryDataStoreDriver;
|
||||
import org.apache.cloudstack.storage.datastore.lifecycle.SolidFirePrimaryDataStoreLifeCycle;
|
||||
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
|
||||
@Component
|
||||
public class SolidfirePrimaryDataStoreProvider implements PrimaryDataStoreProvider {
|
||||
private final String name = "Solidfire Primary Data Store Provider";
|
||||
protected DataStoreLifeCycle lifecycle;
|
||||
protected PrimaryDataStoreDriver driver;
|
||||
protected HypervisorHostListener listener;
|
||||
|
||||
SolidfirePrimaryDataStoreProvider() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
return SolidFireUtil.PROVIDER_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreLifeCycle getDataStoreLifeCycle() {
|
||||
return null;
|
||||
return lifecycle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreDriver getDataStoreDriver() {
|
||||
return null;
|
||||
public PrimaryDataStoreDriver getDataStoreDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HypervisorHostListener getHostListener() {
|
||||
return null;
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(Map<String, Object> params) {
|
||||
return false;
|
||||
lifecycle = ComponentContext.inject(SolidFirePrimaryDataStoreLifeCycle.class);
|
||||
driver = ComponentContext.inject(SolidfirePrimaryDataStoreDriver.class);
|
||||
listener = ComponentContext.inject(new HypervisorHostListener() {
|
||||
public boolean hostConnect(long hostId, long poolId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hostDisconnected(long hostId, long poolId) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DataStoreProviderType> getTypes() {
|
||||
return null;
|
||||
}
|
||||
Set<DataStoreProviderType> types = new HashSet<DataStoreProviderType>();
|
||||
|
||||
types.add(DataStoreProviderType.PRIMARY);
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,901 @@
|
||||
package org.apache.cloudstack.storage.datastore.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.conn.BasicClientConnectionManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
public class SolidFireUtil
|
||||
{
|
||||
public static final String PROVIDER_NAME = "SolidFire";
|
||||
|
||||
public static final String MANAGEMENT_VIP = "mVip";
|
||||
public static final String STORAGE_VIP = "sVip";
|
||||
|
||||
public static final String MANAGEMENT_PORT = "mPort";
|
||||
public static final String STORAGE_PORT = "sPort";
|
||||
|
||||
public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername";
|
||||
public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword";
|
||||
|
||||
public static final String ACCOUNT_ID = "accountId";
|
||||
|
||||
public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
|
||||
public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
|
||||
|
||||
public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
|
||||
public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
|
||||
|
||||
public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||
String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e,
|
||||
long lMinIops, long lMaxIops, long lBurstIops) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e,
|
||||
lMinIops, lMaxIops, lBurstIops);
|
||||
|
||||
String strVolumeToCreateJson = gson.toJson(volumeToCreate);
|
||||
|
||||
String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
|
||||
|
||||
verifyResult(volumeCreateResult.result, strVolumeCreateResultJson, gson);
|
||||
|
||||
return volumeCreateResult.result.volumeID;
|
||||
}
|
||||
|
||||
public static void deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId);
|
||||
|
||||
String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
|
||||
|
||||
executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
}
|
||||
|
||||
public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId);
|
||||
|
||||
String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
|
||||
|
||||
executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
}
|
||||
|
||||
public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VolumeToGet volumeToGet = new VolumeToGet(lVolumeId);
|
||||
|
||||
String strVolumeToGetJson = gson.toJson(volumeToGet);
|
||||
|
||||
String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
|
||||
|
||||
verifyResult(volumeGetResult.result, strVolumeGetResultJson, gson);
|
||||
|
||||
String strVolumeName = getVolumeName(volumeGetResult, lVolumeId);
|
||||
String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId);
|
||||
long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId);
|
||||
String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId);
|
||||
|
||||
return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus);
|
||||
}
|
||||
|
||||
public static List<SolidFireVolume> getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort,
|
||||
String strSfAdmin, String strSfPassword, long lAccountId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId);
|
||||
|
||||
String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount);
|
||||
|
||||
String strVolumesGetForAccountResultJson = executeJsonRpc(strVolumesToGetForAccountJson, strSfMvip, iSfPort,
|
||||
strSfAdmin, strSfPassword);
|
||||
|
||||
VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class);
|
||||
|
||||
verifyResult(volumeGetResult.result, strVolumesGetForAccountResultJson, gson);
|
||||
|
||||
List<SolidFireVolume> sfVolumes = new ArrayList<SolidFireVolume>();
|
||||
|
||||
for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
|
||||
sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status));
|
||||
}
|
||||
|
||||
return sfVolumes;
|
||||
}
|
||||
|
||||
private static final String ACTIVE = "active";
|
||||
|
||||
public static class SolidFireVolume
|
||||
{
|
||||
private final long _id;
|
||||
private final String _name;
|
||||
private final String _iqn;
|
||||
private final long _accountId;
|
||||
private final String _status;
|
||||
|
||||
public SolidFireVolume(long id, String name, String iqn,
|
||||
long accountId, String status)
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
_iqn = "/" + iqn + "/0";
|
||||
_accountId = accountId;
|
||||
_status = status;
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public String getIqn()
|
||||
{
|
||||
return _iqn;
|
||||
}
|
||||
|
||||
public long getAccountId()
|
||||
{
|
||||
return _accountId;
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
{
|
||||
return ACTIVE.equalsIgnoreCase(_status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof SolidFireVolume)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SolidFireVolume sfv = (SolidFireVolume)obj;
|
||||
|
||||
if (_id == sfv._id && _name.equals(sfv._name) &&
|
||||
_iqn.equals(sfv._iqn) && isActive() == sfv.isActive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||
String strAccountName) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
AccountToAdd accountToAdd = new AccountToAdd(strAccountName);
|
||||
|
||||
String strAccountAddJson = gson.toJson(accountToAdd);
|
||||
|
||||
String strAccountAddResultJson = executeJsonRpc(strAccountAddJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
|
||||
|
||||
verifyResult(accountAddResult.result, strAccountAddResultJson, gson);
|
||||
|
||||
return accountAddResult.result.accountID;
|
||||
}
|
||||
|
||||
public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||
long lAccountId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
AccountToRemove accountToRemove = new AccountToRemove(lAccountId);
|
||||
|
||||
String strAccountToRemoveJson = gson.toJson(accountToRemove);
|
||||
|
||||
executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
}
|
||||
|
||||
public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||
long lSfAccountId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId);
|
||||
|
||||
String strAccountToGetByIdJson = gson.toJson(accountToGetById);
|
||||
|
||||
String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
|
||||
|
||||
verifyResult(accountGetByIdResult.result, strAccountGetByIdResultJson, gson);
|
||||
|
||||
String strSfAccountName = accountGetByIdResult.result.account.username;
|
||||
String strSfAccountInitiatorSecret = accountGetByIdResult.result.account.initiatorSecret;
|
||||
String strSfAccountTargetSecret = accountGetByIdResult.result.account.targetSecret;
|
||||
|
||||
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
||||
}
|
||||
|
||||
public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
||||
String strSfAccountName) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
AccountToGetByName accountToGetByName = new AccountToGetByName(strSfAccountName);
|
||||
|
||||
String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
|
||||
|
||||
String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
|
||||
|
||||
verifyResult(accountGetByNameResult.result, strAccountGetByNameResultJson, gson);
|
||||
|
||||
long lSfAccountId = accountGetByNameResult.result.account.accountID;
|
||||
String strSfAccountInitiatorSecret = accountGetByNameResult.result.account.initiatorSecret;
|
||||
String strSfAccountTargetSecret = accountGetByNameResult.result.account.targetSecret;
|
||||
|
||||
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
||||
}
|
||||
|
||||
public static class SolidFireAccount
|
||||
{
|
||||
private final long _id;
|
||||
private final String _name;
|
||||
private final String _initiatorSecret;
|
||||
private final String _targetSecret;
|
||||
|
||||
public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret)
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
_initiatorSecret = initiatorSecret;
|
||||
_targetSecret = targetSecret;
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public String getInitiatorSecret()
|
||||
{
|
||||
return _initiatorSecret;
|
||||
}
|
||||
|
||||
public String getTargetSecret()
|
||||
{
|
||||
return _targetSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof SolidFireAccount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SolidFireAccount sfa = (SolidFireAccount)obj;
|
||||
|
||||
if (_id == sfa._id && _name.equals(sfa._name) &&
|
||||
_initiatorSecret.equals(sfa._initiatorSecret) &&
|
||||
_targetSecret.equals(sfa._targetSecret)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes();
|
||||
|
||||
String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
|
||||
|
||||
String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort,
|
||||
strSfAdmin, strSfPassword);
|
||||
|
||||
VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
|
||||
|
||||
verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson);
|
||||
|
||||
List<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume> ();
|
||||
|
||||
for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
|
||||
deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status));
|
||||
}
|
||||
|
||||
return deletedVolumes;
|
||||
}
|
||||
|
||||
public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VagToCreate vagToCreate = new VagToCreate(strVagName);
|
||||
|
||||
String strVagCreateJson = gson.toJson(vagToCreate);
|
||||
|
||||
String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
|
||||
VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
|
||||
|
||||
verifyResult(vagCreateResult.result, strVagCreateResultJson, gson);
|
||||
|
||||
return vagCreateResult.result.volumeAccessGroupID;
|
||||
}
|
||||
|
||||
public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) throws Exception
|
||||
{
|
||||
final Gson gson = new GsonBuilder().create();
|
||||
|
||||
VagToDelete vagToDelete = new VagToDelete(lVagId);
|
||||
|
||||
String strVagToDeleteJson = gson.toJson(vagToDelete);
|
||||
|
||||
executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VolumeToCreate
|
||||
{
|
||||
private final String method = "CreateVolume";
|
||||
private final VolumeToCreateParams params;
|
||||
|
||||
private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize,
|
||||
final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
|
||||
{
|
||||
params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e,
|
||||
lMinIOPS, lMaxIOPS, lBurstIOPS);
|
||||
}
|
||||
|
||||
private static final class VolumeToCreateParams
|
||||
{
|
||||
private final String name;
|
||||
private final long accountID;
|
||||
private final long totalSize;
|
||||
private final boolean enable512e;
|
||||
private final VolumeToCreateParamsQoS qos;
|
||||
|
||||
private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize,
|
||||
final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
|
||||
{
|
||||
name = strVolumeName;
|
||||
accountID = lAccountId;
|
||||
totalSize = lTotalSize;
|
||||
enable512e = bEnable512e;
|
||||
|
||||
qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
|
||||
}
|
||||
|
||||
private static final class VolumeToCreateParamsQoS
|
||||
{
|
||||
private final long minIOPS;
|
||||
private final long maxIOPS;
|
||||
private final long burstIOPS;
|
||||
|
||||
private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
|
||||
{
|
||||
minIOPS = lMinIOPS;
|
||||
maxIOPS = lMaxIOPS;
|
||||
burstIOPS = lBurstIOPS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VolumeToDelete
|
||||
{
|
||||
private final String method = "DeleteVolume";
|
||||
private final VolumeToDeleteParams params;
|
||||
|
||||
private VolumeToDelete(final long lVolumeId)
|
||||
{
|
||||
params = new VolumeToDeleteParams(lVolumeId);
|
||||
}
|
||||
|
||||
private static final class VolumeToDeleteParams
|
||||
{
|
||||
private long volumeID;
|
||||
|
||||
private VolumeToDeleteParams(final long lVolumeId)
|
||||
{
|
||||
volumeID = lVolumeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class ListDeletedVolumes
|
||||
{
|
||||
private final String method = "ListDeletedVolumes";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VolumeToPurge
|
||||
{
|
||||
private final String method = "PurgeDeletedVolume";
|
||||
private final VolumeToPurgeParams params;
|
||||
|
||||
private VolumeToPurge(final long lVolumeId)
|
||||
{
|
||||
params = new VolumeToPurgeParams(lVolumeId);
|
||||
}
|
||||
|
||||
private static final class VolumeToPurgeParams
|
||||
{
|
||||
private long volumeID;
|
||||
|
||||
private VolumeToPurgeParams(final long lVolumeId)
|
||||
{
|
||||
volumeID = lVolumeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VolumeToGet
|
||||
{
|
||||
private final String method = "ListActiveVolumes";
|
||||
private final VolumeToGetParams params;
|
||||
|
||||
private VolumeToGet(final long lVolumeId)
|
||||
{
|
||||
params = new VolumeToGetParams(lVolumeId);
|
||||
}
|
||||
|
||||
private static final class VolumeToGetParams
|
||||
{
|
||||
private final long startVolumeID;
|
||||
private final long limit = 1;
|
||||
|
||||
private VolumeToGetParams(final long lVolumeId)
|
||||
{
|
||||
startVolumeID = lVolumeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VolumesToGetForAccount
|
||||
{
|
||||
private final String method = "ListVolumesForAccount";
|
||||
private final VolumesToGetForAccountParams params;
|
||||
|
||||
private VolumesToGetForAccount(final long lAccountId)
|
||||
{
|
||||
params = new VolumesToGetForAccountParams(lAccountId);
|
||||
}
|
||||
|
||||
private static final class VolumesToGetForAccountParams
|
||||
{
|
||||
private final long accountID;
|
||||
|
||||
private VolumesToGetForAccountParams(final long lAccountId)
|
||||
{
|
||||
accountID = lAccountId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class AccountToAdd
|
||||
{
|
||||
private final String method = "AddAccount";
|
||||
private final AccountToAddParams params;
|
||||
|
||||
private AccountToAdd(final String strAccountName)
|
||||
{
|
||||
params = new AccountToAddParams(strAccountName);
|
||||
}
|
||||
|
||||
private static final class AccountToAddParams
|
||||
{
|
||||
private final String username;
|
||||
|
||||
private AccountToAddParams(final String strAccountName)
|
||||
{
|
||||
username = strAccountName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class AccountToRemove
|
||||
{
|
||||
private final String method = "RemoveAccount";
|
||||
private final AccountToRemoveParams params;
|
||||
|
||||
private AccountToRemove(final long lAccountId)
|
||||
{
|
||||
params = new AccountToRemoveParams(lAccountId);
|
||||
}
|
||||
|
||||
private static final class AccountToRemoveParams
|
||||
{
|
||||
private long accountID;
|
||||
|
||||
private AccountToRemoveParams(final long lAccountId)
|
||||
{
|
||||
accountID = lAccountId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class AccountToGetById
|
||||
{
|
||||
private final String method = "GetAccountByID";
|
||||
private final AccountToGetByIdParams params;
|
||||
|
||||
private AccountToGetById(final long lAccountId)
|
||||
{
|
||||
params = new AccountToGetByIdParams(lAccountId);
|
||||
}
|
||||
|
||||
private static final class AccountToGetByIdParams
|
||||
{
|
||||
private final long accountID;
|
||||
|
||||
private AccountToGetByIdParams(final long lAccountId)
|
||||
{
|
||||
accountID = lAccountId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class AccountToGetByName
|
||||
{
|
||||
private final String method = "GetAccountName";
|
||||
private final AccountToGetByNameParams params;
|
||||
|
||||
private AccountToGetByName(final String strUsername)
|
||||
{
|
||||
params = new AccountToGetByNameParams(strUsername);
|
||||
}
|
||||
|
||||
private static final class AccountToGetByNameParams
|
||||
{
|
||||
private final String username;
|
||||
|
||||
private AccountToGetByNameParams(final String strUsername)
|
||||
{
|
||||
username = strUsername;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VagToCreate
|
||||
{
|
||||
private final String method = "CreateVolumeAccessGroup";
|
||||
private final VagToCreateParams params;
|
||||
|
||||
private VagToCreate(final String strVagName)
|
||||
{
|
||||
params = new VagToCreateParams(strVagName);
|
||||
}
|
||||
|
||||
private static final class VagToCreateParams
|
||||
{
|
||||
private final String name;
|
||||
|
||||
private VagToCreateParams(final String strVagName)
|
||||
{
|
||||
name = strVagName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class VagToDelete
|
||||
{
|
||||
private final String method = "DeleteVolumeAccessGroup";
|
||||
private final VagToDeleteParams params;
|
||||
|
||||
private VagToDelete(final long lVagId)
|
||||
{
|
||||
params = new VagToDeleteParams(lVagId);
|
||||
}
|
||||
|
||||
private static final class VagToDeleteParams
|
||||
{
|
||||
private long volumeAccessGroupID;
|
||||
|
||||
private VagToDeleteParams(final long lVagId)
|
||||
{
|
||||
volumeAccessGroupID = lVagId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class VolumeCreateResult
|
||||
{
|
||||
private Result result;
|
||||
|
||||
private static final class Result
|
||||
{
|
||||
private long volumeID;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class VolumeGetResult
|
||||
{
|
||||
private Result result;
|
||||
|
||||
private static final class Result
|
||||
{
|
||||
private Volume[] volumes;
|
||||
|
||||
private static final class Volume
|
||||
{
|
||||
private long volumeID;
|
||||
private String name;
|
||||
private String iqn;
|
||||
private long accountID;
|
||||
private String status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AccountAddResult
|
||||
{
|
||||
private Result result;
|
||||
|
||||
private static final class Result
|
||||
{
|
||||
private long accountID;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AccountGetResult
|
||||
{
|
||||
private Result result;
|
||||
|
||||
private static final class Result
|
||||
{
|
||||
private Account account;
|
||||
|
||||
private static final class Account
|
||||
{
|
||||
private long accountID;
|
||||
private String username;
|
||||
private String initiatorSecret;
|
||||
private String targetSecret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class VagCreateResult
|
||||
{
|
||||
private Result result;
|
||||
|
||||
private static final class Result
|
||||
{
|
||||
private long volumeAccessGroupID;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JsonError
|
||||
{
|
||||
private Error error;
|
||||
|
||||
private static final class Error
|
||||
{
|
||||
private String message;
|
||||
}
|
||||
}
|
||||
|
||||
private static DefaultHttpClient getHttpClient(int iPort) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||
X509TrustManager tm = new X509TrustManager() {
|
||||
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
sslContext.init(null, new TrustManager[] { tm }, new SecureRandom());
|
||||
|
||||
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
|
||||
registry.register(new Scheme("https", iPort, socketFactory));
|
||||
|
||||
BasicClientConnectionManager mgr = new BasicClientConnectionManager(registry);
|
||||
DefaultHttpClient client = new DefaultHttpClient();
|
||||
|
||||
return new DefaultHttpClient(mgr, client.getParams());
|
||||
}
|
||||
|
||||
private static String executeJsonRpc(String strJsonToExecute, String strMvip, int iPort,
|
||||
String strAdmin, String strPassword) throws Exception
|
||||
{
|
||||
DefaultHttpClient httpClient = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
StringEntity input = new StringEntity(strJsonToExecute);
|
||||
|
||||
input.setContentType("application/json");
|
||||
|
||||
httpClient = getHttpClient(iPort);
|
||||
|
||||
URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/1.0");
|
||||
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
|
||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
|
||||
|
||||
httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
|
||||
|
||||
HttpPost postRequest = new HttpPost(uri);
|
||||
|
||||
postRequest.setEntity(input);
|
||||
|
||||
HttpResponse response = httpClient.execute(postRequest);
|
||||
|
||||
if (!isSuccess(response.getStatusLine().getStatusCode()))
|
||||
{
|
||||
throw new RuntimeException("Failed on JSON-RPC API call. HTTP error code = " + response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
|
||||
|
||||
String strOutput;
|
||||
|
||||
|
||||
while ((strOutput = br.readLine()) != null)
|
||||
{
|
||||
sb.append(strOutput);
|
||||
}
|
||||
} finally {
|
||||
if (httpClient != null) {
|
||||
try {
|
||||
httpClient.getConnectionManager().shutdown();
|
||||
} catch (Throwable t) {}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean isSuccess(int iCode) {
|
||||
return iCode >= 200 && iCode < 300;
|
||||
}
|
||||
|
||||
private static void verifyResult(Object obj, String strJson, Gson gson) throws IllegalStateException
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
JsonError jsonError = gson.fromJson(strJson, JsonError.class);
|
||||
|
||||
if (jsonError != null)
|
||||
{
|
||||
throw new IllegalStateException(jsonError.error.message);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Problem with the following JSON: " + strJson);
|
||||
}
|
||||
|
||||
private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].name;
|
||||
}
|
||||
|
||||
throw new Exception("Could not determine the name of the volume, " +
|
||||
"but the volume was created with an ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].iqn;
|
||||
}
|
||||
|
||||
throw new Exception("Could not determine the IQN of the volume, " +
|
||||
"but the volume was created with an ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].accountID;
|
||||
}
|
||||
|
||||
throw new Exception("Could not determine the volume's account ID, " +
|
||||
"but the volume was created with an ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId) throws Exception
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].status;
|
||||
}
|
||||
|
||||
throw new Exception("Could not determine the status of the volume, " +
|
||||
"but the volume was created with an ID of " + lVolumeId + ".");
|
||||
}
|
||||
}
|
||||
@ -67,6 +67,8 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO,
|
||||
diskOfferingResponse.setDisplayText(offering.getDisplayText());
|
||||
diskOfferingResponse.setCreated(offering.getCreated());
|
||||
diskOfferingResponse.setDiskSize(offering.getDiskSize() / (1024 * 1024 * 1024));
|
||||
diskOfferingResponse.setMinIops(offering.getMinIops());
|
||||
diskOfferingResponse.setMaxIops(offering.getMaxIops());
|
||||
|
||||
diskOfferingResponse.setDomain(offering.getDomainName());
|
||||
diskOfferingResponse.setDomainId(offering.getDomainUuid());
|
||||
@ -74,6 +76,7 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO,
|
||||
|
||||
diskOfferingResponse.setTags(offering.getTags());
|
||||
diskOfferingResponse.setCustomized(offering.isCustomized());
|
||||
diskOfferingResponse.setCustomizedIops(offering.isCustomizedIops());
|
||||
diskOfferingResponse.setStorageType(offering.isUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString());
|
||||
diskOfferingResponse.setBytesReadRate(offering.getBytesReadRate());
|
||||
diskOfferingResponse.setBytesWriteRate(offering.getBytesWriteRate());
|
||||
|
||||
@ -83,6 +83,7 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
||||
long allocatedSize = pool.getUsedCapacity() + pool.getReservedCapacity();
|
||||
poolResponse.setDiskSizeTotal(pool.getCapacityBytes());
|
||||
poolResponse.setDiskSizeAllocated(allocatedSize);
|
||||
poolResponse.setCapacityIops(pool.getCapacityIops());
|
||||
|
||||
// TODO: StatsCollector does not persist data
|
||||
StorageStats stats = ApiDBUtils.getStoragePoolStatistics(pool.getId());
|
||||
@ -144,6 +145,7 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
||||
long allocatedSize = ApiDBUtils.getStorageCapacitybyPool(pool.getId(), capacityType);
|
||||
poolResponse.setDiskSizeTotal(pool.getCapacityBytes());
|
||||
poolResponse.setDiskSizeAllocated(allocatedSize);
|
||||
poolResponse.setCapacityIops(pool.getCapacityIops());
|
||||
|
||||
// TODO: StatsCollector does not persist data
|
||||
StorageStats stats = ApiDBUtils.getStoragePoolStatistics(pool.getId());
|
||||
|
||||
@ -101,6 +101,9 @@ public class VolumeJoinDaoImpl extends GenericDaoBase<VolumeJoinVO, Long> implem
|
||||
// Show the virtual size of the volume
|
||||
volResponse.setSize(volume.getSize());
|
||||
|
||||
volResponse.setMinIops(volume.getMinIops());
|
||||
volResponse.setMaxIops(volume.getMaxIops());
|
||||
|
||||
volResponse.setCreated(volume.getCreated());
|
||||
volResponse.setState(volume.getState().toString());
|
||||
if (volume.getState() == Volume.State.UploadOp) {
|
||||
|
||||
@ -61,6 +61,15 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
|
||||
@Column(name="customized")
|
||||
private boolean customized;
|
||||
|
||||
@Column(name="customized_iops")
|
||||
private Boolean customizedIops;
|
||||
|
||||
@Column(name="min_iops")
|
||||
private Long minIops;
|
||||
|
||||
@Column(name="max_iops")
|
||||
private Long maxIops;
|
||||
|
||||
@Column(name="sort_key")
|
||||
int sortKey;
|
||||
|
||||
@ -179,6 +188,30 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
|
||||
this.customized = customized;
|
||||
}
|
||||
|
||||
public Boolean isCustomizedIops() {
|
||||
return customizedIops;
|
||||
}
|
||||
|
||||
public void setCustomizedIops(Boolean customizedIops) {
|
||||
this.customizedIops = customizedIops;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
public boolean isDisplayOffering() {
|
||||
return displayOffering;
|
||||
}
|
||||
|
||||
@ -60,7 +60,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
||||
@Column(name="host_address")
|
||||
private String hostAddress;
|
||||
|
||||
|
||||
@Column(name="status")
|
||||
@Enumerated(value=EnumType.STRING)
|
||||
private StoragePoolStatus status;
|
||||
@ -109,7 +108,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
||||
@Column(name="pod_name")
|
||||
private String podName;
|
||||
|
||||
|
||||
@Column(name="tag")
|
||||
private String tag;
|
||||
|
||||
@ -119,7 +117,6 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
||||
@Column(name="disk_reserved_capacity")
|
||||
private long reservedCapacity;
|
||||
|
||||
|
||||
@Column(name="job_id")
|
||||
private Long jobId;
|
||||
|
||||
@ -133,6 +130,8 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private ScopeType scope;
|
||||
|
||||
@Column(name="capacity_iops")
|
||||
private Long capacityIops;
|
||||
|
||||
@Column(name = "hypervisor")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
@ -243,6 +242,14 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
||||
this.capacityBytes = capacityBytes;
|
||||
}
|
||||
|
||||
public Long getCapacityIops() {
|
||||
return capacityIops;
|
||||
}
|
||||
|
||||
public void setCapacityIops(Long capacityIops) {
|
||||
this.capacityIops = capacityIops;
|
||||
}
|
||||
|
||||
public long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
@ -58,6 +58,12 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity {
|
||||
@Column(name = "size")
|
||||
long size;
|
||||
|
||||
@Column(name = "min_iops")
|
||||
Long minIops;
|
||||
|
||||
@Column(name = "max_iops")
|
||||
Long maxIops;
|
||||
|
||||
@Column(name = "state")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private Volume.State state;
|
||||
@ -337,14 +343,27 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Long getMinIops() {
|
||||
return minIops;
|
||||
}
|
||||
|
||||
public void setMinIops(Long minIops) {
|
||||
this.minIops = minIops;
|
||||
}
|
||||
|
||||
public Long getMaxIops() {
|
||||
return maxIops;
|
||||
}
|
||||
|
||||
public void setMaxIops(Long maxIops) {
|
||||
this.maxIops = maxIops;
|
||||
}
|
||||
|
||||
public Volume.State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setState(Volume.State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@ -102,14 +102,18 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
|
||||
* @param isCustomized
|
||||
* @param localStorageRequired
|
||||
* @param isDisplayOfferingEnabled
|
||||
* @param isCustomizedIops (is admin allowing users to set custom iops?)
|
||||
* @param minIops
|
||||
* @param maxIops
|
||||
* @param bytesReadRate
|
||||
* @param bytesWriteRate
|
||||
* @param iopsReadRate
|
||||
* @param iopsWriteRate
|
||||
* @return newly created disk offering
|
||||
*/
|
||||
DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate);
|
||||
DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized,
|
||||
boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate);
|
||||
|
||||
/**
|
||||
* Creates a new pod
|
||||
|
||||
@ -2297,8 +2297,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
|
||||
@Override
|
||||
@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, boolean localStorageRequired, boolean isDisplayOfferingEnabled,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) {
|
||||
public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized,
|
||||
boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) {
|
||||
long diskSize = 0;// special case for custom disk offerings
|
||||
if (numGibibytes != null && (numGibibytes <= 0)) {
|
||||
throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb.");
|
||||
@ -2314,8 +2315,44 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
isCustomized = true;
|
||||
}
|
||||
|
||||
if (isCustomizedIops != null) {
|
||||
bytesReadRate = null;
|
||||
bytesWriteRate = null;
|
||||
iopsReadRate = null;
|
||||
iopsWriteRate = null;
|
||||
|
||||
if (isCustomizedIops) {
|
||||
minIops = null;
|
||||
maxIops = null;
|
||||
}
|
||||
else {
|
||||
if (minIops == null && maxIops == null) {
|
||||
minIops = 0L;
|
||||
maxIops = 0L;
|
||||
}
|
||||
else {
|
||||
if (minIops == null || minIops <= 0) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be greater than 0.");
|
||||
}
|
||||
|
||||
if (maxIops == null) {
|
||||
maxIops = 0L;
|
||||
}
|
||||
|
||||
if (minIops > maxIops) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
minIops = null;
|
||||
maxIops = null;
|
||||
}
|
||||
|
||||
tags = cleanupTags(tags);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized,
|
||||
isCustomizedIops, minIops, maxIops);
|
||||
newDiskOffering.setUseLocalStorage(localStorageRequired);
|
||||
newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled);
|
||||
|
||||
@ -2355,7 +2392,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
Long domainId = cmd.getDomainId();
|
||||
|
||||
if (!isCustomized && numGibibytes == null) {
|
||||
throw new InvalidParameterValueException("Disksize is required for non-customized disk offering");
|
||||
throw new InvalidParameterValueException("Disksize is required for a non-customized disk offering");
|
||||
}
|
||||
|
||||
boolean localStorageRequired = false;
|
||||
@ -2369,11 +2406,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
}
|
||||
|
||||
Boolean isCustomizedIops = cmd.isCustomizedIops();
|
||||
Long minIops = cmd.getMinIops();
|
||||
Long maxIops = cmd.getMaxIops();
|
||||
Long bytesReadRate = cmd.getBytesReadRate();
|
||||
Long bytesWriteRate = cmd.getBytesWriteRate();
|
||||
Long iopsReadRate = cmd.getIopsReadRate();
|
||||
Long iopsWriteRate = cmd.getIopsWriteRate();
|
||||
return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled, bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate);
|
||||
|
||||
return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized,
|
||||
localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, maxIops,
|
||||
bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -932,7 +932,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
||||
diskSize = diskSize * 1024 * 1024 * 1024;
|
||||
tags = cleanupTags(tags);
|
||||
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized);
|
||||
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized, null, null, null);
|
||||
newDiskOffering.setUniqueName("Cloud.Com-" + name);
|
||||
newDiskOffering.setSystemUse(isSystemUse);
|
||||
newDiskOffering = _diskOfferingDao.persistDeafultDiskOffering(newDiskOffering);
|
||||
|
||||
@ -99,28 +99,23 @@ public interface StorageManager extends StorageService {
|
||||
|
||||
void cleanupSecondaryStorage(boolean recurring);
|
||||
|
||||
|
||||
HypervisorType getHypervisorTypeFromFormat(ImageFormat format);
|
||||
|
||||
boolean storagePoolHasEnoughIops(List<Volume> volume, StoragePool pool);
|
||||
|
||||
boolean storagePoolHasEnoughSpace(List<Volume> volume, StoragePool pool);
|
||||
|
||||
|
||||
boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
|
||||
|
||||
StoragePool findStoragePool(DiskProfile dskCh, DataCenterVO dc,
|
||||
HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm,
|
||||
Set<StoragePool> avoid);
|
||||
|
||||
|
||||
void connectHostToSharedPool(long hostId, long poolId)
|
||||
throws StorageUnavailableException;
|
||||
|
||||
void createCapacityEntry(long poolId);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException;
|
||||
|
||||
BigDecimal getStorageOverProvisioningFactor(Long dcId);
|
||||
|
||||
@ -694,9 +694,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
throw new InvalidParameterValueException(
|
||||
"Missing parameter hypervisor. Hypervisor type is required to create zone wide primary storage.");
|
||||
}
|
||||
if (hypervisorType != HypervisorType.KVM && hypervisorType != HypervisorType.VMware) {
|
||||
if (hypervisorType != HypervisorType.KVM && hypervisorType != HypervisorType.VMware &&
|
||||
hypervisorType != HypervisorType.Any) {
|
||||
throw new InvalidParameterValueException(
|
||||
"zone wide storage pool is not suported for hypervisor type " + hypervisor);
|
||||
"zone wide storage pool is not supported for hypervisor type " + hypervisor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -734,6 +735,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
params.put("name", cmd.getStoragePoolName());
|
||||
params.put("details", details);
|
||||
params.put("providerName", storeProvider.getName());
|
||||
params.put("managed", cmd.isManaged());
|
||||
params.put("capacityBytes", cmd.getCapacityBytes());
|
||||
params.put("capacityIops", cmd.getCapacityIops());
|
||||
|
||||
DataStoreLifeCycle lifeCycle = storeProvider.getDataStoreLifeCycle();
|
||||
DataStore store = null;
|
||||
@ -1561,7 +1565,41 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool) {
|
||||
public boolean storagePoolHasEnoughIops(List<Volume> requestedVolumes,
|
||||
StoragePool pool) {
|
||||
if (requestedVolumes == null || requestedVolumes.isEmpty() || pool == null)
|
||||
return false;
|
||||
|
||||
long currentIops = 0;
|
||||
|
||||
List<VolumeVO> volumesInPool = _volumeDao.findByPoolId(pool.getId(), null);
|
||||
|
||||
for (VolumeVO volumeInPool : volumesInPool) {
|
||||
Long minIops = volumeInPool.getMinIops();
|
||||
|
||||
if (minIops != null && minIops > 0) {
|
||||
currentIops += minIops;
|
||||
}
|
||||
}
|
||||
|
||||
long requestedIops = 0;
|
||||
|
||||
for (Volume requestedVolume : requestedVolumes) {
|
||||
Long minIops = requestedVolume.getMinIops();
|
||||
|
||||
if (minIops != null && minIops > 0) {
|
||||
requestedIops += minIops;
|
||||
}
|
||||
}
|
||||
|
||||
long futureIops = currentIops + requestedIops;
|
||||
|
||||
return futureIops <= pool.getCapacityIops();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storagePoolHasEnoughSpace(List<Volume> volumes,
|
||||
StoragePool pool) {
|
||||
if (volumes == null || volumes.isEmpty())
|
||||
return false;
|
||||
|
||||
|
||||
@ -45,7 +45,6 @@ import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
public interface VolumeManager extends VolumeApiService {
|
||||
|
||||
VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
|
||||
Long destPoolClusterId, HypervisorType dataDiskHyperType)
|
||||
throws ConcurrentOperationException;
|
||||
|
||||
@ -55,6 +55,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
|
||||
@ -65,6 +66,7 @@ import org.apache.cloudstack.storage.command.AttachCommand;
|
||||
import org.apache.cloudstack.storage.command.CommandResult;
|
||||
import org.apache.cloudstack.storage.command.DettachCommand;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||
@ -227,6 +229,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
@Inject
|
||||
protected StoragePoolHostDao _storagePoolHostDao;
|
||||
@Inject
|
||||
StoragePoolDetailsDao storagePoolDetailsDao;
|
||||
@Inject
|
||||
protected AlertManager _alertMgr;
|
||||
@Inject
|
||||
protected TemplateDataStoreDao _vmTemplateStoreDao = null;
|
||||
@ -507,7 +511,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(),
|
||||
oldVol.getName(), oldVol.getDataCenterId(),
|
||||
oldVol.getDomainId(), oldVol.getAccountId(),
|
||||
oldVol.getDiskOfferingId(), oldVol.getSize());
|
||||
oldVol.getDiskOfferingId(), oldVol.getSize(),
|
||||
oldVol.getMinIops(), oldVol.getMaxIops(), oldVol.get_iScsiName());
|
||||
if (templateId != null) {
|
||||
newVol.setTemplateId(templateId);
|
||||
} else {
|
||||
@ -680,9 +685,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
pool = storageMgr.findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(),
|
||||
vm, avoidPools);
|
||||
if (pool == null) {
|
||||
s_logger.warn("Unable to find storage poll when create volume "
|
||||
s_logger.warn("Unable to find storage pool when create volume "
|
||||
+ volume.getName());
|
||||
throw new CloudRuntimeException("Unable to find storage poll when create volume" + volume.getName());
|
||||
throw new CloudRuntimeException("Unable to find storage pool when create volume" + volume.getName());
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
@ -731,8 +736,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1L, -1L, -1,
|
||||
new Long(-1), null, null, 0, Volume.Type.DATADISK);
|
||||
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1,
|
||||
new Long(-1), null, null, 0, null, null, null, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
@ -835,6 +840,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
Long diskOfferingId = null;
|
||||
DiskOfferingVO diskOffering = null;
|
||||
Long size = null;
|
||||
Long minIops = null;
|
||||
Long maxIops = null;
|
||||
// Volume VO used for extracting the source template id
|
||||
VolumeVO parentVolume = null;
|
||||
|
||||
@ -896,6 +903,37 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
size = diskOffering.getDiskSize();
|
||||
}
|
||||
|
||||
Boolean isCustomizedIops = diskOffering.isCustomizedIops();
|
||||
|
||||
if (isCustomizedIops != null) {
|
||||
if (isCustomizedIops) {
|
||||
minIops = cmd.getMinIops();
|
||||
maxIops = cmd.getMaxIops();
|
||||
|
||||
if (minIops == null && maxIops == null) {
|
||||
minIops = 0L;
|
||||
maxIops = 0L;
|
||||
}
|
||||
else {
|
||||
if (minIops == null || minIops <= 0) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be greater than 0.");
|
||||
}
|
||||
|
||||
if (maxIops == null) {
|
||||
maxIops = 0L;
|
||||
}
|
||||
|
||||
if (minIops > maxIops) {
|
||||
throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
minIops = diskOffering.getMinIops();
|
||||
maxIops = diskOffering.getMaxIops();
|
||||
}
|
||||
}
|
||||
|
||||
if (!validateVolumeSizeRange(size)) {// convert size from mb to gb
|
||||
// for validation
|
||||
throw new InvalidParameterValueException(
|
||||
@ -970,8 +1008,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1L, -1L, -1, -1,
|
||||
new Long(-1), null, null, 0, Volume.Type.DATADISK);
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1,
|
||||
new Long(-1), null, null, 0, null, null, null, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
@ -980,6 +1018,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
.getDomainId()));
|
||||
volume.setDiskOfferingId(diskOfferingId);
|
||||
volume.setSize(size);
|
||||
volume.setMinIops(minIops);
|
||||
volume.setMaxIops(maxIops);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller
|
||||
@ -1171,7 +1211,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
|
||||
|
||||
PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary);
|
||||
long currentSize = volume.getSize();
|
||||
|
||||
/*
|
||||
@ -1358,7 +1397,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
size = (size * 1024 * 1024 * 1024);
|
||||
}
|
||||
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(),
|
||||
owner.getDomainId(), owner.getId(), offering.getId(), size);
|
||||
owner.getDomainId(), owner.getId(), offering.getId(), size,
|
||||
offering.getMinIops(), offering.getMaxIops(), null);
|
||||
if (vm != null) {
|
||||
vol.setInstanceId(vm.getId());
|
||||
}
|
||||
@ -1398,7 +1438,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId());
|
||||
|
||||
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(),
|
||||
owner.getDomainId(), owner.getId(), offering.getId(), size);
|
||||
owner.getDomainId(), owner.getId(), offering.getId(), size,
|
||||
offering.getMinIops(), offering.getMaxIops(), null);
|
||||
vol.setFormat(this.getSupportedImageFormatForCluster(template.getHypervisorType()));
|
||||
if (vm != null) {
|
||||
vol.setInstanceId(vm.getId());
|
||||
@ -1542,8 +1583,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
return !storeForRootStoreScope.isSameScope(storeForDataStoreScope);
|
||||
}
|
||||
|
||||
private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volume, Long deviceId) {
|
||||
String errorMsg = "Failed to attach volume: " + volume.getName()
|
||||
private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) {
|
||||
String errorMsg = "Failed to attach volume: " + volumeToAttach.getName()
|
||||
+ " to VM: " + vm.getHostName();
|
||||
boolean sendCommand = (vm.getState() == State.Running);
|
||||
AttachAnswer answer = null;
|
||||
@ -1557,12 +1598,37 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
}
|
||||
}
|
||||
|
||||
StoragePoolVO volumeToAttachStoragePool = null;
|
||||
|
||||
if (sendCommand) {
|
||||
DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
|
||||
DiskTO disk = new DiskTO(volTO, deviceId, volume.getVolumeType());
|
||||
volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId());
|
||||
long storagePoolId = volumeToAttachStoragePool.getId();
|
||||
|
||||
DataTO volTO = volFactory.getVolume(volumeToAttach.getId()).getTO();
|
||||
DiskTO disk = new DiskTO(volTO, deviceId, null, volumeToAttach.getVolumeType());
|
||||
|
||||
AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());
|
||||
|
||||
cmd.setManaged(volumeToAttachStoragePool.isManaged());
|
||||
|
||||
cmd.setStorageHost(volumeToAttachStoragePool.getHostAddress());
|
||||
cmd.setStoragePort(volumeToAttachStoragePool.getPort());
|
||||
|
||||
cmd.set_iScsiName(volumeToAttach.get_iScsiName());
|
||||
|
||||
VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId());
|
||||
DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
|
||||
ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore);
|
||||
|
||||
if (chapInfo != null) {
|
||||
cmd.setChapInitiatorUsername(chapInfo.getInitiatorUsername());
|
||||
cmd.setChapInitiatorPassword(chapInfo.getInitiatorSecret());
|
||||
cmd.setChapTargetUsername(chapInfo.getTargetUsername());
|
||||
cmd.setChapTargetPassword(chapInfo.getTargetSecret());
|
||||
}
|
||||
|
||||
try {
|
||||
answer = (AttachAnswer) _agentMgr.send(hostId, cmd);
|
||||
answer = (AttachAnswer)_agentMgr.send(hostId, cmd);
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException(errorMsg + " due to: "
|
||||
+ e.getMessage());
|
||||
@ -1573,19 +1639,29 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
// Mark the volume as attached
|
||||
if (sendCommand) {
|
||||
DiskTO disk = answer.getDisk();
|
||||
_volsDao.attachVolume(volume.getId(), vm.getId(),
|
||||
_volsDao.attachVolume(volumeToAttach.getId(), vm.getId(),
|
||||
disk.getDiskSeq());
|
||||
|
||||
volumeToAttach = _volsDao.findById(volumeToAttach.getId());
|
||||
|
||||
if (volumeToAttachStoragePool.isManaged() &&
|
||||
volumeToAttach.getPath() == null) {
|
||||
volumeToAttach.setPath(answer.getDisk().getVdiUuid());
|
||||
|
||||
_volsDao.update(volumeToAttach.getId(), volumeToAttach);
|
||||
}
|
||||
} else {
|
||||
_volsDao.attachVolume(volume.getId(), vm.getId(), deviceId);
|
||||
_volsDao.attachVolume(volumeToAttach.getId(), vm.getId(), deviceId);
|
||||
}
|
||||
|
||||
// insert record for disk I/O statistics
|
||||
VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId());
|
||||
VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId());
|
||||
if (diskstats == null) {
|
||||
diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId());
|
||||
diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId());
|
||||
_vmDiskStatsDao.persist(diskstats);
|
||||
}
|
||||
|
||||
return _volsDao.findById(volume.getId());
|
||||
return _volsDao.findById(volumeToAttach.getId());
|
||||
} else {
|
||||
if (answer != null) {
|
||||
String details = answer.getDetails();
|
||||
@ -1912,9 +1988,17 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
Answer answer = null;
|
||||
|
||||
if (sendCommand) {
|
||||
StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
|
||||
|
||||
DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
|
||||
DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getVolumeType());
|
||||
DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), null, volume.getVolumeType());
|
||||
|
||||
DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName());
|
||||
|
||||
cmd.setManaged(volumePool.isManaged());
|
||||
|
||||
cmd.set_iScsiName(volume.get_iScsiName());
|
||||
|
||||
try {
|
||||
answer = _agentMgr.send(vm.getHostId(), cmd);
|
||||
} catch (Exception e) {
|
||||
@ -1926,6 +2010,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
if (!sendCommand || (answer != null && answer.getResult())) {
|
||||
// Mark the volume as detached
|
||||
_volsDao.detachVolume(volume.getId());
|
||||
|
||||
return _volsDao.findById(volumeId);
|
||||
} else {
|
||||
|
||||
@ -1940,11 +2025,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@DB
|
||||
protected VolumeVO switchVolume(VolumeVO existingVolume,
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm)
|
||||
@ -2232,7 +2312,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
for (VolumeVO vol : vols) {
|
||||
DataTO volTO = volFactory.getVolume(vol.getId()).getTO();
|
||||
DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), vol.getVolumeType());
|
||||
DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), null, vol.getVolumeType());
|
||||
vm.addDisk(disk);
|
||||
}
|
||||
|
||||
@ -2240,7 +2320,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
UserVmVO userVM = (UserVmVO) vm.getVirtualMachine();
|
||||
if (userVM.getIsoId() != null) {
|
||||
DataTO dataTO = tmplFactory.getTemplate(userVM.getIsoId(), DataStoreRole.Image, userVM.getDataCenterId()).getTO();
|
||||
DiskTO iso = new DiskTO(dataTO, 3L, Volume.Type.ISO);
|
||||
DiskTO iso = new DiskTO(dataTO, 3L, null, Volume.Type.ISO);
|
||||
vm.addDisk(iso);
|
||||
}
|
||||
}
|
||||
@ -2458,7 +2538,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
vol = result.first();
|
||||
}
|
||||
DataTO volumeTO = volFactory.getVolume(vol.getId()).getTO();
|
||||
DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), vol.getVolumeType());
|
||||
DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), null, vol.getVolumeType());
|
||||
vm.addDisk(disk);
|
||||
}
|
||||
}
|
||||
@ -2745,7 +2825,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
@Override
|
||||
public String getVmNameFromVolumeId(long volumeId) {
|
||||
Long instanceId;
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
return getVmNameOnVolume(volume);
|
||||
}
|
||||
|
||||
@ -1023,7 +1023,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||
}
|
||||
|
||||
DataTO isoTO = tmplt.getTO();
|
||||
DiskTO disk = new DiskTO(isoTO, null, Volume.Type.ISO);
|
||||
DiskTO disk = new DiskTO(isoTO, null, null, Volume.Type.ISO);
|
||||
Command cmd = null;
|
||||
if (attach) {
|
||||
cmd = new AttachCommand(disk, vmName);
|
||||
|
||||
@ -979,7 +979,7 @@ public class DatabaseConfig {
|
||||
newTags.delete(newTags.length() - 1, newTags.length());
|
||||
tags = newTags.toString();
|
||||
}
|
||||
DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, diskSpace , tags, false);
|
||||
DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, diskSpace, tags, false, null, null, null);
|
||||
diskOffering.setUseLocalStorage(local);
|
||||
|
||||
Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate"));
|
||||
|
||||
@ -2910,12 +2910,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
||||
|
||||
TemplateObjectTO iso = (TemplateObjectTO)template.getTO();
|
||||
iso.setGuestOsType(displayName);
|
||||
DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO);
|
||||
DiskTO disk = new DiskTO(iso, 3L, null, Volume.Type.ISO);
|
||||
profile.addDisk(disk);
|
||||
} else {
|
||||
TemplateObjectTO iso = new TemplateObjectTO();
|
||||
iso.setFormat(ImageFormat.ISO);
|
||||
DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO);
|
||||
DiskTO disk = new DiskTO(iso, 3L, null, Volume.Type.ISO);
|
||||
profile.addDisk(disk);
|
||||
}
|
||||
|
||||
|
||||
@ -655,8 +655,9 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
|
||||
* @see com.cloud.configuration.ConfigurationManager#createDiskOffering(java.lang.Long, java.lang.String, java.lang.String, java.lang.Long, java.lang.String, boolean, boolean, boolean)
|
||||
*/
|
||||
@Override
|
||||
public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) {
|
||||
public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized,
|
||||
boolean localStorageRequired, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops,
|
||||
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -429,6 +429,20 @@ ALTER TABLE `cloud`.`nics` ADD COLUMN `display_nic` tinyint(1) NOT NULL DEFAULT
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `display_offering` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should disk offering be displayed to the end user';
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `customized_iops` tinyint(1) unsigned COMMENT 'Should customized IOPS be displayed to the end user';
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `min_iops` bigint(20) unsigned COMMENT 'Minimum IOPS';
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `max_iops` bigint(20) unsigned COMMENT 'Maximum IOPS';
|
||||
|
||||
ALTER TABLE `cloud`.`volumes` ADD COLUMN `min_iops` bigint(20) unsigned COMMENT 'Minimum IOPS';
|
||||
|
||||
ALTER TABLE `cloud`.`volumes` ADD COLUMN `max_iops` bigint(20) unsigned COMMENT 'Maximum IOPS';
|
||||
|
||||
ALTER TABLE `cloud`.`storage_pool` ADD COLUMN `managed` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Should CloudStack manage this storage';
|
||||
|
||||
ALTER TABLE `cloud`.`storage_pool` ADD COLUMN `capacity_iops` bigint(20) unsigned DEFAULT NULL COMMENT 'IOPS CloudStack can provision from this storage pool';
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `bytes_read_rate` bigint(20);
|
||||
|
||||
ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `bytes_write_rate` bigint(20);
|
||||
@ -871,6 +885,8 @@ CREATE VIEW `cloud`.`volume_view` AS
|
||||
volumes.device_id,
|
||||
volumes.volume_type,
|
||||
volumes.size,
|
||||
volumes.min_iops,
|
||||
volumes.max_iops,
|
||||
volumes.created,
|
||||
volumes.state,
|
||||
volumes.attached,
|
||||
@ -981,6 +997,7 @@ CREATE VIEW `cloud`.`storage_pool_view` AS
|
||||
storage_pool.created,
|
||||
storage_pool.removed,
|
||||
storage_pool.capacity_bytes,
|
||||
storage_pool.capacity_iops,
|
||||
storage_pool.scope,
|
||||
storage_pool.hypervisor,
|
||||
cluster.id cluster_id,
|
||||
@ -1521,9 +1538,12 @@ CREATE VIEW `cloud`.`disk_offering_view` AS
|
||||
disk_offering.name,
|
||||
disk_offering.display_text,
|
||||
disk_offering.disk_size,
|
||||
disk_offering.min_iops,
|
||||
disk_offering.max_iops,
|
||||
disk_offering.created,
|
||||
disk_offering.tags,
|
||||
disk_offering.customized,
|
||||
disk_offering.customized_iops,
|
||||
disk_offering.removed,
|
||||
disk_offering.use_local_storage,
|
||||
disk_offering.system_use,
|
||||
@ -1736,6 +1756,8 @@ CREATE VIEW `cloud`.`volume_view` AS
|
||||
volumes.device_id,
|
||||
volumes.volume_type,
|
||||
volumes.size,
|
||||
volumes.min_iops,
|
||||
volumes.max_iops,
|
||||
volumes.created,
|
||||
volumes.state,
|
||||
volumes.attached,
|
||||
|
||||
@ -203,7 +203,7 @@ class cloudConnection(object):
|
||||
i = i + 1
|
||||
return cmdname, isAsync, requests
|
||||
|
||||
def marvin_request(self, cmd, response_type=None, method='GET'):
|
||||
def marvin_request(self, cmd, response_type=None, method='GET', data=''):
|
||||
"""
|
||||
Requester for marvin command objects
|
||||
@param cmd: marvin's command from cloudstackAPI
|
||||
|
||||
@ -25,6 +25,9 @@ under the License.
|
||||
<% long now = System.currentTimeMillis(); %>
|
||||
<script language="javascript">
|
||||
dictionary = {
|
||||
'label.custom.disk.iops': '<fmt:message key="label.custom.disk.iops" />',
|
||||
'label.disk.iops.min': '<fmt:message key="label.disk.iops.min" />',
|
||||
'label.disk.iops.max': '<fmt:message key="label.disk.iops.max" />',
|
||||
'label.acquire.new.secondary.ip': '<fmt:message key="label.acquire.new.secondary.ip" />',
|
||||
'label.view.secondary.ips': '<fmt:message key="label.view.secondary.ips" />',
|
||||
'message.acquire.ip.nic': '<fmt:message key="message.acquire.ip.nic" />',
|
||||
@ -472,6 +475,7 @@ dictionary = {
|
||||
'label.disable.vpn': '<fmt:message key="label.disable.vpn" />',
|
||||
'label.disabling.vpn.access': '<fmt:message key="label.disabling.vpn.access" />',
|
||||
'label.disk.allocated': '<fmt:message key="label.disk.allocated" />',
|
||||
'label.disk.iops.total': '<fmt:message key="label.disk.iops.total" />',
|
||||
'label.disk.bytes.read.rate': '<fmt:message key="label.disk.bytes.read.rate" />',
|
||||
'label.disk.bytes.write.rate': '<fmt:message key="label.disk.bytes.write.rate" />',
|
||||
'label.disk.iops.write.rate': '<fmt:message key="label.disk.iops.write.rate" />',
|
||||
@ -1029,6 +1033,7 @@ dictionary = {
|
||||
'label.storage': '<fmt:message key="label.storage" />',
|
||||
'label.storage.tags': '<fmt:message key="label.storage.tags" />',
|
||||
'label.storage.type': '<fmt:message key="label.storage.type" />',
|
||||
'label.qos.type': '<fmt:message key="label.qos.type" />',
|
||||
'label.subdomain.access': '<fmt:message key="label.subdomain.access" />',
|
||||
'label.submit': '<fmt:message key="label.submit" />',
|
||||
'label.submitted.by': '<fmt:message key="label.submitted.by" />',
|
||||
|
||||
@ -1015,6 +1015,86 @@
|
||||
dependsOn: 'isCustomized',
|
||||
validation: { required: true, number: true }
|
||||
},
|
||||
qosType: {
|
||||
label: 'label.qos.type',
|
||||
docID: 'helpDiskOfferingQoSType',
|
||||
select: function(args) {
|
||||
var items = [];
|
||||
items.push({id: '', description: ''});
|
||||
items.push({id: 'hypervisor', description: 'hypervisor'});
|
||||
items.push({id: 'storage', description: 'storage'});
|
||||
args.response.success({data: items});
|
||||
|
||||
args.$select.change(function() {
|
||||
var $form = $(this).closest('form');
|
||||
var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]');
|
||||
var $minIops = $form.find('.form-item[rel=minIops]');
|
||||
var $maxIops = $form.find('.form-item[rel=maxIops]');
|
||||
var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]');
|
||||
var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]');
|
||||
var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]');
|
||||
var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]');
|
||||
|
||||
var qosId = $(this).val();
|
||||
|
||||
if (qosId == 'storage') { // Storage QoS
|
||||
$diskBytesReadRate.hide();
|
||||
$diskBytesWriteRate.hide();
|
||||
$diskIopsReadRate.hide();
|
||||
$diskIopsWriteRate.hide();
|
||||
|
||||
$isCustomizedIops.css('display', 'inline-block');
|
||||
|
||||
if ($isCustomizedIops == true) {
|
||||
$minIops.css('display', 'inline-block');
|
||||
$maxIops.css('display', 'inline-block');
|
||||
}
|
||||
else {
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
}
|
||||
}
|
||||
else if (qosId == 'hypervisor') { // Hypervisor Qos
|
||||
$isCustomizedIops.hide();
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
|
||||
$diskBytesReadRate.css('display', 'inline-block');
|
||||
$diskBytesWriteRate.css('display', 'inline-block');
|
||||
$diskIopsReadRate.css('display', 'inline-block');
|
||||
$diskIopsWriteRate.css('display', 'inline-block');
|
||||
}
|
||||
else { // No Qos
|
||||
$diskBytesReadRate.hide();
|
||||
$diskBytesWriteRate.hide();
|
||||
$diskIopsReadRate.hide();
|
||||
$diskIopsWriteRate.hide();
|
||||
$isCustomizedIops.hide();
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
isCustomizedIops: {
|
||||
label: 'label.custom.disk.iops',
|
||||
docID: 'helpDiskOfferingCustomDiskIops',
|
||||
isBoolean: true,
|
||||
isReverse: true,
|
||||
isChecked: false
|
||||
},
|
||||
minIops: {
|
||||
label: 'label.disk.iops.min',
|
||||
docID: 'helpDiskOfferingDiskIopsMin',
|
||||
dependsOn: 'isCustomizedIops',
|
||||
validation: { required: false, number: true }
|
||||
},
|
||||
maxIops: {
|
||||
label: 'label.disk.iops.max',
|
||||
docID: 'helpDiskOfferingDiskIopsMax',
|
||||
dependsOn: 'isCustomizedIops',
|
||||
validation: { required: false, number: true }
|
||||
},
|
||||
diskBytesReadRate: {
|
||||
label: 'label.disk.bytes.read.rate',
|
||||
validation: {
|
||||
@ -1080,18 +1160,65 @@
|
||||
|
||||
action: function(args) {
|
||||
var data = {
|
||||
isMirrored: false,
|
||||
isMirrored: false,
|
||||
name: args.data.name,
|
||||
displaytext: args.data.description,
|
||||
storageType: args.data.storageType,
|
||||
customized: (args.data.isCustomized=="on")
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
if(args.$form.find('.form-item[rel=disksize]').css("display") != "none") {
|
||||
$.extend(data, {
|
||||
disksize: args.data.disksize
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.qosType == 'storage') {
|
||||
var customIops = args.data.isCustomizedIops == "on";
|
||||
|
||||
$.extend(data, {
|
||||
customizediops: customIops
|
||||
});
|
||||
|
||||
if (!customIops) {
|
||||
if (args.data.minIops != null && args.data.minIops.length > 0) {
|
||||
$.extend(data, {
|
||||
miniops: args.data.minIops
|
||||
});
|
||||
}
|
||||
|
||||
if(args.data.maxIops != null && args.data.maxIops.length > 0) {
|
||||
$.extend(data, {
|
||||
maxiops: args.data.maxIops
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args.data.qosType == 'hypervisor') {
|
||||
if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
bytesreadrate: args.data.diskBytesReadRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
byteswriterate: args.data.diskBytesWriteRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopsreadrate: args.data.diskIopsReadRate
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopswriterate: args.data.diskIopsWriteRate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(args.data.tags != null && args.data.tags.length > 0) {
|
||||
$.extend(data, {
|
||||
@ -1104,26 +1231,6 @@
|
||||
domainid: args.data.domainId
|
||||
});
|
||||
}
|
||||
if(args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
bytesreadrate: args.data.diskBytesReadRate
|
||||
});
|
||||
}
|
||||
if(args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
byteswriterate: args.data.diskBytesWriteRate
|
||||
});
|
||||
}
|
||||
if(args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopsreadrate: args.data.diskIopsReadRate
|
||||
});
|
||||
}
|
||||
if(args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) {
|
||||
$.extend(data, {
|
||||
iopswriterate: args.data.diskIopsWriteRate
|
||||
});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: createURL('createDiskOffering'),
|
||||
@ -1236,6 +1343,28 @@
|
||||
return "N/A";
|
||||
}
|
||||
},
|
||||
iscustomizediops: {
|
||||
label: 'label.custom.disk.iops',
|
||||
converter: cloudStack.converters.toBooleanText
|
||||
},
|
||||
miniops: {
|
||||
label: 'label.disk.iops.min',
|
||||
converter: function(args) {
|
||||
if(args > 0)
|
||||
return args;
|
||||
else
|
||||
return "N/A";
|
||||
}
|
||||
},
|
||||
maxiops: {
|
||||
label: 'label.disk.iops.max',
|
||||
converter: function(args) {
|
||||
if(args > 0)
|
||||
return args;
|
||||
else
|
||||
return "N/A";
|
||||
}
|
||||
},
|
||||
diskBytesReadRate: { label: 'label.disk.bytes.write.rate' },
|
||||
diskBytesWriteRate: { label: 'label.disk.bytes.write.rate' },
|
||||
diskIopsReadRate: { label: 'label.disk.iops.write.rate' },
|
||||
|
||||
@ -270,6 +270,10 @@ cloudStack.docs = {
|
||||
desc: 'Type of disk for the VM. Local is attached to the hypervisor host where the VM is running. Shared is storage accessible via NFS.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingQoSType: {
|
||||
desc: 'Type of Quality of Service desired, if any.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingCustomDiskSize: {
|
||||
desc: 'If checked, the user can set their own disk size. If not checked, the root administrator must define a value in Disk Size.',
|
||||
externalLink: ''
|
||||
@ -278,6 +282,18 @@ cloudStack.docs = {
|
||||
desc: 'Appears only if Custom Disk Size is not selected. Define the volume size in GB.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingCustomDiskIops: {
|
||||
desc: 'If checked, the user can set Min and Max IOPS. If not checked, the root administrator can define such values.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingDiskIopsMin: {
|
||||
desc: 'Appears only if Custom IOPS is not selected. Define the minimum volume IOPS.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingDiskIopsMax: {
|
||||
desc: 'Appears only if Custom IOPS is not selected. Define the maximum volume IOPS.',
|
||||
externalLink: ''
|
||||
},
|
||||
helpDiskOfferingStorageTags: {
|
||||
desc: 'Comma-separated list of attributes that should be associated with the primary storage for this disk. For example "ssd,blue".',
|
||||
externalLink: ''
|
||||
|
||||
@ -321,8 +321,8 @@ cloudStack.converters = {
|
||||
toBooleanText: function(booleanValue) {
|
||||
if(booleanValue == true)
|
||||
return "Yes";
|
||||
else if(booleanValue == false)
|
||||
return "No";
|
||||
|
||||
return "No";
|
||||
},
|
||||
convertHz: function(hz) {
|
||||
if (hz == null)
|
||||
|
||||
@ -132,6 +132,16 @@
|
||||
else {
|
||||
$diskSize.hide();
|
||||
}
|
||||
var $minIops = $form.find('.form-item[rel=minIops]');
|
||||
var $maxIops = $form.find('.form-item[rel=maxIops]');
|
||||
if (selectedDiskOfferingObj.iscustomizediops == true) {
|
||||
$minIops.css('display', 'inline-block');
|
||||
$maxIops.css('display', 'inline-block');
|
||||
}
|
||||
else {
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -141,7 +151,19 @@
|
||||
label: 'label.disk.size.gb',
|
||||
validation: { required: true, number: true },
|
||||
isHidden: true
|
||||
}
|
||||
},
|
||||
|
||||
minIops: {
|
||||
label: 'label.disk.iops.min',
|
||||
validation: { required: false, number: true },
|
||||
isHidden: true
|
||||
},
|
||||
|
||||
maxIops: {
|
||||
label: 'label.disk.iops.max',
|
||||
validation: { required: false, number: true },
|
||||
isHidden: true
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
@ -159,6 +181,20 @@
|
||||
size: args.data.diskSize
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedDiskOfferingObj.iscustomizediops == true) {
|
||||
if (args.data.minIops != "" && args.data.minIops > 0) {
|
||||
$.extend(data, {
|
||||
miniops: args.data.minIops
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.maxIops != "" && args.data.maxIops > 0) {
|
||||
$.extend(data, {
|
||||
maxiops: args.data.maxIops
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: createURL('createVolume'),
|
||||
@ -1228,6 +1264,24 @@
|
||||
return cloudStack.converters.convertBytes(args);
|
||||
}
|
||||
},
|
||||
miniops: {
|
||||
label: 'label.disk.iops.min',
|
||||
converter: function(args) {
|
||||
if(args == null || args == 0)
|
||||
return "";
|
||||
else
|
||||
return args;
|
||||
}
|
||||
},
|
||||
maxiops: {
|
||||
label: 'label.disk.iops.max',
|
||||
converter: function(args) {
|
||||
if(args == null || args == 0)
|
||||
return "";
|
||||
else
|
||||
return args;
|
||||
}
|
||||
},
|
||||
virtualmachineid: {
|
||||
label: 'VM ID',
|
||||
converter: function(args) {
|
||||
|
||||
@ -12745,11 +12745,11 @@
|
||||
{
|
||||
id: { label: 'label.id' },
|
||||
state: { label: 'label.state' },
|
||||
tags: {
|
||||
label: 'label.storage.tags',
|
||||
isEditable: true
|
||||
},
|
||||
podname: { label: 'label.pod' },
|
||||
tags: {
|
||||
label: 'label.storage.tags',
|
||||
isEditable: true
|
||||
},
|
||||
podname: { label: 'label.pod' },
|
||||
clustername: { label: 'label.cluster' },
|
||||
type: { label: 'label.type' },
|
||||
ipaddress: { label: 'label.ip.address' },
|
||||
@ -12771,6 +12771,15 @@
|
||||
else
|
||||
return cloudStack.converters.convertBytes(args);
|
||||
}
|
||||
},
|
||||
capacityiops: {
|
||||
label: 'label.disk.iops.total',
|
||||
converter: function(args) {
|
||||
if (args == null || args == 0)
|
||||
return "";
|
||||
else
|
||||
return args;
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -49,6 +49,14 @@ public class StringUtils {
|
||||
return org.apache.commons.lang.StringUtils.join(components, delimiter);
|
||||
}
|
||||
|
||||
public static boolean isNotBlank(String str) {
|
||||
if (str != null && str.trim().length() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tags
|
||||
* @return List of tags
|
||||
|
||||
@ -26,14 +26,16 @@ import com.vmware.vim25.CustomFieldStringValue;
|
||||
import com.vmware.vim25.DatastoreInfo;
|
||||
import com.vmware.vim25.DynamicProperty;
|
||||
import com.vmware.vim25.HostNasVolumeSpec;
|
||||
import com.vmware.vim25.HostScsiDisk;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
import com.vmware.vim25.NasDatastoreInfo;
|
||||
import com.vmware.vim25.ObjectContent;
|
||||
import com.vmware.vim25.ObjectSpec;
|
||||
import com.vmware.vim25.PropertyFilterSpec;
|
||||
import com.vmware.vim25.PropertySpec;
|
||||
import com.vmware.vim25.SelectionSpec;
|
||||
import com.vmware.vim25.TraversalSpec;
|
||||
import com.vmware.vim25.VmfsDatastoreCreateSpec;
|
||||
import com.vmware.vim25.VmfsDatastoreOption;
|
||||
|
||||
public class HostDatastoreSystemMO extends BaseMO {
|
||||
|
||||
@ -122,6 +124,22 @@ public class HostDatastoreSystemMO extends BaseMO {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<HostScsiDisk> queryAvailableDisksForVmfs() throws Exception {
|
||||
return _context.getService().queryAvailableDisksForVmfs(_mor, null);
|
||||
}
|
||||
|
||||
public ManagedObjectReference createVmfsDatastore(String datastoreName, HostScsiDisk hostScsiDisk) throws Exception {
|
||||
// just grab the first instance of VmfsDatastoreOption
|
||||
VmfsDatastoreOption vmfsDatastoreOption = _context.getService().queryVmfsDatastoreCreateOptions(_mor, hostScsiDisk.getDevicePath(), 4).get(0);
|
||||
|
||||
VmfsDatastoreCreateSpec vmfsDatastoreCreateSpec = (VmfsDatastoreCreateSpec)vmfsDatastoreOption.getSpec();
|
||||
|
||||
// set the name of the datastore to be created
|
||||
vmfsDatastoreCreateSpec.getVmfs().setVolumeName(datastoreName);
|
||||
|
||||
return _context.getService().createVmfsDatastore(_mor, vmfsDatastoreCreateSpec);
|
||||
}
|
||||
|
||||
public boolean deleteDatastore(String name) throws Exception {
|
||||
ManagedObjectReference morDatastore = findDatastore(name);
|
||||
if(morDatastore != null) {
|
||||
|
||||
@ -149,6 +149,13 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
|
||||
throw new Exception("Could not find host default gateway, host is not properly configured?");
|
||||
}
|
||||
|
||||
public HostStorageSystemMO getHostStorageSystemMO() throws Exception {
|
||||
return new HostStorageSystemMO(_context,
|
||||
(ManagedObjectReference)_context.getVimClient().getDynamicProperty(
|
||||
_mor, "configManager.storageSystem")
|
||||
);
|
||||
}
|
||||
|
||||
public HostDatastoreSystemMO getHostDatastoreSystemMO() throws Exception {
|
||||
return new HostDatastoreSystemMO(_context,
|
||||
(ManagedObjectReference)_context.getVimClient().getDynamicProperty(
|
||||
@ -797,14 +804,14 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmountDatastore(String poolUuid) throws Exception {
|
||||
public void unmountDatastore(String uuid) throws Exception {
|
||||
|
||||
if(s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - unmountDatastore(). target MOR: " + _mor.getValue() + ", poolUuid: " + poolUuid);
|
||||
s_logger.trace("vCenter API trace - unmountDatastore(). target MOR: " + _mor.getValue() + ", uuid: " + uuid);
|
||||
|
||||
HostDatastoreSystemMO hostDatastoreSystemMo = getHostDatastoreSystemMO();
|
||||
if(!hostDatastoreSystemMo.deleteDatastore(poolUuid)) {
|
||||
String msg = "Unable to unmount datastore. uuid: " + poolUuid;
|
||||
if(!hostDatastoreSystemMo.deleteDatastore(uuid)) {
|
||||
String msg = "Unable to unmount datastore. uuid: " + uuid;
|
||||
s_logger.error(msg);
|
||||
|
||||
if(s_logger.isTraceEnabled())
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
// 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.hypervisor.vmware.mo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||
|
||||
import com.vmware.vim25.HostInternetScsiHbaStaticTarget;
|
||||
import com.vmware.vim25.HostStorageDeviceInfo;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
|
||||
public class HostStorageSystemMO extends BaseMO {
|
||||
public HostStorageSystemMO(VmwareContext context, ManagedObjectReference morHostDatastore) {
|
||||
super(context, morHostDatastore);
|
||||
}
|
||||
|
||||
public HostStorageSystemMO(VmwareContext context, String morType, String morValue) {
|
||||
super(context, morType, morValue);
|
||||
}
|
||||
|
||||
public HostStorageDeviceInfo getStorageDeviceInfo() throws Exception {
|
||||
return (HostStorageDeviceInfo)_context.getVimClient().getDynamicProperty(_mor, "storageDeviceInfo");
|
||||
}
|
||||
|
||||
public void addInternetScsiStaticTargets(String iScsiHbaDevice, List<HostInternetScsiHbaStaticTarget> lstTargets) throws Exception {
|
||||
_context.getService().addInternetScsiStaticTargets(_mor, iScsiHbaDevice, lstTargets);
|
||||
}
|
||||
|
||||
public void removeInternetScsiStaticTargets(String iScsiHbaDevice, List<HostInternetScsiHbaStaticTarget> lstTargets) throws Exception {
|
||||
_context.getService().removeInternetScsiStaticTargets(_mor, iScsiHbaDevice, lstTargets);
|
||||
}
|
||||
|
||||
public void rescanHba(String iScsiHbaDevice) throws Exception {
|
||||
_context.getService().rescanHba(_mor, iScsiHbaDevice);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user