You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mt...@apache.org on 2013/06/29 01:02:49 UTC
[1/4] SolidFire plug-in and related changes
Updated Branches:
refs/heads/master 02ab2eb38 -> 99227f7b3
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/scripts/sharedFunctions.js
----------------------------------------------------------------------
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index dd9a7d6..bf6464c 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -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)
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/scripts/storage.js
----------------------------------------------------------------------
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index 2c03d39..ad0965a 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -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) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 92faf5e..135307b 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -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;
+ }
}
}
],
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/utils/src/com/cloud/utils/StringUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/StringUtils.java b/utils/src/com/cloud/utils/StringUtils.java
index 359b169..db32dd4 100644
--- a/utils/src/com/cloud/utils/StringUtils.java
+++ b/utils/src/com/cloud/utils/StringUtils.java
@@ -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
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java
----------------------------------------------------------------------
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java
index 3dcd724..7c548ff 100755
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java
@@ -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) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
----------------------------------------------------------------------
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
index a866fdc..e7fd922 100755
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -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())
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostStorageSystemMO.java
----------------------------------------------------------------------
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostStorageSystemMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostStorageSystemMO.java
new file mode 100644
index 0000000..d400185
--- /dev/null
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostStorageSystemMO.java
@@ -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);
+ }
+}
[2/4] SolidFire plug-in and related changes
Posted by mt...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
new file mode 100644
index 0000000..839c5a5
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
@@ -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 + ".");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
index 7022ee6..385ca36 100644
--- a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
@@ -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());
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
index 68d9113..503a563 100644
--- a/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
@@ -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());
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
index ed2732e..1c18c96 100644
--- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
@@ -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) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
index 2336a48..58e8370 100644
--- a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java
index c0d5ee9..69f2204 100644
--- a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
index 1f07f52..701e195 100644
--- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java
index 98eae37..1b99b63 100755
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -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
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 3840c12..2089f82 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -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
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/server/ConfigurationServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index 1ddfcfa..9e79b76 100755
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/storage/StorageManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java
index 29c7ebc..df69092 100755
--- a/server/src/com/cloud/storage/StorageManager.java
+++ b/server/src/com/cloud/storage/StorageManager.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/storage/StorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java
index b3e8b96..241f6e6 100755
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -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;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/storage/VolumeManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java
index c84bb67..2e44a3c 100644
--- a/server/src/com/cloud/storage/VolumeManager.java
+++ b/server/src/com/cloud/storage/VolumeManager.java
@@ -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;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/storage/VolumeManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java
index 4e7b335..a293da5 100644
--- a/server/src/com/cloud/storage/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/VolumeManagerImpl.java
@@ -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);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/template/TemplateManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java
index f70d44d..ca644af 100755
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/test/DatabaseConfig.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java
index ef0259d..63f77b6 100755
--- a/server/src/com/cloud/test/DatabaseConfig.java
+++ b/server/src/com/cloud/test/DatabaseConfig.java
@@ -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"));
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 3cef182..a59fa5b 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -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);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index 95230a5..7a61978 100755
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index 2d0f8de..0c1d753 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -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,
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/tools/marvin/marvin/cloudstackConnection.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py
index 9d60ff9..8129396 100644
--- a/tools/marvin/marvin/cloudstackConnection.py
+++ b/tools/marvin/marvin/cloudstackConnection.py
@@ -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
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/dictionary.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index 7809cdb..af64228 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -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" />',
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/scripts/configuration.js
----------------------------------------------------------------------
diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js
index 7f0e1a5..ab70c3d 100644
--- a/ui/scripts/configuration.js
+++ b/ui/scripts/configuration.js
@@ -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' },
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/ui/scripts/docs.js
----------------------------------------------------------------------
diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js
index 5aa352a..635e619 100755
--- a/ui/scripts/docs.js
+++ b/ui/scripts/docs.js
@@ -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: ''
[3/4] SolidFire plug-in and related changes
Posted by mt...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 5c51585..52f4190 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -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));
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index cbbec7c..d9c357d 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -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);
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
index 399e234..e6358f2 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
@@ -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());
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index 8d7c965..a233407 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -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();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
index 643c933..78f2263 100644
--- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml
index 9db0685..81af8ac 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -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>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
index 960378c..329f27f 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
@@ -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;
}
+ 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 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(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
+ 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(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
+ 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) {
}
-
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
new file mode 100644
index 0000000..2e25cd5
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
index 2965e8f..28864ea 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
@@ -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;
+ }
}
[4/4] git commit: updated refs/heads/master to 99227f7
Posted by mt...@apache.org.
SolidFire plug-in and related changes
SolidFire plug-in
SolidFire plug-in related
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/99227f7b
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/99227f7b
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/99227f7b
Branch: refs/heads/master
Commit: 99227f7b3e824caeb89035982793ad510e460249
Parents: 02ab2eb
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Fri Jun 28 14:05:12 2013 -0600
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Fri Jun 28 16:59:21 2013 -0600
----------------------------------------------------------------------
api/src/com/cloud/agent/api/to/DiskTO.java | 12 +-
api/src/com/cloud/offering/DiskOffering.java | 16 +-
api/src/com/cloud/storage/StoragePool.java | 2 +
api/src/com/cloud/storage/Volume.java | 6 +
.../org/apache/cloudstack/api/ApiConstants.java | 6 +
.../admin/offering/CreateDiskOfferingCmd.java | 27 +-
.../admin/storage/CreateStoragePoolCmd.java | 24 +
.../command/user/volume/CreateVolumeCmd.java | 14 +
.../api/response/DiskOfferingResponse.java | 33 +
.../api/response/StoragePoolResponse.java | 11 +
.../cloudstack/api/response/VolumeResponse.java | 16 +
.../classes/resources/messages.properties | 7 +-
client/pom.xml | 5 +
client/tomcatconf/applicationContext.xml.in | 1 +
.../com/cloud/agent/api/AttachVolumeAnswer.java | 16 +-
.../cloud/agent/api/AttachVolumeCommand.java | 114 ++-
.../api/agent/test/AttachVolumeAnswerTest.java | 6 +-
.../api/agent/test/AttachVolumeCommandTest.java | 10 +-
.../agent/test/BackupSnapshotCommandTest.java | 5 +
.../api/agent/test/CheckNetworkAnswerTest.java | 5 +
.../api/agent/test/SnapshotCommandTest.java | 4 +
.../engine/subsystem/api/storage/ChapInfo.java | 26 +
.../subsystem/api/storage/DataStoreDriver.java | 14 +-
.../api/storage/PrimaryDataStoreDriver.java | 6 +-
.../api/storage/PrimaryDataStoreParameters.java | 50 +
.../subsystem/api/storage/VolumeService.java | 2 +
.../storage/command/AttachCommand.java | 71 ++
.../storage/command/DettachCommand.java | 17 +
.../storage/datastore/db/StoragePoolVO.java | 26 +-
.../src/com/cloud/storage/DiskOfferingVO.java | 46 +-
.../schema/src/com/cloud/storage/VolumeVO.java | 57 +-
.../src/com/cloud/storage/dao/VolumeDao.java | 2 +
.../com/cloud/storage/dao/VolumeDaoImpl.java | 13 +
.../storage/image/TemplateServiceImpl.java | 4 +-
.../storage/image/store/ImageStoreImpl.java | 2 +-
.../storage/allocator/StorageAllocatorTest.java | 3 +-
.../cloudstack/storage/test/SnapshotTest.java | 2 +-
.../cloudstack/storage/test/VolumeTest.java | 2 +-
.../storage/test/VolumeTestVmware.java | 2 +-
.../storage/test/volumeServiceTest.java | 2 +-
.../storage/snapshot/SnapshotServiceImpl.java | 2 +-
.../allocator/ZoneWideStoragePoolAllocator.java | 36 +-
.../datastore/DataObjectManagerImpl.java | 4 +-
.../datastore/PrimaryDataStoreEntityImpl.java | 6 +
.../storage/image/BaseImageStoreDriverImpl.java | 4 +-
.../datastore/PrimaryDataStoreHelper.java | 5 +
.../storage/datastore/PrimaryDataStoreImpl.java | 5 +
.../cloudstack/storage/volume/VolumeObject.java | 15 +
.../storage/volume/VolumeServiceImpl.java | 19 +-
.../kvm/resource/LibvirtComputingResource.java | 2 +-
.../agent/manager/MockStorageManagerImpl.java | 2 +-
.../vmware/resource/VmwareResource.java | 274 +++++-
.../xen/resource/CitrixResourceBase.java | 143 ++-
.../xen/resource/XenServerStorageProcessor.java | 18 +-
.../CloudStackPrimaryDataStoreDriverImpl.java | 9 +-
.../SamplePrimaryDataStoreDriverImpl.java | 9 +-
plugins/storage/volume/solidfire/pom.xml | 7 +-
.../driver/SolidfirePrimaryDataStoreDriver.java | 480 +++++++++-
.../SolidFirePrimaryDataStoreLifeCycle.java | 274 ++++++
.../SolidfirePrimaryDataStoreProvider.java | 81 +-
.../storage/datastore/util/SolidFireUtil.java | 901 +++++++++++++++++++
.../api/query/dao/DiskOfferingJoinDaoImpl.java | 3 +
.../api/query/dao/StoragePoolJoinDaoImpl.java | 2 +
.../cloud/api/query/dao/VolumeJoinDaoImpl.java | 3 +
.../cloud/api/query/vo/DiskOfferingJoinVO.java | 33 +
.../cloud/api/query/vo/StoragePoolJoinVO.java | 13 +-
.../com/cloud/api/query/vo/VolumeJoinVO.java | 21 +-
.../configuration/ConfigurationManager.java | 8 +-
.../configuration/ConfigurationManagerImpl.java | 53 +-
.../cloud/server/ConfigurationServerImpl.java | 2 +-
.../src/com/cloud/storage/StorageManager.java | 9 +-
.../com/cloud/storage/StorageManagerImpl.java | 44 +-
server/src/com/cloud/storage/VolumeManager.java | 1 -
.../com/cloud/storage/VolumeManagerImpl.java | 139 ++-
.../com/cloud/template/TemplateManagerImpl.java | 2 +-
server/src/com/cloud/test/DatabaseConfig.java | 2 +-
server/src/com/cloud/vm/UserVmManagerImpl.java | 4 +-
.../cloud/vpc/MockConfigurationManagerImpl.java | 5 +-
setup/db/db/schema-410to420.sql | 22 +
tools/marvin/marvin/cloudstackConnection.py | 2 +-
ui/dictionary.jsp | 5 +
ui/scripts/configuration.js | 179 +++-
ui/scripts/docs.js | 16 +
ui/scripts/sharedFunctions.js | 4 +-
ui/scripts/storage.js | 56 +-
ui/scripts/system.js | 19 +-
utils/src/com/cloud/utils/StringUtils.java | 8 +
.../vmware/mo/HostDatastoreSystemMO.java | 20 +-
.../com/cloud/hypervisor/vmware/mo/HostMO.java | 15 +-
.../vmware/mo/HostStorageSystemMO.java | 51 ++
90 files changed, 3432 insertions(+), 292 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/com/cloud/agent/api/to/DiskTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java
index 7b32f00..556ccd4 100644
--- a/api/src/com/cloud/agent/api/to/DiskTO.java
+++ b/api/src/com/cloud/agent/api/to/DiskTO.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/com/cloud/offering/DiskOffering.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/offering/DiskOffering.java b/api/src/com/cloud/offering/DiskOffering.java
index ae4528c..9c196e0 100644
--- a/api/src/com/cloud/offering/DiskOffering.java
+++ b/api/src/com/cloud/offering/DiskOffering.java
@@ -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();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/com/cloud/storage/StoragePool.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java
index 8f8b864..6e9af12 100644
--- a/api/src/com/cloud/storage/StoragePool.java
+++ b/api/src/com/cloud/storage/StoragePool.java
@@ -60,6 +60,8 @@ public interface StoragePool extends Identity, InternalIdentity {
*/
long getUsedBytes();
+ Long getCapacityIops();
+
Long getClusterId();
/**
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/com/cloud/storage/Volume.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java
index f5ed4e2..342dfd3 100755
--- a/api/src/com/cloud/storage/Volume.java
+++ b/api/src/com/cloud/storage/Volume.java
@@ -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
*/
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 809e023..dd876f7 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -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";
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
index a2c5f77..4741591 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
index 74eb2b9..f5750b9 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
index 6f0bf3a..f293a03 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
index 35cf21a..4291d85 100644
--- a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
index 0050000..7321d98 100644
--- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
index b643de1..338fcaa 100644
--- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index ad8d29d..b1a09b1 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -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
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index b8182c2..d1eeb3b 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -22,6 +22,11 @@
<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>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 82ce9e9..7052fd7 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -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" />
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/src/com/cloud/agent/api/AttachVolumeAnswer.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/AttachVolumeAnswer.java b/core/src/com/cloud/agent/api/AttachVolumeAnswer.java
index b377b7c..6b965b0 100644
--- a/core/src/com/cloud/agent/api/AttachVolumeAnswer.java
+++ b/core/src/com/cloud/agent/api/AttachVolumeAnswer.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/AttachVolumeCommand.java b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
index 2658262..2eb503a 100644
--- a/core/src/com/cloud/agent/api/AttachVolumeCommand.java
+++ b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
index 251a6cb..9e43d9f 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
@@ -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() {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
index 1ec416a..6f413c0 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
@@ -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
@@ -66,12 +66,6 @@ public class AttachVolumeCommandTest {
}
@Test
- public void testGetVolumeFolder() {
- String vFolder = avc.getVolumeFolder();
- assertTrue(vFolder.equals("vFolder"));
- }
-
- @Test
public void testGetVolumePath() {
String vPath = avc.getVolumePath();
assertTrue(vPath.equals("vPath"));
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java
index 9890593..0fee8c6 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java
@@ -88,6 +88,11 @@ public class BackupSnapshotCommandTest {
};
@Override
+ public Long getCapacityIops() {
+ return 0L;
+ }
+
+ @Override
public Long getClusterId() {
return 0L;
};
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java
index 4db6557..b834a26 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java
@@ -126,6 +126,11 @@ public class CheckNetworkAnswerTest {
};
@Override
+ public Long getCapacityIops() {
+ return 0L;
+ };
+
+ @Override
public Long getClusterId() {
return 0L;
};
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java
index 3076d45..35bdfc8 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java
@@ -78,6 +78,10 @@ public class SnapshotCommandTest {
return 0L;
};
+ public Long getCapacityIops() {
+ return 0L;
+ };
+
public Long getClusterId() {
return 0L;
};
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java
new file mode 100644
index 0000000..97c9ecb
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ChapInfo.java
@@ -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();
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
index 1cb6e15..127b858 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
@@ -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);
-
+ 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);
-
- DataTO getTO(DataObject data);
-
- DataStoreTO getStoreTO(DataStore store);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
index 2528a53..b124d83 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
@@ -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);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
index 3b5362a..c05419f 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
@@ -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;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
index f96ea40..7515088 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
@@ -42,6 +42,8 @@ public interface VolumeService {
}
}
+ ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore);
+
/**
* Creates the volume based on the given criteria
*
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
index 6b4e9f7..44bce91 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
@@ -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;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
index a0ab4b2..bb7325c 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
@@ -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;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java
index 9b8de67..a8c1e7f 100644
--- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java
@@ -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() {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
index b7363e7..d9656b4 100755
--- a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
+++ b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/schema/src/com/cloud/storage/VolumeVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java
index 02c09a2..7b54f3d 100755
--- a/engine/schema/src/com/cloud/storage/VolumeVO.java
+++ b/engine/schema/src/com/cloud/storage/VolumeVO.java
@@ -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();
@@ -275,6 +295,24 @@ public class VolumeVO implements Volume {
}
@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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java
index 79c0dc3..fb7dc70 100755
--- a/engine/schema/src/com/cloud/storage/dao/VolumeDao.java
+++ b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java
index f82b511..ba85466 100755
--- a/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java
+++ b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java
@@ -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);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
index 96c35f3..da62712 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
index 6d8e8e5..438ab69 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
@@ -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) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
index 40d9d41..90696ca 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
@@ -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();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
index 2579a38..f1eed3a 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
index 70fdb1b..cbfafc9 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java
index 4acc8dc..be9dd19 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTestVmware.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java
index 42b0463..08de7f3 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java
@@ -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;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index 631d220..48ec512 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -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 {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java
index 29b3400..300d932 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java
@@ -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);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java
index fa9f993..7878d8d 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java
index e861910..0aebee2 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java
@@ -176,6 +176,12 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity {
}
@Override
+ public Long getCapacityIops() {
+ // TODO Auto-generated method stub
+ return 0L;
+ }
+
+ @Override
public Long getClusterId() {
// TODO Auto-generated method stub
return null;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java
index 93b0c2b..97c1671 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java
@@ -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();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
index 6815dec..53ead0b 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
@@ -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();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
index cfdb5c0..420fd29 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
@@ -288,6 +288,11 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
}
@Override
+ public Long getCapacityIops() {
+ return this.pdsv.getCapacityIops();
+ }
+
+ @Override
public Long getClusterId() {
return this.pdsv.getClusterId();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index 071c110..55fc3a6 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -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();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 56b0b08..de1e423 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -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;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index e0c00fc..914017c 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -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) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java
index 21b81e1..a59949f 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java
@@ -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 "