From d4c6586546ca4c3773dd3f7a25ab1643fffed082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Jandre?= <48719461+JoaoJandre@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:12:28 -0300 Subject: [PATCH] Return vm userdata (#6683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [UI] Update vm userdata * fix vm id * Address review * Address review Co-authored-by: João Paraquetti --- .../api/command/user/vm/ListVMsCmd.java | 8 +++++++ .../api/response/UserVmResponse.java | 12 +++++++++++ .../main/java/com/cloud/api/ApiDBUtils.java | 9 ++++---- .../com/cloud/api/query/QueryManagerImpl.java | 3 ++- .../cloud/api/query/ViewResponseHelper.java | 16 +++++++++----- .../cloud/api/query/dao/UserVmJoinDao.java | 5 +++-- .../api/query/dao/UserVmJoinDaoImpl.java | 9 ++++++-- ui/src/utils/util.js | 7 +++++++ ui/src/views/compute/DeployVM.vue | 11 ++-------- ui/src/views/compute/EditVM.vue | 21 ++++++++++++------- 10 files changed, 70 insertions(+), 31 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java index 078ea55d52a..bb105d2b2bb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java @@ -141,6 +141,10 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { since = "4.17.0") private Boolean accumulate; + @Parameter(name = ApiConstants.USER_DATA, type = CommandType.BOOLEAN, description = "Whether to return the VMs' user data or not. By default, user data will not be returned.", since = "4.18.0.0") + private Boolean showUserData; + + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -219,6 +223,10 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { return haEnabled; } + public Boolean getShowUserData() { + return this.showUserData; + } + public EnumSet getDetails() throws InvalidParameterValueException { EnumSet dv; if (viewDetails == null || viewDetails.size() <= 0) { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java index 76715fe76cb..66a847ad540 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java @@ -332,6 +332,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co @Param(description = "Base64 string representation of the resource icon", since = "4.16.0.0") ResourceIconResponse resourceIconResponse; + @SerializedName(ApiConstants.USER_DATA) + @Param(description = "Base64 string containing the user data", since = "4.18.0.0") + private String userData; + public UserVmResponse() { securityGroupList = new LinkedHashSet(); nics = new TreeSet<>(Comparator.comparingInt(x -> Integer.parseInt(x.getDeviceId()))); @@ -604,6 +608,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co return serviceState; } + public String getUserData() { + return userData; + } + public void setIsDynamicallyScalable(Boolean isDynamicallyScalable) { this.isDynamicallyScalable = isDynamicallyScalable; } @@ -952,4 +960,8 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co public void setBytesSent(Long bytesSent) { this.bytesSent = bytesSent; } + + public void setUserData(String userData) { + this.userData = userData; + } } diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index fe7f39b193d..6780a3a98f9 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -1805,12 +1805,13 @@ public class ApiDBUtils { return s_domainRouterJoinDao.newDomainRouterView(vr); } - public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet details, Account caller) { - return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, null, caller); + public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set details, Account caller) { + return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, null, null, caller); } - public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet details, Boolean accumulateStats, Account caller) { - return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, accumulateStats, caller); + public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set details, Boolean accumulateStats, + Boolean showUserData, Account caller) { + return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, accumulateStats, showUserData, caller); } public static UserVmResponse fillVmDetails(ResponseView view, UserVmResponse vmData, UserVmJoinVO vm) { diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 67666bef331..d6d685e8cf5 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -965,7 +965,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (_accountMgr.isRootAdmin(caller.getId())) { respView = ResponseView.Full; } - List vmResponses = ViewResponseHelper.createUserVmResponse(respView, "virtualmachine", cmd.getDetails(), cmd.getAccumulate(), result.first().toArray(new UserVmJoinVO[result.first().size()])); + List vmResponses = ViewResponseHelper.createUserVmResponse(respView, "virtualmachine", cmd.getDetails(), cmd.getAccumulate(), cmd.getShowUserData(), + result.first().toArray(new UserVmJoinVO[result.first().size()])); response.setResponses(vmResponses, result.second()); return response; diff --git a/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java b/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java index cfa45097455..ecfda39972e 100644 --- a/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java +++ b/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java @@ -25,6 +25,7 @@ import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -135,14 +136,19 @@ public class ViewResponseHelper { } public static List createUserVmResponse(ResponseView view, String objectName, UserVmJoinVO... userVms) { - return createUserVmResponse(view, objectName, EnumSet.of(VMDetails.all), null, userVms); + return createUserVmResponse(view, objectName, EnumSet.of(VMDetails.all), null, null, userVms); } - public static List createUserVmResponse(ResponseView view, String objectName, EnumSet details, UserVmJoinVO... userVms) { - return createUserVmResponse(view, objectName, details, null, userVms); + public static List createUserVmResponse(ResponseView view, String objectName, Set details, UserVmJoinVO... userVms) { + return createUserVmResponse(view, objectName, details, null, null, userVms); } - public static List createUserVmResponse(ResponseView view, String objectName, EnumSet details, Boolean accumulateStats, UserVmJoinVO... userVms) { + public static List createUserVmResponse(ResponseView view, String objectName, Set details, Boolean accumulateStats, UserVmJoinVO... userVms) { + return createUserVmResponse(view, objectName, details, accumulateStats, null, userVms); + } + + public static List createUserVmResponse(ResponseView view, String objectName, Set details, Boolean accumulateStats, Boolean showUserData, + UserVmJoinVO... userVms) { Account caller = CallContext.current().getCallingAccount(); Hashtable vmDataList = new Hashtable(); // Initialise the vmdatalist with the input data @@ -151,7 +157,7 @@ public class ViewResponseHelper { UserVmResponse userVmData = vmDataList.get(userVm.getId()); if (userVmData == null) { // first time encountering this vm - userVmData = ApiDBUtils.newUserVmResponse(view, objectName, userVm, details, accumulateStats, caller); + userVmData = ApiDBUtils.newUserVmResponse(view, objectName, userVm, details, accumulateStats, showUserData, caller); } else{ // update nics, securitygroups, tags, affinitygroups for 1 to many mapping fields userVmData = ApiDBUtils.fillVmDetails(view, userVmData, userVm); diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDao.java index 952a20e8b0d..652f51bcb3d 100644 --- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDao.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.api.query.dao; -import java.util.EnumSet; import java.util.List; +import java.util.Set; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.ResponseObject.ResponseView; @@ -30,7 +30,8 @@ import com.cloud.utils.db.GenericDao; public interface UserVmJoinDao extends GenericDao { - UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet details, Boolean accumulateStats, Account caller); + UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set details, Boolean accumulateStats, Boolean showUserData, + Account caller); UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVmData, UserVmJoinVO uvo); diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 978d5c0b19c..d27af1de02a 100644 --- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -18,7 +18,6 @@ package com.cloud.api.query.dao; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.EnumSet; import java.util.HashMap; import java.util.Hashtable; import java.util.List; @@ -45,6 +44,7 @@ import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.query.QueryService; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -122,7 +122,8 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation details, Boolean accumulateStats, Account caller) { + public UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set details, Boolean accumulateStats, Boolean showUserData, + Account caller) { UserVmResponse userVmResponse = new UserVmResponse(); if (userVm.getHypervisorType() != null) { @@ -347,6 +348,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation') +} diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue index f6ed526466c..0f0e96acf38 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -700,6 +700,7 @@ import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection' import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection' import TooltipLabel from '@/components/widgets/TooltipLabel' import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView.vue' +import { sanitizeReverse } from '@/utils/util' export default { name: 'Wizard', @@ -1708,7 +1709,7 @@ export default { } deployVmData.dynamicscalingenabled = values.dynamicscalingenabled if (values.userdata && values.userdata.length > 0) { - deployVmData.userdata = encodeURIComponent(btoa(this.sanitizeReverse(values.userdata))) + deployVmData.userdata = encodeURIComponent(btoa(sanitizeReverse(values.userdata))) } // step 2: select template/iso if (this.tabKey === 'templateid') { @@ -2148,14 +2149,6 @@ export default { this.fetchAllIsos() } }, - sanitizeReverse (value) { - const reversedValue = value - .replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') - - return reversedValue - }, fetchTemplateNics (template) { var nics = [] this.nicToNetworkSelection = [] diff --git a/ui/src/views/compute/EditVM.vue b/ui/src/views/compute/EditVM.vue index 070823d19fb..b3861d89f46 100644 --- a/ui/src/views/compute/EditVM.vue +++ b/ui/src/views/compute/EditVM.vue @@ -123,6 +123,7 @@ import { ref, reactive, toRaw } from 'vue' import { api } from '@/api' import TooltipLabel from '@/components/widgets/TooltipLabel' +import { sanitizeReverse } from '@/utils/util' export default { name: 'EditVM', @@ -176,7 +177,8 @@ export default { ostypeid: this.resource.ostypeid, isdynamicallyscalable: this.resource.isdynamicallyscalable, group: this.resource.group, - securitygroupids: this.resource.securitygroup.map(x => x.id) + securitygroupids: this.resource.securitygroup.map(x => x.id), + userdata: '' }) this.rules = reactive({}) }, @@ -188,6 +190,7 @@ export default { this.fetchServiceOfferingData() this.fetchTemplateData() this.fetchDynamicScalingVmConfig() + this.fetchUserData() }, fetchZoneDetails () { api('listZones', { @@ -281,13 +284,15 @@ export default { this.$notifyError(error) }).finally(() => { this.groups.loading = false }) }, - sanitizeReverse (value) { - const reversedValue = value - .replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') + fetchUserData () { + const params = { + id: this.resource.id, + userdata: true + } - return reversedValue + api('listVirtualMachines', params).then(json => { + this.form.userdata = atob(json.listvirtualmachinesresponse.virtualmachine[0].userdata || '') + }) }, handleSubmit () { this.formRef.value.validate().then(() => { @@ -312,7 +317,7 @@ export default { params.group = values.group } if (values.userdata && values.userdata.length > 0) { - params.userdata = encodeURIComponent(btoa(this.sanitizeReverse(values.userdata))) + params.userdata = encodeURIComponent(btoa(sanitizeReverse(values.userdata))) } this.loading = true