AutoScaling: support Managed User Data (#7769)

This commit is contained in:
Wei Zhou 2023-08-22 11:07:16 +02:00 committed by GitHub
parent 405ef82aef
commit 78bdde9e98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 785 additions and 128 deletions

View File

@ -35,6 +35,10 @@ public interface AutoScaleVmProfile extends ControlledEntity, InternalIdentity,
String getUserData(); String getUserData();
Long getUserDataId();
String getUserDataDetails();
public String getUuid(); public String getUuid();
public Long getZoneId(); public Long getZoneId();

View File

@ -21,8 +21,10 @@ import java.lang.reflect.Field;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -42,6 +44,7 @@ import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.storage.ImageStoreService; import org.apache.cloudstack.storage.ImageStoreService;
import org.apache.cloudstack.usage.UsageService; import org.apache.cloudstack.usage.UsageService;
import org.apache.commons.collections.MapUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.configuration.ConfigurationService; import com.cloud.configuration.ConfigurationService;
@ -456,4 +459,18 @@ public abstract class BaseCmd {
return ApiCommandResourceType.None; return ApiCommandResourceType.None;
} }
public Map<String, String> convertDetailsToMap(Map details) {
Map<String, String> detailsMap = new HashMap<String, String>();
if (MapUtils.isNotEmpty(details)) {
Collection parameterCollection = details.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (Map.Entry<String,String> entry: value.entrySet()) {
detailsMap.put(entry.getKey(),entry.getValue());
}
}
}
return detailsMap;
}
} }

View File

@ -35,6 +35,7 @@ import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.TemplateResponse; import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserDataResponse;
import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
@ -107,6 +108,12 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd {
since = "4.18.0") since = "4.18.0")
private String userData; private String userData;
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18.1")
private Long userDataId;
@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")
private Map userDataDetails;
@Parameter(name = ApiConstants.AUTOSCALE_USER_ID, @Parameter(name = ApiConstants.AUTOSCALE_USER_ID,
type = CommandType.UUID, type = CommandType.UUID,
entityType = UserResponse.class, entityType = UserResponse.class,
@ -163,6 +170,14 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd {
return userData; return userData;
} }
public Long getUserDataId() {
return userDataId;
}
public Map<String, String> getUserDataDetails() {
return convertDetailsToMap(userDataDetails);
}
public Long getAutoscaleUserId() { public Long getAutoscaleUserId() {
return autoscaleUserId; return autoscaleUserId;
} }

View File

@ -35,6 +35,7 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse; import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.TemplateResponse; import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserDataResponse;
import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
@ -102,6 +103,14 @@ public class UpdateAutoScaleVmProfileCmd extends BaseAsyncCustomIdCmd {
since = "4.18.0") since = "4.18.0")
private String userData; private String userData;
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the userdata",
since = "4.18.1")
private Long userDataId;
@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")
private Map userDataDetails;
@Parameter(name = ApiConstants.AUTOSCALE_USER_ID, @Parameter(name = ApiConstants.AUTOSCALE_USER_ID,
type = CommandType.UUID, type = CommandType.UUID,
entityType = UserResponse.class, entityType = UserResponse.class,
@ -156,6 +165,14 @@ public class UpdateAutoScaleVmProfileCmd extends BaseAsyncCustomIdCmd {
return userData; return userData;
} }
public Long getUserDataId() {
return userDataId;
}
public Map<String, String> getUserDataDetails() {
return convertDetailsToMap(userDataDetails);
}
public Long getAutoscaleUserId() { public Long getAutoscaleUserId() {
return autoscaleUserId; return autoscaleUserId;
} }

View File

@ -309,17 +309,8 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
} }
public Map<String, String> getDetails() { public Map<String, String> getDetails() {
Map<String, String> customparameterMap = new HashMap<String, String>(); Map<String, String> customparameterMap = convertDetailsToMap(details);
if (details != null && details.size() != 0) {
Collection parameterCollection = details.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (Map.Entry<String,String> entry: value.entrySet()) {
customparameterMap.put(entry.getKey(),entry.getValue());
}
}
}
if (getBootType() != null) { if (getBootType() != null) {
customparameterMap.put(getBootType().toString(), getBootMode().toString()); customparameterMap.put(getBootType().toString(), getBootMode().toString());
} }
@ -450,18 +441,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
} }
public Map<String, String> getUserdataDetails() { public Map<String, String> getUserdataDetails() {
Map<String, String> userdataDetailsMap = new HashMap<String, String>(); return convertDetailsToMap(userdataDetails);
if (userdataDetails != null && userdataDetails.size() != 0) {
Collection parameterCollection = userdataDetails.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (Map.Entry<String,String> entry: value.entrySet()) {
userdataDetailsMap.put(entry.getKey(),entry.getValue());
}
}
}
return userdataDetailsMap;
} }
public Long getZoneId() { public Long getZoneId() {

View File

@ -39,9 +39,6 @@ import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
@APICommand(name = "resetUserDataForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the UserData for virtual machine. " + @APICommand(name = "resetUserDataForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the UserData for virtual machine. " +
@ -117,18 +114,7 @@ public class ResetVMUserDataCmd extends BaseCmd implements UserCmd {
} }
public Map<String, String> getUserdataDetails() { public Map<String, String> getUserdataDetails() {
Map<String, String> userdataDetailsMap = new HashMap<String, String>(); return convertDetailsToMap(userdataDetails);
if (userdataDetails != null && userdataDetails.size() != 0) {
Collection parameterCollection = userdataDetails.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (Map.Entry<String,String> entry: value.entrySet()) {
userdataDetailsMap.put(entry.getKey(),entry.getValue());
}
}
}
return userdataDetailsMap;
} }
@Override @Override

View File

@ -16,9 +16,6 @@
// under the License. // under the License.
package org.apache.cloudstack.api.command.user.vm; package org.apache.cloudstack.api.command.user.vm;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -99,17 +96,7 @@ public class ScaleVMCmd extends BaseAsyncCmd implements UserCmd {
//it is because details.values() cannot be cast to a map. //it is because details.values() cannot be cast to a map.
//it gives a exception //it gives a exception
public Map<String, String> getDetails() { public Map<String, String> getDetails() {
Map<String, String> customparameterMap = new HashMap<String, String>(); Map<String, String> customparameterMap = convertDetailsToMap(details);
if (details != null && details.size() != 0) {
Collection parameterCollection = details.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (String key : value.keySet()) {
customparameterMap.put(key, value.get(key));
}
}
}
if (shrinkOk != null) customparameterMap.put(ApiConstants.SHRINK_OK, String.valueOf(isShrinkOk())); if (shrinkOk != null) customparameterMap.put(ApiConstants.SHRINK_OK, String.valueOf(isShrinkOk()));
if (autoMigrate != null) customparameterMap.put(ApiConstants.AUTO_MIGRATE, String.valueOf(getAutoMigrate())); if (autoMigrate != null) customparameterMap.put(ApiConstants.AUTO_MIGRATE, String.valueOf(getAutoMigrate()));

View File

@ -18,7 +18,6 @@ package org.apache.cloudstack.api.command.user.vm;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -176,18 +175,7 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction,
} }
public Map<String, String> getUserdataDetails() { public Map<String, String> getUserdataDetails() {
Map<String, String> userdataDetailsMap = new HashMap<String, String>(); return convertDetailsToMap(userdataDetails);
if (userdataDetails != null && userdataDetails.size() != 0) {
Collection parameterCollection = userdataDetails.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (Map.Entry<String,String> entry: value.entrySet()) {
userdataDetailsMap.put(entry.getKey(),entry.getValue());
}
}
}
return userdataDetailsMap;
} }
public Boolean getDisplayVm() { public Boolean getDisplayVm() {

View File

@ -16,9 +16,6 @@
// under the License. // under the License.
package org.apache.cloudstack.api.command.user.vm; package org.apache.cloudstack.api.command.user.vm;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -95,17 +92,7 @@ public class UpgradeVMCmd extends BaseCmd implements UserCmd {
} }
public Map<String, String> getDetails() { public Map<String, String> getDetails() {
Map<String, String> customparameterMap = new HashMap<String, String>(); Map<String, String> customparameterMap = convertDetailsToMap(details);
if (details != null && details.size() != 0) {
Collection parameterCollection = details.values();
Iterator iter = parameterCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> value = (HashMap<String, String>)iter.next();
for (String key : value.keySet()) {
customparameterMap.put(key, value.get(key));
}
}
}
if (shrinkOk != null) customparameterMap.put(ApiConstants.SHRINK_OK, String.valueOf(isShrinkOk())); if (shrinkOk != null) customparameterMap.put(ApiConstants.SHRINK_OK, String.valueOf(isShrinkOk()));
if (autoMigrate != null) customparameterMap.put(ApiConstants.AUTO_MIGRATE, String.valueOf(getAutoMigrate())); if (autoMigrate != null) customparameterMap.put(ApiConstants.AUTO_MIGRATE, String.valueOf(getAutoMigrate()));

View File

@ -72,6 +72,18 @@ public class AutoScaleVmProfileResponse extends BaseResponse implements Controll
@Param(description = "Base 64 encoded VM user data") @Param(description = "Base 64 encoded VM user data")
private String userData; private String userData;
@SerializedName(ApiConstants.USER_DATA_ID) @Param(description="the id of userdata used for the VM", since = "4.18.1")
private String userDataId;
@SerializedName(ApiConstants.USER_DATA_NAME) @Param(description="the name of userdata used for the VM", since = "4.18.1")
private String userDataName;
@SerializedName(ApiConstants.USER_DATA_POLICY) @Param(description="the userdata override policy with the userdata provided while deploying VM", since = "4.18.1")
private String userDataPolicy;
@SerializedName(ApiConstants.USER_DATA_DETAILS) @Param(description="list of variables and values for the variables declared in userdata", since = "4.18.1")
private String userDataDetails;
@SerializedName(ApiConstants.AUTOSCALE_USER_ID) @SerializedName(ApiConstants.AUTOSCALE_USER_ID)
@Param(description = "the ID of the user used to launch and destroy the VMs") @Param(description = "the ID of the user used to launch and destroy the VMs")
private String autoscaleUserId; private String autoscaleUserId;
@ -153,6 +165,22 @@ public class AutoScaleVmProfileResponse extends BaseResponse implements Controll
this.userData = userData; this.userData = userData;
} }
public void setUserDataId(String userDataId) {
this.userDataId = userDataId;
}
public void setUserDataName(String userDataName) {
this.userDataName = userDataName;
}
public void setUserDataPolicy(String userDataPolicy) {
this.userDataPolicy = userDataPolicy;
}
public void setUserDataDetails(String userDataDetails) {
this.userDataDetails = userDataDetails;
}
@Override @Override
public void setAccountName(String accountName) { public void setAccountName(String accountName) {
this.accountName = accountName; this.accountName = accountName;
@ -193,4 +221,24 @@ public class AutoScaleVmProfileResponse extends BaseResponse implements Controll
public void setForDisplay(Boolean forDisplay) { public void setForDisplay(Boolean forDisplay) {
this.forDisplay = forDisplay; this.forDisplay = forDisplay;
} }
public String getUserData() {
return userData;
}
public String getUserDataId() {
return userDataId;
}
public String getUserDataName() {
return userDataName;
}
public String getUserDataPolicy() {
return userDataPolicy;
}
public String getUserDataDetails() {
return userDataDetails;
}
} }

View File

@ -88,6 +88,12 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity, Inter
@Basic(fetch = FetchType.LAZY) @Basic(fetch = FetchType.LAZY)
private String userData; private String userData;
@Column(name = "user_data_id", nullable = true)
private Long userDataId = null;
@Column(name = "user_data_details", updatable = true, length = 4096)
private String userDataDetails;
@Column(name = GenericDao.REMOVED_COLUMN) @Column(name = GenericDao.REMOVED_COLUMN)
protected Date removed; protected Date removed;
@ -228,6 +234,24 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity, Inter
return userData; return userData;
} }
@Override
public Long getUserDataId() {
return userDataId;
}
public void setUserDataId(Long userDataId) {
this.userDataId = userDataId;
}
@Override
public String getUserDataDetails() {
return userDataDetails;
}
public void setUserDataDetails(String userDataDetails) {
this.userDataDetails = userDataDetails;
}
@Override @Override
public String getUuid() { public String getUuid() {
return uuid; return uuid;

View File

@ -63,6 +63,7 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate
fixForeignKeyNames(conn); fixForeignKeyNames(conn);
updateGuestOsMappings(conn); updateGuestOsMappings(conn);
copyGuestOsMappingsToVMware80u1(); copyGuestOsMappingsToVMware80u1();
addForeignKeyToAutoscaleVmprofiles(conn);
} }
@Override @Override
@ -225,4 +226,8 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate
DbUpgradeUtils.dropKeysIfExist(conn, "cloud.volumes", keys, false); DbUpgradeUtils.dropKeysIfExist(conn, "cloud.volumes", keys, false);
DbUpgradeUtils.addForeignKey(conn, "volumes", "passphrase_id","passphrase", "id"); DbUpgradeUtils.addForeignKey(conn, "volumes", "passphrase_id","passphrase", "id");
} }
private void addForeignKeyToAutoscaleVmprofiles(Connection conn) {
DbUpgradeUtils.addForeignKey(conn, "autoscale_vmprofiles", "user_data_id", "user_data", "id");
}
} }

View File

@ -35,6 +35,10 @@ CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VM
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0.0.1', 'windows2019srvNext_64Guest'); CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0.0.1', 'windows2019srvNext_64Guest');
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'Xenserver', '8.2.0', 'Windows Server 2022 (64-bit)'); CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'Xenserver', '8.2.0', 'Windows Server 2022 (64-bit)');
-- Support userdata ids and details in VM AutoScaling
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.autoscale_vmprofiles', 'user_data_id', 'bigint unsigned DEFAULT NULL COMMENT "id of the user data" AFTER `user_data`');
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`');
-- Don't enable CPU cap for default system offerings, fixes regression from https://github.com/apache/cloudstack/pull/6420 -- Don't enable CPU cap for default system offerings, fixes regression from https://github.com/apache/cloudstack/pull/6420
UPDATE `cloud`.`service_offering` so UPDATE `cloud`.`service_offering` so
SET so.limit_cpu_use = 0 SET so.limit_cpu_use = 0

View File

@ -26,6 +26,18 @@ import org.junit.Test;
public class AutoScaleVmProfileVOTest { public class AutoScaleVmProfileVOTest {
static long zoneId = 1L;
static long domainId = 2L;
static long accountId = 3L;
static long serviceOfferingId = 4L;
static long templateId = 5L;
static String userdata = "userdata";
static long userdataId = 6L;
static String userdataDetails = "userdataDetails";
static String userdataNew = "userdataNew";
static long autoScaleUserId = 7L;
@Test @Test
public void testCounterParamsForUpdate() { public void testCounterParamsForUpdate() {
AutoScaleVmProfileVO profile = new AutoScaleVmProfileVO(); AutoScaleVmProfileVO profile = new AutoScaleVmProfileVO();
@ -62,4 +74,23 @@ public class AutoScaleVmProfileVOTest {
Assert.assertEquals("rootdisksize", otherDeployParamsList.get(1).first()); Assert.assertEquals("rootdisksize", otherDeployParamsList.get(1).first());
Assert.assertEquals("10", otherDeployParamsList.get(1).second()); Assert.assertEquals("10", otherDeployParamsList.get(1).second());
} }
@Test
public void testProperties() {
AutoScaleVmProfileVO profile = new AutoScaleVmProfileVO(zoneId, domainId, accountId, serviceOfferingId, templateId, null, null, userdata, null, autoScaleUserId);
Assert.assertEquals(new Long(zoneId), profile.getZoneId());
Assert.assertEquals(domainId, profile.getDomainId());
Assert.assertEquals(accountId, profile.getAccountId());
Assert.assertEquals(new Long(serviceOfferingId), profile.getServiceOfferingId());
Assert.assertEquals(new Long(templateId), profile.getTemplateId());
Assert.assertEquals(userdata, profile.getUserData());
Assert.assertEquals(new Long(autoScaleUserId), profile.getAutoScaleUserId());
profile.setUserData(userdataNew);
profile.setUserDataId(userdataId);
profile.setUserDataDetails(userdataDetails);
Assert.assertEquals(userdataNew, profile.getUserData());
Assert.assertEquals(new Long(userdataId), profile.getUserDataId());
Assert.assertEquals(userdataDetails, profile.getUserDataDetails());
}
} }

View File

@ -21,6 +21,7 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd;
@ -101,6 +102,11 @@ public class ApiAsyncJobDispatcher extends AdapterBase implements AsyncJobDispat
ctx.putContextParameters((Map<Object, Object>) gson.fromJson(contextDetails, objectMapType)); ctx.putContextParameters((Map<Object, Object>) gson.fromJson(contextDetails, objectMapType));
} }
String httpmethod = params.get(ApiConstants.HTTPMETHOD);
if (httpmethod != null) {
cmdObj.setHttpMethod(httpmethod);
}
try { try {
// dispatch could ultimately queue the job // dispatch could ultimately queue the job
_dispatcher.dispatch(cmdObj, params, true); _dispatcher.dispatch(cmdObj, params, true);

View File

@ -365,6 +365,7 @@ import com.cloud.user.User;
import com.cloud.user.UserAccount; import com.cloud.user.UserAccount;
import com.cloud.user.UserData; import com.cloud.user.UserData;
import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserStatisticsVO;
import com.cloud.user.dao.UserDataDao;
import com.cloud.user.dao.UserStatisticsDao; import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
@ -455,6 +456,8 @@ public class ApiResponseHelper implements ResponseGenerator {
UserVmJoinDao userVmJoinDao; UserVmJoinDao userVmJoinDao;
@Inject @Inject
NetworkServiceMapDao ntwkSrvcDao; NetworkServiceMapDao ntwkSrvcDao;
@Inject
UserDataDao userDataDao;
@Override @Override
public UserResponse createUserResponse(User user) { public UserResponse createUserResponse(User user) {
@ -3393,9 +3396,20 @@ public class ApiResponseHelper implements ResponseGenerator {
VMTemplateVO template = ApiDBUtils.findTemplateById(profile.getTemplateId()); VMTemplateVO template = ApiDBUtils.findTemplateById(profile.getTemplateId());
if (template != null) { if (template != null) {
response.setTemplateId(template.getUuid()); response.setTemplateId(template.getUuid());
if (template.getUserDataOverridePolicy() != null) {
response.setUserDataPolicy(template.getUserDataOverridePolicy().toString());
}
} }
} }
response.setUserData(profile.getUserData()); response.setUserData(profile.getUserData());
if (profile.getUserDataId() != null) {
UserData userData = userDataDao.findById(profile.getUserDataId());
if (userData != null) {
response.setUserDataId(userData.getUuid());
response.setUserDataName(userData.getName());
}
}
response.setUserDataDetails(profile.getUserDataDetails());
response.setOtherDeployParams(profile.getOtherDeployParamsList()); response.setOtherDeployParams(profile.getOtherDeployParamsList());
response.setCounterParams(profile.getCounterParams()); response.setCounterParams(profile.getCounterParams());
response.setExpungeVmGracePeriod(profile.getExpungeVmGracePeriod()); response.setExpungeVmGracePeriod(profile.getExpungeVmGracePeriod());

View File

@ -740,6 +740,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
params.put("ctxStartEventId", String.valueOf(startEventId)); params.put("ctxStartEventId", String.valueOf(startEventId));
params.put("cmdEventType", asyncCmd.getEventType().toString()); params.put("cmdEventType", asyncCmd.getEventType().toString());
params.put("ctxDetails", ApiGsonHelper.getBuilder().create().toJson(ctx.getContextParameters())); params.put("ctxDetails", ApiGsonHelper.getBuilder().create().toJson(ctx.getContextParameters()));
if (asyncCmd.getHttpMethod() != null) {
params.put(ApiConstants.HTTPMETHOD, asyncCmd.getHttpMethod().toString());
}
Long instanceId = (objectId == null) ? asyncCmd.getApiResourceId() : objectId; Long instanceId = (objectId == null) ? asyncCmd.getApiResourceId() : objectId;

View File

@ -532,7 +532,6 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
long zoneId = cmd.getZoneId(); long zoneId = cmd.getZoneId();
long serviceOfferingId = cmd.getServiceOfferingId(); long serviceOfferingId = cmd.getServiceOfferingId();
Long autoscaleUserId = cmd.getAutoscaleUserId(); Long autoscaleUserId = cmd.getAutoscaleUserId();
String userData = cmd.getUserData();
DataCenter zone = entityMgr.findById(DataCenter.class, zoneId); DataCenter zone = entityMgr.findById(DataCenter.class, zoneId);
@ -545,6 +544,11 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
throw new InvalidParameterValueException("Unable to find service offering by id"); throw new InvalidParameterValueException("Unable to find service offering by id");
} }
VirtualMachineTemplate template = entityMgr.findById(VirtualMachineTemplate.class, cmd.getTemplateId());
if (template == null) {
throw new InvalidParameterValueException("Unable to find template by id " + cmd.getTemplateId());
}
// validations // validations
HashMap<String, String> deployParams = cmd.getDeployParamMap(); HashMap<String, String> deployParams = cmd.getDeployParamMap();
/* /*
@ -562,9 +566,23 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
profileVO.setDisplay(cmd.getDisplay()); profileVO.setDisplay(cmd.getDisplay());
} }
String userData = cmd.getUserData();
Long userDataId = cmd.getUserDataId();
String userDataDetails = null;
if (MapUtils.isNotEmpty(cmd.getUserDataDetails())) {
userDataDetails = cmd.getUserDataDetails().toString();
}
userData = userVmMgr.finalizeUserData(userData, userDataId, template);
userData = userVmMgr.validateUserData(userData, cmd.getHttpMethod());
if (userData != null) { if (userData != null) {
profileVO.setUserData(userData); profileVO.setUserData(userData);
} }
if (userDataId != null) {
profileVO.setUserDataId(userDataId);
}
if (userDataDetails != null) {
profileVO.setUserDataDetails(userDataDetails);
}
profileVO = checkValidityAndPersist(profileVO, true); profileVO = checkValidityAndPersist(profileVO, true);
s_logger.info("Successfully create AutoScale Vm Profile with Id: " + profileVO.getId()); s_logger.info("Successfully create AutoScale Vm Profile with Id: " + profileVO.getId());
@ -582,12 +600,19 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
Map<String, HashMap<String, String>> otherDeployParams = cmd.getOtherDeployParams(); Map<String, HashMap<String, String>> otherDeployParams = cmd.getOtherDeployParams();
Map counterParamList = cmd.getCounterParamList(); Map counterParamList = cmd.getCounterParamList();
String userData = cmd.getUserData(); String userData = cmd.getUserData();
Long userDataId = cmd.getUserDataId();
String userDataDetails = null;
if (MapUtils.isNotEmpty(cmd.getUserDataDetails())) {
userDataDetails = cmd.getUserDataDetails().toString();
}
boolean userdataUpdate = userData != null || userDataId != null || MapUtils.isNotEmpty(cmd.getUserDataDetails());
Integer expungeVmGracePeriod = cmd.getExpungeVmGracePeriod(); Integer expungeVmGracePeriod = cmd.getExpungeVmGracePeriod();
AutoScaleVmProfileVO vmProfile = getEntityInDatabase(CallContext.current().getCallingAccount(), "Auto Scale Vm Profile", profileId, autoScaleVmProfileDao); AutoScaleVmProfileVO vmProfile = getEntityInDatabase(CallContext.current().getCallingAccount(), "Auto Scale Vm Profile", profileId, autoScaleVmProfileDao);
boolean physicalParameterUpdate = (templateId != null || autoscaleUserId != null || counterParamList != null || otherDeployParams != null || expungeVmGracePeriod != null || userData != null); boolean physicalParameterUpdate = (templateId != null || autoscaleUserId != null || counterParamList != null
|| otherDeployParams != null || expungeVmGracePeriod != null || userdataUpdate);
if (serviceOfferingId != null) { if (serviceOfferingId != null) {
vmProfile.setServiceOfferingId(serviceOfferingId); vmProfile.setServiceOfferingId(serviceOfferingId);
@ -609,10 +634,6 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
vmProfile.setCounterParamsForUpdate(counterParamList); vmProfile.setCounterParamsForUpdate(counterParamList);
} }
if (userData != null) {
vmProfile.setUserData(userData);
}
if (expungeVmGracePeriod != null) { if (expungeVmGracePeriod != null) {
vmProfile.setExpungeVmGracePeriod(expungeVmGracePeriod); vmProfile.setExpungeVmGracePeriod(expungeVmGracePeriod);
} }
@ -625,6 +646,18 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
vmProfile.setDisplay(cmd.getDisplay()); vmProfile.setDisplay(cmd.getDisplay());
} }
if (userdataUpdate) {
if (templateId == null) {
templateId = vmProfile.getTemplateId();
}
VirtualMachineTemplate template = entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, templateId);
userData = userVmMgr.finalizeUserData(userData, userDataId, template);
userData = userVmMgr.validateUserData(userData, cmd.getHttpMethod());
vmProfile.setUserDataId(userDataId);
vmProfile.setUserData(userData);
vmProfile.setUserDataDetails(userDataDetails);
}
List<AutoScaleVmGroupVO> vmGroupList = autoScaleVmGroupDao.listByAll(null, profileId); List<AutoScaleVmGroupVO> vmGroupList = autoScaleVmGroupDao.listByAll(null, profileId);
for (AutoScaleVmGroupVO vmGroupVO : vmGroupList) { for (AutoScaleVmGroupVO vmGroupVO : vmGroupList) {
if (physicalParameterUpdate && !vmGroupVO.getState().equals(AutoScaleVmGroup.State.DISABLED)) { if (physicalParameterUpdate && !vmGroupVO.getState().equals(AutoScaleVmGroup.State.DISABLED)) {
@ -1740,6 +1773,8 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
} }
String userData = profileVo.getUserData(); String userData = profileVo.getUserData();
Long userDataId = profileVo.getUserDataId();
String userDataDetails = profileVo.getUserDataDetails();
UserVm vm = null; UserVm vm = null;
IpAddresses addrs = new IpAddresses(null, null); IpAddresses addrs = new IpAddresses(null, null);
@ -1763,20 +1798,20 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
if (zone.getNetworkType() == NetworkType.Basic) { if (zone.getNetworkType() == NetworkType.Basic) {
vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName, vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName,
vmHostName, diskOfferingId, dataDiskSize, null, vmHostName, diskOfferingId, dataDiskSize, null,
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs, hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, null, true, null, affinityGroupIdList, customParameters, null, null, null, null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
null, true, overrideDiskOfferingId); null, true, overrideDiskOfferingId);
} else { } else {
if (zone.isSecurityGroupEnabled()) { if (zone.isSecurityGroupEnabled()) {
vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null, vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null,
owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null, owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null,
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs, hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, null, true, null, affinityGroupIdList, customParameters, null, null, null, null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
null, true, overrideDiskOfferingId, null); null, true, overrideDiskOfferingId, null);
} else { } else {
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName, vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName,
diskOfferingId, dataDiskSize, null, diskOfferingId, dataDiskSize, null,
hypervisorType, HTTPMethod.GET, userData, null, null, sshKeyPairs, hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null, null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null,
null, true, null, overrideDiskOfferingId); null, true, null, overrideDiskOfferingId);
} }

View File

@ -92,6 +92,10 @@ public interface UserVmManager extends UserVmService {
void removeInstanceFromInstanceGroup(long vmId); void removeInstanceFromInstanceGroup(long vmId);
String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template);
String validateUserData(String userData, HTTPMethod httpmethod);
boolean isVMUsingLocalStorage(VMInstanceVO vm); boolean isVMUsingLocalStorage(VMInstanceVO vm);
boolean expunge(UserVmVO vm); boolean expunge(UserVmVO vm);

View File

@ -4769,7 +4769,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
protected String validateUserData(String userData, HTTPMethod httpmethod) { @Override
public String validateUserData(String userData, HTTPMethod httpmethod) {
byte[] decodedUserData = null; byte[] decodedUserData = null;
if (userData != null) { if (userData != null) {
@ -5703,7 +5704,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return userVm.getHypervisorType(); return userVm.getHypervisorType();
} }
protected String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template) { @Override
public String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template) {
if (StringUtils.isEmpty(userData) && userDataId == null && (template == null || template.getUserDataId() == null)) { if (StringUtils.isEmpty(userData) && userDataId == null && (template == null || template.getUserDataId() == null)) {
return null; return null;
} }

View File

@ -32,6 +32,7 @@ import java.util.UUID;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse; import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.UsageRecordResponse; import org.apache.cloudstack.api.response.UsageRecordResponse;
@ -52,17 +53,22 @@ import org.powermock.modules.junit4.PowerMockRunner;
import com.cloud.domain.DomainVO; import com.cloud.domain.DomainVO;
import com.cloud.network.as.AutoScaleVmGroup; import com.cloud.network.as.AutoScaleVmGroup;
import com.cloud.network.as.AutoScaleVmGroupVO; import com.cloud.network.as.AutoScaleVmGroupVO;
import com.cloud.network.as.AutoScaleVmProfileVO;
import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao; import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao;
import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.LoadBalancerVO;
import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NetworkVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.usage.UsageVO; import com.cloud.usage.UsageVO;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.UserData;
import com.cloud.user.UserDataVO;
import com.cloud.user.UserVO; import com.cloud.user.UserVO;
import com.cloud.user.dao.UserDataDao;
import com.cloud.utils.net.Ip; import com.cloud.utils.net.Ip;
import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicSecondaryIp;
@ -86,12 +92,27 @@ public class ApiResponseHelperTest {
@Mock @Mock
AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDaoMock; AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDaoMock;
@Mock
UserDataDao userDataDaoMock;
@Spy @Spy
@InjectMocks @InjectMocks
ApiResponseHelper apiResponseHelper = new ApiResponseHelper(); ApiResponseHelper apiResponseHelper = new ApiResponseHelper();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss ZZZ"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss ZZZ");
static long zoneId = 1L;
static long domainId = 2L;
static long accountId = 3L;
static long serviceOfferingId = 4L;
static long templateId = 5L;
static String userdata = "userdata";
static long userdataId = 6L;
static String userdataDetails = "userdataDetails";
static String userdataNew = "userdataNew";
static long autoScaleUserId = 7L;
@Before @Before
public void injectMocks() throws SecurityException, NoSuchFieldException, public void injectMocks() throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException { IllegalArgumentException, IllegalAccessException {
@ -297,4 +318,55 @@ public class ApiResponseHelperTest {
assertEquals("8080", response.getPublicPort()); assertEquals("8080", response.getPublicPort());
assertEquals("8081", response.getPrivatePort()); assertEquals("8081", response.getPrivatePort());
} }
@Test
@PrepareForTest(ApiDBUtils.class)
public void testAutoScaleVmProfileResponse() {
AutoScaleVmProfileVO vmProfile = new AutoScaleVmProfileVO(zoneId, domainId, accountId, serviceOfferingId, templateId, null, null, userdata, null, autoScaleUserId);
vmProfile.setUserDataId(userdataId);
vmProfile.setUserDataDetails(userdataDetails);
PowerMockito.mockStatic(ApiDBUtils.class);
when(ApiDBUtils.findAccountById(anyLong())).thenReturn(new AccountVO());
when(ApiDBUtils.findDomainById(anyLong())).thenReturn(new DomainVO());
UserData.UserDataOverridePolicy templatePolicy = UserData.UserDataOverridePolicy.APPEND;
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
when(ApiDBUtils.findTemplateById(anyLong())).thenReturn(templateVO);
when(templateVO.getUserDataOverridePolicy()).thenReturn(templatePolicy);
UserDataVO userDataVO = Mockito.mock(UserDataVO.class);
String userDataUuid = "userDataUuid";
String userDataName = "userDataName";
when(userDataDaoMock.findById(anyLong())).thenReturn(userDataVO);
when(userDataVO.getUuid()).thenReturn(userDataUuid);
when(userDataVO.getName()).thenReturn(userDataName);
AutoScaleVmProfileResponse response = apiResponseHelper.createAutoScaleVmProfileResponse(vmProfile);
assertEquals(templatePolicy.toString(), response.getUserDataPolicy());
assertEquals(userdata, response.getUserData());
assertEquals(userDataUuid, response.getUserDataId());
assertEquals(userDataName, response.getUserDataName());
assertEquals(userdataDetails, response.getUserDataDetails());
}
@Test
@PrepareForTest(ApiDBUtils.class)
public void testAutoScaleVmProfileResponseWithoutUserData() {
AutoScaleVmProfileVO vmProfile = new AutoScaleVmProfileVO(zoneId, domainId, accountId, serviceOfferingId, templateId, null, null, null, null, autoScaleUserId);
PowerMockito.mockStatic(ApiDBUtils.class);
when(ApiDBUtils.findAccountById(anyLong())).thenReturn(new AccountVO());
when(ApiDBUtils.findDomainById(anyLong())).thenReturn(new DomainVO());
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
when(ApiDBUtils.findTemplateById(anyLong())).thenReturn(templateVO);
AutoScaleVmProfileResponse response = apiResponseHelper.createAutoScaleVmProfileResponse(vmProfile);
assertNull(response.getUserDataPolicy());
assertNull(response.getUserData());
assertNull(response.getUserDataId());
assertNull(response.getUserDataName());
assertNull(response.getUserDataDetails());
}
} }

View File

@ -47,6 +47,7 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd;
import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScalePolicyCmd; import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScalePolicyCmd;
import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmGroupCmd; import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmGroupCmd;
@ -340,6 +341,10 @@ public class AutoScaleManagerImplTest {
private static final Long scaleDownCounterId = 38L; private static final Long scaleDownCounterId = 38L;
private static final Long nextVmSeq = 39L; private static final Long nextVmSeq = 39L;
private static final Long networkOfferingId = 40L; private static final Long networkOfferingId = 40L;
private static final String userData = "VGVzdFVzZXJEYXRh"; //TestUserData
private static final Long userDataId = 41L;
private static final Map<String, HashMap<String, String>> userDataDetails = new HashMap<>();
private static final String userDataFinal = "VGVzdFVzZXJEYXRhRmluYWw="; //TestUserDataFinal
@Mock @Mock
DataCenterVO zoneMock; DataCenterVO zoneMock;
@ -404,6 +409,10 @@ public class AutoScaleManagerImplTest {
Mockito.doNothing().when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.isNull(), Mockito.anyBoolean(), Mockito.any()); Mockito.doNothing().when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.isNull(), Mockito.anyBoolean(), Mockito.any());
when(asPolicyDao.persist(any(AutoScalePolicyVO.class))).thenReturn(asScaleUpPolicyMock); when(asPolicyDao.persist(any(AutoScalePolicyVO.class))).thenReturn(asScaleUpPolicyMock);
userDataDetails.put("0", new HashMap<>() {{ put("key1", "value1"); put("key2", "value2"); }});
Mockito.doReturn(userDataFinal).when(userVmMgr).finalizeUserData(any(), any(), any());
Mockito.doReturn(userDataFinal).when(userVmMgr).validateUserData(eq(userDataFinal), nullable(BaseCmd.HTTPMethod.class));
} }
@After @After
@ -748,10 +757,48 @@ public class AutoScaleManagerImplTest {
ReflectionTestUtils.setField(cmd, "otherDeployParams", otherDeployParams); ReflectionTestUtils.setField(cmd, "otherDeployParams", otherDeployParams);
ReflectionTestUtils.setField(cmd, "counterParamList", counterParamList); ReflectionTestUtils.setField(cmd, "counterParamList", counterParamList);
ReflectionTestUtils.setField(cmd, "userData", userData);
ReflectionTestUtils.setField(cmd, "userDataId", userDataId);
ReflectionTestUtils.setField(cmd, "userDataDetails", userDataDetails);
AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.createAutoScaleVmProfile(cmd); AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.createAutoScaleVmProfile(cmd);
Assert.assertEquals(asVmProfileMock, vmProfile); Assert.assertEquals(asVmProfileMock, vmProfile);
Mockito.verify(autoScaleVmProfileDao).persist(Mockito.any()); Mockito.verify(autoScaleVmProfileDao).persist(Mockito.any());
Mockito.verify(userVmMgr).finalizeUserData(any(), any(), any());
Mockito.verify(userVmMgr).validateUserData(eq(userDataFinal), nullable(BaseCmd.HTTPMethod.class));
}
@Test(expected = InvalidParameterValueException.class)
@PrepareForTest(ComponentContext.class)
public void testCreateAutoScaleVmProfileFail() {
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock);
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOfferingMock);
when(entityManager.findByIdIncludingRemoved(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOfferingMock);
when(entityManager.findById(VirtualMachineTemplate.class, templateId)).thenReturn(templateMock);
when(serviceOfferingMock.isDynamic()).thenReturn(false);
Mockito.doThrow(InvalidParameterValueException.class).when(userVmMgr).finalizeUserData(any(), any(), any());
DispatchChain dispatchChainMock = Mockito.mock(DispatchChain.class);
when(dispatchChainFactory.getStandardDispatchChain()).thenReturn(dispatchChainMock);
Mockito.doNothing().when(dispatchChainMock).dispatch(any());
PowerMockito.mockStatic(ComponentContext.class);
when(ComponentContext.inject(DeployVMCmd.class)).thenReturn(Mockito.mock(DeployVMCmd.class));
CreateAutoScaleVmProfileCmd cmd = new CreateAutoScaleVmProfileCmd();
ReflectionTestUtils.setField(cmd, "zoneId", zoneId);
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
ReflectionTestUtils.setField(cmd, "templateId", templateId);
ReflectionTestUtils.setField(cmd, "expungeVmGracePeriod", expungeVmGracePeriod);
ReflectionTestUtils.setField(cmd, "otherDeployParams", otherDeployParams);
ReflectionTestUtils.setField(cmd, "counterParamList", counterParamList);
ReflectionTestUtils.setField(cmd, "userData", userData);
ReflectionTestUtils.setField(cmd, "userDataId", userDataId);
AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.createAutoScaleVmProfile(cmd);
} }
@Test @Test
@ -774,10 +821,17 @@ public class AutoScaleManagerImplTest {
ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId); ReflectionTestUtils.setField(cmd, "serviceOfferingId", serviceOfferingId);
ReflectionTestUtils.setField(cmd, "templateId", templateId); ReflectionTestUtils.setField(cmd, "templateId", templateId);
ReflectionTestUtils.setField(cmd, "userData", userData);
ReflectionTestUtils.setField(cmd, "userDataId", userDataId);
ReflectionTestUtils.setField(cmd, "userDataDetails", userDataDetails);
AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.updateAutoScaleVmProfile(cmd); AutoScaleVmProfile vmProfile = autoScaleManagerImplSpy.updateAutoScaleVmProfile(cmd);
Assert.assertEquals(asVmProfileMock, vmProfile); Assert.assertEquals(asVmProfileMock, vmProfile);
Mockito.verify(autoScaleVmProfileDao).persist(Mockito.any()); Mockito.verify(autoScaleVmProfileDao).persist(Mockito.any());
Mockito.verify(userVmMgr).finalizeUserData(any(), any(), any());
Mockito.verify(userVmMgr).validateUserData(eq(userDataFinal), nullable(BaseCmd.HTTPMethod.class));
} }
@Test @Test
@ -1208,6 +1262,9 @@ public class AutoScaleManagerImplTest {
when(asVmProfileMock.getAccountId()).thenReturn(accountId); when(asVmProfileMock.getAccountId()).thenReturn(accountId);
when(asVmProfileMock.getZoneId()).thenReturn(zoneId); when(asVmProfileMock.getZoneId()).thenReturn(zoneId);
when(asVmProfileMock.getOtherDeployParams()).thenReturn(""); when(asVmProfileMock.getOtherDeployParams()).thenReturn("");
when(asVmProfileMock.getUserData()).thenReturn(userData);
when(asVmProfileMock.getUserDataId()).thenReturn(userDataId);
when(asVmProfileMock.getUserDataDetails()).thenReturn(userDataDetails.toString());
when(accountService.getActiveAccountById(accountId)).thenReturn(account); when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock); when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock);
@ -1224,7 +1281,7 @@ public class AutoScaleManagerImplTest {
when(userVmMock.getId()).thenReturn(virtualMachineId); when(userVmMock.getId()).thenReturn(virtualMachineId);
when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic); when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
when(userVmService.createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(), when(userVmService.createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), eq(true), any(), any(), any(),
any(), any(), any(), any(), eq(true), any())).thenReturn(userVmMock); any(), any(), any(), any(), eq(true), any())).thenReturn(userVmMock);
long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock); long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock);
@ -1235,7 +1292,7 @@ public class AutoScaleManagerImplTest {
"-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}"; "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
Mockito.verify(userVmService).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), Mockito.verify(userVmService).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(),
matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), eq(true), any(), any(), any(),
any(), any(), any(), any(), eq(true), any()); any(), any(), any(), any(), eq(true), any());
Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 1); Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 1);
} }
@ -1253,6 +1310,9 @@ public class AutoScaleManagerImplTest {
when(asVmProfileMock.getAccountId()).thenReturn(accountId); when(asVmProfileMock.getAccountId()).thenReturn(accountId);
when(asVmProfileMock.getZoneId()).thenReturn(zoneId); when(asVmProfileMock.getZoneId()).thenReturn(zoneId);
when(asVmProfileMock.getOtherDeployParams()).thenReturn(""); when(asVmProfileMock.getOtherDeployParams()).thenReturn("");
when(asVmProfileMock.getUserData()).thenReturn(userData);
when(asVmProfileMock.getUserDataId()).thenReturn(userDataId);
when(asVmProfileMock.getUserDataDetails()).thenReturn(userDataDetails.toString());
when(accountService.getActiveAccountById(accountId)).thenReturn(account); when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock); when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock);
@ -1270,7 +1330,7 @@ public class AutoScaleManagerImplTest {
when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced); when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
when(zoneMock.isSecurityGroupEnabled()).thenReturn(true); when(zoneMock.isSecurityGroupEnabled()).thenReturn(true);
when(userVmService.createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(), when(userVmService.createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), eq(true), any(), any())).thenReturn(userVmMock); any(), any(), any(), any(), any(), eq(true), any(), any())).thenReturn(userVmMock);
long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock); long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock);
@ -1281,7 +1341,7 @@ public class AutoScaleManagerImplTest {
"-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}"; "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
Mockito.verify(userVmService).createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), Mockito.verify(userVmService).createAdvancedSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(),
matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), eq(true), any(), any()); any(), any(), any(), any(), any(), eq(true), any(), any());
Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 2); Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 2);
} }
@ -1299,6 +1359,9 @@ public class AutoScaleManagerImplTest {
when(asVmProfileMock.getAccountId()).thenReturn(accountId); when(asVmProfileMock.getAccountId()).thenReturn(accountId);
when(asVmProfileMock.getZoneId()).thenReturn(zoneId); when(asVmProfileMock.getZoneId()).thenReturn(zoneId);
when(asVmProfileMock.getOtherDeployParams()).thenReturn(""); when(asVmProfileMock.getOtherDeployParams()).thenReturn("");
when(asVmProfileMock.getUserData()).thenReturn(userData);
when(asVmProfileMock.getUserDataId()).thenReturn(userDataId);
when(asVmProfileMock.getUserDataDetails()).thenReturn(userDataDetails.toString());
when(accountService.getActiveAccountById(accountId)).thenReturn(account); when(accountService.getActiveAccountById(accountId)).thenReturn(account);
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock); when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(zoneMock);
@ -1316,7 +1379,7 @@ public class AutoScaleManagerImplTest {
when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced); when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
when(zoneMock.isSecurityGroupEnabled()).thenReturn(false); when(zoneMock.isSecurityGroupEnabled()).thenReturn(false);
when(userVmService.createAdvancedVirtualMachine(any(), any(), any(), any(), any(), any(), any(), when(userVmService.createAdvancedVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), eq(true), any(), any(), any(),
any(), any(), any(), any(), eq(true), any(), any())).thenReturn(userVmMock); any(), any(), any(), any(), eq(true), any(), any())).thenReturn(userVmMock);
long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock); long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock);
@ -1327,7 +1390,7 @@ public class AutoScaleManagerImplTest {
"-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}"; "-" + asVmGroupMock.getNextVmSeq() + "-[a-z]{6}";
Mockito.verify(userVmService).createAdvancedVirtualMachine(any(), any(), any(), any(), any(), Mockito.verify(userVmService).createAdvancedVirtualMachine(any(), any(), any(), any(), any(),
matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern), matches(vmHostNamePattern),
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any(), any(), any(), any(), any(), any(), eq(userData), eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), eq(true), any(), any(), any(),
any(), any(), any(), any(), eq(true), any(), any()); any(), any(), any(), any(), eq(true), any(), any());
Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 3); Mockito.verify(asVmGroupMock).setNextVmSeq(nextVmSeq + 3);
} }

View File

@ -38,6 +38,7 @@ from marvin.lib.base import (Account,
Domain, Domain,
Project, Project,
ServiceOffering, ServiceOffering,
Template,
VirtualMachine, VirtualMachine,
Volume, Volume,
Zone, Zone,
@ -47,6 +48,7 @@ from marvin.lib.base import (Account,
LoadBalancerRule, LoadBalancerRule,
VPC, VPC,
VpcOffering, VpcOffering,
UserData,
SSHKeyPair) SSHKeyPair)
from marvin.lib.common import (get_domain, from marvin.lib.common import (get_domain,
@ -198,6 +200,37 @@ class TestVmAutoScaling(cloudstackTestCase):
name="keypair2" name="keypair2"
) )
# 8-2. Register userdata
cls.apiUserdata = UserData.register(
cls.apiclient,
name="ApiUserdata",
userdata="QVBJdXNlcmRhdGE=", #APIuserdata
account=cls.regular_user.name,
domainid=cls.regular_user.domainid
)
# 8-3. Register userdata for template
cls.templateUserdata = UserData.register(
cls.apiclient,
name="TemplateUserdata",
userdata="IyMgdGVtcGxhdGU6IGppbmphCiNjbG91ZC1jb25maWcKcnVuY21kOgogICAgLSBlY2hvICdrZXkge3sgZHMubWV0YV9kYXRhLmtleTEgfX0nID4+IC9yb290L2luc3RhbmNlX21ldGFkYXRhCgo=",
# ## template: jinja
# #cloud-config
# runcmd:
# - echo 'key {{ ds.meta_data.key1 }}' >> /root/instance_metadata
#
account=cls.regular_user.name,
domainid=cls.regular_user.domainid
)
# 8-3. Link userdata to template
cls.template = Template.linkUserDataToTemplate(
cls.apiclient,
templateid=cls.template.id,
userdataid=cls.templateUserdata.userdata.id,
userdatapolicy="append"
)
# 9. Get counters for cpu and memory # 9. Get counters for cpu and memory
counters = Autoscale.listCounters( counters = Autoscale.listCounters(
cls.regular_user_apiclient, cls.regular_user_apiclient,
@ -294,6 +327,7 @@ class TestVmAutoScaling(cloudstackTestCase):
serviceofferingid=cls.service_offering.id, serviceofferingid=cls.service_offering.id,
zoneid=cls.zone.id, zoneid=cls.zone.id,
templateid=cls.template.id, templateid=cls.template.id,
userdata="VGVzdFVzZXJEYXRh", #TestUserData
expungevmgraceperiod=DEFAULT_EXPUNGE_VM_GRACE_PERIOD, expungevmgraceperiod=DEFAULT_EXPUNGE_VM_GRACE_PERIOD,
otherdeployparams=cls.otherdeployparams otherdeployparams=cls.otherdeployparams
) )
@ -349,6 +383,10 @@ class TestVmAutoScaling(cloudstackTestCase):
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
cls.template = Template.linkUserDataToTemplate(
cls.apiclient,
templateid=cls.template.id
)
Configurations.update(cls.apiclient, Configurations.update(cls.apiclient,
CONFIG_NAME_DISK_CONTROLLER, CONFIG_NAME_DISK_CONTROLLER,
cls.initial_vmware_root_disk_controller) cls.initial_vmware_root_disk_controller)
@ -390,6 +428,7 @@ class TestVmAutoScaling(cloudstackTestCase):
self.regular_user_apiclient, self.regular_user_apiclient,
autoscalevmgroupid=autoscalevmgroupid, autoscalevmgroupid=autoscalevmgroupid,
projectid=projectid, projectid=projectid,
userdata=True,
listall=True listall=True
) )
self.assertEqual( self.assertEqual(
@ -505,6 +544,31 @@ class TestVmAutoScaling(cloudstackTestCase):
else: else:
self.assertEquals(affinitygroupids, '') self.assertEquals(affinitygroupids, '')
userdata = None
userdatadetails = None
userdataid = None
if vm.userdata:
userdata = vm.userdata
if vm.userdatadetails:
userdatadetails = vm.userdatadetails
if vm.userdataid:
userdataid = vm.userdataid
if vmprofile.userdataid:
self.assertEquals(userdataid, vmprofile.userdataid)
else:
self.assertIsNone(userdataid)
if vmprofile.userdatadetails:
self.assertEquals(userdatadetails, vmprofile.userdatadetails)
else:
self.assertIsNone(userdatadetails)
if vmprofile.userdata:
self.assertEquals(userdata, vmprofile.userdata)
else:
self.assertIsNone(userdata)
def wait_for_vm_start(self, vm=None, project_id=None): def wait_for_vm_start(self, vm=None, project_id=None):
""" Wait until vm is Running """ """ Wait until vm is Running """
def check_user_vm_state(): def check_user_vm_state():
@ -512,6 +576,7 @@ class TestVmAutoScaling(cloudstackTestCase):
self.apiclient, self.apiclient,
id=vm.id, id=vm.id,
projectid=project_id, projectid=project_id,
userdata=True,
listall=True listall=True
) )
if isinstance(vms, list): if isinstance(vms, list):
@ -576,6 +641,8 @@ class TestVmAutoScaling(cloudstackTestCase):
Autoscale.updateAutoscaleVMProfile( Autoscale.updateAutoscaleVMProfile(
self.regular_user_apiclient, self.regular_user_apiclient,
id = self.autoscaling_vmprofile.id, id = self.autoscaling_vmprofile.id,
userdataid=self.apiUserdata.userdata.id,
userdatadetails=[{"key1": "value2"}],
serviceofferingid = self.service_offering_new.id, serviceofferingid = self.service_offering_new.id,
expungevmgraceperiod = DEFAULT_EXPUNGE_VM_GRACE_PERIOD + 1, expungevmgraceperiod = DEFAULT_EXPUNGE_VM_GRACE_PERIOD + 1,
otherdeployparams = otherdeployparams_new otherdeployparams = otherdeployparams_new
@ -712,6 +779,7 @@ class TestVmAutoScaling(cloudstackTestCase):
vms = VirtualMachine.list( vms = VirtualMachine.list(
self.regular_user_apiclient, self.regular_user_apiclient,
autoscalevmgroupid=self.autoscaling_vmgroup.id, autoscalevmgroupid=self.autoscaling_vmgroup.id,
userdata=True,
listall=True listall=True
) )
self.assertEqual( self.assertEqual(
@ -889,6 +957,7 @@ class TestVmAutoScaling(cloudstackTestCase):
self.regular_user_apiclient, self.regular_user_apiclient,
autoscalevmgroupid=autoscaling_vmgroup_project.id, autoscalevmgroupid=autoscaling_vmgroup_project.id,
projectid=project.id, projectid=project.id,
userdata=True,
listall=True listall=True
) )
self.assertEqual( self.assertEqual(

View File

@ -1625,6 +1625,7 @@
"label.reset.config.value": "Reset to default value", "label.reset.config.value": "Reset to default value",
"label.reset.ssh.key.pair": "Reset SSH key pair", "label.reset.ssh.key.pair": "Reset SSH key pair",
"label.reset.to.default": "Reset to default", "label.reset.to.default": "Reset to default",
"label.reset.userdata.on.autoscale.vm.group": "Reset Userdata on AutoScale VM Group",
"label.reset.userdata.on.vm": "Reset Userdata on VM", "label.reset.userdata.on.vm": "Reset Userdata on VM",
"label.reset.vpn.connection": "Reset VPN connection", "label.reset.vpn.connection": "Reset VPN connection",
"label.resource": "Resource", "label.resource": "Resource",

View File

@ -69,6 +69,47 @@
{{ getServiceOfferingName(serviceofferingid) }} {{ getServiceOfferingName(serviceofferingid) }}
</div> </div>
</div> </div>
<div class="form" v-if="userdataid">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdataid')"/>
</div>
{{ userdataid }}
</div>
</div>
<div class="form" v-if="userdataname">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdataname')"/>
</div>
{{ userdataname }}
</div>
</div>
<div class="form" v-if="userdatadetails">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdatadetails')"/>
</div>
{{ userdatadetails }}
</div>
</div>
<div class="form" v-if="userdatapolicy">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdatapolicy')"/>
</div>
{{ userdatapolicy }}
</div>
</div>
<div class="form">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdata')" :tooltip="createAutoScaleVmProfileApiParams.userdata.description"/>
</div>
<a-textarea v-model:value="userdata" rows="5" :disabled="true">
</a-textarea>
</div>
</div>
<div class="form"> <div class="form">
<div class="form__item"> <div class="form__item">
<a-button ref="submit" :disabled="!('updateAutoScaleVmProfile' in $store.getters.apis) || resource.state !== 'DISABLED'" type="primary" @click="editProfileModalVisible = true"> <a-button ref="submit" :disabled="!('updateAutoScaleVmProfile' in $store.getters.apis) || resource.state !== 'DISABLED'" type="primary" @click="editProfileModalVisible = true">
@ -76,6 +117,12 @@
{{ $t('label.edit.autoscale.vmprofile') }} {{ $t('label.edit.autoscale.vmprofile') }}
</a-button> </a-button>
</div> </div>
<div class="form__item">
<a-button ref="submit" :disabled="!('updateAutoScaleVmProfile' in $store.getters.apis) || resource.state !== 'DISABLED'" type="primary" @click="showUpdateUserDataForm = true">
<template #icon><solution-outlined /></template>
{{ $t('label.reset.userdata.on.autoscale.vm.group') }}
</a-button>
</div>
</div> </div>
<a-divider/> <a-divider/>
@ -224,20 +271,26 @@
</a-select> </a-select>
</div> </div>
</div> </div>
<div class="form">
<div class="form__item">
<div class="form__label">
<tooltip-label :title="$t('label.userdata')" :tooltip="createAutoScaleVmProfileApiParams.userdata.description"/>
</div>
<a-textarea v-model:value="userdata">
</a-textarea>
</div>
</div>
<div :span="24" class="action-button"> <div :span="24" class="action-button">
<a-button :loading="loading" @click="closeModal">{{ $t('label.cancel') }}</a-button> <a-button :loading="loading" @click="closeModal">{{ $t('label.cancel') }}</a-button>
<a-button :loading="loading" ref="submit" type="primary" @click="updateAutoScaleVmProfile">{{ $t('label.ok') }}</a-button> <a-button :loading="loading" ref="submit" type="primary" @click="updateAutoScaleVmProfile">{{ $t('label.ok') }}</a-button>
</div> </div>
</a-modal> </a-modal>
<a-modal
:visible="showUpdateUserDataForm"
:title="$t('label.reset.userdata.on.autoscale.vm.group')"
:closable="true"
:maskClosable="false"
:footer="null"
@cancel="showUpdateUserDataForm = false"
centered
width="auto">
<reset-user-data
:resource="{ ...resource, ...{ resetUserDataApiName: 'updateAutoScaleVmProfile', resetUserDataResourceId: this.resource.vmprofileid, templateid: this.templateid}}"
@close-action="showUpdateUserDataForm = false"
/>
</a-modal>
</div> </div>
</template> </template>
@ -247,10 +300,12 @@ import { isAdmin, isAdminOrDomainAdmin } from '@/role'
import Status from '@/components/widgets/Status' import Status from '@/components/widgets/Status'
import TooltipButton from '@/components/widgets/TooltipButton' import TooltipButton from '@/components/widgets/TooltipButton'
import TooltipLabel from '@/components/widgets/TooltipLabel' import TooltipLabel from '@/components/widgets/TooltipLabel'
import ResetUserData from '@views/compute/ResetUserData'
export default { export default {
name: 'conditionsTab', name: 'conditionsTab',
components: { components: {
ResetUserData,
Status, Status,
TooltipButton, TooltipButton,
TooltipLabel TooltipLabel
@ -266,12 +321,17 @@ export default {
filterColumns: ['Action'], filterColumns: ['Action'],
loading: true, loading: true,
editProfileModalVisible: false, editProfileModalVisible: false,
showUpdateUserDataForm: false,
profileid: null, profileid: null,
autoscaleuserid: null, autoscaleuserid: null,
expungevmgraceperiod: null, expungevmgraceperiod: null,
templateid: null, templateid: null,
serviceofferingid: null, serviceofferingid: null,
userdata: null, userdata: null,
userdataid: null,
userdataname: null,
userdatadetails: null,
userdatapolicy: null,
usersList: [], usersList: [],
templatesList: [], templatesList: [],
serviceOfferingsList: [], serviceOfferingsList: [],
@ -384,6 +444,11 @@ export default {
this.serviceofferingid = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.serviceofferingid this.serviceofferingid = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.serviceofferingid
this.templateid = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.templateid this.templateid = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.templateid
this.userdata = this.decodeUserData(decodeURIComponent(response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdata || '')) this.userdata = this.decodeUserData(decodeURIComponent(response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdata || ''))
this.userdataid = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdataid
this.userdataname = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdataname
this.userdatadetails = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdatadetails
this.userdatapolicy = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.userdatapolicy
const counterparam = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.counterparam || {} const counterparam = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.counterparam || {}
const otherdeployparams = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.otherdeployparams || {} const otherdeployparams = response.listautoscalevmprofilesresponse?.autoscalevmprofile?.[0]?.otherdeployparams || {}
this.finalizeParams(counterparam, otherdeployparams) this.finalizeParams(counterparam, otherdeployparams)
@ -518,13 +583,10 @@ export default {
if (this.autoscaleuserid) { if (this.autoscaleuserid) {
params.autoscaleuserid = this.autoscaleuserid params.autoscaleuserid = this.autoscaleuserid
} }
if (this.userdata && this.userdata.length > 0) {
params.userdata = this.$toBase64AndURIEncoded(this.userdata)
}
const httpMethod = params.userdata ? 'POST' : 'GET' const httpMethod = 'GET'
const args = httpMethod === 'POST' ? {} : params const args = params
const data = httpMethod === 'POST' ? params : {} const data = {}
api('updateAutoScaleVmProfile', args, httpMethod, data).then(response => { api('updateAutoScaleVmProfile', args, httpMethod, data).then(response => {
this.$pollJob({ this.$pollJob({

View File

@ -407,7 +407,7 @@
<span v-if="property.type && property.type==='boolean'"> <span v-if="property.type && property.type==='boolean'">
<a-switch <a-switch
v-model:cheked="form['properties.' + escapePropertyKey(property.key)]" v-model:checked="form['properties.' + escapePropertyKey(property.key)]"
:placeholder="property.description" :placeholder="property.description"
/> />
</span> </span>
@ -760,15 +760,102 @@
@select-affinity-group-item="($event) => updateAffinityGroups($event)" @select-affinity-group-item="($event) => updateAffinityGroups($event)"
@handle-search-filter="($event) => handleSearchFilter('affinityGroups', $event)"/> @handle-search-filter="($event) => handleSearchFilter('affinityGroups', $event)"/>
</a-form-item> </a-form-item>
<a-form-item name="userdata" ref="userdata"> <a-form-item>
<template #label> <template #label>
<tooltip-label :title="$t('label.userdata')" :tooltip="createAutoScaleVmProfileApiParams.userdata.description"/> <tooltip-label :title="$t('label.userdata')" :tooltip="createAutoScaleVmProfileApiParams.userdata.description"/>
</template> </template>
<a-card>
<div v-if="this.template && this.template.userdataid">
<a-text type="primary">
Userdata "{{ $t(this.template.userdataname) }}" is linked with template "{{ $t(this.template.name) }}" with override policy "{{ $t(this.template.userdatapolicy) }}"
</a-text><br/><br/>
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
<a-text type="primary" v-if="this.template && this.template.userdataid && templateUserDataParams.length > 0">
Enter the values for the variables in userdata
</a-text>
<a-input-group>
<a-table
size="small"
style="overflow-y: auto"
:columns="userDataParamCols"
:dataSource="templateUserDataParams"
:pagination="false"
:rowKey="record => record.key">
<template #value="{ record }">
<a-input v-model:value="templateUserDataValues[record.key]" />
</template>
</a-table>
</a-input-group>
</div>
</div><br/><br/>
<div v-if="userdataDefaultOverridePolicy === 'ALLOWOVERRIDE' || userdataDefaultOverridePolicy === 'APPEND' || !userdataDefaultOverridePolicy">
<span v-if="userdataDefaultOverridePolicy === 'ALLOWOVERRIDE'" >
{{ $t('label.userdata.do.override') }}
<a-switch v-model:checked="doUserdataOverride" style="margin-left: 10px"/>
</span>
<span v-if="userdataDefaultOverridePolicy === 'APPEND'">
{{ $t('label.userdata.do.append') }}
<a-switch v-model:checked="doUserdataAppend" style="margin-left: 10px"/>
</span>
<a-step
:status="zoneSelected ? 'process' : 'wait'">
<template #description>
<div v-if="doUserdataOverride || doUserdataAppend || !userdataDefaultOverridePolicy" style="margin-top: 15px">
<a-card
:tabList="userdataTabList"
:activeTabKey="userdataTabKey"
@tabChange="key => onUserdataTabChange(key, 'userdataTabKey')">
<div v-if="userdataTabKey === 'userdataregistered'">
<a-step
v-if="isUserAllowedToListUserDatas"
:status="zoneSelected ? 'process' : 'wait'">
<template #description>
<div v-if="zoneSelected">
<user-data-selection
:items="options.userDatas"
:row-count="rowCount.userDatas"
:zoneId="zoneId"
:disabled="template.userdatapolicy === 'DENYOVERRIDE'"
:loading="loading.userDatas"
:preFillContent="dataPreFill"
@select-user-data-item="($event) => updateUserData($event)"
@handle-search-filter="($event) => handleSearchFilter('userData', $event)"
/>
<div v-if="userDataParams.length > 0">
<a-input-group>
<a-table
size="small"
style="overflow-y: auto"
:columns="userDataParamCols"
:dataSource="userDataParams"
:pagination="false"
:rowKey="record => record.key">
<template #value="{ record }">
<a-input v-model:value="userDataValues[record.key]" />
</template>
</a-table>
</a-input-group>
</div>
</div>
</template>
</a-step>
</div>
<div v-else>
<a-form-item name="userdata" ref="userdata" >
<a-textarea <a-textarea
placeholder="Userdata"
v-model:value="form.userdata"> v-model:value="form.userdata">
</a-textarea> </a-textarea>
</a-form-item> </a-form-item>
</div> </div>
</a-card>
</div>
</template>
</a-step>
</div>
</a-card>
</a-form-item>
</div>
</template> </template>
</a-step> </a-step>
<a-step <a-step
@ -952,6 +1039,7 @@ import NetworkSelection from '@views/compute/wizard/NetworkSelection'
import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration' import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration'
import LoadBalancerSelection from '@views/compute/wizard/LoadBalancerSelection' import LoadBalancerSelection from '@views/compute/wizard/LoadBalancerSelection'
import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection' import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection'
import UserDataSelection from '@views/compute/wizard/UserDataSelection'
import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection' import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection'
import TooltipLabel from '@/components/widgets/TooltipLabel' import TooltipLabel from '@/components/widgets/TooltipLabel'
import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView.vue' import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView.vue'
@ -964,6 +1052,7 @@ export default {
name: 'Wizard', name: 'Wizard',
components: { components: {
SshKeyPairSelection, SshKeyPairSelection,
UserDataSelection,
NetworkConfiguration, NetworkConfiguration,
NetworkSelection, NetworkSelection,
LoadBalancerSelection, LoadBalancerSelection,
@ -1010,6 +1099,10 @@ export default {
zoneSelected: false, zoneSelected: false,
dynamicscalingenabled: true, dynamicscalingenabled: true,
templateKey: 0, templateKey: 0,
showRegisteredUserdata: true,
doUserdataOverride: false,
doUserdataAppend: false,
userdataDefaultOverridePolicy: 'ALLOWOVERRIDE',
vm: { vm: {
name: null, name: null,
zoneid: null, zoneid: null,
@ -1034,6 +1127,7 @@ export default {
affinityGroups: [], affinityGroups: [],
networks: [], networks: [],
sshKeyPairs: [], sshKeyPairs: [],
UserDatas: [],
loadbalancers: [] loadbalancers: []
}, },
rowCount: {}, rowCount: {},
@ -1045,6 +1139,7 @@ export default {
affinityGroups: false, affinityGroups: false,
networks: false, networks: false,
sshKeyPairs: false, sshKeyPairs: false,
userDatas: false,
loadbalancers: false, loadbalancers: false,
zones: false zones: false
}, },
@ -1123,6 +1218,32 @@ export default {
zone: {}, zone: {},
sshKeyPairs: [], sshKeyPairs: [],
sshKeyPair: {}, sshKeyPair: {},
userData: {},
userDataParams: [],
userDataParamCols: [
{
title: this.$t('label.key'),
dataIndex: 'key'
},
{
title: this.$t('label.value'),
dataIndex: 'value',
slots: { customRender: 'value' }
}
],
userDataValues: {},
templateUserDataCols: [
{
title: this.$t('label.userdata'),
dataIndex: 'userdata'
},
{
title: this.$t('label.userdatapolicy'),
dataIndex: 'userdataoverridepolicy'
}
],
templateUserDataParams: [],
templateUserDataValues: {},
overrideDiskOffering: {}, overrideDiskOffering: {},
templateFilter: [ templateFilter: [
'featured', 'featured',
@ -1134,6 +1255,7 @@ export default {
defaultNetworkId: '', defaultNetworkId: '',
dataNetworkCreated: [], dataNetworkCreated: [],
tabKey: 'templateid', tabKey: 'templateid',
userdataTabKey: 'userdataregistered',
dataPreFill: {}, dataPreFill: {},
showDetails: false, showDetails: false,
showRootDiskSizeChanger: false, showRootDiskSizeChanger: false,
@ -1224,6 +1346,15 @@ export default {
listall: false listall: false
} }
}, },
userDatas: {
list: 'listUserData',
options: {
page: 1,
pageSize: 10,
keyword: undefined,
listall: false
}
},
networks: { networks: {
list: 'listNetworks', list: 'listNetworks',
options: { options: {
@ -1285,12 +1416,27 @@ export default {
}] }]
return tabList return tabList
}, },
userdataTabList () {
let tabList = []
tabList = [{
key: 'userdataregistered',
tab: this.$t('label.userdata.registered')
},
{
key: 'userdatatext',
tab: this.$t('label.userdata.text')
}]
return tabList
},
showSecurityGroupSection () { showSecurityGroupSection () {
return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic') return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic')
}, },
isUserAllowedToListSshKeys () { isUserAllowedToListSshKeys () {
return Boolean('listSSHKeyPairs' in this.$store.getters.apis) return Boolean('listSSHKeyPairs' in this.$store.getters.apis)
}, },
isUserAllowedToListUserDatas () {
return Boolean('listUserData' in this.$store.getters.apis)
},
dynamicScalingVmConfigValue () { dynamicScalingVmConfigValue () {
return this.options.dynamicScalingVmConfig?.[0]?.value === 'true' return this.options.dynamicScalingVmConfig?.[0]?.value === 'true'
}, },
@ -1421,6 +1567,8 @@ export default {
template (oldValue, newValue) { template (oldValue, newValue) {
if (oldValue && newValue && oldValue.id !== newValue.id) { if (oldValue && newValue && oldValue.id !== newValue.id) {
this.dynamicscalingenabled = this.isDynamicallyScalable() this.dynamicscalingenabled = this.isDynamicallyScalable()
this.doUserdataOverride = false
this.doUserdataAppend = false
} }
}, },
beforeCreate () { beforeCreate () {
@ -1853,6 +2001,8 @@ export default {
if (template) { if (template) {
var size = template.size / (1024 * 1024 * 1024) || 0 // bytes to GB var size = template.size / (1024 * 1024 * 1024) || 0 // bytes to GB
this.dataPreFill.minrootdisksize = Math.ceil(size) this.dataPreFill.minrootdisksize = Math.ceil(size)
this.updateTemplateLinkedUserData(this.template.userdataid)
this.userdataDefaultOverridePolicy = this.template.userdatapolicy
} }
} else if (['cpuspeed', 'cpunumber', 'memory'].includes(name)) { } else if (['cpuspeed', 'cpunumber', 'memory'].includes(name)) {
this.vm[name] = value this.vm[name] = value
@ -2017,6 +2167,56 @@ export default {
this.form.keypairs = names this.form.keypairs = names
this.sshKeyPairs = names.map((sshKeyPair) => { return sshKeyPair.name }) this.sshKeyPairs = names.map((sshKeyPair) => { return sshKeyPair.name })
}, },
updateUserData (id) {
if (id === '0') {
this.form.userdataid = undefined
return
}
this.form.userdataid = id
this.userDataParams = []
api('listUserData', { id: id }).then(json => {
const resp = json?.listuserdataresponse?.userdata || []
if (resp) {
var params = resp[0].params
if (params) {
var dataParams = params.split(',')
}
var that = this
dataParams.forEach(function (val, index) {
that.userDataParams.push({
id: index,
key: val
})
})
}
})
},
updateTemplateLinkedUserData (id) {
if (id === '0') {
return
}
this.templateUserDataParams = []
api('listUserData', { id: id }).then(json => {
const resp = json?.listuserdataresponse?.userdata || []
if (resp) {
var params = resp[0].params
if (params) {
var dataParams = params.split(',')
}
var that = this
that.templateUserDataParams = []
if (dataParams) {
dataParams.forEach(function (val, index) {
that.templateUserDataParams.push({
id: index,
key: val
})
})
}
}
})
},
updateAffinityGroups (ids) { updateAffinityGroups (ids) {
this.form.affinitygroupids = ids this.form.affinitygroupids = ids
}, },
@ -2035,17 +2235,21 @@ export default {
}, 1000) }, 1000)
}) })
}, },
createVmProfile (createVmGroupData) { createVmProfile (createVmGroupData, createVmGroupUserDataDetails) {
this.addStep('message.creating.autoscale.vmprofile', 'createVmProfile') this.addStep('message.creating.autoscale.vmprofile', 'createVmProfile')
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const params = { const params = {
...createVmGroupUserDataDetails,
...{
expungevmgraceperiod: createVmGroupData.expungevmgraceperiod, expungevmgraceperiod: createVmGroupData.expungevmgraceperiod,
serviceofferingid: createVmGroupData.serviceofferingid, serviceofferingid: createVmGroupData.serviceofferingid,
templateid: createVmGroupData.templateid, templateid: createVmGroupData.templateid,
userdata: createVmGroupData.userdata, userdata: createVmGroupData.userdata,
userdataid: createVmGroupData.userdataid,
zoneid: createVmGroupData.zoneid zoneid: createVmGroupData.zoneid
} }
}
if (createVmGroupData.autoscaleuserid) { if (createVmGroupData.autoscaleuserid) {
params.autoscaleuserid = createVmGroupData.autoscaleuserid params.autoscaleuserid = createVmGroupData.autoscaleuserid
} }
@ -2425,9 +2629,13 @@ export default {
// advanced settings // advanced settings
createVmGroupData.keypairs = this.sshKeyPairs.join(',') createVmGroupData.keypairs = this.sshKeyPairs.join(',')
createVmGroupData.affinitygroupids = (values.affinitygroupids || []).join(',') createVmGroupData.affinitygroupids = (values.affinitygroupids || []).join(',')
if (values.userdata && values.userdata.length > 0) { const isUserdataAllowed = !this.userdataDefaultOverridePolicy || (this.userdataDefaultOverridePolicy === 'ALLOWOVERRIDE' && this.doUserdataOverride) || (this.userdataDefaultOverridePolicy === 'APPEND' && this.doUserdataAppend)
if (isUserdataAllowed && values.userdata && values.userdata.length > 0) {
createVmGroupData.userdata = this.$toBase64AndURIEncoded(values.userdata) createVmGroupData.userdata = this.$toBase64AndURIEncoded(values.userdata)
} }
if (isUserdataAllowed) {
createVmGroupData.userdataid = values.userdataid
}
// vm profile details // vm profile details
createVmGroupData.autoscaleuserid = values.autoscaleuserid createVmGroupData.autoscaleuserid = values.autoscaleuserid
@ -2436,11 +2644,26 @@ export default {
createVmGroupData = Object.fromEntries( createVmGroupData = Object.fromEntries(
Object.entries(createVmGroupData).filter(([key, value]) => value !== undefined)) Object.entries(createVmGroupData).filter(([key, value]) => value !== undefined))
const createVmGroupUserDataDetails = {}
var idx = 0
if (this.templateUserDataValues) {
for (const [key, value] of Object.entries(this.templateUserDataValues)) {
createVmGroupUserDataDetails['userdatadetails[' + idx + '].' + `${key}`] = value
idx++
}
}
if (isUserdataAllowed && this.userDataValues) {
for (const [key, value] of Object.entries(this.userDataValues)) {
createVmGroupUserDataDetails['userdatadetails[' + idx + '].' + `${key}`] = value
idx++
}
}
this.processStatusModalVisible = true this.processStatusModalVisible = true
this.processStatus = null this.processStatus = null
// create autoscale vm profile // create autoscale vm profile
const vmprofile = await this.createVmProfile(createVmGroupData) const vmprofile = await this.createVmProfile(createVmGroupData, createVmGroupUserDataDetails)
// create scaleup conditions and policy // create scaleup conditions and policy
const scaleUpPolicyIds = [] const scaleUpPolicyIds = []
@ -2547,7 +2770,7 @@ export default {
return new Promise((resolve) => { return new Promise((resolve) => {
this.loading.zones = true this.loading.zones = true
const param = this.params.zones const param = this.params.zones
const args = { listall: true, showicon: true } const args = { showicon: true }
if (zoneId) args.id = zoneId if (zoneId) args.id = zoneId
api(param.list, args).then(json => { api(param.list, args).then(json => {
const zoneResponse = (json.listzonesresponse.zone || []).filter(item => item.securitygroupsenabled === false) const zoneResponse = (json.listzonesresponse.zone || []).filter(item => item.securitygroupsenabled === false)
@ -2579,7 +2802,7 @@ export default {
param.loading = true param.loading = true
param.opts = [] param.opts = []
const options = param.options || {} const options = param.options || {}
if (!('listall' in options)) { if (!('listall' in options) && !['zones', 'pods', 'clusters', 'hosts', 'dynamicScalingVmConfig', 'hypervisors'].includes(name)) {
options.listall = true options.listall = true
} }
api(param.list, options).then((response) => { api(param.list, options).then((response) => {
@ -2703,6 +2926,10 @@ export default {
this.params[name].options = { ...this.params[name].options, ...options } this.params[name].options = { ...this.params[name].options, ...options }
this.fetchOptions(this.params[name], name) this.fetchOptions(this.params[name], name)
}, },
onUserdataTabChange (key, type) {
this[type] = key
this.userDataParams = []
},
fetchTemplateNics (template) { fetchTemplateNics (template) {
var nics = [] var nics = []
this.nicToNetworkSelection = [] this.nicToNetworkSelection = []

View File

@ -335,7 +335,6 @@ export default {
this.loadingData = true this.loadingData = true
console.log(values) console.log(values)
const params = { const params = {
id: this.resource.id
} }
if (values.userdata && values.userdata.length > 0) { if (values.userdata && values.userdata.length > 0) {
params.userdata = this.$toBase64AndURIEncoded(values.userdata) params.userdata = this.$toBase64AndURIEncoded(values.userdata)
@ -356,7 +355,14 @@ export default {
idx++ idx++
} }
} }
api('resetUserDataForVirtualMachine', params).then(json => { params.id = this.resource.resetUserDataResourceId ? this.resource.resetUserDataResourceId : this.resource.id
const resetUserDataApiName = this.resource.resetUserDataApiName ? this.resource.resetUserDataApiName : 'resetUserDataForVirtualMachine'
const httpMethod = params.userdata ? 'POST' : 'GET'
const args = httpMethod === 'POST' ? {} : params
const data = httpMethod === 'POST' ? params : {}
api(resetUserDataApiName, args, httpMethod, data).then(json => {
this.$message.success({ this.$message.success({
content: `${this.$t('label.action.userdata.reset')} - ${this.$t('label.success')}`, content: `${this.$t('label.action.userdata.reset')} - ${this.$t('label.success')}`,
duration: 2 duration: 2