Skip to content

Commit c427e8d

Browse files
author
Mike Tutkowski
committed
CLOUDSTACK-6170
1 parent e37a6cd commit c427e8d

11 files changed

Lines changed: 218 additions & 21 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.cloud.offering;
2+
3+
public class DiskOfferingInfo {
4+
private DiskOffering _diskOffering;
5+
private Long _size;
6+
private Long _minIops;
7+
private Long _maxIops;
8+
9+
public DiskOfferingInfo() {
10+
}
11+
12+
public DiskOfferingInfo(DiskOffering diskOffering) {
13+
_diskOffering = diskOffering;
14+
}
15+
16+
public void setDiskOffering(DiskOffering diskOffering) {
17+
_diskOffering = diskOffering;
18+
}
19+
20+
public DiskOffering getDiskOffering() {
21+
return _diskOffering;
22+
}
23+
24+
public void setSize(Long size) {
25+
_size = size;
26+
}
27+
28+
public Long getSize() {
29+
return _size;
30+
}
31+
32+
public void setMinIops(Long minIops) {
33+
_minIops = minIops;
34+
}
35+
36+
public Long getMinIops() {
37+
return _minIops;
38+
}
39+
40+
public void setMaxIops(Long maxIops) {
41+
_maxIops = maxIops;
42+
}
43+
44+
public Long getMaxIops() {
45+
return _maxIops;
46+
}
47+
}

api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,62 @@ public void execute() {
462462
}
463463
}
464464

465+
// this is an opportunity to verify that parameters that came in via the Details Map are OK
466+
// for example, minIops and maxIops should either both be specified or neither be specified and,
467+
// if specified, minIops should be <= maxIops
468+
private void verifyDetails() {
469+
Map<String, String> map = getDetails();
470+
471+
if (map != null) {
472+
String minIops = (String)map.get("minIops");
473+
String maxIops = (String)map.get("maxIops");
474+
475+
if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) {
476+
throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified.");
477+
}
478+
479+
long lMinIops;
480+
481+
try {
482+
if (minIops != null) {
483+
lMinIops = Long.valueOf(minIops);
484+
}
485+
else {
486+
lMinIops = 0;
487+
}
488+
}
489+
catch (NumberFormatException ex) {
490+
throw new InvalidParameterValueException("'Min IOPS' must be a whole number.");
491+
}
492+
493+
long lMaxIops;
494+
495+
try {
496+
if (maxIops != null) {
497+
lMaxIops = Long.valueOf(maxIops);
498+
}
499+
else {
500+
lMaxIops = 0;
501+
}
502+
}
503+
catch (NumberFormatException ex) {
504+
throw new InvalidParameterValueException("'Max IOPS' must be a whole number.");
505+
}
506+
507+
if (lMinIops > lMaxIops) {
508+
throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'.");
509+
}
510+
}
511+
}
512+
465513
@Override
466514
public void create() throws ResourceAllocationException {
467515
try {
468516
//Verify that all objects exist before passing them to the service
469517
Account owner = _accountService.getActiveAccountById(getEntityOwnerId());
470518

519+
verifyDetails();
520+
471521
DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
472522
if (zone == null) {
473523
throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId);

engine/api/src/com/cloud/vm/VirtualMachineManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
import com.cloud.hypervisor.Hypervisor.HypervisorType;
3838
import com.cloud.network.Network;
3939
import com.cloud.offering.DiskOffering;
40+
import com.cloud.offering.DiskOfferingInfo;
4041
import com.cloud.offering.ServiceOffering;
4142
import com.cloud.storage.StoragePool;
4243
import com.cloud.storage.Volume;
4344
import com.cloud.template.VirtualMachineTemplate;
44-
import com.cloud.utils.Pair;
4545
import com.cloud.utils.component.Manager;
4646
import com.cloud.utils.fsm.NoTransitionException;
4747

@@ -76,7 +76,7 @@ public interface Topics {
7676
* @param hyperType Hypervisor type
7777
* @throws InsufficientCapacityException If there are insufficient capacity to deploy this vm.
7878
*/
79-
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, Pair<? extends DiskOffering, Long> rootDiskOffering,
79+
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
8080
LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
8181
HypervisorType hyperType) throws InsufficientCapacityException;
8282

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
@@ -106,7 +106,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
106106

107107
boolean canVmRestartOnAnotherServer(long vmId);
108108

109-
DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm,
109+
DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
110110
Account owner);
111111

112112
String getVmNameFromVolumeId(long volumeId);

engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
import com.cloud.network.dao.NetworkVO;
155155
import com.cloud.network.rules.RulesManager;
156156
import com.cloud.offering.DiskOffering;
157+
import com.cloud.offering.DiskOfferingInfo;
157158
import com.cloud.offering.ServiceOffering;
158159
import com.cloud.org.Cluster;
159160
import com.cloud.resource.ResourceManager;
@@ -372,7 +373,7 @@ public void registerGuru(VirtualMachine.Type type, VirtualMachineGuru guru) {
372373
@Override
373374
@DB
374375
public void allocate(String vmInstanceName, final VirtualMachineTemplate template, ServiceOffering serviceOffering,
375-
final Pair<? extends DiskOffering, Long> rootDiskOffering, LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings,
376+
final DiskOfferingInfo rootDiskOfferingInfo, LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings,
376377
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType)
377378
throws InsufficientCapacityException {
378379

@@ -412,11 +413,13 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
412413
}
413414

414415
if (template.getFormat() == ImageFormat.ISO) {
415-
volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vmFinal, template, owner);
416+
volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(), vmFinal,
417+
template, owner);
416418
} else if (template.getFormat() == ImageFormat.BAREMETAL) {
417419
// Do nothing
418420
} else {
419-
volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), template, vmFinal, owner);
421+
volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
422+
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner);
420423
}
421424

422425
for (Map.Entry<? extends DiskOffering, Long> offering : dataDiskOfferingsFinal.entrySet()) {
@@ -433,7 +436,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
433436
@Override
434437
public void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
435438
LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException {
436-
allocate(vmInstanceName, template, serviceOffering, new Pair<DiskOffering, Long>(serviceOffering, null), null, networks, plan, hyperType);
439+
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(serviceOffering), null, networks, plan, hyperType);
437440
}
438441

439442
private VirtualMachineGuru getVmGuru(VirtualMachine vm) {

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,19 @@
4646
import com.cloud.network.dao.NetworkDao;
4747
import com.cloud.network.dao.NetworkVO;
4848
import com.cloud.offering.DiskOffering;
49+
import com.cloud.offering.DiskOfferingInfo;
4950
import com.cloud.service.ServiceOfferingVO;
5051
import com.cloud.service.dao.ServiceOfferingDao;
5152
import com.cloud.storage.DiskOfferingVO;
5253
import com.cloud.storage.dao.DiskOfferingDao;
5354
import com.cloud.storage.dao.VMTemplateDao;
5455
import com.cloud.user.dao.AccountDao;
55-
import com.cloud.utils.Pair;
5656
import com.cloud.utils.component.ComponentContext;
5757
import com.cloud.vm.NicProfile;
5858
import com.cloud.vm.VMInstanceVO;
5959
import com.cloud.vm.VirtualMachineManager;
6060
import com.cloud.vm.dao.UserVmDao;
61+
import com.cloud.vm.dao.UserVmDetailsDao;
6162
import com.cloud.vm.dao.VMInstanceDao;
6263

6364
@Component
@@ -78,6 +79,9 @@ public class CloudOrchestrator implements OrchestrationService {
7879
@Inject
7980
protected UserVmDao _userVmDao = null;
8081

82+
@Inject
83+
protected UserVmDetailsDao _userVmDetailsDao = null;
84+
8185
@Inject
8286
protected ServiceOfferingDao _serviceOfferingDao;
8387

@@ -176,12 +180,25 @@ public VirtualMachineEntity createVirtualMachine(String id, String owner, String
176180
// If the template represents an ISO, a disk offering must be passed in, and will be used to create the root disk
177181
// Else, a disk offering is optional, and if present will be used to create the data disk
178182

179-
Pair<DiskOfferingVO, Long> rootDiskOffering = new Pair<DiskOfferingVO, Long>(null, null);
183+
DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
180184
LinkedHashMap<DiskOfferingVO, Long> dataDiskOfferings = new LinkedHashMap<DiskOfferingVO, Long>();
181185

182186
ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
183-
rootDiskOffering.first(offering);
184-
rootDiskOffering.second(rootDiskSize);
187+
188+
rootDiskOfferingInfo.setDiskOffering(offering);
189+
rootDiskOfferingInfo.setSize(rootDiskSize);
190+
191+
if (offering.isCustomizedIops()) {
192+
Map<String, String> userVmDetails = _userVmDetailsDao.listDetailsKeyPairs(vm.getId());
193+
194+
if (userVmDetails != null) {
195+
String minIops = userVmDetails.get("minIops");
196+
String maxIops = userVmDetails.get("maxIops");
197+
198+
rootDiskOfferingInfo.setMinIops(minIops != null && minIops.trim().length() > 0 ? Long.parseLong(minIops) : null);
199+
rootDiskOfferingInfo.setMaxIops(maxIops != null && maxIops.trim().length() > 0 ? Long.parseLong(maxIops) : null);
200+
}
201+
}
185202

186203
if (vm.getDiskOfferingId() != null) {
187204
DiskOfferingVO diskOffering = _diskOfferingDao.findById(vm.getDiskOfferingId());
@@ -199,7 +216,7 @@ public VirtualMachineEntity createVirtualMachine(String id, String owner, String
199216
dataDiskOfferings.put(diskOffering, size);
200217
}
201218

202-
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, plan,
219+
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), offering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan,
203220
hypervisorType);
204221

205222
return vmEntity;
@@ -217,9 +234,11 @@ public VirtualMachineEntity createVirtualMachineFromScratch(String id, String ow
217234
//load vm instance and offerings and call virtualMachineManagerImpl
218235
VMInstanceVO vm = _vmDao.findByUuid(id);
219236

220-
Pair<DiskOffering, Long> rootDiskOffering = new Pair<DiskOffering, Long>(null, null);
221237
ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
222-
rootDiskOffering.first(offering);
238+
239+
DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
240+
241+
rootDiskOfferingInfo.setDiskOffering(offering);
223242

224243
LinkedHashMap<DiskOffering, Long> dataDiskOfferings = new LinkedHashMap<DiskOffering, Long>();
225244
Long diskOfferingId = vm.getDiskOfferingId();
@@ -238,8 +257,9 @@ public VirtualMachineEntity createVirtualMachineFromScratch(String id, String ow
238257
}
239258
_volumeMgr.validateVolumeSizeRange(size * 1024 * 1024 * 1024);
240259
}
241-
rootDiskOffering.first(diskOffering);
242-
rootDiskOffering.second(size);
260+
261+
rootDiskOfferingInfo.setDiskOffering(diskOffering);
262+
rootDiskOfferingInfo.setSize(size);
243263

244264
LinkedHashMap<Network, List<? extends NicProfile>> networkIpMap = new LinkedHashMap<Network, List<? extends NicProfile>>();
245265
for (String uuid : networkNicMap.keySet()) {
@@ -251,7 +271,7 @@ public VirtualMachineEntity createVirtualMachineFromScratch(String id, String ow
251271

252272
HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
253273

254-
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, plan, hypervisorType);
274+
_itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), offering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan, hypervisorType);
255275

256276
return vmEntity;
257277
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,15 +605,19 @@ public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offeri
605605
}
606606

607607
@Override
608-
public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
608+
public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
609609
assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
610610

611611
Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId());
612612
if (rootDisksize != null) {
613613
size = (rootDisksize * 1024 * 1024 * 1024);
614614
}
615-
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, offering.getMinIops(), offering.getMaxIops(),
616-
null);
615+
616+
minIops = minIops != null ? minIops : offering.getMinIops();
617+
maxIops = maxIops != null ? maxIops : offering.getMaxIops();
618+
619+
VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, minIops, maxIops, null);
620+
617621
vol.setFormat(getSupportedImageFormatForCluster(template.getHypervisorType()));
618622
if (vm != null) {
619623
vol.setInstanceId(vm.getId());

ui/css/cloudstack3.css

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6050,6 +6050,13 @@ label.error {
60506050
border-radius: 4px;
60516051
}
60526052

6053+
.multi-wizard.instance-wizard .section.custom-iops {
6054+
position: relative;
6055+
background: #F4F4F4;
6056+
padding: 7px;
6057+
border-radius: 4px;
6058+
}
6059+
60536060
.multi-wizard.instance-wizard .section.custom-size input[type=radio] {
60546061
float: left;
60556062
}
@@ -6060,6 +6067,12 @@ label.error {
60606067
margin: 6px -1px 0 8px;
60616068
}
60626069

6070+
.multi-wizard.instance-wizard .section.custom-iops input[type=text] {
6071+
float: left;
6072+
width: 28px;
6073+
margin: 6px -1px 0 8px;
6074+
}
6075+
60636076
.multi-wizard.instance-wizard .section.custom-size label.error {
60646077
position: absolute;
60656078
top: 29px;
@@ -6075,29 +6088,56 @@ label.error {
60756088
height: 235px;
60766089
}
60776090

6091+
.instance-wizard .step.service-offering.custom-iops .select-container {
6092+
height: 235px;
6093+
}
6094+
60786095
.instance-wizard .step.service-offering .custom-size {
60796096
display: none;
60806097
}
60816098

6099+
.instance-wizard .step.service-offering .custom-iops {
6100+
display: none;
6101+
}
6102+
60826103
.instance-wizard .step.service-offering.custom-size .custom-size {
60836104
display: block;
60846105
}
60856106

6107+
.instance-wizard .step.service-offering.custom-iops .custom-iops {
6108+
display: block;
6109+
}
6110+
60866111
.instance-wizard .step.service-offering .custom-size .field {
60876112
width: 30%;
60886113
float: left;
60896114
margin-bottom: 13px;
60906115
}
60916116

6117+
.instance-wizard .step.service-offering .custom-iops .field {
6118+
width: 30%;
6119+
float: left;
6120+
margin-bottom: 13px;
6121+
}
6122+
60926123
.instance-wizard .step.service-offering .custom-size .field label {
60936124
text-indent: 20px;
60946125
}
60956126

6127+
.instance-wizard .step.service-offering .custom-iops .field label {
6128+
text-indent: 20px;
6129+
}
6130+
60966131
.instance-wizard .step.service-offering .custom-size .field input {
60976132
width: 88%;
60986133
margin-left: 26px;
60996134
}
61006135

6136+
.instance-wizard .step.service-offering .custom-iops .field input {
6137+
width: 88%;
6138+
margin-left: 26px;
6139+
}
6140+
61016141
/*** Network*/
61026142
.multi-wizard.instance-wizard .no-network {
61036143
background: #FFFFFF;

0 commit comments

Comments
 (0)