You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/06/25 01:52:21 UTC

[45/50] [abbrv] merge is complete

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --cc engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 56a6651,1d36f93..95ca968
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@@ -24,15 -25,14 +25,17 @@@ import java.util.Map
  
  import javax.inject.Inject;
  
 +import org.apache.log4j.Logger;
 +import org.springframework.stereotype.Component;
 +
  import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
- import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
  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.DataObject;
  import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+ 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.ObjectInDataStoreStateMachine.Event;
  import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
  import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
@@@ -47,14 -49,28 +52,26 @@@ import org.apache.cloudstack.storage.da
  import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
  import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
  import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
- import org.apache.cloudstack.storage.motion.DataMotionService;
+ import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
+ import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
+ import org.apache.cloudstack.storage.to.VolumeObjectTO;
 -import org.apache.log4j.Logger;
 -import org.springframework.stereotype.Component;
  
+ import com.cloud.agent.api.Answer;
+ import com.cloud.agent.api.storage.ListVolumeAnswer;
+ import com.cloud.agent.api.storage.ListVolumeCommand;
  import com.cloud.agent.api.to.VirtualMachineTO;
+ import com.cloud.alert.AlertManager;
+ import com.cloud.configuration.Config;
+ import com.cloud.configuration.Resource.ResourceType;
+ import com.cloud.configuration.dao.ConfigurationDao;
  import com.cloud.exception.ConcurrentOperationException;
+ import com.cloud.exception.ResourceAllocationException;
  import com.cloud.host.Host;
+ import com.cloud.storage.DataStoreRole;
  import com.cloud.storage.StoragePool;
+ import com.cloud.storage.VMTemplateStorageResourceAssoc;
+ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
  import com.cloud.storage.Volume;
- import com.cloud.storage.Volume.Type;
  import com.cloud.storage.VolumeVO;
  import com.cloud.storage.dao.VolumeDao;
  import com.cloud.storage.snapshot.SnapshotManager;
@@@ -114,16 -143,17 +145,17 @@@ public class VolumeServiceImpl implemen
          DataObject volumeOnStore = dataStore.create(volume);
          volumeOnStore.processEvent(Event.CreateOnlyRequested);
  
-         CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore, future);
+         CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
+                 future);
          AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
-         caller.setCallback(caller.getTarget().createVolumeCallback(null, null))
-         .setContext(context);
+         caller.setCallback(caller.getTarget().createVolumeCallback(null, null)).setContext(context);
 -
 +        
          dataStore.getDriver().createAsync(volumeOnStore, caller);
          return future;
      }
 -
 +    
-     protected Void createVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
+     protected Void createVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback,
+             CreateVolumeContext<VolumeApiResult> context) {
          CreateCmdResult result = callback.getResult();
          DataObject vo = context.getVolume();
          String errMsg = null;
@@@ -172,14 -201,14 +204,14 @@@
              future.complete(result);
              return future;
          }
 -
 +        
-         String vmName = null;
-         VolumeVO vol = volDao.findById(volume.getId());
-         if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) {
-             VirtualMachine vm = vmDao.findByIdIncludingRemoved(vol
-                     .getInstanceId());
-             if (vm != null) {
-                 vmName = vm.getInstanceName();
+         // Find out if the volume is at state of download_in_progress on secondary storage
+         VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(volume.getId());
+         if (volumeStore != null) {
+             if (volumeStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) {
+                 s_logger.debug("Volume: " + volume.getName() + " is currently being uploaded; cant' delete it.");
+                 future.complete(result);
+                 return future;
              }
          }
  
@@@ -194,21 -224,20 +227,20 @@@
              future.complete(result);
              return future;
          }
-         VolumeObject vo = (VolumeObject)volume;
+         VolumeObject vo = (VolumeObject) volume;
 -
 +      
          volume.processEvent(Event.ExpungeRequested);
 -
 +      
-         
          DeleteVolumeContext<VolumeApiResult> context = new DeleteVolumeContext<VolumeApiResult>(null, vo, future);
          AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> caller = AsyncCallbackDispatcher.create(this);
-         caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null))
-             .setContext(context);
+         caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)).setContext(context);
 -
 +        
          volume.getDataStore().getDriver().deleteAsync(volume, caller);
          return future;
      }
 -
 +    
-     public Void deleteVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> callback, DeleteVolumeContext<VolumeApiResult> context) {
+     public Void deleteVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CommandResult> callback,
+             DeleteVolumeContext<VolumeApiResult> context) {
          CommandResult result = callback.getResult();
          VolumeObject vo = context.getVolume();
          VolumeApiResult apiResult = new VolumeApiResult(vo);
@@@ -231,19 -260,9 +263,9 @@@
  
      @Override
      public VolumeEntity getVolumeEntity(long volumeId) {
-         VolumeVO vo = volDao.findById(volumeId);
-         if (vo == null) {
 -        return null;
 -    }
 +            return null;
 +        }
  
-         if (vo.getPoolId() == null) {
-             return new VolumeEntityImpl(VolumeObject.getVolumeObject(null, vo), this);
-         } else {
-             PrimaryDataStore dataStore = dataStoreMgr.getPrimaryDataStore(vo.getPoolId());
-             return new VolumeEntityImpl(dataStore.getVolume(volumeId), this);
-         }
-     }
- 
      class CreateBaseImageContext<T> extends AsyncRpcConext<T> {
          private final VolumeInfo volume;
          private final PrimaryDataStore dataStore;
@@@ -276,31 -296,64 +299,64 @@@
          public AsyncCallFuture<VolumeApiResult> getFuture() {
              return this.future;
          }
 -
 +        
      }
 -
 +    
-     static class CreateBaseImageResult extends CommandResult {
-         final TemplateInfo template;
-         public CreateBaseImageResult(TemplateInfo template) {
-             super();
-             this.template = template;
+     private TemplateInfo waitForTemplateDownloaded(PrimaryDataStore store, TemplateInfo template) {
+         int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(
+                 configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
+         int sleepTime = 120;
+         int tries = storagePoolMaxWaitSeconds / sleepTime;
+         while (tries > 0) {
+             TemplateInfo tmpl = store.getTemplate(template.getId());
+             if (tmpl != null) {
+                 return tmpl;
 -            }
++        }
+             try {
+                 Thread.sleep(sleepTime * 1000);
+             } catch (InterruptedException e) {
+                 s_logger.debug("waiting for template download been interrupted: " + e.toString());
+             }
+             tries--;
          }
+         return null;
      }
 -
 +    
      @DB
-     protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture<VolumeApiResult> future) {
+     protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template,
+             AsyncCallFuture<VolumeApiResult> future) {
 -
 +       
          DataObject templateOnPrimaryStoreObj = dataStore.create(template);
          CreateBaseImageContext<CreateCmdResult> context = new CreateBaseImageContext<CreateCmdResult>(null, volume,
-                 dataStore,
-                 template,
-                 future, templateOnPrimaryStoreObj);
+                 dataStore, template, future, templateOnPrimaryStoreObj);
          AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
-         caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null))
-         .setContext(context);
+         caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)).setContext(context);
 -
 +        
+         try {
 -            templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested);
 +        templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested);
+         } catch (Exception e) {
+             s_logger.info("Got exception in case of multi-thread");
+             try {
+                 templateOnPrimaryStoreObj = waitForTemplateDownloaded(dataStore, template);
+             } catch (Exception e1) {
+                 s_logger.debug("wait for template:" + template.getId() + " downloading finished, but failed");
+                 VolumeApiResult result = new VolumeApiResult(volume);
+                 result.setResult(e1.toString());
+                 future.complete(result);
+                 return;
+             }
+             if (templateOnPrimaryStoreObj == null) {
+                 VolumeApiResult result = new VolumeApiResult(volume);
+                 result.setResult("wait for template:" + template.getId() + " downloading finished, but failed");
+                 future.complete(result);
+                 return;
+             } else {
+                 s_logger.debug("waiting for template:" + template.getId() + " downloading finished, success");
+                 createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
+                 return;
+             }
+         }
 -
 +     
          try {
              motionSrv.copyAsync(template, templateOnPrimaryStoreObj, caller);
          } catch (Exception e) {
@@@ -312,12 -365,13 +368,13 @@@
          }
          return;
      }
 -
 +    
      @DB
-     protected Void copyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CreateBaseImageContext<VolumeApiResult> context) {
+     protected Void copyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+             CreateBaseImageContext<VolumeApiResult> context) {
          CopyCommandResult result = callback.getResult();
          VolumeApiResult res = new VolumeApiResult(context.getVolume());
 -
 +        
          AsyncCallFuture<VolumeApiResult> future = context.getFuture();
          DataObject templateOnPrimaryStoreObj = context.destObj;
          if (!result.isSuccess()) {
@@@ -326,60 -380,59 +383,59 @@@
              future.complete(res);
              return null;
          }
 -
 +        
-         templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed);
+         templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer());
          createVolumeFromBaseImageAsync(context.volume, templateOnPrimaryStoreObj, context.dataStore, future);
          return null;
      }
 -
 +    
      private class CreateVolumeFromBaseImageContext<T> extends AsyncRpcConext<T> {
-         private final VolumeObject vo;
+         private final DataObject vo;
          private final AsyncCallFuture<VolumeApiResult> future;
-         private final DataStore primaryStore;
          private final DataObject templateOnStore;
-         public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
-                 DataStore primaryStore,
-                 DataObject templateOnStore,
-                 AsyncCallFuture<VolumeApiResult> future) {
+         private final SnapshotInfo snapshot;
+ 
+         public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, DataObject vo,
+                 DataStore primaryStore, DataObject templateOnStore, AsyncCallFuture<VolumeApiResult> future,
+                 SnapshotInfo snapshot) {
              super(callback);
              this.vo = vo;
              this.future = future;
-             this.primaryStore = primaryStore;
              this.templateOnStore = templateOnStore;
+             this.snapshot = snapshot;
          }
 -
 +        
- 
          public AsyncCallFuture<VolumeApiResult> getFuture() {
              return this.future;
          }
      }
 -
 +    
      @DB
-     protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
-         VolumeObject vo = (VolumeObject)volume;
-         CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future);
-         AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller =  AsyncCallbackDispatcher.create(this);
-         caller.setCallback(caller.getTarget().copyBaseImageCallBack(null, null))
-         .setContext(context);
- 
+     protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore,
+             PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
          DataObject volumeOnPrimaryStorage = pd.create(volume);
-         volume.processEvent(Event.CreateOnlyRequested);
+         volumeOnPrimaryStorage.processEvent(Event.CreateOnlyRequested);
+ 
+         CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(
+                 null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null);
+         AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+         caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null));
+         caller.setContext(context);
  
          motionSrv.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller);
          return;
      }
 -
 +    
      @DB
-     public Void copyBaseImageCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
-         VolumeObject vo = context.vo;
+     protected Void createVolumeFromBaseImageCallBack(
+             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+             CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
+         DataObject vo = context.vo;
          CopyCommandResult result = callback.getResult();
-         VolumeApiResult volResult = new VolumeApiResult(vo);
+         VolumeApiResult volResult = new VolumeApiResult((VolumeObject) vo);
 -
 +       
          if (result.isSuccess()) {
-             if (result.getPath() != null) {
-                 vo.setPath(result.getPath());
-             }
-             vo.processEvent(Event.OperationSuccessed);
+             vo.processEvent(Event.OperationSuccessed, result.getAnswer());
          } else {
              vo.processEvent(Event.OperationFailed);
              volResult.setResult(result.getResult());
@@@ -396,8 -450,7 +453,7 @@@
          PrimaryDataStore pd = dataStoreMgr.getPrimaryDataStore(dataStoreId);
          TemplateInfo templateOnPrimaryStore = pd.getTemplate(template.getId());
          AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
-         VolumeApiResult result = new VolumeApiResult(volume);
 -
 +        
          if (templateOnPrimaryStore == null) {
              createBaseImageAsync(volume, pd, template, future);
              return future;
@@@ -409,9 -462,8 +465,8 @@@
  
      @Override
      @DB
-     public boolean destroyVolume(long volumeId)
-             throws ConcurrentOperationException {
+     public boolean destroyVolume(long volumeId) throws ConcurrentOperationException {
 -
 +        
          VolumeInfo vol = volFactory.getVolume(volumeId);
          vol.processEvent(Event.DestroyRequested);
          snapshotMgr.deletePoliciesForVolume(volumeId);
@@@ -422,55 -474,61 +477,61 @@@
      }
  
      @Override
-     public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(
-             VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
+     public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(VolumeInfo volume, DataStore store,
+             SnapshotInfo snapshot) {
          AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
 -
 +        
          try {
 -            DataObject volumeOnStore = store.create(volume);
 +        	DataObject volumeOnStore = store.create(volume);
-             volume = this.volFactory.getVolume(volume.getId(), store);
-         	volume.processEvent(Event.CreateOnlyRequested);
-         	 CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
-         			 (VolumeObject)volume, store, volumeOnStore, future);
+             volumeOnStore.processEvent(Event.CreateOnlyRequested);
+             snapshot.processEvent(Event.CopyingRequested);
+             CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(
+                     null, volume, store, volumeOnStore, future, snapshot);
 -            AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
 +             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller =  AsyncCallbackDispatcher.create(this);
-              caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
-              .setContext(context);
+             caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)).setContext(context);
 -            motionSrv.copyAsync(snapshot, volumeOnStore, caller);
 +        	motionSrv.copyAsync(snapshot, volumeOnStore, caller);
          } catch (Exception e) {
 -            s_logger.debug("create volume from snapshot failed", e);
 -            VolumeApiResult result = new VolumeApiResult(volume);
 -            result.setResult(e.toString());
 -            future.complete(result);
 +        	s_logger.debug("create volume from snapshot failed", e);
 +        	VolumeApiResult result = new VolumeApiResult(volume);
 +        	result.setResult(e.toString());
 +        	future.complete(result);
          }
 -
 +        
          return future;
      }
 -
 +    
-     protected Void createVolumeFromSnapshotCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+     protected Void createVolumeFromSnapshotCallback(
+             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
 -            CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
 -        CopyCommandResult result = callback.getResult();
 +    		CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
 +    	CopyCommandResult result = callback.getResult();
-     	VolumeInfo volume = context.vo;
+         VolumeInfo volume = (VolumeInfo) context.templateOnStore;
+         SnapshotInfo snapshot = context.snapshot;
 -        VolumeApiResult apiResult = new VolumeApiResult(volume);
 -        Event event = null;
 -        if (result.isFailed()) {
 -            apiResult.setResult(result.getResult());
 -            event = Event.OperationFailed;
 -        } else {
 -            event = Event.OperationSuccessed;
 -        }
 -
 -        try {
 +    	VolumeApiResult apiResult = new VolumeApiResult(volume);
 +    	Event event = null;
 +    	if (result.isFailed()) {
 +    		apiResult.setResult(result.getResult());
 +    		event = Event.OperationFailed;
 +    	} else {
 +    		event = Event.OperationSuccessed;
 +    	}
 +    	
 +    	try {
+             if (result.isSuccess()) {
+                 volume.processEvent(event, result.getAnswer());
+             } else {
 -                volume.processEvent(event);
 +    		volume.processEvent(event);
+             }
+             snapshot.processEvent(event);
 -        } catch (Exception e) {
 -            s_logger.debug("create volume from snapshot failed", e);
 -            apiResult.setResult(e.toString());
 -        }
 -
 -        AsyncCallFuture<VolumeApiResult> future = context.future;
 -        future.complete(apiResult);
 -        return null;
 +    	} catch (Exception e) {
 +    		s_logger.debug("create volume from snapshot failed", e);
 +    		apiResult.setResult(e.toString());
 +    	}
 +    	
 +    	AsyncCallFuture<VolumeApiResult> future = context.future;
 +    	future.complete(apiResult);
 +    	return null;
      }
 -
 +    
      protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) {
          Long lastPoolId = volume.getPoolId();
          VolumeVO newVol = new VolumeVO(volume);
@@@ -482,8 -540,7 +543,7 @@@
          newVol.setPodId(pool.getPodId());
          return volDao.persist(newVol);
      }
 -
 +    
- 
      private class CopyVolumeContext<T> extends AsyncRpcConext<T> {
          final VolumeInfo srcVolume;
          final VolumeInfo destVolume;
@@@ -497,14 -551,135 +554,135 @@@
              super(callback);
              this.srcVolume = srcVolume;
              this.destVolume = destVolume;
-             this.destStore = destStore;
              this.future = future;
          }
 -
 +        
      }
+ 
+     protected AsyncCallFuture<VolumeApiResult> copyVolumeFromImageToPrimary(VolumeInfo srcVolume, DataStore destStore) {
+         AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+         VolumeApiResult res = new VolumeApiResult(srcVolume);
+         VolumeInfo destVolume = null;
+         try {
+             destVolume = (VolumeInfo) destStore.create(srcVolume);
+             destVolume.processEvent(Event.CopyingRequested);
+             srcVolume.processEvent(Event.CopyingRequested);
 -
++                
+             CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future,
+                     srcVolume, destVolume, destStore);
+             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+             caller.setCallback(caller.getTarget().copyVolumeFromImageToPrimaryCallback(null, null)).setContext(context);
+ 
+             motionSrv.copyAsync(srcVolume, destVolume, caller);
+             return future;
+         } catch (Exception e) {
+             s_logger.error("failed to copy volume from image store", e);
+             if (destVolume != null) {
+                 destVolume.processEvent(Event.OperationFailed);
+             }
+ 
+             srcVolume.processEvent(Event.OperationFailed);
+             res.setResult(e.toString());
 -            future.complete(res);
 -            return future;
 -        }
++                future.complete(res);
++                return future;
++            }
+     }
+ 
+     protected Void copyVolumeFromImageToPrimaryCallback(
+             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+             CopyVolumeContext<VolumeApiResult> context) {
+         VolumeInfo srcVolume = context.srcVolume;
+         VolumeInfo destVolume = context.destVolume;
+         CopyCommandResult result = callback.getResult();
+         AsyncCallFuture<VolumeApiResult> future = context.future;
+         VolumeApiResult res = new VolumeApiResult(destVolume);
+         try {
+             if (res.isFailed()) {
+                 destVolume.processEvent(Event.OperationFailed);
+                 srcVolume.processEvent(Event.OperationFailed);
+                 res.setResult(result.getResult());
+                 future.complete(res);
+                 return null;
+             }
+ 
+             srcVolume.processEvent(Event.OperationSuccessed);
+             destVolume.processEvent(Event.OperationSuccessed, result.getAnswer());
+             srcVolume.getDataStore().delete(srcVolume);
+             future.complete(res);
+         } catch (Exception e) {
+             res.setResult(e.toString());
+             future.complete(res);
+         }
+         return null;
+     }
+ 
+ 
+     protected AsyncCallFuture<VolumeApiResult> copyVolumeFromPrimaryToImage(VolumeInfo srcVolume, DataStore destStore) {
+         AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+         VolumeApiResult res = new VolumeApiResult(srcVolume);
+         VolumeInfo destVolume = null;
+         try {
+             destVolume = (VolumeInfo)destStore.create(srcVolume);
+             srcVolume.processEvent(Event.MigrationRequested);    // this is just used for locking that src volume record in DB to avoid using lock
+             destVolume.processEventOnly(Event.CreateOnlyRequested);
+ 
+             CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume,
+                     destVolume,
+                     destStore);
+             AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+             caller.setCallback(caller.getTarget().copyVolumeFromPrimaryToImageCallback(null, null))
+             .setContext(context);
+ 
+             motionSrv.copyAsync(srcVolume, destVolume, caller);
+             return future;
+         } catch (Exception e) {
+             s_logger.error("failed to copy volume to image store", e);
+             if (destVolume != null) {
+                 destVolume.getDataStore().delete(destVolume);
+             }
+             srcVolume.processEvent(Event.OperationFailed); // unlock source volume record
+             res.setResult(e.toString());
+             future.complete(res);
+             return future;
+         }
+     }
+ 
+     protected Void copyVolumeFromPrimaryToImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
+         VolumeInfo srcVolume = context.srcVolume;
+         VolumeInfo destVolume = context.destVolume;
+         CopyCommandResult result = callback.getResult();
+         AsyncCallFuture<VolumeApiResult> future = context.future;
+         VolumeApiResult res = new VolumeApiResult(destVolume);
+         try {
+             if (res.isFailed()) {
+                 srcVolume.processEvent(Event.OperationFailed); // back to Ready state in Volume table
+                 destVolume.processEventOnly(Event.OperationFailed);
+                 res.setResult(result.getResult());
+                 future.complete(res);
+             }else{
+                 srcVolume.processEvent(Event.OperationSuccessed); // back to Ready state in Volume table
+                 destVolume.processEventOnly(Event.OperationSuccessed, result.getAnswer());
+                 future.complete(res);
+             }
+         } catch (Exception e) {
+             res.setResult(e.toString());
+             future.complete(res);
+         }
+         return null;
+     }
+ 
+ 
      @Override
-     public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume,
-             DataStore destStore) {
+     public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataStore destStore) {
+ 
+         if (srcVolume.getState() == Volume.State.Uploaded) {
+             return copyVolumeFromImageToPrimary(srcVolume, destStore);
+         }
+ 
+         if (destStore.getRole() == DataStoreRole.Image) {
+             return copyVolumeFromPrimaryToImage(srcVolume, destStore);
+         }
+ 
          AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
          VolumeApiResult res = new VolumeApiResult(srcVolume);
          try {
@@@ -536,8 -708,9 +711,9 @@@
          }
          return future;
      }
 -
 +    
-     protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
+     protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+             CopyVolumeContext<VolumeApiResult> context) {
          VolumeInfo srcVolume = context.srcVolume;
          VolumeInfo destVolume = context.destVolume;
          CopyCommandResult result = callback.getResult();
@@@ -730,85 -901,250 +904,250 @@@
  
      @Override
      public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store) {
 -
 +        
          AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
-         VolumeObject vo = (VolumeObject) volume;
+         DataObject volumeOnStore = store.create(volume);
  
-         CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, vo, future);
+         volumeOnStore.processEvent(Event.CreateOnlyRequested);
+ 
+         CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore,
+                 future);
          AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
-         caller.setCallback(caller.getTarget().registerVolumeCallback(null, null))
-         .setContext(context);
+         caller.setCallback(caller.getTarget().registerVolumeCallback(null, null));
+         caller.setContext(context);
 -
 +        
-         dataObjectMgr.createAsync(volume, store, caller, true);
+         store.getDriver().createAsync(volumeOnStore, caller);
          return future;
      }
 -
 +    
-     protected Void registerVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
+     protected Void registerVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback,
+             CreateVolumeContext<VolumeApiResult> context) {
          CreateCmdResult result = callback.getResult();
-         VolumeObject vo = (VolumeObject)context.volume;
+         try {
+             VolumeObject vo = (VolumeObject) context.volume;
 -            if (result.isFailed()) {
 +        if (result.isFailed()) {
-             vo.stateTransit(Volume.Event.OperationFailed);
+                 vo.processEvent(Event.OperationFailed);
 -            } else {
 +        } else {
-             vo.stateTransit(Volume.Event.OperationSucceeded);
+                 vo.processEvent(Event.OperationSuccessed, result.getAnswer());
 -            }
 +        }
+ 
+             _resourceLimitMgr.incrementResourceCount(vo.getAccountId(), ResourceType.secondary_storage, vo.getSize());
 -            VolumeApiResult res = new VolumeApiResult(vo);
 -            context.future.complete(res);
 -            return null;
 +        VolumeApiResult res = new VolumeApiResult(vo);
 +        context.future.complete(res);
 +        return null;
+         } catch (Exception e) {
+             s_logger.error("register volume failed: ", e);
+             VolumeApiResult res = new VolumeApiResult(null);
+             context.future.complete(res);
+             return null;
+         }
      }
-     
  
 -    @Override
 -    public AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume) {
 -        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
 -        VolumeApiResult result = new VolumeApiResult(volume);
 -        try {
 -            volume.processEvent(Event.ResizeRequested);
 -        } catch (Exception e) {
 -            s_logger.debug("Failed to change state to resize", e);
 -            result.setResult(e.toString());
 -            future.complete(result);
 -            return future;
 -        }
 -        CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volume, future);
 -        AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
 +	@Override
 +	public AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume) {
 +		AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
 +		VolumeApiResult result = new VolumeApiResult(volume);
 +		try {
 +			volume.processEvent(Event.ResizeRequested);
 +		} catch (Exception e) {
 +			s_logger.debug("Failed to change state to resize", e);
 +			result.setResult(e.toString());
 +			future.complete(result);
 +			return future;
 +		}
 +		 CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volume, future);
 +	        AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
          caller.setCallback(caller.getTarget().resizeVolumeCallback(caller, context)).setContext(context);
 -        volume.getDataStore().getDriver().resize(volume, caller);
 -        return future;
 -    }
 -
 +		volume.getDataStore().getDriver().resize(volume, caller);
 +		return future;
 +	}
 +	
- 	protected Void resizeVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
+     protected Void resizeVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback,
+             CreateVolumeContext<VolumeApiResult> context) {
 -        CreateCmdResult result = callback.getResult();
 -        AsyncCallFuture<VolumeApiResult> future = context.future;
 +		CreateCmdResult result = callback.getResult();
 +		AsyncCallFuture<VolumeApiResult> future  = context.future;
- 		VolumeInfo volume = (VolumeInfo)context.volume;
+         VolumeInfo volume = (VolumeInfo) context.volume;
 -
 -        if (result.isFailed()) {
 -            try {
 -                volume.processEvent(Event.OperationFailed);
 -            } catch (Exception e) {
 -                s_logger.debug("Failed to change state", e);
 -            }
 -            VolumeApiResult res = new VolumeApiResult(volume);
 -            res.setResult(result.getResult());
 -            future.complete(res);
 -            return null;
 -        }
 -
 -        try {
 -            volume.processEvent(Event.OperationSuccessed);
 +		
 +		if (result.isFailed()) {
 +			try {
 +				volume.processEvent(Event.OperationFailed);
 +			} catch (Exception e) {
 +				s_logger.debug("Failed to change state", e);
 +			}
 +			VolumeApiResult res = new VolumeApiResult(volume);
 +			res.setResult(result.getResult());
 +			future.complete(res);
 +			return null;
 +		}
 +		
 +		try {
 +			volume.processEvent(Event.OperationSuccessed);
- 		} catch(Exception e) {
+         } catch (Exception e) {
 -            s_logger.debug("Failed to change state", e);
 -            VolumeApiResult res = new VolumeApiResult(volume);
 -            res.setResult(result.getResult());
 -            future.complete(res);
 -            return null;
 -        }
 -
 -        VolumeApiResult res = new VolumeApiResult(volume);
 -        future.complete(res);
 -
 -        return null;
 -    }
 -
 +			s_logger.debug("Failed to change state", e);
 +			VolumeApiResult res = new VolumeApiResult(volume);
 +			res.setResult(result.getResult());
 +			future.complete(res);
 +			return null;
 +		}
 +		
 +		VolumeApiResult res = new VolumeApiResult(volume);
 +		future.complete(res);
 +		
 +		return null;
 +	}
 +	
+     @Override
+     public void handleVolumeSync(DataStore store) {
+         if (store == null) {
+             s_logger.warn("Huh? ssHost is null");
+             return;
+         }
+         long storeId = store.getId();
+ 
+         Map<Long, TemplateProp> volumeInfos = listVolume(store);
+         if (volumeInfos == null) {
+             return;
+         }
+ 
+         List<VolumeDataStoreVO> dbVolumes = _volumeStoreDao.listByStoreId(storeId);
+         List<VolumeDataStoreVO> toBeDownloaded = new ArrayList<VolumeDataStoreVO>(dbVolumes);
+         for (VolumeDataStoreVO volumeStore : dbVolumes) {
+             VolumeVO volume = _volumeDao.findById(volumeStore.getVolumeId());
+             // Exists then don't download
+             if (volumeInfos.containsKey(volume.getId())) {
+                 TemplateProp volInfo = volumeInfos.remove(volume.getId());
+                 toBeDownloaded.remove(volumeStore);
+                 s_logger.info("Volume Sync found " + volume.getUuid() + " already in the volume image store table");
+                 if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
+                     volumeStore.setErrorString("");
+                 }
+                 if (volInfo.isCorrupted()) {
+                     volumeStore.setDownloadState(Status.DOWNLOAD_ERROR);
+                     String msg = "Volume " + volume.getUuid() + " is corrupted on image store ";
+                     volumeStore.setErrorString(msg);
+                     s_logger.info("msg");
+                     if (volumeStore.getDownloadUrl() == null) {
+                         msg = "Volume (" + volume.getUuid() + ") with install path " + volInfo.getInstallPath()
+                                 + "is corrupted, please check in image store: " + volumeStore.getDataStoreId();
+                         s_logger.warn(msg);
+                     } else {
+                         toBeDownloaded.add(volumeStore);
+                     }
+ 
+                 } else { // Put them in right status
+                     volumeStore.setDownloadPercent(100);
+                     volumeStore.setDownloadState(Status.DOWNLOADED);
+                     volumeStore.setInstallPath(volInfo.getInstallPath());
+                     volumeStore.setSize(volInfo.getSize());
+                     volumeStore.setPhysicalSize(volInfo.getPhysicalSize());
+                     volumeStore.setLastUpdated(new Date());
+                     _volumeStoreDao.update(volumeStore.getId(), volumeStore);
+ 
+                     if (volume.getSize() == 0) {
+                         // Set volume size in volumes table
+                         volume.setSize(volInfo.getSize());
+                         _volumeDao.update(volumeStore.getVolumeId(), volume);
+                     }
+ 
+                     if (volInfo.getSize() > 0) {
+                         try {
+                             _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()),
+                                     com.cloud.configuration.Resource.ResourceType.secondary_storage, volInfo.getSize()
+                                             - volInfo.getPhysicalSize());
+                         } catch (ResourceAllocationException e) {
+                             s_logger.warn(e.getMessage());
+                             _alertMgr.sendAlert(AlertManager.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
+                                     volume.getDataCenterId(), volume.getPodId(), e.getMessage(), e.getMessage());
+                         } finally {
+                             _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(),
+                                     com.cloud.configuration.Resource.ResourceType.secondary_storage.getOrdinal());
+                         }
+                     }
+                 }
+                 continue;
+             }
+             // Volume is not on secondary but we should download.
+             if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
+                 s_logger.info("Volume Sync did not find " + volume.getName() + " ready on image store " + storeId
+                         + ", will request download to start/resume shortly");
+                 toBeDownloaded.add(volumeStore);
+             }
+         }
+ 
+         // Download volumes which haven't been downloaded yet.
+         if (toBeDownloaded.size() > 0) {
+             for (VolumeDataStoreVO volumeHost : toBeDownloaded) {
+                 if (volumeHost.getDownloadUrl() == null) { // If url is null we
+                                                            // can't initiate the
+                                                            // download
+                     continue;
+                 }
+                 s_logger.debug("Volume " + volumeHost.getVolumeId() + " needs to be downloaded to " + store.getName());
+                 // TODO: pass a callback later
+                 VolumeInfo vol = volFactory.getVolume(volumeHost.getVolumeId());
+                 createVolumeAsync(vol, store);
+             }
+         }
+ 
+         // Delete volumes which are not present on DB.
+         for (Long uniqueName : volumeInfos.keySet()) {
+             TemplateProp tInfo = volumeInfos.get(uniqueName);
+ 
+             //we cannot directly call expungeVolumeAsync here to
+             // reuse delete logic since in this case, our db does not have
+             // this template at all.
+             VolumeObjectTO tmplTO = new VolumeObjectTO();
+             tmplTO.setDataStore(store.getTO());
+             tmplTO.setPath(tInfo.getInstallPath());
+             tmplTO.setId(tInfo.getId());
+             DeleteCommand dtCommand = new DeleteCommand(tmplTO);
+             EndPoint ep = _epSelector.select(store);
+             Answer answer = ep.sendMessage(dtCommand);
+             if (answer == null || !answer.getResult()) {
+                 s_logger.info("Failed to deleted volume at store: " + store.getName());
+ 
+             } else {
+                 String description = "Deleted volume " + tInfo.getTemplateName() + " on secondary storage " + storeId;
+                 s_logger.info(description);
+             }
+         }
+     }
+ 
+     private Map<Long, TemplateProp> listVolume(DataStore store) {
+         ListVolumeCommand cmd = new ListVolumeCommand(store.getTO(), store.getUri());
+         EndPoint ep = _epSelector.select(store);
+         Answer answer = ep.sendMessage(cmd);
+         if (answer != null && answer.getResult()) {
+             ListVolumeAnswer tanswer = (ListVolumeAnswer) answer;
+             return tanswer.getTemplateInfo();
+         } else {
+             if (s_logger.isDebugEnabled()) {
+                 s_logger.debug("Can not list volumes for image store " + store.getId());
+             }
+         }
+ 
+         return null;
+     }
+ 
+     @Override
+     public SnapshotInfo takeSnapshot(VolumeInfo volume) {
+         VolumeObject vol = (VolumeObject) volume;
+         vol.stateTransit(Volume.Event.SnapshotRequested);
 -
 +	
+         SnapshotInfo snapshot = null;
+         try {
+             snapshot = snapshotMgr.takeSnapshot(volume);
+         } catch (Exception e) {
+             s_logger.debug("Take snapshot: " + volume.getId() + " failed: " + e.toString());
+         } finally {
+             if (snapshot != null) {
+                 vol.stateTransit(Volume.Event.OperationSucceeded);
+             } else {
+                 vol.stateTransit(Volume.Event.OperationFailed);
+             }
+         }
+ 
+         return snapshot;
+     }
  
  }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java
----------------------------------------------------------------------
diff --cc framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java
index 8d91f5f,acbc5b6..dbfbd03
--- a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java
+++ b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallbackDispatcher.java
@@@ -22,20 -22,24 +22,24 @@@ package org.apache.cloudstack.framework
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
- import net.sf.cglib.proxy.CallbackFilter;
 -import org.apache.log4j.Logger;
 -
 -import net.sf.cglib.proxy.CallbackFilter;
  import net.sf.cglib.proxy.Callback;
++import net.sf.cglib.proxy.CallbackFilter;
  import net.sf.cglib.proxy.Enhancer;
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;
  
++import org.apache.log4j.Logger;
++
  @SuppressWarnings("rawtypes")
  public class AsyncCallbackDispatcher<T, R> implements AsyncCompletionCallback {
+     private static final Logger s_logger = Logger.getLogger(AsyncCallbackDispatcher.class);
+ 
 -    private Method _callbackMethod;
 -	private T _targetObject;
 +	private Method _callbackMethod;
- 	private T _targetObject;
++	private final T _targetObject;
  	private Object _contextObject;
  	private Object _resultObject;
 -	private AsyncCallbackDriver _driver = new InplaceAsyncCallbackDriver();
 -
 +	private AsyncCallbackDriver _driver = new InplaceAsyncCallbackDriver(); 
 +	
  	private AsyncCallbackDispatcher(T target) {
  		assert(target != null);
  		_targetObject = target;
@@@ -55,8 -59,14 +59,13 @@@
  	@SuppressWarnings("unchecked")
  	public T getTarget() {
  	    Enhancer en = new Enhancer();
- 	    en.setSuperclass(_targetObject.getClass());
- 	    en.setCallbacks(new Callback[] { new MethodInterceptor() {
 -
+ 	    Class<?> clz = _targetObject.getClass();
+ 	    String clzName = clz.getName();
+ 	    if(clzName.contains("EnhancerByCloudStack"))
+ 	        clz = clz.getSuperclass();
+ 
+ 	    en.setSuperclass(clz);
+ 	    en.setCallbacks(new Callback[]{new MethodInterceptor() {
              @Override
              public Object intercept(Object arg0, Method arg1, Object[] arg2,
                  MethodProxy arg3) throws Throwable {
@@@ -74,14 -84,21 +83,22 @@@
          }
  	    });
  	    en.setCallbackFilter(new CallbackFilter() {
--	        public int accept(Method method) {
++	        @Override
++            public int accept(Method method) {
  	            if (method.getParameterTypes().length == 0 && method.getName().equals("finalize")) {
  	                return 1;
  	            }
  	            return 0;
  	        }}
  	       );
+ 
+ 	    try {
 -	        return (T)en.create();
 +		return (T)en.create();
+ 	    } catch(Throwable e) {
+ 	        s_logger.error("Unexpected exception", e);
+ 	    }
+ 
+ 	    return null;
  	}
  
  	public AsyncCallbackDispatcher<T, R> setCallback(Object useless) {
@@@ -97,8 -114,8 +114,9 @@@
  	public <P> P getContext() {
  		return (P)_contextObject;
  	}
 -
 -	public void complete(Object resultObject) {
 +	
- 	public void complete(Object resultObject) {
++	@Override
++    public void complete(Object resultObject) {
  		_resultObject = resultObject;
  		_driver.performCompletionCallback(this);
  	}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
index e9d5499,96d702d..6d266fd
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
@@@ -173,9 -167,9 +173,10 @@@ public class BaremetalDhcpElement exten
      }
  
      @Override
 -    public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
 +    public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
 +            throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
-         return false;  //To change body of implemented methods use File | Settings | File Templates.
+     	//TODO Add support for baremetal
+         return true;
      }
  
      @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManager.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManager.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
index 6a03e88,efdd221..feb23be
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
@@@ -24,8 -24,11 +24,10 @@@ package com.cloud.baremetal.networkserv
  
  import java.util.List;
  
+ import org.apache.cloudstack.api.AddBaremetalPxeCmd;
+ 
  import com.cloud.baremetal.database.BaremetalPxeVO;
  import com.cloud.deploy.DeployDestination;
 -import com.cloud.host.Host;
  import com.cloud.uservm.UserVm;
  import com.cloud.utils.component.Adapter;
  import com.cloud.vm.NicProfile;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalDhcpCmd.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalDhcpCmd.java
index 0000000,7c56a8a..04c9137
mode 000000,100755..100755
--- a/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalDhcpCmd.java
+++ b/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalDhcpCmd.java
@@@ -1,0 -1,155 +1,156 @@@
+ // 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.
+ // 
+ // Automatically generated by addcopyright.py at 01/29/2013
+ package org.apache.cloudstack.api;
+ 
+ import javax.inject.Inject;
+ 
+ import org.apache.cloudstack.api.APICommand;
+ import org.apache.cloudstack.api.ApiConstants;
+ import org.apache.cloudstack.api.ApiErrorCode;
+ import org.apache.cloudstack.api.BaseAsyncCmd;
+ import org.apache.cloudstack.api.BaseCmd;
+ import org.apache.cloudstack.api.BaseCmd.CommandType;
+ import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+ import org.apache.cloudstack.api.response.PodResponse;
+ import org.apache.cloudstack.api.Parameter;
+ import org.apache.cloudstack.api.ServerApiException;
++import org.apache.cloudstack.context.CallContext;
++
+ import org.apache.log4j.Logger;
+ 
+ import com.cloud.baremetal.database.BaremetalDhcpVO;
+ import com.cloud.baremetal.networkservice.BaremetalDhcpManager;
+ import com.cloud.baremetal.networkservice.BaremetalDhcpResponse;
+ import com.cloud.event.EventTypes;
+ import com.cloud.exception.ConcurrentOperationException;
+ import com.cloud.exception.InsufficientCapacityException;
+ import com.cloud.exception.NetworkRuleConflictException;
+ import com.cloud.exception.ResourceAllocationException;
+ import com.cloud.exception.ResourceUnavailableException;
 -import com.cloud.user.UserContext;
+ @APICommand(name="addBaremetalDhcp", description="adds a baremetal dhcp server", responseObject = BaremetalDhcpResponse.class)
+ public class AddBaremetalDhcpCmd extends BaseAsyncCmd {
+     private static final String s_name = "addexternaldhcpresponse";
+     public static final Logger s_logger = Logger.getLogger(AddBaremetalDhcpCmd.class);
+     
+     @Inject BaremetalDhcpManager mgr;
+     
+     /////////////////////////////////////////////////////
+     //////////////// API parameters /////////////////////
+     /////////////////////////////////////////////////////
+     @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType=PhysicalNetworkResponse.class, required=true, description="the Physical Network ID")
+     private Long physicalNetworkId;
+     
+     @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, required = true, description="Pod Id")
+     private Long podId;
+     
+     @Parameter(name=ApiConstants.DHCP_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of dhcp device")
+     private String dhcpType;
+     
+     @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external dhcp appliance.")
+     private String url;
+ 
+     @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to reach external dhcp device")
+     private String username;
+     
+     @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to reach external dhcp device")
+     private String password;
+     
+     @Override
+     public String getEventType() {
+         return EventTypes.EVENT_BAREMETAL_DHCP_SERVER_ADD;
+     }
+ 
+     @Override
+     public String getEventDescription() {
+         return "Adding an external DHCP server";
+     }
+ 
+     @Override
+     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+             ResourceAllocationException, NetworkRuleConflictException {
+         try {
+             BaremetalDhcpVO vo = mgr.addDchpServer(this);
+             BaremetalDhcpResponse response = mgr.generateApiResponse(vo);
+             response.setObjectName(s_name);
+             response.setResponseName(getCommandName());
+             this.setResponseObject(response);
+         } catch (Exception e) {
+             s_logger.warn("Unable to add external dhcp server with url: " + getUrl(), e);
+             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+         }
+     }
+ 
+     @Override
+     public String getCommandName() {
+         return s_name;
+     }
+ 
+     @Override
+     public long getEntityOwnerId() {
 -        return UserContext.current().getCaller().getId();
++        return CallContext.current().getCallingAccount().getId();
+     }
+ 
+     public Long getPodId() {
+         return podId;
+     }
+ 
+     public void setPodId(Long podId) {
+         this.podId = podId;
+     }
+ 
+     public String getDhcpType() {
+         return dhcpType;
+     }
+ 
+     public void setDhcpType(String dhcpType) {
+         this.dhcpType = dhcpType;
+     }
+ 
+     public String getUrl() {
+         return url;
+     }
+ 
+     public void setUrl(String url) {
+         this.url = url;
+     }
+ 
+     public String getUsername() {
+         return username;
+     }
+ 
+     public void setUsername(String username) {
+         this.username = username;
+     }
+ 
+     public String getPassword() {
+         return password;
+     }
+ 
+     public void setPassword(String password) {
+         this.password = password;
+     }
+ 
+     public Long getPhysicalNetworkId() {
+         return physicalNetworkId;
+     }
+ 
+     public void setPhysicalNetworkId(Long physicalNetworkId) {
+         this.physicalNetworkId = physicalNetworkId;
+     }
+ }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalPxeCmd.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalPxeCmd.java
index 0000000,e1b39e9..49effca
mode 000000,100755..100755
--- a/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalPxeCmd.java
+++ b/plugins/hypervisors/baremetal/src/org/apache/cloudstack/api/AddBaremetalPxeCmd.java
@@@ -1,0 -1,148 +1,149 @@@
+ // 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.
+ // 
+ // Automatically generated by addcopyright.py at 01/29/2013
+ package org.apache.cloudstack.api;
+ 
+ import javax.inject.Inject;
+ 
+ import org.apache.cloudstack.api.APICommand;
+ import org.apache.cloudstack.api.ApiConstants;
+ import org.apache.cloudstack.api.ApiErrorCode;
+ import org.apache.cloudstack.api.BaseAsyncCmd;
+ import org.apache.cloudstack.api.BaseCmd;
+ import org.apache.cloudstack.api.BaseCmd.CommandType;
+ import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+ import org.apache.cloudstack.api.response.PodResponse;
+ import org.apache.cloudstack.api.Parameter;
+ import org.apache.cloudstack.api.ServerApiException;
++import org.apache.cloudstack.context.CallContext;
++
+ import org.apache.log4j.Logger;
+ 
+ import com.cloud.baremetal.database.BaremetalPxeVO;
+ import com.cloud.baremetal.networkservice.BaremetalPxeManager;
+ import com.cloud.event.EventTypes;
+ import com.cloud.exception.ConcurrentOperationException;
+ import com.cloud.exception.InsufficientCapacityException;
+ import com.cloud.exception.NetworkRuleConflictException;
+ import com.cloud.exception.ResourceAllocationException;
+ import com.cloud.exception.ResourceUnavailableException;
 -import com.cloud.user.UserContext;
+ public class AddBaremetalPxeCmd extends BaseAsyncCmd {
+     private static final String s_name = "addexternalpxeresponse";
+     public static final Logger s_logger = Logger.getLogger(AddBaremetalPxeCmd.class);
+     
+     @Inject BaremetalPxeManager pxeMgr;
+     /////////////////////////////////////////////////////
+     //////////////// API parameters /////////////////////
+     /////////////////////////////////////////////////////
+     @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType=PhysicalNetworkResponse.class, required=true, description="the Physical Network ID")
+     private Long physicalNetworkId;
+     
+     @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, description="Pod Id")
+     private Long podId;
+     
+     @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external pxe device")
+     private String url;
+ 
+     @Parameter(name=ApiConstants.PXE_SERVER_TYPE, type=CommandType.STRING, required = true, description="type of pxe device")
+     private String deviceType;
+     
+     @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to reach external pxe device")
+     private String username;
+     
+     @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to reach external pxe device")
+     private String password;
+     
+     @Override
+     public String getEventType() {
+         return EventTypes.EVENT_BAREMETAL_PXE_SERVER_ADD;
+     }
+ 
+     @Override
+     public String getEventDescription() {
+         return "Adding an external pxe server";
+     }
+ 
+     @Override
+     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+             ResourceAllocationException, NetworkRuleConflictException {
+         try {
+             BaremetalPxeVO vo = pxeMgr.addPxeServer(this);
+         } catch (Exception e) {
+             s_logger.warn("Unable to add external pxe server with url: " + getUrl(), e);
+             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); 
+         }
+     }
+ 
+     @Override
+     public String getCommandName() {
+         return s_name;
+     }
+ 
+     @Override
+     public long getEntityOwnerId() {
 -        return UserContext.current().getCaller().getId();
++        return CallContext.current().getCallingAccount().getId();
+     }
+ 
+     public Long getPhysicalNetworkId() {
+         return physicalNetworkId;
+     }
+ 
+     public void setPhysicalNetworkId(Long physicalNetworkId) {
+         this.physicalNetworkId = physicalNetworkId;
+     }
+ 
+     public Long getPodId() {
+         return podId;
+     }
+ 
+     public void setPodId(Long podId) {
+         this.podId = podId;
+     }
+ 
+     public String getUrl() {
+         return url;
+     }
+ 
+     public void setUrl(String url) {
+         this.url = url;
+     }
+ 
+     public String getUsername() {
+         return username;
+     }
+ 
+     public void setUsername(String username) {
+         this.username = username;
+     }
+ 
+     public String getPassword() {
+         return password;
+     }
+ 
+     public void setPassword(String password) {
+         this.password = password;
+     }
+ 
+     public String getDeviceType() {
+         return deviceType;
+     }
+ 
+     public void setDeviceType(String deviceType) {
+         this.deviceType = deviceType;
+     }
+ }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 1d847d1,46003e9..a5548c5
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@@ -66,11 -73,6 +66,14 @@@ import org.libvirt.DomainSnapshot
  import org.libvirt.LibvirtException;
  import org.libvirt.NodeInfo;
  
++import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
++import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
++import org.apache.cloudstack.storage.to.VolumeObjectTO;
 +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 com.cloud.agent.api.Answer;
  import com.cloud.agent.api.AttachIsoCommand;
  import com.cloud.agent.api.AttachVolumeAnswer;
@@@ -832,6 -842,10 +844,10 @@@ ServerResource 
  
          configureVifDrivers(params);
  
 -        KVMStorageProcessor storageProcessor = new KVMStorageProcessor(this._storagePoolMgr, this);
++        KVMStorageProcessor storageProcessor = new KVMStorageProcessor(_storagePoolMgr, this);
+         storageProcessor.configure(name, params);
+         storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
+ 
          return true;
      }
  
@@@ -1243,6 -1252,8 +1254,8 @@@
                  return execute((CheckNetworkCommand) cmd);
              } else if (cmd instanceof NetworkRulesVmSecondaryIpCommand) {
                  return execute((NetworkRulesVmSecondaryIpCommand) cmd);
+             } else if (cmd instanceof StorageSubSystemCommand) {
 -                return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
++                return storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
              } else if (cmd instanceof PvlanSetupCommand) {
                  return execute((PvlanSetupCommand) cmd);
              } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
index 3f153a0,951badd..2e23ba6
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java
@@@ -93,12 -94,12 +94,12 @@@ public class OvsVifDriver extends VifDr
                  }
              } else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) {
                  s_logger.debug("nic " + nic + " needs to be connected to LogicalSwitch " + logicalSwitchUuid);
 -                intf.setVirtualPortInterfaceId(nic.getUuid());
 +                intf.setVirtualPortInterfaceId(nic.getNicUuid());
                  String brName = (trafficLabel != null && !trafficLabel.isEmpty()) ? _pifs.get(trafficLabel) : _pifs.get("private");
-                 intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType));
+                 intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
              }
              else {
-                 intf.defBridgeNet(_bridges.get("guest"), null, nic.getMac(), getGuestNicModel(guestOsType));
+                 intf.defBridgeNet(_bridges.get("guest"), null, nic.getMac(), getGuestNicModel(guestOsType), networkRateKBps);
              }
          } else if (nic.getType() == Networks.TrafficType.Control) {
              /* Make sure the network is still there */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
index 089d46d,59ba001..11fa65c
--- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
+++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
@@@ -123,10 -129,8 +129,9 @@@ import com.cloud.utils.script.Script
  import com.cloud.utils.ssh.SSHCmdHelper;
  import com.cloud.vm.DiskProfile;
  import com.cloud.vm.VirtualMachine;
 +import com.cloud.vm.VirtualMachine.PowerState;
  import com.cloud.vm.VirtualMachine.State;
  import com.trilead.ssh2.SCPClient;
- import com.xensource.xenapi.Types.XenAPIException;
  
  public class OvmResourceBase implements ServerResource, HypervisorResource {
  	private static final Logger s_logger = Logger.getLogger(OvmResourceBase.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
index 58840c8,8a03c4b..1263d7d
--- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java
@@@ -51,9 -51,8 +51,9 @@@ import com.cloud.hypervisor.Hypervisor.
  import com.cloud.network.Networks.RouterPrivateIpStrategy;
  import com.cloud.simulator.MockVMVO;
  import com.cloud.storage.Storage.StorageResourceType;
- import com.cloud.storage.template.TemplateInfo;
+ import com.cloud.storage.template.TemplateProp;
  import com.cloud.utils.Pair;
 +import com.cloud.vm.VirtualMachine.PowerState;
  import com.cloud.vm.VirtualMachine.State;
  
  public class AgentRoutingResource extends AgentStorageResource {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
index 21ec998,95521e8..60839b1
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
@@@ -27,8 -27,11 +27,10 @@@ import java.util.Map
  import javax.ejb.Local;
  import javax.inject.Inject;
  
 -import org.apache.cloudstack.api.ApiConstants.VMDetails;
 -import org.apache.cloudstack.storage.command.CopyCommand;
  import org.apache.log4j.Logger;
 -import org.springframework.stereotype.Component;
 +
++import org.apache.cloudstack.storage.command.CopyCommand;
+ 
  import com.cloud.agent.api.BackupSnapshotCommand;
  import com.cloud.agent.api.Command;
  import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
@@@ -284,9 -291,26 +290,26 @@@ public class VMwareGuru extends Hypervi
                  cmd instanceof CopyVolumeCommand ||
                  cmd instanceof CreateVolumeOVACommand ||
                  cmd instanceof PrepareOVAPackingCommand ||
-                 cmd instanceof CreateVolumeFromSnapshotCommand) {
+                 cmd instanceof CreateVolumeFromSnapshotCommand ||
+                 cmd instanceof CopyCommand) {
+             if (cmd instanceof CopyCommand) {
+                 CopyCommand cpyCommand = (CopyCommand)cmd;
+                 DataTO srcData = cpyCommand.getSrcTO();
+                 DataStoreTO srcStoreTO = srcData.getDataStore();
+                 DataTO destData = cpyCommand.getDestTO();
+                 DataStoreTO destStoreTO = destData.getDataStore();
+                 
+                 if (destData.getObjectType() == DataObjectType.VOLUME && destStoreTO.getRole() == DataStoreRole.Primary &&
+                         srcData.getObjectType() == DataObjectType.TEMPLATE && srcStoreTO.getRole() == DataStoreRole.Primary) {
+                     needDelegation = false;
+                 } else {
 -                    needDelegation = true;
 -                }
 +            needDelegation = true;
 +        }
+             } else {
+                 needDelegation = true;
+             }
+             
+         }
          /* Fang: remove this before checking in */
          // needDelegation = false;
  

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7b7db056/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
----------------------------------------------------------------------
diff --cc plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
index 93e6b5f,4ae0f30..887c81d
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@@ -25,12 -25,12 +25,23 @@@ import java.rmi.RemoteException
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
--import java.util.Properties;
  import java.util.Map;
++import java.util.Properties;
  import java.util.UUID;
  
  import org.apache.log4j.Logger;
  
++import com.vmware.vim25.ManagedObjectReference;
++import com.vmware.vim25.TaskInfo;
++import com.vmware.vim25.VirtualDeviceConfigSpec;
++import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
++import com.vmware.vim25.VirtualDisk;
++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 com.cloud.agent.api.Answer;
  import com.cloud.agent.api.BackupSnapshotAnswer;
  import com.cloud.agent.api.BackupSnapshotCommand;
@@@ -46,11 -46,11 +57,10 @@@ import com.cloud.agent.api.RevertToVMSn
  import com.cloud.agent.api.RevertToVMSnapshotCommand;
  import com.cloud.agent.api.storage.CopyVolumeAnswer;
  import com.cloud.agent.api.storage.CopyVolumeCommand;
--import com.cloud.agent.api.storage.PrepareOVAPackingAnswer;
--import com.cloud.agent.api.storage.PrepareOVAPackingCommand;
++import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
  import com.cloud.agent.api.storage.CreateVolumeOVAAnswer;
  import com.cloud.agent.api.storage.CreateVolumeOVACommand;
--import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
++import com.cloud.agent.api.storage.PrepareOVAPackingCommand;
  import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
  import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
  import com.cloud.agent.api.to.StorageFilerTO;
@@@ -60,7 -60,7 +70,6 @@@ import com.cloud.hypervisor.vmware.mo.D
  import com.cloud.hypervisor.vmware.mo.DatastoreMO;
  import com.cloud.hypervisor.vmware.mo.HostMO;
  import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
--import com.cloud.hypervisor.vmware.mo.TaskMO;
  import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
  import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
  import com.cloud.hypervisor.vmware.util.VmwareContext;
@@@ -76,17 -76,17 +85,6 @@@ import com.cloud.utils.Ternary
  import com.cloud.utils.script.Script;
  import com.cloud.vm.VirtualMachine;
  import com.cloud.vm.snapshot.VMSnapshot;
--import com.vmware.vim25.ManagedObjectReference;
--import com.vmware.vim25.TaskEvent;
--import com.vmware.vim25.TaskInfo;
--import com.vmware.vim25.VirtualDeviceConfigSpec;
--import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
--import com.vmware.vim25.VirtualDisk;
--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;
  
  public class VmwareStorageManagerImpl implements VmwareStorageManager {
      private static final Logger s_logger = Logger.getLogger(VmwareStorageManagerImpl.class);
@@@ -111,7 -111,7 +109,7 @@@
      //Fang note: use Answer here instead of the PrepareOVAPackingAnswer
      @Override
      public Answer execute(VmwareHostService hostService, PrepareOVAPackingCommand cmd) {
--		String secStorageUrl = ((PrepareOVAPackingCommand) cmd).getSecondaryStorageUrl();
++		String secStorageUrl = cmd.getSecondaryStorageUrl();
  		assert (secStorageUrl != null);
          String installPath = cmd.getTemplatePath();
          String details = null;
@@@ -165,7 -165,7 +163,7 @@@
      // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature)
      @Override
      public Answer execute(VmwareHostService hostService, CreateVolumeOVACommand cmd) {
--		String secStorageUrl = ((CreateVolumeOVACommand) cmd).getSecondaryStorageUrl();
++		String secStorageUrl = cmd.getSecondaryStorageUrl();
  		assert (secStorageUrl != null);
          String installPath = cmd.getVolPath();
          String details = null;
@@@ -1467,8 -1463,8 +1465,4 @@@
              return command.execute();
          }
      }
--
--    private static String getVolumeRelativeDirInSecStroage(long volumeId) {
--        return "volumes/" + volumeId;
--    }
  }