mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
UserData as first class resource (#6202)
This PR introduces a new feature to make userdata as a first class resource much like existing SSH keys. Detailed feature specification document: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Userdata+as+a+first+class+resource
This commit is contained in:
parent
c83dee5851
commit
713a236843
@ -101,6 +101,8 @@ public class EventTypes {
|
||||
public static final String EVENT_VM_DYNAMIC_SCALE = "VM.DYNAMIC.SCALE";
|
||||
public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD";
|
||||
public static final String EVENT_VM_RESETSSHKEY = "VM.RESETSSHKEY";
|
||||
|
||||
public static final String EVENT_VM_RESETUSERDATA = "VM.RESETUSERDATA";
|
||||
public static final String EVENT_VM_MIGRATE = "VM.MIGRATE";
|
||||
public static final String EVENT_VM_MOVE = "VM.MOVE";
|
||||
public static final String EVENT_VM_RESTORE = "VM.RESTORE";
|
||||
@ -235,6 +237,9 @@ public class EventTypes {
|
||||
//registering SSH keypair events
|
||||
public static final String EVENT_REGISTER_SSH_KEYPAIR = "REGISTER.SSH.KEYPAIR";
|
||||
|
||||
//registering userdata events
|
||||
public static final String EVENT_REGISTER_USER_DATA = "REGISTER.USER.DATA";
|
||||
|
||||
//register for user API and secret keys
|
||||
public static final String EVENT_REGISTER_FOR_SECRET_API_KEY = "REGISTER.USER.KEY";
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package com.cloud.network;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -85,6 +86,9 @@ public interface NetworkModel {
|
||||
.put(HYPERVISOR_HOST_NAME_FILE, HYPERVISOR_HOST_NAME_FILE)
|
||||
.build();
|
||||
|
||||
List<String> metadataFileNames = new ArrayList<>(Arrays.asList(SERVICE_OFFERING_FILE, AVAILABILITY_ZONE_FILE, LOCAL_HOSTNAME_FILE, LOCAL_IPV4_FILE, PUBLIC_HOSTNAME_FILE, PUBLIC_IPV4_FILE,
|
||||
INSTANCE_ID_FILE, VM_ID_FILE, PUBLIC_KEYS_FILE, CLOUD_IDENTIFIER_FILE, HYPERVISOR_HOST_NAME_FILE));
|
||||
|
||||
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<Integer>("Advanced",Integer.class, "mac.identifier", "0",
|
||||
"This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
|
||||
|
||||
@ -325,7 +329,7 @@ public interface NetworkModel {
|
||||
|
||||
boolean getNetworkEgressDefaultPolicy(Long networkId);
|
||||
|
||||
List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId,
|
||||
List<String[]> generateVmData(String userData, String userDataDetails, String serviceOffering, long datacenterId,
|
||||
String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname);
|
||||
|
||||
String getValidNetworkCidr(Network guestNetwork);
|
||||
|
||||
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
|
||||
@ -56,6 +57,9 @@ import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd;
|
||||
import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd;
|
||||
import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd;
|
||||
import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
|
||||
import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
|
||||
import org.apache.cloudstack.config.Configuration;
|
||||
@ -333,6 +337,33 @@ public interface ManagementService {
|
||||
*/
|
||||
String generateRandomPassword();
|
||||
|
||||
/**
|
||||
* Search registered userdatas for the logged in user.
|
||||
*
|
||||
* @param cmd
|
||||
* The api command class.
|
||||
* @return The list of userdatas found.
|
||||
*/
|
||||
Pair<List<? extends UserData>, Integer> listUserDatas(ListUserDataCmd cmd);
|
||||
|
||||
/**
|
||||
* Registers a userdata.
|
||||
*
|
||||
* @param cmd
|
||||
* The api command class.
|
||||
* @return A VO with the registered userdata.
|
||||
*/
|
||||
UserData registerUserData(RegisterUserDataCmd cmd);
|
||||
|
||||
/**
|
||||
* Deletes a userdata.
|
||||
*
|
||||
* @param cmd
|
||||
* The api command class.
|
||||
* @return True on success. False otherwise.
|
||||
*/
|
||||
boolean deleteUserData(DeleteUserDataCmd cmd);
|
||||
|
||||
/**
|
||||
* Search registered key pairs for the logged in user.
|
||||
*
|
||||
|
||||
@ -40,6 +40,7 @@ import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||
|
||||
public interface TemplateApiService {
|
||||
@ -56,6 +57,8 @@ public interface TemplateApiService {
|
||||
|
||||
VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId);
|
||||
|
||||
|
||||
|
||||
boolean detachIso(long vmId, boolean forced);
|
||||
|
||||
boolean attachIso(long isoId, long vmId, boolean forced);
|
||||
@ -106,4 +109,6 @@ public interface TemplateApiService {
|
||||
VirtualMachineTemplate updateTemplate(UpdateIsoCmd cmd);
|
||||
|
||||
VirtualMachineTemplate updateTemplate(UpdateTemplateCmd cmd);
|
||||
|
||||
VirtualMachineTemplate linkUserDataToTemplate(LinkUserDataToTemplateCmd cmd);
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ package com.cloud.template;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
@ -142,4 +143,9 @@ public interface VirtualMachineTemplate extends ControlledEntity, Identity, Inte
|
||||
Date getUpdated();
|
||||
|
||||
boolean isDeployAsIs();
|
||||
|
||||
Long getUserDataId();
|
||||
|
||||
UserData.UserDataOverridePolicy getUserDataOverridePolicy();
|
||||
|
||||
}
|
||||
|
||||
32
api/src/main/java/com/cloud/user/UserData.java
Normal file
32
api/src/main/java/com/cloud/user/UserData.java
Normal file
@ -0,0 +1,32 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.user;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
public interface UserData extends ControlledEntity, InternalIdentity, Identity {
|
||||
|
||||
public enum UserDataOverridePolicy {
|
||||
ALLOWOVERRIDE, APPEND, DENYOVERRIDE
|
||||
}
|
||||
|
||||
String getUserData();
|
||||
|
||||
String getParams();
|
||||
}
|
||||
@ -35,6 +35,14 @@ public interface UserVm extends VirtualMachine, ControlledEntity {
|
||||
|
||||
void setUserData(String userData);
|
||||
|
||||
void setUserDataId(Long userDataId);
|
||||
|
||||
Long getUserDataId();
|
||||
|
||||
void setUserDataDetails(String userDataDetails);
|
||||
|
||||
String getUserDataDetails();
|
||||
|
||||
String getDetail(String name);
|
||||
|
||||
void setAccountId(long accountId);
|
||||
|
||||
@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
|
||||
@ -103,6 +104,8 @@ public interface UserVmService {
|
||||
*/
|
||||
UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
|
||||
|
||||
UserVm resetVMUserData(ResetVMUserDataCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
|
||||
|
||||
UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, ExecutionException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
InsufficientCapacityException, ResourceAllocationException;
|
||||
|
||||
@ -146,6 +149,12 @@ public interface UserVmService {
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param sshKeyPair
|
||||
* - name of the ssh key pair used to login to the virtual
|
||||
* machine
|
||||
* @param cpuSpeed
|
||||
* @param memory
|
||||
* @param cpuNumber
|
||||
* @param zone
|
||||
* - availability zone for the virtual machine
|
||||
* @param serviceOffering
|
||||
@ -181,9 +190,8 @@ public interface UserVmService {
|
||||
* base64 encoded before adding it to the request. Currently only
|
||||
* HTTP GET is supported. Using HTTP GET (via querystring), you
|
||||
* can send up to 2KB of data after base64 encoding
|
||||
* @param sshKeyPair
|
||||
* - name of the ssh key pair used to login to the virtual
|
||||
* machine
|
||||
* @param userDataId
|
||||
* @param userDataDetails
|
||||
* @param requestedIps
|
||||
* TODO
|
||||
* @param defaultIp
|
||||
@ -191,19 +199,16 @@ public interface UserVmService {
|
||||
* @param displayVm
|
||||
* - Boolean flag whether to the display the vm to the end user or not
|
||||
* @param affinityGroupIdList
|
||||
* @param cpuSpeed
|
||||
* @param memory
|
||||
* @param cpuNumber
|
||||
* @param customId
|
||||
* @param dhcpOptionMap
|
||||
* - Maps the dhcp option code and the dhcp value to the network uuid
|
||||
* @return UserVm object if successful.
|
||||
* @param dataDiskTemplateToDiskOfferingMap
|
||||
* - Datadisk template to Disk offering Map
|
||||
* an optional parameter that creates additional data disks for the virtual machine
|
||||
* For each of the templates in the map, a data disk will be created from the corresponding
|
||||
* disk offering obtained from the map
|
||||
*
|
||||
* @return UserVm object if successful.
|
||||
* @throws InsufficientCapacityException
|
||||
* if there is insufficient capacity to deploy the VM.
|
||||
* @throws ConcurrentOperationException
|
||||
@ -214,11 +219,11 @@ public interface UserVmService {
|
||||
* available.
|
||||
*/
|
||||
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||
String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
|
||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
|
||||
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
@ -227,6 +232,7 @@ public interface UserVmService {
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param zone
|
||||
* - availability zone for the virtual machine
|
||||
* @param serviceOffering
|
||||
@ -264,6 +270,8 @@ public interface UserVmService {
|
||||
* base64 encoded before adding it to the request. Currently only
|
||||
* HTTP GET is supported. Using HTTP GET (via querystring), you
|
||||
* can send up to 2KB of data after base64 encoding
|
||||
* @param userDataId
|
||||
* @param userDataDetails
|
||||
* @param requestedIps
|
||||
* TODO
|
||||
* @param defaultIps
|
||||
@ -279,7 +287,6 @@ public interface UserVmService {
|
||||
* an optional parameter that creates additional data disks for the virtual machine
|
||||
* For each of the templates in the map, a data disk will be created from the corresponding
|
||||
* disk offering obtained from the map
|
||||
* @param type
|
||||
* @return UserVm object if successful.
|
||||
*
|
||||
* @throws InsufficientCapacityException
|
||||
@ -292,10 +299,10 @@ public interface UserVmService {
|
||||
* available.
|
||||
*/
|
||||
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
||||
HTTPMethod httpmethod, String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* Creates a User VM in Advanced Zone (Security Group feature is disabled)
|
||||
@ -303,6 +310,12 @@ public interface UserVmService {
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param sshKeyPair
|
||||
* - name of the ssh key pair used to login to the virtual
|
||||
* machine
|
||||
* @param cpuSpeed
|
||||
* @param memory
|
||||
* @param cpuNumber
|
||||
* @param zone
|
||||
* - availability zone for the virtual machine
|
||||
* @param serviceOffering
|
||||
@ -337,9 +350,8 @@ public interface UserVmService {
|
||||
* base64 encoded before adding it to the request. Currently only
|
||||
* HTTP GET is supported. Using HTTP GET (via querystring), you
|
||||
* can send up to 2KB of data after base64 encoding
|
||||
* @param sshKeyPair
|
||||
* - name of the ssh key pair used to login to the virtual
|
||||
* machine
|
||||
* @param userDataId
|
||||
* @param userDataDetails
|
||||
* @param requestedIps
|
||||
* TODO
|
||||
* @param defaultIps
|
||||
@ -347,9 +359,6 @@ public interface UserVmService {
|
||||
* @param displayVm
|
||||
* - Boolean flag whether to the display the vm to the end user or not
|
||||
* @param affinityGroupIdList
|
||||
* @param cpuSpeed
|
||||
* @param memory
|
||||
* @param cpuNumber
|
||||
* @param customId
|
||||
* @param dhcpOptionMap
|
||||
* - Map that maps the DhcpOption code and their value on the Network uuid
|
||||
@ -370,10 +379,10 @@ public interface UserVmService {
|
||||
* available.
|
||||
*/
|
||||
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||
List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId)
|
||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId)
|
||||
|
||||
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public interface AnnotationService {
|
||||
|
||||
enum EntityType {
|
||||
VM(true), VOLUME(true), SNAPSHOT(true),
|
||||
VM_SNAPSHOT(true), INSTANCE_GROUP(true), SSH_KEYPAIR(true),
|
||||
VM_SNAPSHOT(true), INSTANCE_GROUP(true), SSH_KEYPAIR(true), USER_DATA(true),
|
||||
NETWORK(true), VPC(true), PUBLIC_IP_ADDRESS(true), VPN_CUSTOMER_GATEWAY(true),
|
||||
TEMPLATE(true), ISO(true), KUBERNETES_CLUSTER(true),
|
||||
SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false),
|
||||
|
||||
@ -415,6 +415,12 @@ public class ApiConstants {
|
||||
public static final String USAGE_INTERFACE = "usageinterface";
|
||||
public static final String USED_SUBNETS = "usedsubnets";
|
||||
public static final String USER_DATA = "userdata";
|
||||
|
||||
public static final String USER_DATA_NAME = "userdataname";
|
||||
public static final String USER_DATA_ID = "userdataid";
|
||||
public static final String USER_DATA_POLICY = "userdatapolicy";
|
||||
public static final String USER_DATA_DETAILS = "userdatadetails";
|
||||
public static final String USER_DATA_PARAMS = "userdataparams";
|
||||
public static final String USER_FILTER = "userfilter";
|
||||
public static final String USER_ID = "userid";
|
||||
public static final String USER_SOURCE = "usersource";
|
||||
|
||||
@ -118,6 +118,7 @@ import org.apache.cloudstack.api.response.TrafficMonitorResponse;
|
||||
import org.apache.cloudstack.api.response.TrafficTypeResponse;
|
||||
import org.apache.cloudstack.api.response.UpgradeRouterTemplateResponse;
|
||||
import org.apache.cloudstack.api.response.UsageRecordResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.api.response.UserResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
@ -201,8 +202,8 @@ import com.cloud.projects.ProjectAccount;
|
||||
import com.cloud.projects.ProjectInvitation;
|
||||
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
||||
import com.cloud.resource.RollingMaintenanceManager;
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import com.cloud.server.ResourceTag;
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import com.cloud.storage.GuestOS;
|
||||
import com.cloud.storage.GuestOSHypervisor;
|
||||
import com.cloud.storage.ImageStore;
|
||||
@ -216,9 +217,10 @@ import com.cloud.user.Account;
|
||||
import com.cloud.user.SSHKeyPair;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.net.Ip;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.vm.InstanceGroup;
|
||||
import com.cloud.vm.Nic;
|
||||
import com.cloud.vm.NicSecondaryIp;
|
||||
@ -491,6 +493,8 @@ public interface ResponseGenerator {
|
||||
|
||||
SSHKeyPairResponse createSSHKeyPairResponse(SSHKeyPair sshkeyPair, boolean privatekey);
|
||||
|
||||
UserDataResponse createUserDataResponse(UserData userData);
|
||||
|
||||
BackupResponse createBackupResponse(Backup backup);
|
||||
|
||||
BackupScheduleResponse createBackupScheduleResponse(BackupSchedule backup);
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package org.apache.cloudstack.api.command.admin.vm;
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
|
||||
@APICommand(name = "resetUserDataForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the UserData for virtual machine. " +
|
||||
"The virtual machine must be in a \"Stopped\" state. [async]", responseView = ResponseObject.ResponseView.Full, entityType = {VirtualMachine.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
||||
|
||||
public class ResetVMUserDataCmdAdmin extends ResetVMUserDataCmd implements AdminCmd {
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
|
||||
|
||||
@APICommand(name = "deleteUserData", description = "Deletes a userdata", responseObject = SuccessResponse.class, entityType = {UserData.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.18")
|
||||
public class DeleteUserDataCmd extends BaseCmd {
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(DeleteUserDataCmd.class.getName());
|
||||
private static final String s_name = "deleteuserdataresponse";
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, required = true, entityType = UserDataResponse.class, description = "the ID of the Userdata")
|
||||
private Long id;
|
||||
|
||||
//Owner information
|
||||
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the userdata. Must be used with domainId.")
|
||||
private String accountName;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = DomainResponse.class,
|
||||
description = "an optional domainId for the userdata. If the account parameter is used, domainId must also be used.")
|
||||
private Long domainId;
|
||||
|
||||
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the userdata")
|
||||
private Long projectId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getAccountName() {
|
||||
return accountName;
|
||||
}
|
||||
|
||||
public Long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
public Long getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
boolean result = _mgr.deleteUserData(this);
|
||||
if (result) {
|
||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||
response.setSuccess(result);
|
||||
setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete userdata");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
Account account = CallContext.current().getCallingAccount();
|
||||
if ((account == null || _accountService.isAdmin(account.getId())) && (domainId != null && accountName != null)) {
|
||||
Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId);
|
||||
if (userAccount != null) {
|
||||
return userAccount.getId();
|
||||
}
|
||||
}
|
||||
|
||||
if (account != null) {
|
||||
return account.getId();
|
||||
}
|
||||
|
||||
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@APICommand(name = "linkUserDataToTemplate", description = "Link or unlink a userdata to a template.", responseObject = TemplateResponse.class, responseView = ResponseObject.ResponseView.Restricted,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.18.0")
|
||||
public class LinkUserDataToTemplateCmd extends BaseCmd implements AdminCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(LinkUserDataToTemplateCmd.class.getName());
|
||||
|
||||
private static final String s_name = "linkuserdatatotemplateresponse";
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.TEMPLATE_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = TemplateResponse.class,
|
||||
description = "the ID of the template for the virtual machine")
|
||||
private Long templateId;
|
||||
|
||||
@Parameter(name = ApiConstants.ISO_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = TemplateResponse.class,
|
||||
description = "the ID of the ISO for the virtual machine")
|
||||
private Long isoId;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = UserDataResponse.class,
|
||||
description = "the ID of the userdata that has to be linked to template/ISO. If not provided existing userdata will be unlinked from the template/ISO")
|
||||
private Long userdataId;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_POLICY,
|
||||
type = CommandType.STRING,
|
||||
description = "an optional override policy of the userdata. Possible values are - ALLOWOVERRIDE, APPEND, DENYOVERRIDE. Default policy is allowoverride")
|
||||
private String userdataPolicy;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getTemplateId() {
|
||||
return templateId;
|
||||
}
|
||||
|
||||
public Long getIsoId() {
|
||||
return isoId;
|
||||
}
|
||||
|
||||
public Long getUserdataId() {
|
||||
return userdataId;
|
||||
}
|
||||
|
||||
public UserData.UserDataOverridePolicy getUserdataPolicy() {
|
||||
if (userdataPolicy == null) {
|
||||
return UserData.UserDataOverridePolicy.ALLOWOVERRIDE;
|
||||
}
|
||||
return UserData.UserDataOverridePolicy.valueOf(userdataPolicy.toUpperCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
VirtualMachineTemplate result = null;
|
||||
try {
|
||||
result = _templateService.linkUserDataToTemplate(this);
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException(String.format("Failed to link userdata to template, due to: %s", e.getLocalizedMessage()), e);
|
||||
}
|
||||
if (result != null) {
|
||||
TemplateResponse response = _responseGenerator.createTemplateUpdateResponse(getResponseView(), result);
|
||||
if (getTemplateId() != null) {
|
||||
response.setObjectName("template");
|
||||
} else {
|
||||
response.setObjectName("iso");
|
||||
}
|
||||
response.setTemplateType(result.getTemplateType().toString());//Template can be either USER or ROUTING type
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to link userdata to template");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, getTemplateId());
|
||||
if (template != null) {
|
||||
return template.getAccountId();
|
||||
}
|
||||
|
||||
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
@APICommand(name = "listUserData", description = "List registered userdatas", responseObject = UserDataResponse.class, entityType = {UserData.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.18")
|
||||
public class ListUserDataCmd extends BaseListProjectAndAccountResourcesCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(ListUserDataCmd.class.getName());
|
||||
private static final String s_name = "listuserdataresponse";
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Userdata name to look for")
|
||||
private String name;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Pair<List<? extends UserData>, Integer> resultList = _mgr.listUserDatas(this);
|
||||
List<UserDataResponse> responses = new ArrayList<>();
|
||||
for (UserData result : resultList.first()) {
|
||||
UserDataResponse r = _responseGenerator.createUserDataResponse(result);
|
||||
r.setObjectName(ApiConstants.USER_DATA);
|
||||
responses.add(r);
|
||||
}
|
||||
|
||||
ListResponse<UserDataResponse> response = new ListResponse<>();
|
||||
response.setResponses(responses, resultList.second());
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.NetworkModel;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@APICommand(name = "registerUserData",
|
||||
description = "Register a new userdata.",
|
||||
since = "4.18",
|
||||
responseObject = SuccessResponse.class,
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false)
|
||||
public class RegisterUserDataCmd extends BaseCmd {
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(RegisterUserDataCmd.class.getName());
|
||||
private static final String s_name = "registeruserdataresponse";
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of the userdata")
|
||||
private String name;
|
||||
|
||||
//Owner information
|
||||
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the userdata. Must be used with domainId.")
|
||||
private String accountName;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = DomainResponse.class,
|
||||
description = "an optional domainId for the userdata. If the account parameter is used, domainId must also be used.")
|
||||
private Long domainId;
|
||||
|
||||
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the userdata")
|
||||
private Long projectId;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA, type = CommandType.STRING, required = true, description = "Userdata content", length = 1048576)
|
||||
private String userData;
|
||||
|
||||
@Parameter(name = ApiConstants.PARAMS, type = CommandType.STRING, description = "comma separated list of variables declared in userdata content")
|
||||
private String params;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getAccountName() {
|
||||
return accountName;
|
||||
}
|
||||
|
||||
public Long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
public Long getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public String getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
public String getParams() {
|
||||
checkForVRMetadataFileNames(params);
|
||||
return params;
|
||||
}
|
||||
|
||||
public void checkForVRMetadataFileNames(String params) {
|
||||
if (StringUtils.isNotEmpty(params)) {
|
||||
List<String> keyValuePairs = new ArrayList<>(Arrays.asList(params.split(",")));
|
||||
keyValuePairs.retainAll(NetworkModel.metadataFileNames);
|
||||
if (!keyValuePairs.isEmpty()) {
|
||||
throw new InvalidParameterValueException(String.format("Params passed here have a few virtual router metadata file names %s", keyValuePairs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
|
||||
if (accountId == null) {
|
||||
return CallContext.current().getCallingAccount().getId();
|
||||
}
|
||||
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
||||
UserData result = _mgr.registerUserData(this);
|
||||
UserDataResponse response = _responseGenerator.createUserDataResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
response.setObjectName(ApiConstants.USER_DATA);
|
||||
setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
}
|
||||
@ -47,6 +47,7 @@ import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
@ -153,6 +154,12 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
||||
length = 1048576)
|
||||
private String userData;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18")
|
||||
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")
|
||||
private Map userdataDetails;
|
||||
|
||||
@Deprecated
|
||||
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "name of the ssh key pair used to login to the virtual machine")
|
||||
private String sshKeyPairName;
|
||||
@ -420,6 +427,25 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
||||
return userData;
|
||||
}
|
||||
|
||||
public Long getUserdataId() {
|
||||
return userdataId;
|
||||
}
|
||||
|
||||
public Map<String, String> getUserdataDetails() {
|
||||
Map<String, String> userdataDetailsMap = new HashMap<String, String>();
|
||||
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() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
@ -0,0 +1,173 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.vm;
|
||||
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import org.apache.cloudstack.acl.SecurityChecker;
|
||||
import org.apache.cloudstack.api.ACL;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
@APICommand(name = "resetUserDataForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the UserData for virtual machine. " +
|
||||
"The virtual machine must be in a \"Stopped\" state.", responseView = ResponseObject.ResponseView.Restricted, entityType = {VirtualMachine.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, since = "4.18.0")
|
||||
public class ResetVMUserDataCmd extends BaseCmd implements UserCmd {
|
||||
|
||||
public static final Logger s_logger = Logger.getLogger(ResetVMUserDataCmd.class.getName());
|
||||
|
||||
private static final String s_name = "resetuserdataforvirtualmachineresponse";
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ACL(accessType = SecurityChecker.AccessType.OperateEntry)
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, required = true, description = "The ID of the virtual machine")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA,
|
||||
type = CommandType.STRING,
|
||||
description = "an optional binary data that can be sent to the virtual machine upon a successful deployment. " +
|
||||
"This binary data must be base64 encoded before adding it to the request. " +
|
||||
"Using HTTP GET (via querystring), you can send up to 4KB of data after base64 encoding. " +
|
||||
"Using HTTP POST(via POST body), you can send up to 1MB of data after base64 encoding." +
|
||||
"You also need to change vm.userdata.max.length value",
|
||||
length = 1048576)
|
||||
private String userData;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the userdata")
|
||||
private Long userdataId;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.")
|
||||
private Map userdataDetails;
|
||||
|
||||
//Owner information
|
||||
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
|
||||
private String accountName;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID,
|
||||
type = CommandType.UUID,
|
||||
entityType = DomainResponse.class,
|
||||
description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.")
|
||||
private Long domainId;
|
||||
|
||||
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the virtual machine")
|
||||
private Long projectId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getAccountName() {
|
||||
return accountName;
|
||||
}
|
||||
|
||||
public Long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
public Long getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
public String getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
public Long getUserdataId() {
|
||||
return userdataId;
|
||||
}
|
||||
|
||||
public Map<String, String> getUserdataDetails() {
|
||||
Map<String, String> userdataDetailsMap = new HashMap<String, String>();
|
||||
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
|
||||
public ApiCommandResourceType getApiResourceType() {
|
||||
return ApiCommandResourceType.VirtualMachine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
UserVm vm = _responseGenerator.findUserVmById(getId());
|
||||
if (vm != null) {
|
||||
return vm.getAccountId();
|
||||
}
|
||||
|
||||
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getApiResourceId() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
|
||||
CallContext.current().setEventDetails("Vm Id: " + getId());
|
||||
UserVm result = _userVmService.resetVMUserData(this);
|
||||
|
||||
if (result != null) {
|
||||
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", result).get(0);
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to reset vm SSHKey");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,9 +18,14 @@ 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.Map;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.ACL;
|
||||
@ -37,13 +42,11 @@ import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.net.Dhcp;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
@ -90,6 +93,12 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction,
|
||||
since = "4.16.0")
|
||||
private String userData;
|
||||
|
||||
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the userdata", since = "4.18")
|
||||
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")
|
||||
private Map userdataDetails;
|
||||
|
||||
@Parameter(name = ApiConstants.DISPLAY_VM, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the vm to the end user or not.", authorized = {RoleType.Admin})
|
||||
private Boolean displayVm;
|
||||
|
||||
@ -162,6 +171,25 @@ public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction,
|
||||
return userData;
|
||||
}
|
||||
|
||||
public Long getUserdataId() {
|
||||
return userdataId;
|
||||
}
|
||||
|
||||
public Map<String, String> getUserdataDetails() {
|
||||
Map<String, String> userdataDetailsMap = new HashMap<String, String>();
|
||||
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() {
|
||||
return displayVm;
|
||||
}
|
||||
|
||||
@ -227,6 +227,18 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
||||
@Param(description = "Base64 string representation of the resource icon", since = "4.16.0.0")
|
||||
ResourceIconResponse icon;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_ID) @Param(description="the id of userdata linked to this template", since = "4.18.0")
|
||||
private String userDataId;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_NAME) @Param(description="the name of userdata linked to this template", since = "4.18.0")
|
||||
private String userDataName;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_POLICY) @Param(description="the userdata override policy with the userdata provided while deploying VM", since = "4.18.0")
|
||||
private String userDataPolicy;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_PARAMS) @Param(description="list of parameters which contains the list of keys or string parameters that are needed to be passed for any variables declared in userdata", since = "4.18.0")
|
||||
private String userDataParams;
|
||||
|
||||
public TemplateResponse() {
|
||||
tags = new LinkedHashSet<>();
|
||||
}
|
||||
@ -467,4 +479,36 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
||||
public void setResourceIconResponse(ResourceIconResponse icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public String getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
public void setUserDataId(String userDataId) {
|
||||
this.userDataId = userDataId;
|
||||
}
|
||||
|
||||
public String getUserDataName() {
|
||||
return userDataName;
|
||||
}
|
||||
|
||||
public void setUserDataName(String userDataName) {
|
||||
this.userDataName = userDataName;
|
||||
}
|
||||
|
||||
public String getUserDataPolicy() {
|
||||
return userDataPolicy;
|
||||
}
|
||||
|
||||
public void setUserDataPolicy(String userDataPolicy) {
|
||||
this.userDataPolicy = userDataPolicy;
|
||||
}
|
||||
|
||||
public String getUserDataParams() {
|
||||
return userDataParams;
|
||||
}
|
||||
|
||||
public void setUserDataParams(String userDataParams) {
|
||||
this.userDataParams = userDataParams;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.response;
|
||||
|
||||
import com.cloud.serializer.Param;
|
||||
import com.cloud.user.UserData;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponseWithAnnotations;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
|
||||
@EntityReference(value = UserData.class)
|
||||
public class UserDataResponse extends BaseResponseWithAnnotations {
|
||||
|
||||
@SerializedName(ApiConstants.ID)
|
||||
@Param(description = "ID of the ssh keypair")
|
||||
private String id;
|
||||
|
||||
@SerializedName(ApiConstants.NAME)
|
||||
@Param(description = "Name of the userdata")
|
||||
private String name;
|
||||
|
||||
@SerializedName(ApiConstants.ACCOUNT_ID) @Param(description="the owner id of the userdata")
|
||||
private String accountId;
|
||||
|
||||
@SerializedName(ApiConstants.ACCOUNT) @Param(description="the owner of the userdata")
|
||||
private String accountName;
|
||||
|
||||
@SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain id of the userdata owner")
|
||||
private String domainId;
|
||||
|
||||
@SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the userdata owner")
|
||||
private String domain;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA) @Param(description="base64 encoded userdata content")
|
||||
private String userData;
|
||||
|
||||
@SerializedName(ApiConstants.PARAMS) @Param(description="list of parameters which contains the list of keys or string parameters that are needed to be passed for any variables declared in userdata")
|
||||
private String params;
|
||||
|
||||
public UserDataResponse() {
|
||||
}
|
||||
|
||||
public UserDataResponse(String id, String name, String userData, String params) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.userData = userData;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
public void setDomainId(String domainId) {
|
||||
this.domainId = domainId;
|
||||
}
|
||||
|
||||
public String getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
public void setUserData(String userData) {
|
||||
this.userData = userData;
|
||||
}
|
||||
|
||||
public String getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(String params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getAccountName() {
|
||||
return accountName;
|
||||
}
|
||||
|
||||
public void setAccountName(String accountName) {
|
||||
this.accountName = accountName;
|
||||
}
|
||||
|
||||
public String getDomainName() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomainName(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
}
|
||||
@ -336,6 +336,18 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
||||
@Param(description = "Base64 string containing the user data", since = "4.18.0.0")
|
||||
private String userData;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_ID) @Param(description="the id of userdata used for the VM", since = "4.18.0")
|
||||
private String userDataId;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_NAME) @Param(description="the name of userdata used for the VM", since = "4.18.0")
|
||||
private String userDataName;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_POLICY) @Param(description="the userdata override policy with the userdata provided while deploying VM", since = "4.18.0")
|
||||
private String userDataPolicy;
|
||||
|
||||
@SerializedName(ApiConstants.USER_DATA_DETAILS) @Param(description="list of variables and values for the variables declared in userdata", since = "4.18.0")
|
||||
private String userDataDetails;
|
||||
|
||||
public UserVmResponse() {
|
||||
securityGroupList = new LinkedHashSet<SecurityGroupResponse>();
|
||||
nics = new TreeSet<>(Comparator.comparingInt(x -> Integer.parseInt(x.getDeviceId())));
|
||||
@ -964,4 +976,37 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
||||
public void setUserData(String userData) {
|
||||
this.userData = userData;
|
||||
}
|
||||
|
||||
public String getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
public void setUserDataId(String userDataId) {
|
||||
this.userDataId = userDataId;
|
||||
}
|
||||
|
||||
public String getUserDataName() {
|
||||
return userDataName;
|
||||
}
|
||||
|
||||
public void setUserDataName(String userDataName) {
|
||||
this.userDataName = userDataName;
|
||||
}
|
||||
|
||||
public String getUserDataPolicy() {
|
||||
return userDataPolicy;
|
||||
}
|
||||
|
||||
public void setUserDataPolicy(String userDataPolicy) {
|
||||
this.userDataPolicy = userDataPolicy;
|
||||
}
|
||||
|
||||
public String getUserDataDetails() {
|
||||
return userDataDetails;
|
||||
}
|
||||
|
||||
public void setUserDataDetails(String userDataDetails) {
|
||||
this.userDataDetails = userDataDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.test;
|
||||
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.UserVmService;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
|
||||
public class ResetVMUserDataCmdTest {
|
||||
|
||||
@InjectMocks
|
||||
ResetVMUserDataCmd cmd = new ResetVMUserDataCmd();
|
||||
|
||||
@Mock
|
||||
AccountService _accountService;
|
||||
|
||||
@Mock
|
||||
ResponseGenerator _responseGenerator;
|
||||
|
||||
@Mock
|
||||
UserVmService _userVmService;
|
||||
|
||||
private static final long DOMAIN_ID = 5L;
|
||||
private static final long PROJECT_ID = 10L;
|
||||
private static final String ACCOUNT_NAME = "user";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ReflectionTestUtils.setField(cmd, "accountName", ACCOUNT_NAME);
|
||||
ReflectionTestUtils.setField(cmd, "domainId", DOMAIN_ID);
|
||||
ReflectionTestUtils.setField(cmd, "projectId", PROJECT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidResetVMUserDataExecute() {
|
||||
UserVm result = Mockito.mock(UserVm.class);
|
||||
|
||||
UserVmResponse response = new UserVmResponse();
|
||||
List<UserVmResponse> responseList = new ArrayList<>();
|
||||
responseList.add(response);
|
||||
Mockito.doReturn(responseList).when(_responseGenerator).createUserVmResponse(ResponseObject.ResponseView.Restricted, "virtualmachine", result);
|
||||
|
||||
try {
|
||||
Mockito.doReturn(result).when(_userVmService).resetVMUserData(cmd);
|
||||
cmd.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Assert.assertEquals(response, cmd.getResponseObject());
|
||||
Assert.assertEquals("resetuserdataforvirtualmachineresponse", response.getResponseName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateArgsCmd() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
|
||||
ReflectionTestUtils.setField(cmd, "id", 1L);
|
||||
ReflectionTestUtils.setField(cmd, "userdataId", 2L);
|
||||
ReflectionTestUtils.setField(cmd, "userData", "testUserdata");
|
||||
|
||||
UserVm vm = Mockito.mock(UserVm.class);
|
||||
when(_responseGenerator.findUserVmById(1L)).thenReturn(vm);
|
||||
when(vm.getAccountId()).thenReturn(200L);
|
||||
|
||||
Assert.assertEquals(1L, (long)cmd.getId());
|
||||
Assert.assertEquals(2L, (long)cmd.getUserdataId());
|
||||
Assert.assertEquals("testUserdata", cmd.getUserData());
|
||||
Assert.assertEquals(200L, cmd.getEntityOwnerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserdataDetails() {
|
||||
Map<String, String> values1 = new HashMap<>();
|
||||
values1.put("key1", "value1");
|
||||
values1.put("key2", "value2");
|
||||
|
||||
Map<String, String> values2 = new HashMap<>();
|
||||
values1.put("key3", "value3");
|
||||
values1.put("key4", "value4");
|
||||
|
||||
Map<Integer, Map<String, String>> userdataDetails = new HashMap<>();
|
||||
userdataDetails.put(0, values1);
|
||||
userdataDetails.put(1, values2);
|
||||
|
||||
ReflectionTestUtils.setField(cmd, "userdataDetails", userdataDetails);
|
||||
|
||||
Map<String, String> result = cmd.getUserdataDetails();
|
||||
|
||||
values1.putAll(values2);
|
||||
Assert.assertEquals(values1.toString(), result.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.server.ManagementService;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
|
||||
public class DeleteUserDataCmdTest {
|
||||
|
||||
@InjectMocks
|
||||
DeleteUserDataCmd cmd = new DeleteUserDataCmd();
|
||||
|
||||
@Mock
|
||||
AccountService _accountService;
|
||||
@Mock
|
||||
ManagementService _mgr;
|
||||
|
||||
private static final long DOMAIN_ID = 5L;
|
||||
private static final long PROJECT_ID = 10L;
|
||||
private static final String ACCOUNT_NAME = "user";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ReflectionTestUtils.setField(cmd, "accountName", ACCOUNT_NAME);
|
||||
ReflectionTestUtils.setField(cmd, "domainId", DOMAIN_ID);
|
||||
ReflectionTestUtils.setField(cmd, "projectId", PROJECT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidUserDataExecute() {
|
||||
Mockito.doReturn(true).when(_mgr).deleteUserData(cmd);
|
||||
|
||||
try {
|
||||
cmd.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Assert.assertEquals(cmd.getResponseObject().getClass(), SuccessResponse.class);
|
||||
}
|
||||
|
||||
@Test(expected = ServerApiException.class)
|
||||
public void testDeleteFailure() {
|
||||
Mockito.doReturn(false).when(_mgr).deleteUserData(cmd);
|
||||
cmd.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateArgsCmd() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
Account accountMock = PowerMockito.mock(Account.class);
|
||||
PowerMockito.when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||
Mockito.when(accountMock.getId()).thenReturn(2L);
|
||||
Mockito.doReturn(false).when(_accountService).isAdmin(2L);
|
||||
|
||||
ReflectionTestUtils.setField(cmd, "id", 1L);
|
||||
|
||||
Assert.assertEquals(1L, (long)cmd.getId());
|
||||
Assert.assertEquals(2L, cmd.getEntityOwnerId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.template.TemplateApiService;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.utils.db.EntityManager;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
|
||||
public class LinkUserDataToTemplateCmdTest {
|
||||
|
||||
@Mock
|
||||
private ResponseGenerator _responseGenerator;
|
||||
|
||||
@Mock
|
||||
private EntityManager _entityMgr;
|
||||
|
||||
@InjectMocks
|
||||
LinkUserDataToTemplateCmd cmd = new LinkUserDataToTemplateCmd();
|
||||
|
||||
@Mock
|
||||
TemplateApiService _templateService;
|
||||
|
||||
@Mock
|
||||
VirtualMachineTemplate virtualMachineTemplate;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidIds() {
|
||||
ReflectionTestUtils.setField(cmd, "userdataId", 1L);
|
||||
ReflectionTestUtils.setField(cmd, "templateId", 1L);
|
||||
TemplateResponse response = Mockito.mock(TemplateResponse.class);
|
||||
Mockito.doReturn(virtualMachineTemplate).when(_templateService).linkUserDataToTemplate(cmd);
|
||||
Mockito.doReturn(Storage.TemplateType.USER).when(virtualMachineTemplate).getTemplateType();
|
||||
Mockito.doReturn(response).when(_responseGenerator).createTemplateUpdateResponse(cmd.getResponseView(), virtualMachineTemplate);
|
||||
|
||||
try {
|
||||
cmd.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Assert.assertEquals(response, cmd.getResponseObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateArgsCmd() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
Account accountMock = PowerMockito.mock(Account.class);
|
||||
PowerMockito.when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||
Mockito.when(accountMock.getId()).thenReturn(2L);
|
||||
ReflectionTestUtils.setField(cmd, "templateId", 1L);
|
||||
ReflectionTestUtils.setField(cmd, "userdataId", 3L);
|
||||
|
||||
Mockito.doReturn(virtualMachineTemplate).when(_entityMgr).findById(VirtualMachineTemplate.class, cmd.getTemplateId());
|
||||
PowerMockito.when(virtualMachineTemplate.getAccountId()).thenReturn(1L);
|
||||
|
||||
Assert.assertEquals(1L, (long)cmd.getTemplateId());
|
||||
Assert.assertEquals(3L, (long)cmd.getUserdataId());
|
||||
Assert.assertEquals(1L, cmd.getEntityOwnerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultOverridePolicy() {
|
||||
Assert.assertEquals(UserData.UserDataOverridePolicy.ALLOWOVERRIDE, cmd.getUserdataPolicy());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.server.ManagementService;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.utils.Pair;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.junit.Assert;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
|
||||
public class ListUserDataCmdTest {
|
||||
|
||||
@InjectMocks
|
||||
ListUserDataCmd cmd = new ListUserDataCmd();
|
||||
|
||||
@Mock
|
||||
ManagementService _mgr;
|
||||
|
||||
@Mock
|
||||
ResponseGenerator _responseGenerator;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListSuccess() {
|
||||
UserData userData = Mockito.mock(UserData.class);
|
||||
List<UserData> userDataList = new ArrayList<UserData>();
|
||||
userDataList.add(userData);
|
||||
Pair<List<? extends UserData>, Integer> result = new Pair<List<? extends UserData>, Integer>(userDataList, 1);
|
||||
UserDataResponse userDataResponse = Mockito.mock(UserDataResponse.class);
|
||||
|
||||
Mockito.when(_mgr.listUserDatas(cmd)).thenReturn(result);
|
||||
Mockito.when(_responseGenerator.createUserDataResponse(userData)).thenReturn(userDataResponse);
|
||||
|
||||
cmd.execute();
|
||||
|
||||
ListResponse<UserDataResponse> actualResponse = (ListResponse<UserDataResponse>)cmd.getResponseObject();
|
||||
Assert.assertEquals(userDataResponse, actualResponse.getResponses().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyList() {
|
||||
List<UserData> userDataList = new ArrayList<UserData>();
|
||||
Pair<List<? extends UserData>, Integer> result = new Pair<List<? extends UserData>, Integer>(userDataList, 0);
|
||||
|
||||
Mockito.when(_mgr.listUserDatas(cmd)).thenReturn(result);
|
||||
|
||||
cmd.execute();
|
||||
|
||||
ListResponse<UserDataResponse> actualResponse = (ListResponse<UserDataResponse>)cmd.getResponseObject();
|
||||
Assert.assertEquals(new ArrayList<>(), actualResponse.getResponses());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.userdata;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.server.ManagementService;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
|
||||
public class RegisterUserDataCmdTest {
|
||||
|
||||
@InjectMocks
|
||||
RegisterUserDataCmd cmd = new RegisterUserDataCmd();
|
||||
|
||||
@Mock
|
||||
AccountService _accountService;
|
||||
|
||||
@Mock
|
||||
ResponseGenerator _responseGenerator;
|
||||
|
||||
@Mock
|
||||
ManagementService _mgr;
|
||||
|
||||
private static final long DOMAIN_ID = 5L;
|
||||
private static final long PROJECT_ID = 10L;
|
||||
private static final String ACCOUNT_NAME = "user";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ReflectionTestUtils.setField(cmd, "accountName", ACCOUNT_NAME);
|
||||
ReflectionTestUtils.setField(cmd, "domainId", DOMAIN_ID);
|
||||
ReflectionTestUtils.setField(cmd, "projectId", PROJECT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidUserDataExecute() {
|
||||
UserData result = Mockito.mock(UserData.class);
|
||||
Mockito.doReturn(result).when(_mgr).registerUserData(cmd);
|
||||
|
||||
UserDataResponse response = Mockito.mock(UserDataResponse.class);
|
||||
Mockito.doReturn(response).when(_responseGenerator).createUserDataResponse(result);
|
||||
|
||||
try {
|
||||
cmd.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Assert.assertEquals(response, cmd.getResponseObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateArgsCmd() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
Account accountMock = PowerMockito.mock(Account.class);
|
||||
PowerMockito.when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||
Mockito.when(accountMock.getId()).thenReturn(2L);
|
||||
ReflectionTestUtils.setField(cmd, "name", "testUserdataName");
|
||||
ReflectionTestUtils.setField(cmd, "userData", "testUserdata");
|
||||
|
||||
when(_accountService.finalyzeAccountId(ACCOUNT_NAME, DOMAIN_ID, PROJECT_ID, true)).thenReturn(200L);
|
||||
|
||||
Assert.assertEquals("testUserdataName", cmd.getName());
|
||||
Assert.assertEquals("testUserdata", cmd.getUserData());
|
||||
Assert.assertEquals(200L, cmd.getEntityOwnerId());
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void validateIfUserdataParamsHaveMetadataFileNames() {
|
||||
// If the userdata params have any key matched to the VR metadata file names, then it will throw exception
|
||||
ReflectionTestUtils.setField(cmd, "params", "key1,key2,key3,vm-id");
|
||||
cmd.getParams();
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,6 +19,7 @@
|
||||
package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.UserData;
|
||||
|
||||
public interface TemplateInfo extends DataObject, VirtualMachineTemplate {
|
||||
@Override
|
||||
@ -33,4 +34,8 @@ public interface TemplateInfo extends DataObject, VirtualMachineTemplate {
|
||||
boolean isDeployAsIs();
|
||||
|
||||
String getDeployAsIsConfiguration();
|
||||
|
||||
Long getUserDataId();
|
||||
|
||||
UserData.UserDataOverridePolicy getUserDataOverridePolicy();
|
||||
}
|
||||
|
||||
@ -3101,7 +3101,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
|
||||
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
|
||||
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
||||
List<String[]> vmData = _networkModel.generateVmData(userVm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
List<String[]> vmData = _networkModel.generateVmData(userVm.getUserData(), userVm.getUserDataDetails(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
vm.getUuid(), defaultNic.getMacAddress(), userVm.getDetail("SSH.PublicKey"), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows,
|
||||
VirtualMachineManager.getHypervisorHostname(destination.getHost() != null ? destination.getHost().getName() : ""));
|
||||
String vmName = vm.getInstanceName();
|
||||
|
||||
@ -31,6 +31,7 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
@ -157,6 +158,13 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
||||
@Column(name = "deploy_as_is")
|
||||
private boolean deployAsIs;
|
||||
|
||||
@Column(name = "user_data_id")
|
||||
private Long userDataId;
|
||||
|
||||
@Column(name = "user_data_link_policy")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
UserData.UserDataOverridePolicy userDataLinkPolicy;
|
||||
|
||||
@Override
|
||||
public String getUniqueName() {
|
||||
return uniqueName;
|
||||
@ -644,4 +652,23 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
||||
public void setDeployAsIs(boolean deployAsIs) {
|
||||
this.deployAsIs = deployAsIs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
public void setUserDataId(Long userDataId) {
|
||||
this.userDataId = userDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserData.UserDataOverridePolicy getUserDataOverridePolicy() {
|
||||
return userDataLinkPolicy;
|
||||
}
|
||||
|
||||
public void setUserDataLinkPolicy(UserData.UserDataOverridePolicy userDataLinkPolicy) {
|
||||
this.userDataLinkPolicy = userDataLinkPolicy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -86,4 +86,6 @@ public interface VMTemplateDao extends GenericDao<VMTemplateVO, Long>, StateDao<
|
||||
List<VMTemplateVO> listByParentTemplatetId(long parentTemplatetId);
|
||||
|
||||
VMTemplateVO findLatestTemplateByName(String name);
|
||||
|
||||
List<VMTemplateVO> findTemplatesLinkedToUserdata(long userdataId);
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase<VMTemplateVO, Long> implem
|
||||
protected SearchBuilder<VMTemplateVO> ParentTemplateIdSearch;
|
||||
private SearchBuilder<VMTemplateVO> InactiveUnremovedTmpltSearch;
|
||||
private SearchBuilder<VMTemplateVO> LatestTemplateByHypervisorTypeSearch;
|
||||
|
||||
private SearchBuilder<VMTemplateVO> userDataSearch;
|
||||
@Inject
|
||||
ResourceTagDao _tagsDao;
|
||||
|
||||
@ -422,6 +422,11 @@ public class VMTemplateDaoImpl extends GenericDaoBase<VMTemplateVO, Long> implem
|
||||
InactiveUnremovedTmpltSearch.and("removed", InactiveUnremovedTmpltSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
|
||||
InactiveUnremovedTmpltSearch.done();
|
||||
|
||||
userDataSearch = createSearchBuilder();
|
||||
userDataSearch.and("userDataId", userDataSearch.entity().getUserDataId(), SearchCriteria.Op.EQ);
|
||||
userDataSearch.and("state", userDataSearch.entity().getState(), SearchCriteria.Op.EQ);
|
||||
userDataSearch.done();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -629,12 +634,20 @@ public class VMTemplateDaoImpl extends GenericDaoBase<VMTemplateVO, Long> implem
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMTemplateVO> listUnRemovedTemplatesByStates(VirtualMachineTemplate.State ...states) {
|
||||
public List<VMTemplateVO> listUnRemovedTemplatesByStates(VirtualMachineTemplate.State ...states) {
|
||||
SearchCriteria<VMTemplateVO> sc = InactiveUnremovedTmpltSearch.create();
|
||||
sc.setParameters("state", (Object[]) states);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMTemplateVO> findTemplatesLinkedToUserdata(long userdataId) {
|
||||
SearchCriteria<VMTemplateVO> sc = userDataSearch.create();
|
||||
sc.setParameters("userDataId", userdataId);
|
||||
sc.setParameters("state", VirtualMachineTemplate.State.Active.toString());
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public boolean remove(Long id) {
|
||||
|
||||
120
engine/schema/src/main/java/com/cloud/user/UserDataVO.java
Normal file
120
engine/schema/src/main/java/com/cloud/user/UserDataVO.java
Normal file
@ -0,0 +1,120 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.user;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user_data")
|
||||
public class UserDataVO implements UserData {
|
||||
|
||||
public UserDataVO() {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id = null;
|
||||
|
||||
@Column(name = "uuid")
|
||||
private String uuid;
|
||||
|
||||
@Column(name = "account_id")
|
||||
private long accountId;
|
||||
|
||||
@Column(name = "domain_id")
|
||||
private long domainId;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "user_data", updatable = true, length = 1048576)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private String userData;
|
||||
|
||||
@Column(name = "params", length = 4096)
|
||||
private String params;
|
||||
|
||||
@Override
|
||||
public long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getEntityType() {
|
||||
return UserDataVO.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public void setDomainId(long domainId) {
|
||||
this.domainId = domainId;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setUserData(String userData) {
|
||||
this.userData = userData;
|
||||
}
|
||||
|
||||
public void setParams(String params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.user.dao;
|
||||
|
||||
import com.cloud.user.UserDataVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface UserDataDao extends GenericDao<UserDataVO, Long> {
|
||||
|
||||
public UserDataVO findByUserData(long accountId, long domainId, String userData);
|
||||
|
||||
public UserDataVO findByName(long accountId, long domainId, String name);
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.user.dao;
|
||||
|
||||
import com.cloud.user.UserDataVO;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class UserDataDaoImpl extends GenericDaoBase<UserDataVO, Long> implements UserDataDao {
|
||||
|
||||
private final SearchBuilder<UserDataVO> userdataSearch;
|
||||
private final SearchBuilder<UserDataVO> userdataByNameSearch;
|
||||
|
||||
public UserDataDaoImpl() {
|
||||
super();
|
||||
|
||||
userdataSearch = createSearchBuilder();
|
||||
userdataSearch.and("accountId", userdataSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||
userdataSearch.and("domainId", userdataSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
|
||||
userdataSearch.and("userData", userdataSearch.entity().getUserData(), SearchCriteria.Op.EQ);
|
||||
userdataSearch.done();
|
||||
|
||||
userdataByNameSearch = createSearchBuilder();
|
||||
userdataByNameSearch.and("accountId", userdataByNameSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||
userdataByNameSearch.and("domainId", userdataByNameSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
|
||||
userdataByNameSearch.and("name", userdataByNameSearch.entity().getName(), SearchCriteria.Op.EQ);
|
||||
userdataByNameSearch.done();
|
||||
|
||||
}
|
||||
@Override
|
||||
public UserDataVO findByUserData(long accountId, long domainId, String userData) {
|
||||
SearchCriteria<UserDataVO> sc = userdataSearch.create();
|
||||
sc.setParameters("accountId", accountId);
|
||||
sc.setParameters("domainId", domainId);
|
||||
sc.setParameters("userData", userData);
|
||||
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDataVO findByName(long accountId, long domainId, String name) {
|
||||
SearchCriteria<UserDataVO> sc = userdataByNameSearch.create();
|
||||
sc.setParameters("accountId", accountId);
|
||||
sc.setParameters("domainId", domainId);
|
||||
sc.setParameters("name", name);
|
||||
|
||||
return findOneBy(sc);
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,12 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
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 = "display_name", updatable = true, nullable = true)
|
||||
private String displayName;
|
||||
|
||||
@ -74,9 +80,11 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
}
|
||||
|
||||
public UserVmVO(long id, String instanceName, String displayName, long templateId, HypervisorType hypervisorType, long guestOsId, boolean haEnabled,
|
||||
boolean limitCpuUse, long domainId, long accountId, long userId, long serviceOfferingId, String userData, String name) {
|
||||
boolean limitCpuUse, long domainId, long accountId, long userId, long serviceOfferingId, String userData, Long userDataId, String userDataDetails, String name) {
|
||||
super(id, serviceOfferingId, name, instanceName, Type.User, templateId, hypervisorType, guestOsId, domainId, accountId, userId, haEnabled, limitCpuUse);
|
||||
this.userData = userData;
|
||||
this.userDataId = userDataId;
|
||||
this.userDataDetails = userDataDetails;
|
||||
this.displayName = displayName;
|
||||
this.details = new HashMap<String, String>();
|
||||
}
|
||||
@ -99,6 +107,16 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
return userData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserDataId(Long userDataId) {
|
||||
this.userDataId = userDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
@ -146,4 +164,14 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
public String getDisplayNameOrHostName() {
|
||||
return StringUtils.isNotBlank(displayName) ? displayName : getHostName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserDataDetails() {
|
||||
return userDataDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserDataDetails(String userDataDetails) {
|
||||
this.userDataDetails = userDataDetails;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,14 +43,17 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
|
||||
|
||||
/**
|
||||
* Updates display name and group for vm; enables/disables ha
|
||||
* @param id vm id.
|
||||
* @param userData updates the userData of the vm
|
||||
* @param displayVm updates the displayvm attribute signifying whether it has to be displayed to the end user or not.
|
||||
*
|
||||
* @param id vm id.
|
||||
* @param userData updates the userData of the vm
|
||||
* @param userDataId
|
||||
* @param userDataDetails
|
||||
* @param displayVm updates the displayvm attribute signifying whether it has to be displayed to the end user or not.
|
||||
* @param customId
|
||||
* @param hostName TODO
|
||||
* @param hostName TODO
|
||||
* @param instanceName
|
||||
*/
|
||||
void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, boolean displayVm, boolean isDynamicallyScalable, String customId, String hostName, String instanceName);
|
||||
void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, Long userDataId, String userDataDetails, boolean displayVm, boolean isDynamicallyScalable, String customId, String hostName, String instanceName);
|
||||
|
||||
List<UserVmVO> findDestroyedVms(Date date);
|
||||
|
||||
@ -97,4 +100,7 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
|
||||
List<Ternary<Integer, Integer, Integer>> countVmsBySize(long dcId, int limit);
|
||||
|
||||
int getActiveAccounts(final long dcId);
|
||||
|
||||
List<UserVmVO> findByUserDataId(long userdataId);
|
||||
|
||||
}
|
||||
|
||||
@ -81,6 +81,8 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
||||
|
||||
protected SearchBuilder<UserVmVO> UserVmSearch;
|
||||
protected SearchBuilder<UserVmVO> UserVmByIsoSearch;
|
||||
|
||||
protected SearchBuilder<UserVmVO> listByUserdataId;
|
||||
protected Attribute _updateTimeAttr;
|
||||
// ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class);
|
||||
@Inject
|
||||
@ -219,6 +221,10 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
||||
UserVmByIsoSearch.and("isoId", UserVmByIsoSearch.entity().getIsoId(), SearchCriteria.Op.EQ);
|
||||
UserVmByIsoSearch.done();
|
||||
|
||||
listByUserdataId = createSearchBuilder();
|
||||
listByUserdataId.and("userDataId", listByUserdataId.entity().getUserDataId(), SearchCriteria.Op.EQ);
|
||||
listByUserdataId.done();
|
||||
|
||||
_updateTimeAttr = _allAttributes.get("updateTime");
|
||||
assert _updateTimeAttr != null : "Couldn't get this updateTime attribute";
|
||||
}
|
||||
@ -255,13 +261,15 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, boolean displayVm,
|
||||
boolean isDynamicallyScalable, String customId, String hostName, String instanceName) {
|
||||
public void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, Long userDataId, String userDataDetails, boolean displayVm,
|
||||
boolean isDynamicallyScalable, String customId, String hostName, String instanceName) {
|
||||
UserVmVO vo = createForUpdate();
|
||||
vo.setDisplayName(displayName);
|
||||
vo.setHaEnabled(enable);
|
||||
vo.setGuestOSId(osTypeId);
|
||||
vo.setUserData(userData);
|
||||
vo.setUserDataId(userDataId);
|
||||
vo.setUserDataDetails(userDataDetails);
|
||||
vo.setDisplayVm(displayVm);
|
||||
vo.setDynamicallyScalable(isDynamicallyScalable);
|
||||
if (hostName != null) {
|
||||
@ -763,4 +771,11 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
||||
|
||||
return customSearch(sc, null).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserVmVO> findByUserDataId(long userdataId) {
|
||||
SearchCriteria<UserVmVO> sc = listByUserdataId.create();
|
||||
sc.setParameters("userDataId", userdataId);
|
||||
return listBy(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,6 +183,7 @@
|
||||
<bean id="resourceTagsDaoImpl" class="com.cloud.tags.dao.ResourceTagsDaoImpl" />
|
||||
<bean id="routerNetworkDaoImpl" class="com.cloud.network.dao.RouterNetworkDaoImpl" />
|
||||
<bean id="sSHKeyPairDaoImpl" class="com.cloud.user.dao.SSHKeyPairDaoImpl" />
|
||||
<bean id="userDataDaoImpl" class="com.cloud.user.dao.UserDataDaoImpl" />
|
||||
<bean id="secondaryStorageVmDaoImpl" class="com.cloud.vm.dao.SecondaryStorageVmDaoImpl" />
|
||||
<bean id="securityGroupDaoImpl" class="com.cloud.network.security.dao.SecurityGroupDaoImpl" />
|
||||
<bean id="securityGroupJoinDaoImpl" class="com.cloud.api.query.dao.SecurityGroupJoinDaoImpl" />
|
||||
|
||||
@ -251,3 +251,327 @@ DELETE role_perm
|
||||
FROM role_permissions role_perm
|
||||
INNER JOIN roles ON role_perm.role_id = roles.id
|
||||
WHERE roles.role_type != 'Admin' AND roles.is_default = 1 AND role_perm.rule = 'migrateVolume';
|
||||
|
||||
CREATE TABLE `cloud`.`user_data` (
|
||||
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
|
||||
`uuid` varchar(40) NOT NULL COMMENT 'UUID of the user data',
|
||||
`name` varchar(256) NOT NULL COMMENT 'name of the user data',
|
||||
`account_id` bigint unsigned NOT NULL COMMENT 'owner, foreign key to account table',
|
||||
`domain_id` bigint unsigned NOT NULL COMMENT 'domain, foreign key to domain table',
|
||||
`user_data` mediumtext COMMENT 'value of the userdata',
|
||||
`params` mediumtext COMMENT 'value of the comma-separated list of parameters',
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_userdata__account_id` FOREIGN KEY(`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_userdata__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `uc_userdata__uuid` UNIQUE (`uuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
ALTER TABLE `cloud`.`user_vm` ADD COLUMN `user_data_id` bigint unsigned DEFAULT NULL COMMENT 'id of the user data' AFTER `user_data`;
|
||||
ALTER TABLE `cloud`.`user_vm` ADD COLUMN `user_data_details` mediumtext DEFAULT NULL COMMENT 'value of the comma-separated list of parameters' AFTER `user_data_id`;
|
||||
ALTER TABLE `cloud`.`user_vm` ADD CONSTRAINT `fk_user_vm__user_data_id` FOREIGN KEY `fk_user_vm__user_data_id`(`user_data_id`) REFERENCES `user_data`(`id`);
|
||||
|
||||
ALTER TABLE `cloud`.`vm_template` ADD COLUMN `user_data_id` bigint unsigned DEFAULT NULL COMMENT 'id of the user data';
|
||||
ALTER TABLE `cloud`.`vm_template` ADD COLUMN `user_data_link_policy` varchar(255) DEFAULT NULL COMMENT 'user data link policy with template';
|
||||
ALTER TABLE `cloud`.`vm_template` ADD CONSTRAINT `fk_vm_template__user_data_id` FOREIGN KEY `fk_vm_template__user_data_id`(`user_data_id`) REFERENCES `user_data`(`id`);
|
||||
|
||||
-- Added userdata details to template
|
||||
DROP VIEW IF EXISTS `cloud`.`template_view`;
|
||||
CREATE VIEW `cloud`.`template_view` AS
|
||||
SELECT
|
||||
`vm_template`.`id` AS `id`,
|
||||
`vm_template`.`uuid` AS `uuid`,
|
||||
`vm_template`.`unique_name` AS `unique_name`,
|
||||
`vm_template`.`name` AS `name`,
|
||||
`vm_template`.`public` AS `public`,
|
||||
`vm_template`.`featured` AS `featured`,
|
||||
`vm_template`.`type` AS `type`,
|
||||
`vm_template`.`hvm` AS `hvm`,
|
||||
`vm_template`.`bits` AS `bits`,
|
||||
`vm_template`.`url` AS `url`,
|
||||
`vm_template`.`format` AS `format`,
|
||||
`vm_template`.`created` AS `created`,
|
||||
`vm_template`.`checksum` AS `checksum`,
|
||||
`vm_template`.`display_text` AS `display_text`,
|
||||
`vm_template`.`enable_password` AS `enable_password`,
|
||||
`vm_template`.`dynamically_scalable` AS `dynamically_scalable`,
|
||||
`vm_template`.`state` AS `template_state`,
|
||||
`vm_template`.`guest_os_id` AS `guest_os_id`,
|
||||
`guest_os`.`uuid` AS `guest_os_uuid`,
|
||||
`guest_os`.`display_name` AS `guest_os_name`,
|
||||
`vm_template`.`bootable` AS `bootable`,
|
||||
`vm_template`.`prepopulate` AS `prepopulate`,
|
||||
`vm_template`.`cross_zones` AS `cross_zones`,
|
||||
`vm_template`.`hypervisor_type` AS `hypervisor_type`,
|
||||
`vm_template`.`extractable` AS `extractable`,
|
||||
`vm_template`.`template_tag` AS `template_tag`,
|
||||
`vm_template`.`sort_key` AS `sort_key`,
|
||||
`vm_template`.`removed` AS `removed`,
|
||||
`vm_template`.`enable_sshkey` AS `enable_sshkey`,
|
||||
`parent_template`.`id` AS `parent_template_id`,
|
||||
`parent_template`.`uuid` AS `parent_template_uuid`,
|
||||
`source_template`.`id` AS `source_template_id`,
|
||||
`source_template`.`uuid` AS `source_template_uuid`,
|
||||
`account`.`id` AS `account_id`,
|
||||
`account`.`uuid` AS `account_uuid`,
|
||||
`account`.`account_name` AS `account_name`,
|
||||
`account`.`type` AS `account_type`,
|
||||
`domain`.`id` AS `domain_id`,
|
||||
`domain`.`uuid` AS `domain_uuid`,
|
||||
`domain`.`name` AS `domain_name`,
|
||||
`domain`.`path` AS `domain_path`,
|
||||
`projects`.`id` AS `project_id`,
|
||||
`projects`.`uuid` AS `project_uuid`,
|
||||
`projects`.`name` AS `project_name`,
|
||||
`data_center`.`id` AS `data_center_id`,
|
||||
`data_center`.`uuid` AS `data_center_uuid`,
|
||||
`data_center`.`name` AS `data_center_name`,
|
||||
`launch_permission`.`account_id` AS `lp_account_id`,
|
||||
`template_store_ref`.`store_id` AS `store_id`,
|
||||
`image_store`.`scope` AS `store_scope`,
|
||||
`template_store_ref`.`state` AS `state`,
|
||||
`template_store_ref`.`download_state` AS `download_state`,
|
||||
`template_store_ref`.`download_pct` AS `download_pct`,
|
||||
`template_store_ref`.`error_str` AS `error_str`,
|
||||
`template_store_ref`.`size` AS `size`,
|
||||
`template_store_ref`.physical_size AS `physical_size`,
|
||||
`template_store_ref`.`destroyed` AS `destroyed`,
|
||||
`template_store_ref`.`created` AS `created_on_store`,
|
||||
`vm_template_details`.`name` AS `detail_name`,
|
||||
`vm_template_details`.`value` AS `detail_value`,
|
||||
`resource_tags`.`id` AS `tag_id`,
|
||||
`resource_tags`.`uuid` AS `tag_uuid`,
|
||||
`resource_tags`.`key` AS `tag_key`,
|
||||
`resource_tags`.`value` AS `tag_value`,
|
||||
`resource_tags`.`domain_id` AS `tag_domain_id`,
|
||||
`domain`.`uuid` AS `tag_domain_uuid`,
|
||||
`domain`.`name` AS `tag_domain_name`,
|
||||
`resource_tags`.`account_id` AS `tag_account_id`,
|
||||
`account`.`account_name` AS `tag_account_name`,
|
||||
`resource_tags`.`resource_id` AS `tag_resource_id`,
|
||||
`resource_tags`.`resource_uuid` AS `tag_resource_uuid`,
|
||||
`resource_tags`.`resource_type` AS `tag_resource_type`,
|
||||
`resource_tags`.`customer` AS `tag_customer`,
|
||||
CONCAT(`vm_template`.`id`,
|
||||
'_',
|
||||
IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair`,
|
||||
`vm_template`.`direct_download` AS `direct_download`,
|
||||
`vm_template`.`deploy_as_is` AS `deploy_as_is`,
|
||||
`user_data`.`id` AS `user_data_id`,
|
||||
`user_data`.`uuid` AS `user_data_uuid`,
|
||||
`user_data`.`name` AS `user_data_name`,
|
||||
`user_data`.`params` AS `user_data_params`,
|
||||
`vm_template`.`user_data_link_policy` AS `user_data_policy`
|
||||
FROM
|
||||
(((((((((((((`vm_template`
|
||||
JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`)))
|
||||
JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`)))
|
||||
JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`)))
|
||||
LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`)))
|
||||
LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`)))
|
||||
LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`)))
|
||||
LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`)
|
||||
AND (`template_store_ref`.`store_role` = 'Image')
|
||||
AND (`template_store_ref`.`destroyed` = 0))))
|
||||
LEFT JOIN `vm_template` `parent_template` ON ((`parent_template`.`id` = `vm_template`.`parent_template_id`)))
|
||||
LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`)
|
||||
AND (`template_store_ref`.`store_id` IS NOT NULL)
|
||||
AND (`image_store`.`id` = `template_store_ref`.`store_id`))))
|
||||
LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`)
|
||||
AND ISNULL(`template_store_ref`.`store_id`)
|
||||
AND ISNULL(`template_zone_ref`.`removed`))))
|
||||
LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`)
|
||||
OR (`template_zone_ref`.`zone_id` = `data_center`.`id`))))
|
||||
LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`)))
|
||||
LEFT JOIN `user_data` ON ((`user_data`.`id` = `vm_template`.`user_data_id`))
|
||||
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`)
|
||||
AND ((`resource_tags`.`resource_type` = 'Template')
|
||||
OR (`resource_tags`.`resource_type` = 'ISO')))));
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`user_vm_view`;
|
||||
CREATE
|
||||
VIEW `user_vm_view` AS
|
||||
SELECT
|
||||
`vm_instance`.`id` AS `id`,
|
||||
`vm_instance`.`name` AS `name`,
|
||||
`user_vm`.`display_name` AS `display_name`,
|
||||
`user_vm`.`user_data` AS `user_data`,
|
||||
`account`.`id` AS `account_id`,
|
||||
`account`.`uuid` AS `account_uuid`,
|
||||
`account`.`account_name` AS `account_name`,
|
||||
`account`.`type` AS `account_type`,
|
||||
`domain`.`id` AS `domain_id`,
|
||||
`domain`.`uuid` AS `domain_uuid`,
|
||||
`domain`.`name` AS `domain_name`,
|
||||
`domain`.`path` AS `domain_path`,
|
||||
`projects`.`id` AS `project_id`,
|
||||
`projects`.`uuid` AS `project_uuid`,
|
||||
`projects`.`name` AS `project_name`,
|
||||
`instance_group`.`id` AS `instance_group_id`,
|
||||
`instance_group`.`uuid` AS `instance_group_uuid`,
|
||||
`instance_group`.`name` AS `instance_group_name`,
|
||||
`vm_instance`.`uuid` AS `uuid`,
|
||||
`vm_instance`.`user_id` AS `user_id`,
|
||||
`vm_instance`.`last_host_id` AS `last_host_id`,
|
||||
`vm_instance`.`vm_type` AS `type`,
|
||||
`vm_instance`.`limit_cpu_use` AS `limit_cpu_use`,
|
||||
`vm_instance`.`created` AS `created`,
|
||||
`vm_instance`.`state` AS `state`,
|
||||
`vm_instance`.`update_time` AS `update_time`,
|
||||
`vm_instance`.`removed` AS `removed`,
|
||||
`vm_instance`.`ha_enabled` AS `ha_enabled`,
|
||||
`vm_instance`.`hypervisor_type` AS `hypervisor_type`,
|
||||
`vm_instance`.`instance_name` AS `instance_name`,
|
||||
`vm_instance`.`guest_os_id` AS `guest_os_id`,
|
||||
`vm_instance`.`display_vm` AS `display_vm`,
|
||||
`guest_os`.`uuid` AS `guest_os_uuid`,
|
||||
`vm_instance`.`pod_id` AS `pod_id`,
|
||||
`host_pod_ref`.`uuid` AS `pod_uuid`,
|
||||
`vm_instance`.`private_ip_address` AS `private_ip_address`,
|
||||
`vm_instance`.`private_mac_address` AS `private_mac_address`,
|
||||
`vm_instance`.`vm_type` AS `vm_type`,
|
||||
`data_center`.`id` AS `data_center_id`,
|
||||
`data_center`.`uuid` AS `data_center_uuid`,
|
||||
`data_center`.`name` AS `data_center_name`,
|
||||
`data_center`.`is_security_group_enabled` AS `security_group_enabled`,
|
||||
`data_center`.`networktype` AS `data_center_type`,
|
||||
`host`.`id` AS `host_id`,
|
||||
`host`.`uuid` AS `host_uuid`,
|
||||
`host`.`name` AS `host_name`,
|
||||
`host`.`cluster_id` AS `cluster_id`,
|
||||
`vm_template`.`id` AS `template_id`,
|
||||
`vm_template`.`uuid` AS `template_uuid`,
|
||||
`vm_template`.`name` AS `template_name`,
|
||||
`vm_template`.`display_text` AS `template_display_text`,
|
||||
`vm_template`.`enable_password` AS `password_enabled`,
|
||||
`iso`.`id` AS `iso_id`,
|
||||
`iso`.`uuid` AS `iso_uuid`,
|
||||
`iso`.`name` AS `iso_name`,
|
||||
`iso`.`display_text` AS `iso_display_text`,
|
||||
`service_offering`.`id` AS `service_offering_id`,
|
||||
`service_offering`.`uuid` AS `service_offering_uuid`,
|
||||
`disk_offering`.`uuid` AS `disk_offering_uuid`,
|
||||
`disk_offering`.`id` AS `disk_offering_id`,
|
||||
(CASE
|
||||
WHEN ISNULL(`service_offering`.`cpu`) THEN `custom_cpu`.`value`
|
||||
ELSE `service_offering`.`cpu`
|
||||
END) AS `cpu`,
|
||||
(CASE
|
||||
WHEN ISNULL(`service_offering`.`speed`) THEN `custom_speed`.`value`
|
||||
ELSE `service_offering`.`speed`
|
||||
END) AS `speed`,
|
||||
(CASE
|
||||
WHEN ISNULL(`service_offering`.`ram_size`) THEN `custom_ram_size`.`value`
|
||||
ELSE `service_offering`.`ram_size`
|
||||
END) AS `ram_size`,
|
||||
`backup_offering`.`uuid` AS `backup_offering_uuid`,
|
||||
`backup_offering`.`id` AS `backup_offering_id`,
|
||||
`service_offering`.`name` AS `service_offering_name`,
|
||||
`disk_offering`.`name` AS `disk_offering_name`,
|
||||
`backup_offering`.`name` AS `backup_offering_name`,
|
||||
`storage_pool`.`id` AS `pool_id`,
|
||||
`storage_pool`.`uuid` AS `pool_uuid`,
|
||||
`storage_pool`.`pool_type` AS `pool_type`,
|
||||
`volumes`.`id` AS `volume_id`,
|
||||
`volumes`.`uuid` AS `volume_uuid`,
|
||||
`volumes`.`device_id` AS `volume_device_id`,
|
||||
`volumes`.`volume_type` AS `volume_type`,
|
||||
`security_group`.`id` AS `security_group_id`,
|
||||
`security_group`.`uuid` AS `security_group_uuid`,
|
||||
`security_group`.`name` AS `security_group_name`,
|
||||
`security_group`.`description` AS `security_group_description`,
|
||||
`nics`.`id` AS `nic_id`,
|
||||
`nics`.`uuid` AS `nic_uuid`,
|
||||
`nics`.`device_id` AS `nic_device_id`,
|
||||
`nics`.`network_id` AS `network_id`,
|
||||
`nics`.`ip4_address` AS `ip_address`,
|
||||
`nics`.`ip6_address` AS `ip6_address`,
|
||||
`nics`.`ip6_gateway` AS `ip6_gateway`,
|
||||
`nics`.`ip6_cidr` AS `ip6_cidr`,
|
||||
`nics`.`default_nic` AS `is_default_nic`,
|
||||
`nics`.`gateway` AS `gateway`,
|
||||
`nics`.`netmask` AS `netmask`,
|
||||
`nics`.`mac_address` AS `mac_address`,
|
||||
`nics`.`broadcast_uri` AS `broadcast_uri`,
|
||||
`nics`.`isolation_uri` AS `isolation_uri`,
|
||||
`vpc`.`id` AS `vpc_id`,
|
||||
`vpc`.`uuid` AS `vpc_uuid`,
|
||||
`networks`.`uuid` AS `network_uuid`,
|
||||
`networks`.`name` AS `network_name`,
|
||||
`networks`.`traffic_type` AS `traffic_type`,
|
||||
`networks`.`guest_type` AS `guest_type`,
|
||||
`user_ip_address`.`id` AS `public_ip_id`,
|
||||
`user_ip_address`.`uuid` AS `public_ip_uuid`,
|
||||
`user_ip_address`.`public_ip_address` AS `public_ip_address`,
|
||||
`ssh_details`.`value` AS `keypair_names`,
|
||||
`resource_tags`.`id` AS `tag_id`,
|
||||
`resource_tags`.`uuid` AS `tag_uuid`,
|
||||
`resource_tags`.`key` AS `tag_key`,
|
||||
`resource_tags`.`value` AS `tag_value`,
|
||||
`resource_tags`.`domain_id` AS `tag_domain_id`,
|
||||
`domain`.`uuid` AS `tag_domain_uuid`,
|
||||
`domain`.`name` AS `tag_domain_name`,
|
||||
`resource_tags`.`account_id` AS `tag_account_id`,
|
||||
`account`.`account_name` AS `tag_account_name`,
|
||||
`resource_tags`.`resource_id` AS `tag_resource_id`,
|
||||
`resource_tags`.`resource_uuid` AS `tag_resource_uuid`,
|
||||
`resource_tags`.`resource_type` AS `tag_resource_type`,
|
||||
`resource_tags`.`customer` AS `tag_customer`,
|
||||
`async_job`.`id` AS `job_id`,
|
||||
`async_job`.`uuid` AS `job_uuid`,
|
||||
`async_job`.`job_status` AS `job_status`,
|
||||
`async_job`.`account_id` AS `job_account_id`,
|
||||
`affinity_group`.`id` AS `affinity_group_id`,
|
||||
`affinity_group`.`uuid` AS `affinity_group_uuid`,
|
||||
`affinity_group`.`name` AS `affinity_group_name`,
|
||||
`affinity_group`.`description` AS `affinity_group_description`,
|
||||
`vm_instance`.`dynamically_scalable` AS `dynamically_scalable`,
|
||||
`user_data`.`id` AS `user_data_id`,
|
||||
`user_data`.`uuid` AS `user_data_uuid`,
|
||||
`user_data`.`name` AS `user_data_name`,
|
||||
`user_vm`.`user_data_details` AS `user_data_details`,
|
||||
`vm_template`.`user_data_link_policy` AS `user_data_policy`
|
||||
FROM
|
||||
(((((((((((((((((((((((((((((((((`user_vm`
|
||||
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
|
||||
AND ISNULL(`vm_instance`.`removed`))))
|
||||
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
|
||||
JOIN `domain` ON ((`vm_instance`.`domain_id` = `domain`.`id`)))
|
||||
LEFT JOIN `guest_os` ON ((`vm_instance`.`guest_os_id` = `guest_os`.`id`)))
|
||||
LEFT JOIN `host_pod_ref` ON ((`vm_instance`.`pod_id` = `host_pod_ref`.`id`)))
|
||||
LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`)))
|
||||
LEFT JOIN `instance_group_vm_map` ON ((`vm_instance`.`id` = `instance_group_vm_map`.`instance_id`)))
|
||||
LEFT JOIN `instance_group` ON ((`instance_group_vm_map`.`group_id` = `instance_group`.`id`)))
|
||||
LEFT JOIN `data_center` ON ((`vm_instance`.`data_center_id` = `data_center`.`id`)))
|
||||
LEFT JOIN `host` ON ((`vm_instance`.`host_id` = `host`.`id`)))
|
||||
LEFT JOIN `vm_template` ON ((`vm_instance`.`vm_template_id` = `vm_template`.`id`)))
|
||||
LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `user_vm`.`iso_id`)))
|
||||
LEFT JOIN `volumes` ON ((`vm_instance`.`id` = `volumes`.`instance_id`)))
|
||||
LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`)))
|
||||
LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`volumes`.`disk_offering_id` = `svc_disk_offering`.`id`)))
|
||||
LEFT JOIN `disk_offering` ON ((`volumes`.`disk_offering_id` = `disk_offering`.`id`)))
|
||||
LEFT JOIN `backup_offering` ON ((`vm_instance`.`backup_offering_id` = `backup_offering`.`id`)))
|
||||
LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`)))
|
||||
LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`)))
|
||||
LEFT JOIN `security_group` ON ((`security_group_vm_map`.`security_group_id` = `security_group`.`id`)))
|
||||
LEFT JOIN `user_data` ON ((`user_data`.`id` = `user_vm`.`user_data_id`)))
|
||||
LEFT JOIN `nics` ON (((`vm_instance`.`id` = `nics`.`instance_id`)
|
||||
AND ISNULL(`nics`.`removed`))))
|
||||
LEFT JOIN `networks` ON ((`nics`.`network_id` = `networks`.`id`)))
|
||||
LEFT JOIN `vpc` ON (((`networks`.`vpc_id` = `vpc`.`id`)
|
||||
AND ISNULL(`vpc`.`removed`))))
|
||||
LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`)))
|
||||
LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`)
|
||||
AND (`ssh_details`.`name` = 'SSH.KeyPairNames'))))
|
||||
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`)
|
||||
AND (`resource_tags`.`resource_type` = 'UserVm'))))
|
||||
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`)
|
||||
AND (`async_job`.`instance_type` = 'VirtualMachine')
|
||||
AND (`async_job`.`job_status` = 0))))
|
||||
LEFT JOIN `affinity_group_vm_map` ON ((`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`)))
|
||||
LEFT JOIN `affinity_group` ON ((`affinity_group_vm_map`.`affinity_group_id` = `affinity_group`.`id`)))
|
||||
LEFT JOIN `user_vm_details` `custom_cpu` ON (((`custom_cpu`.`vm_id` = `vm_instance`.`id`)
|
||||
AND (`custom_cpu`.`name` = 'CpuNumber'))))
|
||||
LEFT JOIN `user_vm_details` `custom_speed` ON (((`custom_speed`.`vm_id` = `vm_instance`.`id`)
|
||||
AND (`custom_speed`.`name` = 'CpuSpeed'))))
|
||||
LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`)
|
||||
AND (`custom_ram_size`.`name` = 'memory'))));
|
||||
|
||||
@ -30,8 +30,11 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
@ -91,7 +94,7 @@ public class ConfigDriveBuilder {
|
||||
* This method will build the metadata files required by OpenStack driver. Then, an ISO is going to be generated and returned as a String in base 64.
|
||||
* If vmData is null, we throw a {@link CloudRuntimeException}. Moreover, {@link IOException} are captured and re-thrown as {@link CloudRuntimeException}.
|
||||
*/
|
||||
public static String buildConfigDrive(List<String[]> vmData, String isoFileName, String driveLabel) {
|
||||
public static String buildConfigDrive(List<String[]> vmData, String isoFileName, String driveLabel, Map<String, String> customUserdataParams) {
|
||||
if (vmData == null) {
|
||||
throw new CloudRuntimeException("No VM metadata provided");
|
||||
}
|
||||
@ -105,7 +108,7 @@ public class ConfigDriveBuilder {
|
||||
File openStackFolder = new File(tempDirName + ConfigDrive.openStackConfigDriveName);
|
||||
|
||||
writeVendorAndNetworkEmptyJsonFile(openStackFolder);
|
||||
writeVmMetadata(vmData, tempDirName, openStackFolder);
|
||||
writeVmMetadata(vmData, tempDirName, openStackFolder, customUserdataParams);
|
||||
|
||||
linkUserData(tempDirName);
|
||||
|
||||
@ -187,10 +190,10 @@ public class ConfigDriveBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* First we generate a JSON object using {@link #createJsonObjectWithVmData(List, String)}, then we write it to a file called "meta_data.json".
|
||||
* First we generate a JSON object using {@link #createJsonObjectWithVmData(List, String, Map)}, then we write it to a file called "meta_data.json".
|
||||
*/
|
||||
static void writeVmMetadata(List<String[]> vmData, String tempDirName, File openStackFolder) {
|
||||
JsonObject metaData = createJsonObjectWithVmData(vmData, tempDirName);
|
||||
static void writeVmMetadata(List<String[]> vmData, String tempDirName, File openStackFolder, Map<String, String> customUserdataParams) {
|
||||
JsonObject metaData = createJsonObjectWithVmData(vmData, tempDirName, customUserdataParams);
|
||||
writeFile(openStackFolder, "meta_data.json", metaData.toString());
|
||||
}
|
||||
|
||||
@ -220,7 +223,7 @@ public class ConfigDriveBuilder {
|
||||
* <li> [2]: config data file content
|
||||
* </ul>
|
||||
*/
|
||||
static JsonObject createJsonObjectWithVmData(List<String[]> vmData, String tempDirName) {
|
||||
static JsonObject createJsonObjectWithVmData(List<String[]> vmData, String tempDirName, Map<String, String> customUserdataParams) {
|
||||
JsonObject metaData = new JsonObject();
|
||||
for (String[] item : vmData) {
|
||||
String dataType = item[CONFIGDATA_DIR];
|
||||
@ -228,12 +231,12 @@ public class ConfigDriveBuilder {
|
||||
String content = item[CONFIGDATA_CONTENT];
|
||||
LOG.debug(String.format("[createConfigDriveIsoForVM] dataType=%s, filename=%s, content=%s", dataType, fileName, (PASSWORD_FILE.equals(fileName) ? "********" : content)));
|
||||
|
||||
createFileInTempDirAnAppendOpenStackMetadataToJsonObject(tempDirName, metaData, dataType, fileName, content);
|
||||
createFileInTempDirAnAppendOpenStackMetadataToJsonObject(tempDirName, metaData, dataType, fileName, content, customUserdataParams);
|
||||
}
|
||||
return metaData;
|
||||
}
|
||||
|
||||
static void createFileInTempDirAnAppendOpenStackMetadataToJsonObject(String tempDirName, JsonObject metaData, String dataType, String fileName, String content) {
|
||||
static void createFileInTempDirAnAppendOpenStackMetadataToJsonObject(String tempDirName, JsonObject metaData, String dataType, String fileName, String content, Map<String, String> customUserdataParams) {
|
||||
if (StringUtils.isBlank(dataType)) {
|
||||
return;
|
||||
}
|
||||
@ -258,6 +261,22 @@ public class ConfigDriveBuilder {
|
||||
|
||||
//now write the file to the OpenStack directory
|
||||
buildOpenStackMetaData(metaData, dataType, fileName, content);
|
||||
buildCustomUserdataParamsMetaData(metaData, dataType, fileName, content, customUserdataParams);
|
||||
}
|
||||
|
||||
protected static void buildCustomUserdataParamsMetaData(JsonObject metaData, String dataType, String fileName, String content, Map<String, String> customUserdataParams) {
|
||||
if (!NetworkModel.METATDATA_DIR.equals(dataType)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(content)) {
|
||||
return;
|
||||
}
|
||||
if (MapUtils.isNotEmpty(customUserdataParams)) {
|
||||
Set<String> userdataVariableFileNames = customUserdataParams.keySet();
|
||||
if (userdataVariableFileNames.contains(fileName)) {
|
||||
metaData.addProperty(fileName, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.cloudstack.storage.configdrive;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.times;
|
||||
@ -28,7 +29,9 @@ import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -124,7 +127,7 @@ public class ConfigDriveBuilderTest {
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void buildConfigDriveTestNoVmData() {
|
||||
ConfigDriveBuilder.buildConfigDrive(null, "teste", "C:");
|
||||
ConfigDriveBuilder.buildConfigDrive(null, "teste", "C:", null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -140,9 +143,9 @@ public class ConfigDriveBuilderTest {
|
||||
|
||||
//This is odd, but it was necessary to allow us to check if we catch the IOexception and re-throw as a CloudRuntimeException
|
||||
//We are mocking the class being tested; therefore, we needed to force the execution of the real method we want to test.
|
||||
PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:").thenCallRealMethod();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:", null).thenCallRealMethod();
|
||||
|
||||
ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:");
|
||||
ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -155,7 +158,7 @@ public class ConfigDriveBuilderTest {
|
||||
PowerMockito.doNothing().when(ConfigDriveBuilder.class, writeVendorAndNetworkEmptyJsonFileMethod).withArguments(Mockito.any(File.class));
|
||||
|
||||
Method writeVmMetadataMethod = getWriteVmMetadataMethod();
|
||||
PowerMockito.doNothing().when(ConfigDriveBuilder.class, writeVmMetadataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class));
|
||||
PowerMockito.doNothing().when(ConfigDriveBuilder.class, writeVmMetadataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class), anyMap());
|
||||
|
||||
Method linkUserDataMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("linkUserData")).iterator().next();
|
||||
PowerMockito.doNothing().when(ConfigDriveBuilder.class, linkUserDataMethod).withArguments(Mockito.anyString());
|
||||
@ -164,15 +167,15 @@ public class ConfigDriveBuilderTest {
|
||||
PowerMockito.doReturn("mockIsoDataBase64").when(ConfigDriveBuilder.class, generateAndRetrieveIsoAsBase64IsoMethod).withArguments(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
|
||||
|
||||
//force execution of real method
|
||||
PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:").thenCallRealMethod();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, new ArrayList<>(), "teste", "C:", null).thenCallRealMethod();
|
||||
|
||||
String returnedIsoData = ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:");
|
||||
String returnedIsoData = ConfigDriveBuilder.buildConfigDrive(new ArrayList<>(), "teste", "C:", null);
|
||||
|
||||
Assert.assertEquals("mockIsoDataBase64", returnedIsoData);
|
||||
|
||||
PowerMockito.verifyStatic(ConfigDriveBuilder.class);
|
||||
ConfigDriveBuilder.writeVendorAndNetworkEmptyJsonFile(Mockito.any(File.class));
|
||||
ConfigDriveBuilder.writeVmMetadata(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class));
|
||||
ConfigDriveBuilder.writeVmMetadata(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.any(File.class), anyMap());
|
||||
ConfigDriveBuilder.linkUserData(Mockito.anyString());
|
||||
ConfigDriveBuilder.generateAndRetrieveIsoAsBase64Iso(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
@ -233,20 +236,20 @@ public class ConfigDriveBuilderTest {
|
||||
PowerMockito.mockStatic(ConfigDriveBuilder.class);
|
||||
|
||||
Method method = getWriteVmMetadataMethod();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), anyString(), any(File.class)).thenCallRealMethod();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), anyString(), any(File.class), anyMap()).thenCallRealMethod();
|
||||
|
||||
Method createJsonObjectWithVmDataMethod = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("createJsonObjectWithVmData")).iterator().next();
|
||||
|
||||
PowerMockito.when(ConfigDriveBuilder.class, createJsonObjectWithVmDataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString()).thenReturn(new JsonObject());
|
||||
PowerMockito.when(ConfigDriveBuilder.class, createJsonObjectWithVmDataMethod).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyMap()).thenReturn(new JsonObject());
|
||||
|
||||
List<String[]> vmData = new ArrayList<>();
|
||||
vmData.add(new String[] {"dataType", "fileName", "content"});
|
||||
vmData.add(new String[] {"dataType2", "fileName2", "content2"});
|
||||
|
||||
ConfigDriveBuilder.writeVmMetadata(vmData, "metadataFile", new File("folder"));
|
||||
ConfigDriveBuilder.writeVmMetadata(vmData, "metadataFile", new File("folder"), new HashMap<>());
|
||||
|
||||
PowerMockito.verifyStatic(ConfigDriveBuilder.class);
|
||||
ConfigDriveBuilder.createJsonObjectWithVmData(vmData, "metadataFile");
|
||||
ConfigDriveBuilder.createJsonObjectWithVmData(vmData, "metadataFile", new HashMap<>());
|
||||
ConfigDriveBuilder.writeFile(Mockito.any(File.class), Mockito.eq("meta_data.json"), Mockito.eq("{}"));
|
||||
}
|
||||
|
||||
@ -398,19 +401,58 @@ public class ConfigDriveBuilderTest {
|
||||
PowerMockito.mockStatic(ConfigDriveBuilder.class);
|
||||
|
||||
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("createJsonObjectWithVmData")).iterator().next();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString()).thenCallRealMethod();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.nullable(Map.class)).thenCallRealMethod();
|
||||
|
||||
List<String[]> vmData = new ArrayList<>();
|
||||
vmData.add(new String[] {"dataType", "fileName", "content"});
|
||||
vmData.add(new String[] {"dataType2", "fileName2", "content2"});
|
||||
|
||||
ConfigDriveBuilder.createJsonObjectWithVmData(vmData, "tempDirName");
|
||||
ConfigDriveBuilder.createJsonObjectWithVmData(vmData, "tempDirName", new HashMap<>());
|
||||
|
||||
PowerMockito.verifyStatic(ConfigDriveBuilder.class, Mockito.times(1));
|
||||
ConfigDriveBuilder.createFileInTempDirAnAppendOpenStackMetadataToJsonObject(Mockito.eq("tempDirName"), Mockito.any(JsonObject.class), Mockito.eq("dataType"), Mockito.eq("fileName"),
|
||||
Mockito.eq("content"));
|
||||
Mockito.eq("content"), Mockito.anyMap());
|
||||
ConfigDriveBuilder.createFileInTempDirAnAppendOpenStackMetadataToJsonObject(Mockito.eq("tempDirName"), Mockito.any(JsonObject.class), Mockito.eq("dataType2"), Mockito.eq("fileName2"),
|
||||
Mockito.eq("content2"));
|
||||
Mockito.eq("content2"), Mockito.anyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@PrepareForTest({ConfigDriveBuilder.class})
|
||||
public void buildCustomUserdataParamsMetadataTestNullContent() throws Exception {
|
||||
PowerMockito.mockStatic(ConfigDriveBuilder.class);
|
||||
|
||||
JsonObject metadata = new JsonObject();
|
||||
String dataType = "dataType1";
|
||||
String fileName = "testFileName";
|
||||
String content = null;
|
||||
Map<String, String> customUserdataParams = new HashMap<>();
|
||||
customUserdataParams.put(fileName, content);
|
||||
|
||||
PowerMockito.when(ConfigDriveBuilder.class, metadata, dataType, fileName, content, customUserdataParams).thenCallRealMethod();
|
||||
|
||||
ConfigDriveBuilder.buildCustomUserdataParamsMetaData(metadata, dataType, fileName, content, customUserdataParams);
|
||||
|
||||
Assert.assertEquals(null, metadata.getAsJsonPrimitive(fileName));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@PrepareForTest({ConfigDriveBuilder.class})
|
||||
public void buildCustomUserdataParamsMetadataTestWithContent() throws Exception {
|
||||
PowerMockito.mockStatic(ConfigDriveBuilder.class);
|
||||
|
||||
JsonObject metadata = new JsonObject();
|
||||
String dataType = "metadata";
|
||||
String fileName = "testFileName";
|
||||
String content = "testContent";
|
||||
Map<String, String> customUserdataParams = new HashMap<>();
|
||||
customUserdataParams.put(fileName, content);
|
||||
|
||||
PowerMockito.when(ConfigDriveBuilder.class, metadata, dataType, fileName, content, customUserdataParams).thenCallRealMethod();
|
||||
ConfigDriveBuilder.buildCustomUserdataParamsMetaData(metadata, dataType, fileName, content, customUserdataParams);
|
||||
|
||||
Assert.assertEquals(content, metadata.getAsJsonPrimitive(fileName).getAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -23,6 +23,7 @@ import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
||||
@ -327,6 +328,16 @@ public class TemplateObject implements TemplateInfo {
|
||||
return deployAsIsConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getUserDataId() {
|
||||
return imageVO.getUserDataId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserData.UserDataOverridePolicy getUserDataOverridePolicy() {
|
||||
return imageVO.getUserDataOverridePolicy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTO getTO() {
|
||||
DataTO to = null;
|
||||
|
||||
@ -677,7 +677,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
||||
vmInternalName, id, vmInternalName, templateId, guestOsId, serviceOfferingId));
|
||||
|
||||
UserVmVO vmInstanceVO = new UserVmVO(id, vmInternalName, vmInternalName, templateId, HypervisorType.VMware, guestOsId, false, false, domainId, accountId, userId,
|
||||
serviceOfferingId, null, vmInternalName);
|
||||
serviceOfferingId, null, null, null, vmInternalName);
|
||||
vmInstanceVO.setDataCenterId(zoneId);
|
||||
return userVmDao.persist(vmInstanceVO);
|
||||
}
|
||||
|
||||
@ -387,13 +387,13 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
||||
List<Long> securityGroupIds = new ArrayList<>();
|
||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||
nodeVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, securityGroupIds, owner,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, keypairs,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||
null, addrs, null, null, null, customParameterMap, null, null, null,
|
||||
null, true, null, UserVmManager.CKS_NODE);
|
||||
} else {
|
||||
nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
|
||||
hostName, hostName, null, null, null,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||
null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
|
||||
}
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
|
||||
@ -221,13 +221,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
||||
List<Long> securityGroupIds = new ArrayList<>();
|
||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||
controlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, securityGroupIds, owner,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, keypairs,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||
requestedIps, addrs, null, null, null, customParameterMap, null, null, null,
|
||||
null, true, null, UserVmManager.CKS_NODE);
|
||||
} else {
|
||||
controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
|
||||
hostName, hostName, null, null, null,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||
requestedIps, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
|
||||
}
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
@ -295,13 +295,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
||||
List<Long> securityGroupIds = new ArrayList<>();
|
||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||
additionalControlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, securityGroupIds, owner,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, keypairs,
|
||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||
null, addrs, null, null, null, customParameterMap, null, null, null,
|
||||
null, true, null, UserVmManager.CKS_NODE);
|
||||
} else {
|
||||
additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
|
||||
hostName, hostName, null, null, null,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
|
||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||
null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,6 @@ import com.cloud.vm.UserVmVO;
|
||||
public class ServiceVirtualMachine extends UserVmVO {
|
||||
public ServiceVirtualMachine(long id, String instanceName, String name, long templateId, long serviceOfferingId, HypervisorType hypervisorType, long guestOSId,
|
||||
long dataCenterId, long domainId, long accountId, long userId, boolean haEnabled) {
|
||||
super(id, instanceName, name, templateId, hypervisorType, guestOSId, false, false, domainId, accountId, userId, serviceOfferingId, null, name);
|
||||
super(id, instanceName, name, templateId, hypervisorType, guestOSId, false, false, domainId, accountId, userId, serviceOfferingId, null, null, null, name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ public class ManagementServerMock {
|
||||
long id = _userVmDao.getNextInSequence(Long.class, "id");
|
||||
UserVmVO vm =
|
||||
new UserVmVO(id, name, name, tmpl.getId(), HypervisorType.XenServer, tmpl.getGuestOSId(), false, false, _zone.getDomainId(), Account.ACCOUNT_ID_SYSTEM,
|
||||
1, small.getId(), null, name);
|
||||
1, small.getId(), null, null, null, name);
|
||||
vm.setState(com.cloud.vm.VirtualMachine.State.Running);
|
||||
vm.setHostId(_hostId);
|
||||
vm.setDataCenterId(network.getDataCenterId());
|
||||
|
||||
@ -37,6 +37,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.utils.security.CertificateHelper;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.api.query.dao.UserVmJoinDao;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
@ -156,6 +158,7 @@ import org.apache.cloudstack.api.response.TrafficMonitorResponse;
|
||||
import org.apache.cloudstack.api.response.TrafficTypeResponse;
|
||||
import org.apache.cloudstack.api.response.UpgradeRouterTemplateResponse;
|
||||
import org.apache.cloudstack.api.response.UsageRecordResponse;
|
||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||
import org.apache.cloudstack.api.response.UserResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
@ -370,7 +373,6 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.net.Dhcp;
|
||||
import com.cloud.utils.net.Ip;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.utils.security.CertificateHelper;
|
||||
import com.cloud.vm.ConsoleProxyVO;
|
||||
import com.cloud.vm.InstanceGroup;
|
||||
import com.cloud.vm.Nic;
|
||||
@ -4573,6 +4575,20 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDataResponse createUserDataResponse(UserData userData) {
|
||||
UserDataResponse response = new UserDataResponse(userData.getUuid(), userData.getName(), userData.getUserData(), userData.getParams());
|
||||
Account account = ApiDBUtils.findAccountById(userData.getAccountId());
|
||||
response.setAccountId(account.getUuid());
|
||||
response.setAccountName(account.getAccountName());
|
||||
Domain domain = ApiDBUtils.findDomainById(userData.getDomainId());
|
||||
response.setDomainId(domain.getUuid());
|
||||
response.setDomainName(domain.getName());
|
||||
response.setHasAnnotation(annotationDao.hasAnnotations(userData.getUuid(), AnnotationService.EntityType.USER_DATA.name(),
|
||||
_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupResponse createBackupResponse(Backup backup) {
|
||||
return ApiDBUtils.newBackupResponse(backup);
|
||||
|
||||
@ -29,6 +29,7 @@ import javax.inject.Inject;
|
||||
import com.cloud.deployasis.DeployAsIsConstants;
|
||||
import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
|
||||
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
@ -90,6 +91,8 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||
private TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
|
||||
@Inject
|
||||
private AnnotationDao annotationDao;
|
||||
@Inject
|
||||
private UserDataDao userDataDao;
|
||||
|
||||
private final SearchBuilder<TemplateJoinVO> tmpltIdPairSearch;
|
||||
|
||||
@ -290,6 +293,12 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||
templateResponse.setChildTemplates(childTemplatesSet);
|
||||
}
|
||||
|
||||
if (template.getUserDataId() != null) {
|
||||
templateResponse.setUserDataId(template.getUserDataUUid());
|
||||
templateResponse.setUserDataName(template.getUserDataName());
|
||||
templateResponse.setUserDataParams(template.getUserDataParams());
|
||||
templateResponse.setUserDataPolicy(template.getUserDataPolicy());
|
||||
}
|
||||
templateResponse.setObjectName("template");
|
||||
return templateResponse;
|
||||
}
|
||||
@ -338,6 +347,13 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||
response.setDetails(details);
|
||||
}
|
||||
|
||||
if (result.getUserDataId() != null) {
|
||||
response.setUserDataId(result.getUserDataUUid());
|
||||
response.setUserDataName(result.getUserDataName());
|
||||
response.setUserDataParams(result.getUserDataParams());
|
||||
response.setUserDataPolicy(result.getUserDataPolicy());
|
||||
}
|
||||
|
||||
// update tag information
|
||||
long tag_id = result.getTagId();
|
||||
if (tag_id > 0) {
|
||||
@ -451,6 +467,13 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||
isoResponse.setSize(isoSize);
|
||||
}
|
||||
|
||||
if (iso.getUserDataId() != null) {
|
||||
isoResponse.setUserDataId(iso.getUserDataUUid());
|
||||
isoResponse.setUserDataName(iso.getUserDataName());
|
||||
isoResponse.setUserDataParams(iso.getUserDataParams());
|
||||
isoResponse.setUserDataPolicy(iso.getUserDataPolicy());
|
||||
}
|
||||
|
||||
// update tag information
|
||||
long tag_id = iso.getTagId();
|
||||
if (tag_id > 0) {
|
||||
|
||||
@ -398,6 +398,13 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||
userVmResponse.setDynamicallyScalable(userVm.isDynamicallyScalable());
|
||||
}
|
||||
|
||||
if (userVm.getUserDataId() != null) {
|
||||
userVmResponse.setUserDataId(userVm.getUserDataUUid());
|
||||
userVmResponse.setUserDataName(userVm.getUserDataName());
|
||||
userVmResponse.setUserDataDetails(userVm.getUserDataDetails());
|
||||
userVmResponse.setUserDataPolicy(userVm.getUserDataPolicy());
|
||||
}
|
||||
|
||||
addVmRxTxDataToResponse(userVm, userVmResponse);
|
||||
|
||||
return userVmResponse;
|
||||
|
||||
@ -236,6 +236,21 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
||||
@Column(name = "deploy_as_is")
|
||||
private boolean deployAsIs;
|
||||
|
||||
@Column(name = "user_data_id")
|
||||
private Long userDataId;
|
||||
|
||||
@Column(name = "user_data_uuid")
|
||||
private String userDataUuid;
|
||||
|
||||
@Column(name = "user_data_name")
|
||||
private String userDataName;
|
||||
|
||||
@Column(name = "user_data_policy")
|
||||
private String userDataPolicy;
|
||||
|
||||
@Column(name = "user_data_params")
|
||||
private String userDataParams;
|
||||
|
||||
public TemplateJoinVO() {
|
||||
}
|
||||
|
||||
@ -507,4 +522,23 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
||||
return parentTemplateUuid;
|
||||
}
|
||||
|
||||
public Long getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
public String getUserDataUUid() {
|
||||
return userDataUuid;
|
||||
}
|
||||
|
||||
public String getUserDataName() {
|
||||
return userDataName;
|
||||
}
|
||||
|
||||
public String getUserDataPolicy() {
|
||||
return userDataPolicy;
|
||||
}
|
||||
|
||||
public String getUserDataParams() {
|
||||
return userDataParams;
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,6 +379,21 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
||||
@Column(name = "affinity_group_description")
|
||||
private String affinityGroupDescription;
|
||||
|
||||
@Column(name = "user_data_id")
|
||||
private Long userDataId;
|
||||
|
||||
@Column(name = "user_data_uuid")
|
||||
private String userDataUuid;
|
||||
|
||||
@Column(name = "user_data_name")
|
||||
private String userDataName;
|
||||
|
||||
@Column(name = "user_data_policy")
|
||||
private String userDataPolicy;
|
||||
|
||||
@Column(name = "user_data_details")
|
||||
private String userDataDetails;
|
||||
|
||||
transient String password;
|
||||
|
||||
@Transient
|
||||
@ -877,4 +892,24 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
||||
return VirtualMachine.class;
|
||||
}
|
||||
|
||||
public Long getUserDataId() {
|
||||
return userDataId;
|
||||
}
|
||||
|
||||
public String getUserDataUUid() {
|
||||
return userDataUuid;
|
||||
}
|
||||
|
||||
public String getUserDataName() {
|
||||
return userDataName;
|
||||
}
|
||||
|
||||
public String getUserDataPolicy() {
|
||||
return userDataPolicy;
|
||||
}
|
||||
|
||||
public String getUserDataDetails() {
|
||||
return userDataDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2549,7 +2549,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId,
|
||||
public List<String[]> generateVmData(String userData, String userDataDetails, String serviceOffering, long datacenterId,
|
||||
String vmName, String vmHostName, long vmId, String vmUuid,
|
||||
String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
|
||||
|
||||
@ -2572,6 +2572,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
||||
vmData.add(new String[]{METATDATA_DIR, LOCAL_HOSTNAME_FILE, StringUtils.unicodeEscape(vmHostName)});
|
||||
vmData.add(new String[]{METATDATA_DIR, LOCAL_IPV4_FILE, guestIpAddress});
|
||||
|
||||
addUserDataDetailsToCommand(vmData, userDataDetails);
|
||||
|
||||
String publicIpAddress = guestIpAddress;
|
||||
String publicHostName = StringUtils.unicodeEscape(vmHostName);
|
||||
|
||||
@ -2640,6 +2642,20 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
||||
return vmData;
|
||||
}
|
||||
|
||||
protected void addUserDataDetailsToCommand(List<String[]> vmData, String userDataDetails) {
|
||||
if(userDataDetails != null && !userDataDetails.isEmpty()) {
|
||||
userDataDetails = userDataDetails.substring(1, userDataDetails.length()-1);
|
||||
String[] keyValuePairs = userDataDetails.split(",");
|
||||
for(String pair : keyValuePairs)
|
||||
{
|
||||
String[] entry = pair.split("=");
|
||||
String key = entry[0].trim();
|
||||
String value = entry[1].trim();
|
||||
vmData.add(new String[]{METATDATA_DIR, key, StringUtils.unicodeEscape(value)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigComponentName() {
|
||||
return NetworkModel.class.getSimpleName();
|
||||
|
||||
@ -1330,17 +1330,17 @@ public class AutoScaleManagerImpl<Type> extends ManagerBase implements AutoScale
|
||||
if (zone.getNetworkType() == NetworkType.Basic) {
|
||||
vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
|
||||
getCurrentTimeStampString(),
|
||||
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null,
|
||||
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, null, null,
|
||||
null, true, null, null, null, null, null, null, null, true, null);
|
||||
} else {
|
||||
if (zone.isSecurityGroupEnabled()) {
|
||||
vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, null, null,
|
||||
owner, "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(),
|
||||
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null,null, null, true, null, null, null, null, null, null, null, true, null, null);
|
||||
"autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, null,null, null, true, null, null, null, null, null, null, null, true, null, null);
|
||||
} else {
|
||||
vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
|
||||
getCurrentTimeStampString(), "autoScaleVm-" + asGroup.getId() + "-" + getCurrentTimeStampString(),
|
||||
null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null, null, null, null, true, null, null);
|
||||
null, null, null, HypervisorType.XenServer, HTTPMethod.GET, null, null, null, null, null, addrs, true, null, null, null, null, null, null, null, true, null, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
|
||||
|
||||
if (userVm != null) {
|
||||
final boolean isWindows = isWindows(userVm.getGuestOSId());
|
||||
List<String[]> vmData = _networkModel.generateVmData(userVm.getUserData(), _serviceOfferingDao.findById(userVm.getServiceOfferingId()).getName(), userVm.getDataCenterId(), userVm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
List<String[]> vmData = _networkModel.generateVmData(userVm.getUserData(), userVm.getUserDataDetails(), _serviceOfferingDao.findById(userVm.getServiceOfferingId()).getName(), userVm.getDataCenterId(), userVm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
vm.getUuid(), nic.getMacAddress(), userVm.getDetail("SSH.PublicKey"), (String) vm.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, VirtualMachineManager.getHypervisorHostname(dest.getHost() != null ? dest.getHost().getName() : ""));
|
||||
vm.setVmData(vmData);
|
||||
vm.setConfigDriveLabel(VirtualMachineManager.VmConfigDriveLabel.value());
|
||||
@ -534,9 +534,11 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
|
||||
|
||||
LOG.debug("Creating config drive ISO for vm: " + profile.getInstanceName() + " on host: " + hostId);
|
||||
|
||||
Map<String, String> customUserdataParamMap = getVMCustomUserdataParamMap(profile.getId());
|
||||
|
||||
final String isoFileName = ConfigDrive.configIsoFileName(profile.getInstanceName());
|
||||
final String isoPath = ConfigDrive.createConfigDrivePath(profile.getInstanceName());
|
||||
final String isoData = ConfigDriveBuilder.buildConfigDrive(profile.getVmData(), isoFileName, profile.getConfigDriveLabel());
|
||||
final String isoData = ConfigDriveBuilder.buildConfigDrive(profile.getVmData(), isoFileName, profile.getConfigDriveLabel(), customUserdataParamMap);
|
||||
final HandleConfigDriveIsoCommand configDriveIsoCommand = new HandleConfigDriveIsoCommand(isoPath, isoData, null, false, true, true);
|
||||
|
||||
final HandleConfigDriveIsoAnswer answer = (HandleConfigDriveIsoAnswer) agentManager.easySend(hostId, configDriveIsoCommand);
|
||||
@ -593,9 +595,11 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
|
||||
|
||||
LOG.debug("Creating config drive ISO for vm: " + profile.getInstanceName());
|
||||
|
||||
Map<String, String> customUserdataParamMap = getVMCustomUserdataParamMap(profile.getId());
|
||||
|
||||
final String isoFileName = ConfigDrive.configIsoFileName(profile.getInstanceName());
|
||||
final String isoPath = ConfigDrive.createConfigDrivePath(profile.getInstanceName());
|
||||
final String isoData = ConfigDriveBuilder.buildConfigDrive(profile.getVmData(), isoFileName, profile.getConfigDriveLabel());
|
||||
final String isoData = ConfigDriveBuilder.buildConfigDrive(profile.getVmData(), isoFileName, profile.getConfigDriveLabel(), customUserdataParamMap);
|
||||
boolean useHostCacheOnUnsupportedPool = VirtualMachineManager.VmConfigDriveUseHostCacheOnUnsupportedPool.valueIn(dest.getDataCenter().getId());
|
||||
boolean preferHostCache = VirtualMachineManager.VmConfigDriveForceHostCacheUse.valueIn(dest.getDataCenter().getId());
|
||||
final HandleConfigDriveIsoCommand configDriveIsoCommand = new HandleConfigDriveIsoCommand(isoPath, isoData, dataStore.getTO(), useHostCacheOnUnsupportedPool, preferHostCache, true);
|
||||
@ -611,6 +615,23 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
|
||||
return true;
|
||||
}
|
||||
|
||||
private Map<String, String> getVMCustomUserdataParamMap(long vmId) {
|
||||
UserVmVO userVm = _userVmDao.findById(vmId);
|
||||
String userDataDetails = userVm.getUserDataDetails();
|
||||
Map<String,String> customUserdataParamMap = new HashMap<>();
|
||||
if(userDataDetails != null && !userDataDetails.isEmpty()) {
|
||||
userDataDetails = userDataDetails.substring(1, userDataDetails.length()-1);
|
||||
String[] keyValuePairs = userDataDetails.split(",");
|
||||
for(String pair : keyValuePairs)
|
||||
{
|
||||
String[] entry = pair.split("=");
|
||||
customUserdataParamMap.put(entry[0].trim(), entry[1].trim());
|
||||
}
|
||||
}
|
||||
|
||||
return customUserdataParamMap;
|
||||
}
|
||||
|
||||
private DataStore getDatastoreForConfigDriveIso(DiskTO disk, VirtualMachineProfile profile, DeployDestination dest) {
|
||||
DataStore dataStore = null;
|
||||
if (disk != null) {
|
||||
@ -723,7 +744,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
|
||||
} else {
|
||||
destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost().getName());
|
||||
}
|
||||
final List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
final List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), vm.getUserDataDetails(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
vm.getUuid(), nic.getIPv4Address(), sshPublicKey, (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, destHostname);
|
||||
profile.setVmData(vmData);
|
||||
profile.setConfigDriveLabel(VirtualMachineManager.VmConfigDriveLabel.value());
|
||||
|
||||
@ -214,7 +214,7 @@ public class CommandSetupHelper {
|
||||
|
||||
Host host = _hostDao.findById(vm.getHostId());
|
||||
String destHostname = VirtualMachineManager.getHypervisorHostname(host != null ? host.getName() : "");
|
||||
VmDataCommand vmDataCommand = generateVmDataCommand(router, nic.getIPv4Address(), vm.getUserData(), serviceOffering, zoneName,
|
||||
VmDataCommand vmDataCommand = generateVmDataCommand(router, nic.getIPv4Address(), vm.getUserData(), vm.getUserDataDetails(), serviceOffering, zoneName,
|
||||
staticNatIp == null || staticNatIp.getState() != IpAddress.State.Allocated ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(),
|
||||
vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId(), destHostname);
|
||||
|
||||
@ -1185,9 +1185,9 @@ public class CommandSetupHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, final String serviceOffering,
|
||||
final String zoneName, final String publicIpAddress, final String vmName, final String vmInstanceName, final long vmId, final String vmUuid, final String publicKey,
|
||||
final long guestNetworkId, String hostname) {
|
||||
private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, String userDataDetails, final String serviceOffering,
|
||||
final String zoneName, final String publicIpAddress, final String vmName, final String vmInstanceName, final long vmId, final String vmUuid, final String publicKey,
|
||||
final long guestNetworkId, String hostname) {
|
||||
final VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkModel.getExecuteInSeqNtwkElmtCmd());
|
||||
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
|
||||
@ -1203,6 +1203,8 @@ public class CommandSetupHelper {
|
||||
cmd.addVmData("metadata", "local-ipv4", vmPrivateIpAddress);
|
||||
cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vmName));
|
||||
|
||||
addUserDataDetailsToCommand(cmd, userDataDetails);
|
||||
|
||||
Network network = _networkDao.findById(guestNetworkId);
|
||||
if (dcVo.getNetworkType() == NetworkType.Basic || network.getGuestType() == Network.GuestType.Shared) {
|
||||
cmd.addVmData("metadata", "public-ipv4", vmPrivateIpAddress);
|
||||
@ -1237,6 +1239,20 @@ public class CommandSetupHelper {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
protected void addUserDataDetailsToCommand(VmDataCommand cmd, String userDataDetails) {
|
||||
if(userDataDetails != null && !userDataDetails.isEmpty()) {
|
||||
userDataDetails = userDataDetails.substring(1, userDataDetails.length()-1);
|
||||
String[] keyValuePairs = userDataDetails.split(",");
|
||||
for(String pair : keyValuePairs)
|
||||
{
|
||||
String[] entry = pair.split("=");
|
||||
String key = entry[0].trim();
|
||||
String value = entry[1].trim();
|
||||
cmd.addVmData("metadata", key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NicVO findGatewayIp(final long userVmId) {
|
||||
final NicVO defaultNic = _nicDao.findDefaultNicForVM(userVmId);
|
||||
return defaultNic;
|
||||
|
||||
@ -16,7 +16,9 @@
|
||||
// under the License.
|
||||
package com.cloud.server;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@ -43,6 +45,11 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.user.UserDataVO;
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.PatchSystemVmAnswer;
|
||||
@ -68,6 +75,7 @@ import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd;
|
||||
import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd;
|
||||
import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd;
|
||||
@ -506,6 +514,10 @@ import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||
@ -518,6 +530,7 @@ import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
|
||||
@ -786,6 +799,9 @@ import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
import static com.cloud.configuration.ConfigurationManagerImpl.VM_USERDATA_MAX_LENGTH;
|
||||
import static com.cloud.vm.UserVmManager.MAX_USER_DATA_LENGTH_BYTES;
|
||||
|
||||
public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
|
||||
public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
|
||||
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
|
||||
@ -796,6 +812,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
public static final ConfigKey<String> customCsIdentifier = new ConfigKey<String>("Advanced", String.class, "custom.cs.identifier", UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for the cloudstack installation", true, ConfigKey.Scope.Global);
|
||||
private static final VirtualMachine.Type []systemVmTypes = { VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.ConsoleProxy};
|
||||
|
||||
private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES;
|
||||
private static final int NUM_OF_2K_BLOCKS = 512;
|
||||
private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES;
|
||||
|
||||
@Inject
|
||||
public AccountManager _accountMgr;
|
||||
@Inject
|
||||
@ -829,7 +849,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
@Inject
|
||||
private UserDao _userDao;
|
||||
@Inject
|
||||
private UserVmDao _userVmDao;
|
||||
protected UserVmDao _userVmDao;
|
||||
@Inject
|
||||
private ConfigurationDao _configDao;
|
||||
@Inject
|
||||
@ -927,8 +947,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
@Inject
|
||||
private VpcDao _vpcDao;
|
||||
@Inject
|
||||
private AnnotationDao annotationDao;
|
||||
@Inject
|
||||
private DomainVlanMapDao _domainVlanMapDao;
|
||||
@Inject
|
||||
private NicDao nicDao;
|
||||
@ -936,6 +954,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
DomainRouterDao routerDao;
|
||||
@Inject
|
||||
public UUIDManager uuidMgr;
|
||||
@Inject
|
||||
protected UserDataDao userDataDao;
|
||||
@Inject
|
||||
protected VMTemplateDao templateDao;
|
||||
@Inject
|
||||
protected AnnotationDao annotationDao;
|
||||
|
||||
private LockControllerListener _lockControllerListener;
|
||||
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
|
||||
@ -3455,6 +3479,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
cmdList.add(RemoveNicFromVMCmd.class);
|
||||
cmdList.add(ResetVMPasswordCmd.class);
|
||||
cmdList.add(ResetVMSSHKeyCmd.class);
|
||||
cmdList.add(ResetVMUserDataCmd.class);
|
||||
cmdList.add(RestoreVMCmd.class);
|
||||
cmdList.add(StartVMCmd.class);
|
||||
cmdList.add(StopVMCmd.class);
|
||||
@ -3671,6 +3696,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
cmdList.add(ChangeOutOfBandManagementPasswordCmd.class);
|
||||
cmdList.add(GetUserKeysCmd.class);
|
||||
cmdList.add(CreateConsoleEndpointCmd.class);
|
||||
|
||||
//user data APIs
|
||||
cmdList.add(RegisterUserDataCmd.class);
|
||||
cmdList.add(DeleteUserDataCmd.class);
|
||||
cmdList.add(ListUserDataCmd.class);
|
||||
cmdList.add(LinkUserDataToTemplateCmd.class);
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
@ -4329,9 +4360,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
final String keyword = cmd.getKeyword();
|
||||
|
||||
final Account caller = getCaller();
|
||||
final List<Long> permittedAccounts = new ArrayList<Long>();
|
||||
final List<Long> permittedAccounts = new ArrayList<>();
|
||||
|
||||
final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
|
||||
final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
|
||||
_accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
|
||||
final Long domainId = domainIdRecursiveListProject.first();
|
||||
final Boolean isRecursive = domainIdRecursiveListProject.second();
|
||||
@ -4363,7 +4394,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
}
|
||||
|
||||
final Pair<List<SSHKeyPairVO>, Integer> result = _sshKeyPairDao.searchAndCount(sc, searchFilter);
|
||||
return new Pair<List<? extends SSHKeyPair>, Integer>(result.first(), result.second());
|
||||
return new Pair<>(result.first(), result.second());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -4382,6 +4413,180 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
return createAndSaveSSHKeyPair(name, fingerprint, publicKey, null, owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteUserData(final DeleteUserDataCmd cmd) {
|
||||
final Account caller = getCaller();
|
||||
final String accountName = cmd.getAccountName();
|
||||
final Long domainId = cmd.getDomainId();
|
||||
final Long projectId = cmd.getProjectId();
|
||||
|
||||
Account owner = null;
|
||||
try {
|
||||
owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId);
|
||||
} catch (InvalidParameterValueException ex) {
|
||||
if (caller.getType() == Account.Type.ADMIN && accountName != null && domainId != null) {
|
||||
owner = _accountDao.findAccountIncludingRemoved(accountName, domainId);
|
||||
}
|
||||
if (owner == null) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
final UserDataVO userData = userDataDao.findById(cmd.getId());
|
||||
if (userData == null) {
|
||||
final InvalidParameterValueException ex = new InvalidParameterValueException(
|
||||
"A UserData with id '" + cmd.getId() + "' does not exist for account " + owner.getAccountName() + " in specified domain id");
|
||||
final DomainVO domain = ApiDBUtils.findDomainById(owner.getDomainId());
|
||||
String domainUuid = String.valueOf(owner.getDomainId());
|
||||
if (domain != null) {
|
||||
domainUuid = domain.getUuid();
|
||||
}
|
||||
ex.addProxyObject(domainUuid, "domainId");
|
||||
throw ex;
|
||||
}
|
||||
|
||||
List<VMTemplateVO> templatesLinkedToUserData = templateDao.findTemplatesLinkedToUserdata(userData.getId());
|
||||
if (CollectionUtils.isNotEmpty(templatesLinkedToUserData)) {
|
||||
throw new CloudRuntimeException(String.format("Userdata %s cannot be removed as it is linked to active template/templates", userData.getName()));
|
||||
}
|
||||
|
||||
List<UserVmVO> userVMsHavingUserdata = _userVmDao.findByUserDataId(userData.getId());
|
||||
if (CollectionUtils.isNotEmpty(userVMsHavingUserdata)) {
|
||||
throw new CloudRuntimeException(String.format("Userdata %s cannot be removed as it is being used by some VMs", userData.getName()));
|
||||
}
|
||||
|
||||
annotationDao.removeByEntityType(AnnotationService.EntityType.USER_DATA.name(), userData.getUuid());
|
||||
|
||||
return userDataDao.remove(userData.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<List<? extends UserData>, Integer> listUserDatas(final ListUserDataCmd cmd) {
|
||||
final Long id = cmd.getId();
|
||||
final String name = cmd.getName();
|
||||
final String keyword = cmd.getKeyword();
|
||||
|
||||
final Account caller = getCaller();
|
||||
final List<Long> permittedAccounts = new ArrayList<Long>();
|
||||
|
||||
final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
|
||||
_accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
|
||||
final Long domainId = domainIdRecursiveListProject.first();
|
||||
final Boolean isRecursive = domainIdRecursiveListProject.second();
|
||||
final ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||
final SearchBuilder<UserDataVO> sb = userDataDao.createSearchBuilder();
|
||||
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
final Filter searchFilter = new Filter(UserDataVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||
|
||||
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
|
||||
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
||||
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
|
||||
final SearchCriteria<UserDataVO> sc = sb.create();
|
||||
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
|
||||
if (id != null) {
|
||||
sc.setParameters("id", id);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
sc.setParameters("name", name);
|
||||
}
|
||||
|
||||
if (keyword != null) {
|
||||
sc.setParameters("name", "%" + keyword + "%");
|
||||
}
|
||||
|
||||
final Pair<List<UserDataVO>, Integer> result = userDataDao.searchAndCount(sc, searchFilter);
|
||||
return new Pair<>(result.first(), result.second());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_REGISTER_USER_DATA, eventDescription = "registering userdata", async = true)
|
||||
public UserData registerUserData(final RegisterUserDataCmd cmd) {
|
||||
final Account owner = getOwner(cmd);
|
||||
checkForUserDataByName(cmd, owner);
|
||||
checkForUserData(cmd, owner);
|
||||
|
||||
final String name = cmd.getName();
|
||||
String userdata = cmd.getUserData();
|
||||
final String params = cmd.getParams();
|
||||
|
||||
userdata = validateUserData(userdata, cmd.getHttpMethod());
|
||||
|
||||
return createAndSaveUserData(name, userdata, params, owner);
|
||||
}
|
||||
|
||||
private String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod) {
|
||||
byte[] decodedUserData = null;
|
||||
if (userData != null) {
|
||||
|
||||
if (userData.contains("%")) {
|
||||
try {
|
||||
userData = URLDecoder.decode(userData, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new InvalidParameterValueException("Url decoding of userdata failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Base64.isBase64(userData)) {
|
||||
throw new InvalidParameterValueException("User data is not base64 encoded");
|
||||
}
|
||||
// If GET, use 4K. If POST, support up to 1M.
|
||||
if (httpmethod.equals(BaseCmd.HTTPMethod.GET)) {
|
||||
decodedUserData = validateAndDecodeByHTTPmethod(userData, MAX_HTTP_GET_LENGTH, BaseCmd.HTTPMethod.GET);
|
||||
} else if (httpmethod.equals(BaseCmd.HTTPMethod.POST)) {
|
||||
decodedUserData = validateAndDecodeByHTTPmethod(userData, MAX_HTTP_POST_LENGTH, BaseCmd.HTTPMethod.POST);
|
||||
}
|
||||
|
||||
if (decodedUserData == null || decodedUserData.length < 1) {
|
||||
throw new InvalidParameterValueException("User data is too short");
|
||||
}
|
||||
// Re-encode so that the '=' paddings are added if necessary since 'isBase64' does not require it, but python does on the VR.
|
||||
return Base64.encodeBase64String(decodedUserData);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] validateAndDecodeByHTTPmethod(String userData, int maxHTTPlength, BaseCmd.HTTPMethod httpMethod) {
|
||||
byte[] decodedUserData = null;
|
||||
|
||||
if (userData.length() >= maxHTTPlength) {
|
||||
throw new InvalidParameterValueException(String.format("User data is too long for an http %s request", httpMethod.toString()));
|
||||
}
|
||||
if (userData.length() > VM_USERDATA_MAX_LENGTH.value()) {
|
||||
throw new InvalidParameterValueException("User data has exceeded configurable max length : " + VM_USERDATA_MAX_LENGTH.value());
|
||||
}
|
||||
decodedUserData = Base64.decodeBase64(userData.getBytes());
|
||||
if (decodedUserData.length > maxHTTPlength) {
|
||||
throw new InvalidParameterValueException(String.format("User data is too long for http %s request", httpMethod.toString()));
|
||||
}
|
||||
return decodedUserData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
* @param owner
|
||||
* @throws InvalidParameterValueException
|
||||
*/
|
||||
private void checkForUserData(final RegisterUserDataCmd cmd, final Account owner) throws InvalidParameterValueException {
|
||||
final UserDataVO userData = userDataDao.findByUserData(owner.getAccountId(), owner.getDomainId(), cmd.getUserData());
|
||||
if (userData != null) {
|
||||
throw new InvalidParameterValueException(String.format("Userdata %s with same content already exists for this account.", userData.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
* @param owner
|
||||
* @throws InvalidParameterValueException
|
||||
*/
|
||||
private void checkForUserDataByName(final RegisterUserDataCmd cmd, final Account owner) throws InvalidParameterValueException {
|
||||
final UserDataVO userData = userDataDao.findByName(owner.getAccountId(), owner.getDomainId(), cmd.getName());
|
||||
if (userData != null) {
|
||||
throw new InvalidParameterValueException(String.format("A userdata with name %s already exists for this account.", cmd.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
* @param owner
|
||||
@ -4440,6 +4645,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
* @return Account
|
||||
*/
|
||||
protected Account getOwner(final RegisterUserDataCmd cmd) {
|
||||
final Account caller = getCaller();
|
||||
return _accountMgr.finalizeOwner(caller, cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@ -4463,6 +4677,20 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
return newPair;
|
||||
}
|
||||
|
||||
private UserData createAndSaveUserData(final String name, final String userdata, final String params, final Account owner) {
|
||||
final UserDataVO userDataVO = new UserDataVO();
|
||||
|
||||
userDataVO.setAccountId(owner.getAccountId());
|
||||
userDataVO.setDomainId(owner.getDomainId());
|
||||
userDataVO.setName(name);
|
||||
userDataVO.setUserData(userdata);
|
||||
userDataVO.setParams(params);
|
||||
|
||||
userDataDao.persist(userDataVO);
|
||||
|
||||
return userDataVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVMPassword(GetVMPasswordCmd cmd) {
|
||||
Account caller = getCaller();
|
||||
|
||||
@ -34,6 +34,7 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.storage.VolumeApiService;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
@ -56,6 +57,7 @@ import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCm
|
||||
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||
@ -2289,4 +2291,41 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||
return _tmpltSvr.getTemplateDatadisksOnImageStore(templateObject, configurationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualMachineTemplate linkUserDataToTemplate(LinkUserDataToTemplateCmd cmd) {
|
||||
Long templateId = cmd.getTemplateId();
|
||||
Long isoId = cmd.getIsoId();
|
||||
Long userDataId = cmd.getUserdataId();
|
||||
UserData.UserDataOverridePolicy overridePolicy = cmd.getUserdataPolicy();
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
if (templateId != null && isoId != null) {
|
||||
throw new InvalidParameterValueException("Both template ID and ISO ID are passed, API accepts only one");
|
||||
}
|
||||
if (templateId == null && isoId == null) {
|
||||
throw new InvalidParameterValueException("Atleast one of template ID or ISO ID needs to be passed");
|
||||
}
|
||||
|
||||
VMTemplateVO template = null;
|
||||
if (templateId != null) {
|
||||
template = _tmpltDao.findById(templateId);
|
||||
} else {
|
||||
template = _tmpltDao.findById(isoId);
|
||||
}
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException(String.format("unable to find template/ISO with id %s", templateId == null? isoId : templateId));
|
||||
}
|
||||
|
||||
_accountMgr.checkAccess(caller, AccessType.OperateEntry, true, template);
|
||||
|
||||
template.setUserDataId(userDataId);
|
||||
if (userDataId != null) {
|
||||
template.setUserDataLinkPolicy(overridePolicy);
|
||||
} else {
|
||||
template.setUserDataLinkPolicy(null);
|
||||
}
|
||||
_tmpltDao.update(template.getId(), template);
|
||||
|
||||
return _tmpltDao.findById(template.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ public interface UserVmManager extends UserVmService {
|
||||
boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic);
|
||||
|
||||
UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData,
|
||||
Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap) throws ResourceUnavailableException, InsufficientCapacityException;
|
||||
Long userDataId, String userDataDetails, Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap) throws ResourceUnavailableException, InsufficientCapacityException;
|
||||
|
||||
//the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can
|
||||
//find a common place for all the scaling and upgrading code of both user and systemvms.
|
||||
|
||||
@ -75,6 +75,7 @@ import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction;
|
||||
@ -327,8 +328,10 @@ import com.cloud.user.VmDiskStatisticsVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.user.dao.SSHKeyPairDao;
|
||||
import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import com.cloud.user.dao.UserStatisticsDao;
|
||||
import com.cloud.user.dao.VmDiskStatisticsDao;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.Journal;
|
||||
@ -569,6 +572,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
|
||||
@Inject
|
||||
private StatsCollector statsCollector;
|
||||
@Inject
|
||||
private UserDataDao userDataDao;
|
||||
|
||||
@Inject
|
||||
protected SnapshotHelper snapshotHelper;
|
||||
@ -899,6 +904,49 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_RESETUSERDATA, eventDescription = "resetting VM userdata", async = true)
|
||||
public UserVm resetVMUserData(ResetVMUserDataCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
Long vmId = cmd.getId();
|
||||
UserVmVO userVm = _vmDao.findById(cmd.getId());
|
||||
|
||||
if (userVm == null) {
|
||||
throw new InvalidParameterValueException("unable to find a virtual machine by id" + cmd.getId());
|
||||
}
|
||||
_accountMgr.checkAccess(caller, null, true, userVm);
|
||||
|
||||
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(userVm.getTemplateId());
|
||||
|
||||
// Do parameters input validation
|
||||
|
||||
if (userVm.getState() != State.Stopped) {
|
||||
s_logger.error("vm is not in the right state: " + vmId);
|
||||
throw new InvalidParameterValueException(String.format("VM %s should be stopped to do UserData reset", userVm));
|
||||
}
|
||||
|
||||
String userData = cmd.getUserData();
|
||||
Long userDataId = cmd.getUserdataId();
|
||||
String userDataDetails = null;
|
||||
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
|
||||
userDataDetails = cmd.getUserdataDetails().toString();
|
||||
}
|
||||
userData = finalizeUserData(userData, userDataId, template);
|
||||
userData = validateUserData(userData, cmd.getHttpMethod());
|
||||
|
||||
userVm.setUserDataId(userDataId);
|
||||
userVm.setUserData(userData);
|
||||
userVm.setUserDataDetails(userDataDetails);
|
||||
_vmDao.update(userVm.getId(), userVm);
|
||||
|
||||
updateUserData(userVm);
|
||||
|
||||
UserVmVO vm = _vmDao.findById(vmId);
|
||||
_vmDao.loadDetails(vm);
|
||||
return vm;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_RESETSSHKEY, eventDescription = "resetting Vm SSHKey", async = true)
|
||||
public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
@ -2437,6 +2485,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vm.getUserDataId() != null) {
|
||||
vm.setUserDataId(null);
|
||||
_vmDao.update(vm.getId(), vm);
|
||||
}
|
||||
|
||||
_vmDao.remove(vm.getId());
|
||||
}
|
||||
|
||||
@ -2719,7 +2772,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
Boolean isDisplayVm = cmd.getDisplayVm();
|
||||
Long id = cmd.getId();
|
||||
Long osTypeId = cmd.getOsTypeId();
|
||||
String userData = cmd.getUserData();
|
||||
Boolean isDynamicallyScalable = cmd.isDynamicallyScalable();
|
||||
String hostName = cmd.getHostName();
|
||||
Map<String,String> details = cmd.getDetails();
|
||||
@ -2728,12 +2780,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
String extraConfig = cmd.getExtraConfig();
|
||||
|
||||
UserVmVO vmInstance = _vmDao.findById(cmd.getId());
|
||||
VMTemplateVO template = _templateDao.findById(vmInstance.getTemplateId());
|
||||
if (MapUtils.isNotEmpty(details) || cmd.isCleanupDetails()) {
|
||||
VMTemplateVO template = _templateDao.findById(vmInstance.getTemplateId());
|
||||
if (template != null && template.isDeployAsIs()) {
|
||||
throw new CloudRuntimeException("Detail settings are read from OVA, it cannot be changed by API call.");
|
||||
}
|
||||
}
|
||||
String userData = cmd.getUserData();
|
||||
Long userDataId = cmd.getUserdataId();
|
||||
String userDataDetails = null;
|
||||
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
|
||||
userDataDetails = cmd.getUserdataDetails().toString();
|
||||
}
|
||||
userData = finalizeUserData(userData, userDataId, template);
|
||||
|
||||
long accountId = vmInstance.getAccountId();
|
||||
|
||||
@ -2795,7 +2854,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
}
|
||||
}
|
||||
return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable,
|
||||
return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, userDataId, userDataDetails, isDynamicallyScalable,
|
||||
cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList, cmd.getDhcpOptionsMap());
|
||||
}
|
||||
|
||||
@ -2893,7 +2952,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
|
||||
@Override
|
||||
public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData,
|
||||
Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap)
|
||||
Long userDataId, String userDataDetails, Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List<Long> securityGroupIdList, Map<String, Map<Integer, String>> extraDhcpOptionsMap)
|
||||
throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
UserVmVO vm = _vmDao.findById(id);
|
||||
if (vm == null) {
|
||||
@ -2940,6 +2999,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
userData = vm.getUserData();
|
||||
}
|
||||
|
||||
if (userDataId == null) {
|
||||
userDataId = vm.getUserDataId();
|
||||
}
|
||||
|
||||
if (userDataDetails == null) {
|
||||
userDataDetails = vm.getUserDataDetails();
|
||||
}
|
||||
|
||||
if (osTypeId == null) {
|
||||
osTypeId = vm.getGuestOSId();
|
||||
}
|
||||
@ -3035,7 +3102,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
.getUuid(), nic.getId(), extraDhcpOptionsMap);
|
||||
}
|
||||
|
||||
_vmDao.updateVM(id, displayName, ha, osTypeId, userData, isDisplayVmEnabled, isDynamicallyScalable, customId, hostName, instanceName);
|
||||
_vmDao.updateVM(id, displayName, ha, osTypeId, userData, userDataId, userDataDetails, isDisplayVmEnabled, isDynamicallyScalable, customId, hostName, instanceName);
|
||||
|
||||
if (updateUserdata) {
|
||||
updateUserData(vm);
|
||||
@ -3048,7 +3115,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
return _vmDao.findById(id);
|
||||
}
|
||||
|
||||
private void updateUserData(UserVm vm) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
protected void updateUserData(UserVm vm) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
boolean result = updateUserDataInternal(vm);
|
||||
if (result) {
|
||||
s_logger.debug(String.format("User data successfully updated for vm id: %s", vm.getId()));
|
||||
@ -3456,10 +3523,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||
String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
@ -3507,7 +3574,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
|
||||
userData, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap,
|
||||
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap,
|
||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
|
||||
|
||||
}
|
||||
@ -3515,10 +3582,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
||||
HTTPMethod httpmethod, String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
|
||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
List<NetworkVO> networkList = new ArrayList<NetworkVO>();
|
||||
@ -3617,17 +3684,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
|
||||
userData, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||
userVmOVFProperties, dynamicScalingEnabled, vmType, overrideDiskOfferingId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||
List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
|
||||
Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
@ -3677,7 +3744,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList);
|
||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData,
|
||||
sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap,
|
||||
userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap,
|
||||
dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, overrideDiskOfferingId);
|
||||
}
|
||||
|
||||
@ -3794,7 +3861,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
@DB
|
||||
private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner,
|
||||
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
|
||||
List<String> sshKeyPairs, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId) throws InsufficientCapacityException, ResourceUnavailableException,
|
||||
@ -3889,7 +3956,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
volumesSize += verifyAndGetDiskSize(diskOffering, diskSize);
|
||||
}
|
||||
UserVm vm = getCheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
UserVm vm = getCheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
|
||||
_securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList);
|
||||
|
||||
@ -3900,13 +3967,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
CallContext.current().putContextParameter(VirtualMachine.class, vm.getUuid());
|
||||
return vm;
|
||||
}
|
||||
private UserVm getCheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData, List<String> sshKeyPairs, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template, HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso, Long rootDiskOfferingId, long volumesSize) throws ResourceAllocationException, StorageUnavailableException, InsufficientCapacityException {
|
||||
private UserVm getCheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template, HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso, Long rootDiskOfferingId, long volumesSize) throws ResourceAllocationException, StorageUnavailableException, InsufficientCapacityException {
|
||||
if (!VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
|
||||
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, 1l, reservationDao, resourceLimitService);
|
||||
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, Long.valueOf(offering.getCpu()), reservationDao, resourceLimitService);
|
||||
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, Long.valueOf(offering.getRamSize()), reservationDao, resourceLimitService);
|
||||
) {
|
||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
} catch (ResourceAllocationException | CloudRuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
@ -3915,11 +3982,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
} else {
|
||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize);
|
||||
}
|
||||
}
|
||||
|
||||
private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData, List<String> sshKeyPairs, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template, HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso, Long rootDiskOfferingId, long volumesSize) throws ResourceAllocationException, StorageUnavailableException, InsufficientCapacityException {
|
||||
private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template, HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso, Long rootDiskOfferingId, long volumesSize) throws ResourceAllocationException, StorageUnavailableException, InsufficientCapacityException {
|
||||
try (CheckedReservation volumeReservation = new CheckedReservation(owner, ResourceType.volume, (isIso || diskOfferingId == null ? 1l : 2), reservationDao, resourceLimitService);
|
||||
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, volumesSize, reservationDao, resourceLimitService)) {
|
||||
|
||||
@ -4195,7 +4262,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
|
||||
dynamicScalingEnabled = dynamicScalingEnabled && checkIfDynamicScalingCanBeEnabled(null, offering, template, zone.getId());
|
||||
|
||||
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, accountId, userId, offering,
|
||||
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, userDataId, userDataDetails, caller, isDisplayVm, keyboard, accountId, userId, offering,
|
||||
isIso, sshPublicKeys, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap,
|
||||
datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, rootDiskOfferingId, keypairnames);
|
||||
|
||||
@ -4332,7 +4399,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
private UserVmVO commitUserVm(final boolean isImport, final DataCenter zone, final Host host, final Host lastHost, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner,
|
||||
final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
|
||||
final Long diskOfferingId, final Long diskSize, final String userData, Long userDataId, String userDataDetails, final Boolean isDisplayVm, final String keyboard,
|
||||
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
|
||||
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
@ -4341,7 +4408,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
@Override
|
||||
public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException {
|
||||
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(),
|
||||
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, hostName);
|
||||
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
|
||||
vm.setUuid(uuidName);
|
||||
vm.setDynamicallyScalable(dynamicScalingEnabled);
|
||||
|
||||
@ -4555,13 +4622,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
private UserVmVO commitUserVm(final DataCenter zone, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner,
|
||||
final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
|
||||
final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String,
|
||||
final Long diskOfferingId, final Long diskSize, final String userData, Long userDataId, String userDataDetails, final Account caller, final Boolean isDisplayVm, final String keyboard,
|
||||
final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String,
|
||||
Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||
Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs) throws InsufficientCapacityException {
|
||||
Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs) throws InsufficientCapacityException {
|
||||
return commitUserVm(false, zone, null, null, template, hostName, displayName, owner,
|
||||
diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard,
|
||||
diskOfferingId, diskSize, userData, userDataId, userDataDetails, isDisplayVm, keyboard,
|
||||
accountId, userId, offering, isIso, sshPublicKeys, networkNicMap,
|
||||
id, instanceName, uuidName, hypervisorType, customParameters,
|
||||
extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||
@ -4934,7 +5001,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
|
||||
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
||||
String destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost() != null ? dest.getHost().getName() : "");
|
||||
List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), vm.getUserDataDetails(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
|
||||
vm.getUuid(), defaultNic.getIPv4Address(), vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, destHostname);
|
||||
String vmName = vm.getInstanceName();
|
||||
String configDriveIsoRootFolder = "/tmp";
|
||||
@ -5685,6 +5752,73 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
return userVm.getHypervisorType();
|
||||
}
|
||||
|
||||
protected String finalizeUserData(String userData, Long userDataId, VirtualMachineTemplate template) {
|
||||
if (StringUtils.isEmpty(userData) && userDataId == null && (template == null || template.getUserDataId() == null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (userDataId != null && StringUtils.isNotEmpty(userData)) {
|
||||
throw new InvalidParameterValueException("Both userdata and userdata ID inputs are not allowed, please provide only one");
|
||||
}
|
||||
if (template != null && template.getUserDataId() != null) {
|
||||
switch (template.getUserDataOverridePolicy()) {
|
||||
case DENYOVERRIDE:
|
||||
if (StringUtils.isNotEmpty(userData) || userDataId != null) {
|
||||
String msg = String.format("UserData input is not allowed here since template %s is configured to deny any userdata", template.getName());
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
case ALLOWOVERRIDE:
|
||||
if (userDataId != null) {
|
||||
UserData apiUserDataVO = userDataDao.findById(userDataId);
|
||||
return apiUserDataVO.getUserData();
|
||||
} else if (StringUtils.isNotEmpty(userData)) {
|
||||
return userData;
|
||||
} else {
|
||||
UserData templateUserDataVO = userDataDao.findById(template.getUserDataId());
|
||||
if (templateUserDataVO == null) {
|
||||
String msg = String.format("UserData linked to the template %s is not found", template.getName());
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
return templateUserDataVO.getUserData();
|
||||
}
|
||||
case APPEND:
|
||||
UserData templateUserDataVO = userDataDao.findById(template.getUserDataId());
|
||||
if (templateUserDataVO == null) {
|
||||
String msg = String.format("UserData linked to the template %s is not found", template.getName());
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
if (userDataId != null) {
|
||||
UserData apiUserDataVO = userDataDao.findById(userDataId);
|
||||
return doConcateUserDatas(templateUserDataVO.getUserData(), apiUserDataVO.getUserData());
|
||||
} else if (StringUtils.isNotEmpty(userData)) {
|
||||
return doConcateUserDatas(templateUserDataVO.getUserData(), userData);
|
||||
} else {
|
||||
return templateUserDataVO.getUserData();
|
||||
}
|
||||
default:
|
||||
String msg = String.format("This userdataPolicy %s is not supported for use with this feature", template.getUserDataOverridePolicy().toString());
|
||||
throw new CloudRuntimeException(msg); }
|
||||
} else {
|
||||
if (userDataId != null) {
|
||||
UserData apiUserDataVO = userDataDao.findById(userDataId);
|
||||
return apiUserDataVO.getUserData();
|
||||
} else if (StringUtils.isNotEmpty(userData)) {
|
||||
return userData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String doConcateUserDatas(String userdata1, String userdata2) {
|
||||
byte[] userdata1Bytes = Base64.decodeBase64(userdata1.getBytes());
|
||||
byte[] userdata2Bytes = Base64.decodeBase64(userdata2.getBytes());
|
||||
byte[] finalUserDataBytes = new byte[userdata1Bytes.length + userdata2Bytes.length];
|
||||
System.arraycopy(userdata1Bytes, 0, finalUserDataBytes, 0, userdata1Bytes.length);
|
||||
System.arraycopy(userdata2Bytes, 0, finalUserDataBytes, userdata1Bytes.length, userdata2Bytes.length);
|
||||
|
||||
return Base64.encodeBase64String(finalUserDataBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
@ -5775,6 +5909,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
networkIds = new ArrayList<>(userVmNetworkMap.values());
|
||||
}
|
||||
|
||||
String userData = cmd.getUserData();
|
||||
Long userDataId = cmd.getUserdataId();
|
||||
String userDataDetails = null;
|
||||
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
|
||||
userDataDetails = cmd.getUserdataDetails().toString();
|
||||
}
|
||||
userData = finalizeUserData(userData, userDataId, template);
|
||||
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
Long callerId = caller.getId();
|
||||
|
||||
@ -5792,7 +5934,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
IpAddresses addrs = new IpAddresses(ipAddress, ip6Address, macAddress);
|
||||
Long size = cmd.getSize();
|
||||
String group = cmd.getGroup();
|
||||
String userData = cmd.getUserData();
|
||||
List<String> sshKeyPairNames = cmd.getSSHKeyPairNames();
|
||||
Boolean displayVm = cmd.isDisplayVm();
|
||||
String keyboard = cmd.getKeyboard();
|
||||
@ -5803,14 +5944,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
||||
} else {
|
||||
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
|
||||
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
||||
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
||||
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
|
||||
}
|
||||
} else {
|
||||
if (zone.isSecurityGroupEnabled()) {
|
||||
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name,
|
||||
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
||||
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
||||
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null);
|
||||
|
||||
@ -5819,7 +5960,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
|
||||
}
|
||||
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
|
||||
cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
||||
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
||||
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
|
||||
}
|
||||
}
|
||||
@ -7964,7 +8105,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null;
|
||||
final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId());
|
||||
return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner,
|
||||
null, null, userData, caller, isDisplayVm, keyboard,
|
||||
null, null, userData, null, null, isDisplayVm, keyboard,
|
||||
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, null,
|
||||
id, instanceName, uuidName, hypervisorType, customParameters,
|
||||
null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null);
|
||||
|
||||
@ -26,6 +26,7 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.Role;
|
||||
import org.apache.cloudstack.acl.RoleService;
|
||||
@ -152,6 +153,8 @@ public final class AnnotationManagerImpl extends ManagerBase implements Annotati
|
||||
@Inject
|
||||
private NetworkOfferingDao networkOfferingDao;
|
||||
@Inject
|
||||
private UserDataDao userDataDao;
|
||||
@Inject
|
||||
EntityManager entityManager;
|
||||
|
||||
private static final List<RoleType> adminRoles = Collections.singletonList(RoleType.Admin);
|
||||
@ -165,6 +168,7 @@ public final class AnnotationManagerImpl extends ManagerBase implements Annotati
|
||||
s_typeMap.put(EntityType.VM_SNAPSHOT, ApiCommandResourceType.VmSnapshot);
|
||||
s_typeMap.put(EntityType.INSTANCE_GROUP, ApiCommandResourceType.None);
|
||||
s_typeMap.put(EntityType.SSH_KEYPAIR, ApiCommandResourceType.None);
|
||||
s_typeMap.put(EntityType.USER_DATA, ApiCommandResourceType.None);
|
||||
s_typeMap.put(EntityType.NETWORK, ApiCommandResourceType.Network);
|
||||
s_typeMap.put(EntityType.VPC, ApiCommandResourceType.Vpc);
|
||||
s_typeMap.put(EntityType.PUBLIC_IP_ADDRESS, ApiCommandResourceType.IpAddress);
|
||||
@ -507,6 +511,8 @@ public final class AnnotationManagerImpl extends ManagerBase implements Annotati
|
||||
return instanceGroupDao.findByUuid(entityUuid);
|
||||
case SSH_KEYPAIR:
|
||||
return sshKeyPairDao.findByUuid(entityUuid);
|
||||
case USER_DATA:
|
||||
return userDataDao.findByUuid(entityUuid);
|
||||
case NETWORK:
|
||||
return networkDao.findByUuid(entityUuid);
|
||||
case VPC:
|
||||
|
||||
@ -911,7 +911,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
|
||||
public List<String[]> generateVmData(String userData, String userDataDetails, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -274,7 +274,7 @@ public class ConfigDriveNetworkElementTest {
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
|
||||
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("buildConfigDrive")).iterator().next();
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyString()).thenReturn("content");
|
||||
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyString(), Mockito.anyMap()).thenReturn("content");
|
||||
|
||||
final HandleConfigDriveIsoAnswer answer = mock(HandleConfigDriveIsoAnswer.class);
|
||||
final UserVmDetailVO userVmDetailVO = mock(UserVmDetailVO.class);
|
||||
|
||||
@ -157,7 +157,7 @@ public class AssignLoadBalancerTest {
|
||||
vmIds.add(2L);
|
||||
|
||||
LoadBalancerVO lbVO = new LoadBalancerVO("1", "L1", "Lbrule", 1, 22, 22, "rb", 204, 0, 0, "tcp", null);
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", "test");
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", 1L, null, "test");
|
||||
|
||||
LoadBalancerDao lbDao = Mockito.mock(LoadBalancerDao.class);
|
||||
LoadBalancerVMMapDao lb2VmMapDao = Mockito.mock(LoadBalancerVMMapDao.class);
|
||||
@ -200,7 +200,7 @@ public class AssignLoadBalancerTest {
|
||||
vmIds.add(2L);
|
||||
|
||||
LoadBalancerVO lbVO = new LoadBalancerVO("1", "L1", "Lbrule", 1, 22, 22, "rb", 204, 0, 0, "tcp", null);
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", "test");
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", 1L, null, "test");
|
||||
|
||||
LoadBalancerDao lbDao = Mockito.mock(LoadBalancerDao.class);
|
||||
LoadBalancerVMMapDao lb2VmMapDao = Mockito.mock(LoadBalancerVMMapDao.class);
|
||||
@ -245,7 +245,7 @@ public class AssignLoadBalancerTest {
|
||||
vmIds.add(2L);
|
||||
|
||||
LoadBalancerVO lbVO = new LoadBalancerVO("1", "L1", "Lbrule", 1, 22, 22, "rb", 204, 0, 0, "tcp", null);
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", "test");
|
||||
UserVmVO vm = new UserVmVO(2L, "test", "test", 101L, Hypervisor.HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", 1L, null, "test");
|
||||
|
||||
LoadBalancerDao lbDao = Mockito.mock(LoadBalancerDao.class);
|
||||
LoadBalancerVMMapDao lb2VmMapDao = Mockito.mock(LoadBalancerVMMapDao.class);
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.network.router;
|
||||
|
||||
import com.cloud.agent.api.routing.VmDataCommand;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
public class CommandSetupHelperTest {
|
||||
|
||||
@InjectMocks
|
||||
protected CommandSetupHelper commandSetupHelper = new CommandSetupHelper();
|
||||
|
||||
@Test
|
||||
public void testUserDataDetails() {
|
||||
VmDataCommand vmDataCommand = new VmDataCommand("testVMname");
|
||||
String testUserDataDetails = new String("{test1=value1,test2=value2}");
|
||||
commandSetupHelper.addUserDataDetailsToCommand(vmDataCommand, testUserDataDetails);
|
||||
|
||||
List<String[]> metadata = vmDataCommand.getVmData();
|
||||
String[] metadataFile1 = metadata.get(0);
|
||||
String[] metadataFile2 = metadata.get(1);
|
||||
|
||||
Assert.assertEquals("metadata", metadataFile1[0]);
|
||||
Assert.assertEquals("metadata", metadataFile2[0]);
|
||||
|
||||
Assert.assertEquals("test1", metadataFile1[1]);
|
||||
Assert.assertEquals("test2", metadataFile2[1]);
|
||||
|
||||
Assert.assertEquals("value1", metadataFile1[2]);
|
||||
Assert.assertEquals("value2", metadataFile2[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullUserDataDetails() {
|
||||
VmDataCommand vmDataCommand = new VmDataCommand("testVMname");
|
||||
String testUserDataDetails = null;
|
||||
commandSetupHelper.addUserDataDetailsToCommand(vmDataCommand, testUserDataDetails);
|
||||
Assert.assertEquals(new ArrayList<>(), vmDataCommand.getVmData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataDetailsWithWhiteSpaces() {
|
||||
VmDataCommand vmDataCommand = new VmDataCommand("testVMname");
|
||||
String testUserDataDetails = new String("{test1 =value1,test2= value2 }");
|
||||
commandSetupHelper.addUserDataDetailsToCommand(vmDataCommand, testUserDataDetails);
|
||||
|
||||
List<String[]> metadata = vmDataCommand.getVmData();
|
||||
String[] metadataFile1 = metadata.get(0);
|
||||
String[] metadataFile2 = metadata.get(1);
|
||||
|
||||
Assert.assertEquals("metadata", metadataFile1[0]);
|
||||
Assert.assertEquals("metadata", metadataFile2[0]);
|
||||
|
||||
Assert.assertEquals("test1", metadataFile1[1]);
|
||||
Assert.assertEquals("test2", metadataFile2[1]);
|
||||
|
||||
Assert.assertEquals("value1", metadataFile1[2]);
|
||||
Assert.assertEquals("value2", metadataFile2[2]);
|
||||
}
|
||||
}
|
||||
@ -16,21 +16,46 @@
|
||||
// under the License.
|
||||
package com.cloud.server;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.user.UserDataVO;
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
|
||||
import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import com.cloud.dc.Vlan.VlanType;
|
||||
@ -44,7 +69,11 @@ import com.cloud.user.SSHKeyPairVO;
|
||||
import com.cloud.user.dao.SSHKeyPairDao;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
public class ManagementServerImplTest {
|
||||
|
||||
@Mock
|
||||
@ -61,7 +90,6 @@ public class ManagementServerImplTest {
|
||||
|
||||
@Mock
|
||||
SSHKeyPairDao sshKeyPairDao;
|
||||
ManagementServerImpl ms = new ManagementServerImpl();
|
||||
|
||||
@Mock
|
||||
SSHKeyPair sshKeyPair;
|
||||
@ -69,15 +97,42 @@ public class ManagementServerImplTest {
|
||||
@Mock
|
||||
IpAddressManagerImpl ipAddressManagerImpl;
|
||||
|
||||
@Mock
|
||||
AccountManager _accountMgr;
|
||||
|
||||
@Mock
|
||||
UserDataDao _userDataDao;
|
||||
|
||||
@Mock
|
||||
VMTemplateDao _templateDao;
|
||||
|
||||
@Mock
|
||||
AnnotationDao annotationDao;
|
||||
|
||||
@Mock
|
||||
UserVmDao _userVmDao;
|
||||
|
||||
@Spy
|
||||
ManagementServerImpl spy;
|
||||
ManagementServerImpl spy = new ManagementServerImpl();
|
||||
|
||||
ConfigKey mockConfig;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
|
||||
mockConfig = Mockito.mock(ConfigKey.class);
|
||||
Whitebox.setInternalState(ipAddressManagerImpl.getClass(), "SystemVmPublicIpReservationModeStrictness", mockConfig);
|
||||
spy._accountMgr = _accountMgr;
|
||||
spy.userDataDao = _userDataDao;
|
||||
spy.templateDao = _templateDao;
|
||||
spy._userVmDao = _userVmDao;
|
||||
spy.annotationDao = annotationDao;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
CallContext.unregister();
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
@ -221,4 +276,264 @@ public class ManagementServerImplTest {
|
||||
Mockito.verify(sc, Mockito.times(1)).setParameters("sourceNetworkId", 10L);
|
||||
Mockito.verify(sc, Mockito.never()).setParameters("forsystemvms", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulRegisterUserdata() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
RegisterUserDataCmd cmd = Mockito.mock(RegisterUserDataCmd.class);
|
||||
when(cmd.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getName()).thenReturn("testName");
|
||||
when(cmd.getHttpMethod()).thenReturn(BaseCmd.HTTPMethod.GET);
|
||||
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
|
||||
when(_userDataDao.findByUserData(account.getAccountId(), account.getDomainId(), "testUserdata")).thenReturn(null);
|
||||
|
||||
UserData userData = spy.registerUserData(cmd);
|
||||
Assert.assertEquals("testName", userData.getName());
|
||||
Assert.assertEquals("testUserdata", userData.getUserData());
|
||||
Assert.assertEquals(1L, userData.getAccountId());
|
||||
Assert.assertEquals(2L, userData.getDomainId());
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void testRegisterExistingUserdata() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
RegisterUserDataCmd cmd = Mockito.mock(RegisterUserDataCmd.class);
|
||||
when(cmd.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getName()).thenReturn("testName");
|
||||
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
|
||||
when(_userDataDao.findByUserData(account.getAccountId(), account.getDomainId(), "testUserdata")).thenReturn(userData);
|
||||
|
||||
spy.registerUserData(cmd);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void testRegisterExistingName() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
PowerMockito.when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
RegisterUserDataCmd cmd = Mockito.mock(RegisterUserDataCmd.class);
|
||||
when(cmd.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getName()).thenReturn("testName");
|
||||
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(userData);
|
||||
|
||||
spy.registerUserData(cmd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulDeleteUserdata() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
DeleteUserDataCmd cmd = Mockito.mock(DeleteUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
|
||||
Mockito.when(userData.getId()).thenReturn(1L);
|
||||
when(_userDataDao.findById(1L)).thenReturn(userData);
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
|
||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
||||
when(_userVmDao.findByUserDataId(1L)).thenReturn(new ArrayList<UserVmVO>());
|
||||
when(_userDataDao.remove(1L)).thenReturn(true);
|
||||
|
||||
boolean result = spy.deleteUserData(cmd);
|
||||
Assert.assertEquals(true, result);
|
||||
}
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void testDeleteUserdataLinkedToTemplate() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
DeleteUserDataCmd cmd = Mockito.mock(DeleteUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
Mockito.when(userData.getId()).thenReturn(1L);
|
||||
when(_userDataDao.findById(1L)).thenReturn(userData);
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
|
||||
|
||||
VMTemplateVO vmTemplateVO = Mockito.mock(VMTemplateVO.class);
|
||||
List<VMTemplateVO> linkedTemplates = new ArrayList<>();
|
||||
linkedTemplates.add(vmTemplateVO);
|
||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(linkedTemplates);
|
||||
|
||||
spy.deleteUserData(cmd);
|
||||
}
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void testDeleteUserdataUsedByVM() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
DeleteUserDataCmd cmd = Mockito.mock(DeleteUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
Mockito.when(userData.getId()).thenReturn(1L);
|
||||
when(_userDataDao.findById(1L)).thenReturn(userData);
|
||||
when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
|
||||
|
||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
||||
|
||||
UserVmVO userVmVO = Mockito.mock(UserVmVO.class);
|
||||
List<UserVmVO> vms = new ArrayList<>();
|
||||
vms.add(userVmVO);
|
||||
when(_userVmDao.findByUserDataId(1L)).thenReturn(vms);
|
||||
|
||||
spy.deleteUserData(cmd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListUserDataById() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
ListUserDataCmd cmd = Mockito.mock(ListUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
when(cmd.isRecursive()).thenReturn(false);
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
|
||||
SearchBuilder<UserDataVO> sb = Mockito.mock(SearchBuilder.class);
|
||||
when(_userDataDao.createSearchBuilder()).thenReturn(sb);
|
||||
when(sb.entity()).thenReturn(userData);
|
||||
|
||||
SearchCriteria<UserDataVO> sc = Mockito.mock(SearchCriteria.class);
|
||||
when(sb.create()).thenReturn(sc);
|
||||
|
||||
List<UserDataVO> userDataList = new ArrayList<UserDataVO>();
|
||||
userDataList.add(userData);
|
||||
Pair<List<UserDataVO>, Integer> result = new Pair(userDataList, 1);
|
||||
when(_userDataDao.searchAndCount(nullable(SearchCriteria.class), nullable(Filter.class))).thenReturn(result);
|
||||
|
||||
Pair<List<? extends UserData>, Integer> userdataResultList = spy.listUserDatas(cmd);
|
||||
|
||||
Assert.assertEquals(userdataResultList.first().get(0), userDataList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListUserDataByName() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
ListUserDataCmd cmd = Mockito.mock(ListUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getName()).thenReturn("testSearchUserdataName");
|
||||
when(cmd.isRecursive()).thenReturn(false);
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
|
||||
SearchBuilder<UserDataVO> sb = Mockito.mock(SearchBuilder.class);
|
||||
when(_userDataDao.createSearchBuilder()).thenReturn(sb);
|
||||
when(sb.entity()).thenReturn(userData);
|
||||
|
||||
SearchCriteria<UserDataVO> sc = Mockito.mock(SearchCriteria.class);
|
||||
when(sb.create()).thenReturn(sc);
|
||||
|
||||
List<UserDataVO> userDataList = new ArrayList<UserDataVO>();
|
||||
userDataList.add(userData);
|
||||
Pair<List<UserDataVO>, Integer> result = new Pair(userDataList, 1);
|
||||
when(_userDataDao.searchAndCount(nullable(SearchCriteria.class), nullable(Filter.class))).thenReturn(result);
|
||||
|
||||
Pair<List<? extends UserData>, Integer> userdataResultList = spy.listUserDatas(cmd);
|
||||
|
||||
Assert.assertEquals(userdataResultList.first().get(0), userDataList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListUserDataByKeyword() {
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
when(CallContext.current()).thenReturn(callContextMock);
|
||||
when(account.getAccountId()).thenReturn(1L);
|
||||
when(account.getDomainId()).thenReturn(2L);
|
||||
when(callContextMock.getCallingAccount()).thenReturn(account);
|
||||
when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
|
||||
|
||||
ListUserDataCmd cmd = Mockito.mock(ListUserDataCmd.class);
|
||||
when(cmd.getAccountName()).thenReturn("testAccountName");
|
||||
when(cmd.getDomainId()).thenReturn(1L);
|
||||
when(cmd.getProjectId()).thenReturn(2L);
|
||||
when(cmd.getKeyword()).thenReturn("testSearchUserdataKeyword");
|
||||
when(cmd.isRecursive()).thenReturn(false);
|
||||
UserDataVO userData = Mockito.mock(UserDataVO.class);
|
||||
|
||||
SearchBuilder<UserDataVO> sb = Mockito.mock(SearchBuilder.class);
|
||||
when(_userDataDao.createSearchBuilder()).thenReturn(sb);
|
||||
when(sb.entity()).thenReturn(userData);
|
||||
|
||||
SearchCriteria<UserDataVO> sc = Mockito.mock(SearchCriteria.class);
|
||||
when(sb.create()).thenReturn(sc);
|
||||
|
||||
List<UserDataVO> userDataList = new ArrayList<UserDataVO>();
|
||||
userDataList.add(userData);
|
||||
Pair<List<UserDataVO>, Integer> result = new Pair(userDataList, 1);
|
||||
when(_userDataDao.searchAndCount(nullable(SearchCriteria.class), nullable(Filter.class))).thenReturn(result);
|
||||
|
||||
Pair<List<? extends UserData>, Integer> userdataResultList = spy.listUserDatas(cmd);
|
||||
|
||||
Assert.assertEquals(userdataResultList.first().get(0), userDataList.get(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ public class VolumeApiServiceImplTest {
|
||||
VolumeVO volumeOfRunningVm = new VolumeVO("root", 1L, 1L, 1L, 1L, 1L, "root", "root", Storage.ProvisioningType.THIN, 1, null, null, "root", Volume.Type.ROOT);
|
||||
when(volumeDaoMock.findById(1L)).thenReturn(volumeOfRunningVm);
|
||||
|
||||
UserVmVO runningVm = new UserVmVO(1L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm");
|
||||
UserVmVO runningVm = new UserVmVO(1L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, null, null, "vm");
|
||||
runningVm.setState(State.Running);
|
||||
runningVm.setDataCenterId(1L);
|
||||
when(userVmDaoMock.findById(1L)).thenReturn(runningVm);
|
||||
@ -230,13 +230,13 @@ public class VolumeApiServiceImplTest {
|
||||
volumeOfStoppedVm.setPoolId(1L);
|
||||
when(volumeDaoMock.findById(2L)).thenReturn(volumeOfStoppedVm);
|
||||
|
||||
UserVmVO stoppedVm = new UserVmVO(2L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm");
|
||||
UserVmVO stoppedVm = new UserVmVO(2L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, null, null, "vm");
|
||||
stoppedVm.setState(State.Stopped);
|
||||
stoppedVm.setDataCenterId(1L);
|
||||
when(userVmDaoMock.findById(2L)).thenReturn(stoppedVm);
|
||||
|
||||
// volume of hyperV vm id=3
|
||||
UserVmVO hyperVVm = new UserVmVO(3L, "vm", "vm", 1, HypervisorType.Hyperv, 1L, false, false, 1L, 1L, 1, 1L, null, "vm");
|
||||
UserVmVO hyperVVm = new UserVmVO(3L, "vm", "vm", 1, HypervisorType.Hyperv, 1L, false, false, 1L, 1L, 1, 1L, null, null, null, "vm");
|
||||
hyperVVm.setState(State.Stopped);
|
||||
hyperVVm.setDataCenterId(1L);
|
||||
when(userVmDaoMock.findById(3L)).thenReturn(hyperVVm);
|
||||
@ -290,7 +290,7 @@ public class VolumeApiServiceImplTest {
|
||||
managedVolume1.setDataCenterId(1L);
|
||||
|
||||
// vm having root volume
|
||||
UserVmVO vmHavingRootVolume = new UserVmVO(4L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, "vm");
|
||||
UserVmVO vmHavingRootVolume = new UserVmVO(4L, "vm", "vm", 1, HypervisorType.XenServer, 1L, false, false, 1L, 1L, 1, 1L, null, null, null, "vm");
|
||||
vmHavingRootVolume.setState(State.Stopped);
|
||||
vmHavingRootVolume.setDataCenterId(1L);
|
||||
when(userVmDaoMock.findById(4L)).thenReturn(vmHavingRootVolume);
|
||||
@ -314,7 +314,7 @@ public class VolumeApiServiceImplTest {
|
||||
upVolume.setState(Volume.State.Uploaded);
|
||||
when(volumeDaoMock.findById(8L)).thenReturn(upVolume);
|
||||
|
||||
UserVmVO kvmVm = new UserVmVO(4L, "vm", "vm", 1, HypervisorType.KVM, 1L, false, false, 1L, 1L, 1, 1L, null, "vm");
|
||||
UserVmVO kvmVm = new UserVmVO(4L, "vm", "vm", 1, HypervisorType.KVM, 1L, false, false, 1L, 1L, 1, 1L, null, null, null, "vm");
|
||||
kvmVm.setState(State.Running);
|
||||
kvmVm.setDataCenterId(1L);
|
||||
when(userVmDaoMock.findById(4L)).thenReturn(kvmVm);
|
||||
|
||||
@ -57,6 +57,7 @@ import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.ResourceLimitService;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
@ -67,6 +68,7 @@ import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||
@ -89,12 +91,14 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||
import org.apache.cloudstack.test.utils.SpringUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -132,6 +136,7 @@ import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||
public class TemplateManagerImplTest {
|
||||
|
||||
@ -186,6 +191,9 @@ public class TemplateManagerImplTest {
|
||||
@Inject
|
||||
HypervisorGuruManager _hvGuruMgr;
|
||||
|
||||
@Inject
|
||||
AccountManager _accountMgr;
|
||||
|
||||
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
AtomicInteger ai = new AtomicInteger(0);
|
||||
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
|
||||
@ -506,6 +514,80 @@ public class TemplateManagerImplTest {
|
||||
assertTrue("Template in a region store should have cross zones set", template.isCrossZones());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkUserDataToTemplate() {
|
||||
LinkUserDataToTemplateCmd cmd = Mockito.mock(LinkUserDataToTemplateCmd.class);
|
||||
when(cmd.getTemplateId()).thenReturn(1L);
|
||||
when(cmd.getIsoId()).thenReturn(null);
|
||||
when(cmd.getUserdataId()).thenReturn(2L);
|
||||
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(_tmpltDao.findById(anyLong())).thenReturn(template);
|
||||
|
||||
VirtualMachineTemplate resultTemplate = templateManager.linkUserDataToTemplate(cmd);
|
||||
|
||||
Assert.assertEquals(template, resultTemplate);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void testLinkUserDataToTemplateByProvidingBothISOAndTemplateId() {
|
||||
LinkUserDataToTemplateCmd cmd = Mockito.mock(LinkUserDataToTemplateCmd.class);
|
||||
when(cmd.getTemplateId()).thenReturn(1L);
|
||||
when(cmd.getIsoId()).thenReturn(1L);
|
||||
when(cmd.getUserdataId()).thenReturn(2L);
|
||||
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(_tmpltDao.findById(1L)).thenReturn(template);
|
||||
|
||||
templateManager.linkUserDataToTemplate(cmd);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void testLinkUserDataToTemplateByNotProvidingBothISOAndTemplateId() {
|
||||
LinkUserDataToTemplateCmd cmd = Mockito.mock(LinkUserDataToTemplateCmd.class);
|
||||
when(cmd.getTemplateId()).thenReturn(null);
|
||||
when(cmd.getIsoId()).thenReturn(null);
|
||||
when(cmd.getUserdataId()).thenReturn(2L);
|
||||
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(_tmpltDao.findById(1L)).thenReturn(template);
|
||||
|
||||
templateManager.linkUserDataToTemplate(cmd);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void testLinkUserDataToTemplateWhenNoTemplate() {
|
||||
LinkUserDataToTemplateCmd cmd = Mockito.mock(LinkUserDataToTemplateCmd.class);
|
||||
when(cmd.getTemplateId()).thenReturn(1L);
|
||||
when(cmd.getIsoId()).thenReturn(null);
|
||||
when(cmd.getUserdataId()).thenReturn(2L);
|
||||
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
when(_tmpltDao.findById(anyLong())).thenReturn(null);
|
||||
|
||||
templateManager.linkUserDataToTemplate(cmd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnLinkUserDataToTemplate() {
|
||||
LinkUserDataToTemplateCmd cmd = Mockito.mock(LinkUserDataToTemplateCmd.class);
|
||||
when(cmd.getTemplateId()).thenReturn(1L);
|
||||
when(cmd.getIsoId()).thenReturn(null);
|
||||
when(cmd.getUserdataId()).thenReturn(null);
|
||||
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(template.getId()).thenReturn(1L);
|
||||
when(_tmpltDao.findById(1L)).thenReturn(template);
|
||||
|
||||
VirtualMachineTemplate resultTemplate = templateManager.linkUserDataToTemplate(cmd);
|
||||
|
||||
Assert.assertEquals(template, resultTemplate);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = {TemplateManagerImpl.class},
|
||||
includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)},
|
||||
|
||||
@ -24,6 +24,8 @@ import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -33,7 +35,13 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.UserData;
|
||||
import com.cloud.user.UserDataVO;
|
||||
import com.cloud.user.dao.UserDataDao;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
@ -155,6 +163,9 @@ public class UserVmManagerImplTest {
|
||||
@Mock
|
||||
VolumeApiService volumeApiService;
|
||||
|
||||
@Mock
|
||||
UserDataDao userDataDao;
|
||||
|
||||
private long vmId = 1l;
|
||||
|
||||
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
||||
@ -254,6 +265,7 @@ public class UserVmManagerImplTest {
|
||||
Mockito.when(_serviceOfferingDao.findById(Mockito.anyLong(), Mockito.anyLong())).thenReturn((ServiceOfferingVO) offering);
|
||||
Mockito.when(userVmVoMock.isDisplay()).thenReturn(true);
|
||||
Mockito.doNothing().when(userVmManagerImpl).updateDisplayVmFlag(false, vmId, userVmVoMock);
|
||||
Mockito.when(updateVmCommand.getUserdataId()).thenReturn(null);
|
||||
userVmManagerImpl.updateVirtualMachine(updateVmCommand);
|
||||
verifyMethodsThatAreAlwaysExecuted();
|
||||
|
||||
@ -269,6 +281,7 @@ public class UserVmManagerImplTest {
|
||||
Mockito.when(updateVmCommand.isCleanupDetails()).thenReturn(true);
|
||||
Mockito.lenient().doNothing().when(userVmManagerImpl).updateDisplayVmFlag(false, vmId, userVmVoMock);
|
||||
Mockito.doNothing().when(userVmDetailVO).removeDetails(vmId);
|
||||
Mockito.when(updateVmCommand.getUserdataId()).thenReturn(null);
|
||||
|
||||
userVmManagerImpl.updateVirtualMachine(updateVmCommand);
|
||||
verifyMethodsThatAreAlwaysExecuted();
|
||||
@ -319,6 +332,7 @@ public class UserVmManagerImplTest {
|
||||
if(!isDetailsEmpty) {
|
||||
details.put("", "");
|
||||
}
|
||||
Mockito.when(updateVmCommand.getUserdataId()).thenReturn(null);
|
||||
Mockito.when(updateVmCommand.getDetails()).thenReturn(details);
|
||||
Mockito.when(updateVmCommand.isCleanupDetails()).thenReturn(cleanUpDetails);
|
||||
configureDoNothingForDetailsMethod();
|
||||
@ -345,7 +359,7 @@ public class UserVmManagerImplTest {
|
||||
|
||||
Mockito.verify(userVmManagerImpl).updateVirtualMachine(nullable(Long.class), nullable(String.class), nullable(String.class), nullable(Boolean.class),
|
||||
nullable(Boolean.class), nullable(Long.class),
|
||||
nullable(String.class), nullable(Boolean.class), nullable(HTTPMethod.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(List.class),
|
||||
nullable(String.class), nullable(Long.class), nullable(String.class), nullable(Boolean.class), nullable(HTTPMethod.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(List.class),
|
||||
nullable(Map.class));
|
||||
|
||||
}
|
||||
@ -356,7 +370,7 @@ public class UserVmManagerImplTest {
|
||||
Mockito.doReturn(new ArrayList<Long>()).when(userVmManagerImpl).getSecurityGroupIdList(updateVmCommand);
|
||||
Mockito.lenient().doReturn(Mockito.mock(UserVm.class)).when(userVmManagerImpl).updateVirtualMachine(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(), Mockito.anyLong(),
|
||||
Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(HTTPMethod.class), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyListOf(Long.class),
|
||||
Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(HTTPMethod.class), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyListOf(Long.class),
|
||||
Mockito.anyMap());
|
||||
}
|
||||
|
||||
@ -573,4 +587,231 @@ public class UserVmManagerImplTest {
|
||||
Mockito.when(newRootDiskOffering.getName()).thenReturn("OfferingName");
|
||||
return newRootDiskOffering;
|
||||
}
|
||||
|
||||
@Test (expected = CloudRuntimeException.class)
|
||||
public void testUserDataDenyOverride() {
|
||||
Long userDataId = 1L;
|
||||
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(2L);
|
||||
when(template.getUserDataOverridePolicy()).thenReturn(UserData.UserDataOverridePolicy.DENYOVERRIDE);
|
||||
|
||||
userVmManagerImpl.finalizeUserData(null, userDataId, template);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataAllowOverride() {
|
||||
String templateUserData = "testTemplateUserdata";
|
||||
Long userDataId = 1L;
|
||||
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(2L);
|
||||
when(template.getUserDataOverridePolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
|
||||
UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
doReturn(apiUserDataVO).when(userDataDao).findById(userDataId);
|
||||
when(apiUserDataVO.getUserData()).thenReturn(templateUserData);
|
||||
|
||||
String finalUserdata = userVmManagerImpl.finalizeUserData(null, userDataId, template);
|
||||
|
||||
Assert.assertEquals(finalUserdata, templateUserData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataAppend() {
|
||||
String userData = "testUserdata";
|
||||
String templateUserData = "testTemplateUserdata";
|
||||
Long userDataId = 1L;
|
||||
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(2L);
|
||||
when(template.getUserDataOverridePolicy()).thenReturn(UserData.UserDataOverridePolicy.APPEND);
|
||||
|
||||
UserDataVO templateUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
doReturn(templateUserDataVO).when(userDataDao).findById(2L);
|
||||
when(templateUserDataVO.getUserData()).thenReturn(templateUserData);
|
||||
|
||||
UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
doReturn(apiUserDataVO).when(userDataDao).findById(userDataId);
|
||||
when(apiUserDataVO.getUserData()).thenReturn(userData);
|
||||
|
||||
String finalUserdata = userVmManagerImpl.finalizeUserData(null, userDataId, template);
|
||||
|
||||
Assert.assertEquals(finalUserdata, templateUserData+userData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataWithoutTemplate() {
|
||||
String userData = "testUserdata";
|
||||
Long userDataId = 1L;
|
||||
|
||||
UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
doReturn(apiUserDataVO).when(userDataDao).findById(userDataId);
|
||||
when(apiUserDataVO.getUserData()).thenReturn(userData);
|
||||
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(null);
|
||||
|
||||
String finalUserdata = userVmManagerImpl.finalizeUserData(null, userDataId, template);
|
||||
|
||||
Assert.assertEquals(finalUserdata, userData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataAllowOverrideWithoutAPIuserdata() {
|
||||
String templateUserData = "testTemplateUserdata";
|
||||
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(2L);
|
||||
when(template.getUserDataOverridePolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
|
||||
UserDataVO templateUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
doReturn(templateUserDataVO).when(userDataDao).findById(2L);
|
||||
when(templateUserDataVO.getUserData()).thenReturn(templateUserData);
|
||||
|
||||
String finalUserdata = userVmManagerImpl.finalizeUserData(null, null, template);
|
||||
|
||||
Assert.assertEquals(finalUserdata, templateUserData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDataAllowOverrideWithUserdataText() {
|
||||
String userData = "testUserdata";
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
when(template.getUserDataId()).thenReturn(null);
|
||||
|
||||
String finalUserdata = userVmManagerImpl.finalizeUserData(userData, null, template);
|
||||
|
||||
Assert.assertEquals(finalUserdata, userData);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
public void testResetVMUserDataVMStateNotStopped() {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
Mockito.lenient().doReturn(accountMock).when(callContextMock).getCallingAccount();
|
||||
|
||||
ResetVMUserDataCmd cmd = Mockito.mock(ResetVMUserDataCmd.class);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
when(userVmDao.findById(1L)).thenReturn(userVmVoMock);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(userVmVoMock.getTemplateId()).thenReturn(2L);
|
||||
when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
|
||||
|
||||
|
||||
when(userVmVoMock.getState()).thenReturn(VirtualMachine.State.Running);
|
||||
|
||||
try {
|
||||
userVmManagerImpl.resetVMUserData(cmd);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InsufficientCapacityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
@PrepareForTest(CallContext.class)
|
||||
public void testResetVMUserDataDontAcceptBothUserdataAndUserdataId() {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
Mockito.lenient().doReturn(accountMock).when(callContextMock).getCallingAccount();
|
||||
|
||||
ResetVMUserDataCmd cmd = Mockito.mock(ResetVMUserDataCmd.class);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
when(userVmDao.findById(1L)).thenReturn(userVmVoMock);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(userVmVoMock.getTemplateId()).thenReturn(2L);
|
||||
when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
|
||||
|
||||
|
||||
when(userVmVoMock.getState()).thenReturn(VirtualMachine.State.Stopped);
|
||||
|
||||
when(cmd.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getUserdataId()).thenReturn(1L);
|
||||
|
||||
try {
|
||||
userVmManagerImpl.resetVMUserData(cmd);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InsufficientCapacityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@PrepareForTest(CallContext.class)
|
||||
public void testResetVMUserDataSuccessResetWithUserdata() {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
Mockito.lenient().doReturn(accountMock).when(callContextMock).getCallingAccount();
|
||||
|
||||
UserVmVO userVmVO = new UserVmVO();
|
||||
userVmVO.setTemplateId(2L);
|
||||
userVmVO.setState(VirtualMachine.State.Stopped);
|
||||
userVmVO.setUserDataId(100L);
|
||||
userVmVO.setUserData("RandomUserdata");
|
||||
|
||||
ResetVMUserDataCmd cmd = Mockito.mock(ResetVMUserDataCmd.class);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
when(userVmDao.findById(1L)).thenReturn(userVmVO);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
|
||||
when(template.getUserDataId()).thenReturn(null);
|
||||
|
||||
when(cmd.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getUserdataId()).thenReturn(null);
|
||||
when(cmd.getHttpMethod()).thenReturn(HTTPMethod.GET);
|
||||
|
||||
try {
|
||||
doNothing().when(userVmManagerImpl).updateUserData(userVmVO);
|
||||
userVmManagerImpl.resetVMUserData(cmd);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InsufficientCapacityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Assert.assertEquals("testUserdata", userVmVO.getUserData());
|
||||
Assert.assertEquals(null, userVmVO.getUserDataId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@PrepareForTest(CallContext.class)
|
||||
public void testResetVMUserDataSuccessResetWithUserdataId() {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
Mockito.lenient().doReturn(accountMock).when(callContextMock).getCallingAccount();
|
||||
|
||||
UserVmVO userVmVO = new UserVmVO();
|
||||
userVmVO.setTemplateId(2L);
|
||||
userVmVO.setState(VirtualMachine.State.Stopped);
|
||||
userVmVO.setUserDataId(100L);
|
||||
userVmVO.setUserData("RandomUserdata");
|
||||
|
||||
ResetVMUserDataCmd cmd = Mockito.mock(ResetVMUserDataCmd.class);
|
||||
when(cmd.getId()).thenReturn(1L);
|
||||
when(userVmDao.findById(1L)).thenReturn(userVmVO);
|
||||
|
||||
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
|
||||
when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
|
||||
when(template.getUserDataId()).thenReturn(null);
|
||||
|
||||
when(cmd.getUserdataId()).thenReturn(1L);
|
||||
UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
|
||||
when(userDataDao.findById(1L)).thenReturn(apiUserDataVO);
|
||||
when(apiUserDataVO.getUserData()).thenReturn("testUserdata");
|
||||
when(cmd.getHttpMethod()).thenReturn(HTTPMethod.GET);
|
||||
|
||||
try {
|
||||
doNothing().when(userVmManagerImpl).updateUserData(userVmVO);
|
||||
userVmManagerImpl.resetVMUserData(cmd);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InsufficientCapacityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Assert.assertEquals("testUserdata", userVmVO.getUserData());
|
||||
Assert.assertEquals(1L, (long)userVmVO.getUserDataId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -516,7 +516,7 @@ public class UserVmManagerTest {
|
||||
AccountVO newAccount = new AccountVO("testaccount", 1, "networkdomain", Account.Type.ADMIN, UUID.randomUUID().toString());
|
||||
newAccount.setId(2L);
|
||||
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 1L, HypervisorType.Any, 1L, false, false, 1L, 1L, 1, 5L, "test", "test");
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 1L, HypervisorType.Any, 1L, false, false, 1L, 1L, 1, 5L, "test", null, null, "test");
|
||||
vm.setState(VirtualMachine.State.Stopped);
|
||||
when(_vmDao.findById(anyLong())).thenReturn(vm);
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ public class UserVmDaoImplTest extends TestCase {
|
||||
// Persist the data.
|
||||
UserVmVO vo =
|
||||
new UserVmVO(vmId, instanceName, displayName, templateId, hypervisor, guestOsId, haEnabled, limitCpuUse, domainId, accountId, 1, serviceOfferingId, userdata,
|
||||
name);
|
||||
null, null, name);
|
||||
dao.persist(vo);
|
||||
|
||||
vo = dao.findById(vmId);
|
||||
|
||||
@ -926,7 +926,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
|
||||
public List<String[]> generateVmData(String userData, String userDataDetails, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -205,7 +205,7 @@ public class AffinityApiUnitTest {
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void updateAffinityGroupVMRunning() throws ResourceInUseException {
|
||||
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", "test");
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, domainId, 200L, 1, 5L, "", null, null, "test");
|
||||
vm.setState(VirtualMachine.State.Running);
|
||||
when(_vmDao.findById(10L)).thenReturn(vm);
|
||||
|
||||
|
||||
@ -270,7 +270,7 @@ public class AffinityGroupServiceImplTest {
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
public void updateAffinityGroupVMRunning() throws ResourceInUseException {
|
||||
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, DOMAIN_ID, 200L, 1, 5L, "", "test");
|
||||
UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, DOMAIN_ID, 200L, 1, 5L, "", null, null, "test");
|
||||
vm.setState(VirtualMachine.State.Running);
|
||||
when(_vmDao.findById(10L)).thenReturn(vm);
|
||||
|
||||
|
||||
766
test/integration/smoke/test_register_userdata.py
Normal file
766
test/integration/smoke/test_register_userdata.py
Normal file
@ -0,0 +1,766 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#All tests inherit from cloudstackTestCase
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.lib.base import (ServiceOffering,
|
||||
VirtualMachine,
|
||||
Account,
|
||||
UserData,
|
||||
NetworkOffering,
|
||||
Network,
|
||||
Router,
|
||||
EgressFireWallRule,
|
||||
PublicIPAddress,
|
||||
NATRule,
|
||||
Template)
|
||||
from marvin.lib.common import get_test_template, get_zone, list_virtual_machines
|
||||
from marvin.lib.utils import (validateList, cleanup_resources)
|
||||
from nose.plugins.attrib import attr
|
||||
from marvin.codes import PASS,FAIL
|
||||
|
||||
|
||||
from marvin.lib.common import (get_domain, get_template)
|
||||
|
||||
class Services:
|
||||
def __init__(self):
|
||||
self.services = {
|
||||
"virtual_machine": {
|
||||
"displayname": "TesVM1",
|
||||
"username": "root",
|
||||
"password": "password",
|
||||
"ssh_port": 22,
|
||||
"privateport": 22,
|
||||
"publicport": 22,
|
||||
"protocol": 'TCP',
|
||||
},
|
||||
"ostype": 'CentOS 5.5 (64-bit)',
|
||||
"service_offering": {
|
||||
"name": "Tiny Instance",
|
||||
"displaytext": "Tiny Instance",
|
||||
"cpunumber": 1,
|
||||
"cpuspeed": 100,
|
||||
"memory": 256,
|
||||
},
|
||||
"egress": {
|
||||
"name": 'web',
|
||||
"protocol": 'TCP',
|
||||
"startport": 80,
|
||||
"endport": 80,
|
||||
"cidrlist": '0.0.0.0/0',
|
||||
},
|
||||
"natrule": {
|
||||
"privateport": 22,
|
||||
"publicport": 22,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
}
|
||||
|
||||
class TestRegisteredUserdata(cloudstackTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestRegisteredUserdata, cls)
|
||||
cls.api_client = cls.testClient.getApiClient()
|
||||
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
|
||||
cls.services = Services().services
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.testdata = self.testClient.getParsedTestDataConfig()
|
||||
|
||||
# Get Zone, Domain and Default Built-in template
|
||||
self.domain = get_domain(self.apiclient)
|
||||
self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
|
||||
|
||||
#create a user account
|
||||
self.account = Account.create(
|
||||
self.apiclient,
|
||||
self.testdata["account"],
|
||||
domainid=self.domain.id
|
||||
)
|
||||
|
||||
self.testdata["mode"] = self.zone.networktype
|
||||
self.template = get_template(self.apiclient, self.zone.id, self.testdata["ostype"])
|
||||
|
||||
#create a service offering
|
||||
small_service_offering = self.testdata["service_offerings"]["small"]
|
||||
self.service_offering = ServiceOffering.create(
|
||||
self.apiclient,
|
||||
small_service_offering
|
||||
)
|
||||
|
||||
self.no_isolate = NetworkOffering.create(
|
||||
self.apiclient,
|
||||
self.testdata["isolated_network_offering"]
|
||||
)
|
||||
self.no_isolate.update(self.apiclient, state='Enabled')
|
||||
self.isolated_network = Network.create(
|
||||
self.apiclient,
|
||||
self.testdata["network"],
|
||||
networkofferingid=self.no_isolate.id,
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1
|
||||
)
|
||||
|
||||
#build cleanup list
|
||||
self.cleanup = [
|
||||
self.service_offering,
|
||||
self.isolated_network,
|
||||
self.no_isolate,
|
||||
self.account,
|
||||
]
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
cleanup_resources(self.apiclient, self.cleanup)
|
||||
except Exception as e:
|
||||
self.debug("Warning! Exception in tearDown: %s" % e)
|
||||
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
|
||||
def test_CRUD_operations_userdata(self):
|
||||
"""Test register, list, update operations on userdata
|
||||
1. Register a userdata
|
||||
2. List the registered userdata
|
||||
3. Delete the registered userdata
|
||||
"""
|
||||
|
||||
self.userdata1 = UserData.register(
|
||||
self.apiclient,
|
||||
name="UserdataName",
|
||||
userdata="VGVzdFVzZXJEYXRh", #TestUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
list_userdata = UserData.list(self.apiclient, id=self.userdata1.userdata.id, listall=True)
|
||||
|
||||
self.assertNotEqual(
|
||||
len(list_userdata),
|
||||
0,
|
||||
"List userdata was empty"
|
||||
)
|
||||
|
||||
userdata = list_userdata[0]
|
||||
self.assertEqual(
|
||||
userdata.id,
|
||||
self.userdata1.userdata.id,
|
||||
"userdata ids do not match"
|
||||
)
|
||||
|
||||
UserData.delete(
|
||||
self.apiclient,
|
||||
id=self.userdata1.userdata.id
|
||||
)
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=True)
|
||||
def test_deploy_vm_with_registered_userdata(self):
|
||||
"""Test deploy VM with registered userdata
|
||||
1. Register a userdata
|
||||
2. Deploy a VM by passing the userdata id
|
||||
3. Test the VM response
|
||||
4. SSH into VM and access the userdata
|
||||
"""
|
||||
|
||||
self.userdata2 = UserData.register(
|
||||
self.apiclient,
|
||||
name="testUserData2",
|
||||
userdata="VGVzdFVzZXJEYXRh", #TestUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.services["virtual_machine"],
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
templateid=self.template.id,
|
||||
networkids=[self.isolated_network.id],
|
||||
userdataid=self.userdata2.userdata.id
|
||||
)
|
||||
self.cleanup.append(self.virtual_machine)
|
||||
self.cleanup.append(self.userdata2)
|
||||
|
||||
networkid = self.virtual_machine.nic[0].networkid
|
||||
src_nat_list = PublicIPAddress.list(
|
||||
self.apiclient,
|
||||
associatednetworkid=networkid,
|
||||
account="admin",
|
||||
domainid=1,
|
||||
listall=True,
|
||||
issourcenat=True,
|
||||
)
|
||||
src_nat = src_nat_list[0]
|
||||
|
||||
NATRule.create(
|
||||
self.apiclient,
|
||||
self.virtual_machine,
|
||||
self.services["natrule"],
|
||||
src_nat.id
|
||||
)
|
||||
|
||||
# create egress rule to allow wget of my cloud-set-guest-password script
|
||||
if self.zone.networktype.lower() == 'advanced':
|
||||
EgressFireWallRule.create(self.api_client,
|
||||
networkid=networkid,
|
||||
protocol=self.testdata["egress_80"]["protocol"],
|
||||
startport=self.testdata["egress_80"]["startport"],
|
||||
endport=self.testdata["egress_80"]["endport"],
|
||||
cidrlist=self.testdata["egress_80"]["cidrlist"])
|
||||
|
||||
list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)
|
||||
|
||||
self.assertEqual(
|
||||
isinstance(list_vms, list),
|
||||
True,
|
||||
"List VM response was not a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_vms),
|
||||
0,
|
||||
"List VM response was empty"
|
||||
)
|
||||
|
||||
vm = list_vms[0]
|
||||
self.assertEqual(
|
||||
vm.id,
|
||||
self.virtual_machine.id,
|
||||
"Virtual Machine ids do not match"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.state,
|
||||
"Running",
|
||||
msg="VM is not in Running state"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.userdataid,
|
||||
self.userdata2.userdata.id,
|
||||
"Virtual Machine names do not match"
|
||||
)
|
||||
|
||||
# Verify the retrieved ip address in listNICs API response
|
||||
self.list_nics(vm.id)
|
||||
vr_res = Router.list(
|
||||
self.apiclient,
|
||||
networkid=self.isolated_network.id,
|
||||
listAll=True
|
||||
)
|
||||
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
|
||||
vr_ip = vr_res[0].guestipaddress
|
||||
ssh = self.virtual_machine.get_ssh_client(ipaddress=src_nat.ipaddress)
|
||||
cmd = "curl http://%s/latest/user-data" % vr_ip
|
||||
res = ssh.execute(cmd)
|
||||
self.debug("Verifying userdata in the VR")
|
||||
self.assertEqual(
|
||||
str(res[0]),
|
||||
"TestUserData",
|
||||
"Failed to match userdata"
|
||||
)
|
||||
|
||||
def list_nics(self, vm_id):
|
||||
list_vm_res = VirtualMachine.list(self.apiclient, id=vm_id)
|
||||
self.assertEqual(validateList(list_vm_res)[0], PASS, "List vms returned invalid response")
|
||||
nics = list_vm_res[0].nic
|
||||
for nic in nics:
|
||||
if nic.type == "Shared":
|
||||
nic_res = NIC.list(
|
||||
self.apiclient,
|
||||
virtualmachineid=vm_id,
|
||||
nicid=nic.id
|
||||
)
|
||||
nic_ip = nic_res[0].ipaddress
|
||||
self.assertIsNotNone(nic_ip, "listNics API response does not have the ip address")
|
||||
else:
|
||||
continue
|
||||
return
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=True)
|
||||
def test_deploy_vm_with_registered_userdata_with_params(self):
|
||||
"""Test deploy VM with registered userdata with variables
|
||||
1. Register a userdata having variables
|
||||
2. Deploy a VM by passing the userdata id and custom userdata params map with values
|
||||
3. Test the VM response
|
||||
4. SSH into VM and access the userdata, check if values got rendered for the decalared variables in userdata
|
||||
"""
|
||||
self.userdata2 = UserData.register(
|
||||
self.apiclient,
|
||||
name="testUserData2",
|
||||
userdata="IyMgdGVtcGxhdGU6IGppbmphCiNjbG91ZC1jb25maWcKcnVuY21kOgogICAgLSBlY2hvICdrZXkge3sgZHMubWV0YV9kYXRhLmtleTEgfX0nID4+IC9yb290L2luc3RhbmNlX21ldGFkYXRh",
|
||||
# ## template: jinja
|
||||
# #cloud-config
|
||||
# runcmd:
|
||||
# - echo 'key {{ ds.meta_data.key1 }}' >> /root/instance_metadata
|
||||
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.services["virtual_machine"],
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
templateid=self.template.id,
|
||||
networkids=[self.isolated_network.id],
|
||||
userdataid=self.userdata2.userdata.id,
|
||||
userdatadetails=[{"key1": "value1"}]
|
||||
)
|
||||
self.cleanup.append(self.virtual_machine)
|
||||
self.cleanup.append(self.userdata2)
|
||||
|
||||
networkid = self.virtual_machine.nic[0].networkid
|
||||
src_nat_list = PublicIPAddress.list(
|
||||
self.apiclient,
|
||||
associatednetworkid=networkid,
|
||||
account="admin",
|
||||
domainid=1,
|
||||
listall=True,
|
||||
issourcenat=True,
|
||||
)
|
||||
src_nat = src_nat_list[0]
|
||||
|
||||
NATRule.create(
|
||||
self.apiclient,
|
||||
self.virtual_machine,
|
||||
self.services["natrule"],
|
||||
src_nat.id
|
||||
)
|
||||
|
||||
# create egress rule to allow wget of my cloud-set-guest-password script
|
||||
if self.zone.networktype.lower() == 'advanced':
|
||||
EgressFireWallRule.create(self.api_client,
|
||||
networkid=networkid,
|
||||
protocol=self.testdata["egress_80"]["protocol"],
|
||||
startport=self.testdata["egress_80"]["startport"],
|
||||
endport=self.testdata["egress_80"]["endport"],
|
||||
cidrlist=self.testdata["egress_80"]["cidrlist"])
|
||||
|
||||
list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)
|
||||
|
||||
self.assertEqual(
|
||||
isinstance(list_vms, list),
|
||||
True,
|
||||
"List VM response was not a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_vms),
|
||||
0,
|
||||
"List VM response was empty"
|
||||
)
|
||||
|
||||
vm = list_vms[0]
|
||||
self.assertEqual(
|
||||
vm.id,
|
||||
self.virtual_machine.id,
|
||||
"Virtual Machine ids do not match"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.state,
|
||||
"Running",
|
||||
msg="VM is not in Running state"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.userdataid,
|
||||
self.userdata2.userdata.id,
|
||||
"Userdata ids do not match"
|
||||
)
|
||||
|
||||
# Verify the retrieved ip address in listNICs API response
|
||||
self.list_nics(vm.id)
|
||||
vr_res = Router.list(
|
||||
self.apiclient,
|
||||
networkid=self.isolated_network.id,
|
||||
listAll=True
|
||||
)
|
||||
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
|
||||
vr_ip = vr_res[0].guestipaddress
|
||||
ssh = self.virtual_machine.get_ssh_client(ipaddress=src_nat.ipaddress)
|
||||
cmd = "curl http://%s/latest/meta-data/key1" % vr_ip
|
||||
res = ssh.execute(cmd)
|
||||
self.debug("Verifying userdata in the VR")
|
||||
self.assertEqual(
|
||||
str(res[0]),
|
||||
"value1",
|
||||
"Failed to match userdata"
|
||||
)
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
|
||||
def test_link_and_unlink_userdata_to_template(self):
|
||||
"""Test link and unlink of userdata to a template
|
||||
1. Register a userdata
|
||||
2. Link the registered userdata to a template
|
||||
3. Verify the template response and check userdata details in it
|
||||
4. Unlink the registered userdata from template
|
||||
5. Verify the template response
|
||||
"""
|
||||
|
||||
self.userdata3 = UserData.register(
|
||||
self.apiclient,
|
||||
name="testUserData2",
|
||||
userdata="VGVzdFVzZXJEYXRh", #TestUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id,
|
||||
userdataid=self.userdata3.userdata.id
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.userdata3.userdata.id,
|
||||
self.template.userdataid,
|
||||
"Match userdata id in template response"
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.template.userdatapolicy,
|
||||
"ALLOWOVERRIDE",
|
||||
"Match default userdata override policy in template response"
|
||||
)
|
||||
|
||||
self.debug("Verifying unlinking of userdata from template " + self.template.id)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.template.userdataid,
|
||||
None,
|
||||
"Check userdata id in template response is None"
|
||||
)
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=True)
|
||||
def test_deploy_vm_with_registered_userdata_with_override_policy_allow(self):
|
||||
"""Test deploy VM with registered userdata with variables
|
||||
1. Register two userdata, one to link to template and another to pass while deploying VM
|
||||
2. Link a userdata to template, default override policy is allow override
|
||||
3. Deploy a VM with that template and also by passing another userdata id
|
||||
4. Since the override policy is allow override, userdata id passed during VM deployment will be consider.
|
||||
Verify the same by SSH into VM.
|
||||
"""
|
||||
|
||||
self.apiUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="ApiUserdata",
|
||||
userdata="QVBJdXNlcmRhdGE=", #APIuserdata
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.templateUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="TemplateUserdata",
|
||||
userdata="VGVtcGxhdGVVc2VyRGF0YQ==", #TemplateUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id,
|
||||
userdataid=self.templateUserdata.userdata.id,
|
||||
userdatapolicy="allowoverride"
|
||||
)
|
||||
|
||||
self.virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.services["virtual_machine"],
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
templateid=self.template.id,
|
||||
networkids=[self.isolated_network.id],
|
||||
userdataid=self.apiUserdata.userdata.id
|
||||
)
|
||||
self.cleanup.append(self.virtual_machine)
|
||||
self.cleanup.append(self.apiUserdata)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id
|
||||
)
|
||||
|
||||
networkid = self.virtual_machine.nic[0].networkid
|
||||
src_nat_list = PublicIPAddress.list(
|
||||
self.apiclient,
|
||||
associatednetworkid=networkid,
|
||||
account="admin",
|
||||
domainid=1,
|
||||
listall=True,
|
||||
issourcenat=True,
|
||||
)
|
||||
src_nat = src_nat_list[0]
|
||||
|
||||
NATRule.create(
|
||||
self.apiclient,
|
||||
self.virtual_machine,
|
||||
self.services["natrule"],
|
||||
src_nat.id
|
||||
)
|
||||
|
||||
# create egress rule to allow wget of my cloud-set-guest-password script
|
||||
if self.zone.networktype.lower() == 'advanced':
|
||||
EgressFireWallRule.create(self.api_client,
|
||||
networkid=networkid,
|
||||
protocol=self.testdata["egress_80"]["protocol"],
|
||||
startport=self.testdata["egress_80"]["startport"],
|
||||
endport=self.testdata["egress_80"]["endport"],
|
||||
cidrlist=self.testdata["egress_80"]["cidrlist"])
|
||||
|
||||
list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)
|
||||
|
||||
self.assertEqual(
|
||||
isinstance(list_vms, list),
|
||||
True,
|
||||
"List VM response was not a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_vms),
|
||||
0,
|
||||
"List VM response was empty"
|
||||
)
|
||||
|
||||
vm = list_vms[0]
|
||||
self.assertEqual(
|
||||
vm.id,
|
||||
self.virtual_machine.id,
|
||||
"Virtual Machine ids do not match"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.state,
|
||||
"Running",
|
||||
msg="VM is not in Running state"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.userdataid,
|
||||
self.apiUserdata.userdata.id,
|
||||
"Virtual Machine names do not match"
|
||||
)
|
||||
|
||||
# Verify the retrieved ip address in listNICs API response
|
||||
self.list_nics(vm.id)
|
||||
vr_res = Router.list(
|
||||
self.apiclient,
|
||||
networkid=self.isolated_network.id,
|
||||
listAll=True
|
||||
)
|
||||
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
|
||||
vr_ip = vr_res[0].guestipaddress
|
||||
ssh = self.virtual_machine.get_ssh_client(ipaddress=src_nat.ipaddress)
|
||||
cmd = "curl http://%s/latest/user-data" % vr_ip
|
||||
res = ssh.execute(cmd)
|
||||
self.debug("Verifying userdata in the VR")
|
||||
self.assertEqual(
|
||||
str(res[0]),
|
||||
"APIuserdata",
|
||||
"Failed to match userdata"
|
||||
)
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=True)
|
||||
def test_deploy_vm_with_registered_userdata_with_override_policy_append(self):
|
||||
"""Test deploy VM with registered userdata with variables
|
||||
1. Register two userdata, one to link to template and another to pass while deploying VM
|
||||
2. Link a userdata to template with override policy is append
|
||||
3. Deploy a VM with that template and also by passing another userdata id
|
||||
4. Since the override policy is append, userdata passed during VM deployment will be appended to template's
|
||||
userdata and configured to VM. Verify the same by SSH into VM.
|
||||
"""
|
||||
|
||||
self.apiUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="ApiUserdata",
|
||||
userdata="QVBJdXNlcmRhdGE=", #APIuserdata
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.templateUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="TemplateUserdata",
|
||||
userdata="VGVtcGxhdGVVc2VyRGF0YQ==", #TemplateUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id,
|
||||
userdataid=self.templateUserdata.userdata.id,
|
||||
userdatapolicy="append"
|
||||
)
|
||||
|
||||
self.virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.services["virtual_machine"],
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
templateid=self.template.id,
|
||||
networkids=[self.isolated_network.id],
|
||||
userdataid=self.apiUserdata.userdata.id
|
||||
)
|
||||
self.cleanup.append(self.virtual_machine)
|
||||
self.cleanup.append(self.apiUserdata)
|
||||
self.cleanup.append(self.templateUserdata)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id
|
||||
)
|
||||
|
||||
networkid = self.virtual_machine.nic[0].networkid
|
||||
src_nat_list = PublicIPAddress.list(
|
||||
self.apiclient,
|
||||
associatednetworkid=networkid,
|
||||
account="admin",
|
||||
domainid=1,
|
||||
listall=True,
|
||||
issourcenat=True,
|
||||
)
|
||||
src_nat = src_nat_list[0]
|
||||
|
||||
NATRule.create(
|
||||
self.apiclient,
|
||||
self.virtual_machine,
|
||||
self.services["natrule"],
|
||||
src_nat.id
|
||||
)
|
||||
|
||||
# create egress rule to allow wget of my cloud-set-guest-password script
|
||||
if self.zone.networktype.lower() == 'advanced':
|
||||
EgressFireWallRule.create(self.api_client,
|
||||
networkid=networkid,
|
||||
protocol=self.testdata["egress_80"]["protocol"],
|
||||
startport=self.testdata["egress_80"]["startport"],
|
||||
endport=self.testdata["egress_80"]["endport"],
|
||||
cidrlist=self.testdata["egress_80"]["cidrlist"])
|
||||
|
||||
list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)
|
||||
|
||||
self.assertEqual(
|
||||
isinstance(list_vms, list),
|
||||
True,
|
||||
"List VM response was not a valid list"
|
||||
)
|
||||
self.assertNotEqual(
|
||||
len(list_vms),
|
||||
0,
|
||||
"List VM response was empty"
|
||||
)
|
||||
|
||||
vm = list_vms[0]
|
||||
self.assertEqual(
|
||||
vm.id,
|
||||
self.virtual_machine.id,
|
||||
"Virtual Machine ids do not match"
|
||||
)
|
||||
self.assertEqual(
|
||||
vm.state,
|
||||
"Running",
|
||||
msg="VM is not in Running state"
|
||||
)
|
||||
|
||||
# Verify the retrieved ip address in listNICs API response
|
||||
self.list_nics(vm.id)
|
||||
vr_res = Router.list(
|
||||
self.apiclient,
|
||||
networkid=self.isolated_network.id,
|
||||
listAll=True
|
||||
)
|
||||
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
|
||||
vr_ip = vr_res[0].guestipaddress
|
||||
ssh = self.virtual_machine.get_ssh_client(ipaddress=src_nat.ipaddress)
|
||||
cmd = "curl http://%s/latest/user-data" % vr_ip
|
||||
res = ssh.execute(cmd)
|
||||
self.debug("Verifying userdata in the VR")
|
||||
self.assertEqual(
|
||||
str(res[0]),
|
||||
"TemplateUserDataAPIuserdata",
|
||||
"Failed to match userdata"
|
||||
)
|
||||
|
||||
@attr(tags=['advanced', 'simulator', 'basic', 'sg', 'testnow'], required_hardware=True)
|
||||
def test_deploy_vm_with_registered_userdata_with_override_policy_deny(self):
|
||||
"""Test deploy VM with registered userdata with variables
|
||||
1. Register two userdata, one to link to template and another to pass while deploying VM
|
||||
2. Link a userdata to template with override policy is deny override
|
||||
3. Deploy a VM with that template and also by passing another userdata id
|
||||
4. Since the override policy is deny override, userdata passed during VM deployment will not be accepted.
|
||||
So expect an exception.
|
||||
"""
|
||||
|
||||
self.apiUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="ApiUserdata",
|
||||
userdata="QVBJdXNlcmRhdGE=", #APIuserdata
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.templateUserdata = UserData.register(
|
||||
self.apiclient,
|
||||
name="TemplateUserdata",
|
||||
userdata="VGVtcGxhdGVVc2VyRGF0YQ==", #TemplateUserData
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id,
|
||||
userdataid=self.templateUserdata.userdata.id,
|
||||
userdatapolicy="denyoverride"
|
||||
)
|
||||
|
||||
with self.assertRaises(Exception) as e:
|
||||
self.virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.services["virtual_machine"],
|
||||
zoneid=self.zone.id,
|
||||
accountid="admin",
|
||||
domainid=1,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
templateid=self.template.id,
|
||||
networkids=[self.isolated_network.id],
|
||||
userdataid=self.apiUserdata.userdata.id
|
||||
)
|
||||
self.cleanup.append(self.virtual_machine)
|
||||
self.debug("Deploy VM with userdata passed during deployment failed as expected because template userdata override policy is deny. Exception here is : %s" %
|
||||
e.exception)
|
||||
|
||||
self.cleanup.append(self.apiUserdata)
|
||||
self.cleanup.append(self.templateUserdata)
|
||||
|
||||
self.template = Template.linkUserDataToTemplate(
|
||||
self.apiclient,
|
||||
templateid=self.template.id
|
||||
)
|
||||
|
||||
|
||||
@ -522,7 +522,7 @@ class VirtualMachine:
|
||||
method='GET', hypervisor=None, customcpunumber=None,
|
||||
customcpuspeed=None, custommemory=None, rootdisksize=None,
|
||||
rootdiskcontroller=None, vpcid=None, macaddress=None, datadisktemplate_diskoffering_list={},
|
||||
properties=None, nicnetworklist=None, bootmode=None, boottype=None, dynamicscalingenabled=None):
|
||||
properties=None, nicnetworklist=None, bootmode=None, boottype=None, dynamicscalingenabled=None, userdataid=None, userdatadetails=None):
|
||||
"""Create the instance"""
|
||||
|
||||
cmd = deployVirtualMachine.deployVirtualMachineCmd()
|
||||
@ -612,6 +612,12 @@ class VirtualMachine:
|
||||
if "userdata" in services:
|
||||
cmd.userdata = base64.urlsafe_b64encode(services["userdata"].encode()).decode()
|
||||
|
||||
if userdataid is not None:
|
||||
cmd.userdataid = userdataid
|
||||
|
||||
if userdatadetails is not None:
|
||||
cmd.userdatadetails = userdatadetails
|
||||
|
||||
if "dhcpoptionsnetworklist" in services:
|
||||
cmd.dhcpoptionsnetworklist = services["dhcpoptionsnetworklist"]
|
||||
|
||||
@ -1665,6 +1671,18 @@ class Template:
|
||||
cmd.listall = True
|
||||
return (apiclient.listTemplates(cmd))
|
||||
|
||||
@classmethod
|
||||
def linkUserDataToTemplate(cls, apiclient, templateid, userdataid=None, userdatapolicy=None):
|
||||
"Link userdata to template "
|
||||
|
||||
cmd = linkUserDataToTemplate.linkUserDataToTemplateCmd()
|
||||
cmd.templateid = templateid
|
||||
if userdataid is not None:
|
||||
cmd.userdataid = userdataid
|
||||
if userdatapolicy is not None:
|
||||
cmd.userdatapolicy = userdatapolicy
|
||||
|
||||
return apiclient.linkUserDataToTemplate(cmd)
|
||||
|
||||
class Iso:
|
||||
"""Manage ISO life cycle"""
|
||||
@ -4998,6 +5016,45 @@ class SSHKeyPair:
|
||||
cmd.listall = True
|
||||
return (apiclient.listSSHKeyPairs(cmd))
|
||||
|
||||
class UserData:
|
||||
"""Manage Userdata"""
|
||||
|
||||
def __init__(self, items, services):
|
||||
self.__dict__.update(items)
|
||||
|
||||
@classmethod
|
||||
def register(cls, apiclient, name=None, account=None,
|
||||
domainid=None, projectid=None, userdata=None, params=None):
|
||||
"""Registers Userdata"""
|
||||
cmd = registerUserData.registerUserDataCmd()
|
||||
cmd.name = name
|
||||
cmd.userdata = userdata
|
||||
if params is not None:
|
||||
cmd.params = params
|
||||
if account is not None:
|
||||
cmd.account = account
|
||||
if domainid is not None:
|
||||
cmd.domainid = domainid
|
||||
if projectid is not None:
|
||||
cmd.projectid = projectid
|
||||
|
||||
return (apiclient.registerUserData(cmd))
|
||||
|
||||
@classmethod
|
||||
def delete(cls, apiclient, id):
|
||||
"""Delete Userdata"""
|
||||
cmd = deleteUserData.deleteUserDataCmd()
|
||||
cmd.id = id
|
||||
apiclient.deleteUserData(cmd)
|
||||
|
||||
@classmethod
|
||||
def list(cls, apiclient, **kwargs):
|
||||
"""List all UserData"""
|
||||
cmd = listUserData.listUserDataCmd()
|
||||
[setattr(cmd, k, v) for k, v in list(kwargs.items())]
|
||||
if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
|
||||
cmd.listall = True
|
||||
return (apiclient.listUserData(cmd))
|
||||
|
||||
class Capacities:
|
||||
"""Manage Capacities"""
|
||||
|
||||
@ -165,6 +165,7 @@
|
||||
"label.action.unmanage.virtualmachine": "Unmanage VM",
|
||||
"label.action.update.offering.access": "Update offering access",
|
||||
"label.action.update.resource.count": "Update resource count",
|
||||
"label.action.userdata.reset": "Reset userdata",
|
||||
"label.action.vmsnapshot.create": "Take VM snapshot",
|
||||
"label.action.vmsnapshot.delete": "Delete VM snapshot",
|
||||
"label.action.vmsnapshot.revert": "Revert to VM snapshot",
|
||||
@ -1386,6 +1387,7 @@
|
||||
"label.refresh": "Refresh",
|
||||
"label.region": "Region",
|
||||
"label.register.template": "Register template",
|
||||
"label.register.user.data": "Register a userdata",
|
||||
"label.reinstall.vm": "Reinstall VM",
|
||||
"label.reject": "Reject",
|
||||
"label.related": "Related",
|
||||
@ -1408,6 +1410,7 @@
|
||||
"label.remove.project.user": "Remove user from project",
|
||||
"label.remove.rule": "Remove rule",
|
||||
"label.remove.ssh.key.pair": "Remove SSH Key pair",
|
||||
"label.remove.user.data": "Remove userdata",
|
||||
"label.remove.vm.from.lb": "Remove VM from load balancer rule",
|
||||
"label.remove.vmware.datacenter": "Remove VMware Datacenter",
|
||||
"label.remove.vpc": "Remove VPC",
|
||||
@ -1432,6 +1435,7 @@
|
||||
"label.reset.config.value": "Reset to default value",
|
||||
"label.reset.ssh.key.pair": "Reset SSH key pair",
|
||||
"label.reset.to.default": "Reset to default",
|
||||
"label.reset.userdata.on.vm": "Reset Userdata on VM",
|
||||
"label.reset.vpn.connection": "Reset VPN connection",
|
||||
"label.resource": "Resource",
|
||||
"label.resource.limit.exceeded": "Resource limit exceeded",
|
||||
@ -1590,6 +1594,17 @@
|
||||
"label.srx": "SRX",
|
||||
"label.srx.firewall": "Juniper SRX firewall",
|
||||
"label.ssh.key.pairs": "SSH key pairs",
|
||||
"label.userdataid": "Userdata ID",
|
||||
"label.userdataname": "Userdata name",
|
||||
"label.userdatadetails": "Userdata details",
|
||||
"label.userdataparams": "Userdata parameters",
|
||||
"label.userdatapolicy": "Userdata link policy",
|
||||
"label.userdata.text": "Userdata Text",
|
||||
"label.userdata.registered": "Userdata Registered",
|
||||
"label.userdata.do.override": "Userdata override",
|
||||
"label.userdata.do.append": "Userdata append",
|
||||
"label.userdatapolicy.tooltip": "Userdata linked to the template can be overridden by userdata provided during VM deploy. Select the override policy as required.",
|
||||
"label.user.data": "User Data",
|
||||
"label.ssh.port": "SSH port",
|
||||
"label.sshkeypair": "New SSH key pair",
|
||||
"label.sshkeypairs": "SSH key pairs",
|
||||
@ -2172,6 +2187,8 @@
|
||||
"message.desc.primary.storage": "Each cluster must contain one or more primary storage servers. We will add the first one now. Primary storage contains the disk volumes for all the VMs running on hosts in the cluster. Use any standards-compliant protocol that is supported by the underlying hypervisor.",
|
||||
"message.desc.reset.ssh.key.pair": "Please specify a ssh key pair that you would like to add to this VM. Please note the root password will be changed by this operation if password is enabled.",
|
||||
"message.desc.secondary.storage": "Each zone must have at least one NFS or secondary storage server. We will add the first one now. Secondary storage stores VM templates, ISO images, and VM disk volume snapshots. This server must be available to all hosts in the zone.<br/><br/>Provide the IP address and exported path.",
|
||||
"message.desc.register.user.data": "Please fill in the following data to register a user data.",
|
||||
"message.desc.registered.user.data": "Registered a User Data.",
|
||||
"message.desc.zone": "A zone is the largest organizational unit in CloudStack, and it typically corresponds to a single datacenter. Zones provide physical isolation and redundancy. A zone consists of one or more pods (each of which contains hosts and primary storage servers) and a secondary storage server which is shared by all pods in the zone.",
|
||||
"message.detach.disk": "Are you sure you want to detach this disk?",
|
||||
"message.detach.iso.confirm": "Please confirm that you want to detach the ISO from this virtual instance.",
|
||||
@ -2300,6 +2317,7 @@
|
||||
"message.error.upload.template": "Template upload failed.",
|
||||
"message.error.upload.template.description": "Only one template can be uploaded at a time.",
|
||||
"message.error.url": "Please enter URL.",
|
||||
"message.error.userdata": "Please enter userdata",
|
||||
"message.error.username": "Enter your username.",
|
||||
"message.error.valid.iops.range": "Please enter a valid IOPS range.",
|
||||
"message.error.vcenter.datacenter": "Please enter vCenter datacenter.",
|
||||
@ -2407,6 +2425,7 @@
|
||||
"message.ovf.configurations": "OVF configurations available for the selected appliance. Please select the desired value. Incompatible compute offerings will get disabled.",
|
||||
"message.path.description": "NFS: exported path from the server. VMFS: /datacenter name/datastore name. SharedMountPoint: path where primary storage is mounted, such as /mnt/primary.",
|
||||
"message.please.confirm.remove.ssh.key.pair": "Please confirm that you want to remove this SSH key pair.",
|
||||
"message.please.confirm.remove.user.data": "Please confirm that you want to remove this userdata",
|
||||
"message.please.enter.valid.value": "Please enter a valid value.",
|
||||
"message.please.enter.value": "Please enter values.",
|
||||
"message.please.wait.while.zone.is.being.created": "Please wait while your zone is being created; this may take a while...",
|
||||
@ -2541,6 +2560,7 @@
|
||||
"message.success.register.iso": "Successfully registered ISO",
|
||||
"message.success.register.keypair": "Successfully registered SSH key pair",
|
||||
"message.success.register.template": "Successfully registered template",
|
||||
"message.success.register.user.data": "Successfully registered Userdata",
|
||||
"message.success.release.ip": "Successfully released IP",
|
||||
"message.success.remove.egress.rule": "Successfully removed egress rule",
|
||||
"message.success.remove.firewall.rule": "Successfully removed firewall rule",
|
||||
|
||||
@ -1381,6 +1381,7 @@
|
||||
"message.desc.primary.storage": "Each cluster must contain one or more primary storage servers, and we will add the first one now. Primary storage contains the disk volumes for all the VMs running on hosts in the cluster. Use any standards-compliant protocol that is supported by the underlying hypervisor.",
|
||||
"message.desc.reset.ssh.key.pair": "Please specify a ssh key pair that you would like to add to this VM. Please note the root password will be changed by this operation if password is enabled.",
|
||||
"message.desc.secondary.storage": "Each zone must have at least one NFS or secondary storage server, and we will add the first one now. Secondary storage stores VM templates, ISO images, and VM disk volume snapshots. This server must be available to all hosts in the zone.<br/><br/>Provide the IP address and exported path.",
|
||||
"message.desc.reset.userdata": "Please select a userdata that you would like to add to this VM.",
|
||||
"message.desc.zone": "A zone is the largest organizational unit in CloudStack, and it typically corresponds to a single datacenter. Zones provide physical isolation and redundancy. A zone consists of one or more pods (each of which contains hosts and primary storage servers) and a secondary storage server which is shared by all pods in the zone.",
|
||||
"message.detach.disk": "Are you sure you want to detach this disk?",
|
||||
"message.detach.iso.confirm": "Please confirm that you want to detach the ISO from this virtual instance.",
|
||||
|
||||
@ -173,6 +173,7 @@ export default {
|
||||
case 'VMSnapshot': return 'VM_SNAPSHOT'
|
||||
case 'VMInstanceGroup': return 'INSTANCE_GROUP'
|
||||
case 'SSHKeyPair': return 'SSH_KEYPAIR'
|
||||
case 'UserData': return 'USER_DATA'
|
||||
case 'KubernetesCluster': return 'KUBERNETES_CLUSTER'
|
||||
case 'Network': return 'NETWORK'
|
||||
case 'Vpc': return 'VPC'
|
||||
|
||||
@ -51,6 +51,9 @@
|
||||
<div v-else-if="['created', 'sent', 'lastannotated', 'collectiontime', 'lastboottime', 'lastserverstart', 'lastserverstop'].includes(item)">
|
||||
{{ $toLocaleDate(dataResource[item]) }}
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'userdata' && item === 'userdata'">
|
||||
<div style="white-space: pre-wrap;"> {{ decodeUserData(dataResource.userdata)}} </div>
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'guestnetwork' && item === 'egressdefaultpolicy'">
|
||||
{{ dataResource[item]? $t('message.egress.rules.allow') : $t('message.egress.rules.deny') }}
|
||||
</div>
|
||||
@ -166,6 +169,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
decodeUserData (userdata) {
|
||||
const decodedData = Buffer.from(userdata, 'base64')
|
||||
return decodedData.toString('utf-8')
|
||||
},
|
||||
fetchProjectAdmins () {
|
||||
if (!this.dataResource.owner) {
|
||||
return false
|
||||
|
||||
@ -533,6 +533,14 @@
|
||||
<span v-else>{{ resource.zone || resource.zonename || resource.zoneid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.userdataname">
|
||||
<div class="resource-detail-item__label">{{ $t('label.userdata') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<solution-outlined />
|
||||
<router-link v-if="!isStatic && $router.resolve('/userdata/' + resource.userdataid).matched[0].redirect !== '/exception/404'" :to="{ path: '/userdata/' + resource.userdataid }">{{ resource.userdataname || resource.userdataid }}</router-link>
|
||||
<span v-else>{{ resource.userdataname || resource.userdataid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.owner">
|
||||
<div class="resource-detail-item__label">{{ $t('label.owners') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
|
||||
@ -511,7 +511,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
quickViewEnabled () {
|
||||
return new RegExp(['/vm', '/kubernetes', '/ssh', '/vmgroup', '/affinitygroup',
|
||||
return new RegExp(['/vm', '/kubernetes', '/ssh', '/userdata', '/vmgroup', '/affinitygroup',
|
||||
'/volume', '/snapshot', '/vmsnapshot', '/backup',
|
||||
'/guestnetwork', '/vpc', '/vpncustomergateway',
|
||||
'/template', '/iso',
|
||||
@ -521,7 +521,7 @@ export default {
|
||||
.test(this.$route.path)
|
||||
},
|
||||
enableGroupAction () {
|
||||
return ['vm', 'alert', 'vmgroup', 'ssh', 'affinitygroup', 'volume', 'snapshot',
|
||||
return ['vm', 'alert', 'vmgroup', 'ssh', 'userdata', 'affinitygroup', 'volume', 'snapshot',
|
||||
'vmsnapshot', 'guestnetwork', 'vpc', 'publicip', 'vpnuser', 'vpncustomergateway',
|
||||
'project', 'account', 'systemvm', 'router', 'computeoffering', 'systemoffering',
|
||||
'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment'
|
||||
|
||||
@ -77,7 +77,9 @@ export default {
|
||||
},
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'groupid', 'tags'],
|
||||
details: () => {
|
||||
var fields = ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename', 'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account', 'domain', 'zonename']
|
||||
var fields = ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename',
|
||||
'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account',
|
||||
'domain', 'zonename', 'userdataid', 'userdataname', 'userdataparams', 'userdatadetails', 'userdatapolicy']
|
||||
const listZoneHaveSGEnabled = store.getters.zones.filter(zone => zone.securitygroupsenabled === true)
|
||||
if (!listZoneHaveSGEnabled || listZoneHaveSGEnabled.length === 0) {
|
||||
return fields
|
||||
@ -365,6 +367,17 @@ export default {
|
||||
popup: true,
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ResetSshKeyPair')))
|
||||
},
|
||||
{
|
||||
api: 'resetUserDataForVirtualMachine',
|
||||
icon: 'solution-outlined',
|
||||
label: 'label.reset.userdata.on.vm',
|
||||
message: 'message.desc.reset.userdata',
|
||||
docHelp: 'adminguide/virtual_machines.html#resetting-userdata',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||
popup: true,
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ResetUserData')))
|
||||
},
|
||||
{
|
||||
api: 'assignVirtualMachine',
|
||||
icon: 'user-add-outlined',
|
||||
@ -633,6 +646,77 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'userdata',
|
||||
title: 'label.user.data',
|
||||
icon: 'solution-outlined',
|
||||
docHelp: 'adminguide/virtual_machines.html#user-data-and-meta-data',
|
||||
permission: ['listUserData'],
|
||||
columns: () => {
|
||||
var fields = ['name', 'id']
|
||||
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
||||
fields.push('account')
|
||||
}
|
||||
return fields
|
||||
},
|
||||
resourceType: 'UserData',
|
||||
details: ['id', 'name', 'userdata', 'account', 'domain', 'params'],
|
||||
related: [{
|
||||
name: 'vm',
|
||||
title: 'label.instances',
|
||||
param: 'userdata'
|
||||
}],
|
||||
tabs: [
|
||||
{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'comments',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
api: 'registerUserData',
|
||||
icon: 'plus-outlined',
|
||||
label: 'label.register.user.data',
|
||||
docHelp: 'adminguide/virtual_machines.html#creating-the-ssh-keypair',
|
||||
listView: true,
|
||||
popup: true,
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/RegisterUserData.vue')))
|
||||
},
|
||||
{
|
||||
api: 'deleteUserData',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.remove.user.data',
|
||||
message: 'message.please.confirm.remove.user.data',
|
||||
dataView: true,
|
||||
args: ['id', 'account', 'domainid'],
|
||||
mapping: {
|
||||
id: {
|
||||
value: (record, params) => { return record.id }
|
||||
},
|
||||
account: {
|
||||
value: (record, params) => { return record.account }
|
||||
},
|
||||
domainid: {
|
||||
value: (record, params) => { return record.domainid }
|
||||
}
|
||||
},
|
||||
groupAction: true,
|
||||
popup: true,
|
||||
groupMap: (selection, values, record) => {
|
||||
return selection.map(x => {
|
||||
const data = record.filter(y => { return y.id === x })
|
||||
return {
|
||||
id: x, account: data[0].account, domainid: data[0].domainid
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'affinitygroup',
|
||||
title: 'label.affinity.groups',
|
||||
|
||||
@ -47,7 +47,7 @@ export default {
|
||||
details: () => {
|
||||
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'isready', 'passwordenabled',
|
||||
'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
||||
'account', 'domain', 'created']
|
||||
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy']
|
||||
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
||||
fields.push('templatetype', 'url')
|
||||
}
|
||||
@ -101,7 +101,7 @@ export default {
|
||||
{
|
||||
api: 'updateTemplate',
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
label: 'label.action.edit.template',
|
||||
dataView: true,
|
||||
show: (record, store) => {
|
||||
return (['Admin'].includes(store.userInfo.roletype) || // If admin or owner or belongs to current project
|
||||
@ -195,7 +195,7 @@ export default {
|
||||
}
|
||||
return fields
|
||||
},
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'bootable', 'isready', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'crosszones', 'account', 'domain', 'created'],
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'bootable', 'isready', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy'],
|
||||
searchFilters: ['name', 'zoneid', 'tags'],
|
||||
related: [{
|
||||
name: 'vm',
|
||||
@ -250,7 +250,8 @@ export default {
|
||||
!(record.account === 'system' && record.domainid === 1) &&
|
||||
record.isready
|
||||
},
|
||||
args: ['name', 'displaytext', 'bootable', 'ostypeid']
|
||||
popup: true,
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/views/image/UpdateISO.vue')))
|
||||
},
|
||||
{
|
||||
api: 'updateIsoPermissions',
|
||||
|
||||
@ -156,7 +156,8 @@ import {
|
||||
UsergroupDeleteOutlined,
|
||||
UserOutlined,
|
||||
UploadOutlined,
|
||||
WifiOutlined
|
||||
WifiOutlined,
|
||||
SolutionOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import renderIcon from '@/utils/renderIcon'
|
||||
|
||||
@ -304,5 +305,6 @@ export default {
|
||||
app.component('UploadOutlined', UploadOutlined)
|
||||
app.component('WifiOutlined', WifiOutlined)
|
||||
app.component('renderIcon', renderIcon)
|
||||
app.component('SolutionOutlined', SolutionOutlined)
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,7 +551,7 @@
|
||||
ref="bootintosetup">
|
||||
<a-switch v-model:checked="form.bootintosetup" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.dynamicscalingenabled')" name="dynamicscalingenabled" ref="dynamicscalingenabled">
|
||||
<a-form-item name="dynamicscalingenabled" ref="dynamicscalingenabled">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.dynamicscalingenabled')" :tooltip="$t('label.dynamicscalingenabled.tooltip')"/>
|
||||
</template>
|
||||
@ -563,10 +563,120 @@
|
||||
@change="val => { dynamicscalingenabled = val }"/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.userdata')" name="userdata" ref="userdata">
|
||||
<a-textarea
|
||||
v-model:value="form.userdata">
|
||||
</a-textarea>
|
||||
<a-form-item :label="$t('label.userdata')">
|
||||
<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>
|
||||
<div v-if="this.iso && this.iso.userdataid">
|
||||
<a-text type="primary">
|
||||
Userdata "{{ $t(this.iso.userdataname) }}" is linked with ISO "{{ $t(this.iso.name) }}" with override policy "{{ $t(this.iso.userdatapolicy) }}"
|
||||
</a-text><br/><br/>
|
||||
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
|
||||
<a-text type="primary" v-if="this.iso && this.iso.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
|
||||
placeholder="Userdata"
|
||||
v-model:value="form.userdata">
|
||||
</a-textarea>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.affinity.groups')">
|
||||
<affinity-group-selection
|
||||
@ -697,6 +807,7 @@ import AffinityGroupSelection from '@views/compute/wizard/AffinityGroupSelection
|
||||
import NetworkSelection from '@views/compute/wizard/NetworkSelection'
|
||||
import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration'
|
||||
import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection'
|
||||
import UserDataSelection from '@views/compute/wizard/UserDataSelection'
|
||||
import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView.vue'
|
||||
@ -706,6 +817,7 @@ export default {
|
||||
name: 'Wizard',
|
||||
components: {
|
||||
SshKeyPairSelection,
|
||||
UserDataSelection,
|
||||
NetworkConfiguration,
|
||||
NetworkSelection,
|
||||
AffinityGroupSelection,
|
||||
@ -739,6 +851,10 @@ export default {
|
||||
zoneSelected: false,
|
||||
dynamicscalingenabled: true,
|
||||
templateKey: 0,
|
||||
showRegisteredUserdata: true,
|
||||
doUserdataOverride: false,
|
||||
doUserdataAppend: false,
|
||||
userdataDefaultOverridePolicy: 'ALLOWOVERRIDE',
|
||||
vm: {
|
||||
name: null,
|
||||
zoneid: null,
|
||||
@ -768,6 +884,7 @@ export default {
|
||||
affinityGroups: [],
|
||||
networks: [],
|
||||
sshKeyPairs: [],
|
||||
UserDatas: [],
|
||||
pods: [],
|
||||
clusters: [],
|
||||
hosts: [],
|
||||
@ -788,6 +905,7 @@ export default {
|
||||
affinityGroups: false,
|
||||
networks: false,
|
||||
sshKeyPairs: false,
|
||||
userDatas: false,
|
||||
zones: false,
|
||||
pods: false,
|
||||
clusters: false,
|
||||
@ -813,6 +931,32 @@ export default {
|
||||
zone: {},
|
||||
sshKeyPairs: [],
|
||||
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: {},
|
||||
templateFilter: [
|
||||
'featured',
|
||||
@ -831,6 +975,7 @@ export default {
|
||||
networkConfig: [],
|
||||
dataNetworkCreated: [],
|
||||
tabKey: 'templateid',
|
||||
userdataTabKey: 'userdataregistered',
|
||||
dataPreFill: {},
|
||||
showDetails: false,
|
||||
showRootDiskSizeChanger: false,
|
||||
@ -926,6 +1071,15 @@ export default {
|
||||
listall: false
|
||||
}
|
||||
},
|
||||
userDatas: {
|
||||
list: 'listUserData',
|
||||
options: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
keyword: undefined,
|
||||
listall: false
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
list: 'listNetworks',
|
||||
options: {
|
||||
@ -1082,12 +1236,28 @@ export default {
|
||||
|
||||
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 () {
|
||||
return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic')
|
||||
},
|
||||
isUserAllowedToListSshKeys () {
|
||||
return Boolean('listSSHKeyPairs' in this.$store.getters.apis)
|
||||
},
|
||||
isUserAllowedToListUserDatas () {
|
||||
return Boolean('listUserData' in this.$store.getters.apis)
|
||||
},
|
||||
dynamicScalingVmConfigValue () {
|
||||
return this.options.dynamicScalingVmConfig?.[0]?.value === 'true'
|
||||
},
|
||||
@ -1273,6 +1443,8 @@ export default {
|
||||
template (oldValue, newValue) {
|
||||
if (oldValue && newValue && oldValue.id !== newValue.id) {
|
||||
this.dynamicscalingenabled = this.isDynamicallyScalable()
|
||||
this.doUserdataOverride = false
|
||||
this.doUserdataAppend = false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@ -1586,6 +1758,8 @@ export default {
|
||||
this.defaultBootType = this.template?.details?.UEFI ? 'UEFI' : ''
|
||||
this.fetchBootModes(this.defaultBootType)
|
||||
this.defaultBootMode = this.template?.details?.UEFI
|
||||
this.updateTemplateLinkedUserData(this.template.userdataid)
|
||||
this.userdataDefaultOverridePolicy = this.template.userdatapolicy
|
||||
}
|
||||
} else if (name === 'isoid') {
|
||||
this.templateConfigurations = []
|
||||
@ -1597,6 +1771,8 @@ export default {
|
||||
this.resetFromTemplateConfiguration()
|
||||
this.form.isoid = value
|
||||
this.form.templateid = null
|
||||
this.updateTemplateLinkedUserData(this.iso.userdataid)
|
||||
this.userdataDefaultOverridePolicy = this.iso.userdatapolicy
|
||||
} else if (['cpuspeed', 'cpunumber', 'memory'].includes(name)) {
|
||||
this.vm[name] = value
|
||||
this.form[name] = value
|
||||
@ -1644,6 +1820,56 @@ export default {
|
||||
this.form.keypairs = names
|
||||
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
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
escapePropertyKey (key) {
|
||||
return key.split('.').join('\\002E')
|
||||
},
|
||||
@ -1830,6 +2056,7 @@ export default {
|
||||
}
|
||||
// step 7: select ssh key pair
|
||||
deployVmData.keypairs = this.sshKeyPairs.join(',')
|
||||
deployVmData.userdataid = values.userdataid
|
||||
|
||||
if (values.name) {
|
||||
deployVmData.name = values.name
|
||||
@ -1858,6 +2085,20 @@ export default {
|
||||
deployVmData = Object.fromEntries(
|
||||
Object.entries(deployVmData).filter(([key, value]) => value !== undefined))
|
||||
|
||||
var idx = 0
|
||||
if (this.templateUserDataValues) {
|
||||
for (const [key, value] of Object.entries(this.templateUserDataValues)) {
|
||||
deployVmData['userdatadetails[' + idx + '].' + `${key}`] = value
|
||||
idx++
|
||||
}
|
||||
}
|
||||
if (this.userDataValues) {
|
||||
for (const [key, value] of Object.entries(this.userDataValues)) {
|
||||
deployVmData['userdatadetails[' + idx + '].' + `${key}`] = value
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
api('deployVirtualMachine', {}, 'POST', deployVmData).then(response => {
|
||||
const jobId = response.deployvirtualmachineresponse.jobid
|
||||
if (jobId) {
|
||||
@ -2149,6 +2390,10 @@ export default {
|
||||
this.fetchAllIsos()
|
||||
}
|
||||
},
|
||||
onUserdataTabChange (key, type) {
|
||||
this[type] = key
|
||||
this.userDataParams = []
|
||||
},
|
||||
fetchTemplateNics (template) {
|
||||
var nics = []
|
||||
this.nicToNetworkSelection = []
|
||||
|
||||
255
ui/src/views/compute/RegisterUserData.vue
Normal file
255
ui/src/views/compute/RegisterUserData.vue
Normal file
@ -0,0 +1,255 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div class="form-layout">
|
||||
<a-spin :spinning="loading" v-if="!isSubmitted">
|
||||
<p v-html="$t('message.desc.register.user.data')"></p>
|
||||
<a-form
|
||||
v-ctrl-enter="handleSubmit"
|
||||
:ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
@finish="handleSubmit"
|
||||
layout="vertical">
|
||||
<a-form-item name="name" ref="name">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"
|
||||
v-focus="true" />
|
||||
</a-form-item>
|
||||
<a-form-item name="userdata" ref="userdata">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdata')" :tooltip="apiParams.userdata.description"/>
|
||||
</template>
|
||||
<a-textarea
|
||||
v-model:value="form.userdata"
|
||||
:placeholder="apiParams.userdata.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item name="params" ref="params">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdataparams')" :tooltip="apiParams.params.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
mode="tags"
|
||||
v-model:value="form.params"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:placeholder="apiParams.params.description">
|
||||
<a-select-option v-for="opt in params" :key="opt">
|
||||
{{ opt }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="domainid" ref="domainid" v-if="isAdminOrDomainAdmin()">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.domainid')" :tooltip="apiParams.domainid.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
id="domain-selection"
|
||||
v-model:value="form.domainid"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
:loading="domainLoading"
|
||||
:placeholder="apiParams.domainid.description"
|
||||
@change="val => { handleDomainChanged(domains[val]) }">
|
||||
<a-select-option v-for="(opt, optIndex) in domains" :key="optIndex">
|
||||
{{ opt.path || opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="account" ref="account" v-if="isAdminOrDomainAdmin() && !isObjectEmpty(selectedDomain) && selectedDomain.id !== null">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.account"
|
||||
:placeholder="apiParams.account.description"/>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
<div v-if="isSubmitted">
|
||||
<p v-html="$t('message.desc.registered.user.data')"></p>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="notifyCopied" v-clipboard:copy="hiddenElement.innerHTML" type="primary">{{ $t('label.copy.clipboard') }}</a-button>
|
||||
<a-button @click="downloadKey" type="primary">{{ $t('label.download') }}</a-button>
|
||||
<a-button @click="closeAction">{{ $t('label.close') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'registerUserData',
|
||||
props: {},
|
||||
components: {
|
||||
TooltipLabel
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
domains: [],
|
||||
domainLoading: false,
|
||||
selectedDomain: {},
|
||||
loading: false,
|
||||
isSubmitted: false,
|
||||
hiddenElement: null
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('registerUserData')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.domains = [
|
||||
{
|
||||
id: null,
|
||||
name: ''
|
||||
}
|
||||
]
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
name: [{ required: true, message: this.$t('message.error.name') }],
|
||||
userdata: [{ required: true, message: this.$t('message.error.userdata') }]
|
||||
})
|
||||
},
|
||||
fetchData () {
|
||||
if (this.isAdminOrDomainAdmin()) {
|
||||
this.fetchDomainData()
|
||||
}
|
||||
},
|
||||
isAdminOrDomainAdmin () {
|
||||
return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype)
|
||||
},
|
||||
isValidValueForKey (obj, key) {
|
||||
return key in obj && obj[key] != null
|
||||
},
|
||||
arrayHasItems (array) {
|
||||
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
|
||||
},
|
||||
isObjectEmpty (obj) {
|
||||
return !(obj !== null && obj !== undefined && Object.keys(obj).length > 0 && obj.constructor === Object)
|
||||
},
|
||||
fetchDomainData () {
|
||||
const params = {}
|
||||
this.domainLoading = true
|
||||
api('listDomains', params).then(json => {
|
||||
const listdomains = json.listdomainsresponse.domain
|
||||
this.domains = this.domains.concat(listdomains)
|
||||
}).finally(() => {
|
||||
this.domainLoading = false
|
||||
if (this.arrayHasItems(this.domains)) {
|
||||
this.form.domainid = 0
|
||||
this.handleDomainChanged(this.domains[0])
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDomainChanged (domain) {
|
||||
this.selectedDomain = domain
|
||||
},
|
||||
sanitizeReverse (value) {
|
||||
const reversedValue = value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
|
||||
return reversedValue
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.loading) return
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
this.loading = true
|
||||
const params = {
|
||||
name: values.name
|
||||
}
|
||||
if (this.isValidValueForKey(values, 'domainid') &&
|
||||
this.arrayHasItems(this.domains) &&
|
||||
this.domains[values.domainid].id !== null) {
|
||||
params.domainid = this.domains[values.domainid].id
|
||||
}
|
||||
if (this.isValidValueForKey(values, 'account') && values.account.length > 0) {
|
||||
params.account = values.account
|
||||
}
|
||||
params.userdata = encodeURIComponent(btoa(this.sanitizeReverse(values.userdata)))
|
||||
|
||||
if (values.params != null && values.params.length > 0) {
|
||||
var userdataparams = values.params.join(',')
|
||||
params.params = userdataparams
|
||||
}
|
||||
|
||||
api('registerUserData', params).then(json => {
|
||||
this.$message.success(this.$t('message.success.register.user.data') + ' ' + values.name)
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.$emit('refresh-data')
|
||||
this.loading = false
|
||||
this.closeAction()
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
})
|
||||
},
|
||||
downloadKey () {
|
||||
this.hiddenElement.click()
|
||||
},
|
||||
notifyCopied () {
|
||||
this.$notification.info({
|
||||
message: this.$t('message.success.copy.clipboard')
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-layout {
|
||||
width: 80vw;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
394
ui/src/views/compute/ResetUserData.vue
Normal file
394
ui/src/views/compute/ResetUserData.vue
Normal file
@ -0,0 +1,394 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<a-spin :spinning="loadingData">
|
||||
<a-form
|
||||
:ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
layout="vertical"
|
||||
class="form"
|
||||
v-ctrl-enter="handleSubmit"
|
||||
@finish="handleSubmit">
|
||||
<div v-if="template && template.userdataid">
|
||||
<a-text type="primary">
|
||||
The template "{{ $t(this.template.name) }}" is linked to Userdata "{{ $t(this.template.userdataname) }}" 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><br/><br/>
|
||||
</div>
|
||||
<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>
|
||||
<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">
|
||||
<template #description>
|
||||
<div>
|
||||
<user-data-selection
|
||||
:items="items"
|
||||
:row-count="rowCount.userDatas"
|
||||
: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
|
||||
placeholder="Userdata"
|
||||
v-model:value="form.userdata">
|
||||
</a-textarea>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</div>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button :loading="loadingData" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import { genericCompare } from '@/utils/sort.js'
|
||||
import UserDataSelection from '@views/compute/wizard/UserDataSelection'
|
||||
|
||||
export default {
|
||||
name: 'ResetUserData',
|
||||
components: {
|
||||
UserDataSelection
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
preFillContent: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
items: [],
|
||||
total: 0,
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.name'),
|
||||
sorter: function (a, b) { return genericCompare(a[this.dataIndex] || '', b[this.dataIndex] || '') },
|
||||
width: '40%'
|
||||
},
|
||||
{
|
||||
dataIndex: 'account',
|
||||
slots: { title: 'account' },
|
||||
width: '30%'
|
||||
},
|
||||
{
|
||||
dataIndex: 'domain',
|
||||
slots: { title: 'domain' },
|
||||
width: '30%'
|
||||
}
|
||||
],
|
||||
selectedRowKeys: [],
|
||||
options: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
listall: false,
|
||||
response: 'json'
|
||||
},
|
||||
filter: '',
|
||||
rowCount: {},
|
||||
loading: {
|
||||
userDatas: false
|
||||
},
|
||||
loadingData: false,
|
||||
doUserdataOverride: false,
|
||||
doUserdataAppend: false,
|
||||
userdataTabList: [],
|
||||
userdataDefaultOverridePolicy: 'ALLOWOVERRIDE',
|
||||
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: {},
|
||||
template: {},
|
||||
userdataTabKey: 'userdataregistered',
|
||||
dataPreFill: {},
|
||||
userdata: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.fetchData()
|
||||
this.loadUserdataTabList()
|
||||
this.fetchTemplateData()
|
||||
this.dataPreFill = this.preFillContent && Object.keys(this.preFillContent).length > 0 ? this.preFillContent : {}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
},
|
||||
fetchData () {
|
||||
this.loadingData = true
|
||||
this.items = []
|
||||
this.total = 0
|
||||
api('listUserData', this.options).then(response => {
|
||||
this.total = response.listuserdataresponse.count
|
||||
if (this.total !== 0) {
|
||||
this.items = response.listuserdataresponse.userdata
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loadingData = false
|
||||
})
|
||||
},
|
||||
fetchTemplateData () {
|
||||
const params = {}
|
||||
params.id = this.resource.templateid
|
||||
params.isrecursive = true
|
||||
params.templatefilter = 'all'
|
||||
var apiName = 'listTemplates'
|
||||
api(apiName, params).then(json => {
|
||||
const templateResponses = json.listtemplatesresponse.template
|
||||
this.template = templateResponses[0]
|
||||
this.updateTemplateLinkedUserData(this.template.userdataid)
|
||||
this.userdataDefaultOverridePolicy = this.template.userdatapolicy
|
||||
})
|
||||
},
|
||||
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
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
loadUserdataTabList () {
|
||||
this.userdataTabList = [{
|
||||
key: 'userdataregistered',
|
||||
tab: this.$t('label.userdata.registered')
|
||||
},
|
||||
{
|
||||
key: 'userdatatext',
|
||||
tab: this.$t('label.userdata.text')
|
||||
}]
|
||||
},
|
||||
onUserdataTabChange (key, type) {
|
||||
this[type] = key
|
||||
this.userDataParams = []
|
||||
},
|
||||
sanitizeReverse (value) {
|
||||
const reversedValue = value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
|
||||
return reversedValue
|
||||
},
|
||||
isUserAllowedToListUserDatas () {
|
||||
return Boolean('listUserData' in this.$store.getters.apis)
|
||||
},
|
||||
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
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
handleSearch (keyword) {
|
||||
this.filter = keyword
|
||||
this.options.keyword = keyword
|
||||
this.fetchData()
|
||||
},
|
||||
handleTableChange (pagination) {
|
||||
this.options.page = pagination.current
|
||||
this.options.pageSize = pagination.pageSize
|
||||
this.fetchData()
|
||||
},
|
||||
handleSubmit () {
|
||||
if (this.loadingData) return
|
||||
const values = toRaw(this.form)
|
||||
this.loadingData = true
|
||||
console.log(values)
|
||||
const params = {
|
||||
id: this.resource.id
|
||||
}
|
||||
if (values.userdata && values.userdata.length > 0) {
|
||||
params.userdata = encodeURIComponent(btoa(this.sanitizeReverse(values.userdata)))
|
||||
}
|
||||
if (values.userdataid) {
|
||||
params.userdataid = values.userdataid
|
||||
}
|
||||
var idx = 0
|
||||
if (this.templateUserDataValues) {
|
||||
for (const [key, value] of Object.entries(this.templateUserDataValues)) {
|
||||
params['userdatadetails[' + idx + '].' + `${key}`] = value
|
||||
idx++
|
||||
}
|
||||
}
|
||||
if (this.userDataValues) {
|
||||
for (const [key, value] of Object.entries(this.userDataValues)) {
|
||||
params['userdatadetails[' + idx + '].' + `${key}`] = value
|
||||
idx++
|
||||
}
|
||||
}
|
||||
api('resetUserDataForVirtualMachine', params).then(json => {
|
||||
this.$message.success({
|
||||
content: `${this.$t('label.action.userdata.reset')} - ${this.$t('label.success')}`,
|
||||
duration: 2
|
||||
})
|
||||
this.$emit('refresh-data')
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loadingData = false
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form {
|
||||
width: 90vw;
|
||||
@media (min-width: 800px) {
|
||||
width: 45vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
202
ui/src/views/compute/wizard/UserDataSelection.vue
Normal file
202
ui/src/views/compute/wizard/UserDataSelection.vue
Normal file
@ -0,0 +1,202 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-input-search
|
||||
style="width: 25vw;float: right;margin-bottom: 10px; z-index: 8"
|
||||
:placeholder="$t('label.search')"
|
||||
v-model:value="filter"
|
||||
@search="handleSearch" />
|
||||
<a-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="tableSource"
|
||||
:rowSelection="rowSelection"
|
||||
:customRow="onClickRow"
|
||||
:pagination="true"
|
||||
size="middle"
|
||||
:scroll="{ y: 225 }"
|
||||
>
|
||||
<template #account><user-outlined /> {{ $t('label.account') }}</template>
|
||||
<template #domain><block-outlined /> {{ $t('label.domain') }}</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UserDataSelection',
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
rowCount: {
|
||||
type: Number,
|
||||
default: () => 0
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
preFillContent: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
zoneId: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
filter: '',
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: this.$t('label.userdata'),
|
||||
width: '40%'
|
||||
},
|
||||
{
|
||||
dataIndex: 'account',
|
||||
slots: { title: 'account' },
|
||||
width: '30%'
|
||||
},
|
||||
{
|
||||
dataIndex: 'domain',
|
||||
slots: { title: 'domain' },
|
||||
width: '30%'
|
||||
}
|
||||
],
|
||||
selectedRowKeys: [this.$t('label.noselect')],
|
||||
dataItems: [],
|
||||
oldZoneId: null,
|
||||
options: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
keyword: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableSource () {
|
||||
const dataItems = []
|
||||
|
||||
if (this.options.page === 1) {
|
||||
dataItems.push({
|
||||
key: this.$t('label.noselect'),
|
||||
name: this.$t('label.noselect'),
|
||||
account: '-',
|
||||
domain: '-'
|
||||
})
|
||||
}
|
||||
|
||||
this.items.map((item) => {
|
||||
dataItems.push({
|
||||
key: item.id,
|
||||
name: item.name,
|
||||
account: item.account,
|
||||
domain: item.domain
|
||||
})
|
||||
})
|
||||
|
||||
return dataItems
|
||||
},
|
||||
rowSelection () {
|
||||
return {
|
||||
type: 'radio',
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectRow
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (newValue, oldValue) {
|
||||
if (newValue && newValue !== oldValue) {
|
||||
this.selectedRowKeys = [newValue]
|
||||
}
|
||||
},
|
||||
loading () {
|
||||
if (!this.loading) {
|
||||
if (this.preFillContent.userdataid) {
|
||||
this.selectedRowKeys = [this.preFillContent.userdataid]
|
||||
this.$emit('select-user-data-item', this.preFillContent.userdataid)
|
||||
} else {
|
||||
if (this.oldZoneId === this.zoneId) {
|
||||
return
|
||||
}
|
||||
this.oldZoneId = this.zoneId
|
||||
this.selectedRowKeys = [this.$t('label.noselect')]
|
||||
this.$emit('select-user-data-item', this.$t('label.noselect'))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSelectRow (value) {
|
||||
this.selectedRowKeys = value
|
||||
this.$emit('select-user-data-item', value[0])
|
||||
},
|
||||
handleSearch (value) {
|
||||
this.filter = value
|
||||
this.options.page = 1
|
||||
this.options.pageSize = 10
|
||||
this.options.keyword = this.filter
|
||||
this.$emit('handle-search-filter', this.options)
|
||||
},
|
||||
onChangePage (page, pageSize) {
|
||||
this.options.page = page
|
||||
this.options.pageSize = pageSize
|
||||
this.$emit('handle-search-filter', this.options)
|
||||
},
|
||||
onChangePageSize (page, pageSize) {
|
||||
this.options.page = page
|
||||
this.options.pageSize = pageSize
|
||||
this.$emit('handle-search-filter', this.options)
|
||||
},
|
||||
onClickRow (record) {
|
||||
return {
|
||||
on: {
|
||||
click: () => {
|
||||
this.selectedRowKeys = [record.key]
|
||||
this.$emit('select-user-data-item', record.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-table-wrapper {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
:deep(.ant-table-tbody) > tr > td {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@ -121,6 +121,47 @@
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item
|
||||
name="userdataid"
|
||||
ref="userdataid"
|
||||
:label="$t('label.userdata')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="userdataid"
|
||||
:placeholder="linkUserDataParams.userdataid.description"
|
||||
:loading="userdata.loading">
|
||||
<a-select-option v-for="opt in userdata.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item ref="userdatapolicy" name="userdatapolicy">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="userdatapolicy"
|
||||
:placeholder="linkUserDataParams.userdatapolicy.description"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
|
||||
{{ opt.id || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item ref="isextractable" name="isextractable" :label="$t('label.isextractable')">
|
||||
<a-switch v-model:checked="form.isextractable" />
|
||||
</a-form-item>
|
||||
@ -153,6 +194,7 @@ import store from '@/store'
|
||||
import { axios } from '../../utils/request'
|
||||
import { mixinForm } from '@/utils/mixin'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'RegisterIso',
|
||||
@ -168,7 +210,8 @@ export default {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ResourceIcon
|
||||
ResourceIcon,
|
||||
TooltipLabel
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@ -177,6 +220,10 @@ export default {
|
||||
osTypes: [],
|
||||
zoneLoading: false,
|
||||
osTypeLoading: false,
|
||||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {},
|
||||
loading: false,
|
||||
allowed: false,
|
||||
uploadParams: null,
|
||||
@ -186,6 +233,7 @@ export default {
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('registerIso')
|
||||
this.linkUserDataParams = this.$getApiParams('linkUserDataToTemplate')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
@ -220,6 +268,8 @@ export default {
|
||||
fetchData () {
|
||||
this.fetchZoneData()
|
||||
this.fetchOsType()
|
||||
this.fetchUserData()
|
||||
this.fetchUserdataPolicy()
|
||||
},
|
||||
fetchZoneData () {
|
||||
const params = {}
|
||||
@ -250,6 +300,36 @@ export default {
|
||||
this.form.ostypeid = this.osTypes[0].id
|
||||
})
|
||||
},
|
||||
fetchUserData () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
|
||||
this.userdata.opts = []
|
||||
this.userdata.loading = true
|
||||
|
||||
api('listUserData', params).then(json => {
|
||||
const listUserdata = json.listuserdataresponse.userdata
|
||||
this.userdata.opts = listUserdata
|
||||
}).finally(() => {
|
||||
this.userdata.loading = false
|
||||
})
|
||||
},
|
||||
fetchUserdataPolicy () {
|
||||
const userdataPolicy = []
|
||||
userdataPolicy.push({
|
||||
id: 'allowoverride',
|
||||
description: 'allowoverride'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'append',
|
||||
description: 'append'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'denyoverride',
|
||||
description: 'denyoverride'
|
||||
})
|
||||
this.userdatapolicylist.opts = userdataPolicy
|
||||
},
|
||||
handleRemove (file) {
|
||||
const index = this.fileList.indexOf(file)
|
||||
const newFileList = this.fileList.slice()
|
||||
@ -336,6 +416,9 @@ export default {
|
||||
if (this.currentForm === 'Create') {
|
||||
this.loading = true
|
||||
api('registerIso', params).then(json => {
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.registerisoresponse.iso[0].id, this.userdatapolicy)
|
||||
}
|
||||
this.$notification.success({
|
||||
message: this.$t('label.action.register.iso'),
|
||||
description: `${this.$t('message.success.register.iso')} ${params.name}`
|
||||
@ -356,6 +439,9 @@ export default {
|
||||
api('getUploadParamsForIso', params).then(json => {
|
||||
this.uploadParams = (json.postuploadisoresponse && json.postuploadisoresponse.getuploadparams) ? json.postuploadisoresponse.getuploadparams : ''
|
||||
const response = this.handleUpload()
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.postuploadisoresponse.iso[0].id)
|
||||
}
|
||||
if (response === 'upload successful') {
|
||||
this.$notification.success({
|
||||
message: this.$t('message.success.upload'),
|
||||
@ -375,6 +461,22 @@ export default {
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
},
|
||||
linkUserdataToTemplate (userdataid, templateid, userdatapolicy) {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
params.userdataid = userdataid
|
||||
params.templateid = templateid
|
||||
if (userdatapolicy) {
|
||||
params.userdatapolicy = userdatapolicy
|
||||
}
|
||||
api('linkUserDataToTemplate', params).then(json => {
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,6 +253,46 @@
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item
|
||||
name="userdataid"
|
||||
ref="userdataid"
|
||||
:label="$t('label.userdata')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="userdataid"
|
||||
:placeholder="linkUserDataParams.userdataid.description"
|
||||
:loading="userdata.loading">
|
||||
<a-select-option v-for="opt in userdata.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item ref="userdatapolicy" name="userdatapolicy">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="userdatapolicy"
|
||||
:placeholder="linkUserDataParams.userdatapolicy.description"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
|
||||
{{ opt.id || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item ref="groupenabled" name="groupenabled">
|
||||
@ -318,6 +358,7 @@ import store from '@/store'
|
||||
import { axios } from '../../utils/request'
|
||||
import { mixinForm } from '@/utils/mixin'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'RegisterOrUploadTemplate',
|
||||
@ -333,7 +374,8 @@ export default {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ResourceIcon
|
||||
ResourceIcon,
|
||||
TooltipLabel
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@ -349,6 +391,10 @@ export default {
|
||||
format: {},
|
||||
osTypes: {},
|
||||
defaultOsType: '',
|
||||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {},
|
||||
defaultOsId: null,
|
||||
hyperKVMShow: false,
|
||||
hyperXenServerShow: false,
|
||||
@ -366,6 +412,7 @@ export default {
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('registerTemplate')
|
||||
this.linkUserDataParams = this.$getApiParams('linkUserDataToTemplate')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
@ -405,6 +452,8 @@ export default {
|
||||
fetchData () {
|
||||
this.fetchZone()
|
||||
this.fetchOsTypes()
|
||||
this.fetchUserData()
|
||||
this.fetchUserdataPolicy()
|
||||
if (Object.prototype.hasOwnProperty.call(store.getters.apis, 'listConfigurations')) {
|
||||
if (this.allowed && this.hyperXenServerShow) {
|
||||
this.fetchXenServerProvider()
|
||||
@ -520,6 +569,20 @@ export default {
|
||||
this.osTypes.loading = false
|
||||
})
|
||||
},
|
||||
fetchUserData () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
|
||||
this.userdata.opts = []
|
||||
this.userdata.loading = true
|
||||
|
||||
api('listUserData', params).then(json => {
|
||||
const listUserdata = json.listuserdataresponse.userdata
|
||||
this.userdata.opts = listUserdata
|
||||
}).finally(() => {
|
||||
this.userdata.loading = false
|
||||
})
|
||||
},
|
||||
fetchXenServerProvider () {
|
||||
const params = {}
|
||||
params.name = 'xenserver.pvdriver.version'
|
||||
@ -712,6 +775,23 @@ export default {
|
||||
}
|
||||
this.format.opts = format
|
||||
},
|
||||
fetchUserdataPolicy () {
|
||||
const userdataPolicy = []
|
||||
userdataPolicy.push({
|
||||
id: 'allowoverride',
|
||||
description: 'allowoverride'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'append',
|
||||
description: 'append'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'denyoverride',
|
||||
description: 'denyoverride'
|
||||
})
|
||||
this.userdatapolicylist.opts = userdataPolicy
|
||||
},
|
||||
|
||||
handlerSelectZone (value) {
|
||||
if (!Array.isArray(value)) {
|
||||
value = [value]
|
||||
@ -830,6 +910,9 @@ export default {
|
||||
if (this.currentForm === 'Create') {
|
||||
this.loading = true
|
||||
api('registerTemplate', params).then(json => {
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.registertemplateresponse.template[0].id, this.userdatapolicy)
|
||||
}
|
||||
this.$notification.success({
|
||||
message: this.$t('label.register.template'),
|
||||
description: `${this.$t('message.success.register.template')} ${params.name}`
|
||||
@ -853,6 +936,9 @@ export default {
|
||||
api('getUploadParamsForTemplate', params).then(json => {
|
||||
this.uploadParams = (json.postuploadtemplateresponse && json.postuploadtemplateresponse.getuploadparams) ? json.postuploadtemplateresponse.getuploadparams : ''
|
||||
this.handleUpload()
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.postuploadtemplateresponse.template[0].id)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
@ -881,6 +967,22 @@ export default {
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
},
|
||||
linkUserdataToTemplate (userdataid, templateid, userdatapolicy) {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
params.userdataid = userdataid
|
||||
params.templateid = templateid
|
||||
if (userdatapolicy) {
|
||||
params.userdatapolicy = userdatapolicy
|
||||
}
|
||||
api('linkUserDataToTemplate', params).then(json => {
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
resetSelect (arrSelectReset) {
|
||||
arrSelectReset.forEach(name => {
|
||||
this.form[name] = undefined
|
||||
|
||||
307
ui/src/views/image/UpdateISO.vue
Normal file
307
ui/src/views/image/UpdateISO.vue
Normal file
@ -0,0 +1,307 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div class="form-layout" v-ctrl-enter="handleSubmit">
|
||||
<a-spin :spinning="loading">
|
||||
<a-form
|
||||
:ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
@finish="handleSubmit"
|
||||
layout="vertical">
|
||||
<a-form-item name="name" ref="name">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.name"
|
||||
:placeholder="apiParams.name.description"
|
||||
autoFocus />
|
||||
</a-form-item>
|
||||
<a-form-item name="displaytext" ref="displaytext">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.displaytext')" :tooltip="apiParams.displaytext.description"/>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:value="form.displaytext"
|
||||
:placeholder="apiParams.displaytext.description"
|
||||
autoFocus />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="ostypeid" ref="ostypeid" :label="$t('label.ostypeid')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.ostypeid"
|
||||
:loading="osTypes.loading"
|
||||
:placeholder="apiParams.ostypeid.description">
|
||||
<a-select-option v-for="opt in osTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item
|
||||
name="userdataid"
|
||||
ref="userdataid"
|
||||
:label="$t('label.userdata')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="userdataid"
|
||||
:placeholder="linkUserDataParams.userdataid.description"
|
||||
:loading="userdata.loading">
|
||||
<a-select-option v-for="opt in userdata.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item ref="userdatapolicy" name="userdatapolicy">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="userdatapolicy"
|
||||
:placeholder="linkUserDataParams.userdatapolicy.description"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
|
||||
{{ opt.id || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'UpdateIso',
|
||||
components: {
|
||||
TooltipLabel
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
osTypes: {},
|
||||
loading: false,
|
||||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('updateIso')
|
||||
this.isAdmin = ['Admin'].includes(this.$store.getters.userInfo.roletype)
|
||||
this.linkUserDataParams = this.$getApiParams('linkUserDataToTemplate')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
this.osTypes.loading = false
|
||||
this.osTypes.opts = []
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({
|
||||
name: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
ostypeid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
const resourceFields = ['name', 'displaytext', 'ostypeid', 'userdataid', 'userdatapolicy']
|
||||
|
||||
for (var field of resourceFields) {
|
||||
var fieldValue = this.resource[field]
|
||||
if (fieldValue) {
|
||||
switch (field) {
|
||||
case 'userdataid':
|
||||
this.userdataid = fieldValue
|
||||
break
|
||||
case 'userdatapolicy':
|
||||
this.userdatapolicy = fieldValue
|
||||
break
|
||||
default:
|
||||
this.form[field] = fieldValue
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
fetchData () {
|
||||
this.fetchOsTypes()
|
||||
this.fetchUserdata()
|
||||
this.fetchUserdataPolicy()
|
||||
},
|
||||
isValidValueForKey (obj, key) {
|
||||
return key in obj && obj[key] != null && obj[key] !== undefined && obj[key] !== ''
|
||||
},
|
||||
fetchOsTypes () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
this.osTypes.opts = []
|
||||
this.osTypes.loading = true
|
||||
api('listOsTypes', params).then(json => {
|
||||
const listOsTypes = json.listostypesresponse.ostype
|
||||
this.osTypes.opts = listOsTypes
|
||||
}).finally(() => {
|
||||
this.osTypes.loading = false
|
||||
})
|
||||
},
|
||||
fetchUserdataPolicy () {
|
||||
const userdataPolicy = []
|
||||
userdataPolicy.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'allowoverride',
|
||||
description: 'allowoverride'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'append',
|
||||
description: 'append'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'denyoverride',
|
||||
description: 'denyoverride'
|
||||
})
|
||||
this.userdatapolicylist.opts = userdataPolicy
|
||||
},
|
||||
fetchUserdata () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
|
||||
this.userdata.opts = []
|
||||
this.userdata.loading = true
|
||||
|
||||
api('listUserData', params).then(json => {
|
||||
const userdataIdAndName = []
|
||||
const userdataOpts = json.listuserdataresponse.userdata
|
||||
userdataIdAndName.push({
|
||||
id: '',
|
||||
name: ''
|
||||
})
|
||||
|
||||
Object.values(userdataOpts).forEach(userdata => {
|
||||
userdataIdAndName.push({
|
||||
id: userdata.id,
|
||||
name: userdata.name
|
||||
})
|
||||
})
|
||||
|
||||
this.userdata.opts = userdataIdAndName
|
||||
}).finally(() => {
|
||||
this.userdata.loading = false
|
||||
})
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.loading) return
|
||||
this.formRef.value.validate().then(() => {
|
||||
const values = toRaw(this.form)
|
||||
this.loading = true
|
||||
const params = {
|
||||
id: this.resource.id
|
||||
}
|
||||
for (const key in values) {
|
||||
if (!this.isValidValueForKey(values, key)) continue
|
||||
params[key] = values[key]
|
||||
}
|
||||
api('updateIso', params).then(json => {
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.updateisoresponse.iso.id, this.userdatapolicy)
|
||||
}
|
||||
this.$message.success(`${this.$t('message.success.update.iso')}: ${this.resource.name}`)
|
||||
this.$emit('refresh-data')
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}).catch(error => {
|
||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
},
|
||||
linkUserdataToTemplate (userdataid, isoid, userdatapolicy) {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
console.log(userdataid)
|
||||
if (userdataid && userdataid.length > 0) {
|
||||
params.userdataid = userdataid
|
||||
}
|
||||
params.isoid = isoid
|
||||
if (userdatapolicy) {
|
||||
params.userdatapolicy = userdatapolicy
|
||||
}
|
||||
api('linkUserDataToTemplate', params).then(json => {
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-layout {
|
||||
width: 60vw;
|
||||
|
||||
@media (min-width: 500px) {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -104,6 +104,46 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item
|
||||
name="userdataid"
|
||||
ref="userdataid"
|
||||
:label="$t('label.userdata')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="userdataid"
|
||||
:placeholder="linkUserDataParams.userdataid.description"
|
||||
:loading="userdata.loading">
|
||||
<a-select-option v-for="opt in userdata.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item ref="userdatapolicy" name="userdatapolicy">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="userdatapolicy"
|
||||
:placeholder="linkUserDataParams.userdatapolicy.description"
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
|
||||
{{ opt.id || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-form-item name="isdynamicallyscalable" ref="isdynamicallyscalable">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.isdynamicallyscalable')" :tooltip="apiParams.isdynamicallyscalable.description"/>
|
||||
@ -170,12 +210,17 @@ export default {
|
||||
keyboardType: {},
|
||||
osTypes: {},
|
||||
loading: false,
|
||||
selectedTemplateType: ''
|
||||
selectedTemplateType: '',
|
||||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.apiParams = this.$getApiParams('updateTemplate')
|
||||
this.isAdmin = ['Admin'].includes(this.$store.getters.userInfo.roletype)
|
||||
this.linkUserDataParams = this.$getApiParams('linkUserDataToTemplate')
|
||||
},
|
||||
created () {
|
||||
this.initForm()
|
||||
@ -198,14 +243,24 @@ export default {
|
||||
displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
ostypeid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable']
|
||||
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable', 'userdataid', 'userdatapolicy']
|
||||
if (this.isAdmin) {
|
||||
resourceFields.push('templatetype')
|
||||
}
|
||||
for (var field of resourceFields) {
|
||||
var fieldValue = this.resource[field]
|
||||
if (fieldValue) {
|
||||
this.form[field] = fieldValue
|
||||
switch (field) {
|
||||
case 'userdataid':
|
||||
this.userdataid = fieldValue
|
||||
break
|
||||
case 'userdatapolicy':
|
||||
this.userdatapolicy = fieldValue
|
||||
break
|
||||
default:
|
||||
this.form[field] = fieldValue
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
const resourceDetailsFields = []
|
||||
@ -226,6 +281,8 @@ export default {
|
||||
this.fetchRootDiskControllerTypes(this.resource.hypervisor)
|
||||
this.fetchNicAdapterTypes()
|
||||
this.fetchKeyboardTypes()
|
||||
this.fetchUserdata()
|
||||
this.fetchUserdataPolicy()
|
||||
},
|
||||
isValidValueForKey (obj, key) {
|
||||
return key in obj && obj[key] != null && obj[key] !== undefined && obj[key] !== ''
|
||||
@ -346,6 +403,53 @@ export default {
|
||||
|
||||
this.keyboardType.opts = keyboardType
|
||||
},
|
||||
fetchUserdataPolicy () {
|
||||
const userdataPolicy = []
|
||||
userdataPolicy.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'allowoverride',
|
||||
description: 'allowoverride'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'append',
|
||||
description: 'append'
|
||||
})
|
||||
userdataPolicy.push({
|
||||
id: 'denyoverride',
|
||||
description: 'denyoverride'
|
||||
})
|
||||
this.userdatapolicylist.opts = userdataPolicy
|
||||
},
|
||||
fetchUserdata () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
|
||||
this.userdata.opts = []
|
||||
this.userdata.loading = true
|
||||
|
||||
api('listUserData', params).then(json => {
|
||||
const userdataIdAndName = []
|
||||
const userdataOpts = json.listuserdataresponse.userdata
|
||||
userdataIdAndName.push({
|
||||
id: '',
|
||||
name: ''
|
||||
})
|
||||
|
||||
Object.values(userdataOpts).forEach(userdata => {
|
||||
userdataIdAndName.push({
|
||||
id: userdata.id,
|
||||
name: userdata.name
|
||||
})
|
||||
})
|
||||
|
||||
this.userdata.opts = userdataIdAndName
|
||||
}).finally(() => {
|
||||
this.userdata.loading = false
|
||||
})
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.loading) return
|
||||
@ -365,6 +469,9 @@ export default {
|
||||
params[key] = values[key]
|
||||
}
|
||||
api('updateTemplate', params).then(json => {
|
||||
if (this.userdataid !== null) {
|
||||
this.linkUserdataToTemplate(this.userdataid, json.updatetemplateresponse.template.id, this.userdatapolicy)
|
||||
}
|
||||
this.$message.success(`${this.$t('message.success.update.template')}: ${this.resource.name}`)
|
||||
this.$emit('refresh-data')
|
||||
this.closeAction()
|
||||
@ -379,6 +486,24 @@ export default {
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
},
|
||||
linkUserdataToTemplate (userdataid, templateid, userdatapolicy) {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
if (userdataid && userdataid.length > 0) {
|
||||
params.userdataid = userdataid
|
||||
}
|
||||
params.templateid = templateid
|
||||
if (userdatapolicy) {
|
||||
params.userdatapolicy = userdatapolicy
|
||||
}
|
||||
api('linkUserDataToTemplate', params).then(json => {
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user