Return vm userdata (#6683)

* [UI] Update vm userdata

* fix vm id

* Address review

* Address review

Co-authored-by: João Paraquetti <joao@scclouds.com.br>
This commit is contained in:
João Jandre 2022-09-26 19:12:28 -03:00 committed by GitHub
parent efbf74ee06
commit d4c6586546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 31 deletions

View File

@ -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<VMDetails> getDetails() throws InvalidParameterValueException {
EnumSet<VMDetails> dv;
if (viewDetails == null || viewDetails.size() <= 0) {

View File

@ -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<SecurityGroupResponse>();
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;
}
}

View File

@ -1805,12 +1805,13 @@ public class ApiDBUtils {
return s_domainRouterJoinDao.newDomainRouterView(vr);
}
public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Account caller) {
return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, null, caller);
public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set<VMDetails> 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<VMDetails> 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<VMDetails> 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) {

View File

@ -965,7 +965,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (_accountMgr.isRootAdmin(caller.getId())) {
respView = ResponseView.Full;
}
List<UserVmResponse> vmResponses = ViewResponseHelper.createUserVmResponse(respView, "virtualmachine", cmd.getDetails(), cmd.getAccumulate(), result.first().toArray(new UserVmJoinVO[result.first().size()]));
List<UserVmResponse> 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;

View File

@ -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<UserVmResponse> 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<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, EnumSet<VMDetails> details, UserVmJoinVO... userVms) {
return createUserVmResponse(view, objectName, details, null, userVms);
public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, Set<VMDetails> details, UserVmJoinVO... userVms) {
return createUserVmResponse(view, objectName, details, null, null, userVms);
}
public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, EnumSet<VMDetails> details, Boolean accumulateStats, UserVmJoinVO... userVms) {
public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, Set<VMDetails> details, Boolean accumulateStats, UserVmJoinVO... userVms) {
return createUserVmResponse(view, objectName, details, accumulateStats, null, userVms);
}
public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, Set<VMDetails> details, Boolean accumulateStats, Boolean showUserData,
UserVmJoinVO... userVms) {
Account caller = CallContext.current().getCallingAccount();
Hashtable<Long, UserVmResponse> vmDataList = new Hashtable<Long, UserVmResponse>();
// 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);

View File

@ -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<UserVmJoinVO, Long> {
UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Boolean accumulateStats, Account caller);
UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set<VMDetails> details, Boolean accumulateStats, Boolean showUserData,
Account caller);
UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVmData, UserVmJoinVO uvo);

View File

@ -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<UserVmJo
}
@Override
public UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Boolean accumulateStats, Account caller) {
public UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, Set<VMDetails> details, Boolean accumulateStats, Boolean showUserData,
Account caller) {
UserVmResponse userVmResponse = new UserVmResponse();
if (userVm.getHypervisorType() != null) {
@ -347,6 +348,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
}
}
if (BooleanUtils.isTrue(showUserData)) {
userVmResponse.setUserData(userVm.getUserData());
}
// set resource details map
// Allow passing details to end user
// Honour the display field and only return if display is set to true

View File

@ -61,3 +61,10 @@ export function removeLoadingAnimate (id = '', timeout = 1500) {
document.body.removeChild(document.getElementById(id))
}, timeout)
}
export function sanitizeReverse (value) {
return value
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
}

View File

@ -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(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
return reversedValue
},
fetchTemplateNics (template) {
var nics = []
this.nicToNetworkSelection = []

View File

@ -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(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/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