You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2014/01/09 01:50:59 UTC

[1/3] git commit: updated refs/heads/4.3 to 693f0c2

Updated Branches:
  refs/heads/4.3 f7e0a540d -> 693f0c280


CLOUDSTACK-5841:Snapshots taken before migration NFS to S3 can not be
used cross-zone.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/693f0c28
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/693f0c28
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/693f0c28

Branch: refs/heads/4.3
Commit: 693f0c280ae9955e57b6b90c5f7709d61902ba8b
Parents: 62aa147
Author: Min Chen <mi...@citrix.com>
Authored: Wed Jan 8 16:31:12 2014 -0800
Committer: Min Chen <mi...@citrix.com>
Committed: Wed Jan 8 16:33:37 2014 -0800

----------------------------------------------------------------------
 .../api/storage/SnapshotDataFactory.java        |   2 +
 .../subsystem/api/storage/SnapshotService.java  |   2 +
 .../orchestration/VolumeOrchestrator.java       |  16 ++-
 .../datastore/db/SnapshotDataStoreDao.java      |   2 +
 .../storage/image/TemplateServiceImpl.java      |   3 +
 .../snapshot/SnapshotDataFactoryImpl.java       |  12 ++
 .../storage/snapshot/SnapshotObject.java        |  17 ++-
 .../storage/snapshot/SnapshotServiceImpl.java   | 130 +++++++++++++++++--
 .../endpoint/DefaultEndPointSelector.java       |   7 +-
 .../image/db/SnapshotDataStoreDaoImpl.java      |  10 ++
 10 files changed, 178 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java
index d5255f4..01b0cde 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java
@@ -30,4 +30,6 @@ public interface SnapshotDataFactory {
     SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role);
 
     List<SnapshotInfo> listSnapshotOnCache(long snapshotId);
+    
+    SnapshotInfo getReadySnapshotOnCache(long snapshotId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
----------------------------------------------------------------------
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 e953eb6..000b9ec 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
@@ -25,4 +25,6 @@ public interface SnapshotService {
     boolean deleteSnapshot(SnapshotInfo snapshot);
 
     boolean revertSnapshot(Long snapshotId);
+
+    void syncVolumeSnapshotsToRegionStore(long volumeId, DataStore store);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index ff6ace8..268b317 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -31,12 +31,14 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
 import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 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.SnapshotService;
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
@@ -144,6 +146,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
     ConfigDepot _configDepot;
     @Inject
     HostDao _hostDao;
+    @Inject
+    SnapshotService _snapshotSrv;
 
     private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
     protected List<StoragePoolAllocator> _storagePoolAllocators;
@@ -346,6 +350,16 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
         VolumeInfo vol = volFactory.getVolume(volume.getId());
         DataStore store = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
         SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Image);
+        // sync snapshot to region store if necessary
+        DataStore snapStore = snapInfo.getDataStore();
+        long snapVolId = snapInfo.getVolumeId();
+        try {
+            _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, snapStore);
+        } catch (Exception ex) {
+            // log but ignore the sync error to avoid any potential S3 down issue, it should be sync next time
+            s_logger.warn(ex.getMessage(), ex);
+        }
+        // create volume on primary from snapshot
         AsyncCallFuture<VolumeApiResult> future = volService.createVolumeFromSnapshot(vol, store, snapInfo);
         try {
             VolumeApiResult result = future.get();
@@ -771,7 +785,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
             templateIdToUse = vmTemplateId;
         }
 
-        final Long templateIdToUseFinal = templateIdToUse; 
+        final Long templateIdToUseFinal = templateIdToUse;
         return Transaction.execute(new TransactionCallback<VolumeVO>() {
             @Override
             public VolumeVO doInTransaction(TransactionStatus status) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
index 666d2ce..b995fbb 100644
--- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
@@ -47,6 +47,8 @@ StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Even
     // delete the snapshot entry on primary data store to make sure that next snapshot will be full snapshot
     void deleteSnapshotRecordsOnPrimary();
 
+    SnapshotDataStoreVO findReadyOnCache(long snapshotId);
+
     List<SnapshotDataStoreVO> listOnCache(long snapshotId);
 
     void updateStoreRoleToCache(long storeId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
index cf9b473..7514f43 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
@@ -704,6 +704,9 @@ public class TemplateServiceImpl implements TemplateService {
     @Override
     public void syncTemplateToRegionStore(long templateId, DataStore store) {
         if (_storeMgr.isRegionStore(store)) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Sync template " + templateId + " from cache to object store...");
+            }
             // if template is on region wide object store, check if it is really downloaded there (by checking install_path). Sync template to region
             // wide store if it is not there physically.
             TemplateInfo tmplOnStore = _templateFactory.getTemplate(templateId, store);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
index 6205fe4..16c14f3 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
@@ -80,6 +80,18 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory {
     }
 
     @Override
+    public SnapshotInfo getReadySnapshotOnCache(long snapshotId) {
+        SnapshotDataStoreVO snapStore = snapshotStoreDao.findReadyOnCache(snapshotId);
+        if (snapStore != null) {
+            DataStore store = storeMgr.getDataStore(snapStore.getDataStoreId(), DataStoreRole.ImageCache);
+            return getSnapshot(snapshotId, store);
+        } else {
+            return null;
+        }
+
+    }
+
+    @Override
     public List<SnapshotInfo> listSnapshotOnCache(long snapshotId) {
         List<SnapshotDataStoreVO> cacheSnapshots = snapshotStoreDao.listOnCache(snapshotId);
         List<SnapshotInfo> snapObjs = new ArrayList<SnapshotInfo>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index 63ca1bd..314ce8e 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -19,10 +19,11 @@
 package org.apache.cloudstack.storage.snapshot;
 
 import java.util.Date;
-import java.util.List;
 
 import javax.inject.Inject;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
@@ -30,7 +31,6 @@ 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.SnapshotStrategy;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation;
-import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
 import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -40,7 +40,6 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
 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 com.cloud.agent.api.Answer;
 import com.cloud.agent.api.to.DataObjectType;
@@ -79,6 +78,7 @@ public class SnapshotObject implements SnapshotInfo {
     SnapshotDataStoreDao snapshotStoreDao;
     @Inject
     StorageStrategyFactory storageStrategyFactory;
+    private String installPath; // temporarily set installPath before passing to resource for entries with empty installPath for object store migration case
 
     public SnapshotObject() {
 
@@ -200,6 +200,9 @@ public class SnapshotObject implements SnapshotInfo {
 
     @Override
     public String getPath() {
+        if (installPath != null)
+            return installPath;
+
         DataObjectInStore objectInStore = objectInStoreMgr.findObject(this, getDataStore());
         if (objectInStore != null) {
             return objectInStore.getInstallPath();
@@ -207,6 +210,10 @@ public class SnapshotObject implements SnapshotInfo {
         return null;
     }
 
+    public void setPath(String installPath) {
+        this.installPath = installPath;
+    }
+
     @Override
     public String getName() {
         return snapshot.getName();
@@ -360,12 +367,12 @@ public class SnapshotObject implements SnapshotInfo {
 
     @Override
     public void addPayload(Object data) {
-        this.payload = data;
+        payload = data;
     }
 
     @Override
     public Object getPayload() {
-        return this.payload;
+        return payload;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
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 7df2432..f1a7d74 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,10 +17,14 @@
 
 package org.apache.cloudstack.storage.snapshot;
 
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.Snapshot;
-import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.fsm.NoTransitionException;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
 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;
@@ -28,11 +32,13 @@ 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.PrimaryDataStore;
 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.StorageCacheManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
@@ -40,26 +46,32 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.framework.async.AsyncRpcContext;
 import org.apache.cloudstack.storage.command.CommandResult;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
 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.storage.DataStoreRole;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.template.TemplateConstants;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
 
 @Component
 public class SnapshotServiceImpl implements SnapshotService {
     private static final Logger s_logger = Logger.getLogger(SnapshotServiceImpl.class);
     @Inject
+    protected SnapshotDao _snapshotDao;
+    @Inject
     protected SnapshotDataStoreDao _snapshotStoreDao;
     @Inject
-    SnapshotDataFactory snapshotfactory;
+    SnapshotDataFactory _snapshotFactory;
     @Inject
     DataStoreManager dataStoreMgr;
     @Inject
     DataMotionService motionSrv;
+    @Inject
+    StorageCacheManager _cacheMgr;
 
     static private class CreateSnapshotContext<T> extends AsyncRpcContext<T> {
         final SnapshotInfo snapshot;
@@ -249,7 +261,7 @@ public class SnapshotServiceImpl implements SnapshotService {
         try {
             snapObj.processEvent(Snapshot.Event.BackupToSecondary);
 
-            DataStore imageStore = this.findSnapshotImageStore(snapshot);
+            DataStore imageStore = findSnapshotImageStore(snapshot);
             if (imageStore == null) {
                 throw new CloudRuntimeException("can not find an image stores");
             }
@@ -262,7 +274,7 @@ public class SnapshotServiceImpl implements SnapshotService {
             AsyncCallbackDispatcher<SnapshotServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher
                     .create(this);
             caller.setCallback(caller.getTarget().copySnapshotAsyncCallback(null, null)).setContext(context);
-            this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller);
+            motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller);
         } catch (Exception e) {
             s_logger.debug("Failed to copy snapshot", e);
             result.setResult("Failed to copy snapshot:" + e.toString());
@@ -314,7 +326,7 @@ public class SnapshotServiceImpl implements SnapshotService {
             CopyCmdAnswer answer = (CopyCmdAnswer) result.getAnswer();
             destSnapshot.processEvent(Event.OperationSuccessed, result.getAnswer());
             srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
-            snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId(),
+            snapResult = new SnapshotResult(_snapshotFactory.getSnapshot(destSnapshot.getId(),
                     destSnapshot.getDataStore()), answer);
             future.complete(snapResult);
         } catch (Exception e) {
@@ -403,7 +415,7 @@ public class SnapshotServiceImpl implements SnapshotService {
 
     @Override
     public boolean revertSnapshot(Long snapshotId) {
-        SnapshotInfo snapshot = snapshotfactory.getSnapshot(snapshotId, DataStoreRole.Primary);
+        SnapshotInfo snapshot = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
         PrimaryDataStore store = (PrimaryDataStore)snapshot.getDataStore();
 
         AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
@@ -429,4 +441,94 @@ public class SnapshotServiceImpl implements SnapshotService {
         return false;
     }
 
+    
+    // This routine is used to push snapshots currently on cache store, but not in region store to region store.
+    // used in migrating existing NFS secondary storage to S3. We chose to push all volume related snapshots to handle delta snapshots smoothly.
+    @Override
+    public void syncVolumeSnapshotsToRegionStore(long volumeId, DataStore store) {
+        if (dataStoreMgr.isRegionStore(store)) {
+            // list all backed up snapshots for the given volume
+            List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volumeId, Snapshot.State.BackedUp);
+            if (snapshots != null ){
+                for (SnapshotVO snapshot : snapshots){
+                    syncSnapshotToRegionStore(snapshot.getId(), store);
+                }
+            }
+        }
+    }
+    
+    // push one individual snapshots currently on cache store to region store if it is not there already
+    private void syncSnapshotToRegionStore(long snapshotId, DataStore store){
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("sync snapshot " + snapshotId + " from cache to object store...");
+        }
+        // if snapshot is already on region wide object store, check if it is really downloaded there (by checking install_path). Sync snapshot to region
+        // wide store if it is not there physically.
+        SnapshotInfo snapOnStore = _snapshotFactory.getSnapshot(snapshotId, store);
+        if (snapOnStore == null) {
+            throw new CloudRuntimeException("Cannot find an entry in snapshot_store_ref for snapshot " + snapshotId + " on region store: " + store.getName());
+        }
+        if (snapOnStore.getPath() == null || snapOnStore.getPath().length() == 0) {
+            // snapshot is not on region store yet, sync to region store
+            SnapshotInfo srcSnapshot = _snapshotFactory.getReadySnapshotOnCache(snapshotId);
+            if (srcSnapshot == null) {
+                throw new CloudRuntimeException("Cannot find snapshot " + snapshotId + "  on cache store");
+            }
+            AsyncCallFuture<SnapshotResult> future = syncToRegionStoreAsync(srcSnapshot, store);
+            try {
+                SnapshotResult result = future.get();
+                if (result.isFailed()) {
+                    throw new CloudRuntimeException("sync snapshot from cache to region wide store failed for image store " + store.getName() + ":"
+                            + result.getResult());
+                }
+                _cacheMgr.releaseCacheObject(srcSnapshot); // reduce reference count for template on cache, so it can recycled by schedule
+            } catch (Exception ex) {
+                throw new CloudRuntimeException("sync snapshot from cache to region wide store failed for image store " + store.getName());
+            }
+        }
+
+    }
+
+
+    private AsyncCallFuture<SnapshotResult> syncToRegionStoreAsync(SnapshotInfo snapshot, DataStore store) {
+        AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
+        // no need to create entry on snapshot_store_ref here, since entries are already created when updateCloudToUseObjectStore is invoked.
+        // But we need to set default install path so that sync can be done in the right s3 path
+        SnapshotInfo snapshotOnStore = _snapshotFactory.getSnapshot(snapshot, store);
+        String installPath = TemplateConstants.DEFAULT_SNAPSHOT_ROOT_DIR + "/"
+                + snapshot.getAccountId() + "/" + snapshot.getVolumeId();
+        ((SnapshotObject)snapshotOnStore).setPath(installPath);
+        CopySnapshotContext<CommandResult> context = new CopySnapshotContext<CommandResult>(null, snapshot,
+                snapshotOnStore, future);
+        AsyncCallbackDispatcher<SnapshotServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher
+                .create(this);
+        caller.setCallback(caller.getTarget().syncSnapshotCallBack(null, null)).setContext(context);
+        motionSrv.copyAsync(snapshot, snapshotOnStore, caller);
+        return future;
+    }
+
+    protected Void syncSnapshotCallBack(AsyncCallbackDispatcher<SnapshotServiceImpl, CopyCommandResult> callback,
+            CopySnapshotContext<CommandResult> context) {
+        CopyCommandResult result = callback.getResult();
+        SnapshotInfo destSnapshot = context.destSnapshot;
+        SnapshotResult res = new SnapshotResult(destSnapshot, null);
+        
+        AsyncCallFuture<SnapshotResult> future = context.future;
+        try {
+            if (result.isFailed()) {
+                res.setResult(result.getResult());
+                // no change to existing snapshot_store_ref, will try to re-sync later if other call triggers this sync operation
+            } else {
+                // this will update install path properly, next time it will not sync anymore.
+                destSnapshot.processEvent(Event.OperationSuccessed, result.getAnswer());
+            }
+            future.complete(res);
+        } catch (Exception e) {
+            s_logger.debug("Failed to process sync snapshot callback", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
----------------------------------------------------------------------
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 4fc7247..967251f 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
@@ -27,6 +27,9 @@ 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;
@@ -38,8 +41,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 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;
@@ -212,7 +213,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
 
     @Override
     public EndPoint select(DataObject srcData, DataObject destData, StorageAction action) {
-        if (action == StorageAction.BACKUPSNAPSHOT) {
+        if (action == StorageAction.BACKUPSNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
             SnapshotInfo srcSnapshot = (SnapshotInfo)srcData;
             if (srcSnapshot.getHypervisorType() == Hypervisor.HypervisorType.KVM) {
                 VolumeInfo volumeInfo = srcSnapshot.getBaseVolume();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/693f0c28/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
index dc85fd8..7d726d3 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
@@ -105,6 +105,7 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
         storeSnapshotSearch.and("snapshot_id", storeSnapshotSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
         storeSnapshotSearch.and("store_id", storeSnapshotSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
         storeSnapshotSearch.and("store_role", storeSnapshotSearch.entity().getRole(), SearchCriteria.Op.EQ);
+        storeSnapshotSearch.and("state", storeSnapshotSearch.entity().getState(), SearchCriteria.Op.EQ);
         storeSnapshotSearch.done();
 
         snapshotIdSearch = createSearchBuilder();
@@ -319,6 +320,15 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
     }
 
     @Override
+    public SnapshotDataStoreVO findReadyOnCache(long snapshotId) {
+        SearchCriteria<SnapshotDataStoreVO> sc = storeSnapshotSearch.create();
+        sc.setParameters("snapshot_id", snapshotId);
+        sc.setParameters("store_role", DataStoreRole.ImageCache);
+        sc.setParameters("state", ObjectInDataStoreStateMachine.State.Ready);
+        return findOneIncludingRemovedBy(sc);
+    }
+
+    @Override
     public List<SnapshotDataStoreVO> listOnCache(long snapshotId) {
         SearchCriteria<SnapshotDataStoreVO> sc = storeSnapshotSearch.create();
         sc.setParameters("snapshot_id", snapshotId);


[2/3] git commit: updated refs/heads/4.3 to 693f0c2

Posted by mc...@apache.org.
CLOUDSTACK-5840:Migration from NFS to S3 should be done in one API
(updateCloudToUseObjectStore) instead of two APIs.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/62aa1477
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/62aa1477
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/62aa1477

Branch: refs/heads/4.3
Commit: 62aa14771c80c46e78f993cae90f3026b2312dbe
Parents: 5b07590
Author: Min Chen <mi...@citrix.com>
Authored: Wed Jan 8 16:28:20 2014 -0800
Committer: Min Chen <mi...@citrix.com>
Committed: Wed Jan 8 16:33:37 2014 -0800

----------------------------------------------------------------------
 api/src/com/cloud/storage/StorageService.java   |   8 +-
 .../admin/host/AddSecondaryStorageCmd.java      |  13 +-
 .../command/admin/storage/AddImageStoreCmd.java |   9 +-
 .../api/command/admin/storage/AddS3Cmd.java     |  96 ++++++-------
 .../PrepareSecondaryStorageForMigrationCmd.java | 109 --------------
 .../storage/UpdateCloudToUseObjectStoreCmd.java | 142 +++++++++++++++++++
 .../api/command/admin/swift/AddSwiftCmd.java    |  26 ++--
 .../test/AddSecondaryStorageCmdTest.java        |  20 ++-
 client/tomcatconf/commands.properties.in        |   2 +-
 .../com/cloud/server/ManagementServerImpl.java  |   6 +-
 .../com/cloud/storage/StorageManagerImpl.java   |  65 ++++++---
 11 files changed, 277 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/com/cloud/storage/StorageService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/StorageService.java b/api/src/com/cloud/storage/StorageService.java
index cbbc1f3..4d44045 100644
--- a/api/src/com/cloud/storage/StorageService.java
+++ b/api/src/com/cloud/storage/StorageService.java
@@ -17,8 +17,8 @@
 package com.cloud.storage;
 
 import java.net.UnknownHostException;
+import java.util.Map;
 
-import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
 import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
@@ -95,7 +95,8 @@ public interface StorageService{
 
     boolean deleteSecondaryStagingStore(DeleteSecondaryStagingStoreCmd cmd);
 
-    ImageStore discoverImageStore(AddImageStoreCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
+    public ImageStore discoverImageStore(String name, String url, String providerName, Long dcId, Map details) throws IllegalArgumentException, DiscoveryException,
+            InvalidParameterValueException;
 
     /**
      * Prepare NFS secondary storage for object store migration
@@ -108,6 +109,9 @@ public interface StorageService{
      * @throws InsufficientCapacityException
      *             TODO
      */
+    public ImageStore migrateToObjectStore(String name, String url, String providerName, Map details) throws IllegalArgumentException, DiscoveryException,
+            InvalidParameterValueException;
+
     public ImageStore prepareSecondaryStorageForObjectStoreMigration(Long storeId) throws ResourceUnavailableException,
             InsufficientCapacityException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java
index 69a4a49..02e53a9 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/AddSecondaryStorageCmd.java
@@ -16,16 +16,16 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.host;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
-import org.apache.log4j.Logger;
 
 import com.cloud.exception.DiscoveryException;
 import com.cloud.storage.ImageStore;
@@ -78,19 +78,14 @@ public class AddSecondaryStorageCmd extends BaseCmd {
 
     @Override
     public void execute(){
-        AddImageStoreCmd cmd = new AddImageStoreCmd();
-        cmd.setUrl(this.getUrl());
-        cmd.setZoneId(this.getZoneId());
-        cmd.setProviderName("NFS");
-
         try{
-            ImageStore result = _storageService.discoverImageStore(cmd);
+            ImageStore result = _storageService.discoverImageStore(null, getUrl(), "NFS", getZoneId(), null);
             ImageStoreResponse storeResponse = null;
             if (result != null ) {
                     storeResponse = _responseGenerator.createImageStoreResponse(result);
                     storeResponse.setResponseName(getCommandName());
                     storeResponse.setObjectName("secondarystorage");
-                    this.setResponseObject(storeResponse);
+                    setResponseObject(storeResponse);
             } else {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage");
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java
index 1552e05..98c0988 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java
@@ -21,6 +21,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
@@ -29,7 +31,6 @@ import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
-import org.apache.log4j.Logger;
 
 import com.cloud.exception.DiscoveryException;
 import com.cloud.storage.ImageStore;
@@ -98,7 +99,7 @@ public class AddImageStoreCmd extends BaseCmd {
     }
 
     public String getProviderName() {
-        return this.providerName;
+        return providerName;
     }
 
     public void setUrl(String url) {
@@ -136,13 +137,13 @@ public class AddImageStoreCmd extends BaseCmd {
     @Override
     public void execute(){
         try{
-            ImageStore result = _storageService.discoverImageStore(this);
+            ImageStore result = _storageService.discoverImageStore(getName(), getUrl(), getProviderName(), getZoneId(), getDetails());
             ImageStoreResponse storeResponse = null;
             if (result != null ) {
                 storeResponse = _responseGenerator.createImageStoreResponse(result);
                 storeResponse.setResponseName(getCommandName());
                 storeResponse.setObjectName("imagestore");
-                this.setResponseObject(storeResponse);
+                setResponseObject(storeResponse);
             } else {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage");
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java
index 0af1a85..035a85c 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddS3Cmd.java
@@ -34,6 +34,8 @@ import static org.apache.cloudstack.api.BaseCmd.CommandType.STRING;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
@@ -41,7 +43,6 @@ import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
-import org.apache.log4j.Logger;
 
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.DiscoveryException;
@@ -94,39 +95,32 @@ public final class AddS3Cmd extends BaseCmd {
     ServerApiException, ConcurrentOperationException, ResourceAllocationException,
     NetworkRuleConflictException {
 
-        AddImageStoreCmd cmd = new AddImageStoreCmd() {
-            @Override
-            public Map<String, String> getDetails() {
-                Map<String, String> dm = new HashMap<String, String>();
-                dm.put(ApiConstants.S3_ACCESS_KEY, getAccessKey());
-                dm.put(ApiConstants.S3_SECRET_KEY, getSecretKey());
-                dm.put(ApiConstants.S3_END_POINT, getEndPoint());
-                dm.put(ApiConstants.S3_BUCKET_NAME, getBucketName());
-                if (getHttpsFlag() != null) {
-                    dm.put(ApiConstants.S3_HTTPS_FLAG, getHttpsFlag().toString());
-                }
-                if (getConnectionTimeout() != null) {
-                    dm.put(ApiConstants.S3_CONNECTION_TIMEOUT, getConnectionTimeout().toString());
-                }
-                if (getMaxErrorRetry() != null) {
-                    dm.put(ApiConstants.S3_MAX_ERROR_RETRY, getMaxErrorRetry().toString());
-                }
-                if (getSocketTimeout() != null) {
-                    dm.put(ApiConstants.S3_SOCKET_TIMEOUT, getSocketTimeout().toString());
-                }
-                return dm;
-            }
-        };
-        cmd.setProviderName("S3");
+        Map<String, String> dm = new HashMap<String, String>();
+        dm.put(ApiConstants.S3_ACCESS_KEY, getAccessKey());
+        dm.put(ApiConstants.S3_SECRET_KEY, getSecretKey());
+        dm.put(ApiConstants.S3_END_POINT, getEndPoint());
+        dm.put(ApiConstants.S3_BUCKET_NAME, getBucketName());
+        if (getHttpsFlag() != null) {
+            dm.put(ApiConstants.S3_HTTPS_FLAG, getHttpsFlag().toString());
+        }
+        if (getConnectionTimeout() != null) {
+            dm.put(ApiConstants.S3_CONNECTION_TIMEOUT, getConnectionTimeout().toString());
+        }
+        if (getMaxErrorRetry() != null) {
+            dm.put(ApiConstants.S3_MAX_ERROR_RETRY, getMaxErrorRetry().toString());
+        }
+        if (getSocketTimeout() != null) {
+            dm.put(ApiConstants.S3_SOCKET_TIMEOUT, getSocketTimeout().toString());
+        }
 
         try{
-            ImageStore result = _storageService.discoverImageStore(cmd);
+            ImageStore result = _storageService.discoverImageStore(null, null, "S3", null, dm);
             ImageStoreResponse storeResponse = null;
             if (result != null ) {
                 storeResponse = _responseGenerator.createImageStoreResponse(result);
                 storeResponse.setResponseName(getCommandName());
                 storeResponse.setObjectName("secondarystorage");
-                this.setResponseObject(storeResponse);
+                setResponseObject(storeResponse);
             } else {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add S3 secondary storage");
             }
@@ -149,35 +143,35 @@ public final class AddS3Cmd extends BaseCmd {
 
         final AddS3Cmd thatAddS3Cmd = (AddS3Cmd) thatObject;
 
-        if (this.httpsFlag != null ? !this.httpsFlag.equals(thatAddS3Cmd.httpsFlag) : thatAddS3Cmd.httpsFlag != null) {
+        if (httpsFlag != null ? !httpsFlag.equals(thatAddS3Cmd.httpsFlag) : thatAddS3Cmd.httpsFlag != null) {
             return false;
         }
 
-        if (this.accessKey != null ? !this.accessKey.equals(thatAddS3Cmd.accessKey) : thatAddS3Cmd.accessKey != null) {
+        if (accessKey != null ? !accessKey.equals(thatAddS3Cmd.accessKey) : thatAddS3Cmd.accessKey != null) {
             return false;
         }
 
-        if (this.connectionTimeout != null ? !this.connectionTimeout.equals(thatAddS3Cmd.connectionTimeout) : thatAddS3Cmd.connectionTimeout != null) {
+        if (connectionTimeout != null ? !connectionTimeout.equals(thatAddS3Cmd.connectionTimeout) : thatAddS3Cmd.connectionTimeout != null) {
             return false;
         }
 
-        if (this.endPoint != null ? !this.endPoint.equals(thatAddS3Cmd.endPoint) : thatAddS3Cmd.endPoint != null) {
+        if (endPoint != null ? !endPoint.equals(thatAddS3Cmd.endPoint) : thatAddS3Cmd.endPoint != null) {
             return false;
         }
 
-        if (this.maxErrorRetry != null ? !this.maxErrorRetry.equals(thatAddS3Cmd.maxErrorRetry) : thatAddS3Cmd.maxErrorRetry != null) {
+        if (maxErrorRetry != null ? !maxErrorRetry.equals(thatAddS3Cmd.maxErrorRetry) : thatAddS3Cmd.maxErrorRetry != null) {
             return false;
         }
 
-        if (this.secretKey != null ? !this.secretKey.equals(thatAddS3Cmd.secretKey) : thatAddS3Cmd.secretKey != null) {
+        if (secretKey != null ? !secretKey.equals(thatAddS3Cmd.secretKey) : thatAddS3Cmd.secretKey != null) {
             return false;
         }
 
-        if (this.socketTimeout != null ? !this.socketTimeout.equals(thatAddS3Cmd.socketTimeout) : thatAddS3Cmd.socketTimeout != null) {
+        if (socketTimeout != null ? !socketTimeout.equals(thatAddS3Cmd.socketTimeout) : thatAddS3Cmd.socketTimeout != null) {
             return false;
         }
 
-        if (this.bucketName != null ? !this.bucketName.equals(thatAddS3Cmd.bucketName) : thatAddS3Cmd.bucketName != null) {
+        if (bucketName != null ? !bucketName.equals(thatAddS3Cmd.bucketName) : thatAddS3Cmd.bucketName != null) {
             return false;
         }
 
@@ -188,14 +182,14 @@ public final class AddS3Cmd extends BaseCmd {
     @Override
     public int hashCode() {
 
-        int result = this.accessKey != null ? this.accessKey.hashCode() : 0;
-        result = 31 * result + (this.secretKey != null ? this.secretKey.hashCode() : 0);
-        result = 31 * result + (this.endPoint != null ? this.endPoint.hashCode() : 0);
-        result = 31 * result + (this.bucketName != null ? this.bucketName.hashCode() : 0);
-        result = 31 * result + (this.httpsFlag != null && this.httpsFlag == true ? 1 : 0);
-        result = 31 * result + (this.connectionTimeout != null ? this.connectionTimeout.hashCode() : 0);
-        result = 31 * result + (this.maxErrorRetry != null ? this.maxErrorRetry.hashCode() : 0);
-        result = 31 * result + (this.socketTimeout != null ? this.socketTimeout.hashCode() : 0);
+        int result = accessKey != null ? accessKey.hashCode() : 0;
+        result = 31 * result + (secretKey != null ? secretKey.hashCode() : 0);
+        result = 31 * result + (endPoint != null ? endPoint.hashCode() : 0);
+        result = 31 * result + (bucketName != null ? bucketName.hashCode() : 0);
+        result = 31 * result + (httpsFlag != null && httpsFlag == true ? 1 : 0);
+        result = 31 * result + (connectionTimeout != null ? connectionTimeout.hashCode() : 0);
+        result = 31 * result + (maxErrorRetry != null ? maxErrorRetry.hashCode() : 0);
+        result = 31 * result + (socketTimeout != null ? socketTimeout.hashCode() : 0);
 
         return result;
 
@@ -212,35 +206,35 @@ public final class AddS3Cmd extends BaseCmd {
     }
 
     public String getAccessKey() {
-        return this.accessKey;
+        return accessKey;
     }
 
     public String getSecretKey() {
-        return this.secretKey;
+        return secretKey;
     }
 
     public String getEndPoint() {
-        return this.endPoint;
+        return endPoint;
     }
 
     public String getBucketName() {
-        return this.bucketName;
+        return bucketName;
     }
 
     public Boolean getHttpsFlag() {
-        return this.httpsFlag;
+        return httpsFlag;
     }
 
     public Integer getConnectionTimeout() {
-        return this.connectionTimeout;
+        return connectionTimeout;
     }
 
     public Integer getMaxErrorRetry() {
-        return this.maxErrorRetry;
+        return maxErrorRetry;
     }
 
     public Integer getSocketTimeout() {
-        return this.socketTimeout;
+        return socketTimeout;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java
deleted file mode 100644
index d0c995a..0000000
--- a/api/src/org/apache/cloudstack/api/command/admin/storage/PrepareSecondaryStorageForMigrationCmd.java
+++ /dev/null
@@ -1,109 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-package org.apache.cloudstack.api.command.admin.storage;
-
-import org.apache.log4j.Logger;
-
-import org.apache.cloudstack.api.APICommand;
-import org.apache.cloudstack.api.ApiCommandJobType;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.ApiErrorCode;
-import org.apache.cloudstack.api.BaseAsyncCmd;
-import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.response.ImageStoreResponse;
-import org.apache.cloudstack.context.CallContext;
-
-import com.cloud.event.EventTypes;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.storage.ImageStore;
-import com.cloud.user.Account;
-
-@APICommand(name = "prepareSecondaryStorageForMigration", description = "Prepare a NFS secondary storage to migrate to use object store like S3", responseObject = ImageStoreResponse.class)
-public class PrepareSecondaryStorageForMigrationCmd extends BaseAsyncCmd {
-    public static final Logger s_logger = Logger.getLogger(PrepareSecondaryStorageForMigrationCmd.class.getName());
-    private static final String s_name = "preparesecondarystorageformigrationresponse";
-
-    /////////////////////////////////////////////////////
-    //////////////// API parameters /////////////////////
-    /////////////////////////////////////////////////////
-
-    @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ImageStoreResponse.class,
-            required = true, description = "Secondary image store ID")
-    private Long id;
-
-    /////////////////////////////////////////////////////
-    /////////////////// Accessors ///////////////////////
-    /////////////////////////////////////////////////////
-
-    public Long getId() {
-        return id;
-    }
-
-    /////////////////////////////////////////////////////
-    /////////////// API Implementation///////////////////
-    /////////////////////////////////////////////////////
-
-    @Override
-    public String getCommandName() {
-        return s_name;
-    }
-
-    @Override
-    public ApiCommandJobType getInstanceType() {
-        return ApiCommandJobType.ImageStore;
-    }
-
-    @Override
-    public Long getInstanceId() {
-        return getId();
-    }
-
-    @Override
-    public long getEntityOwnerId() {
-        Account account = CallContext.current().getCallingAccount();
-        if (account != null) {
-            return account.getId();
-        }
-
-        return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
-    }
-
-    @Override
-    public String getEventType() {
-        return EventTypes.EVENT_MIGRATE_PREPARE_SECONDARY_STORAGE;
-    }
-
-    @Override
-    public String getEventDescription() {
-        return "preparing secondary storage: " + getId() + " for object store migration";
-    }
-
-    @Override
-    public void execute() throws ResourceUnavailableException, InsufficientCapacityException{
-        ImageStore result = _storageService.prepareSecondaryStorageForObjectStoreMigration(getId());
-        if (result != null){
-            ImageStoreResponse response = _responseGenerator.createImageStoreResponse(result);
-            response.setResponseName(getCommandName());
-            response.setResponseName("secondarystorage");
-            setResponseObject(response);
-        } else {
-            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to prepare secondary storage for object store migration");
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java
new file mode 100644
index 0000000..983a01c
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/UpdateCloudToUseObjectStoreCmd.java
@@ -0,0 +1,142 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
+
+import com.cloud.exception.DiscoveryException;
+import com.cloud.storage.ImageStore;
+import com.cloud.user.Account;
+
+@APICommand(name = "updateCloudToUseObjectStore", description = "Migrate current NFS secondary storages to use object store.", responseObject = ImageStoreResponse.class, since = "4.3.0")
+public class UpdateCloudToUseObjectStoreCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(UpdateCloudToUseObjectStoreCmd.class.getName());
+    private static final String s_name = "updatecloudtouseobjectstoreresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name for the image store")
+    private String name;
+
+    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, description="the URL for the image store")
+    private String url;
+
+    @Parameter(name=ApiConstants.PROVIDER, type=CommandType.STRING,
+            required=true, description="the image store provider name")
+    private String providerName;
+
+    @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, description="the details for the image store. Example: details[0].key=accesskey&details[0].value=s389ddssaa&details[1].key=secretkey&details[1].value=8dshfsss")
+    private Map details;
+
+
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+
+    public String getUrl() {
+        return url;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Map<String, String> getDetails() {
+        Map<String, String> detailsMap = null;
+        if (details != null && !details.isEmpty()) {
+            detailsMap = new HashMap<String, String>();
+            Collection<?> props = details.values();
+            Iterator<?> iter = props.iterator();
+            while (iter.hasNext()) {
+                HashMap<String, String> detail = (HashMap<String, String>) iter.next();
+                String key = detail.get("key");
+                String value = detail.get("value");
+                detailsMap.put(key, value);
+            }
+        }
+        return detailsMap;
+    }
+
+    public String getProviderName() {
+        return providerName;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+
+    public void setProviderName(String providerName) {
+        this.providerName = providerName;
+    }
+
+    public void setDetails(Map<String, String> details) {
+        this.details = details;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @Override
+    public void execute(){
+        try{
+            ImageStore result = _storageService.migrateToObjectStore(getName(), getUrl(), getProviderName(), getDetails());
+            ImageStoreResponse storeResponse = null;
+            if (result != null ) {
+                storeResponse = _responseGenerator.createImageStoreResponse(result);
+                storeResponse.setResponseName(getCommandName());
+                storeResponse.setObjectName("imagestore");
+                setResponseObject(storeResponse);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add secondary storage");
+            }
+        } catch (DiscoveryException ex) {
+            s_logger.warn("Exception: ", ex);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java b/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java
index ea22429..ec6e88c 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/swift/AddSwiftCmd.java
@@ -19,15 +19,15 @@ package org.apache.cloudstack.api.command.admin.swift;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
-import org.apache.log4j.Logger;
 
 import com.cloud.exception.DiscoveryException;
 import com.cloud.storage.ImageStore;
@@ -89,28 +89,20 @@ public class AddSwiftCmd extends BaseCmd {
     }
 
     @Override
-    public void execute(){
-        AddImageStoreCmd cmd = new AddImageStoreCmd() {
-            @Override
-            public Map<String, String> getDetails() {
-                Map<String, String> dm = new HashMap<String, String>();
-                dm.put(ApiConstants.ACCOUNT, getAccount());
-                dm.put(ApiConstants.USERNAME, getUsername());
-                dm.put(ApiConstants.KEY, getKey());
-                return dm;
-            }
-        };
-        cmd.setProviderName("Swift");
-        cmd.setUrl(this.getUrl());
+    public void execute() {
+        Map<String, String> dm = new HashMap<String, String>();
+        dm.put(ApiConstants.ACCOUNT, getAccount());
+        dm.put(ApiConstants.USERNAME, getUsername());
+        dm.put(ApiConstants.KEY, getKey());
 
         try{
-            ImageStore result = _storageService.discoverImageStore(cmd);
+            ImageStore result = _storageService.discoverImageStore(null, getUrl(), "Swift", null, dm);
             ImageStoreResponse storeResponse = null;
             if (result != null ) {
                 storeResponse = _responseGenerator.createImageStoreResponse(result);
                 storeResponse.setResponseName(getCommandName());
                 storeResponse.setObjectName("secondarystorage");
-                this.setResponseObject(storeResponse);
+                setResponseObject(storeResponse);
             } else {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Swift secondary storage");
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java
----------------------------------------------------------------------
diff --git a/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java
index c221ace..552a3c7 100644
--- a/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java
+++ b/api/test/org/apache/cloudstack/api/command/test/AddSecondaryStorageCmdTest.java
@@ -16,20 +16,26 @@
 // under the License.
 package org.apache.cloudstack.api.command.test;
 
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+
+import java.util.Map;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import org.apache.cloudstack.api.ResponseGenerator;
-import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
-import org.apache.cloudstack.api.response.HostResponse;
-import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.Mockito;
 
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
+
 import com.cloud.storage.ImageStore;
 import com.cloud.storage.StorageService;
 
@@ -56,7 +62,7 @@ public class AddSecondaryStorageCmdTest extends TestCase {
 
         ImageStore store = Mockito.mock(ImageStore.class);
 
-        Mockito.when(resourceService.discoverImageStore(addImageStoreCmd))
+        Mockito.when(resourceService.discoverImageStore(anyString(), anyString(), anyString(), anyLong(), (Map)anyObject()))
                 .thenReturn(store);
 
         ResponseGenerator responseGenerator = Mockito
@@ -88,7 +94,7 @@ public class AddSecondaryStorageCmdTest extends TestCase {
         StorageService resourceService = Mockito.mock(StorageService.class);
         addImageStoreCmd._storageService = resourceService;
 
-        Mockito.when(resourceService.discoverImageStore(addImageStoreCmd))
+        Mockito.when(resourceService.discoverImageStore(anyString(), anyString(), anyString(), anyLong(), (Map)anyObject()))
                 .thenReturn(null);
 
         try {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 3016543..28789c1 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -266,7 +266,7 @@ deleteImageStore=1
 createSecondaryStagingStore=1
 listSecondaryStagingStores=1
 deleteSecondaryStagingStore=1
-prepareSecondaryStorageForMigration=1
+updateCloudToUseObjectStore=1
 
 #### host commands
 addHost=3

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index d81e847..2237694 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -42,7 +42,6 @@ import javax.crypto.spec.SecretKeySpec;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.cloudstack.framework.config.ConfigDepot;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -162,7 +161,7 @@ import org.apache.cloudstack.api.command.admin.storage.ListSecondaryStagingStore
 import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
 import org.apache.cloudstack.api.command.admin.storage.ListStorageProvidersCmd;
 import org.apache.cloudstack.api.command.admin.storage.PreparePrimaryStorageForMaintenanceCmd;
-import org.apache.cloudstack.api.command.admin.storage.PrepareSecondaryStorageForMigrationCmd;
+import org.apache.cloudstack.api.command.admin.storage.UpdateCloudToUseObjectStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
 import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd;
 import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd;
@@ -440,6 +439,7 @@ import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.framework.config.ConfigDepot;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
@@ -2876,7 +2876,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(CreateSecondaryStagingStoreCmd.class);
         cmdList.add(ListSecondaryStagingStoresCmd.class);
         cmdList.add(DeleteSecondaryStagingStoreCmd.class);
-        cmdList.add(PrepareSecondaryStorageForMigrationCmd.class);
+        cmdList.add(UpdateCloudToUseObjectStoreCmd.class);
         cmdList.add(CreateApplicationLoadBalancerCmd.class);
         cmdList.add(ListApplicationLoadBalancersCmd.class);
         cmdList.add(DeleteApplicationLoadBalancerCmd.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/62aa1477/server/src/com/cloud/storage/StorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java
index e478956..b901e49 100755
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -41,7 +41,9 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
 import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
 import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
@@ -86,8 +88,6 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
@@ -1670,8 +1670,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
     }
 
     @Override
-    public ImageStore discoverImageStore(AddImageStoreCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException {
-        String providerName = cmd.getProviderName();
+    public ImageStore discoverImageStore(String name, String url, String providerName, Long dcId, Map details) throws IllegalArgumentException, DiscoveryException,
+            InvalidParameterValueException {
         DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(providerName);
 
         if (storeProvider == null) {
@@ -1682,16 +1682,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
             providerName = storeProvider.getName(); // ignored passed provider name and use default image store provider name
         }
 
-        Long dcId = cmd.getZoneId();
-        Map details = cmd.getDetails();
         ScopeType scopeType = ScopeType.ZONE;
         if (dcId == null) {
             scopeType = ScopeType.REGION;
         }
 
-        String name = cmd.getName();
         if (name == null) {
-            name = cmd.getUrl();
+            name = url;
         }
         ImageStoreVO imageStore = _imageStoreDao.findByName(name);
         if (imageStore != null) {
@@ -1699,7 +1696,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         }
 
         // check if scope is supported by store provider
-        if (!((ImageStoreProvider) storeProvider).isScopeSupported(scopeType)) {
+        if (!((ImageStoreProvider)storeProvider).isScopeSupported(scopeType)) {
             throw new InvalidParameterValueException("Image store provider " + providerName + " does not support scope " + scopeType);
         }
 
@@ -1732,8 +1729,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
 
         Map<String, Object> params = new HashMap<String, Object>();
         params.put("zoneId", dcId);
-        params.put("url", cmd.getUrl());
-        params.put("name", cmd.getName());
+        params.put("url", url);
+        params.put("name", name);
         params.put("details", details);
         params.put("scope", scopeType);
         params.put("providerName", storeProvider.getName());
@@ -1744,11 +1741,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         try {
             store = lifeCycle.initialize(params);
         } catch (Exception e) {
-            s_logger.debug("Failed to add data store: "+e.getMessage(), e);
-            throw new CloudRuntimeException("Failed to add data store: "+e.getMessage(), e);
+            s_logger.debug("Failed to add data store: " + e.getMessage(), e);
+            throw new CloudRuntimeException("Failed to add data store: " + e.getMessage(), e);
         }
 
-        if (((ImageStoreProvider) storeProvider).needDownloadSysTemplate()) {
+        if (((ImageStoreProvider)storeProvider).needDownloadSysTemplate()) {
             // trigger system vm template download
             _imageSrv.downloadBootstrapSysTemplate(store);
         }
@@ -1766,7 +1763,43 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
             duplicateCacheStoreRecordsToRegionStore(store.getId());
         }
 
-        return (ImageStore) _dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Image);
+        return (ImageStore)_dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Image);
+    }
+
+    @Override
+    public ImageStore migrateToObjectStore(String name, String url, String providerName, Map details) throws IllegalArgumentException, DiscoveryException,
+            InvalidParameterValueException {
+        // check if current cloud is ready to migrate, we only support cloud with only NFS secondary storages
+        List<ImageStoreVO> imgStores = _imageStoreDao.listImageStores();
+        List<ImageStoreVO> nfsStores = new ArrayList<ImageStoreVO>();
+        if (imgStores != null && imgStores.size() > 0) {
+            for (ImageStoreVO store : imgStores) {
+                if (!store.getProviderName().equals(DataStoreProvider.NFS_IMAGE)) {
+                    throw new InvalidParameterValueException("We only support migrate NFS secondary storage to use object store!");
+                } else {
+                    nfsStores.add(store);
+                }
+            }
+        }
+        // convert all NFS secondary storage to staging store
+        if (nfsStores != null && nfsStores.size() > 0) {
+            for (ImageStoreVO store : nfsStores) {
+                long storeId = store.getId();
+
+                _accountMgr.checkAccessAndSpecifyAuthority(CallContext.current().getCallingAccount(), store.getDataCenterId());
+
+                DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider(store.getProviderName());
+                DataStoreLifeCycle lifeCycle = provider.getDataStoreLifeCycle();
+                DataStore secStore = dataStoreMgr.getDataStore(storeId, DataStoreRole.Image);
+                lifeCycle.migrateToObjectStore(secStore);
+                // update store_role in template_store_ref and snapshot_store_ref to ImageCache
+                _templateStoreDao.updateStoreRoleToCachce(storeId);
+                _snapshotStoreDao.updateStoreRoleToCache(storeId);
+            }
+        }
+        // add object store
+        return discoverImageStore(name, url, providerName, null, details);
+
     }
 
     private void duplicateCacheStoreRecordsToRegionStore(long storeId) {


[3/3] git commit: updated refs/heads/4.3 to 693f0c2

Posted by mc...@apache.org.
CLOUDSTACK-5813: With S3 as secondary storage, snapshot taken in one
zone cannot be used to create volume in another zone. zoneId parameter
in createVolumeCmd is not observed.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/5b075907
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/5b075907
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/5b075907

Branch: refs/heads/4.3
Commit: 5b075907867d60dd589c11009385035623e6a73c
Parents: f7e0a54
Author: Min Chen <mi...@citrix.com>
Authored: Wed Jan 8 16:23:02 2014 -0800
Committer: Min Chen <mi...@citrix.com>
Committed: Wed Jan 8 16:33:37 2014 -0800

----------------------------------------------------------------------
 .../motion/AncientDataMotionStrategy.java       | 26 ++++++++++++++------
 .../com/cloud/storage/VolumeApiServiceImpl.java | 16 +++++++-----
 2 files changed, 29 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5b075907/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
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 c2792c7..30edf68 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
@@ -23,10 +23,22 @@ import java.util.Map;
 
 import javax.inject.Inject;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.*;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
+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.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
+import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
+import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
 import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction;
 import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
@@ -36,8 +48,6 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.MigrateVolumeAnswer;
@@ -189,9 +199,9 @@ AncientDataMotionStrategy implements DataMotionStrategy {
         }
     }
 
-    protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
+    protected DataObject cacheSnapshotChain(SnapshotInfo snapshot, Scope scope) {
         DataObject leafData = null;
-        DataStore store = cacheMgr.getCacheStorage(snapshot.getDataStore().getScope());
+        DataStore store = cacheMgr.getCacheStorage(scope);
         while (snapshot != null) {
             DataObject cacheData = cacheMgr.createCacheObject(snapshot, store);
             if (leafData == null) {
@@ -202,6 +212,7 @@ AncientDataMotionStrategy implements DataMotionStrategy {
         return leafData;
     }
 
+
     protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) {
         while (snapshot != null) {
             cacheMgr.deleteCacheObject(snapshot);
@@ -226,7 +237,8 @@ AncientDataMotionStrategy implements DataMotionStrategy {
         DataObject srcData = snapObj;
         try {
             if (!(storTO instanceof NfsTO)) {
-                srcData = cacheSnapshotChain(snapshot);
+                // cache snapshot to zone-wide staging store for the volume to be created
+                srcData = cacheSnapshotChain(snapshot, new ZoneScope(pool.getDataCenterId()));
             }
 
             String value = configDao.getValue(Config.CreateVolumeFromSnapshotWait.toString());
@@ -440,7 +452,7 @@ AncientDataMotionStrategy implements DataMotionStrategy {
         if (needCacheStorage(srcData, destData)) {
             needCache = true;
             SnapshotInfo snapshot = (SnapshotInfo) srcData;
-            srcData = cacheSnapshotChain(snapshot);
+            srcData = cacheSnapshotChain(snapshot, snapshot.getDataStore().getScope());
         }
 
         EndPoint ep = null;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5b075907/server/src/com/cloud/storage/VolumeApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index c68da8e..3de2767 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -45,6 +45,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@@ -119,7 +120,6 @@ import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.SnapshotPolicyDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.storage.dao.StoragePoolWorkDao;
-import com.cloud.storage.dao.UploadDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.storage.dao.VolumeDao;
@@ -129,7 +129,6 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.snapshot.SnapshotApiService;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.storage.snapshot.SnapshotScheduler;
-import com.cloud.storage.upload.UploadMonitor;
 import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.template.TemplateManager;
 import com.cloud.user.Account;
@@ -315,9 +314,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
     @Inject
     SnapshotApiService snapshotMgr;
     @Inject
-    UploadMonitor _uploadMonitor;
-    @Inject
-    UploadDao _uploadDao;
+    SnapshotService snapshotSrv;
 
     @Inject
     protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
@@ -596,7 +593,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
             diskOfferingId = snapshotCheck.getDiskOfferingId();
             diskOffering = _diskOfferingDao.findById(diskOfferingId);
-            zoneId = snapshotCheck.getDataCenterId();
+            if (zoneId == null) {
+                // if zoneId is not provided, we default to create volume in the same zone as the snapshot zone.
+                zoneId = snapshotCheck.getDataCenterId();
+            }
             size = snapshotCheck.getSize(); // ; disk offering is used for tags
             // purposes
 
@@ -768,11 +768,15 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             throws StorageUnavailableException {
         VolumeInfo createdVolume = null;
         SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
+        long snapshotVolId = snapshot.getVolumeId();
 
         UserVmVO vm = null;
         if (vmId != null) {
             vm = _userVmDao.findById(vmId);
         }
+
+        // sync old snapshots to region store if necessary
+
         createdVolume = _volumeMgr.createVolumeFromSnapshot(volume, snapshot, vm);
 
         UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), createdVolume.getDataCenterId(), createdVolume.getId(),