Skip to content

Commit 87d81eb

Browse files
committed
AutoScaling: support userdata id and userdata details
1 parent 5ab2faf commit 87d81eb

File tree

12 files changed

+203
-37
lines changed

12 files changed

+203
-37
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.cloudstack.api.response.ProjectResponse;
3636
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
3737
import org.apache.cloudstack.api.response.TemplateResponse;
38+
import org.apache.cloudstack.api.response.UserDataResponse;
3839
import org.apache.cloudstack.api.response.UserResponse;
3940
import org.apache.cloudstack.api.response.ZoneResponse;
4041
import org.apache.cloudstack.context.CallContext;
@@ -107,6 +108,12 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd {
107108
since = "4.18.0")
108109
private String userData;
109110

111+
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18.1")
112+
private Long userDataId;
113+
114+
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.", since = "4.18.1")
115+
private Map userDataDetails;
116+
110117
@Parameter(name = ApiConstants.AUTOSCALE_USER_ID,
111118
type = CommandType.UUID,
112119
entityType = UserResponse.class,
@@ -163,6 +170,14 @@ public String getUserData() {
163170
return userData;
164171
}
165172

173+
public Long getUserDataId() {
174+
return userDataId;
175+
}
176+
177+
public Map<String, String> getUserDataDetails() {
178+
return convertDetailsToMap(userDataDetails);
179+
}
180+
166181
public Long getAutoscaleUserId() {
167182
return autoscaleUserId;
168183
}

api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/UpdateAutoScaleVmProfileCmd.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
package org.apache.cloudstack.api.command.user.autoscale;
1919

20+
import java.util.Collection;
2021
import java.util.HashMap;
22+
import java.util.Iterator;
2123
import java.util.Map;
2224

2325
import org.apache.log4j.Logger;
@@ -35,6 +37,7 @@
3537
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
3638
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
3739
import org.apache.cloudstack.api.response.TemplateResponse;
40+
import org.apache.cloudstack.api.response.UserDataResponse;
3841
import org.apache.cloudstack.api.response.UserResponse;
3942
import org.apache.cloudstack.context.CallContext;
4043

@@ -102,6 +105,14 @@ public class UpdateAutoScaleVmProfileCmd extends BaseAsyncCustomIdCmd {
102105
since = "4.18.0")
103106
private String userData;
104107

108+
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the userdata",
109+
since = "4.18.1")
110+
private Long userdataId;
111+
112+
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.",
113+
since = "4.18.1")
114+
private Map userdataDetails;
115+
105116
@Parameter(name = ApiConstants.AUTOSCALE_USER_ID,
106117
type = CommandType.UUID,
107118
entityType = UserResponse.class,
@@ -156,6 +167,25 @@ public String getUserData() {
156167
return userData;
157168
}
158169

170+
public Long getUserdataId() {
171+
return userdataId;
172+
}
173+
174+
public Map<String, String> getUserdataDetails() {
175+
Map<String, String> userdataDetailsMap = new HashMap<String, String>();
176+
if (userdataDetails != null && userdataDetails.size() != 0) {
177+
Collection parameterCollection = userdataDetails.values();
178+
Iterator iter = parameterCollection.iterator();
179+
while (iter.hasNext()) {
180+
HashMap<String, String> value = (HashMap<String, String>)iter.next();
181+
for (Map.Entry<String,String> entry: value.entrySet()) {
182+
userdataDetailsMap.put(entry.getKey(),entry.getValue());
183+
}
184+
}
185+
}
186+
return userdataDetailsMap;
187+
}
188+
159189
public Long getAutoscaleUserId() {
160190
return autoscaleUserId;
161191
}

engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmProfileVO.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity, Inter
8888
@Basic(fetch = FetchType.LAZY)
8989
private String userData;
9090

91+
@Column(name = "user_data_id", nullable = true)
92+
private Long userDataId = null;
93+
94+
@Column(name = "user_data_details", updatable = true, length = 4096)
95+
private String userDataDetails;
96+
9197
@Column(name = GenericDao.REMOVED_COLUMN)
9298
protected Date removed;
9399

@@ -228,6 +234,22 @@ public String getUserData() {
228234
return userData;
229235
}
230236

237+
public Long getUserDataId() {
238+
return userDataId;
239+
}
240+
241+
public void setUserDataId(Long userDataId) {
242+
this.userDataId = userDataId;
243+
}
244+
245+
public String getUserDataDetails() {
246+
return userDataDetails;
247+
}
248+
249+
public void setUserDataDetails(String userDataDetails) {
250+
this.userDataDetails = userDataDetails;
251+
}
252+
231253
@Override
232254
public String getUuid() {
233255
return uuid;

engine/schema/src/main/resources/META-INF/db/schema-41800to41810.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VM
3131
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0', 'windows2019srvNext_64Guest');
3232
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0.0.1', 'windows2019srvNext_64Guest');
3333
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'Xenserver', '8.2.0', 'Windows Server 2022 (64-bit)');
34+
35+
-- Support userdata ids and details in VM AutoScaling
36+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.autoscale_vmprofiles', 'user_data_id', 'bigint unsigned DEFAULT NULL COMMENT "id of the user data" AFTER `user_data`');
37+
CALL `cloud`.`IDEMPOTENT_ADD_FOREIGN_KEY`('cloud.autoscale_vmprofiles', 'user_data', 'id');
38+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.autoscale_vmprofiles', 'user_data_details', 'mediumtext DEFAULT NULL COMMENT "value of the comma-separated list of parameters" AFTER `user_data_id`');

server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,6 @@ public AutoScaleVmProfile createAutoScaleVmProfile(CreateAutoScaleVmProfileCmd c
532532
long zoneId = cmd.getZoneId();
533533
long serviceOfferingId = cmd.getServiceOfferingId();
534534
Long autoscaleUserId = cmd.getAutoscaleUserId();
535-
String userData = cmd.getUserData();
536535

537536
DataCenter zone = entityMgr.findById(DataCenter.class, zoneId);
538537

@@ -545,6 +544,11 @@ public AutoScaleVmProfile createAutoScaleVmProfile(CreateAutoScaleVmProfileCmd c
545544
throw new InvalidParameterValueException("Unable to find service offering by id");
546545
}
547546

547+
VirtualMachineTemplate template = entityMgr.findById(VirtualMachineTemplate.class, cmd.getTemplateId());
548+
if (template == null) {
549+
throw new InvalidParameterValueException("Unable to find template by id " + cmd.getTemplateId());
550+
}
551+
548552
// validations
549553
HashMap<String, String> deployParams = cmd.getDeployParamMap();
550554
/*
@@ -562,9 +566,23 @@ public AutoScaleVmProfile createAutoScaleVmProfile(CreateAutoScaleVmProfileCmd c
562566
profileVO.setDisplay(cmd.getDisplay());
563567
}
564568

569+
String userData = cmd.getUserData();
570+
Long userDataId = cmd.getUserDataId();
571+
String userDataDetails = null;
572+
if (MapUtils.isNotEmpty(cmd.getUserDataDetails())) {
573+
userDataDetails = cmd.getUserDataDetails().toString();
574+
}
575+
userData = userVmMgr.finalizeUserData(userData, userDataId, template);
576+
userData = userVmMgr.validateUserData(userData, cmd.getHttpMethod());
565577
if (userData != null) {
566578
profileVO.setUserData(userData);
567579
}
580+
if (userDataId != null) {
581+
profileVO.setUserDataId(userDataId);
582+
}
583+
if (userDataDetails != null) {
584+
profileVO.setUserDataDetails(userDataDetails);
585+
}
568586

569587
profileVO = checkValidityAndPersist(profileVO, true);
570588
s_logger.info("Successfully create AutoScale Vm Profile with Id: " + profileVO.getId());
@@ -582,12 +600,19 @@ public AutoScaleVmProfile updateAutoScaleVmProfile(UpdateAutoScaleVmProfileCmd c
582600
Map<String, HashMap<String, String>> otherDeployParams = cmd.getOtherDeployParams();
583601
Map counterParamList = cmd.getCounterParamList();
584602
String userData = cmd.getUserData();
603+
Long userDataId = cmd.getUserdataId();
604+
String userDataDetails = null;
605+
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
606+
userDataDetails = cmd.getUserdataDetails().toString();
607+
}
608+
boolean userdataUpdate = userData != null || userDataId != null || MapUtils.isNotEmpty(cmd.getUserdataDetails());
585609

586610
Integer expungeVmGracePeriod = cmd.getExpungeVmGracePeriod();
587611

588612
AutoScaleVmProfileVO vmProfile = getEntityInDatabase(CallContext.current().getCallingAccount(), "Auto Scale Vm Profile", profileId, autoScaleVmProfileDao);
589613

590-
boolean physicalParameterUpdate = (templateId != null || autoscaleUserId != null || counterParamList != null || otherDeployParams != null || expungeVmGracePeriod != null || userData != null);
614+
boolean physicalParameterUpdate = (templateId != null || autoscaleUserId != null || counterParamList != null
615+
|| otherDeployParams != null || expungeVmGracePeriod != null || userdataUpdate);
591616

592617
if (serviceOfferingId != null) {
593618
vmProfile.setServiceOfferingId(serviceOfferingId);
@@ -609,10 +634,6 @@ public AutoScaleVmProfile updateAutoScaleVmProfile(UpdateAutoScaleVmProfileCmd c
609634
vmProfile.setCounterParamsForUpdate(counterParamList);
610635
}
611636

612-
if (userData != null) {
613-
vmProfile.setUserData(userData);
614-
}
615-
616637
if (expungeVmGracePeriod != null) {
617638
vmProfile.setExpungeVmGracePeriod(expungeVmGracePeriod);
618639
}
@@ -625,6 +646,18 @@ public AutoScaleVmProfile updateAutoScaleVmProfile(UpdateAutoScaleVmProfileCmd c
625646
vmProfile.setDisplay(cmd.getDisplay());
626647
}
627648

649+
if (userdataUpdate) {
650+
if (templateId == null) {
651+
templateId = vmProfile.getTemplateId();
652+
}
653+
VirtualMachineTemplate template = entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, templateId);
654+
userData = userVmMgr.finalizeUserData(userData, userDataId, template);
655+
userData = userVmMgr.validateUserData(userData, cmd.getHttpMethod());
656+
vmProfile.setUserDataId(userDataId);
657+
vmProfile.setUserData(userData);
658+
vmProfile.setUserDataDetails(userDataDetails);
659+
}
660+
628661
List<AutoScaleVmGroupVO> vmGroupList = autoScaleVmGroupDao.listByAll(null, profileId);
629662
for (AutoScaleVmGroupVO vmGroupVO : vmGroupList) {
630663
if (physicalParameterUpdate && !vmGroupVO.getState().equals(AutoScaleVmGroup.State.DISABLED)) {
@@ -1740,6 +1773,8 @@ protected long createNewVM(AutoScaleVmGroupVO asGroup) {
17401773
}
17411774

17421775
String userData = profileVo.getUserData();
1776+
Long userDataId = profileVo.getUserDataId();
1777+
String userDataDetails = profileVo.getUserDataDetails();
17431778

17441779
UserVm vm = null;
17451780
IpAddresses addrs = new IpAddresses(null, null);
@@ -1763,20 +1798,20 @@ protected long createNewVM(AutoScaleVmGroupVO asGroup) {
17631798
if (zone.getNetworkType() == NetworkType.Basic) {
17641799
vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName,
17651800
vmHostName, diskOfferingId, dataDiskSize, null,
1766-
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs,
1801+
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
17671802
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
17681803
null, true, overrideDiskOfferingId);
17691804
} else {
17701805
if (zone.isSecurityGroupEnabled()) {
17711806
vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null,
17721807
owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null,
1773-
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs,
1808+
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
17741809
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
17751810
null, true, overrideDiskOfferingId, null);
17761811
} else {
17771812
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName,
17781813
diskOfferingId, dataDiskSize, null,
1779-
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs,
1814+
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
17801815
null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null,
17811816
null, true, null, overrideDiskOfferingId);
17821817
}

server/src/main/java/com/cloud/vm/UserVmManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public interface UserVmManager extends UserVmService {
9292

9393
void removeInstanceFromInstanceGroup(long vmId);
9494

95+
String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template);
96+
97+
String validateUserData(String userData, HTTPMethod httpmethod);
98+
9599
boolean isVMUsingLocalStorage(VMInstanceVO vm);
96100

97101
boolean expunge(UserVmVO vm);

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4756,7 +4756,8 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
47564756
}
47574757
}
47584758

4759-
protected String validateUserData(String userData, HTTPMethod httpmethod) {
4759+
@Override
4760+
public String validateUserData(String userData, HTTPMethod httpmethod) {
47604761
byte[] decodedUserData = null;
47614762
if (userData != null) {
47624763

@@ -5690,7 +5691,8 @@ public HypervisorType getHypervisorTypeOfUserVM(long vmId) {
56905691
return userVm.getHypervisorType();
56915692
}
56925693

5693-
protected String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template) {
5694+
@Override
5695+
public String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template) {
56945696
if (StringUtils.isEmpty(userData) && userDataId == null && (template == null || template.getUserDataId() == null)) {
56955697
return null;
56965698
}

server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ public class AutoScaleManagerImplTest {
340340
private static final Long scaleDownCounterId = 38L;
341341
private static final Long nextVmSeq = 39L;
342342
private static final Long networkOfferingId = 40L;
343+
private static final String userData = "VGVzdFVzZXJEYXRh"; //TestUserData
344+
private static final Long userDataId = 41L;
343345

344346
@Mock
345347
DataCenterVO zoneMock;
@@ -748,12 +750,45 @@ public void testCreateAutoScaleVmProfile() {
748750
ReflectionTestUtils.setField(cmd, "otherDeployParams", otherDeployParams);
749751
ReflectionTestUtils.setField(cmd, "counterParamList", counterParamList);
750752

753+
ReflectionTestUtils.setField(cmd, "userData", userData);
754+
751755
AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.createAutoScaleVmProfile(cmd);
752756

753757
Assert.assertEquals(asVmProfileMock, vmProfile);
754758
Mockito.verify(autoScaleVmProfileDao).persist(Mockito.any());
755759
}
756760

761+
@Test(expected = InvalidParameterValueException.class)
762+
@PrepareForTest(ComponentContext.class)
763+
public void testCreateAutoScaleVmProfileFail() {
764+
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock);
765+
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOfferingMock);
766+
when(entityManager.findByIdIncludingRemoved(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOfferingMock);
767+
when(entityManager.findById(VirtualMachineTemplate.class, templateId)).thenReturn(templateMock);
768+
when(serviceOfferingMock.isDynamic()).thenReturn(false);
769+
Mockito.doThrow(InvalidParameterValueException.class).when(userVmMgr).finalizeUserData(any(), any(), any());
770+
771+
DispatchChain dispatchChainMock = Mockito.mock(DispatchChain.class);
772+
when(dispatchChainFactory.getStandardDispatchChain()).thenReturn(dispatchChainMock);
773+
Mockito.doNothing().when(dispatchChainMock).dispatch(any());
774+
PowerMockito.mockStatic(ComponentContext.class);
775+
when(ComponentContext.inject(DeployVMCmd.class)).thenReturn(Mockito.mock(DeployVMCmd.class));
776+
777+
CreateAutoScaleVmProfileCmd cmd = new CreateAutoScaleVmProfileCmd();
778+
779+
ReflectionTestUtils.setField(cmd, "zoneId", zoneId);
780+
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
781+
ReflectionTestUtils.setField(cmd, "templateId", templateId);
782+
ReflectionTestUtils.setField(cmd, "expungeVmGracePeriod", expungeVmGracePeriod);
783+
ReflectionTestUtils.setField(cmd, "otherDeployParams", otherDeployParams);
784+
ReflectionTestUtils.setField(cmd, "counterParamList", counterParamList);
785+
786+
ReflectionTestUtils.setField(cmd, "userData", userData);
787+
ReflectionTestUtils.setField(cmd, "userDataId", userDataId);
788+
789+
AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.createAutoScaleVmProfile(cmd);
790+
}
791+
757792
@Test
758793
public void testUpdateAutoScaleVmProfile() {
759794
when(autoScaleVmProfileDao.findById(vmProfileId)).thenReturn(asVmProfileMock);

ui/public/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,7 @@
16241624
"label.reset.config.value": "Reset to default value",
16251625
"label.reset.ssh.key.pair": "Reset SSH key pair",
16261626
"label.reset.to.default": "Reset to default",
1627+
"label.reset.userdata.on.autoscale.vm.group": "Reset Userdata on AutoScale VM Group",
16271628
"label.reset.userdata.on.vm": "Reset Userdata on VM",
16281629
"label.reset.vpn.connection": "Reset VPN connection",
16291630
"label.resource": "Resource",

0 commit comments

Comments
 (0)