Skip to content

Commit 3a889aa

Browse files
author
Alena Prokharchyk
committed
CLOUDSTACK-3886: Volume attach/detach implementation for ROOT disk
Implemented for Xen hypervisor only by now Unittests are included
1 parent af1eba2 commit 3a889aa

7 files changed

Lines changed: 528 additions & 163 deletions

File tree

api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public class AttachVolumeCmd extends BaseAsyncVolumeCmd {
4848
/////////////////////////////////////////////////////
4949

5050
@Parameter(name = ApiConstants.DEVICE_ID, type = CommandType.LONG, description = "the ID of the device to map the volume to within the guest OS. "
51-
+ "If no deviceId is passed in, the next available deviceId will be chosen. " + "Possible values for a Linux OS are:" + "* 1 - /dev/xvdb" + "* 2 - /dev/xvdc"
51+
+ "If no deviceId is passed in, the next available deviceId will be chosen. " + "Possible values for a Linux OS are:" + "* 0 - /dev/xvda" + "* 1 - /dev/xvdb" + "* 2 - /dev/xvdc"
5252
+ "* 4 - /dev/xvde" + "* 5 - /dev/xvdf" + "* 6 - /dev/xvdg" + "* 7 - /dev/xvdh" + "* 8 - /dev/xvdi" + "* 9 - /dev/xvdj")
5353
private Long deviceId;
5454

engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
8989

9090
DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner);
9191

92-
VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, Volume rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException;
92+
VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volume, HypervisorType rootDiskHyperType, StoragePool storagePool) throws NoTransitionException;
9393

9494
void release(VirtualMachineProfile profile);
9595

engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
import javax.inject.Inject;
3131
import javax.naming.ConfigurationException;
3232

33-
import org.apache.log4j.Logger;
34-
3533
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
3634
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
3735
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
@@ -58,6 +56,7 @@
5856
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
5957
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
6058
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
59+
import org.apache.log4j.Logger;
6160

6261
import com.cloud.agent.api.to.DataTO;
6362
import com.cloud.agent.api.to.DiskTO;
@@ -721,20 +720,20 @@ private VolumeInfo copyVolume(StoragePool rootDiskPool, VolumeInfo volume, Virtu
721720
}
722721

723722
@Override
724-
public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, Volume rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException {
723+
public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volume, HypervisorType rootDiskHyperType, StoragePool storagePool) throws NoTransitionException {
725724
VirtualMachineTemplate rootDiskTmplt = _entityMgr.findById(VirtualMachineTemplate.class, vm.getTemplateId());
726725
DataCenter dcVO = _entityMgr.findById(DataCenter.class, vm.getDataCenterId());
727726
Pod pod = _entityMgr.findById(Pod.class, vm.getPodIdToDeployIn());
728-
StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId());
727+
729728
ServiceOffering svo = _entityMgr.findById(ServiceOffering.class, vm.getServiceOfferingId());
730729
DiskOffering diskVO = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId());
731-
Long clusterId = (rootDiskPool == null ? null : rootDiskPool.getClusterId());
730+
Long clusterId = (storagePool == null ? null : storagePool.getClusterId());
732731

733732
VolumeInfo vol = null;
734733
if (volume.getState() == Volume.State.Allocated) {
735734
vol = createVolume(volume, vm, rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, new ArrayList<StoragePool>(), volume.getSize(), rootDiskHyperType);
736735
} else if (volume.getState() == Volume.State.Uploaded) {
737-
vol = copyVolume(rootDiskPool, volume, vm, rootDiskTmplt, dcVO, pod, diskVO, svo, rootDiskHyperType);
736+
vol = copyVolume(storagePool, volume, vm, rootDiskTmplt, dcVO, pod, diskVO, svo, rootDiskHyperType);
738737
if (vol != null) {
739738
// Moving of Volume is successful, decrement the volume resource count from secondary for an account and increment it into primary storage under same account.
740739
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage, volume.getSize());
@@ -1234,6 +1233,12 @@ public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws Sto
12341233
}
12351234
throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null, vm:" + vm);
12361235
}
1236+
1237+
// don't allow to start vm that doesn't have a root volume
1238+
if (_volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT).isEmpty()) {
1239+
throw new CloudRuntimeException("Unable to prepare volumes for vm as ROOT volume is missing");
1240+
}
1241+
12371242
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
12381243
if (s_logger.isDebugEnabled()) {
12391244
s_logger.debug("Checking if we need to prepare " + vols.size() + " volumes for " + vm);

engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ public void attachVolume(long volumeId, long vmId, long deviceId) {
225225
volume.setDeviceId(deviceId);
226226
volume.setUpdated(new Date());
227227
volume.setAttached(new Date());
228+
if (deviceId == 0L) {
229+
volume.setVolumeType(Type.ROOT);
230+
}
228231
update(volumeId, volume);
229232
}
230233

@@ -235,6 +238,9 @@ public void detachVolume(long volumeId) {
235238
volume.setDeviceId(null);
236239
volume.setUpdated(new Date());
237240
volume.setAttached(null);
241+
if (findById(volumeId).getVolumeType() == Type.ROOT) {
242+
volume.setVolumeType(Type.DATADISK);
243+
}
238244
update(volumeId, volume);
239245
}
240246

server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
package com.cloud.deploy;
1818

1919
import java.util.ArrayList;
20-
import java.util.Arrays;
20+
import java.util.Arrays;
2121
import java.util.Comparator;
2222
import java.util.HashMap;
23-
import java.util.HashSet;
23+
import java.util.HashSet;
2424
import java.util.List;
2525
import java.util.Map;
26-
import java.util.Set;
26+
import java.util.Set;
2727
import java.util.Timer;
2828
import java.util.TreeSet;
2929

@@ -33,7 +33,7 @@
3333

3434
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
3535
import org.apache.cloudstack.affinity.AffinityGroupService;
36-
import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
36+
import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
3737
import org.apache.cloudstack.affinity.AffinityGroupVO;
3838
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
3939
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
@@ -49,17 +49,17 @@
4949
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
5050
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
5151
import org.apache.cloudstack.utils.identity.ManagementServerNode;
52-
import org.apache.log4j.Logger;
53-
54-
import com.cloud.agent.AgentManager;
55-
import com.cloud.agent.Listener;
56-
import com.cloud.agent.api.AgentControlAnswer;
57-
import com.cloud.agent.api.AgentControlCommand;
58-
import com.cloud.agent.api.Answer;
59-
import com.cloud.agent.api.Command;
60-
import com.cloud.agent.api.StartupCommand;
61-
import com.cloud.agent.api.StartupRoutingCommand;
62-
import com.cloud.agent.manager.allocator.HostAllocator;
52+
import org.apache.log4j.Logger;
53+
54+
import com.cloud.agent.AgentManager;
55+
import com.cloud.agent.Listener;
56+
import com.cloud.agent.api.AgentControlAnswer;
57+
import com.cloud.agent.api.AgentControlCommand;
58+
import com.cloud.agent.api.Answer;
59+
import com.cloud.agent.api.Command;
60+
import com.cloud.agent.api.StartupCommand;
61+
import com.cloud.agent.api.StartupRoutingCommand;
62+
import com.cloud.agent.manager.allocator.HostAllocator;
6363
import com.cloud.capacity.CapacityManager;
6464
import com.cloud.capacity.dao.CapacityDao;
6565
import com.cloud.configuration.Config;
@@ -68,19 +68,19 @@
6868
import com.cloud.dc.ClusterVO;
6969
import com.cloud.dc.DataCenter;
7070
import com.cloud.dc.DataCenterVO;
71-
import com.cloud.dc.DedicatedResourceVO;
71+
import com.cloud.dc.DedicatedResourceVO;
7272
import com.cloud.dc.Pod;
7373
import com.cloud.dc.dao.ClusterDao;
7474
import com.cloud.dc.dao.DataCenterDao;
75-
import com.cloud.dc.dao.DedicatedResourceDao;
75+
import com.cloud.dc.dao.DedicatedResourceDao;
7676
import com.cloud.dc.dao.HostPodDao;
7777
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
7878
import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage;
7979
import com.cloud.deploy.dao.PlannerHostReservationDao;
8080
import com.cloud.exception.AffinityConflictException;
8181
import com.cloud.exception.ConnectionException;
8282
import com.cloud.exception.InsufficientServerCapacityException;
83-
import com.cloud.gpu.GPU;
83+
import com.cloud.gpu.GPU;
8484
import com.cloud.host.Host;
8585
import com.cloud.host.HostVO;
8686
import com.cloud.host.Status;
@@ -89,13 +89,13 @@
8989
import com.cloud.offering.ServiceOffering;
9090
import com.cloud.org.Cluster;
9191
import com.cloud.org.Grouping;
92-
import com.cloud.resource.ResourceManager;
92+
import com.cloud.resource.ResourceManager;
9393
import com.cloud.resource.ResourceState;
94-
import com.cloud.service.ServiceOfferingDetailsVO;
95-
import com.cloud.service.dao.ServiceOfferingDetailsDao;
94+
import com.cloud.service.ServiceOfferingDetailsVO;
95+
import com.cloud.service.dao.ServiceOfferingDetailsDao;
9696
import com.cloud.storage.DiskOfferingVO;
9797
import com.cloud.storage.ScopeType;
98-
import com.cloud.storage.Storage;
98+
import com.cloud.storage.Storage;
9999
import com.cloud.storage.StorageManager;
100100
import com.cloud.storage.StoragePool;
101101
import com.cloud.storage.StoragePoolHostVO;
@@ -117,15 +117,15 @@
117117
import com.cloud.utils.db.Transaction;
118118
import com.cloud.utils.db.TransactionCallback;
119119
import com.cloud.utils.db.TransactionStatus;
120-
import com.cloud.utils.exception.CloudRuntimeException;
120+
import com.cloud.utils.exception.CloudRuntimeException;
121121
import com.cloud.utils.fsm.StateListener;
122122
import com.cloud.vm.DiskProfile;
123123
import com.cloud.vm.ReservationContext;
124124
import com.cloud.vm.VMInstanceVO;
125125
import com.cloud.vm.VirtualMachine;
126126
import com.cloud.vm.VirtualMachine.Event;
127127
import com.cloud.vm.VirtualMachine.State;
128-
import com.cloud.vm.VirtualMachineProfile;
128+
import com.cloud.vm.VirtualMachineProfile;
129129
import com.cloud.vm.dao.UserVmDao;
130130
import com.cloud.vm.dao.VMInstanceDao;
131131

@@ -1161,6 +1161,11 @@ protected Pair<Map<Volume, List<StoragePool>>, List<Volume>> findSuitablePoolsFo
11611161
throw new CloudRuntimeException("Unable to create deployment, no usable volumes found for the VM");
11621162
}
11631163

1164+
// don't allow to start vm that doesn't have a root volume
1165+
if (_volsDao.findByInstanceAndType(vmProfile.getId(), Volume.Type.ROOT).isEmpty()) {
1166+
throw new CloudRuntimeException("Unable to prepare volumes for vm as ROOT volume is missing");
1167+
}
1168+
11641169
// for each volume find list of suitable storage pools by calling the
11651170
// allocators
11661171
Set<Long> originalAvoidPoolSet = avoid.getPoolsToAvoid();

0 commit comments

Comments
 (0)