diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 6e8e48e48d8..f54dfef865f 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -147,4 +147,14 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject disks, String reservationId); + void destroy(List disks, String reservationId); /** * Cancel a reservation * @param reservationId reservation to */ void cancel(String reservationId); + + /** + * If attaching a volume in allocated state to a running vm, need to create this volume + */ + void prepareAttachDiskToVM(long diskId, long vmId, String reservationId); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java b/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java new file mode 100644 index 00000000000..8bebf3e9712 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java @@ -0,0 +1,196 @@ +/* + * 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; + +import java.util.List; + +import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; +import org.apache.cloudstack.platform.subsystem.api.storage.StorageProvider; +import org.apache.cloudstack.platform.subsystem.api.storage.VolumeStrategy; +import org.apache.cloudstack.storage.volume.VolumeManager; +import org.apache.log4j.Logger; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.offering.DiskOffering; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.utils.component.Inject; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.VMInstanceDao; + +public class StorageOrchestratorImpl implements StorageOrchestrator { + private static final Logger s_logger = Logger.getLogger(StorageOrchestratorImpl.class); + @Inject + StoragePoolDao _storagePoolDao; + @Inject + StorageProviderManager _spManager; + @Inject + VolumeDao _volumeDao; + @Inject + VMInstanceDao _vmDao; + @Inject + DiskOfferingDao _diskOfferingDao; + @Inject + VolumeHostDao _volumeHostDao; + @Inject + StorageProviderManager _storageProviderMgr; + @Inject + VolumeManager _volumeMgr; + + protected Volume copyVolumeFromBackupStorage(VolumeVO volume, DataStore destStore, String reservationId) { + StorageProvider sp = _storageProviderMgr.getBackupStorageProvider(volume.getDataCenterId()); + + VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId()); + long poolId = volumeHostVO.getHostId(); + DataStore srcStore = _storageProviderMgr.getDataStore(poolId); + + + + } + + protected Volume migrateVolume(VolumeVO volume, DataStore srcStore, DataStore destStore, String reservationId) throws NoTransitionException { + VolumeStrategy vs = srcStore.getVolumeStrategy(); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + volume.setReservationId(reservationId); + volume = _volumeMgr.processEvent(volume, Volume.Event.MigrationRequested); + Volume destVolume = _volumeMgr.allocateDuplicateVolume(volume); + destVolume = _volumeMgr.processEvent(destVolume, Volume.Event.CreateRequested); + txn.commit(); + + vs.migrateVolume(volume, srcStore, destVolume, destStore); + + txn.start(); + volume = _volumeMgr.processEvent(volume, Volume.Event.OperationSucceeded); + destVolume = _volumeMgr.processEvent(destVolume, Volume.Event.OperationSucceeded); + txn.commit(); + _volumeDao.remove(volume.getId()); + return destVolume; + } + + @DB + protected void prepareVolumes(List vols, Long destPoolId, String reservationId) throws NoTransitionException { + DataStore destStore = null; + if (destPoolId != null) { + destStore = _storageProviderMgr.getDataStore(destPoolId); + } + + for (VolumeVO volume : vols) { + if (volume.getPoolId() == null && destStore == null) { + throw new CloudRuntimeException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create."); + } + if (destStore == null) { + continue; + } + + DataStore srcStore = _storageProviderMgr.getDataStore(volume.getPoolId()); + boolean needToCreateVolume = false; + boolean needToRecreateVolume = false; + boolean needToMigrateVolume = false; + boolean needToCopyFromSec = false; + + Volume.State state = volume.getState(); + if (state == Volume.State.Allocated) { + needToCreateVolume = true; + } else if (state == Volume.State.UploadOp) { + needToCopyFromSec = true; + } else if (destStore.getId() != srcStore.getId()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Mismatch in storage pool " + destStore.getId() + " assigned by deploymentPlanner and the one associated with volume " + volume); + } + + if (Volume.Type.ROOT == volume.getVolumeType()) { + needToMigrateVolume = true; + } else { + if (destStore.getCluterId() != srcStore.getCluterId()) { + needToMigrateVolume = true; + } else if (!srcStore.isSharedStorage() && srcStore.getId() != destStore.getId()) { + needToMigrateVolume = true; + } else { + continue; + } + } + } else { + continue; + } + + VolumeStrategy vs = srcStore.getVolumeStrategy(); + if (needToCreateVolume) { + volume.setReservationId(reservationId); + volume = _volumeMgr.processEvent(volume, Volume.Event.CreateRequested); + + vs.createVolume(volume, destStore); + + volume = _volumeMgr.processEvent(volume, Volume.Event.OperationSucceeded); + } else if (needToMigrateVolume) { + migrateVolume(volume, srcStore, destStore, reservationId); + } else if (needToCopyFromSec) { + _volumeMgr.processEvent(volume, Volume.Event.CopyRequested); + } else if (needToRecreateVolume) { + + } + } + } + + public void prepare(long vmId, DeploymentPlan plan, String reservationId) { + VirtualMachine vm = _vmDao.findById(vmId); + + + List vols = _volumeDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Prepare " + vols.size() + " volumes for " + vm.getInstanceName()); + } + + + } + + + public void release(long vmId, String reservationId) { + // TODO Auto-generated method stub + + } + + public void destroy(List disks, String reservationId) { + // TODO Auto-generated method stub + + } + + public void cancel(String reservationId) { + // TODO Auto-generated method stub + + } + + public void prepareAttachDiskToVM(long disk, long vm, String reservationId) { + // TODO Auto-generated method stub + + } + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/StorageProviderManager.java b/platform/storage/src/org/apache/cloudstack/storage/StorageProviderManager.java index 25b9bdd4ad4..e7b03a788ab 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/StorageProviderManager.java +++ b/platform/storage/src/org/apache/cloudstack/storage/StorageProviderManager.java @@ -1,7 +1,11 @@ package org.apache.cloudstack.storage; +import org.apache.cloudstack.platform.subsystem.api.storage.DataStore; import org.apache.cloudstack.platform.subsystem.api.storage.StorageProvider; public interface StorageProviderManager { StorageProvider getProvider(String uuid); + StorageProvider getProvider(long poolId); + StorageProvider getBackupStorageProvider(long zoneId); + DataStore getDataStore(long poolId); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/datastoreconfigurator/XenNfsDataStoreConfigurator.java b/platform/storage/src/org/apache/cloudstack/storage/datastoreconfigurator/XenNfsDataStoreConfigurator.java index beed2627035..8f4993473b4 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/datastoreconfigurator/XenNfsDataStoreConfigurator.java +++ b/platform/storage/src/org/apache/cloudstack/storage/datastoreconfigurator/XenNfsDataStoreConfigurator.java @@ -11,7 +11,7 @@ import org.apache.cloudstack.storage.filesystem.DefaultFileSystem; import org.apache.cloudstack.storage.lifecycle.DefaultPrimaryDataStoreLifeCycle; import org.apache.cloudstack.storage.strategy.XenBackupStrategy; import org.apache.cloudstack.storage.strategy.XenSnapshotStrategy; -import org.apache.cloudstack.storage.strategy.XenVolumeStrategy; +import org.apache.cloudstack.storage.strategy.DefaultVolumeStrategy; import com.cloud.storage.StoragePool; @@ -26,7 +26,7 @@ public class XenNfsDataStoreConfigurator extends NfsDataStoreConfigurator { ds.setUUID(pool.getUuid()); ds.setDataStoreDriver(new XenDataStoreDriver(ds)); ds.setBackupStrategy(new XenBackupStrategy(ds)); - ds.setVolumeStrategy(new XenVolumeStrategy(ds)); + ds.setVolumeStrategy(new DefaultVolumeStrategy(ds)); ds.setSnapshotStrategy(new XenSnapshotStrategy(ds)); ds.setLifeCycle(new DefaultPrimaryDataStoreLifeCycle(ds)); return ds; diff --git a/platform/storage/src/org/apache/cloudstack/storage/strategy/XenVolumeStrategy.java b/platform/storage/src/org/apache/cloudstack/storage/strategy/DefaultVolumeStrategy.java similarity index 91% rename from platform/storage/src/org/apache/cloudstack/storage/strategy/XenVolumeStrategy.java rename to platform/storage/src/org/apache/cloudstack/storage/strategy/DefaultVolumeStrategy.java index 4015fec88b1..bbbbade3cd9 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/strategy/XenVolumeStrategy.java +++ b/platform/storage/src/org/apache/cloudstack/storage/strategy/DefaultVolumeStrategy.java @@ -6,9 +6,9 @@ import org.apache.cloudstack.platform.subsystem.api.storage.Template; import org.apache.cloudstack.platform.subsystem.api.storage.Volume; import org.apache.cloudstack.platform.subsystem.api.storage.VolumeStrategy; -public class XenVolumeStrategy implements VolumeStrategy { +public class DefaultVolumeStrategy implements VolumeStrategy { protected DataStore _ds; - public XenVolumeStrategy(DataStore ds) { + public DefaultVolumeStrategy(DataStore ds) { _ds = ds; } diff --git a/platform/api/src/org/apache/cloudstack/platform/subsystem/api/storage/Volume.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManager.java similarity index 70% rename from platform/api/src/org/apache/cloudstack/platform/subsystem/api/storage/Volume.java rename to platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManager.java index dc72d8f654e..625f305922a 100644 --- a/platform/api/src/org/apache/cloudstack/platform/subsystem/api/storage/Volume.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManager.java @@ -16,7 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.platform.subsystem.api.storage; +package org.apache.cloudstack.storage.volume; -public interface Volume extends DataObject { +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.utils.fsm.NoTransitionException; + +public interface VolumeManager { + VolumeVO allocateDuplicateVolume(VolumeVO oldVol); + VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException; } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java new file mode 100644 index 00000000000..20af34eb655 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java @@ -0,0 +1,50 @@ +/* + * 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.volume; + +import com.cloud.storage.VolumeVO; +import com.cloud.storage.Volume; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.utils.component.Inject; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; + +public class VolumeManagerImpl implements VolumeManager { + private StateMachine2 _volStateMachine; + @Inject + protected VolumeDao _volumeDao; + + + public VolumeVO allocateDuplicateVolume(VolumeVO oldVol) { + VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); + newVol.setTemplateId(oldVol.getTemplateId()); + newVol.setDeviceId(oldVol.getDeviceId()); + newVol.setInstanceId(oldVol.getInstanceId()); + newVol.setRecreatable(oldVol.isRecreatable()); + newVol.setReservationId(oldVol.getReservationId()); + + return _volumeDao.persist(newVol); + } + + + public VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException { + _volStateMachine.transitTo(vol, event, null, _volumeDao); + return _volumeDao.findById(vol.getId()); + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java new file mode 100644 index 00000000000..d1b3d368783 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java @@ -0,0 +1,68 @@ +/* + * 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.volume; + +import org.apache.cloudstack.platform.subsystem.api.storage.Volume; + +import com.cloud.api.commands.CreateVolumeCmd; + +public interface VolumeService { + /** + * Creates the database object for a volume based on the given criteria + * + * @param cmd + * @return the volume object + * @throws PermissionDeniedException + */ + Volume allocVolumeInDB(CreateVolumeCmd cmd); + + /** + * Creates the volume based on the given criteria + * + * @param cmd + * + * @return the volume object + */ + Volume createVolume(CreateVolumeCmd cmd); + + /** + * Delete volume + * @param volumeId + * @return + * @throws ConcurrentOperationException + */ + boolean deleteVolume(long volumeId); + + /** + * Migrate volume to another storage pool + * @param volumeId + * @param storagePoolId + * @return + * @throws ConcurrentOperationException + */ + Volume migrateVolume(Long volumeId, Long storagePoolId); + + /** + * Copy volume another storage pool, a new volume will be created on destination storage pool + * @param volumeId + * @param destStoragePoolId + * @return + */ + Volume copyVolume(Long volumeId, Long destStoragePoolId); +}