mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
SolidFire (shared-access) Provider
This commit is contained in:
parent
520ff00083
commit
42d00cae58
@ -18,7 +18,16 @@ package com.cloud.agent.api;
|
|||||||
|
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class CreateStoragePoolCommand extends ModifyStoragePoolCommand {
|
public class CreateStoragePoolCommand extends ModifyStoragePoolCommand {
|
||||||
|
public static final String DATASTORE_NAME = "datastoreName";
|
||||||
|
public static final String IQN = "iqn";
|
||||||
|
public static final String STORAGE_HOST = "storageHost";
|
||||||
|
public static final String STORAGE_PORT = "storagePort";
|
||||||
|
|
||||||
|
private boolean _createDatastore;
|
||||||
|
private Map<String, String> _details;
|
||||||
|
|
||||||
public CreateStoragePoolCommand() {
|
public CreateStoragePoolCommand() {
|
||||||
}
|
}
|
||||||
@ -26,4 +35,20 @@ public class CreateStoragePoolCommand extends ModifyStoragePoolCommand {
|
|||||||
public CreateStoragePoolCommand(boolean add, StoragePool pool) {
|
public CreateStoragePoolCommand(boolean add, StoragePool pool) {
|
||||||
super(add, pool);
|
super(add, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCreateDatastore(boolean createDatastore) {
|
||||||
|
_createDatastore = createDatastore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCreateDatastore() {
|
||||||
|
return _createDatastore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(Map<String, String> details) {
|
||||||
|
_details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getDetails() {
|
||||||
|
return _details;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,45 +17,68 @@
|
|||||||
package com.cloud.agent.api;
|
package com.cloud.agent.api;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.cloud.agent.api.to.StorageFilerTO;
|
import com.cloud.agent.api.to.StorageFilerTO;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
|
|
||||||
public class DeleteStoragePoolCommand extends Command {
|
public class DeleteStoragePoolCommand extends Command {
|
||||||
|
public static final String DATASTORE_NAME = "datastoreName";
|
||||||
|
public static final String IQN = "iqn";
|
||||||
|
public static final String STORAGE_HOST = "storageHost";
|
||||||
|
public static final String STORAGE_PORT = "storagePort";
|
||||||
|
|
||||||
StorageFilerTO pool;
|
|
||||||
public static final String LOCAL_PATH_PREFIX = "/mnt/";
|
public static final String LOCAL_PATH_PREFIX = "/mnt/";
|
||||||
String localPath;
|
|
||||||
|
private StorageFilerTO _pool;
|
||||||
|
private String _localPath;
|
||||||
|
private boolean _removeDatastore;
|
||||||
|
private Map<String, String> _details;
|
||||||
|
|
||||||
public DeleteStoragePoolCommand() {
|
public DeleteStoragePoolCommand() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteStoragePoolCommand(StoragePool pool, String localPath) {
|
public DeleteStoragePoolCommand(StoragePool pool, String localPath) {
|
||||||
this.pool = new StorageFilerTO(pool);
|
_pool = new StorageFilerTO(pool);
|
||||||
this.localPath = localPath;
|
_localPath = localPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteStoragePoolCommand(StoragePool pool) {
|
public DeleteStoragePoolCommand(StoragePool pool) {
|
||||||
this(pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()));
|
this(pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public StorageFilerTO getPool() {
|
public void setPool(StoragePool pool) {
|
||||||
return pool;
|
_pool = new StorageFilerTO(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPool(StoragePool pool) {
|
public StorageFilerTO getPool() {
|
||||||
this.pool = new StorageFilerTO(pool);
|
return _pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocalPath() {
|
||||||
|
return _localPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveDatastore(boolean removeDatastore) {
|
||||||
|
_removeDatastore = removeDatastore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getRemoveDatastore() {
|
||||||
|
return _removeDatastore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(Map<String, String> details) {
|
||||||
|
_details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getDetails() {
|
||||||
|
return _details;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocalPath() {
|
|
||||||
return localPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3177,6 +3177,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Answer execute(CreateStoragePoolCommand cmd) {
|
protected Answer execute(CreateStoragePoolCommand cmd) {
|
||||||
|
if (cmd.getCreateDatastore()) {
|
||||||
|
try {
|
||||||
|
VmwareContext context = getServiceContext();
|
||||||
|
|
||||||
|
_storageProcessor.prepareManagedDatastore(context, getHyperHost(context),
|
||||||
|
cmd.getDetails().get(CreateStoragePoolCommand.DATASTORE_NAME), cmd.getDetails().get(CreateStoragePoolCommand.IQN),
|
||||||
|
cmd.getDetails().get(CreateStoragePoolCommand.STORAGE_HOST), Integer.parseInt(cmd.getDetails().get(CreateStoragePoolCommand.STORAGE_PORT)));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return new Answer(cmd, false, "Issue creating datastore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Answer(cmd, true, "success");
|
return new Answer(cmd, true, "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3223,22 +3235,32 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd));
|
s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageFilerTO pool = cmd.getPool();
|
|
||||||
try {
|
try {
|
||||||
// We will leave datastore cleanup management to vCenter. Since for cluster VMFS datastore, it will always
|
if (cmd.getRemoveDatastore()) {
|
||||||
// be mounted by vCenter.
|
_storageProcessor.handleDatastoreAndVmdkDetach(cmd.getDetails().get(DeleteStoragePoolCommand.DATASTORE_NAME), cmd.getDetails().get(DeleteStoragePoolCommand.IQN),
|
||||||
|
cmd.getDetails().get(DeleteStoragePoolCommand.STORAGE_HOST), Integer.parseInt(cmd.getDetails().get(DeleteStoragePoolCommand.STORAGE_PORT)));
|
||||||
|
|
||||||
// VmwareHypervisorHost hyperHost = this.getHyperHost(getServiceContext());
|
return new Answer(cmd, true, "success");
|
||||||
// hyperHost.unmountDatastore(pool.getUuid());
|
}
|
||||||
Answer answer = new Answer(cmd, true, "success");
|
else {
|
||||||
return answer;
|
// We will leave datastore cleanup management to vCenter. Since for cluster VMFS datastore, it will always
|
||||||
|
// be mounted by vCenter.
|
||||||
|
|
||||||
|
// VmwareHypervisorHost hyperHost = this.getHyperHost(getServiceContext());
|
||||||
|
// hyperHost.unmountDatastore(pool.getUuid());
|
||||||
|
|
||||||
|
return new Answer(cmd, true, "success");
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (e instanceof RemoteException) {
|
if (e instanceof RemoteException) {
|
||||||
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
|
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
|
||||||
|
|
||||||
invalidateServiceContext();
|
invalidateServiceContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StorageFilerTO pool = cmd.getPool();
|
||||||
String msg = "DeleteStoragePoolCommand (pool: " + pool.getHost() + ", path: " + pool.getPath() + ") failed due to " + VmwareHelper.getExceptionMessage(e);
|
String msg = "DeleteStoragePoolCommand (pool: " + pool.getHost() + ", path: " + pool.getPath() + ") failed due to " + VmwareHelper.getExceptionMessage(e);
|
||||||
|
|
||||||
return new Answer(cmd, false, msg);
|
return new Answer(cmd, false, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1688,6 +1688,11 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName,
|
||||||
|
String iScsiName, String storageHost, int storagePort) throws Exception {
|
||||||
|
return getVmfsDatastore(context, hyperHost, datastoreName, storageHost, storagePort, trimIqn(iScsiName), null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
private ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String iScsiName,
|
private ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String iScsiName,
|
||||||
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
|
String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
|
||||||
String chapTargetUsername, String chapTargetSecret) throws Exception {
|
String chapTargetUsername, String chapTargetSecret) throws Exception {
|
||||||
@ -1800,8 +1805,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
|
private void removeVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
|
||||||
// hyperHost.unmountDatastore(volumeUuid);
|
// hyperHost.unmountDatastore(datastoreName);
|
||||||
|
|
||||||
VmwareContext context = hostService.getServiceContext(null);
|
VmwareContext context = hostService.getServiceContext(null);
|
||||||
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
||||||
@ -1990,11 +1995,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
return morDs;
|
return morDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
|
public void handleDatastoreAndVmdkDetach(String datastoreName, String iqn, String storageHost, int storagePort) throws Exception {
|
||||||
VmwareContext context = hostService.getServiceContext(null);
|
VmwareContext context = hostService.getServiceContext(null);
|
||||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
|
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
|
||||||
|
|
||||||
removeVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iqn), storageHost, storagePort, trimIqn(iqn));
|
removeVmfsDatastore(hyperHost, datastoreName, storageHost, storagePort, trimIqn(iqn));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
|
||||||
|
handleDatastoreAndVmdkDetach(VmwareResource.getDatastoreName(iqn), iqn, storageHost, storagePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeManagedTargetsFromCluster(List<String> iqns) throws Exception {
|
private void removeManagedTargetsFromCluster(List<String> iqns) throws Exception {
|
||||||
|
|||||||
@ -53,7 +53,6 @@ import org.apache.log4j.Logger;
|
|||||||
import org.apache.xmlrpc.XmlRpcException;
|
import org.apache.xmlrpc.XmlRpcException;
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.CreateStoragePoolCommand;
|
|
||||||
import com.cloud.agent.api.to.DataObjectType;
|
import com.cloud.agent.api.to.DataObjectType;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
@ -66,7 +65,6 @@ import com.cloud.exception.InternalErrorException;
|
|||||||
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.SRType;
|
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.SRType;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
import com.cloud.storage.Storage.StoragePoolType;
|
|
||||||
import com.cloud.storage.resource.StorageProcessor;
|
import com.cloud.storage.resource.StorageProcessor;
|
||||||
import com.cloud.utils.S3Utils;
|
import com.cloud.utils.S3Utils;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
@ -76,7 +74,6 @@ import com.cloud.utils.storage.encoding.Decoder;
|
|||||||
import com.xensource.xenapi.Connection;
|
import com.xensource.xenapi.Connection;
|
||||||
import com.xensource.xenapi.Host;
|
import com.xensource.xenapi.Host;
|
||||||
import com.xensource.xenapi.PBD;
|
import com.xensource.xenapi.PBD;
|
||||||
import com.xensource.xenapi.Pool;
|
|
||||||
import com.xensource.xenapi.SR;
|
import com.xensource.xenapi.SR;
|
||||||
import com.xensource.xenapi.Types;
|
import com.xensource.xenapi.Types;
|
||||||
import com.xensource.xenapi.Types.BadServerResponse;
|
import com.xensource.xenapi.Types.BadServerResponse;
|
||||||
@ -572,150 +569,6 @@ public class XenServerStorageProcessor implements StorageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SR getIscsiSR(Connection conn, StorageFilerTO pool) {
|
|
||||||
synchronized (pool.getUuid().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";
|
|
||||||
s_logger.warn(msg);
|
|
||||||
throw new CloudRuntimeException(msg);
|
|
||||||
}
|
|
||||||
String targetiqn = tmp[1].trim();
|
|
||||||
String lunid = tmp[2].trim();
|
|
||||||
String scsiid = "";
|
|
||||||
|
|
||||||
Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
|
|
||||||
for (SR sr : srs) {
|
|
||||||
if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Set<PBD> pbds = sr.getPBDs(conn);
|
|
||||||
if (pbds.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PBD pbd = pbds.iterator().next();
|
|
||||||
Map<String, String> dc = pbd.getDeviceConfig(conn);
|
|
||||||
if (dc == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dc.get("target") == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dc.get("targetIQN") == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dc.get("lunid") == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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:" + hypervisorResource.getHost().uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deviceConfig.put("target", target);
|
|
||||||
deviceConfig.put("targetIQN", targetiqn);
|
|
||||||
|
|
||||||
Host host = Host.getByUuid(conn, hypervisorResource.getHost().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, smConfig);
|
|
||||||
} catch (XenAPIException e) {
|
|
||||||
String errmsg = e.toString();
|
|
||||||
if (errmsg.contains("SR_BACKEND_FAILURE_107")) {
|
|
||||||
String lun[] = errmsg.split("<LUN>");
|
|
||||||
boolean found = false;
|
|
||||||
for (int i = 1; i < lun.length; i++) {
|
|
||||||
int blunindex = lun[i].indexOf("<LUNid>") + 7;
|
|
||||||
int elunindex = lun[i].indexOf("</LUNid>");
|
|
||||||
String ilun = lun[i].substring(blunindex, elunindex);
|
|
||||||
ilun = ilun.trim();
|
|
||||||
if (ilun.equals(lunid)) {
|
|
||||||
int bscsiindex = lun[i].indexOf("<SCSIid>") + 8;
|
|
||||||
int escsiindex = lun[i].indexOf("</SCSIid>");
|
|
||||||
scsiid = lun[i].substring(bscsiindex, escsiindex);
|
|
||||||
scsiid = scsiid.trim();
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
String msg = "can not find LUN " + lunid + " in " + errmsg;
|
|
||||||
s_logger.warn(msg);
|
|
||||||
throw new CloudRuntimeException(msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString();
|
|
||||||
s_logger.warn(msg, e);
|
|
||||||
throw new CloudRuntimeException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deviceConfig.put("SCSIid", scsiid);
|
|
||||||
|
|
||||||
String result = SR.probe(conn, host, deviceConfig, type, smConfig);
|
|
||||||
String pooluuid = null;
|
|
||||||
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, smConfig);
|
|
||||||
} 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.scan(conn);
|
|
||||||
return sr;
|
|
||||||
} catch (XenAPIException e) {
|
|
||||||
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString();
|
|
||||||
s_logger.warn(msg, e);
|
|
||||||
throw new CloudRuntimeException(msg, e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.getMessage();
|
|
||||||
s_logger.warn(msg, e);
|
|
||||||
throw new CloudRuntimeException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Answer execute(CreateStoragePoolCommand cmd) {
|
|
||||||
Connection conn = hypervisorResource.getConnection();
|
|
||||||
StorageFilerTO pool = cmd.getPool();
|
|
||||||
try {
|
|
||||||
if (pool.getType() == StoragePoolType.NetworkFilesystem) {
|
|
||||||
getNfsSR(conn, pool);
|
|
||||||
} else if (pool.getType() == StoragePoolType.IscsiLUN) {
|
|
||||||
getIscsiSR(conn, pool);
|
|
||||||
} else if (pool.getType() == StoragePoolType.PreSetup) {
|
|
||||||
} else {
|
|
||||||
return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
|
|
||||||
}
|
|
||||||
return new Answer(cmd, true, "success");
|
|
||||||
} catch (Exception e) {
|
|
||||||
String msg =
|
|
||||||
"Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" +
|
|
||||||
hypervisorResource.getHost().uuid + " pool: " + pool.getHost() + pool.getPath();
|
|
||||||
s_logger.warn(msg, e);
|
|
||||||
return new Answer(cmd, false, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
|
protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
|
||||||
Connection conn = hypervisorResource.getConnection();
|
Connection conn = hypervisorResource.getConnection();
|
||||||
SR poolsr = null;
|
SR poolsr = null;
|
||||||
|
|||||||
@ -20,6 +20,11 @@
|
|||||||
<relativePath>../../../pom.xml</relativePath>
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cloudstack</groupId>
|
||||||
|
<artifactId>cloud-plugin-storage-volume-default</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.cloudstack</groupId>
|
<groupId>org.apache.cloudstack</groupId>
|
||||||
<artifactId>cloud-engine-storage-volume</artifactId>
|
<artifactId>cloud-engine-storage-volume</artifactId>
|
||||||
|
|||||||
@ -29,5 +29,7 @@
|
|||||||
|
|
||||||
<bean id="solidFireDataStoreProvider"
|
<bean id="solidFireDataStoreProvider"
|
||||||
class="org.apache.cloudstack.storage.datastore.provider.SolidfirePrimaryDataStoreProvider" />
|
class="org.apache.cloudstack.storage.datastore.provider.SolidfirePrimaryDataStoreProvider" />
|
||||||
|
<bean id="solidFireSharedDataStoreProvider"
|
||||||
|
class="org.apache.cloudstack.storage.datastore.provider.SolidFireSharedPrimaryDataStoreProvider" />
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@ -0,0 +1,65 @@
|
|||||||
|
// 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.driver;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||||
|
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||||
|
import org.apache.cloudstack.storage.command.CommandResult;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.agent.api.to.DataTO;
|
||||||
|
|
||||||
|
public class SolidFireSharedPrimaryDataStoreDriver extends CloudStackPrimaryDataStoreDriverImpl {
|
||||||
|
@Override
|
||||||
|
public DataTO getTO(DataObject data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStoreTO getStoreTO(DataStore store) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCopy(DataObject srcData, DataObject destData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,15 +17,11 @@
|
|||||||
package org.apache.cloudstack.storage.datastore.driver;
|
package org.apache.cloudstack.storage.datastore.driver;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
||||||
@ -57,23 +53,20 @@ import com.cloud.storage.StoragePool;
|
|||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
|
||||||
import com.cloud.user.AccountDetailVO;
|
import com.cloud.user.AccountDetailVO;
|
||||||
import com.cloud.user.AccountDetailsDao;
|
import com.cloud.user.AccountDetailsDao;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
|
||||||
|
|
||||||
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||||
@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 AccountDao _accountDao;
|
||||||
@Inject private AccountDetailsDao _accountDetailsDao;
|
@Inject private AccountDetailsDao _accountDetailsDao;
|
||||||
@Inject private ClusterDetailsDao _clusterDetailsDao;
|
@Inject private ClusterDetailsDao _clusterDetailsDao;
|
||||||
|
@Inject private DataCenterDao _zoneDao;
|
||||||
@Inject private HostDao _hostDao;
|
@Inject private HostDao _hostDao;
|
||||||
|
@Inject private PrimaryDataStoreDao _storagePoolDao;
|
||||||
|
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||||
|
@Inject private VolumeDao _volumeDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getCapabilities() {
|
public Map<String, String> getCapabilities() {
|
||||||
@ -90,131 +83,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SolidFireConnection {
|
private SolidFireUtil.SolidFireAccount createSolidFireAccount(SolidFireUtil.SolidFireConnection sfConnection, String sfAccountName) {
|
||||||
private final String _managementVip;
|
long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName);
|
||||||
private final int _managementPort;
|
|
||||||
private final String _clusterAdminUsername;
|
|
||||||
private final String _clusterAdminPassword;
|
|
||||||
|
|
||||||
public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) {
|
return SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber);
|
||||||
_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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
|
|
||||||
AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
|
|
||||||
SolidFireUtil.ACCOUNT_ID,
|
|
||||||
String.valueOf(sfAccount.getId()));
|
|
||||||
|
|
||||||
_accountDetailsDao.persist(accountDetail);
|
|
||||||
|
|
||||||
accountDetail = new AccountDetailVO(csAccountId,
|
|
||||||
SolidFireUtil.CHAP_INITIATOR_USERNAME,
|
|
||||||
String.valueOf(sfAccount.getName()));
|
|
||||||
|
|
||||||
_accountDetailsDao.persist(accountDetail);
|
|
||||||
|
|
||||||
accountDetail = new AccountDetailVO(csAccountId,
|
|
||||||
SolidFireUtil.CHAP_INITIATOR_SECRET,
|
|
||||||
String.valueOf(sfAccount.getInitiatorSecret()));
|
|
||||||
|
|
||||||
_accountDetailsDao.persist(accountDetail);
|
|
||||||
|
|
||||||
accountDetail = new AccountDetailVO(csAccountId,
|
|
||||||
SolidFireUtil.CHAP_TARGET_USERNAME,
|
|
||||||
sfAccount.getName());
|
|
||||||
|
|
||||||
_accountDetailsDao.persist(accountDetail);
|
|
||||||
|
|
||||||
accountDetail = new AccountDetailVO(csAccountId,
|
|
||||||
SolidFireUtil.CHAP_TARGET_SECRET,
|
|
||||||
sfAccount.getTargetSecret());
|
|
||||||
|
|
||||||
_accountDetailsDao.persist(accountDetail);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInitiatorUsername() {
|
|
||||||
return _initiatorUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInitiatorSecret() {
|
|
||||||
return _initiatorSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTargetUsername() {
|
|
||||||
return _targetUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTargetSecret() {
|
|
||||||
return _targetSecret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -222,38 +94,13 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups)
|
// get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups)
|
||||||
// if the VAG exists
|
// if the VAG exists
|
||||||
// update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup)
|
// update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup)
|
||||||
// if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup)
|
// if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup)
|
||||||
// if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup)
|
// if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup)
|
||||||
@Override
|
@Override
|
||||||
public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
|
public synchronized boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
|
||||||
{
|
{
|
||||||
if (volumeInfo == null || host == null || dataStore == null) {
|
if (volumeInfo == null || host == null || dataStore == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -263,111 +110,38 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
long clusterId = host.getClusterId();
|
long clusterId = host.getClusterId();
|
||||||
long storagePoolId = dataStore.getId();
|
long storagePoolId = dataStore.getId();
|
||||||
|
|
||||||
ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
|
ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
|
||||||
|
|
||||||
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
|
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
|
||||||
|
|
||||||
List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
|
List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
|
||||||
|
|
||||||
if (!hostsSupport_iScsi(hosts)) {
|
if (!SolidFireUtil.hostsSupport_iScsi(hosts)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
if (vagId != null) {
|
if (vagId != null) {
|
||||||
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
|
|
||||||
|
|
||||||
String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
|
String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts));
|
||||||
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
|
long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
|
||||||
|
|
||||||
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds);
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
|
|
||||||
hostIqns, volumeIds);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
long lVagId;
|
SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, hosts, _clusterDetailsDao);
|
||||||
|
|
||||||
try {
|
|
||||||
lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(),
|
|
||||||
getIqnsFromHosts(hosts), new long[] { sfVolumeId });
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator";
|
|
||||||
|
|
||||||
if (!ex.getMessage().contains(iqnInVagAlready)) {
|
|
||||||
throw new CloudRuntimeException(ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCompatibleVag throws an exception if an existing VAG can't be located
|
|
||||||
SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(hosts, sfConnection);
|
|
||||||
|
|
||||||
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
|
|
||||||
|
|
||||||
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
|
|
||||||
sfVag.getInitiators(), volumeIds);
|
|
||||||
|
|
||||||
lVagId = sfVag.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId));
|
|
||||||
|
|
||||||
_clusterDetailsDao.persist(clusterDetail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method takes in a collection of hosts and tries to find an existing VAG that has all three of them in it
|
|
||||||
// if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin
|
|
||||||
private SolidFireUtil.SolidFireVag getCompatibleVag(List<HostVO> hosts, SolidFireConnection sfConnection) {
|
|
||||||
List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
|
|
||||||
|
|
||||||
if (sfVags != null) {
|
|
||||||
List<String> hostIqns = new ArrayList<String>();
|
|
||||||
|
|
||||||
// where the method we're in is called, hosts should not be null
|
|
||||||
for (HostVO host : hosts) {
|
|
||||||
// where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn")
|
|
||||||
hostIqns.add(host.getStorageUrl().toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (SolidFireUtil.SolidFireVag sfVag : sfVags) {
|
|
||||||
List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators());
|
|
||||||
|
|
||||||
// lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null
|
|
||||||
if (lstInitiators.containsAll(hostIqns)) {
|
|
||||||
return sfVag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group");
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getStringArrayAsLowerCaseStringList(String[] aString) {
|
|
||||||
List<String> lstLowerCaseString = new ArrayList<String>();
|
|
||||||
|
|
||||||
if (aString != null) {
|
|
||||||
for (String str : aString) {
|
|
||||||
if (str != null) {
|
|
||||||
lstLowerCaseString.add(str.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstLowerCaseString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP
|
// get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP
|
||||||
// if the VAG exists
|
// if the VAG exists
|
||||||
// remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup)
|
// remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup)
|
||||||
@Override
|
@Override
|
||||||
public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
|
public synchronized void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
|
||||||
{
|
{
|
||||||
if (volumeInfo == null || host == null || dataStore == null) {
|
if (volumeInfo == null || host == null || dataStore == null) {
|
||||||
return;
|
return;
|
||||||
@ -377,135 +151,24 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
long clusterId = host.getClusterId();
|
long clusterId = host.getClusterId();
|
||||||
long storagePoolId = dataStore.getId();
|
long storagePoolId = dataStore.getId();
|
||||||
|
|
||||||
ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
|
ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
|
||||||
|
|
||||||
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
|
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
|
||||||
|
|
||||||
if (vagId != null) {
|
if (vagId != null) {
|
||||||
List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
|
List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
|
||||||
|
|
||||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
|
|
||||||
|
|
||||||
String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
|
String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts));
|
||||||
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
|
long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
|
||||||
|
|
||||||
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
|
SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds);
|
||||||
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
|
|
||||||
hostIqns, volumeIds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hostsSupport_iScsi(List<HostVO> hosts) {
|
|
||||||
if (hosts == null || hosts.size() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Host host : hosts) {
|
|
||||||
if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
|
|
||||||
List<String> lstIqns = new ArrayList<String>();
|
|
||||||
|
|
||||||
if (currentIqns != null) {
|
|
||||||
for (String currentIqn : currentIqns) {
|
|
||||||
lstIqns.add(currentIqn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newIqns != null) {
|
|
||||||
for (String newIqn : newIqns) {
|
|
||||||
if (!lstIqns.contains(newIqn)) {
|
|
||||||
lstIqns.add(newIqn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstIqns.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
|
|
||||||
if (add) {
|
|
||||||
return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) {
|
|
||||||
List<Long> lstVolumeIds = new ArrayList<Long>();
|
|
||||||
|
|
||||||
if (volumeIds != null) {
|
|
||||||
for (long volumeId : volumeIds) {
|
|
||||||
lstVolumeIds.add(volumeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lstVolumeIds.contains(volumeIdToAdd)) {
|
|
||||||
return volumeIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
lstVolumeIds.add(volumeIdToAdd);
|
|
||||||
|
|
||||||
return convertArray(lstVolumeIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) {
|
|
||||||
List<Long> lstVolumeIds = new ArrayList<Long>();
|
|
||||||
|
|
||||||
if (volumeIds != null) {
|
|
||||||
for (long volumeId : volumeIds) {
|
|
||||||
lstVolumeIds.add(volumeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lstVolumeIds.remove(volumeIdToRemove);
|
|
||||||
|
|
||||||
return convertArray(lstVolumeIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long[] convertArray(List<Long> items) {
|
|
||||||
if (items == null) {
|
|
||||||
return new long[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
long[] outArray = new long[items.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
|
||||||
Long value = items.get(i);
|
|
||||||
|
|
||||||
outArray[i] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return outArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getVagKey(long storagePoolId) {
|
|
||||||
return "sfVolumeAccessGroup_" + storagePoolId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getIqnsFromHosts(List<? extends Host> hosts) {
|
|
||||||
if (hosts == null || hosts.size() == 0) {
|
|
||||||
throw new CloudRuntimeException("There do not appear to be any hosts in this cluster.");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> lstIqns = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (Host host : hosts) {
|
|
||||||
lstIqns.add(host.getStorageUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstIqns.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getDefaultMinIops(long storagePoolId) {
|
private long getDefaultMinIops(long storagePoolId) {
|
||||||
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
|
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
|
||||||
|
|
||||||
@ -532,12 +195,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops);
|
return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) {
|
private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo) {
|
||||||
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);
|
AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID);
|
||||||
long sfAccountId = Long.parseLong(accountDetail.getValue());
|
long sfAccountId = Long.parseLong(accountDetail.getValue());
|
||||||
|
|
||||||
@ -558,12 +216,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
|
|
||||||
long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId));
|
long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId));
|
||||||
|
|
||||||
long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword,
|
long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
|
||||||
getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
|
NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
|
||||||
NumberFormat.getInstance().format(volumeInfo.getSize()),
|
|
||||||
iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
|
|
||||||
|
|
||||||
return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
|
return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -582,24 +238,6 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return volumeSize;
|
return volumeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSolidFireVolumeName(String strCloudStackVolumeName) {
|
|
||||||
final String specialChar = "-";
|
|
||||||
|
|
||||||
StringBuilder strSolidFireVolumeName = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i = 0; i < strCloudStackVolumeName.length(); i++) {
|
|
||||||
String strChar = strCloudStackVolumeName.substring(i, i + 1);
|
|
||||||
|
|
||||||
if (StringUtils.isAlphanumeric(strChar)) {
|
|
||||||
strSolidFireVolumeName.append(strChar);
|
|
||||||
} else {
|
|
||||||
strSolidFireVolumeName.append(specialChar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strSolidFireVolumeName.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Iops {
|
private static class Iops {
|
||||||
private final long _minIops;
|
private final long _minIops;
|
||||||
private final long _maxIops;
|
private final long _maxIops;
|
||||||
@ -636,7 +274,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
|
private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo)
|
||||||
{
|
{
|
||||||
Long storagePoolId = volumeInfo.getPoolId();
|
Long storagePoolId = volumeInfo.getPoolId();
|
||||||
|
|
||||||
@ -644,33 +282,9 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return null; // this volume was never assigned to a storage pool, so no SAN volume should exist for it
|
return null; // 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());
|
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
|
||||||
|
|
||||||
return SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
|
return SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
|
||||||
}
|
|
||||||
|
|
||||||
private String getSfAccountName(String csAccountUuid, long csAccountId) {
|
|
||||||
return "CloudStack_" + csAccountUuid + "_" + csAccountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean sfAccountExists(String sfAccountName, SolidFireConnection sfConnection) {
|
|
||||||
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
|
@Override
|
||||||
@ -681,18 +295,18 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
if (dataObject.getType() == DataObjectType.VOLUME) {
|
if (dataObject.getType() == DataObjectType.VOLUME) {
|
||||||
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
|
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
|
||||||
AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
|
AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
|
||||||
String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId());
|
String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId());
|
||||||
|
|
||||||
long storagePoolId = dataStore.getId();
|
long storagePoolId = dataStore.getId();
|
||||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
if (!sfAccountExists(sfAccountName, sfConnection)) {
|
if (SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName) == null) {
|
||||||
SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName, sfConnection);
|
SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
|
||||||
|
|
||||||
updateCsDbWithAccountInfo(account.getId(), sfAccount);
|
SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, _accountDetailsDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection);
|
SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo);
|
||||||
|
|
||||||
iqn = sfVolume.getIqn();
|
iqn = sfVolume.getIqn();
|
||||||
|
|
||||||
@ -728,74 +342,20 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
callback.complete(result);
|
callback.complete(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
|
|
||||||
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) {
|
|
||||||
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
|
@Override
|
||||||
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
|
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
|
||||||
String errMsg = null;
|
String errMsg = null;
|
||||||
|
|
||||||
if (dataObject.getType() == DataObjectType.VOLUME) {
|
if (dataObject.getType() == DataObjectType.VOLUME) {
|
||||||
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
|
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();
|
long storagePoolId = dataStore.getId();
|
||||||
SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(volumeInfo, sfConnection);
|
SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(sfConnection, volumeInfo);
|
||||||
|
|
||||||
_volumeDao.deleteVolumesByInstance(volumeInfo.getId());
|
_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);
|
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
|
||||||
|
|
||||||
long usedBytes = storagePool.getUsedBytes();
|
long usedBytes = storagePool.getUsedBytes();
|
||||||
|
|||||||
@ -21,7 +21,6 @@ package org.apache.cloudstack.storage.datastore.lifecycle;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCy
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
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.datastore.util.SolidFireUtil;
|
||||||
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
||||||
|
|
||||||
@ -61,14 +59,9 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
@Inject
|
@Inject
|
||||||
private ResourceManager _resourceMgr;
|
private ResourceManager _resourceMgr;
|
||||||
@Inject
|
@Inject
|
||||||
StorageManager _storageMgr;
|
private StorageManager _storageMgr;
|
||||||
@Inject
|
@Inject
|
||||||
private StoragePoolAutomation storagePoolAutomation;
|
private StoragePoolAutomation storagePoolAutomation;
|
||||||
@Inject
|
|
||||||
private StoragePoolDetailsDao storagePoolDetailsDao;
|
|
||||||
|
|
||||||
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
|
// invoked to add primary storage that is based on the SolidFire plug-in
|
||||||
@Override
|
@Override
|
||||||
@ -80,10 +73,11 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
||||||
String tags = (String)dsInfos.get("tags");
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
String storageVip = getStorageVip(url);
|
String storageVip = SolidFireUtil.getStorageVip(url);
|
||||||
int storagePort = getStoragePort(url);
|
int storagePort = SolidFireUtil.getStoragePort(url);
|
||||||
|
|
||||||
DataCenterVO zone = zoneDao.findById(zoneId);
|
DataCenterVO zone = zoneDao.findById(zoneId);
|
||||||
|
|
||||||
@ -101,7 +95,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
|
|
||||||
parameters.setHost(storageVip);
|
parameters.setHost(storageVip);
|
||||||
parameters.setPort(storagePort);
|
parameters.setPort(storagePort);
|
||||||
parameters.setPath(getModifiedUrl(url));
|
parameters.setPath(SolidFireUtil.getModifiedUrl(url));
|
||||||
parameters.setType(StoragePoolType.Iscsi);
|
parameters.setType(StoragePoolType.Iscsi);
|
||||||
parameters.setUuid(uuid);
|
parameters.setUuid(uuid);
|
||||||
parameters.setZoneId(zoneId);
|
parameters.setZoneId(zoneId);
|
||||||
@ -115,14 +109,14 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
|
|
||||||
String managementVip = getManagementVip(url);
|
String managementVip = SolidFireUtil.getManagementVip(url);
|
||||||
int managementPort = getManagementPort(url);
|
int managementPort = SolidFireUtil.getManagementPort(url);
|
||||||
|
|
||||||
details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
|
details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
|
||||||
details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
|
details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
|
||||||
|
|
||||||
String clusterAdminUsername = getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
|
String clusterAdminUsername = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
|
||||||
String clusterAdminPassword = getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
|
String clusterAdminPassword = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
|
||||||
|
|
||||||
details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
|
details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
|
||||||
details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
|
details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
|
||||||
@ -132,7 +126,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
float fClusterDefaultBurstIopsPercentOfMaxIops = 1.5f;
|
float fClusterDefaultBurstIopsPercentOfMaxIops = 1.5f;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String clusterDefaultMinIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS, url);
|
String clusterDefaultMinIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS, url);
|
||||||
|
|
||||||
if (clusterDefaultMinIops != null && clusterDefaultMinIops.trim().length() > 0) {
|
if (clusterDefaultMinIops != null && clusterDefaultMinIops.trim().length() > 0) {
|
||||||
lClusterDefaultMinIops = Long.parseLong(clusterDefaultMinIops);
|
lClusterDefaultMinIops = Long.parseLong(clusterDefaultMinIops);
|
||||||
@ -144,7 +138,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String clusterDefaultMaxIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, url);
|
String clusterDefaultMaxIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, url);
|
||||||
|
|
||||||
if (clusterDefaultMaxIops != null && clusterDefaultMaxIops.trim().length() > 0) {
|
if (clusterDefaultMaxIops != null && clusterDefaultMaxIops.trim().length() > 0) {
|
||||||
lClusterDefaultMaxIops = Long.parseLong(clusterDefaultMaxIops);
|
lClusterDefaultMaxIops = Long.parseLong(clusterDefaultMaxIops);
|
||||||
@ -156,7 +150,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String clusterDefaultBurstIopsPercentOfMaxIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, url);
|
String clusterDefaultBurstIopsPercentOfMaxIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, url);
|
||||||
|
|
||||||
if (clusterDefaultBurstIopsPercentOfMaxIops != null && clusterDefaultBurstIopsPercentOfMaxIops.trim().length() > 0) {
|
if (clusterDefaultBurstIopsPercentOfMaxIops != null && clusterDefaultBurstIopsPercentOfMaxIops.trim().length() > 0) {
|
||||||
fClusterDefaultBurstIopsPercentOfMaxIops = Float.parseFloat(clusterDefaultBurstIopsPercentOfMaxIops);
|
fClusterDefaultBurstIopsPercentOfMaxIops = Float.parseFloat(clusterDefaultBurstIopsPercentOfMaxIops);
|
||||||
@ -168,7 +162,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lClusterDefaultMinIops > lClusterDefaultMaxIops) {
|
if (lClusterDefaultMinIops > lClusterDefaultMaxIops) {
|
||||||
throw new CloudRuntimeException("The parameter '" + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + "' must be less than " + "or equal to the parameter '" +
|
throw new CloudRuntimeException("The parameter '" + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + "' must be less than or equal to the parameter '" +
|
||||||
SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + "'.");
|
SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + "'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,111 +178,6 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
return dataStoreHelper.createPrimaryDataStore(parameters);
|
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().toUpperCase();
|
|
||||||
|
|
||||||
if (token.startsWith(SolidFireUtil.MANAGEMENT_VIP.toUpperCase()) || token.startsWith(SolidFireUtil.STORAGE_VIP.toUpperCase())) {
|
|
||||||
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
|
// do not implement this method for SolidFire's plug-in
|
||||||
@Override
|
@Override
|
||||||
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
||||||
|
|||||||
@ -0,0 +1,548 @@
|
|||||||
|
/*
|
||||||
|
* 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.text.NumberFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
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.PrimaryDataStoreInfo;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
|
||||||
|
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
||||||
|
|
||||||
|
import com.cloud.template.TemplateManager;
|
||||||
|
import com.cloud.user.AccountDetailsDao;
|
||||||
|
import com.cloud.user.AccountVO;
|
||||||
|
import com.cloud.agent.AgentManager;
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||||
|
import com.cloud.agent.api.DeleteStoragePoolCommand;
|
||||||
|
import com.cloud.agent.api.StoragePoolInfo;
|
||||||
|
import com.cloud.dc.ClusterDetailsDao;
|
||||||
|
import com.cloud.dc.ClusterVO;
|
||||||
|
import com.cloud.dc.dao.ClusterDao;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.resource.ResourceManager;
|
||||||
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
|
import com.cloud.storage.StorageManager;
|
||||||
|
import com.cloud.storage.StoragePool;
|
||||||
|
import com.cloud.storage.StoragePoolAutomation;
|
||||||
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.dao.AccountDao;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
|
public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
|
||||||
|
private static final Logger s_logger = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class);
|
||||||
|
|
||||||
|
@Inject private AccountDao _accountDao;
|
||||||
|
@Inject private AccountDetailsDao _accountDetailsDao;
|
||||||
|
@Inject private AgentManager _agentMgr;
|
||||||
|
@Inject private ClusterDao _clusterDao;
|
||||||
|
@Inject private ClusterDetailsDao _clusterDetailsDao;
|
||||||
|
@Inject private DataCenterDao _zoneDao;
|
||||||
|
@Inject private HostDao _hostDao;
|
||||||
|
@Inject private PrimaryDataStoreDao _primaryDataStoreDao;
|
||||||
|
@Inject private PrimaryDataStoreHelper _primaryDataStoreHelper;
|
||||||
|
@Inject private ResourceManager _resourceMgr;
|
||||||
|
@Inject private StorageManager _storageMgr;
|
||||||
|
@Inject private StoragePoolAutomation _storagePoolAutomation;
|
||||||
|
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||||
|
@Inject private StoragePoolHostDao _storagePoolHostDao;
|
||||||
|
@Inject protected TemplateManager _tmpltMgr;
|
||||||
|
|
||||||
|
// invoked to add primary storage that is based on the SolidFire plug-in
|
||||||
|
@Override
|
||||||
|
public DataStore initialize(Map<String, Object> dsInfos) {
|
||||||
|
final String CAPACITY_IOPS = "capacityIops";
|
||||||
|
|
||||||
|
String url = (String)dsInfos.get("url");
|
||||||
|
Long zoneId = (Long)dsInfos.get("zoneId");
|
||||||
|
Long podId = (Long)dsInfos.get("podId");
|
||||||
|
Long clusterId = (Long)dsInfos.get("clusterId");
|
||||||
|
String storagePoolName = (String)dsInfos.get("name");
|
||||||
|
String providerName = (String)dsInfos.get("providerName");
|
||||||
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
|
Long capacityIops = (Long)dsInfos.get(CAPACITY_IOPS);
|
||||||
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
|
if (podId == null) {
|
||||||
|
throw new CloudRuntimeException("The Pod ID must be specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clusterId == null) {
|
||||||
|
throw new CloudRuntimeException("The Cluster ID must be specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String storageVip = SolidFireUtil.getStorageVip(url);
|
||||||
|
int storagePort = SolidFireUtil.getStoragePort(url);
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
HypervisorType hypervisorType = getHypervisorTypeForCluster(clusterId);
|
||||||
|
|
||||||
|
if (!isSupportedHypervisorType(hypervisorType)) {
|
||||||
|
throw new CloudRuntimeException(hypervisorType + " is not a supported hypervisor type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String datacenter = SolidFireUtil.getValue(SolidFireUtil.DATACENTER, url, false);
|
||||||
|
|
||||||
|
if (HypervisorType.VMware.equals(hypervisorType) && datacenter == null) {
|
||||||
|
throw new CloudRuntimeException("'Datacenter' must be set for hypervisor type of " + HypervisorType.VMware);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
|
||||||
|
|
||||||
|
parameters.setType(getStorageType(hypervisorType));
|
||||||
|
parameters.setZoneId(zoneId);
|
||||||
|
parameters.setPodId(podId);
|
||||||
|
parameters.setClusterId(clusterId);
|
||||||
|
parameters.setName(storagePoolName);
|
||||||
|
parameters.setProviderName(providerName);
|
||||||
|
parameters.setManaged(false);
|
||||||
|
parameters.setCapacityBytes(capacityBytes);
|
||||||
|
parameters.setUsedBytes(0);
|
||||||
|
parameters.setCapacityIops(capacityIops);
|
||||||
|
parameters.setHypervisorType(hypervisorType);
|
||||||
|
parameters.setTags(tags);
|
||||||
|
parameters.setDetails(details);
|
||||||
|
|
||||||
|
String managementVip = SolidFireUtil.getManagementVip(url);
|
||||||
|
int managementPort = SolidFireUtil.getManagementPort(url);
|
||||||
|
|
||||||
|
details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
|
||||||
|
details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
|
||||||
|
|
||||||
|
String clusterAdminUsername = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
|
||||||
|
String clusterAdminPassword = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
|
||||||
|
|
||||||
|
details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
|
||||||
|
details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
|
||||||
|
|
||||||
|
long lMinIops = 100;
|
||||||
|
long lMaxIops = 15000;
|
||||||
|
long lBurstIops = 15000;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String minIops = SolidFireUtil.getValue(SolidFireUtil.MIN_IOPS, url);
|
||||||
|
|
||||||
|
if (minIops != null && minIops.trim().length() > 0) {
|
||||||
|
lMinIops = Long.parseLong(minIops);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String maxIops = SolidFireUtil.getValue(SolidFireUtil.MAX_IOPS, url);
|
||||||
|
|
||||||
|
if (maxIops != null && maxIops.trim().length() > 0) {
|
||||||
|
lMaxIops = Long.parseLong(maxIops);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String burstIops = SolidFireUtil.getValue(SolidFireUtil.BURST_IOPS, url);
|
||||||
|
|
||||||
|
if (burstIops != null && burstIops.trim().length() > 0) {
|
||||||
|
lBurstIops = Long.parseLong(burstIops);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lMinIops > lMaxIops) {
|
||||||
|
throw new CloudRuntimeException("The parameter '" + SolidFireUtil.MIN_IOPS + "' must be less than or equal to the parameter '" + SolidFireUtil.MAX_IOPS + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lMaxIops > lBurstIops) {
|
||||||
|
throw new CloudRuntimeException("The parameter '" + SolidFireUtil.MAX_IOPS + "' must be less than or equal to the parameter '" + SolidFireUtil.BURST_IOPS + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lMinIops != capacityIops) {
|
||||||
|
throw new CloudRuntimeException("The parameter '" + CAPACITY_IOPS + "' must be equal to the parameter '" + SolidFireUtil.MIN_IOPS + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
details.put(SolidFireUtil.MIN_IOPS, String.valueOf(lMinIops));
|
||||||
|
details.put(SolidFireUtil.MAX_IOPS, String.valueOf(lMaxIops));
|
||||||
|
details.put(SolidFireUtil.BURST_IOPS, String.valueOf(lBurstIops));
|
||||||
|
|
||||||
|
SolidFireUtil.SolidFireConnection sfConnection = new SolidFireUtil.SolidFireConnection(managementVip, managementPort, clusterAdminUsername, clusterAdminPassword);
|
||||||
|
|
||||||
|
SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, storagePoolName, capacityBytes, lMinIops, lMaxIops, lBurstIops);
|
||||||
|
|
||||||
|
String iqn = sfVolume.getIqn();
|
||||||
|
|
||||||
|
details.put(SolidFireUtil.VOLUME_ID, String.valueOf(sfVolume.getId()));
|
||||||
|
|
||||||
|
parameters.setUuid(iqn);
|
||||||
|
|
||||||
|
if (HypervisorType.VMware.equals(hypervisorType)) {
|
||||||
|
String datastore = iqn.replace("/", "_");
|
||||||
|
String path = "/" + datacenter + "/" + datastore;
|
||||||
|
|
||||||
|
parameters.setHost("VMFS datastore: " + path);
|
||||||
|
parameters.setPort(0);
|
||||||
|
parameters.setPath(path);
|
||||||
|
|
||||||
|
details.put(SolidFireUtil.DATASTORE_NAME, datastore);
|
||||||
|
details.put(SolidFireUtil.IQN, iqn);
|
||||||
|
details.put(SolidFireUtil.STORAGE_VIP, storageVip);
|
||||||
|
details.put(SolidFireUtil.STORAGE_PORT, String.valueOf(storagePort));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parameters.setHost(storageVip);
|
||||||
|
parameters.setPort(storagePort);
|
||||||
|
parameters.setPath(iqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this adds a row in the cloud.storage_pool table for this SolidFire volume
|
||||||
|
DataStore dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters);
|
||||||
|
|
||||||
|
// now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and
|
||||||
|
// place the newly created volume in the Volume Access Group
|
||||||
|
try {
|
||||||
|
List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
|
||||||
|
|
||||||
|
SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), hosts, _clusterDetailsDao);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
_primaryDataStoreDao.expunge(dataStore.getId());
|
||||||
|
|
||||||
|
throw new CloudRuntimeException(ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HypervisorType getHypervisorTypeForCluster(long clusterId) {
|
||||||
|
ClusterVO cluster = _clusterDao.findById(clusterId);
|
||||||
|
|
||||||
|
if (cluster == null) {
|
||||||
|
throw new CloudRuntimeException("Cluster ID '" + clusterId + "' was not found in the database.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return cluster.getHypervisorType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private StoragePoolType getStorageType(HypervisorType hypervisorType) {
|
||||||
|
if (HypervisorType.XenServer.equals(hypervisorType)) {
|
||||||
|
return StoragePoolType.IscsiLUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HypervisorType.VMware.equals(hypervisorType)) {
|
||||||
|
return StoragePoolType.VMFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CloudRuntimeException("The 'hypervisor' parameter must be '" + HypervisorType.XenServer + "' or '" + HypervisorType.VMware + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection,
|
||||||
|
String volumeName, long volumeSize, long minIops, long maxIops, long burstIops) {
|
||||||
|
try {
|
||||||
|
Account csAccount = CallContext.current().getCallingAccount();
|
||||||
|
long csAccountId = csAccount.getId();
|
||||||
|
AccountVO accountVo = _accountDao.findById(csAccountId);
|
||||||
|
|
||||||
|
String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId);
|
||||||
|
|
||||||
|
SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName);
|
||||||
|
|
||||||
|
if (sfAccount == null) {
|
||||||
|
long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName);
|
||||||
|
|
||||||
|
sfAccount = SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber);
|
||||||
|
|
||||||
|
SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccountId, sfAccount, _accountDetailsDao);
|
||||||
|
}
|
||||||
|
|
||||||
|
long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize,
|
||||||
|
true, NumberFormat.getInstance().format(volumeSize), minIops, maxIops, burstIops);
|
||||||
|
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
|
||||||
|
|
||||||
|
return sfVolume;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new CloudRuntimeException("Failed to create a SolidFire volume: " + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean attachCluster(DataStore store, ClusterScope scope) {
|
||||||
|
PrimaryDataStoreInfo primaryDataStoreInfo = (PrimaryDataStoreInfo)store;
|
||||||
|
|
||||||
|
// check if there is at least one host up in this cluster
|
||||||
|
List<HostVO> allHosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, primaryDataStoreInfo.getClusterId(),
|
||||||
|
primaryDataStoreInfo.getPodId(), primaryDataStoreInfo.getDataCenterId());
|
||||||
|
|
||||||
|
if (allHosts.isEmpty()) {
|
||||||
|
_primaryDataStoreDao.expunge(primaryDataStoreInfo.getId());
|
||||||
|
|
||||||
|
throw new CloudRuntimeException("No host up to associate a storage pool with in cluster " + primaryDataStoreInfo.getClusterId());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
for (HostVO host : allHosts) {
|
||||||
|
success = createStoragePool(host, primaryDataStoreInfo);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
throw new CloudRuntimeException("Unable to create storage in cluster " + primaryDataStoreInfo.getClusterId());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<HostVO> poolHosts = new ArrayList<HostVO>();
|
||||||
|
|
||||||
|
for (HostVO host : allHosts) {
|
||||||
|
try {
|
||||||
|
_storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId());
|
||||||
|
|
||||||
|
poolHosts.add(host);
|
||||||
|
} catch (Exception e) {
|
||||||
|
s_logger.warn("Unable to establish a connection between " + host + " and " + primaryDataStoreInfo, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poolHosts.isEmpty()) {
|
||||||
|
s_logger.warn("No host can access storage pool '" + primaryDataStoreInfo + "' on cluster '" + primaryDataStoreInfo.getClusterId() + "'.");
|
||||||
|
|
||||||
|
_primaryDataStoreDao.expunge(primaryDataStoreInfo.getId());
|
||||||
|
|
||||||
|
throw new CloudRuntimeException("Failed to access storage pool");
|
||||||
|
}
|
||||||
|
|
||||||
|
_primaryDataStoreHelper.attachCluster(store);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean createStoragePool(HostVO host, StoragePool storagePool) {
|
||||||
|
long hostId = host.getId();
|
||||||
|
HypervisorType hypervisorType = host.getHypervisorType();
|
||||||
|
CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, storagePool);
|
||||||
|
|
||||||
|
if (HypervisorType.VMware.equals(hypervisorType)) {
|
||||||
|
cmd.setCreateDatastore(true);
|
||||||
|
|
||||||
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
|
||||||
|
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME);
|
||||||
|
|
||||||
|
details.put(CreateStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN);
|
||||||
|
|
||||||
|
details.put(CreateStoragePoolCommand.IQN, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP);
|
||||||
|
|
||||||
|
details.put(CreateStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT);
|
||||||
|
|
||||||
|
details.put(CreateStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
cmd.setDetails(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
Answer answer = _agentMgr.easySend(hostId, cmd);
|
||||||
|
|
||||||
|
if (answer != null && answer.getResult()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
_primaryDataStoreDao.expunge(storagePool.getId());
|
||||||
|
|
||||||
|
String msg = "";
|
||||||
|
|
||||||
|
if (answer != null) {
|
||||||
|
msg = "Cannot create storage pool through host '" + hostId + "' due to the following: " + answer.getDetails();
|
||||||
|
} else {
|
||||||
|
msg = "Cannot create storage pool through host '" + hostId + "' due to CreateStoragePoolCommand returns null";
|
||||||
|
}
|
||||||
|
|
||||||
|
s_logger.warn(msg);
|
||||||
|
|
||||||
|
throw new CloudRuntimeException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean maintain(DataStore dataStore) {
|
||||||
|
_storagePoolAutomation.maintain(dataStore);
|
||||||
|
_primaryDataStoreHelper.maintain(dataStore);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cancelMaintain(DataStore store) {
|
||||||
|
_primaryDataStoreHelper.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 dataStore) {
|
||||||
|
List<StoragePoolHostVO> hostPoolRecords = _storagePoolHostDao.listByPoolId(dataStore.getId());
|
||||||
|
|
||||||
|
HypervisorType hypervisorType = null;
|
||||||
|
|
||||||
|
if (hostPoolRecords.size() > 0 ) {
|
||||||
|
hypervisorType = getHypervisorType(hostPoolRecords.get(0).getHostId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSupportedHypervisorType(hypervisorType)) {
|
||||||
|
throw new CloudRuntimeException(hypervisorType + " is not a supported hypervisor type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
StoragePool storagePool = (StoragePool)dataStore;
|
||||||
|
StoragePoolVO storagePoolVO = _primaryDataStoreDao.findById(storagePool.getId());
|
||||||
|
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = _tmpltMgr.getUnusedTemplatesInPool(storagePoolVO);
|
||||||
|
|
||||||
|
for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
|
||||||
|
_tmpltMgr.evictTemplateFromStoragePool(templatePoolVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StoragePoolHostVO host : hostPoolRecords) {
|
||||||
|
DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(storagePool);
|
||||||
|
|
||||||
|
if (HypervisorType.VMware.equals(hypervisorType)) {
|
||||||
|
deleteCmd.setRemoveDatastore(true);
|
||||||
|
|
||||||
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
|
||||||
|
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME);
|
||||||
|
|
||||||
|
details.put(DeleteStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN);
|
||||||
|
|
||||||
|
details.put(DeleteStoragePoolCommand.IQN, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP);
|
||||||
|
|
||||||
|
details.put(DeleteStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT);
|
||||||
|
|
||||||
|
details.put(DeleteStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue());
|
||||||
|
|
||||||
|
deleteCmd.setDetails(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd);
|
||||||
|
|
||||||
|
if (answer != null && answer.getResult()) {
|
||||||
|
s_logger.info("Successfully deleted storage pool using Host ID " + host.getHostId());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_logger.error("Failed to delete storage pool using Host ID " + host.getHostId() + ": " + answer.getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSolidFireVolume(storagePool.getId());
|
||||||
|
|
||||||
|
return _primaryDataStoreHelper.deletePrimaryDataStore(dataStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteSolidFireVolume(long storagePoolId) {
|
||||||
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
|
long sfVolumeId = getVolumeId(storagePoolId);
|
||||||
|
|
||||||
|
SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getVolumeId(long storagePoolId) {
|
||||||
|
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.VOLUME_ID);
|
||||||
|
|
||||||
|
String volumeId = storagePoolDetail.getValue();
|
||||||
|
|
||||||
|
return Long.parseLong(volumeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSupportedHypervisorType(HypervisorType hypervisorType) {
|
||||||
|
return HypervisorType.XenServer.equals(hypervisorType) || HypervisorType.VMware.equals(hypervisorType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HypervisorType getHypervisorType(long hostId) {
|
||||||
|
HostVO host = _hostDao.findById(hostId);
|
||||||
|
|
||||||
|
if (host != null) {
|
||||||
|
return host.getHypervisorType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return HypervisorType.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean migrateToObjectStore(DataStore store) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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 javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import com.cloud.agent.AgentManager;
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||||
|
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||||
|
import com.cloud.alert.AlertManager;
|
||||||
|
import com.cloud.storage.DataStoreRole;
|
||||||
|
import com.cloud.storage.StoragePool;
|
||||||
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
|
public class SolidFireSharedHostListener implements HypervisorHostListener {
|
||||||
|
private static final Logger s_logger = Logger.getLogger(DefaultHostListener.class);
|
||||||
|
|
||||||
|
@Inject private AgentManager agentMgr;
|
||||||
|
@Inject private DataStoreManager dataStoreMgr;
|
||||||
|
@Inject private AlertManager alertMgr;
|
||||||
|
@Inject private StoragePoolHostDao storagePoolHostDao;
|
||||||
|
@Inject private PrimaryDataStoreDao primaryStoreDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hostConnect(long hostId, long storagePoolId) {
|
||||||
|
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
|
||||||
|
|
||||||
|
if (storagePoolHost == null) {
|
||||||
|
storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, "");
|
||||||
|
|
||||||
|
storagePoolHostDao.persist(storagePoolHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
|
||||||
|
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool);
|
||||||
|
Answer answer = agentMgr.easySend(hostId, cmd);
|
||||||
|
|
||||||
|
if (answer == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!answer.getResult()) {
|
||||||
|
String msg = "Unable to attach storage pool " + storagePoolId + " to the host " + hostId;
|
||||||
|
|
||||||
|
alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
|
||||||
|
|
||||||
|
throw new CloudRuntimeException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " +
|
||||||
|
storagePool.getId() + "; Host=" + hostId;
|
||||||
|
|
||||||
|
s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hostDisconnected(long hostId, long storagePoolId) {
|
||||||
|
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
|
||||||
|
|
||||||
|
if (storagePoolHost != null) {
|
||||||
|
storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
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.SolidFireSharedPrimaryDataStoreDriver;
|
||||||
|
import org.apache.cloudstack.storage.datastore.lifecycle.SolidFireSharedPrimaryDataStoreLifeCycle;
|
||||||
|
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
|
||||||
|
|
||||||
|
import com.cloud.utils.component.ComponentContext;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SolidFireSharedPrimaryDataStoreProvider implements PrimaryDataStoreProvider {
|
||||||
|
private DataStoreLifeCycle lifecycle;
|
||||||
|
private PrimaryDataStoreDriver driver;
|
||||||
|
private HypervisorHostListener listener;
|
||||||
|
|
||||||
|
SolidFireSharedPrimaryDataStoreProvider() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return SolidFireUtil.SHARED_PROVIDER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStoreLifeCycle getDataStoreLifeCycle() {
|
||||||
|
return lifecycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrimaryDataStoreDriver getDataStoreDriver() {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HypervisorHostListener getHostListener() {
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean configure(Map<String, Object> params) {
|
||||||
|
lifecycle = ComponentContext.inject(SolidFireSharedPrimaryDataStoreLifeCycle.class);
|
||||||
|
driver = ComponentContext.inject(SolidFireSharedPrimaryDataStoreDriver.class);
|
||||||
|
listener = ComponentContext.inject(SolidFireSharedHostListener.class);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<DataStoreProviderType> getTypes() {
|
||||||
|
Set<DataStoreProviderType> types = new HashSet<DataStoreProviderType>();
|
||||||
|
|
||||||
|
types.add(DataStoreProviderType.PRIMARY);
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,11 +29,16 @@ import java.security.cert.CertificateException;
|
|||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.auth.AuthScope;
|
import org.apache.http.auth.AuthScope;
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
@ -49,10 +54,17 @@ import org.apache.http.impl.conn.BasicClientConnectionManager;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import com.cloud.dc.ClusterDetailsDao;
|
||||||
|
import com.cloud.dc.ClusterDetailsVO;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.user.AccountDetailVO;
|
||||||
|
import com.cloud.user.AccountDetailsDao;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
public class SolidFireUtil {
|
public class SolidFireUtil {
|
||||||
public static final String PROVIDER_NAME = "SolidFire";
|
public static final String PROVIDER_NAME = "SolidFire";
|
||||||
|
public static final String SHARED_PROVIDER_NAME = "SolidFireShared";
|
||||||
|
|
||||||
public static final String MANAGEMENT_VIP = "mVip";
|
public static final String MANAGEMENT_VIP = "mVip";
|
||||||
public static final String STORAGE_VIP = "sVip";
|
public static final String STORAGE_VIP = "sVip";
|
||||||
@ -63,11 +75,18 @@ public class SolidFireUtil {
|
|||||||
public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername";
|
public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername";
|
||||||
public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword";
|
public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword";
|
||||||
|
|
||||||
|
// these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.PROVIDER_NAME
|
||||||
public static final String CLUSTER_DEFAULT_MIN_IOPS = "clusterDefaultMinIops";
|
public static final String CLUSTER_DEFAULT_MIN_IOPS = "clusterDefaultMinIops";
|
||||||
public static final String CLUSTER_DEFAULT_MAX_IOPS = "clusterDefaultMaxIops";
|
public static final String CLUSTER_DEFAULT_MAX_IOPS = "clusterDefaultMaxIops";
|
||||||
public static final String CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS = "clusterDefaultBurstIopsPercentOfMaxIops";
|
public static final String CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS = "clusterDefaultBurstIopsPercentOfMaxIops";
|
||||||
|
|
||||||
|
// these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME
|
||||||
|
public static final String MIN_IOPS = "minIops";
|
||||||
|
public static final String MAX_IOPS = "maxIops";
|
||||||
|
public static final String BURST_IOPS = "burstIops";
|
||||||
|
|
||||||
public static final String ACCOUNT_ID = "accountId";
|
public static final String ACCOUNT_ID = "accountId";
|
||||||
|
public static final String VOLUME_ID = "volumeId";
|
||||||
|
|
||||||
public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
|
public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
|
||||||
public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
|
public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
|
||||||
@ -75,18 +94,323 @@ public class SolidFireUtil {
|
|||||||
public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
|
public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
|
||||||
public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
|
public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
|
||||||
|
|
||||||
public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
|
public static final String DATACENTER = "datacenter";
|
||||||
String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize,
|
|
||||||
long lMinIops, long lMaxIops, long lBurstIops)
|
public static final String DATASTORE_NAME = "datastoreName";
|
||||||
|
public static final String IQN = "iqn";
|
||||||
|
|
||||||
|
private static final int DEFAULT_MANAGEMENT_PORT = 443;
|
||||||
|
private static final int DEFAULT_STORAGE_PORT = 3260;
|
||||||
|
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SolidFireConnection getSolidFireConnection(long storagePoolId, StoragePoolDetailsDao storagePoolDetailsDao) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSolidFireAccountName(String csAccountUuid, long csAccountId) {
|
||||||
|
return "CloudStack_" + csAccountUuid + "_" + csAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateCsDbWithSolidFireAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount,
|
||||||
|
AccountDetailsDao accountDetailsDao) {
|
||||||
|
AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
|
||||||
|
SolidFireUtil.ACCOUNT_ID,
|
||||||
|
String.valueOf(sfAccount.getId()));
|
||||||
|
|
||||||
|
accountDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new AccountDetailVO(csAccountId,
|
||||||
|
SolidFireUtil.CHAP_INITIATOR_USERNAME,
|
||||||
|
String.valueOf(sfAccount.getName()));
|
||||||
|
|
||||||
|
accountDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new AccountDetailVO(csAccountId,
|
||||||
|
SolidFireUtil.CHAP_INITIATOR_SECRET,
|
||||||
|
String.valueOf(sfAccount.getInitiatorSecret()));
|
||||||
|
|
||||||
|
accountDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new AccountDetailVO(csAccountId,
|
||||||
|
SolidFireUtil.CHAP_TARGET_USERNAME,
|
||||||
|
sfAccount.getName());
|
||||||
|
|
||||||
|
accountDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new AccountDetailVO(csAccountId,
|
||||||
|
SolidFireUtil.CHAP_TARGET_SECRET,
|
||||||
|
sfAccount.getTargetSecret());
|
||||||
|
|
||||||
|
accountDetailsDao.persist(accountDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SolidFireAccount getSolidFireAccount(SolidFireConnection sfConnection, String sfAccountName) {
|
||||||
|
try {
|
||||||
|
return getSolidFireAccountByName(sfConnection, sfAccountName);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, List<HostVO> hosts,
|
||||||
|
ClusterDetailsDao clusterDetailsDao) {
|
||||||
|
if (hosts == null || hosts.isEmpty()) {
|
||||||
|
throw new CloudRuntimeException("There must be at least one host in the cluster.");
|
||||||
|
}
|
||||||
|
|
||||||
|
long lVagId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
lVagId = SolidFireUtil.createSolidFireVag(sfConnection, "CloudStack-" + UUID.randomUUID().toString(),
|
||||||
|
SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId });
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator";
|
||||||
|
|
||||||
|
if (!ex.getMessage().contains(iqnInVagAlready)) {
|
||||||
|
throw new CloudRuntimeException(ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCompatibleVag throws an exception if an existing VAG can't be located
|
||||||
|
SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(sfConnection, hosts);
|
||||||
|
|
||||||
|
lVagId = sfVag.getId();
|
||||||
|
|
||||||
|
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
|
||||||
|
|
||||||
|
SolidFireUtil.modifySolidFireVag(sfConnection, lVagId,
|
||||||
|
sfVag.getInitiators(), volumeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId));
|
||||||
|
|
||||||
|
clusterDetailsDao.persist(clusterDetail);
|
||||||
|
|
||||||
|
return lVagId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hostsSupport_iScsi(List<HostVO> hosts) {
|
||||||
|
if (hosts == null || hosts.size() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Host host : hosts) {
|
||||||
|
if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
|
||||||
|
List<String> lstIqns = new ArrayList<String>();
|
||||||
|
|
||||||
|
if (currentIqns != null) {
|
||||||
|
for (String currentIqn : currentIqns) {
|
||||||
|
lstIqns.add(currentIqn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newIqns != null) {
|
||||||
|
for (String newIqn : newIqns) {
|
||||||
|
if (!lstIqns.contains(newIqn)) {
|
||||||
|
lstIqns.add(newIqn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstIqns.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
|
||||||
|
if (add) {
|
||||||
|
return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) {
|
||||||
|
List<Long> lstVolumeIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
if (volumeIds != null) {
|
||||||
|
for (long volumeId : volumeIds) {
|
||||||
|
lstVolumeIds.add(volumeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstVolumeIds.contains(volumeIdToAdd)) {
|
||||||
|
return volumeIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstVolumeIds.add(volumeIdToAdd);
|
||||||
|
|
||||||
|
return convertArray(lstVolumeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) {
|
||||||
|
List<Long> lstVolumeIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
if (volumeIds != null) {
|
||||||
|
for (long volumeId : volumeIds) {
|
||||||
|
lstVolumeIds.add(volumeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lstVolumeIds.remove(volumeIdToRemove);
|
||||||
|
|
||||||
|
return convertArray(lstVolumeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long[] convertArray(List<Long> items) {
|
||||||
|
if (items == null) {
|
||||||
|
return new long[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
long[] outArray = new long[items.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
Long value = items.get(i);
|
||||||
|
|
||||||
|
outArray[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVagKey(long storagePoolId) {
|
||||||
|
return "sfVolumeAccessGroup_" + storagePoolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getIqnsFromHosts(List<? extends Host> hosts) {
|
||||||
|
if (hosts == null || hosts.size() == 0) {
|
||||||
|
throw new CloudRuntimeException("There do not appear to be any hosts in this cluster.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> lstIqns = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (Host host : hosts) {
|
||||||
|
lstIqns.add(host.getStorageUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstIqns.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method takes in a collection of hosts and tries to find an existing VAG that has all of them in it
|
||||||
|
// if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin
|
||||||
|
private static SolidFireUtil.SolidFireVag getCompatibleVag(SolidFireConnection sfConnection, List<HostVO> hosts) {
|
||||||
|
List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection);
|
||||||
|
|
||||||
|
if (sfVags != null) {
|
||||||
|
List<String> hostIqns = new ArrayList<String>();
|
||||||
|
|
||||||
|
// where the method we're in is called, hosts should not be null
|
||||||
|
for (HostVO host : hosts) {
|
||||||
|
// where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn")
|
||||||
|
hostIqns.add(host.getStorageUrl().toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SolidFireUtil.SolidFireVag sfVag : sfVags) {
|
||||||
|
List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators());
|
||||||
|
|
||||||
|
// lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null
|
||||||
|
if (lstInitiators.containsAll(hostIqns)) {
|
||||||
|
return sfVag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> getStringArrayAsLowerCaseStringList(String[] aString) {
|
||||||
|
List<String> lstLowerCaseString = new ArrayList<String>();
|
||||||
|
|
||||||
|
if (aString != null) {
|
||||||
|
for (String str : aString) {
|
||||||
|
if (str != null) {
|
||||||
|
lstLowerCaseString.add(str.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstLowerCaseString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSolidFireVolumeName(String strCloudStackVolumeName) {
|
||||||
|
final String specialChar = "-";
|
||||||
|
|
||||||
|
StringBuilder strSolidFireVolumeName = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < strCloudStackVolumeName.length(); i++) {
|
||||||
|
String strChar = strCloudStackVolumeName.substring(i, i + 1);
|
||||||
|
|
||||||
|
if (StringUtils.isAlphanumeric(strChar)) {
|
||||||
|
strSolidFireVolumeName.append(strChar);
|
||||||
|
} else {
|
||||||
|
strSolidFireVolumeName.append(specialChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strSolidFireVolumeName.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize,
|
||||||
|
boolean bEnable512e, final String strCloudStackVolumeSize, long lMinIops, long lMaxIops, long lBurstIops)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
VolumeToCreate volumeToCreate =
|
VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
|
||||||
new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
|
|
||||||
|
|
||||||
String strVolumeToCreateJson = gson.toJson(volumeToCreate);
|
String strVolumeToCreateJson = gson.toJson(volumeToCreate);
|
||||||
|
|
||||||
String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strVolumeCreateResultJson = executeJsonRpc(sfConnection, strVolumeToCreateJson);
|
||||||
|
|
||||||
VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
|
VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
|
||||||
|
|
||||||
@ -95,7 +419,7 @@ public class SolidFireUtil {
|
|||||||
return volumeCreateResult.result.volumeID;
|
return volumeCreateResult.result.volumeID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
|
public static SolidFireVolume getSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -103,7 +427,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVolumeToGetJson = gson.toJson(volumeToGet);
|
String strVolumeToGetJson = gson.toJson(volumeToGet);
|
||||||
|
|
||||||
String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strVolumeGetResultJson = executeJsonRpc(sfConnection, strVolumeToGetJson);
|
||||||
|
|
||||||
VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
|
VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
|
||||||
|
|
||||||
@ -118,14 +442,14 @@ public class SolidFireUtil {
|
|||||||
return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
|
return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SolidFireVolume> getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) {
|
public static List<SolidFireVolume> getSolidFireVolumesForAccountId(SolidFireConnection sfConnection, long lAccountId) {
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId);
|
VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId);
|
||||||
|
|
||||||
String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount);
|
String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount);
|
||||||
|
|
||||||
String strVolumesGetForAccountResultJson = executeJsonRpc(strVolumesToGetForAccountJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strVolumesGetForAccountResultJson = executeJsonRpc(sfConnection, strVolumesToGetForAccountJson);
|
||||||
|
|
||||||
VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class);
|
VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class);
|
||||||
|
|
||||||
@ -140,7 +464,7 @@ public class SolidFireUtil {
|
|||||||
return sfVolumes;
|
return sfVolumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
|
public static List<SolidFireVolume> getDeletedVolumes(SolidFireConnection sfConnection)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -148,8 +472,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
|
String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
|
||||||
|
|
||||||
String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort,
|
String strListDeletedVolumesResultJson = executeJsonRpc(sfConnection, strListDeletedVolumesJson);
|
||||||
strSfAdmin, strSfPassword);
|
|
||||||
|
|
||||||
VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
|
VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
|
||||||
|
|
||||||
@ -164,9 +487,9 @@ public class SolidFireUtil {
|
|||||||
return deletedVolumes;
|
return deletedVolumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
|
public static SolidFireVolume deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
|
||||||
{
|
{
|
||||||
SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId);
|
SolidFireVolume sfVolume = getSolidFireVolume(sfConnection, lVolumeId);
|
||||||
|
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -174,12 +497,12 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
|
String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
|
||||||
|
|
||||||
executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
executeJsonRpc(sfConnection, strVolumeToDeleteJson);
|
||||||
|
|
||||||
return sfVolume;
|
return sfVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
|
public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -187,7 +510,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
|
String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
|
||||||
|
|
||||||
executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
executeJsonRpc(sfConnection, strVolumeToPurgeJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String ACTIVE = "active";
|
private static final String ACTIVE = "active";
|
||||||
@ -267,7 +590,7 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strAccountName)
|
public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -275,7 +598,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strAccountAddJson = gson.toJson(accountToAdd);
|
String strAccountAddJson = gson.toJson(accountToAdd);
|
||||||
|
|
||||||
String strAccountAddResultJson = executeJsonRpc(strAccountAddJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strAccountAddResultJson = executeJsonRpc(sfConnection, strAccountAddJson);
|
||||||
|
|
||||||
AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
|
AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
|
||||||
|
|
||||||
@ -284,7 +607,7 @@ public class SolidFireUtil {
|
|||||||
return accountAddResult.result.accountID;
|
return accountAddResult.result.accountID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId)
|
public static SolidFireAccount getSolidFireAccountById(SolidFireConnection sfConnection, long lSfAccountId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -292,7 +615,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strAccountToGetByIdJson = gson.toJson(accountToGetById);
|
String strAccountToGetByIdJson = gson.toJson(accountToGetById);
|
||||||
|
|
||||||
String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strAccountGetByIdResultJson = executeJsonRpc(sfConnection, strAccountToGetByIdJson);
|
||||||
|
|
||||||
AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
|
AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
|
||||||
|
|
||||||
@ -305,7 +628,7 @@ public class SolidFireUtil {
|
|||||||
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfAccountName)
|
public static SolidFireAccount getSolidFireAccountByName(SolidFireConnection sfConnection, String strSfAccountName)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -313,7 +636,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
|
String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
|
||||||
|
|
||||||
String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strAccountGetByNameResultJson = executeJsonRpc(sfConnection, strAccountToGetByNameJson);
|
||||||
|
|
||||||
AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
|
AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
|
||||||
|
|
||||||
@ -326,7 +649,7 @@ public class SolidFireUtil {
|
|||||||
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId)
|
public static void deleteSolidFireAccount(SolidFireConnection sfConnection, long lAccountId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -334,7 +657,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strAccountToRemoveJson = gson.toJson(accountToRemove);
|
String strAccountToRemoveJson = gson.toJson(accountToRemove);
|
||||||
|
|
||||||
executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
executeJsonRpc(sfConnection, strAccountToRemoveJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SolidFireAccount
|
public static class SolidFireAccount
|
||||||
@ -399,7 +722,7 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName,
|
public static long createSolidFireVag(SolidFireConnection sfConnection, String strVagName,
|
||||||
String[] iqns, long[] volumeIds)
|
String[] iqns, long[] volumeIds)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
@ -408,7 +731,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVagCreateJson = gson.toJson(vagToCreate);
|
String strVagCreateJson = gson.toJson(vagToCreate);
|
||||||
|
|
||||||
String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strVagCreateResultJson = executeJsonRpc(sfConnection, strVagCreateJson);
|
||||||
|
|
||||||
VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
|
VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
|
||||||
|
|
||||||
@ -417,8 +740,7 @@ public class SolidFireUtil {
|
|||||||
return vagCreateResult.result.volumeAccessGroupID;
|
return vagCreateResult.result.volumeAccessGroupID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId,
|
public static void modifySolidFireVag(SolidFireConnection sfConnection, long lVagId, String[] iqns, long[] volumeIds)
|
||||||
String[] iqns, long[] volumeIds)
|
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -426,10 +748,10 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVagModifyJson = gson.toJson(vagToModify);
|
String strVagModifyJson = gson.toJson(vagToModify);
|
||||||
|
|
||||||
executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
executeJsonRpc(sfConnection, strVagModifyJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
|
public static SolidFireVag getSolidFireVag(SolidFireConnection sfConnection, long lVagId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -437,7 +759,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVagToGetJson = gson.toJson(vagToGet);
|
String strVagToGetJson = gson.toJson(vagToGet);
|
||||||
|
|
||||||
String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strVagGetResultJson = executeJsonRpc(sfConnection, strVagToGetJson);
|
||||||
|
|
||||||
VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class);
|
VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class);
|
||||||
|
|
||||||
@ -449,7 +771,7 @@ public class SolidFireUtil {
|
|||||||
return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
|
return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SolidFireVag> getAllSolidFireVags(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
|
public static List<SolidFireVag> getAllSolidFireVags(SolidFireConnection sfConnection)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -457,7 +779,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strAllVagsJson = gson.toJson(allVags);
|
String strAllVagsJson = gson.toJson(allVags);
|
||||||
|
|
||||||
String strAllVagsGetResultJson = executeJsonRpc(strAllVagsJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
String strAllVagsGetResultJson = executeJsonRpc(sfConnection, strAllVagsJson);
|
||||||
|
|
||||||
VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class);
|
VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class);
|
||||||
|
|
||||||
@ -476,7 +798,7 @@ public class SolidFireUtil {
|
|||||||
return lstSolidFireVags;
|
return lstSolidFireVags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
|
public static void deleteSolidFireVag(SolidFireConnection sfConnection, long lVagId)
|
||||||
{
|
{
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -484,7 +806,7 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
String strVagToDeleteJson = gson.toJson(vagToDelete);
|
String strVagToDeleteJson = gson.toJson(vagToDelete);
|
||||||
|
|
||||||
executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
|
executeJsonRpc(sfConnection, strVagToDeleteJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SolidFireVag
|
public static class SolidFireVag
|
||||||
@ -996,7 +1318,7 @@ public class SolidFireUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String executeJsonRpc(String strJsonToExecute, String strMvip, int iPort, String strAdmin, String strPassword) {
|
private static String executeJsonRpc(SolidFireConnection sfConnection, String strJsonToExecute) {
|
||||||
DefaultHttpClient httpClient = null;
|
DefaultHttpClient httpClient = null;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
@ -1005,11 +1327,11 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
input.setContentType("application/json");
|
input.setContentType("application/json");
|
||||||
|
|
||||||
httpClient = getHttpClient(iPort);
|
httpClient = getHttpClient(sfConnection.getManagementPort());
|
||||||
|
|
||||||
URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0");
|
URI uri = new URI("https://" + sfConnection.getManagementVip() + ":" + sfConnection.getManagementPort() + "/json-rpc/5.0");
|
||||||
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
|
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
|
||||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
|
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
|
||||||
|
|
||||||
httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
|
httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
|
||||||
|
|
||||||
@ -1132,4 +1454,119 @@ public class SolidFireUtil {
|
|||||||
|
|
||||||
throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + ".");
|
throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used to parse the "url" parameter when creating primary storage that's based on the SolidFire plug-in with the
|
||||||
|
// name SolidFireUtil.PROVIDER_NAME (as opposed to the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME)
|
||||||
|
// return a String instance that contains at most the MVIP and SVIP info
|
||||||
|
public static String getModifiedUrl(String originalUrl) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
String delimiter = ";";
|
||||||
|
|
||||||
|
StringTokenizer st = new StringTokenizer(originalUrl, delimiter);
|
||||||
|
|
||||||
|
while (st.hasMoreElements()) {
|
||||||
|
String token = st.nextElement().toString().toUpperCase();
|
||||||
|
|
||||||
|
if (token.startsWith(SolidFireUtil.MANAGEMENT_VIP.toUpperCase()) || token.startsWith(SolidFireUtil.STORAGE_VIP.toUpperCase())) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getManagementVip(String url) {
|
||||||
|
return getVip(SolidFireUtil.MANAGEMENT_VIP, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStorageVip(String url) {
|
||||||
|
return getVip(SolidFireUtil.STORAGE_VIP, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getManagementPort(String url) {
|
||||||
|
return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStoragePort(String url) {
|
||||||
|
return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static 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 static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValue(String keyToMatch, String url) {
|
||||||
|
return getValue(keyToMatch, url, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValue(String keyToMatch, String url, boolean throwExceptionIfNotFound) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (throwExceptionIfNotFound) {
|
||||||
|
throw new RuntimeException("Key not found in URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -699,7 +699,7 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
|
|||||||
ManagedObjectReference morDs = oc.getObj();
|
ManagedObjectReference morDs = oc.getObj();
|
||||||
String name = (String)VmwareHelper.getPropValue(oc, "name");
|
String name = (String)VmwareHelper.getPropValue(oc, "name");
|
||||||
|
|
||||||
if (!name.startsWith("-iqn.")) {
|
if (!name.startsWith("-iqn.") && !name.startsWith("_iqn.")) {
|
||||||
dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
|
dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user