Adding support for the SolidFireShared plug-in
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a004fba7 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a004fba7 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a004fba7 Branch: refs/heads/sf-4.3.2 Commit: a004fba7770afe6d4ab9442a05a7506d5f3dd6ee Parents: ebf9897 Author: Mike Tutkowski <[email protected]> Authored: Tue Dec 16 15:33:43 2014 -0700 Committer: Mike Tutkowski <[email protected]> Committed: Thu Dec 18 23:17:23 2014 -0700 ---------------------------------------------------------------------- plugins/storage/volume/solidfire/pom.xml | 5 + .../spring-storage-volume-solidfire-context.xml | 4 +- .../SolidFireSharedPrimaryDataStoreDriver.java | 65 ++ .../driver/SolidfirePrimaryDataStoreDriver.java | 205 +--- ...olidFireSharedPrimaryDataStoreLifeCycle.java | 535 +++++++++ .../provider/SolidFireSharedHostListener.java | 92 ++ ...SolidFireSharedPrimaryDataStoreProvider.java | 83 ++ .../storage/datastore/util/SolidFireUtil.java | 1083 ++++++++++++++---- 8 files changed, 1700 insertions(+), 372 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/pom.xml ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index 052fdf7..112e4ad 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -22,6 +22,11 @@ <dependencies> <dependency> <groupId>org.apache.cloudstack</groupId> + <artifactId>cloud-plugin-storage-volume-default</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cloudstack</groupId> <artifactId>cloud-engine-storage-volume</artifactId> <version>${project.version}</version> </dependency> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml b/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml index a83e3ca..df32f1e 100644 --- a/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml +++ b/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml @@ -29,5 +29,7 @@ <bean id="solidFireDataStoreProvider" class="org.apache.cloudstack.storage.datastore.provider.SolidfirePrimaryDataStoreProvider" /> - + <bean id="solidFireSharedDataStoreProvider" + class="org.apache.cloudstack.storage.datastore.provider.SolidFireSharedPrimaryDataStoreProvider" /> + </beans> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java new file mode 100644 index 0000000..a16408e --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java @@ -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(); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index 6a180ad..f83c86c 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -82,66 +82,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return null; } - private static class SolidFireConnection { - private final String _managementVip; - private final int _managementPort; - private final String _clusterAdminUsername; - private final String _clusterAdminPassword; + private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, SolidFireUtil.SolidFireConnection sfConnection) { + long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName); - public SolidFireConnection(String managementVip, int managementPort, - String clusterAdminUsername, String clusterAdminPassword) { - _managementVip = managementVip; - _managementPort = managementPort; - _clusterAdminUsername = clusterAdminUsername; - _clusterAdminPassword = clusterAdminPassword; - } - - public String getManagementVip() { - return _managementVip; - } - - public int getManagementPort() { - return _managementPort; - } - - public String getClusterAdminUsername() { - return _clusterAdminUsername; - } - - public String getClusterAdminPassword() { - return _clusterAdminPassword; - } - } - - private SolidFireConnection getSolidFireConnection(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP); - - String mVip = storagePoolDetail.getValue(); - - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT); - - int mPort = Integer.parseInt(storagePoolDetail.getValue()); - - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME); - - String clusterAdminUsername = storagePoolDetail.getValue(); - - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD); - - String clusterAdminPassword = storagePoolDetail.getValue(); - - return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword); - } - - private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, SolidFireConnection sfConnection) { - 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); + return SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber); } private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) { @@ -176,77 +120,18 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { _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 public ChapInfo getChapInfo(VolumeInfo volumeInfo) { 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) // if the VAG exists // 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 VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup) @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) { return false; @@ -266,25 +151,21 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return false; } - SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); if (vagId != null) { - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts)); long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), - hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); } else { long lVagId; try { - lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(), + lVagId = SolidFireUtil.createSolidFireVag(sfConnection, "CloudStack-" + UUID.randomUUID().toString(), getIqnsFromHosts(hosts), new long[] { sfVolumeId }); } catch (Exception ex) { @@ -299,9 +180,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), - sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); lVagId = sfVag.getId(); } @@ -316,9 +195,8 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { // 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()); + private SolidFireUtil.SolidFireVag getCompatibleVag(List<HostVO> hosts, SolidFireUtil.SolidFireConnection sfConnection) { + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection); if (sfVags != null) { List<String> hostIqns = new ArrayList<String>(); @@ -360,7 +238,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { // if the VAG exists // remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup) @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) { return; @@ -377,17 +255,14 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (vagId != null) { 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(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts)); long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(), - sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(), - hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); } } @@ -525,13 +400,8 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops); } - private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) + private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireUtil.SolidFireConnection sfConnection) { - String mVip = sfConnection.getManagementVip(); - int mPort = sfConnection.getManagementPort(); - String clusterAdminUsername = sfConnection.getClusterAdminUsername(); - String clusterAdminPassword = sfConnection.getClusterAdminPassword(); - AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID); long sfAccountId = Long.parseLong(accountDetail.getValue()); @@ -553,12 +423,12 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); - long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, + long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, 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 @@ -637,7 +507,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { } } - private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) + private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireUtil.SolidFireConnection sfConnection) { Long storagePoolId = volumeInfo.getPoolId(); @@ -645,36 +515,15 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { 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()); - 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 public void createAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CreateCmdResult> callback) { @@ -687,10 +536,16 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId()); long storagePoolId = dataStore.getId(); - SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + + AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID); - if (!sfAccountExists(sfAccountName, sfConnection)) { - SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName, sfConnection); + if (accountDetail == null || accountDetail.getValue() == null) { + SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); + + if (sfAccount == null) { + sfAccount = createSolidFireAccount(sfAccountName, sfConnection); + } updateCsDbWithAccountInfo(account.getId(), sfAccount); } @@ -786,7 +641,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { // long sfAccountId = Long.parseLong(accountDetails.getValue()); long storagePoolId = dataStore.getId(); - SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(volumeInfo, sfConnection); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java new file mode 100644 index 0000000..89d1fa9 --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -0,0 +1,535 @@ +/* + * 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 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.ClusterDetailsVO; +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."); + } + + 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 + "'."); + } + + if (lMinIops > SolidFireUtil.MAX_IOPS_PER_VOLUME || lMaxIops > SolidFireUtil.MAX_IOPS_PER_VOLUME || lBurstIops > SolidFireUtil.MAX_IOPS_PER_VOLUME) { + throw new CloudRuntimeException("This volume cannot exceed " + NumberFormat.getInstance().format(SolidFireUtil.MAX_IOPS_PER_VOLUME) + " 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); + + SolidFireCreateVolume sfCreateVolume = createSolidFireVolume(sfConnection, storagePoolName, capacityBytes, lMinIops, lMaxIops, lBurstIops); + + SolidFireUtil.SolidFireVolume sfVolume = sfCreateVolume.getVolume(); + + String iqn = sfVolume.getIqn(); + + details.put(SolidFireUtil.VOLUME_ID, String.valueOf(sfVolume.getId())); + + parameters.setUuid(iqn); + + 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); + ClusterVO cluster = _clusterDao.findById(clusterId); + + synchronized (this) { + SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), cluster.getUuid(), hosts, _clusterDetailsDao); + } + + SolidFireUtil.SolidFireAccount sfAccount = sfCreateVolume.getAccount(); + Account csAccount = CallContext.current().getCallingAccount(); + + SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccount.getId(), sfAccount, dataStore.getId(), _accountDetailsDao); + } 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; + } + + throw new CloudRuntimeException("The 'hypervisor' parameter must be '" + HypervisorType.XenServer + "'."); + } + + private class SolidFireCreateVolume { + private final SolidFireUtil.SolidFireVolume _sfVolume; + private final SolidFireUtil.SolidFireAccount _sfAccount; + + public SolidFireCreateVolume(SolidFireUtil.SolidFireVolume sfVolume, SolidFireUtil.SolidFireAccount sfAccount) { + _sfVolume = sfVolume; + _sfAccount = sfAccount; + } + + public SolidFireUtil.SolidFireVolume getVolume() { + return _sfVolume; + } + + public SolidFireUtil.SolidFireAccount getAccount() { + return _sfAccount; + } + } + + private SolidFireCreateVolume 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); + } + + long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize, + true, null, minIops, maxIops, burstIops); + SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); + + return new SolidFireCreateVolume(sfVolume, sfAccount); + } 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(); + CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, storagePool); + + 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); + } + + Long clusterId = null; + + for (StoragePoolHostVO host : hostPoolRecords) { + DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(storagePool); + + 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()); + + HostVO hostVO = this._hostDao.findById(host.getHostId()); + + if (hostVO != null) { + clusterId = hostVO.getClusterId(); + } + + break; + } + else { + s_logger.error("Failed to delete storage pool using Host ID " + host.getHostId() + ": " + answer.getResult()); + } + } + + if (clusterId != null) { + removeVolumeFromVag(storagePool.getId(), clusterId); + } + + deleteSolidFireVolume(storagePool.getId()); + + return _primaryDataStoreHelper.deletePrimaryDataStore(dataStore); + } + + private synchronized void removeVolumeFromVag(long storagePoolId, long clusterId) { + long sfVolumeId = getVolumeId(storagePoolId); + ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + if (vagId != null) { + List<HostVO> hosts = _hostDao.findByClusterId(clusterId); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + + String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); + long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); + + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + } + } + + 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); + } + + 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; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java new file mode 100644 index 0000000..9881d1d --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java @@ -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; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java new file mode 100644 index 0000000..d5b82a1 --- /dev/null +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java @@ -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; + } +}
