Multiple SSH Keys support (#5965)

* keypairs added in api-constants

* names parameter added

* findbynames method added in dao

* change in impl to find and reset multiple keys

* findbynames method implemented

* log the publickeys, check the ssh keys given exists or not

* new ArrayList<>

* SQL IN toArray

* keypair

* null pointer exception solved with + concatanation

* null pointer exception solved with + concatanation

* error resolved

* keypair name to names in uservmresponse

* keypair name is set in the uservmresponse, from the details

* null checks are removed, keypairnames are stored in a string, sent to the resetvmsshinternal, and added in details

* commit first eval

* deploy vm takes multiple ssh-keys

* Deploy VM UI changed to accept multiple ssh keys

* Reset SSH UI API changed

* ResetSSH.vue

* ssh keys joined, ssh added in infocard

* changes made

* schema error resolved

* potential null pointer exception removed

* Update UserVmManagerImpl.java

unnecessary check removed.

* Update DeployVMCmd.java

* Update DeployVMCmd.java

* Update ResetVMSSHKeyCmd.java

* Update UserVmJoinDaoImpl.java

* .

* arraylist

* Update DeployVMCmd.java

* Update UserVmManagerImpl.java

* Update ResetVMSSHKeyCmd.java

* Update db

* Fix list vm by keypair

* ui fixes

* Fix typos

* ui fixes

* Cleanup

* Adding deprecated and since in api params

* Adding upgrade for existing vms with ssh keys

* Handle no key for cks

* Show existing keyparis in reset ssh key form

* get keys from the right account

Co-authored-by: bicrxm <bickrombishsass@gmail.com>
This commit is contained in:
David Jumani 2022-03-02 06:00:55 +05:30 committed by GitHub
parent cb2ddc45ac
commit 85c59979f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 378 additions and 177 deletions

View File

@ -215,7 +215,7 @@ public interface UserVmService {
*/ */
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, 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, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard, 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, List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
@ -297,7 +297,7 @@ public interface UserVmService {
*/ */
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, 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, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, 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, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
@ -377,7 +377,7 @@ public interface UserVmService {
*/ */
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, 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, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList, 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> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId) Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId)

View File

@ -59,6 +59,7 @@ public interface VmDetailConstants {
String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag"; String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag";
String DEPLOY_VM = "deployvm"; String DEPLOY_VM = "deployvm";
String SSH_PUBLIC_KEY = "SSH.PublicKey"; String SSH_PUBLIC_KEY = "SSH.PublicKey";
String SSH_KEY_PAIR_NAMES = "SSH.KeyPairNames";
String PASSWORD = "password"; String PASSWORD = "password";
String ENCRYPTED_PASSWORD = "Encrypted.Password"; String ENCRYPTED_PASSWORD = "Encrypted.Password";
@ -73,5 +74,6 @@ public interface VmDetailConstants {
String DISK_OFFERING = "diskOffering"; String DISK_OFFERING = "diskOffering";
String DEPLOY_AS_IS_CONFIGURATION = "configurationId"; String DEPLOY_AS_IS_CONFIGURATION = "configurationId";
String KEY_PAIR_NAMES = "keypairnames";
String CKS_CONTROL_NODE_LOGIN_USER = "controlNodeLoginUser"; String CKS_CONTROL_NODE_LOGIN_USER = "controlNodeLoginUser";
} }

View File

@ -441,6 +441,7 @@ public class ApiConstants {
public static final String NETWORKRATE = "networkrate"; public static final String NETWORKRATE = "networkrate";
public static final String HOST_TAGS = "hosttags"; public static final String HOST_TAGS = "hosttags";
public static final String SSH_KEYPAIR = "keypair"; public static final String SSH_KEYPAIR = "keypair";
public static final String SSH_KEYPAIRS = "keypairs";
public static final String HTTPMETHOD = "httpmethod"; public static final String HTTPMETHOD = "httpmethod";
public static final String HOST_CPU_CAPACITY = "hostcpucapacity"; public static final String HOST_CPU_CAPACITY = "hostcpucapacity";
public static final String HOST_CPU_NUM = "hostcpunum"; public static final String HOST_CPU_NUM = "hostcpunum";

View File

@ -153,9 +153,13 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
length = 1048576) length = 1048576)
private String userData; private String userData;
@Deprecated
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "name of the ssh key pair used to login to the virtual machine") @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; private String sshKeyPairName;
@Parameter(name = ApiConstants.SSH_KEYPAIRS, type = CommandType.LIST, collectionType = CommandType.STRING, since="4.17", description = "names of the ssh key pairs used to login to the virtual machine")
private List<String> sshKeyPairNames;
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "destination Host ID to deploy the VM to - parameter available for root admin only") @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "destination Host ID to deploy the VM to - parameter available for root admin only")
private Long hostId; private Long hostId;
@ -444,8 +448,15 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
return name; return name;
} }
public String getSSHKeyPairName() { public List<String> getSSHKeyPairNames() {
return sshKeyPairName; List<String> sshKeyPairs = new ArrayList<String>();
if(sshKeyPairNames != null) {
sshKeyPairs = sshKeyPairNames;
}
if(sshKeyPairName != null && !sshKeyPairName.isEmpty()) {
sshKeyPairs.add(sshKeyPairName);
}
return sshKeyPairs;
} }
public Long getHostId() { public Long getHostId() {

View File

@ -42,6 +42,9 @@ import com.cloud.user.Account;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import java.util.ArrayList;
import java.util.List;
@APICommand(name = "resetSSHKeyForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the SSH Key for virtual machine. " + @APICommand(name = "resetSSHKeyForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the SSH Key for virtual machine. " +
"The virtual machine must be in a \"Stopped\" state. [async]", responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, "The virtual machine must be in a \"Stopped\" state. [async]", responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
@ -58,8 +61,12 @@ public class ResetVMSSHKeyCmd extends BaseAsyncCmd implements UserCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, required = true, description = "The ID of the virtual machine") @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, required = true, description = "The ID of the virtual machine")
private Long id; private Long id;
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, required = true, description = "name of the ssh key pair used to login to the virtual machine") @Deprecated
private String name; @Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING ,description = "name of the ssh key pair used to login to the virtual machine")
String name;
@Parameter(name = ApiConstants.SSH_KEYPAIRS, type = CommandType.LIST, collectionType = CommandType.STRING, since="4.17", description = "names of the ssh key pairs to be used to login to the virtual machine")
List<String> names;
//Owner information //Owner information
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the ssh key. Must be used with domainId.") @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the ssh key. Must be used with domainId.")
@ -78,8 +85,15 @@ public class ResetVMSSHKeyCmd extends BaseAsyncCmd implements UserCmd {
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
public String getName() { public List<String> getNames() {
return name; List<String> keypairnames = new ArrayList<String>();
if (names != null) {
keypairnames = names;
}
if (name != null && !name.isEmpty()) {
keypairnames.add(name);
}
return keypairnames;
} }
public Long getId() { public Long getId() {

View File

@ -280,9 +280,9 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "List of read-only Vm details as comma separated string.", since = "4.16.0") @Param(description = "List of read-only Vm details as comma separated string.", since = "4.16.0")
private String readOnlyDetails; private String readOnlyDetails;
@SerializedName(ApiConstants.SSH_KEYPAIR) @SerializedName(ApiConstants.SSH_KEYPAIRS)
@Param(description = "ssh key-pair") @Param(description = "ssh key-pairs")
private String keyPairName; private String keyPairNames;
@SerializedName("affinitygroup") @SerializedName("affinitygroup")
@Param(description = "list of affinity groups associated with the virtual machine", responseObject = AffinityGroupResponse.class) @Param(description = "list of affinity groups associated with the virtual machine", responseObject = AffinityGroupResponse.class)
@ -588,8 +588,8 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
return instanceName; return instanceName;
} }
public String getKeyPairName() { public String getKeyPairNames() {
return keyPairName; return keyPairNames;
} }
public Set<AffinityGroupResponse> getAffinityGroupList() { public Set<AffinityGroupResponse> getAffinityGroupList() {
@ -848,8 +848,8 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
this.tags = tags; this.tags = tags;
} }
public void setKeyPairName(String keyPairName) { public void setKeyPairNames(String keyPairNames) {
this.keyPairName = keyPairName; this.keyPairNames = keyPairNames;
} }
public void setAffinityGroupList(Set<AffinityGroupResponse> affinityGroups) { public void setAffinityGroupList(Set<AffinityGroupResponse> affinityGroups) {

View File

@ -37,4 +37,6 @@ public interface SSHKeyPairDao extends GenericDao<SSHKeyPairVO, Long> {
public SSHKeyPairVO findByPublicKey(long accountId, long domainId, String publicKey); public SSHKeyPairVO findByPublicKey(long accountId, long domainId, String publicKey);
public List<SSHKeyPairVO> findByNames(long accountId, long domainId, List<String> names);
} }

View File

@ -19,6 +19,7 @@ package com.cloud.user.dao;
import java.util.List; import java.util.List;
import com.cloud.utils.db.Filter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.cloud.user.SSHKeyPairVO; import com.cloud.user.SSHKeyPairVO;
@ -63,6 +64,16 @@ public class SSHKeyPairDaoImpl extends GenericDaoBase<SSHKeyPairVO, Long> implem
return findOneBy(sc); return findOneBy(sc);
} }
@Override
public List<SSHKeyPairVO> findByNames(long accountId, long domainId, List<String> names) {
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
final Filter filter = new Filter(SSHKeyPairVO.class,"name",false, null, null);
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
sc.addAnd("name", SearchCriteria.Op.IN, names.toArray());
return this.search(sc, filter);
}
@Override @Override
public SSHKeyPairVO findByPublicKey(String publicKey) { public SSHKeyPairVO findByPublicKey(String publicKey) {
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria(); SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();

View File

@ -488,8 +488,7 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
public void setDetail(String name, String value) { public void setDetail(String name, String value) {
assert (details != null) : "Did you forget to load the details?"; assert (details != null) : "Did you forget to load the details?";
this.details.put(name, value);
details.put(name, value);
} }
public void setDetails(Map<String, String> details) { public void setDetails(Map<String, String> details) {

View File

@ -471,7 +471,7 @@ SELECT
`user_ip_address`.`id` AS `public_ip_id`, `user_ip_address`.`id` AS `public_ip_id`,
`user_ip_address`.`uuid` AS `public_ip_uuid`, `user_ip_address`.`uuid` AS `public_ip_uuid`,
`user_ip_address`.`public_ip_address` AS `public_ip_address`, `user_ip_address`.`public_ip_address` AS `public_ip_address`,
`ssh_keypairs`.`keypair_name` AS `keypair_name`, `ssh_details`.`value` AS `keypair_names`,
`resource_tags`.`id` AS `tag_id`, `resource_tags`.`id` AS `tag_id`,
`resource_tags`.`uuid` AS `tag_uuid`, `resource_tags`.`uuid` AS `tag_uuid`,
`resource_tags`.`key` AS `tag_key`, `resource_tags`.`key` AS `tag_key`,
@ -495,7 +495,7 @@ SELECT
`affinity_group`.`description` AS `affinity_group_description`, `affinity_group`.`description` AS `affinity_group_description`,
`vm_instance`.`dynamically_scalable` AS `dynamically_scalable` `vm_instance`.`dynamically_scalable` AS `dynamically_scalable`
FROM FROM
(((((((((((((((((((((((((((((((((`user_vm` ((((((((((((((((((((((((((((((((`user_vm`
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`) JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
AND ISNULL(`vm_instance`.`removed`)))) AND ISNULL(`vm_instance`.`removed`))))
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`))) JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
@ -524,9 +524,7 @@ FROM
AND ISNULL(`vpc`.`removed`)))) AND ISNULL(`vpc`.`removed`))))
LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`))) 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`) LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`)
AND (`ssh_details`.`name` = 'SSH.PublicKey')))) AND (`ssh_details`.`name` = 'SSH.KeyPairNames'))))
LEFT JOIN `ssh_keypairs` ON (((`ssh_keypairs`.`public_key` = `ssh_details`.`value`)
AND (`ssh_keypairs`.`account_id` = `account`.`id`))))
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`) LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`)
AND (`resource_tags`.`resource_type` = 'UserVm')))) AND (`resource_tags`.`resource_type` = 'UserVm'))))
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`) LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`)
@ -646,3 +644,11 @@ CREATE VIEW `cloud`.`domain_router_view` AS
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'listConfigurations', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule; INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'listConfigurations', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule;
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'updateConfiguration', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule; INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'updateConfiguration', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule;
INSERT INTO `cloud`.`user_vm_details`(`vm_id`, `name`, `value`)
SELECT `user_vm_details`.`vm_id`, 'SSH.KeyPairNames', `ssh_keypairs`.`keypair_name`
FROM `cloud`.`user_vm_details`
INNER JOIN `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value
INNER JOIN `cloud`.`vm_instance` ON vm_instance.id = user_vm_details.vm_id
WHERE ssh_keypairs.account_id = vm_instance.account_id;

View File

@ -376,9 +376,13 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
logAndThrow(Level.ERROR, "Failed to read Kubernetes node configuration file", e); logAndThrow(Level.ERROR, "Failed to read Kubernetes node configuration file", e);
} }
String base64UserData = Base64.encodeBase64String(k8sNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset())); String base64UserData = Base64.encodeBase64String(k8sNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset()));
List<String> keypairs = new ArrayList<String>();
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
hostName, hostName, null, null, null, hostName, hostName, null, null, null,
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null); null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
if (LOGGER.isInfoEnabled()) { if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Created node VM : %s, %s in the Kubernetes cluster : %s", hostName, nodeVm.getUuid(), kubernetesCluster.getName())); LOGGER.info(String.format("Created node VM : %s, %s in the Kubernetes cluster : %s", hostName, nodeVm.getUuid(), kubernetesCluster.getName()));

View File

@ -213,9 +213,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
logAndThrow(Level.ERROR, "Failed to read Kubernetes control node configuration file", e); logAndThrow(Level.ERROR, "Failed to read Kubernetes control node configuration file", e);
} }
String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset())); String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset()));
List<String> keypairs = new ArrayList<String>();
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
hostName, hostName, null, null, null, hostName, hostName, null, null, null,
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
requestedIps, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null); requestedIps, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
if (LOGGER.isInfoEnabled()) { if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Created control VM ID: %s, %s in the Kubernetes cluster : %s", controlVm.getUuid(), hostName, kubernetesCluster.getName())); LOGGER.info(String.format("Created control VM ID: %s, %s in the Kubernetes cluster : %s", controlVm.getUuid(), hostName, kubernetesCluster.getName()));
@ -273,9 +277,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
logAndThrow(Level.ERROR, "Failed to read Kubernetes control configuration file", e); logAndThrow(Level.ERROR, "Failed to read Kubernetes control configuration file", e);
} }
String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset())); String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(com.cloud.utils.StringUtils.getPreferredCharset()));
List<String> keypairs = new ArrayList<String>();
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner,
hostName, hostName, null, null, null, hostName, hostName, null, null, null,
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, keypairs,
null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null); null, addrs, null, null, null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null);
if (LOGGER.isInfoEnabled()) { if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Created control VM ID : %s, %s in the Kubernetes cluster : %s", additionalControlVm.getUuid(), hostName, kubernetesCluster.getName())); LOGGER.info(String.format("Created control VM ID : %s, %s in the Kubernetes cluster : %s", additionalControlVm.getUuid(), hostName, kubernetesCluster.getName()));

View File

@ -1072,7 +1072,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
if (keyPairName != null) { if (keyPairName != null) {
sb.and("keyPairName", sb.entity().getKeypairName(), SearchCriteria.Op.EQ); sb.and("keyPairName", sb.entity().getKeypairNames(), SearchCriteria.Op.FIND_IN_SET);
} }
if (!isRootAdmin) { if (!isRootAdmin) {

View File

@ -219,7 +219,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
userVmResponse.setPublicIpId(userVm.getPublicIpUuid()); userVmResponse.setPublicIpId(userVm.getPublicIpUuid());
userVmResponse.setPublicIp(userVm.getPublicIpAddress()); userVmResponse.setPublicIp(userVm.getPublicIpAddress());
userVmResponse.setKeyPairName(userVm.getKeypairName()); userVmResponse.setKeyPairNames(userVm.getKeypairNames());
userVmResponse.setOsTypeId(userVm.getGuestOsUuid()); userVmResponse.setOsTypeId(userVm.getGuestOsUuid());
GuestOS guestOS = ApiDBUtils.findGuestOSById(userVm.getGuestOsId()); GuestOS guestOS = ApiDBUtils.findGuestOSById(userVm.getGuestOsId());
if (guestOS != null) { if (guestOS != null) {

View File

@ -353,8 +353,8 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
@Column(name = "project_name") @Column(name = "project_name")
private String projectName; private String projectName;
@Column(name = "keypair_name") @Column(name = "keypair_names")
private String keypairName; private String keypairNames;
@Column(name = "job_id") @Column(name = "job_id")
private Long jobId; private Long jobId;
@ -779,8 +779,8 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return projectName; return projectName;
} }
public String getKeypairName() { public String getKeypairNames() {
return keypairName; return keypairNames;
} }
public boolean isLimitCpuUse() { public boolean isLimitCpuUse() {

View File

@ -313,7 +313,6 @@ import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.user.ResourceLimitService; import com.cloud.user.ResourceLimitService;
import com.cloud.user.SSHKeyPair;
import com.cloud.user.SSHKeyPairVO; import com.cloud.user.SSHKeyPairVO;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserStatisticsVO;
@ -888,8 +887,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
Account owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId()); Account owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId());
Long vmId = cmd.getId(); Long vmId = cmd.getId();
UserVmVO userVm = _vmDao.findById(cmd.getId()); UserVmVO userVm = _vmDao.findById(cmd.getId());
if (userVm == null) { if (userVm == null) {
throw new InvalidParameterValueException("unable to find a virtual machine by id" + cmd.getId()); throw new InvalidParameterValueException("unable to find a virtual machine by id" + cmd.getId());
} }
@ -907,18 +906,27 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Vm " + userVm + " should be stopped to do SSH Key reset"); throw new InvalidParameterValueException("Vm " + userVm + " should be stopped to do SSH Key reset");
} }
SSHKeyPairVO s = _sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), cmd.getName()); if (cmd.getNames() == null || cmd.getNames().isEmpty()) {
if (s == null) { throw new InvalidParameterValueException("'keypair' or 'keyparis' must be specified");
throw new InvalidParameterValueException("A key pair with name '" + cmd.getName() + "' does not exist for account " + owner.getAccountName()
+ " in specified domain id");
} }
String keypairnames = "";
String sshPublicKeys = "";
List<SSHKeyPairVO> pairs = new ArrayList<>();
pairs = _sshKeyPairDao.findByNames(owner.getAccountId(), owner.getDomainId(), cmd.getNames());
if (pairs == null || pairs.size() != cmd.getNames().size()) {
throw new InvalidParameterValueException("Not all specified keyparis exist");
}
sshPublicKeys = pairs.stream().map(p -> p.getPublicKey()).collect(Collectors.joining("\n"));
keypairnames = String.join(",", cmd.getNames());
_accountMgr.checkAccess(caller, null, true, userVm); _accountMgr.checkAccess(caller, null, true, userVm);
String sshPublicKey = s.getPublicKey(); boolean result = resetVMSSHKeyInternal(vmId, sshPublicKeys, keypairnames);
boolean result = resetVMSSHKeyInternal(vmId, sshPublicKey);
UserVmVO vm = _vmDao.findById(vmId);
_vmDao.loadDetails(vm);
if (!result) { if (!result) {
throw new CloudRuntimeException("Failed to reset SSH Key for the virtual machine "); throw new CloudRuntimeException("Failed to reset SSH Key for the virtual machine ");
} }
@ -933,7 +941,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
userVmDetailsDao.removeDetail(vmId, VmDetailConstants.ENCRYPTED_PASSWORD); userVmDetailsDao.removeDetail(vmId, VmDetailConstants.ENCRYPTED_PASSWORD);
} }
private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey) throws ResourceUnavailableException, InsufficientCapacityException { private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKeys, String keypairnames) throws ResourceUnavailableException, InsufficientCapacityException {
Long userId = CallContext.current().getCallingUserId(); Long userId = CallContext.current().getCallingUserId();
VMInstanceVO vmInstance = _vmDao.findById(vmId); VMInstanceVO vmInstance = _vmDao.findById(vmId);
@ -954,8 +962,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (element == null) { if (element == null) {
throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for SSH Key reset"); throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for SSH Key reset");
} }
boolean result = element.saveSSHKey(defaultNetwork, defaultNicProfile, vmProfile, sshPublicKey); boolean result = element.saveSSHKey(defaultNetwork, defaultNicProfile, vmProfile, sshPublicKeys);
// Need to reboot the virtual machine so that the password gets redownloaded from the DomR, and reset on the VM // Need to reboot the virtual machine so that the password gets redownloaded from the DomR, and reset on the VM
if (!result) { if (!result) {
s_logger.debug("Failed to reset SSH Key for the virtual machine; no need to reboot the vm"); s_logger.debug("Failed to reset SSH Key for the virtual machine; no need to reboot the vm");
@ -963,7 +970,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} else { } else {
final UserVmVO userVm = _vmDao.findById(vmId); final UserVmVO userVm = _vmDao.findById(vmId);
_vmDao.loadDetails(userVm); _vmDao.loadDetails(userVm);
userVm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey); userVm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKeys);
userVm.setDetail(VmDetailConstants.SSH_KEY_PAIR_NAMES, keypairnames);
_vmDao.saveDetails(userVm); _vmDao.saveDetails(userVm);
if (vmInstance.getState() == State.Stopped) { if (vmInstance.getState() == State.Stopped) {
@ -3403,7 +3411,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, 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, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList, 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<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, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException, ResourceAllocationException { StorageUnavailableException, ResourceAllocationException {
@ -3453,7 +3461,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap, userData, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap,
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId); dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
} }
@ -3462,7 +3470,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, 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, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, 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, 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) throws InsufficientCapacityException, ConcurrentOperationException, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
@ -3564,7 +3572,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap, userData, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId); userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
} }
@ -3572,7 +3580,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) @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, 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, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList, 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> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException, ResourceAllocationException { StorageUnavailableException, ResourceAllocationException {
@ -3623,9 +3631,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList); verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList);
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData,
sshKeyPair, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap,
dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, type, overrideDiskOfferingId); dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, type, overrideDiskOfferingId);
} }
@ -3742,7 +3749,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@DB @DB
private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner, 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, Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard, 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, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId) throws InsufficientCapacityException, ResourceUnavailableException, Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId) throws InsufficientCapacityException, ResourceUnavailableException,
@ -3945,14 +3952,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Find an SSH public key corresponding to the key pair name, if one is // Find an SSH public key corresponding to the key pair name, if one is
// given // given
String sshPublicKey = null; String sshPublicKeys = "";
if (sshKeyPair != null && !sshKeyPair.equals("")) { String keypairnames = "";
SSHKeyPair pair = _sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), sshKeyPair); if (!sshKeyPairs.isEmpty()) {
if (pair == null) { List<SSHKeyPairVO> pairs = _sshKeyPairDao.findByNames(owner.getAccountId(), owner.getDomainId(), sshKeyPairs);
throw new InvalidParameterValueException("A key pair with name '" + sshKeyPair + "' was not found."); if (pairs == null || pairs.size() != sshKeyPairs.size()) {
throw new InvalidParameterValueException("Not all specified keyparis exist");
} }
sshPublicKey = pair.getPublicKey(); sshPublicKeys = pairs.stream().map(p -> p.getPublicKey()).collect(Collectors.joining("\n"));
keypairnames = String.join(",", sshKeyPairs);
} }
LinkedHashMap<String, List<NicProfile>> networkNicMap = new LinkedHashMap<>(); LinkedHashMap<String, List<NicProfile>> networkNicMap = new LinkedHashMap<>();
@ -4014,7 +4023,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Unable to deploy VM as UserData is provided while deploying the VM, but there is no support for " + Network.Service.UserData.getName() + " service in the default network " + network.getId()); throw new InvalidParameterValueException("Unable to deploy VM as UserData is provided while deploying the VM, but there is no support for " + Network.Service.UserData.getName() + " service in the default network " + network.getId());
} }
if ((sshPublicKey != null) && (!sshPublicKey.isEmpty())) { if ((sshPublicKeys != null) && (!sshPublicKeys.isEmpty())) {
throw new InvalidParameterValueException("Unable to deploy VM as SSH keypair is provided while deploying the VM, but there is no support for " + Network.Service.UserData.getName() + " service in the default network " + network.getId()); throw new InvalidParameterValueException("Unable to deploy VM as SSH keypair is provided while deploying the VM, but there is no support for " + Network.Service.UserData.getName() + " service in the default network " + network.getId());
} }
@ -4113,8 +4122,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
dynamicScalingEnabled = dynamicScalingEnabled && checkIfDynamicScalingCanBeEnabled(null, offering, template, zone.getId()); 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, caller, isDisplayVm, keyboard, accountId, userId, offering,
isIso, sshPublicKey, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap, isIso, sshPublicKeys, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap,
datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, type, rootDiskOfferingId); datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, type, rootDiskOfferingId, keypairnames);
// Assign instance to the group // Assign instance to the group
try { try {
@ -4248,10 +4257,10 @@ 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, 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, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap<String, List<NicProfile>> networkNicMap, 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 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, final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String type, final Long rootDiskOfferingId) throws InsufficientCapacityException { final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String type, final Long rootDiskOfferingId, String sshkeypairs) throws InsufficientCapacityException {
return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() { return Transaction.execute(new TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() {
@Override @Override
public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException { public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException {
@ -4265,8 +4274,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
vm.details.putAll(details); vm.details.putAll(details);
} }
if (sshPublicKey != null) { if (sshPublicKeys != "") {
vm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey); vm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKeys);
}
if (sshkeypairs != "") {
vm.setDetail(VmDetailConstants.SSH_KEY_PAIR_NAMES, sshkeypairs);
} }
if (keyboard != null && !keyboard.isEmpty()) { if (keyboard != null && !keyboard.isEmpty()) {
@ -4452,16 +4465,16 @@ 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, 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 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 sshPublicKey, final LinkedHashMap<String, List<NicProfile>> networkNicMap, 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 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<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String type, final Long rootDiskOfferingId) throws InsufficientCapacityException { Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String type, final Long rootDiskOfferingId, String sshkeypairs) throws InsufficientCapacityException {
return commitUserVm(false, zone, null, null, template, hostName, displayName, owner, return commitUserVm(false, zone, null, null, template, hostName, displayName, owner,
diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard,
accountId, userId, offering, isIso, sshPublicKey, networkNicMap, accountId, userId, offering, isIso, sshPublicKeys, networkNicMap,
id, instanceName, uuidName, hypervisorType, customParameters, id, instanceName, uuidName, hypervisorType, customParameters,
extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
userVmOVFPropertiesMap, null, dynamicScalingEnabled, type, rootDiskOfferingId); userVmOVFPropertiesMap, null, dynamicScalingEnabled, type, rootDiskOfferingId, sshkeypairs);
} }
public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map<String, String> customParameters) throws InvalidParameterValueException public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map<String, String> customParameters) throws InvalidParameterValueException
@ -5689,7 +5702,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long size = cmd.getSize(); Long size = cmd.getSize();
String group = cmd.getGroup(); String group = cmd.getGroup();
String userData = cmd.getUserData(); String userData = cmd.getUserData();
String sshKeyPairName = cmd.getSSHKeyPairName(); List<String> sshKeyPairNames = cmd.getSSHKeyPairNames();
Boolean displayVm = cmd.isDisplayVm(); Boolean displayVm = cmd.isDisplayVm();
String keyboard = cmd.getKeyboard(); String keyboard = cmd.getKeyboard();
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap(); Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
@ -5699,14 +5712,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
} else { } else {
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(), size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId); dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
} }
} else { } else {
if (zone.isSecurityGroupEnabled()) { if (zone.isSecurityGroupEnabled()) {
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name, vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name,
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(), cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId); dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
@ -5715,10 +5728,11 @@ 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"); 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, vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId); cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
} }
} }
// check if this templateId has a child ISO // check if this templateId has a child ISO
List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(templateId); List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(templateId);
for (VMTemplateVO tmpl: child_templates){ for (VMTemplateVO tmpl: child_templates){
@ -5750,7 +5764,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
} }
return vm; return vm;
} }
@ -7694,13 +7707,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
private void encryptAndStorePassword(UserVmVO vm, String password) { private void encryptAndStorePassword(UserVmVO vm, String password) {
String sshPublicKey = vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY); String sshPublicKeys = vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY);
if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) { if (sshPublicKeys != null && !sshPublicKeys.equals("") && password != null && !password.equals("saved_password")) {
if (!sshPublicKey.startsWith("ssh-rsa")) { if (!sshPublicKeys.startsWith("ssh-rsa")) {
s_logger.warn("Only RSA public keys can be used to encrypt a vm password."); s_logger.warn("Only RSA public keys can be used to encrypt a vm password.");
return; return;
} }
String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKey, password); String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKeys, password);
if (encryptedPasswd == null) { if (encryptedPasswd == null) {
throw new CloudRuntimeException("Error encrypting password"); throw new CloudRuntimeException("Error encrypting password");
} }
@ -7830,7 +7843,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override @Override
public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName,
final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey, final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKeys,
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException { final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException {
if (zone == null) { if (zone == null) {
throw new InvalidParameterValueException("Unable to import virtual machine with invalid zone"); throw new InvalidParameterValueException("Unable to import virtual machine with invalid zone");
@ -7851,9 +7864,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId()); final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId());
return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner,
null, null, userData, caller, isDisplayVm, keyboard, null, null, userData, caller, isDisplayVm, keyboard,
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKey, null, accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, null,
id, instanceName, uuidName, hypervisorType, customParameters, id, instanceName, uuidName, hypervisorType, customParameters,
null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId()); null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null);
} }
@Override @Override

View File

@ -1240,6 +1240,7 @@
"label.keyboard": "Keyboard language", "label.keyboard": "Keyboard language",
"label.keyboardtype": "Keyboard type", "label.keyboardtype": "Keyboard type",
"label.keypair": "SSH Key Pair", "label.keypair": "SSH Key Pair",
"label.keypairs": "SSH Key Pair(s)",
"label.kubeconfig.cluster": "Kubernetes Cluster Config", "label.kubeconfig.cluster": "Kubernetes Cluster Config",
"label.kubernetes": "Kubernetes", "label.kubernetes": "Kubernetes",
"label.kubernetes.access.details": "The kubernetes nodes can be accessed via ssh using: <br> <code><b> ssh -i [ssh_key] -p [port_number] cloud@[public_ip_address] </b></code> <br><br> where, <br> <code><b>ssh_key:</b></code> points to the ssh private key file corresponding to the key that was associated while creating the Kubernetes cluster. If no ssh key was provided during Kubernetes cluster creation, use the ssh private key of the management server. <br> <code><b>port_number:</b></code> can be obtained from the Port Forwarding Tab (Public Port column)", "label.kubernetes.access.details": "The kubernetes nodes can be accessed via ssh using: <br> <code><b> ssh -i [ssh_key] -p [port_number] cloud@[public_ip_address] </b></code> <br><br> where, <br> <code><b>ssh_key:</b></code> points to the ssh private key file corresponding to the key that was associated while creating the Kubernetes cluster. If no ssh key was provided during Kubernetes cluster creation, use the ssh private key of the management server. <br> <code><b>port_number:</b></code> can be obtained from the Port Forwarding Tab (Public Port column)",

View File

@ -361,11 +361,13 @@
<router-link :to="{ path: '/vmgroup/' + resource.groupid }">{{ resource.group || resource.groupid }}</router-link> <router-link :to="{ path: '/vmgroup/' + resource.groupid }">{{ resource.group || resource.groupid }}</router-link>
</div> </div>
</div> </div>
<div class="resource-detail-item" v-if="resource.keypair"> <div class="resource-detail-item" v-if="resource.keypairs">
<div class="resource-detail-item__label">{{ $t('label.keypair') }}</div> <div class="resource-detail-item__label">{{ $t('label.keypairs') }}</div>
<div class="resource-detail-item__details"> <div class="resource-detail-item__details">
<a-icon type="key" /> <a-icon type="key" />
<router-link :to="{ path: '/ssh/' + resource.keypair }">{{ resource.keypair }}</router-link> <li v-for="keypair in keypairs" :key="keypair">
<router-link :to="{ path: '/ssh/' + keypair }" style="margin-right: 5px">{{ keypair }}</router-link>
</li>
</div> </div>
</div> </div>
<div class="resource-detail-item" v-if="resource.virtualmachineid"> <div class="resource-detail-item" v-if="resource.virtualmachineid">
@ -813,6 +815,15 @@ export default {
return null return null
}, },
keypairs () {
if (!this.resource.keypairs) {
return null
}
if (typeof this.resource.keypairs === 'string' || this.resource.keypairs instanceof String) {
return this.resource.keypairs.split(',')
}
return [this.resource.keypairs.toString()]
},
templateIcon () { templateIcon () {
return this.resource.templateid return this.resource.templateid
}, },

View File

@ -343,31 +343,9 @@ export default {
message: 'message.desc.reset.ssh.key.pair', message: 'message.desc.reset.ssh.key.pair',
docHelp: 'adminguide/virtual_machines.html#resetting-ssh-keys', docHelp: 'adminguide/virtual_machines.html#resetting-ssh-keys',
dataView: true, dataView: true,
args: ['keypair', 'account', 'domainid'],
show: (record) => { return ['Stopped'].includes(record.state) }, show: (record) => { return ['Stopped'].includes(record.state) },
mapping: { popup: true,
keypair: { component: () => import('@/views/compute/ResetSshKeyPair')
api: 'listSSHKeyPairs',
params: (record) => { return { account: record.account, domainid: record.domainid } }
},
account: {
value: (record) => { return record.account }
},
domainid: {
value: (record) => { return record.domainid }
}
},
successMethod: (obj, result) => {
const vm = result.jobresult.virtualmachine || {}
if (result.jobstatus === 1 && vm.password) {
const name = vm.displayname || vm.name || vm.id
obj.$notification.success({
message: `${obj.$t('label.reset.ssh.key.pair.on.vm')}: ` + name,
description: `${obj.$t('label.password.reset.confirm')}: ` + vm.password,
duration: 0
})
}
}
}, },
{ {
api: 'assignVirtualMachine', api: 'assignVirtualMachine',

View File

@ -440,7 +440,7 @@
:items="options.sshKeyPairs" :items="options.sshKeyPairs"
:row-count="rowCount.sshKeyPairs" :row-count="rowCount.sshKeyPairs"
:zoneId="zoneId" :zoneId="zoneId"
:value="sshKeyPair ? sshKeyPair.name : ''" :value="sshKeyPairs"
:loading="loading.sshKeyPairs" :loading="loading.sshKeyPairs"
:preFillContent="dataPreFill" :preFillContent="dataPreFill"
@select-ssh-key-pair-item="($event) => updateSshKeyPairs($event)" @select-ssh-key-pair-item="($event) => updateSshKeyPairs($event)"
@ -797,7 +797,7 @@ export default {
templateid: null, templateid: null,
templatename: null, templatename: null,
keyboard: null, keyboard: null,
keypair: null, keypairs: [],
group: null, group: null,
affinitygroupids: [], affinitygroupids: [],
affinitygroup: [], affinitygroup: [],
@ -861,6 +861,7 @@ export default {
networks: [], networks: [],
networksAdd: [], networksAdd: [],
zone: {}, zone: {},
sshKeyPairs: [],
sshKeyPair: {}, sshKeyPair: {},
overrideDiskOffering: {}, overrideDiskOffering: {},
templateFilter: [ templateFilter: [
@ -1186,7 +1187,6 @@ export default {
if (this.rootDiskSelected?.id) { if (this.rootDiskSelected?.id) {
instanceConfig.overridediskofferingid = this.rootDiskSelected.id instanceConfig.overridediskofferingid = this.rootDiskSelected.id
} }
console.log('overrided value ' + instanceConfig.overridediskofferingid)
if (instanceConfig.overridediskofferingid) { if (instanceConfig.overridediskofferingid) {
this.overrideDiskOffering = _.find(this.options.diskOfferings, (option) => option.id === instanceConfig.overridediskofferingid) this.overrideDiskOffering = _.find(this.options.diskOfferings, (option) => option.id === instanceConfig.overridediskofferingid)
} else { } else {
@ -1195,7 +1195,6 @@ export default {
this.zone = _.find(this.options.zones, (option) => option.id === instanceConfig.zoneid) this.zone = _.find(this.options.zones, (option) => option.id === instanceConfig.zoneid)
this.affinityGroups = _.filter(this.options.affinityGroups, (option) => _.includes(instanceConfig.affinitygroupids, option.id)) this.affinityGroups = _.filter(this.options.affinityGroups, (option) => _.includes(instanceConfig.affinitygroupids, option.id))
this.networks = _.filter(this.options.networks, (option) => _.includes(instanceConfig.networkids, option.id)) this.networks = _.filter(this.options.networks, (option) => _.includes(instanceConfig.networkids, option.id))
this.sshKeyPair = _.find(this.options.sshKeyPairs, (option) => option.name === instanceConfig.keypair)
if (this.zone) { if (this.zone) {
this.vm.zoneid = this.zone.id this.vm.zoneid = this.zone.id
@ -1276,6 +1275,9 @@ export default {
if (this.affinityGroups) { if (this.affinityGroups) {
this.vm.affinitygroup = this.affinityGroups this.vm.affinitygroup = this.affinityGroups
} }
if (this.sshKeyPairs) {
this.vm.keypairs = this.sshKeyPairs
}
} }
}, },
serviceOffering (oldValue, newValue) { serviceOffering (oldValue, newValue) {
@ -1314,7 +1316,7 @@ export default {
this.form.getFieldDecorator('affinitygroupids', { initialValue: [], preserve: true }) this.form.getFieldDecorator('affinitygroupids', { initialValue: [], preserve: true })
this.form.getFieldDecorator('networkids', { initialValue: [], preserve: true }) this.form.getFieldDecorator('networkids', { initialValue: [], preserve: true })
this.form.getFieldDecorator('defaultnetworkid', { initialValue: undefined, preserve: true }) this.form.getFieldDecorator('defaultnetworkid', { initialValue: undefined, preserve: true })
this.form.getFieldDecorator('keypair', { initialValue: undefined, preserve: true }) this.form.getFieldDecorator('keypairs', { initialValue: [], preserve: true })
this.form.getFieldDecorator('cpunumber', { initialValue: undefined, preserve: true }) this.form.getFieldDecorator('cpunumber', { initialValue: undefined, preserve: true })
this.form.getFieldDecorator('cpuSpeed', { initialValue: undefined, preserve: true }) this.form.getFieldDecorator('cpuSpeed', { initialValue: undefined, preserve: true })
this.form.getFieldDecorator('memory', { initialValue: undefined, preserve: true }) this.form.getFieldDecorator('memory', { initialValue: undefined, preserve: true })
@ -1615,16 +1617,11 @@ export default {
updateNetworkConfig (networks) { updateNetworkConfig (networks) {
this.networkConfig = networks this.networkConfig = networks
}, },
updateSshKeyPairs (name) { updateSshKeyPairs (names) {
if (name === this.$t('label.noselect')) {
this.form.setFieldsValue({
keypair: undefined
})
return
}
this.form.setFieldsValue({ this.form.setFieldsValue({
keypair: name keypairs: names
}) })
this.sshKeyPairs = names.map((sshKeyPair) => { return sshKeyPair.name })
}, },
escapePropertyKey (key) { escapePropertyKey (key) {
return key.split('.').join('\\002E') return key.split('.').join('\\002E')
@ -1831,7 +1828,8 @@ export default {
deployVmData.securitygroupids = this.securitygroupids.join(',') deployVmData.securitygroupids = this.securitygroupids.join(',')
} }
// step 7: select ssh key pair // step 7: select ssh key pair
deployVmData.keypair = values.keypair deployVmData.keypairs = this.sshKeyPairs.join(',')
if (values.name) { if (values.name) {
deployVmData.name = values.name deployVmData.name = values.name
deployVmData.displayname = values.name deployVmData.displayname = values.name

View File

@ -0,0 +1,178 @@
// 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-form class="form" v-ctrl-enter="handleSubmit">
<p v-html="$t('message.desc.reset.ssh.key.pair')" />
<a-spin :spinning="loading">
<div class="form__item">
<a-input-search
style="margin-bottom: 10px;"
:placeholder="$t('label.search')"
v-model="filter"
@search="handleSearch"
autoFocus />
</div>
<div class="form__item">
<a-table
size="small"
:loading="loading"
:columns="columns"
:dataSource="items"
:rowKey="record => record.name"
:pagination="{showSizeChanger: true, total: total}"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange"
@handle-search-filter="handleTableChange"
style="overflow-y: auto" >
<template v-slot:account><a-icon type="user" /> {{ $t('label.account') }}</template>
<template v-slot:domain><a-icon type="block" /> {{ $t('label.domain') }}</template>
</a-table>
</div>
<div :span="24" class="action-button">
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
</div>
</a-spin>
</a-form>
</template>
<script>
import { api } from '@/api'
import { genericCompare } from '@/utils/sort.js'
export default {
name: 'ResetSshKeyPair',
props: {
resource: {
type: Object,
required: true
}
},
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,
keyword: '',
response: 'json'
},
filter: '',
loading: false
}
},
created () {
this.fetchData()
if (this.resource.keypairs) {
this.selectedRowKeys = this.resource.keypairs.split(',')
}
},
methods: {
fetchData () {
this.loading = true
this.items = []
this.total = 0
api('listSSHKeyPairs', this.options).then(response => {
this.total = response.listsshkeypairsresponse.count
if (this.total !== 0) {
this.items = response.listsshkeypairsresponse.sshkeypair
}
}).finally(() => {
this.loading = false
})
},
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.loading) return
this.loading = true
api('resetSSHKeyForVirtualMachine', {
id: this.resource.id,
keypairs: this.selectedRowKeys.join(',')
}).then(response => {
const jobId = response.resetSSHKeyforvirtualmachineresponse.jobid
const title = `${this.$t('label.reset.ssh.key.pair')}`
if (jobId) {
this.$pollJob({
jobId,
title,
description: this.resource.name,
successMessage: `${title} ${this.$t('label.success')}`,
loadingMessage: `${title} ${this.$t('label.in.progress')}`,
catchMessage: this.$t('error.fetching.async.job.result')
})
}
this.closeAction()
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
closeAction () {
this.$emit('close-action')
}
}
}
</script>
<style scoped lang="scss">
.form {
width: 90vw;
@media (min-width: 800px) {
width: 45vw;
}
}
</style>

View File

@ -25,15 +25,16 @@
<a-table <a-table
:loading="loading" :loading="loading"
:columns="columns" :columns="columns"
:dataSource="tableSource" :dataSource="items"
:rowSelection="rowSelection" :rowSelection="rowSelection"
:customRow="onClickRow" :rowKey="item => item.name"
:pagination="false" :pagination="false"
size="middle" size="middle"
:scroll="{ y: 225 }" :scroll="{ y: 225 }" >
>
<template v-slot:account><a-icon type="user" /> {{ $t('label.account') }}</template> <template v-slot:account><a-icon type="user" /> {{ $t('label.account') }}</template>
<template v-slot:domain><a-icon type="block" /> {{ $t('label.domain') }}</template> <template v-slot:domain><a-icon type="block" /> {{ $t('label.domain') }}</template>
</a-table> </a-table>
<div style="display: block; text-align: right;"> <div style="display: block; text-align: right;">
<a-pagination <a-pagination
@ -67,8 +68,8 @@ export default {
default: () => 0 default: () => 0
}, },
value: { value: {
type: String, type: Array,
default: '' default: () => []
}, },
loading: { loading: {
type: Boolean, type: Boolean,
@ -103,8 +104,7 @@ export default {
width: '30%' width: '30%'
} }
], ],
selectedRowKeys: [this.$t('label.noselect')], selectedRowKeys: [],
dataItems: [],
oldZoneId: null, oldZoneId: null,
options: { options: {
page: 1, page: 1,
@ -114,64 +114,38 @@ export default {
} }
}, },
computed: { 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.name,
name: item.name,
account: item.account,
domain: item.domain
})
})
return dataItems
},
rowSelection () { rowSelection () {
return { return {
type: 'radio', type: 'checkbox',
selectedRowKeys: this.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) => {
onChange: this.onSelectRow this.$emit('select-ssh-key-pair-item', selectedRows)
}
} }
} }
}, },
watch: { watch: {
value (newValue, oldValue) { value (newValue, oldValue) {
if (newValue && newValue !== oldValue) { if (newValue && newValue !== oldValue) {
this.selectedRowKeys = [newValue] this.selectedRowKeys = newValue
} }
}, },
loading () { loading () {
if (!this.loading) { if (!this.loading) {
if (this.preFillContent.keypair) { if (this.preFillContent.keypairs) {
this.selectedRowKeys = [this.preFillContent.keypair] this.selectedRowKeys = this.preFillContent.keypairs
this.$emit('select-ssh-key-pair-item', this.preFillContent.keypair) this.$emit('select-ssh-key-pair-item', this.selectedRowKeys)
} else { } else {
if (this.oldZoneId === this.zoneId) { if (this.oldZoneId === this.zoneId) {
return return
} }
this.oldZoneId = this.zoneId this.oldZoneId = this.zoneId
this.selectedRowKeys = [this.$t('label.noselect')] this.selectedRowKeys = []
this.$emit('select-ssh-key-pair-item', this.$t('label.noselect')) this.$emit('select-ssh-key-pair-item', this.selectedRowKeys)
} }
} }
} }
}, },
methods: { methods: {
onSelectRow (value) {
this.selectedRowKeys = value
this.$emit('select-ssh-key-pair-item', value[0])
},
handleSearch (value) { handleSearch (value) {
this.filter = value this.filter = value
this.options.page = 1 this.options.page = 1
@ -188,16 +162,6 @@ export default {
this.options.page = page this.options.page = page
this.options.pageSize = pageSize this.options.pageSize = pageSize
this.$emit('handle-search-filter', this.options) this.$emit('handle-search-filter', this.options)
},
onClickRow (record) {
return {
on: {
click: () => {
this.selectedRowKeys = [record.key]
this.$emit('select-ssh-key-pair-item', record.key)
}
}
}
} }
} }
} }