Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 8899E17954 for ; Wed, 22 Oct 2014 18:44:58 +0000 (UTC) Received: (qmail 23087 invoked by uid 500); 22 Oct 2014 18:44:58 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 22885 invoked by uid 500); 22 Oct 2014 18:44:58 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 22727 invoked by uid 99); 22 Oct 2014 18:44:58 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Oct 2014 18:44:58 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id BDEE09D1170; Wed, 22 Oct 2014 18:44:57 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mtutkowski@apache.org To: commits@cloudstack.apache.org Date: Wed, 22 Oct 2014 18:45:00 -0000 Message-Id: <75b8907140ea4d64ad3b3f89be3ac7b2@git.apache.org> In-Reply-To: <699b2a0750bb4920b10e9ac84cd5a293@git.apache.org> References: <699b2a0750bb4920b10e9ac84cd5a293@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [04/12] git commit: updated refs/heads/master to 97aa02c Support for back-end snapshots on primary storage Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/0cea0346 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/0cea0346 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/0cea0346 Branch: refs/heads/master Commit: 0cea0346aed5590950712210be92f54b698057c7 Parents: 6beeeff Author: Mike Tutkowski Authored: Sun Oct 19 18:34:36 2014 -0600 Committer: Mike Tutkowski Committed: Tue Oct 21 16:01:14 2014 -0600 ---------------------------------------------------------------------- api/src/com/cloud/agent/api/to/DiskTO.java | 1 + api/src/com/cloud/storage/Volume.java | 5 - .../storage/resource/StorageProcessor.java | 7 +- .../storage/command/SnapshotAndCopyAnswer.java | 41 +++ .../storage/command/SnapshotAndCopyCommand.java | 60 +++++ .../api/storage/DataMotionStrategy.java | 3 - .../snapshot/StorageSystemSnapshotStrategy.java | 247 +++++++++++++------ .../kvm/storage/KVMStorageProcessor.java | 9 + .../resource/SimulatorStorageProcessor.java | 9 + .../resource/VmwareStorageProcessor.java | 9 + .../xenserver/resource/CitrixResourceBase.java | 5 +- .../resource/XenServerStorageProcessor.java | 63 +++++ .../driver/SolidFirePrimaryDataStoreDriver.java | 24 +- .../storage/datastore/util/SolidFireUtil.java | 2 +- 14 files changed, 379 insertions(+), 106 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/api/src/com/cloud/agent/api/to/DiskTO.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java index afab856..9e4dfd9 100644 --- a/api/src/com/cloud/agent/api/to/DiskTO.java +++ b/api/src/com/cloud/agent/api/to/DiskTO.java @@ -34,6 +34,7 @@ public class DiskTO { public static final String VOLUME_SIZE = "volumeSize"; public static final String MOUNT_POINT = "mountpoint"; public static final String PROTOCOL_TYPE = "protocoltype"; + public static final String PATH = "path"; private DataTO data; private Long diskSeq; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/api/src/com/cloud/storage/Volume.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 48145a7..b67a395 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -38,7 +38,6 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba Ready("The volume is ready to be used."), Migrating("The volume is migrating to other storage pool"), Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"), - Reverting("Replace the existing volume on a storage system with a snapshot of it"), Resizing("The volume is being resized"), Expunging("The volume is being expunging"), Expunged("The volume is being expunging"), @@ -86,11 +85,8 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(Expunging, Event.OperationSucceeded, Expunged); s_fsm.addTransition(Expunging, Event.OperationFailed, Destroy); s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting); - s_fsm.addTransition(Ready, Event.RevertRequested, Reverting); s_fsm.addTransition(Snapshotting, Event.OperationSucceeded, Ready); s_fsm.addTransition(Snapshotting, Event.OperationFailed, Ready); - s_fsm.addTransition(Reverting, Event.OperationSucceeded, Ready); - s_fsm.addTransition(Reverting, Event.OperationFailed, Ready); s_fsm.addTransition(Ready, Event.MigrationRequested, Migrating); s_fsm.addTransition(Migrating, Event.OperationSucceeded, Ready); s_fsm.addTransition(Migrating, Event.OperationFailed, Ready); @@ -115,7 +111,6 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba UploadRequested, MigrationRequested, SnapshotRequested, - RevertRequested, DestroyRequested, ExpungingRequested, ResizeRequested; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/core/src/com/cloud/storage/resource/StorageProcessor.java ---------------------------------------------------------------------- diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index b673d70..e2bf1b7 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import com.cloud.agent.api.Answer; @@ -62,7 +63,9 @@ public interface StorageProcessor { public Answer deleteSnapshot(DeleteCommand cmd); - Answer introduceObject(IntroduceObjectCmd cmd); + public Answer introduceObject(IntroduceObjectCmd cmd); - Answer forgetObject(ForgetObjectCmd cmd); + public Answer forgetObject(ForgetObjectCmd cmd); + + public Answer snapshotAndCopy(SnapshotAndCopyCommand cmd); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyAnswer.java ---------------------------------------------------------------------- diff --git a/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyAnswer.java b/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyAnswer.java new file mode 100644 index 0000000..b99d182 --- /dev/null +++ b/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyAnswer.java @@ -0,0 +1,41 @@ +// +// 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.command; + +import com.cloud.agent.api.Answer; + +public class SnapshotAndCopyAnswer extends Answer { + private String _path; + + public SnapshotAndCopyAnswer() { + } + + public SnapshotAndCopyAnswer(String errMsg) { + super(null, false, errMsg); + } + + public void setPath(String path) { + _path = path; + } + + public String getPath() { + return _path; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyCommand.java ---------------------------------------------------------------------- diff --git a/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyCommand.java b/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyCommand.java new file mode 100644 index 0000000..c599916 --- /dev/null +++ b/core/src/org/apache/cloudstack/storage/command/SnapshotAndCopyCommand.java @@ -0,0 +1,60 @@ +// +// 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.command; + +import com.cloud.agent.api.Command; + +import java.util.Map; + +public final class SnapshotAndCopyCommand extends Command implements StorageSubSystemCommand { + private String _uuidOfSourceVdi; + private Map _sourceDetails; + private Map _destDetails; + + private boolean _executeInSequence = true; + + public SnapshotAndCopyCommand(String uuidOfSourceVdi, Map sourceDetails, Map destDetails) { + _uuidOfSourceVdi = uuidOfSourceVdi; + _sourceDetails = sourceDetails; + _destDetails = destDetails; + } + + public String getUuidOfSourceVdi() { + return _uuidOfSourceVdi; + } + + public Map getSourceDetails() { + return _sourceDetails; + } + + public Map getDestDetails() { + return _destDetails; + } + + @Override + public void setExecuteInSequence(boolean executeInSequence) { + _executeInSequence = executeInSequence; + } + + @Override + public boolean executeInSequence() { + return _executeInSequence; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java ---------------------------------------------------------------------- diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java index 17856bb..b5601e9 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java @@ -26,9 +26,6 @@ import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.host.Host; public interface DataMotionStrategy { - // IQN is used by the StorageSystemDataMotionStrategy to create a template from a snapshot or clone that resides on a storage system - public static final String IQN = "iqn"; - StrategyPriority canHandle(DataObject srcData, DataObject destData); StrategyPriority canHandle(Map volumeMap, Host srcHost, Host destHost); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java ---------------------------------------------------------------------- diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java index dc43d7d..dd6c654 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java @@ -16,12 +16,15 @@ // under the License. package org.apache.cloudstack.storage.snapshot; +import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -30,43 +33,53 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.dao.ClusterDao; +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.to.DiskTO; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping.AllocationState; +import com.cloud.resource.ResourceState; +import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotDetailsDao; +import com.cloud.storage.dao.SnapshotDetailsVO; import com.cloud.storage.dao.VolumeDao; -import com.cloud.uservm.UserVm; import com.cloud.utils.db.DB; -import com.cloud.utils.db.EntityManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; @Component public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { private static final Logger s_logger = Logger.getLogger(StorageSystemSnapshotStrategy.class); - @Inject private ClusterDao _clusterDao; + @Inject private AgentManager _agentMgr; @Inject private DataStoreManager _dataStoreMgr; - @Inject private EntityManager _entityMgr; @Inject private HostDao _hostDao; + @Inject private ManagementService _mgr; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private SnapshotDao _snapshotDao; @Inject private SnapshotDataFactory _snapshotDataFactory; - @Inject private SnapshotDataStoreDao _snapshotStoreDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SnapshotDetailsDao _snapshotDetailsDao; + @Inject private VMInstanceDao _vmInstanceDao; @Inject private VolumeDao _volumeDao; + @Inject private VolumeService _volService; @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { @@ -133,103 +146,91 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { @Override public boolean revertSnapshot(Long snapshotId) { - // verify the following: - // if root disk, the VM cannot be running (don't allow this at all for ESX) - // if data disk, the disk cannot be in the attached state + throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead."); + } - SnapshotInfo snapshotInfo = _snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + @Override + @DB + public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { VolumeInfo volumeInfo = snapshotInfo.getBaseVolume(); - VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); - - if (volume.getVolumeType() == Type.DATADISK) { - if (volume.getAttached() != null) { - throw new CloudRuntimeException("A data disk must be in the detached state in order to perform a revert."); - } - } - else if (volume.getVolumeType() == Type.ROOT) { - Long instanceId = volume.getInstanceId(); - UserVm vm = _entityMgr.findById(UserVm.class, instanceId); - - Long hostId = vm.getHostId(); - HostVO hostVO = _hostDao.findById(hostId); - Long clusterId = hostVO.getClusterId(); - ClusterVO clusterVO = _clusterDao.findById(clusterId); - - if (clusterVO.getHypervisorType() != HypervisorType.XenServer && clusterVO.getHypervisorType() != HypervisorType.KVM) { - throw new CloudRuntimeException("Unsupported hypervisor type for root disk revert. Create a template from this disk and use it instead."); - } - if (vm.getState() != State.Stopped) { - throw new CloudRuntimeException("A root disk cannot be reverted unless the VM it's attached to is in the stopped state."); - } - } - else { - throw new CloudRuntimeException("Unsupported volume type"); + if (volumeInfo.getFormat() != ImageFormat.VHD) { + throw new CloudRuntimeException("Only the " + ImageFormat.VHD.toString() + " image type is currently supported."); } - SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotId); + SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotInfo.getId()); if (snapshotVO == null) { - throw new CloudRuntimeException("Failed to acquire lock on the following snapshot: " + snapshotId); + throw new CloudRuntimeException("Failed to acquire lock on the following snapshot: " + snapshotInfo.getId()); } try { - volumeInfo.stateTransit(Volume.Event.RevertRequested); + volumeInfo.stateTransit(Volume.Event.SnapshotRequested); - boolean result = false; + SnapshotResult result = null; try { - result = snapshotSvr.revertSnapshot(snapshotId); - } - finally { - if (result) { - volumeInfo.stateTransit(Volume.Event.OperationSucceeded); + // tell the storage driver to create a back-end volume (eventually used to create a new SR on and to copy the VM snapshot VDI to) + result = snapshotSvr.takeSnapshot(snapshotInfo); + + if (result.isFailed()) { + s_logger.debug("Failed to take a snapshot: " + result.getResult()); + + throw new CloudRuntimeException(result.getResult()); } - else { - String msg = "Failed to revert the volume to a snapshot"; - s_logger.debug(msg); + // send a command to XenServer to create a VM snapshot on the applicable SR (get back the VDI UUID of the VM snapshot) - volumeInfo.stateTransit(Volume.Event.OperationFailed); + Map sourceDetails = null; - throw new CloudRuntimeException("Failed to revert the volume to a snapshot"); - } - } - } - finally { - if (snapshotVO != null) { - _snapshotDao.releaseFromLockTable(snapshotId); - } - } + VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); - return true; - } + Long vmInstanceId = volumeVO.getInstanceId(); + VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vmInstanceId); - @Override - @DB - public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { - SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotInfo.getId()); + Long hostId = null; - if (snapshotVO == null) { - throw new CloudRuntimeException("Failed to acquire lock on the following snapshot: " + snapshotInfo.getId()); - } + // if the volume to snapshot is associated with a VM + if (vmInstanceVO != null) { + hostId = vmInstanceVO.getHostId(); - try { - VolumeInfo volumeInfo = snapshotInfo.getBaseVolume(); + // if the VM is not associated with a host + if (hostId == null) { + sourceDetails = getSourceDetails(volumeInfo); - volumeInfo.stateTransit(Volume.Event.SnapshotRequested); + hostId = vmInstanceVO.getLastHostId(); + } + } + // volume to snapshot is not associated with a VM (could be a data disk in the detached state) + else { + sourceDetails = getSourceDetails(volumeInfo); + } - SnapshotResult result = null; + long storagePoolId = volumeVO.getPoolId(); + StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - try { - result = snapshotSvr.takeSnapshot(snapshotInfo); + Map destDetails = getDestDetails(storagePoolVO, snapshotInfo); - if (result.isFailed()) { - s_logger.debug("Failed to take the following snapshot: " + result.getResult()); + SnapshotAndCopyCommand snapshotAndCopyCommand = new SnapshotAndCopyCommand(volumeInfo.getPath(), sourceDetails, destDetails); - throw new CloudRuntimeException(result.getResult()); + SnapshotAndCopyAnswer snapshotAndCopyAnswer = null; + + try { + snapshotAndCopyAnswer = (SnapshotAndCopyAnswer)_agentMgr.send(getHostId(hostId, volumeVO), snapshotAndCopyCommand); + } + catch (Exception e) { + throw new CloudRuntimeException(e.getMessage()); } + String path = snapshotAndCopyAnswer.getPath(); // for XenServer, this is the VDI's UUID + + SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(snapshotInfo.getId(), + DiskTO.PATH, + path, + false); + + _snapshotDetailsDao.persist(snapshotDetail); + markAsBackedUp((SnapshotObject)result.getSnashot()); } finally { @@ -250,6 +251,92 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { return snapshotInfo; } + private Map getSourceDetails(VolumeInfo volumeInfo) { + Map sourceDetails = new HashMap(); + + VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); + + long storagePoolId = volumeVO.getPoolId(); + StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); + + sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); + + ChapInfo chapInfo = _volService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); + + if (chapInfo != null) { + sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + sourceDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + sourceDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + sourceDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + } + + return sourceDetails; + } + + private Map getDestDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { + Map destDetails = new HashMap(); + + destDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + destDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + + long snapshotId = snapshotInfo.getId(); + + destDetails.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); + + destDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); + destDetails.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); + destDetails.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); + destDetails.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); + + return destDetails; + } + + private String getProperty(long snapshotId, String property) { + SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, property); + + if (snapshotDetails != null) { + return snapshotDetails.getValue(); + } + + return null; + } + + private Long getHostId(Long hostId, VolumeVO volumeVO) { + HostVO hostVO = _hostDao.findById(hostId); + + if (hostVO != null) { + return hostId; + } + + // pick a host in any XenServer cluster that's in the applicable zone + + long zoneId = volumeVO.getDataCenterId(); + + List clusters = _mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); + + if (clusters == null) { + throw new CloudRuntimeException("Unable to locate an applicable cluster"); + } + + for (Cluster cluster : clusters) { + if (cluster.getAllocationState() == AllocationState.Enabled) { + List hosts = _hostDao.findByClusterId(cluster.getId()); + + if (hosts != null) { + for (HostVO host : hosts) { + if (host.getResourceState() == ResourceState.Enabled) { + return host.getId(); + } + } + } + } + } + + throw new CloudRuntimeException("Unable to locate an applicable cluster"); + } + private void markAsBackedUp(SnapshotObject snapshotObj) { try { snapshotObj.processEvent(Snapshot.Event.BackupToSecondary); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index e7ed264..21f5919 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -62,6 +62,8 @@ import org.apache.cloudstack.storage.command.DettachAnswer; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -142,6 +144,13 @@ public class KVMStorageProcessor implements StorageProcessor { } @Override + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + s_logger.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for KVMStorageProcessor"); + + return new SnapshotAndCopyAnswer(); + } + + @Override public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { DataTO srcData = cmd.getSrcTO(); DataTO destData = cmd.getDestTO(); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java index bdb3277..418dd0c 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java @@ -35,6 +35,8 @@ import org.apache.cloudstack.storage.command.DettachAnswer; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -58,6 +60,13 @@ public class SimulatorStorageProcessor implements StorageProcessor { } @Override + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + s_logger.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for SimulatorStorageProcessor"); + + return new SnapshotAndCopyAnswer(); + } + + @Override public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { TemplateObjectTO template = new TemplateObjectTO(); template.setPath(UUID.randomUUID().toString()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 27f6160..1a39410 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -59,6 +59,8 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -124,6 +126,13 @@ public class VmwareStorageProcessor implements StorageProcessor { _gson = GsonHelper.getGsonLogger(); } + @Override + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + s_logger.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for VmwareStorageProcessor"); + + return new SnapshotAndCopyAnswer(); + } + private String getOVFFilePath(String srcOVAFileName) { File file = new File(srcOVAFileName); assert (_storage != null); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 1412b17..a1067f4 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -1911,7 +1911,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME); String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET); String mountpoint = details.get(DiskTO.MOUNT_POINT); - String protocoltype=details.get(DiskTO.PROTOCOL_TYPE); + String protocoltype = details.get(DiskTO.PROTOCOL_TYPE); if (StoragePoolType.NetworkFilesystem.toString().equalsIgnoreCase(protocoltype)) { String poolid = storageHost + ":" + mountpoint; @@ -6124,8 +6124,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe VDI vdi = null; if (cmd.getAttach() && cmd.isManaged()) { - SR sr = - getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(), cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), true); + SR sr = getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(), cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), true); vdi = getVDIbyUuid(conn, cmd.getVolumePath(), false); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java index 2a1ee1b..933fd20 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java @@ -44,6 +44,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectAnswer; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; +import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; @@ -93,6 +95,67 @@ public class XenServerStorageProcessor implements StorageProcessor { hypervisorResource = resource; } + // if the source SR needs to be attached to, do so + // take a snapshot of the source VDI (on the source SR) + // create an iSCSI SR based on the new back-end volume + // copy the snapshot to the new SR + // delete the snapshot + // detach the new SR + // if we needed to perform an attach to the source SR, detach from it + @Override + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + Connection conn = hypervisorResource.getConnection(); + + try { + SR sourceSr = null; + + Map sourceDetails = cmd.getSourceDetails(); + + if (sourceDetails != null && sourceDetails.keySet().size() > 0) { + String iScsiName = sourceDetails.get(DiskTO.IQN); + String storageHost = sourceDetails.get(DiskTO.STORAGE_HOST); + String chapInitiatorUsername = sourceDetails.get(DiskTO.CHAP_INITIATOR_USERNAME); + String chapInitiatorSecret = sourceDetails.get(DiskTO.CHAP_INITIATOR_SECRET); + + sourceSr = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, false); + } + + VDI vdiToSnapshot = VDI.getByUuid(conn, cmd.getUuidOfSourceVdi()); + + VDI vdiSnapshot = vdiToSnapshot.snapshot(conn, new HashMap()); + + Map destDetails = cmd.getDestDetails(); + + String iScsiName = destDetails.get(DiskTO.IQN); + String storageHost = destDetails.get(DiskTO.STORAGE_HOST); + String chapInitiatorUsername = destDetails.get(DiskTO.CHAP_INITIATOR_USERNAME); + String chapInitiatorSecret = destDetails.get(DiskTO.CHAP_INITIATOR_SECRET); + + SR newSr = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, false); + + VDI vdiCopy = vdiSnapshot.copy(conn, newSr); + + vdiSnapshot.destroy(conn); + + if (sourceSr != null) { + hypervisorResource.removeSR(conn, sourceSr); + } + + hypervisorResource.removeSR(conn, newSr); + + SnapshotAndCopyAnswer snapshotAndCopyAnswer = new SnapshotAndCopyAnswer(); + + snapshotAndCopyAnswer.setPath(vdiCopy.getUuid(conn)); + + return snapshotAndCopyAnswer; + } + catch (Exception ex) { + s_logger.warn("Failed to take and copy snapshot: " + ex.toString(), ex); + + return new SnapshotAndCopyAnswer(ex.getMessage()); + } + } + @Override public AttachAnswer attachIso(AttachCommand cmd) { DiskTO disk = cmd.getDisk(); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/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 1a3085a..17fc4ba 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 @@ -26,7 +26,6 @@ import javax.inject.Inject; 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.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; @@ -48,6 +47,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; import com.cloud.capacity.CapacityManager; import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterDetailsVO; @@ -269,7 +269,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (lstSnapshots != null) { for (SnapshotVO snapshot : lstSnapshots) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID); + SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); // if this snapshot belongs to the storagePool that was passed in if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePool.getId()) { @@ -554,33 +554,33 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { } private void updateSnapshotDetails(long csSnapshotId, long sfNewVolumeId, long storagePoolId, long sfNewVolumeSize, String sfNewVolumeIqn) { - SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId, + SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId, SolidFireUtil.VOLUME_ID, String.valueOf(sfNewVolumeId), false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(snapshotDetail); - accountDetail = new SnapshotDetailsVO(csSnapshotId, - SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID, + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, + SolidFireUtil.STORAGE_POOL_ID, String.valueOf(storagePoolId), false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(snapshotDetail); - accountDetail = new SnapshotDetailsVO(csSnapshotId, + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfNewVolumeSize), false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(snapshotDetail); - accountDetail = new SnapshotDetailsVO(csSnapshotId, - DataMotionStrategy.IQN, + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, + DiskTO.IQN, sfNewVolumeIqn, false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(snapshotDetail); } // return null for no error message http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0cea0346/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 5ea28cb..174dc18 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -95,7 +95,7 @@ public class SolidFireUtil { public static final String VOLUME_SIZE = "sfVolumeSize"; - public static final String SNAPSHOT_STORAGE_POOL_ID = "sfSnapshotStoragePoolId"; + public static final String STORAGE_POOL_ID = "sfStoragePoolId"; public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";