diff --git a/api/src/com/cloud/agent/api/to/DataStoreTO.java b/api/src/com/cloud/agent/api/to/DataStoreTO.java index 9014f8e2b81..b79ba7d64be 100644 --- a/api/src/com/cloud/agent/api/to/DataStoreTO.java +++ b/api/src/com/cloud/agent/api/to/DataStoreTO.java @@ -20,7 +20,7 @@ package com.cloud.agent.api.to; import com.cloud.storage.DataStoreRole; - public interface DataStoreTO { public DataStoreRole getRole(); + public String getUuid(); } diff --git a/api/src/com/cloud/agent/api/to/NfsTO.java b/api/src/com/cloud/agent/api/to/NfsTO.java index 415c95ce3f5..54683c7f410 100644 --- a/api/src/com/cloud/agent/api/to/NfsTO.java +++ b/api/src/com/cloud/agent/api/to/NfsTO.java @@ -22,6 +22,7 @@ public class NfsTO implements DataStoreTO { private String _url; private DataStoreRole _role; + private String uuid; public NfsTO() { @@ -55,6 +56,12 @@ public class NfsTO implements DataStoreTO { this._role = _role; } + @Override + public String getUuid() { + return uuid; + } - + public void setUuid(String uuid) { + this.uuid = uuid; + } } diff --git a/api/src/com/cloud/agent/api/to/SwiftTO.java b/api/src/com/cloud/agent/api/to/SwiftTO.java index 7349d7779ac..3ad131ac4d8 100644 --- a/api/src/com/cloud/agent/api/to/SwiftTO.java +++ b/api/src/com/cloud/agent/api/to/SwiftTO.java @@ -29,8 +29,7 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg { public SwiftTO() { } - public SwiftTO(Long id, String url, String account, String userName, String key - ) { + public SwiftTO(Long id, String url, String account, String userName, String key) { this.id = id; this.url = url; this.account = account; @@ -46,14 +45,17 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg { return url; } + @Override public String getAccount() { return account; } + @Override public String getUserName() { return userName; } + @Override public String getKey() { return key; } @@ -67,4 +69,9 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg { public String getEndPoint() { return this.url; } + + @Override + public String getUuid() { + return null; + } } diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index ec9604e3f90..a762606e9ad 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -199,6 +199,7 @@ public class EventTypes { // Snapshots public static final String EVENT_SNAPSHOT_CREATE = "SNAPSHOT.CREATE"; public static final String EVENT_SNAPSHOT_DELETE = "SNAPSHOT.DELETE"; + public static final String EVENT_SNAPSHOT_REVERT = "SNAPSHOT.REVERT"; public static final String EVENT_SNAPSHOT_POLICY_CREATE = "SNAPSHOTPOLICY.CREATE"; public static final String EVENT_SNAPSHOT_POLICY_UPDATE = "SNAPSHOTPOLICY.UPDATE"; public static final String EVENT_SNAPSHOT_POLICY_DELETE = "SNAPSHOTPOLICY.DELETE"; @@ -387,7 +388,7 @@ public class EventTypes { public static final String EVENT_RESOURCE_DETAILS_CREATE = "CREATE_RESOURCE_DETAILS"; public static final String EVENT_RESOURCE_DETAILS_DELETE = "DELETE_RESOURCE_DETAILS"; - // vm snapshot events + // vm snapshot events public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE"; public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE"; public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO"; @@ -444,7 +445,7 @@ public class EventTypes { public static final String EVENT_DEDICATE_RESOURCE_RELEASE = "DEDICATE.RESOURCE.RELEASE"; public static final String EVENT_CLEANUP_VM_RESERVATION = "VM.RESERVATION.CLEANUP"; - + public static final String EVENT_UCS_ASSOCIATED_PROFILE = "UCS.ASSOCIATEPROFILE"; static { diff --git a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java index 23e65220ff9..4f135107f07 100644 --- a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java +++ b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java @@ -106,4 +106,6 @@ public interface SnapshotApiService { * @return */ Long getHostIdForSnapshotOperation(Volume vol); + + boolean revertSnapshot(Long snapshotId); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java index 26351bb7755..ddf0391a905 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java @@ -59,7 +59,7 @@ public class ListStoragePoolsCmd extends BaseListCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, description="the Zone ID for the storage pool") private Long zoneId; - + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = StoragePoolResponse.class, description="the ID of the storage pool") private Long id; @@ -109,6 +109,7 @@ public class ListStoragePoolsCmd extends BaseListCmd { return s_name; } + @Override public ApiCommandJobType getInstanceType() { return ApiCommandJobType.StoragePool; } diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index 5fa9f8a86e3..29f4a677375 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -23,8 +23,12 @@ import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectCommand; 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 com.cloud.agent.api.Answer; +import org.apache.cloudstack.storage.command.ForgetObjectCmd; +import org.apache.cloudstack.storage.command.IntroduceObjectCmd; public interface StorageProcessor { public Answer copyTemplateToPrimaryStorage(CopyCommand cmd); @@ -43,4 +47,6 @@ public interface StorageProcessor { public Answer deleteVolume(DeleteCommand cmd); public Answer createVolumeFromSnapshot(CopyCommand cmd); public Answer deleteSnapshot(DeleteCommand cmd); + Answer introduceObject(IntroduceObjectCmd cmd); + Answer forgetObject(ForgetObjectCmd cmd); } diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index ab9aa2a3ee6..002143f460e 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; +import org.apache.cloudstack.storage.command.IntroduceObjectCmd; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.log4j.Logger; @@ -55,6 +56,8 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma return execute((AttachCommand)command); } else if (command instanceof DettachCommand) { return execute((DettachCommand)command); + } else if (command instanceof IntroduceObjectCmd) { + return processor.introduceObject((IntroduceObjectCmd)command); } return new Answer((Command)command, false, "not implemented yet"); } @@ -65,7 +68,7 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma DataStoreTO srcDataStore = srcData.getDataStore(); DataStoreTO destDataStore = destData.getDataStore(); - if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (srcDataStore instanceof NfsTO) && (destData.getDataStore().getRole() == DataStoreRole.Primary)) { + if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (destData.getObjectType() == DataObjectType.TEMPLATE && destData.getDataStore().getRole() == DataStoreRole.Primary)) { //copy template to primary storage return processor.copyTemplateToPrimaryStorage(cmd); } else if (srcData.getObjectType() == DataObjectType.TEMPLATE && srcDataStore.getRole() == DataStoreRole.Primary && destDataStore.getRole() == DataStoreRole.Primary) { @@ -80,18 +83,19 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma } else if (destData.getObjectType() == DataObjectType.TEMPLATE) { return processor.createTemplateFromVolume(cmd); } - } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) { + } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.SNAPSHOT && + destData.getDataStore().getRole() == DataStoreRole.Primary) { return processor.backupSnapshot(cmd); } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.VOLUME) { - return processor.createVolumeFromSnapshot(cmd); + return processor.createVolumeFromSnapshot(cmd); } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { return processor.createTemplateFromSnapshot(cmd); } return new Answer(cmd, false, "not implemented yet"); } - - + + protected Answer execute(CreateObjectCommand cmd) { DataTO data = cmd.getData(); try { @@ -106,21 +110,21 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma return new CreateObjectAnswer(e.toString()); } } - + protected Answer execute(DeleteCommand cmd) { DataTO data = cmd.getData(); Answer answer = null; if (data.getObjectType() == DataObjectType.VOLUME) { answer = processor.deleteVolume(cmd); } else if (data.getObjectType() == DataObjectType.SNAPSHOT) { - answer = processor.deleteSnapshot(cmd); + answer = processor.deleteSnapshot(cmd); } else { answer = new Answer(cmd, false, "unsupported type"); } return answer; } - + protected Answer execute(AttachCommand cmd) { DiskTO disk = cmd.getDisk(); if (disk.getType() == Volume.Type.ISO) { @@ -129,7 +133,7 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma return processor.attachVolume(cmd); } } - + protected Answer execute(DettachCommand cmd) { DiskTO disk = cmd.getDisk(); if (disk.getType() == Volume.Type.ISO) { diff --git a/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java b/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java index 0037ea57242..ec6c24092d3 100644 --- a/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java @@ -26,6 +26,7 @@ public class ImageStoreTO implements DataStoreTO { private String uri; private String providerName; private DataStoreRole role; + private String uuid; public ImageStoreTO() { @@ -76,4 +77,13 @@ public class ImageStoreTO implements DataStoreTO { return new StringBuilder("ImageStoreTO[type=").append(type).append("|provider=").append(providerName) .append("|role=").append(role).append("|uri=").append(uri).append("]").toString(); } + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } } diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index 5e870df3716..91d78a49350 100644 --- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -46,6 +46,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { return this.id; } + @Override public String getUuid() { return this.uuid; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java index ca0cc2c970a..b812f6efd99 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java @@ -28,4 +28,6 @@ public interface EndPointSelector { EndPoint select(DataStore store); List selectAll(DataStore store); + + EndPoint select(Scope scope, Long storeId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java index d594a0728cb..e953eb6e21b 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java @@ -24,5 +24,5 @@ public interface SnapshotService { boolean deleteSnapshot(SnapshotInfo snapshot); - boolean revertSnapshot(SnapshotInfo snapshot); + boolean revertSnapshot(Long snapshotId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java index 86ae532e2dc..47e595be6a6 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java @@ -11,7 +11,7 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package org.apache.cloudstack.engine.subsystem.api.storage; @@ -25,5 +25,7 @@ public interface SnapshotStrategy { boolean deleteSnapshot(Long snapshotId); + boolean revertSnapshot(Long snapshotId); + boolean canHandle(Snapshot snapshot); } diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 96d1f5ab785..fb6962a60f1 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -47,7 +47,7 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; - +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -62,9 +62,9 @@ import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.configuration.Config; import com.cloud.host.Host; import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeVO; @@ -81,7 +81,7 @@ import com.cloud.utils.exception.CloudRuntimeException; @Component public class - AncientDataMotionStrategy implements DataMotionStrategy { +AncientDataMotionStrategy implements DataMotionStrategy { private static final Logger s_logger = Logger.getLogger(AncientDataMotionStrategy.class); @Inject EndPointSelector selector; @@ -138,7 +138,8 @@ public class DataTO destTO = destData.getTO(); DataStoreTO srcStoreTO = srcTO.getDataStore(); DataStoreTO destStoreTO = destTO.getDataStore(); - if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) { + if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache || + (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) { return false; } @@ -264,8 +265,14 @@ public class int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CreateVolumeFromSnapshotWait.getDefaultValue())); + EndPoint ep = null; + if (srcData.getDataStore().getRole() == DataStoreRole.Primary) { + ep = selector.select(volObj); + } else { + ep = selector.select(snapObj, volObj); + } + CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait, _mgmtServer.getExecuteInSequence()); - EndPoint ep = selector.select(snapObj, volObj); Answer answer = ep.sendMessage(cmd); return answer; @@ -433,11 +440,17 @@ public class srcData = cacheSnapshotChain(snapshot); } + EndPoint ep = null; + if (srcData.getDataStore().getRole() == DataStoreRole.Primary) { + ep = selector.select(destData); + } else { + ep = selector.select(srcData, destData); + } + CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait, _mgmtServer.getExecuteInSequence()); - EndPoint ep = selector.select(srcData, destData); Answer answer = ep.sendMessage(cmd); - - // clean up snapshot copied to staging + + // clean up snapshot copied to staging if (needCache && srcData != null) { cacheMgr.deleteCacheObject(srcData); } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java index 855d8cbfe0f..d77658b4314 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java @@ -24,7 +24,6 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import com.cloud.capacity.dao.CapacityDao; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider; @@ -39,9 +38,11 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.image.ImageStoreDriver; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; +import org.apache.cloudstack.storage.to.ImageStoreTO; import org.apache.log4j.Logger; import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.capacity.dao.CapacityDao; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.dao.VMTemplateDao; @@ -181,7 +182,16 @@ public class ImageStoreImpl implements ImageStoreEntity { @Override public DataStoreTO getTO() { - return getDriver().getStoreTO(this); + DataStoreTO to = getDriver().getStoreTO(this); + if (to == null) { + ImageStoreTO primaryTO = new ImageStoreTO(); + primaryTO.setProviderName(getProviderName()); + primaryTO.setRole(getRole()); + primaryTO.setType(getProtocol()); + primaryTO.setUri(getUri()); + return primaryTO; + } + return to; } @Override diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java index 2aaabdaf430..c73d1672d27 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java @@ -18,7 +18,50 @@ */ package org.apache.cloudstack.storage.test; -import com.cloud.cluster.LockMasterListener; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import javax.inject.Inject; + +import junit.framework.Assert; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +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.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.volume.VolumeObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; @@ -29,6 +72,7 @@ import com.cloud.dc.dao.HostPodDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.org.Cluster; import com.cloud.org.Managed; +import com.cloud.server.LockMasterListener; import com.cloud.storage.CreateSnapshotPayload; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; @@ -47,53 +91,7 @@ import com.cloud.user.AccountManager; import com.cloud.user.User; import com.cloud.utils.DateUtil; import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.db.DB; import com.cloud.utils.db.Merovingian2; -import junit.framework.Assert; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; -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.SnapshotService; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; -import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.storage.volume.VolumeObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import javax.inject.Inject; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -317,7 +315,7 @@ public class SnapshotTestWithFakeData { final VolumeInfo volumeInfo = createVolume(1L, store); Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready); vol = volumeInfo; - // final SnapshotPolicyVO policyVO = createSnapshotPolicy(vol.getId()); + // final SnapshotPolicyVO policyVO = createSnapshotPolicy(vol.getId()); ExecutorService pool = Executors.newFixedThreadPool(2); @@ -325,7 +323,7 @@ public class SnapshotTestWithFakeData { List> future = new ArrayList>(); for(int i = 0; i < 12; i++) { final int cnt = i; - Future task = pool.submit(new Callable() { + Future task = pool.submit(new Callable() { @Override public Boolean call() throws Exception { boolean r = true; diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 3ead93f9c5f..c09adcad12d 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -17,20 +17,24 @@ package org.apache.cloudstack.storage.snapshot; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.Snapshot; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.snapshot.SnapshotManager; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.snapshot.dao.VMSnapshotDao; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; -import org.apache.cloudstack.engine.subsystem.api.storage.*; +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.DataMotionService; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +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.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -41,13 +45,19 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.inject.Inject; - -import java.util.concurrent.ExecutionException; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Snapshot; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component public class SnapshotServiceImpl implements SnapshotService { @@ -383,7 +393,7 @@ public class SnapshotServiceImpl implements SnapshotService { } @Override - public boolean revertSnapshot(SnapshotInfo snapshot) { + public boolean revertSnapshot(Long snapshotId) { return false; } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java index 1b579227f84..6db8343214b 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java @@ -11,7 +11,7 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package org.apache.cloudstack.storage.snapshot; @@ -35,4 +35,9 @@ public abstract class SnapshotStrategyBase implements SnapshotStrategy { public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { return snapshotSvr.backupSnapshot(snapshot); } + + @Override + public boolean revertSnapshot(Long snapshotId) { + return snapshotSvr.revertSnapshot(snapshotId); + } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index 60d9407f2a0..aae4cde115a 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -11,24 +11,27 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package org.apache.cloudstack.storage.snapshot; import javax.inject.Inject; -import com.cloud.storage.Volume; -import com.cloud.utils.db.DB; -import org.apache.cloudstack.engine.subsystem.api.storage.*; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +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.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -36,9 +39,11 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Volume; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; @@ -236,6 +241,11 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { return true; } + @Override + public boolean revertSnapshot(Long snapshotId) { + throw new CloudRuntimeException("revert Snapshot is not supported"); + } + @Override @DB public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) { diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index fdc12bf1cee..e7c66279e06 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -27,9 +27,6 @@ import java.util.List; import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - 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.EndPoint; @@ -37,6 +34,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.storage.LocalHostEndpoint; import org.apache.cloudstack.storage.RemoteHostEndPoint; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -250,6 +249,11 @@ public class DefaultEndPointSelector implements EndPointSelector { } } + @Override + public EndPoint select(Scope scope, Long storeId) { + return findEndPointInScope(scope, findOneHostOnPrimaryStorage, storeId); + } + @Override public List selectAll(DataStore store) { List endPoints = new ArrayList(); 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 82fd2ce99cc..b1c8ec7622a 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 @@ -18,10 +18,10 @@ */ package com.cloud.hypervisor.kvm.storage; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileNotFoundException; import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; import java.text.DateFormat; @@ -35,11 +35,6 @@ import java.util.UUID; import javax.naming.ConfigurationException; -import com.cloud.agent.api.storage.CopyVolumeAnswer; -import com.cloud.agent.api.to.DataObjectType; -import com.cloud.agent.api.to.S3TO; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.utils.S3Utils; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; @@ -49,6 +44,8 @@ import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; 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.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -57,20 +54,28 @@ import org.apache.cloudstack.utils.qemu.QemuImg; import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.cloudstack.utils.qemu.QemuImgException; import org.apache.cloudstack.utils.qemu.QemuImgFile; -import org.apache.log4j.Logger; import org.apache.commons.io.FileUtils; +import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.Domain; import org.libvirt.DomainInfo; import org.libvirt.DomainSnapshot; import org.libvirt.LibvirtException; +import com.ceph.rados.IoCTX; +import com.ceph.rados.Rados; +import com.ceph.rados.RadosException; +import com.ceph.rbd.Rbd; +import com.ceph.rbd.RbdException; +import com.ceph.rbd.RbdImage; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; +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.agent.api.to.NfsTO; +import com.cloud.agent.api.to.S3TO; import com.cloud.exception.InternalErrorException; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; import com.cloud.hypervisor.kvm.resource.LibvirtConnection; @@ -87,16 +92,10 @@ import com.cloud.storage.template.Processor.FormatInfo; import com.cloud.storage.template.QCOW2Processor; import com.cloud.storage.template.TemplateLocation; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.S3Utils; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import com.ceph.rados.Rados; -import com.ceph.rados.RadosException; -import com.ceph.rados.IoCTX; -import com.ceph.rbd.Rbd; -import com.ceph.rbd.RbdImage; -import com.ceph.rbd.RbdException; - import static com.cloud.utils.S3Utils.putFile; public class KVMStorageProcessor implements StorageProcessor { @@ -197,7 +196,7 @@ public class KVMStorageProcessor implements StorageProcessor { primaryPool, cmd.getWaitInMillSeconds()); - DataTO data = null; + DataTO data = null; /** * Force the ImageFormat for RBD templates to RAW * @@ -370,7 +369,7 @@ public class KVMStorageProcessor implements StorageProcessor { String srcVolumeName = srcVolumePath.substring(index + 1); secondaryStoragePool = storagePoolMgr.getStoragePoolByURI( secondaryStorageUrl + File.separator + volumeDir - ); + ); if (!srcVolumeName.endsWith(".qcow2") && srcFormat == ImageFormat.QCOW2) { srcVolumeName = srcVolumeName + ".qcow2"; } @@ -1207,4 +1206,14 @@ public class KVMStorageProcessor implements StorageProcessor { public Answer deleteSnapshot(DeleteCommand cmd) { return new Answer(cmd); } + + @Override + public Answer introduceObject(IntroduceObjectCmd cmd) { + return new Answer(cmd, false, "not implememented yet"); + } + + @Override + public Answer forgetObject(ForgetObjectCmd cmd) { + return new Answer(cmd, false, "not implememented yet"); + } } diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java index c7768aa5b69..1c992722058 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java @@ -19,14 +19,9 @@ package com.cloud.resource; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DataTO; -import com.cloud.agent.api.to.DiskTO; -import com.cloud.agent.api.to.NfsTO; -import com.cloud.agent.manager.SimulatorManager; -import com.cloud.storage.Storage; -import com.cloud.storage.resource.StorageProcessor; +import java.io.File; +import java.util.UUID; + import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; @@ -36,13 +31,21 @@ import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; 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.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.log4j.Logger; -import java.io.File; -import java.util.UUID; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.NfsTO; +import com.cloud.agent.manager.SimulatorManager; +import com.cloud.storage.Storage; +import com.cloud.storage.resource.StorageProcessor; public class SimulatorStorageProcessor implements StorageProcessor { @@ -214,4 +217,16 @@ public class SimulatorStorageProcessor implements StorageProcessor { public Answer deleteSnapshot(DeleteCommand cmd) { return new Answer(cmd); } + + @Override + public Answer introduceObject(IntroduceObjectCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Answer forgetObject(ForgetObjectCmd cmd) { + // TODO Auto-generated method stub + return null; + } } 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 4982d879751..a14c40337c6 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -26,22 +26,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; - -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import com.google.gson.Gson; -import com.vmware.vim25.ManagedObjectReference; -import com.vmware.vim25.VirtualDeviceConfigSpec; -import com.vmware.vim25.VirtualDeviceConfigSpecOperation; -import com.vmware.vim25.VirtualDisk; -import com.vmware.vim25.VirtualEthernetCard; -import com.vmware.vim25.VirtualLsiLogicController; -import com.vmware.vim25.VirtualMachineConfigSpec; -import com.vmware.vim25.VirtualMachineFileInfo; -import com.vmware.vim25.VirtualMachineGuestOsIdentifier; -import com.vmware.vim25.VirtualSCSISharing; - import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; @@ -50,10 +34,14 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; 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.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -88,10 +76,13 @@ import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.script.Script; import com.cloud.vm.VirtualMachine.State; +import com.google.gson.Gson; +import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.VirtualDisk; public class VmwareStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); - + private VmwareHostService hostService; private boolean _fullCloneFlag; private VmwareStorageMount mountService; @@ -128,9 +119,9 @@ public class VmwareStorageProcessor implements StorageProcessor { } return null; } - + private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage @@ -140,9 +131,9 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = VmwareStorageLayoutHelper.getTemplateOnSecStorageFilePath( - secondaryMountPoint, templatePathAtSecondaryStorage, - templateName, ImageFormat.OVA.getFileExtension()); - + secondaryMountPoint, templatePathAtSecondaryStorage, + templateName, ImageFormat.OVA.getFileExtension()); + String srcFileName = getOVFFilePath(srcOVAFileName); if(srcFileName == null) { Script command = new Script("tar", 0, s_logger); @@ -178,8 +169,8 @@ public class VmwareStorageProcessor implements StorageProcessor { } if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) { - // the same template may be deployed with multiple copies at per-datastore per-host basis, - // save the original template name from CloudStack DB as the UUID to associate them. + // the same template may be deployed with multiple copies at per-datastore per-host basis, + // save the original template name from CloudStack DB as the UUID to associate them. vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateName); vmMo.markAsTemplate(); } else { @@ -197,7 +188,7 @@ public class VmwareStorageProcessor implements StorageProcessor { DataStoreTO srcStore = srcData.getDataStore(); if (!(srcStore instanceof NfsTO)) { return new CopyCmdAnswer("unsupported protocol"); - } + } NfsTO nfsImageStore = (NfsTO)srcStore; DataTO destData = cmd.getDestTO(); DataStoreTO destStore = destData.getDataStore(); @@ -206,9 +197,9 @@ public class VmwareStorageProcessor implements StorageProcessor { assert (secondaryStorageUrl != null); String templateUrl = secondaryStorageUrl + "/" + srcData.getPath(); - + Pair templateInfo = VmwareStorageLayoutHelper.decodeTemplateRelativePathAndNameFromUrl( - secondaryStorageUrl, templateUrl, template.getName()); + secondaryStorageUrl, templateUrl, template.getName()); VmwareContext context = hostService.getServiceContext(cmd); try { @@ -246,7 +237,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return new CopyCmdAnswer(msg); } } - + private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { @@ -265,16 +256,16 @@ public class VmwareStorageProcessor implements StorageProcessor { } s_logger.info("Move volume out of volume-wrapper VM "); - String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true); - String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true); - + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true); + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[0], dcMo.getMor(), true); - + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[1], @@ -292,18 +283,18 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.error(msg); throw new Exception(msg); } - + s_logger.info("Move volume out of volume-wrapper VM "); - String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false); - String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, - vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false); - + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false); + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[0], dcMo.getMor(), true); - + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[1], @@ -343,17 +334,17 @@ public class VmwareStorageProcessor implements StorageProcessor { throw new Exception("Unable to create a dummy VM for volume creation"); } - String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName, - VmwareStorageLayoutType.CLOUDSTACK_LEGACY, - true // we only use the first file in the pair, linked or not will not matter - ); + String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName, + VmwareStorageLayoutType.CLOUDSTACK_LEGACY, + true // we only use the first file in the pair, linked or not will not matter + ); String volumeDatastorePath = vmdkFilePair[0]; synchronized (this) { s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); vmMo.createDisk(volumeDatastorePath, (int) (volume.getSize() / (1024L * 1024L)), morDatastore, -1); vmMo.detachDisk(volumeDatastorePath, false); - } + } VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(vmdkName); @@ -506,7 +497,7 @@ public class VmwareStorageProcessor implements StorageProcessor { try { ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId); - + if (morDs == null) { String msg = "Unable to find volumes's storage pool for copy volume operation"; s_logger.error(msg); @@ -518,7 +509,7 @@ public class VmwareStorageProcessor implements StorageProcessor { // create a dummy worker vm for attaching the volume DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs); workerVm = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVmName); - + if (workerVm == null) { String msg = "Unable to create worker VM to execute CopyVolumeCommand"; s_logger.error(msg); @@ -657,7 +648,7 @@ public class VmwareStorageProcessor implements StorageProcessor { Pair cloneResult = vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(), VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first())); clonedVm = cloneResult.first(); - + clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false); long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); @@ -960,7 +951,7 @@ public class VmwareStorageProcessor implements StorageProcessor { throw new Exception("unable to prepare snapshot backup directory"); } } - } + } VirtualMachineMO clonedVm = null; try { @@ -974,7 +965,7 @@ public class VmwareStorageProcessor implements StorageProcessor { // 4 MB is the minimum requirement for VM memory in VMware Pair cloneResult = vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(), - VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first())); + VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first())); clonedVm = cloneResult.first(); String disks[] = cloneResult.second(); @@ -998,7 +989,7 @@ public class VmwareStorageProcessor implements StorageProcessor { installPath, backupUuid, workerVmName); return new Ternary(backupUuid + "/" + backupUuid, snapshotInfo.first(), snapshotInfo.second()); } - + @Override public Answer backupSnapshot(CopyCommand cmd) { SnapshotObjectTO srcSnapshot = (SnapshotObjectTO)cmd.getSrcTO(); @@ -1025,7 +1016,7 @@ public class VmwareStorageProcessor implements StorageProcessor { String details = null; boolean success = false; String snapshotBackupUuid = null; - + boolean hasOwnerVm = false; Ternary backupResult = null; @@ -1037,7 +1028,7 @@ public class VmwareStorageProcessor implements StorageProcessor { morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid()); CopyCmdAnswer answer = null; - + try { vmMo = hyperHost.findVmOnHyperHost(vmName); if (vmMo == null) { @@ -1050,7 +1041,7 @@ public class VmwareStorageProcessor implements StorageProcessor { dsMo = new DatastoreMO(hyperHost.getContext(), morDs); workerVMName = hostService.getWorkerName(context, cmd, 0); - + vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName); if (vmMo == null) { @@ -1062,12 +1053,12 @@ public class VmwareStorageProcessor implements StorageProcessor { String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk"); vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); } else { - s_logger.info("Using owner VM " + vmName + " for snapshot operation"); - hasOwnerVm = true; + s_logger.info("Using owner VM " + vmName + " for snapshot operation"); + hasOwnerVm = true; } } else { - s_logger.info("Using owner VM " + vmName + " for snapshot operation"); - hasOwnerVm = true; + s_logger.info("Using owner VM " + vmName + " for snapshot operation"); + hasOwnerVm = true; } if (!vmMo.createSnapshot(snapshotUuid, "Snapshot taken for " + srcSnapshot.getName(), false, false)) { @@ -1093,52 +1084,52 @@ public class VmwareStorageProcessor implements StorageProcessor { ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid); if (snapshotMor != null) { vmMo.removeSnapshot(snapshotUuid, false); - + // Snapshot operation may cause disk consolidation in VMware, when this happens // we need to update CloudStack DB // // TODO: this post operation fixup is not atomic and not safe when management server stops // in the middle if(backupResult != null && hasOwnerVm) { - s_logger.info("Check if we have disk consolidation after snapshot operation"); - - boolean chainConsolidated = false; - for(String vmdkDsFilePath : backupResult.third()) { - s_logger.info("Validate disk chain file:" + vmdkDsFilePath); - - if(vmMo.getDiskDevice(vmdkDsFilePath, false) == null) { - s_logger.info("" + vmdkDsFilePath + " no longer exists, consolidation detected"); - chainConsolidated = true; - break; - } else { - s_logger.info("" + vmdkDsFilePath + " is found still in chain"); - } - } - - if(chainConsolidated) { - String topVmdkFilePath = null; - try { - topVmdkFilePath = vmMo.getDiskCurrentTopBackingFileInChain(backupResult.second()); - } catch(Exception e) { - s_logger.error("Unexpected exception", e); - } - - s_logger.info("Disk has been consolidated, top VMDK is now: " + topVmdkFilePath); - if(topVmdkFilePath != null) { - DatastoreFile file = new DatastoreFile(topVmdkFilePath); - - SnapshotObjectTO snapshotInfo = (SnapshotObjectTO)answer.getNewData(); - VolumeObjectTO vol = new VolumeObjectTO(); - vol.setUuid(srcSnapshot.getVolume().getUuid()); - vol.setPath(file.getFileBaseName()); - snapshotInfo.setVolume(vol); - } else { - s_logger.error("Disk has been consolidated, but top VMDK is not found ?!"); - } - } + s_logger.info("Check if we have disk consolidation after snapshot operation"); + + boolean chainConsolidated = false; + for(String vmdkDsFilePath : backupResult.third()) { + s_logger.info("Validate disk chain file:" + vmdkDsFilePath); + + if(vmMo.getDiskDevice(vmdkDsFilePath, false) == null) { + s_logger.info("" + vmdkDsFilePath + " no longer exists, consolidation detected"); + chainConsolidated = true; + break; + } else { + s_logger.info("" + vmdkDsFilePath + " is found still in chain"); + } + } + + if(chainConsolidated) { + String topVmdkFilePath = null; + try { + topVmdkFilePath = vmMo.getDiskCurrentTopBackingFileInChain(backupResult.second()); + } catch(Exception e) { + s_logger.error("Unexpected exception", e); + } + + s_logger.info("Disk has been consolidated, top VMDK is now: " + topVmdkFilePath); + if(topVmdkFilePath != null) { + DatastoreFile file = new DatastoreFile(topVmdkFilePath); + + SnapshotObjectTO snapshotInfo = (SnapshotObjectTO)answer.getNewData(); + VolumeObjectTO vol = new VolumeObjectTO(); + vol.setUuid(srcSnapshot.getVolume().getUuid()); + vol.setPath(file.getFileBaseName()); + snapshotInfo.setVolume(vol); + } else { + s_logger.error("Disk has been consolidated, but top VMDK is not found ?!"); + } + } } } else { - s_logger.error("Can not find the snapshot we just used ?!"); + s_logger.error("Can not find the snapshot we just used ?!"); } } @@ -1152,7 +1143,7 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.warn("Failed to destroy worker VM: " + workerVMName); } } - + return answer; } catch (Throwable e) { if (e instanceof RemoteException) { @@ -1205,7 +1196,7 @@ public class VmwareStorageProcessor implements StorageProcessor { } else { morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid()); - } + } if (morDs == null) { String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + vmName; @@ -1217,30 +1208,30 @@ public class VmwareStorageProcessor implements StorageProcessor { String datastoreVolumePath; if(isAttach) { - if(!isManaged) - datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, - dsMo, volumeTO.getPath()); - else - datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); + if(!isManaged) + datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, + dsMo, volumeTO.getPath()); + else + datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); } else { - datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk"); - if(!dsMo.fileExists(datastoreVolumePath)) - datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk"); + datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk"); + if(!dsMo.fileExists(datastoreVolumePath)) + datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk"); } - + disk.setVdiUuid(datastoreVolumePath); AttachAnswer answer = new AttachAnswer(disk); if (isAttach) { vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); - } else { + } else { vmMo.removeAllSnapshots(); vmMo.detachDisk(datastoreVolumePath, false); if (isManaged) { this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort); } else { - VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath()); + VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath()); } } @@ -1274,7 +1265,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return morDatastore; } - + private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) { try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(hostService.getServiceContext(null), null); @@ -1387,7 +1378,7 @@ public class VmwareStorageProcessor implements StorageProcessor { String volumeDatastorePath = dsMo.getDatastorePath(volumeUuid + ".vmdk"); String dummyVmName = this.hostService.getWorkerName(context, cmd, 0); try { - s_logger.info("Create worker VM " + dummyVmName); + s_logger.info("Create worker VM " + dummyVmName); vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName); if (vmMo == null) { throw new Exception("Unable to create a dummy VM for volume creation"); @@ -1408,8 +1399,8 @@ public class VmwareStorageProcessor implements StorageProcessor { } finally { s_logger.info("Destroy dummy VM after volume creation"); if(vmMo != null) { - vmMo.detachAllDisks(); - vmMo.destroy(); + vmMo.detachAllDisks(); + vmMo.destroy(); } } } catch (Throwable e) { @@ -1460,7 +1451,7 @@ public class VmwareStorageProcessor implements StorageProcessor { ClusterMO clusterMo = new ClusterMO(context, morCluster); if (vol.getVolumeType() == Volume.Type.ROOT) { - + String vmName = vol.getVmName(); if (vmName != null) { VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName); @@ -1471,12 +1462,12 @@ public class VmwareStorageProcessor implements StorageProcessor { // Remove all snapshots to consolidate disks for removal vmMo.removeAllSnapshots(); - + VirtualMachineDiskInfo diskInfo = null; if(vol.getChainInfo() != null) - diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class); - - + diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class); + + HostMO hostMo = vmMo.getRunningHost(); List networks = vmMo.getNetworksWithDetails(); @@ -1484,7 +1475,7 @@ public class VmwareStorageProcessor implements StorageProcessor { if (this.resource.getVmState(vmMo) != State.Stopped) { vmMo.safePowerOff(_shutdown_waitMs); } - + List detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null); VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks); @@ -1501,13 +1492,13 @@ public class VmwareStorageProcessor implements StorageProcessor { } } -/* + /* if (s_logger.isInfoEnabled()) { s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk"); } VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc)); -*/ + */ return new Answer(cmd, true, "Success"); } @@ -1527,8 +1518,8 @@ public class VmwareStorageProcessor implements StorageProcessor { } } - VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc)); - + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc)); + return new Answer(cmd, true, "Success"); } catch (Throwable e) { if (e instanceof RemoteException) { @@ -1672,10 +1663,20 @@ public class VmwareStorageProcessor implements StorageProcessor { return new Answer(cmd, false, "unsupported command"); } } - + + @Override + public Answer introduceObject(IntroduceObjectCmd cmd) { + return new Answer(cmd, false, "not implememented yet"); + } + + @Override + public Answer forgetObject(ForgetObjectCmd cmd) { + return new Answer(cmd, false, "not implememented yet"); + } + private static String deriveTemplateUuidOnHost(VmwareHypervisorHost hyperHost, String storeIdentifier, String templateName) { - String templateUuid = UUID.nameUUIDFromBytes((templateName + "@" + storeIdentifier + "-" + hyperHost.getMor().getValue()).getBytes()).toString(); - templateUuid = templateUuid.replaceAll("-", ""); - return templateUuid; + String templateUuid = UUID.nameUUIDFromBytes((templateName + "@" + storeIdentifier + "-" + hyperHost.getMor().getValue()).getBytes()).toString(); + templateUuid = templateUuid.replaceAll("-", ""); + return templateUuid; } } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index 739b9743f44..5da0571fc94 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -18,6 +18,36 @@ */ package com.cloud.hypervisor.xen.resource; +import java.io.File; +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.cloudstack.storage.command.AttachAnswer; +import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; +import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; +import org.apache.cloudstack.storage.command.CreateObjectCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; +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.IntroduceObjectAnswer; +import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.CreateStoragePoolCommand; import com.cloud.agent.api.to.DataObjectType; @@ -51,33 +81,6 @@ import com.xensource.xenapi.VBD; import com.xensource.xenapi.VDI; import com.xensource.xenapi.VM; import com.xensource.xenapi.VMGuestMetrics; -import org.apache.cloudstack.storage.command.AttachAnswer; -import org.apache.cloudstack.storage.command.AttachCommand; -import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; -import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.CreateObjectAnswer; -import org.apache.cloudstack.storage.command.CreateObjectCommand; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.command.DettachAnswer; -import org.apache.cloudstack.storage.command.DettachCommand; -import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; -import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.log4j.Logger; -import org.apache.xmlrpc.XmlRpcException; - -import java.io.File; -import java.net.URI; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import static com.cloud.utils.ReflectUtil.flattenProperties; import static com.google.common.collect.Lists.newArrayList; @@ -841,8 +844,7 @@ public class XenServerStorageProcessor implements StorageProcessor { URI uri = new URI(storeUrl); String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath(); - PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore(); - String poolName = destStore.getUuid(); + String poolName = destData.getDataStore().getUuid(); Connection conn = hypervisorResource.getConnection(); SR poolsr = null; @@ -892,8 +894,7 @@ public class XenServerStorageProcessor implements StorageProcessor { try { Connection conn = hypervisorResource.getConnection(); - PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore(); - SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid()); + SR poolSr = hypervisorResource.getStorageRepository(conn, data.getDataStore().getUuid()); VDI.Record vdir = new VDI.Record(); vdir.nameLabel = volume.getName(); vdir.SR = poolSr; @@ -921,7 +922,6 @@ public class XenServerStorageProcessor implements StorageProcessor { Connection conn = hypervisorResource.getConnection(); DataTO srcData = cmd.getSrcTO(); DataTO destData = cmd.getDestTO(); - PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore(); VolumeObjectTO volume = (VolumeObjectTO)destData; VDI vdi = null; try { @@ -943,7 +943,7 @@ public class XenServerStorageProcessor implements StorageProcessor { return new CopyCmdAnswer(newVol); } catch (Exception e) { - s_logger.warn("Unable to create volume; Pool=" + pool + "; Disk: ", e); + s_logger.warn("Unable to create volume; Pool=" + destData + "; Disk: ", e); return new CopyCmdAnswer(e.toString()); } } @@ -956,13 +956,12 @@ public class XenServerStorageProcessor implements StorageProcessor { int wait = cmd.getWait(); VolumeObjectTO srcVolume = (VolumeObjectTO)srcData; VolumeObjectTO destVolume = (VolumeObjectTO)destData; - PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore(); DataStoreTO srcStore = srcVolume.getDataStore(); if (srcStore instanceof NfsTO) { NfsTO nfsStore = (NfsTO)srcStore; try { - SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid()); + SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, destVolume.getDataStore().getUuid()); String srUuid = primaryStoragePool.getUuid(conn); URI uri = new URI(nfsStore.getUrl()); String volumePath = uri.getHost() + ":" + uri.getPath() + File.separator + srcVolume.getPath(); @@ -1179,8 +1178,7 @@ public class XenServerStorageProcessor implements StorageProcessor { DataTO cacheData = cmd.getCacheTO(); DataTO destData = cmd.getDestTO(); int wait = cmd.getWait(); - PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore(); - String primaryStorageNameLabel = primaryStore.getUuid(); + String primaryStorageNameLabel = srcData.getDataStore().getUuid(); String secondaryStorageUrl = null; NfsTO cacheStore = null; String destPath = null; @@ -1415,7 +1413,6 @@ public class XenServerStorageProcessor implements StorageProcessor { DataTO srcData = cmd.getSrcTO(); SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData; DataTO destData = cmd.getDestTO(); - PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore(); DataStoreTO imageStore = srcData.getDataStore(); if (!(imageStore instanceof NfsTO)) { @@ -1423,7 +1420,7 @@ public class XenServerStorageProcessor implements StorageProcessor { } NfsTO nfsImageStore = (NfsTO)imageStore; - String primaryStorageNameLabel = pool.getUuid(); + String primaryStorageNameLabel = destData.getDataStore().getUuid(); String secondaryStorageUrl = nfsImageStore.getUrl(); int wait = cmd.getWait(); boolean result = false; @@ -1503,4 +1500,32 @@ public class XenServerStorageProcessor implements StorageProcessor { } return new Answer(cmd, false, "unsupported storage type"); } + + @Override + public Answer introduceObject(IntroduceObjectCmd cmd) { + try { + Connection conn = hypervisorResource.getConnection(); + DataStoreTO store = cmd.getDataTO().getDataStore(); + SR poolSr = hypervisorResource.getStorageRepository(conn, store.getUuid()); + poolSr.scan(conn); + return new IntroduceObjectAnswer(cmd.getDataTO()); + } catch (Exception e) { + s_logger.debug("Failed to introduce object", e); + return new Answer(cmd, false, e.toString()); + } + } + + @Override + public Answer forgetObject(ForgetObjectCmd cmd) { + try { + Connection conn = hypervisorResource.getConnection(); + DataTO data = cmd.getDataTO(); + VDI vdi = VDI.getByUuid(conn, data.getPath()); + vdi.forget(conn); + return new IntroduceObjectAnswer(cmd.getDataTO()); + } catch (Exception e) { + s_logger.debug("Failed to introduce object", e); + return new Answer(cmd, false, e.toString()); + } + } } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 2297e6adde3..0b53cfda11f 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -48,7 +48,6 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -69,13 +68,11 @@ import com.cloud.event.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.UsageEventUtils; -import com.cloud.event.dao.EventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.resource.ResourceManager; @@ -193,10 +190,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Inject VolumeDataFactory volFactory; @Inject SnapshotDataFactory snapshotFactory; @Inject EndPointSelector _epSelector; - @Inject - private ResourceManager _resourceMgr; - @Inject - protected List snapshotStrategies; + @Inject + private ResourceManager _resourceMgr; + @Inject + protected List snapshotStrategies; private int _totalRetries; @@ -260,17 +257,39 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return null; } + @Override + public boolean revertSnapshot(Long snapshotId) { + Snapshot snapshot = _snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new InvalidParameterValueException("No such snapshot"); + } + + SnapshotStrategy snapshotStrategy = null; + for (SnapshotStrategy strategy : snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + snapshotStrategy = strategy; + break; + } + } + + if (snapshotStrategy == null) { + return false; + } + + return snapshotStrategy.revertSnapshot(snapshotId); + } + @Override @DB @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true) public Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) { VolumeInfo volume = volFactory.getVolume(volumeId); if (volume == null) { - throw new InvalidParameterValueException("No such volume exist"); + throw new InvalidParameterValueException("No such volume exist"); } if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("Volume is not in ready state"); + throw new InvalidParameterValueException("Volume is not in ready state"); } @@ -281,16 +300,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary); try { - postCreateSnapshot(volumeId, snapshot.getId(), policyId); - //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event - SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); - if ((freshSnapshot != null) && backedUp) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), - snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, - volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); - } + postCreateSnapshot(volumeId, snapshot.getId(), policyId); + //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event + SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); + if ((freshSnapshot != null) && backedUp) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), + snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, + volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); + } - _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); + _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); } catch(Exception e) { s_logger.debug("Failed to create snapshot", e); @@ -311,12 +330,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Override public Snapshot backupSnapshot(Long snapshotId) { - SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image); - if (snapshot != null) { - throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId); - } + SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image); + if (snapshot != null) { + throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId); + } - return snapshotSrv.backupSnapshot(snapshot); + return snapshotSrv.backupSnapshot(snapshot); } /* @@ -412,14 +431,14 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Override public SnapshotVO getParentSnapshot(VolumeInfo volume) { - long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary); + long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary); - SnapshotVO preSnapshotVO = null; - if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) { - preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId); - } + SnapshotVO preSnapshotVO = null; + if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) { + preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId); + } - return preSnapshotVO; + return preSnapshotVO; } private Long getSnapshotUserId() { @@ -463,7 +482,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId); } if(deleteSnapshot(oldSnapId)){ - //log Snapshot delete event + //log Snapshot delete event ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0); } snaps.remove(oldestSnapshot); @@ -485,27 +504,27 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, _accountMgr.checkAccess(caller, null, true, snapshotCheck); SnapshotStrategy snapshotStrategy = null; for (SnapshotStrategy strategy : snapshotStrategies) { - if (strategy.canHandle(snapshotCheck)) { - snapshotStrategy = strategy; - break; - } + if (strategy.canHandle(snapshotCheck)) { + snapshotStrategy = strategy; + break; + } } try { - boolean result = snapshotStrategy.deleteSnapshot(snapshotId); - if (result) { + boolean result = snapshotStrategy.deleteSnapshot(snapshotId); + if (result) { if (snapshotCheck.getState() == Snapshot.State.BackedUp) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), - snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L, - snapshotCheck.getClass().getName(), snapshotCheck.getUuid()); - } + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), + snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L, + snapshotCheck.getClass().getName(), snapshotCheck.getUuid()); + } _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot); _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, new Long(snapshotCheck.getSize())); - } - return result; + } + return result; } catch (Exception e) { - s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString()); - throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString()); + s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString()); + throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString()); } } @@ -544,10 +563,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); - _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); - Long domainId = domainIdRecursiveListProject.first(); - Boolean isRecursive = domainIdRecursiveListProject.second(); - ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); + Long domainId = domainIdRecursiveListProject.first(); + Boolean isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); Filter searchFilter = new Filter(SnapshotVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchBuilder sb = _snapshotDao.createSearchBuilder(); @@ -560,7 +579,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN); sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); - + if (tags != null && !tags.isEmpty()) { SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); for (int count=0; count < tags.size(); count++) { @@ -595,7 +614,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if (zoneId != null) { sc.setParameters("dataCenterId", zoneId); } - + if (name != null) { sc.setParameters("name", "%" + name + "%"); } @@ -763,10 +782,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, long domainLimit = _resourceLimitMgr.findCorrectResourceLimitForDomain(_domainMgr.getDomain(owner.getDomainId()), ResourceType.snapshot); int max = cmd.getMaxSnaps().intValue(); if (owner.getType() != Account.ACCOUNT_TYPE_ADMIN && ((accountLimit != -1 && max > accountLimit) || (domainLimit != -1 && max > domainLimit))) { - String message = "domain/account"; - if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) { - message = "domain/project"; - } + String message = "domain/account"; + if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) { + message = "domain/project"; + } throw new InvalidParameterValueException("Max number of snapshots shouldn't exceed the " + message + " level snapshot limit"); } @@ -905,37 +924,37 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo volume) { - if (host.getHypervisorType() != HypervisorType.KVM) { - return true; - } + if (host.getHypervisorType() != HypervisorType.KVM) { + return true; + } //Turn off snapshot by default for KVM if the volume attached to vm that is not in the Stopped/Destroyed state, - //unless it is set in the global flag - Long vmId = volume.getInstanceId(); - if (vmId != null) { - VMInstanceVO vm = _vmDao.findById(vmId); - if (vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Destroyed) { - boolean snapshotEnabled = Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled")); - if (!snapshotEnabled) { - s_logger.debug("Snapshot is not supported on host " + host + " for the volume " + volume + " attached to the vm " + vm); - return false; - } - } - } - - // Determine host capabilities - String caps = host.getCapabilities(); + //unless it is set in the global flag + Long vmId = volume.getInstanceId(); + if (vmId != null) { + VMInstanceVO vm = _vmDao.findById(vmId); + if (vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Destroyed) { + boolean snapshotEnabled = Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled")); + if (!snapshotEnabled) { + s_logger.debug("Snapshot is not supported on host " + host + " for the volume " + volume + " attached to the vm " + vm); + return false; + } + } + } - if (caps != null) { - String[] tokens = caps.split(","); - for (String token : tokens) { - if (token.contains("snapshot")) { - return true; - } - } - } - return false; - } + // Determine host capabilities + String caps = host.getCapabilities(); + + if (caps != null) { + String[] tokens = caps.split(","); + for (String token : tokens) { + if (token.contains("snapshot")) { + return true; + } + } + } + return false; + } private boolean supportedByHypervisor(VolumeInfo volume) { HypervisorType hypervisorType; @@ -967,10 +986,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } - // if volume is attached to a vm in destroyed or expunging state; disallow - if (volume.getInstanceId() != null) { - UserVmVO userVm = _vmDao.findById(volume.getInstanceId()); - if (userVm != null) { + // if volume is attached to a vm in destroyed or expunging state; disallow + if (volume.getInstanceId() != null) { + UserVmVO userVm = _vmDao.findById(volume.getInstanceId()); + if (userVm != null) { if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) { throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in " @@ -993,11 +1012,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new CloudRuntimeException( "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later"); } - } - } + } + } - return true; - } + return true; + } @Override @DB public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException { @@ -1124,10 +1143,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, public boolean canOperateOnVolume(Volume volume) { List snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); - if (snapshots.size() > 0) { - return false; - } - return true; + if (snapshots.size() > 0) { + return false; + } + return true; } @Override diff --git a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 3ef950b1a0b..e26f02d89f4 100755 --- a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -16,14 +16,15 @@ // under the License. package org.apache.cloudstack.storage.resource; -import static com.cloud.utils.S3Utils.putFile; -import static com.cloud.utils.StringUtils.join; -import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock; -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static org.apache.commons.lang.StringUtils.substringAfterLast; - -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; import java.net.InetAddress; import java.net.URI; @@ -39,10 +40,6 @@ import java.util.concurrent.Callable; import javax.naming.ConfigurationException; -import com.cloud.agent.api.storage.*; -import com.cloud.storage.VMTemplateStorageResourceAssoc; -import com.cloud.storage.template.*; -import com.cloud.utils.SwiftUtil; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DeleteCommand; @@ -53,6 +50,8 @@ import org.apache.cloudstack.storage.template.DownloadManagerImpl; import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser; import org.apache.cloudstack.storage.template.UploadManager; import org.apache.cloudstack.storage.template.UploadManagerImpl; +import org.apache.cloudstack.storage.to.ImageStoreTO; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -88,6 +87,14 @@ import com.cloud.agent.api.SecStorageSetupCommand.Certificates; import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupSecondaryStorageCommand; +import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; +import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand; +import com.cloud.agent.api.storage.DownloadAnswer; +import com.cloud.agent.api.storage.ListTemplateAnswer; +import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.storage.ListVolumeAnswer; +import com.cloud.agent.api.storage.ListVolumeCommand; +import com.cloud.agent.api.storage.UploadCommand; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; @@ -101,16 +108,34 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageLayer; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.template.Processor; import com.cloud.storage.template.Processor.FormatInfo; +import com.cloud.storage.template.QCOW2Processor; +import com.cloud.storage.template.RawImageProcessor; +import com.cloud.storage.template.TemplateLocation; +import com.cloud.storage.template.TemplateProp; +import com.cloud.storage.template.VhdProcessor; +import com.cloud.storage.template.VmdkProcessor; import com.cloud.utils.NumbersUtil; import com.cloud.utils.S3Utils; import com.cloud.utils.S3Utils.FileNamingStrategy; +import com.cloud.utils.SwiftUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.vm.SecondaryStorageVm; +import com.google.common.io.Files; + +import static com.cloud.utils.S3Utils.putFile; +import static com.cloud.utils.StringUtils.join; +import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static org.apache.commons.lang.StringUtils.substringAfterLast; public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { @@ -357,6 +382,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S snapshotName = snapshotName + ".vhd"; } snapshotPath = snapshotPath.substring(0, index); + snapshotPath = srcMountPoint + File.separator + snapshotPath; String destMountPoint = this.getRootDir(destDataStore.getUrl()); String destPath = destMountPoint + File.separator + destData.getPath(); @@ -424,7 +450,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S // get snapshot file name String templateName = srcFile.getName(); - // add kvm file extension for copied template name + // add kvm file extension for copied template name String fileName = templateName + "." + srcFormat.getFileExtension(); String destFileFullPath = destFile.getAbsolutePath() + File.separator + fileName; s_logger.debug("copy snapshot " + srcFile.getAbsolutePath() + " to template " + destFileFullPath); @@ -509,15 +535,16 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S DataTO destData = cmd.getDestTO(); DataStoreTO srcDataStore = srcData.getDataStore(); DataStoreTO destDataStore = destData.getDataStore(); - if (srcDataStore.getRole() == DataStoreRole.Image || srcDataStore.getRole() == DataStoreRole.ImageCache) { + if (srcDataStore.getRole() == DataStoreRole.Image || srcDataStore.getRole() == DataStoreRole.ImageCache || + srcDataStore.getRole() == DataStoreRole.Primary) { if (!(srcDataStore instanceof NfsTO)) { s_logger.debug("only support nfs storage as src, when create template from snapshot"); return Answer.createUnsupportedCommandAnswer(cmd); } if (destDataStore instanceof NfsTO) { - return copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO) srcDataStore, - (TemplateObjectTO) destData, (NfsTO) destDataStore); + return copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO)srcDataStore, + (TemplateObjectTO) destData, (NfsTO)destDataStore); } else if (destDataStore instanceof SwiftTO) { //create template on the same data store CopyCmdAnswer answer = (CopyCmdAnswer)copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO) srcDataStore, @@ -543,8 +570,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S execute(deleteCommand); } catch (Exception e) { s_logger.debug("Failed to clean up staging area:", e); - } - + } + TemplateObjectTO template = new TemplateObjectTO(); template.setPath(swiftPath); template.setSize(templateFile.length()); @@ -569,7 +596,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S execute(deleteCommand); } catch (Exception e) { s_logger.debug("Failed to clean up staging area:", e); - } + } return result; } } @@ -792,7 +819,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S processor.configure("template processor", new HashMap()); return processor.getVirtualSize(file); } catch (Exception e) { - s_logger.debug("Failed to get virtual size:" ,e); + s_logger.debug("Failed to get virtual size:" ,e); } return file.length(); } @@ -2226,8 +2253,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S * * CIFS parameters are documented with mount.cifs at * http://linux.die.net/man/8/mount.cifs - * For simplicity, when a URI is used to specify a CIFS share, - * options such as domain,user,password are passed as query parameters. + * For simplicity, when a URI is used to specify a CIFS share, + * options such as domain,user,password are passed as query parameters. * * @param uri * crresponding to the remote device. Will throw for unsupported @@ -2262,7 +2289,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return dir; } - + protected void umount(String localRootPath, URI uri) { ensureLocalRootPathExists(localRootPath, uri); @@ -2286,7 +2313,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } s_logger.debug("Successfully umounted " + localRootPath); } - + protected void mount(String localRootPath, String remoteDevice, URI uri) { s_logger.debug("mount " + uri.toString() + " on " + localRootPath); ensureLocalRootPathExists(localRootPath, uri);