Skip to content

Commit 85c5997

Browse files
davidjumanibicrxm
andauthored
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>
1 parent cb2ddc4 commit 85c5997

22 files changed

Lines changed: 378 additions & 177 deletions

File tree

api/src/main/java/com/cloud/vm/UserVmService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, E
215215
*/
216216
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
217217
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
218-
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
218+
String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
219219
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
220220
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
221221
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
@@ -297,7 +297,7 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
297297
*/
298298
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
299299
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
300-
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
300+
HTTPMethod httpmethod, String userData, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
301301
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
302302
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
303303
Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId) throws InsufficientCapacityException,
@@ -377,7 +377,7 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
377377
*/
378378
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
379379
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
380-
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
380+
List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
381381
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
382382
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String type, Long overrideDiskOfferingId)
383383

api/src/main/java/com/cloud/vm/VmDetailConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public interface VmDetailConstants {
5959
String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag";
6060
String DEPLOY_VM = "deployvm";
6161
String SSH_PUBLIC_KEY = "SSH.PublicKey";
62+
String SSH_KEY_PAIR_NAMES = "SSH.KeyPairNames";
6263
String PASSWORD = "password";
6364
String ENCRYPTED_PASSWORD = "Encrypted.Password";
6465

@@ -73,5 +74,6 @@ public interface VmDetailConstants {
7374
String DISK_OFFERING = "diskOffering";
7475

7576
String DEPLOY_AS_IS_CONFIGURATION = "configurationId";
77+
String KEY_PAIR_NAMES = "keypairnames";
7678
String CKS_CONTROL_NODE_LOGIN_USER = "controlNodeLoginUser";
7779
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ public class ApiConstants {
441441
public static final String NETWORKRATE = "networkrate";
442442
public static final String HOST_TAGS = "hosttags";
443443
public static final String SSH_KEYPAIR = "keypair";
444+
public static final String SSH_KEYPAIRS = "keypairs";
444445
public static final String HTTPMETHOD = "httpmethod";
445446
public static final String HOST_CPU_CAPACITY = "hostcpucapacity";
446447
public static final String HOST_CPU_NUM = "hostcpunum";

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,13 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
153153
length = 1048576)
154154
private String userData;
155155

156+
@Deprecated
156157
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "name of the ssh key pair used to login to the virtual machine")
157158
private String sshKeyPairName;
158159

160+
@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")
161+
private List<String> sshKeyPairNames;
162+
159163
@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")
160164
private Long hostId;
161165

@@ -444,8 +448,15 @@ public String getName() {
444448
return name;
445449
}
446450

447-
public String getSSHKeyPairName() {
448-
return sshKeyPairName;
451+
public List<String> getSSHKeyPairNames() {
452+
List<String> sshKeyPairs = new ArrayList<String>();
453+
if(sshKeyPairNames != null) {
454+
sshKeyPairs = sshKeyPairNames;
455+
}
456+
if(sshKeyPairName != null && !sshKeyPairName.isEmpty()) {
457+
sshKeyPairs.add(sshKeyPairName);
458+
}
459+
return sshKeyPairs;
449460
}
450461

451462
public Long getHostId() {

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ResetVMSSHKeyCmd.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
import com.cloud.uservm.UserVm;
4343
import com.cloud.vm.VirtualMachine;
4444

45+
import java.util.ArrayList;
46+
import java.util.List;
47+
4548
@APICommand(name = "resetSSHKeyForVirtualMachine", responseObject = UserVmResponse.class, description = "Resets the SSH Key for virtual machine. " +
4649
"The virtual machine must be in a \"Stopped\" state. [async]", responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
4750
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
@@ -58,8 +61,12 @@ public class ResetVMSSHKeyCmd extends BaseAsyncCmd implements UserCmd {
5861
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, required = true, description = "The ID of the virtual machine")
5962
private Long id;
6063

61-
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, required = true, description = "name of the ssh key pair used to login to the virtual machine")
62-
private String name;
64+
@Deprecated
65+
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING ,description = "name of the ssh key pair used to login to the virtual machine")
66+
String name;
67+
68+
@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")
69+
List<String> names;
6370

6471
//Owner information
6572
@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 {
7885
/////////////////// Accessors ///////////////////////
7986
/////////////////////////////////////////////////////
8087

81-
public String getName() {
82-
return name;
88+
public List<String> getNames() {
89+
List<String> keypairnames = new ArrayList<String>();
90+
if (names != null) {
91+
keypairnames = names;
92+
}
93+
if (name != null && !name.isEmpty()) {
94+
keypairnames.add(name);
95+
}
96+
return keypairnames;
8397
}
8498

8599
public Long getId() {

api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,9 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
280280
@Param(description = "List of read-only Vm details as comma separated string.", since = "4.16.0")
281281
private String readOnlyDetails;
282282

283-
@SerializedName(ApiConstants.SSH_KEYPAIR)
284-
@Param(description = "ssh key-pair")
285-
private String keyPairName;
283+
@SerializedName(ApiConstants.SSH_KEYPAIRS)
284+
@Param(description = "ssh key-pairs")
285+
private String keyPairNames;
286286

287287
@SerializedName("affinitygroup")
288288
@Param(description = "list of affinity groups associated with the virtual machine", responseObject = AffinityGroupResponse.class)
@@ -588,8 +588,8 @@ public String getInstanceName() {
588588
return instanceName;
589589
}
590590

591-
public String getKeyPairName() {
592-
return keyPairName;
591+
public String getKeyPairNames() {
592+
return keyPairNames;
593593
}
594594

595595
public Set<AffinityGroupResponse> getAffinityGroupList() {
@@ -848,8 +848,8 @@ public void setTags(Set<ResourceTagResponse> tags) {
848848
this.tags = tags;
849849
}
850850

851-
public void setKeyPairName(String keyPairName) {
852-
this.keyPairName = keyPairName;
851+
public void setKeyPairNames(String keyPairNames) {
852+
this.keyPairNames = keyPairNames;
853853
}
854854

855855
public void setAffinityGroupList(Set<AffinityGroupResponse> affinityGroups) {

engine/schema/src/main/java/com/cloud/user/dao/SSHKeyPairDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ public interface SSHKeyPairDao extends GenericDao<SSHKeyPairVO, Long> {
3737

3838
public SSHKeyPairVO findByPublicKey(long accountId, long domainId, String publicKey);
3939

40+
public List<SSHKeyPairVO> findByNames(long accountId, long domainId, List<String> names);
41+
4042
}

engine/schema/src/main/java/com/cloud/user/dao/SSHKeyPairDaoImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.List;
2020

2121

22+
import com.cloud.utils.db.Filter;
2223
import org.springframework.stereotype.Component;
2324

2425
import com.cloud.user.SSHKeyPairVO;
@@ -63,6 +64,16 @@ public SSHKeyPairVO findByName(long accountId, long domainId, String name) {
6364
return findOneBy(sc);
6465
}
6566

67+
@Override
68+
public List<SSHKeyPairVO> findByNames(long accountId, long domainId, List<String> names) {
69+
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();
70+
final Filter filter = new Filter(SSHKeyPairVO.class,"name",false, null, null);
71+
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
72+
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
73+
sc.addAnd("name", SearchCriteria.Op.IN, names.toArray());
74+
return this.search(sc, filter);
75+
}
76+
6677
@Override
6778
public SSHKeyPairVO findByPublicKey(String publicKey) {
6879
SearchCriteria<SSHKeyPairVO> sc = createSearchCriteria();

engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,7 @@ public Map<String, String> getDetails() {
488488

489489
public void setDetail(String name, String value) {
490490
assert (details != null) : "Did you forget to load the details?";
491-
492-
details.put(name, value);
491+
this.details.put(name, value);
493492
}
494493

495494
public void setDetails(Map<String, String> details) {

engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ SELECT
471471
`user_ip_address`.`id` AS `public_ip_id`,
472472
`user_ip_address`.`uuid` AS `public_ip_uuid`,
473473
`user_ip_address`.`public_ip_address` AS `public_ip_address`,
474-
`ssh_keypairs`.`keypair_name` AS `keypair_name`,
474+
`ssh_details`.`value` AS `keypair_names`,
475475
`resource_tags`.`id` AS `tag_id`,
476476
`resource_tags`.`uuid` AS `tag_uuid`,
477477
`resource_tags`.`key` AS `tag_key`,
@@ -495,7 +495,7 @@ SELECT
495495
`affinity_group`.`description` AS `affinity_group_description`,
496496
`vm_instance`.`dynamically_scalable` AS `dynamically_scalable`
497497
FROM
498-
(((((((((((((((((((((((((((((((((`user_vm`
498+
((((((((((((((((((((((((((((((((`user_vm`
499499
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
500500
AND ISNULL(`vm_instance`.`removed`))))
501501
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
@@ -524,9 +524,7 @@ FROM
524524
AND ISNULL(`vpc`.`removed`))))
525525
LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`)))
526526
LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`)
527-
AND (`ssh_details`.`name` = 'SSH.PublicKey'))))
528-
LEFT JOIN `ssh_keypairs` ON (((`ssh_keypairs`.`public_key` = `ssh_details`.`value`)
529-
AND (`ssh_keypairs`.`account_id` = `account`.`id`))))
527+
AND (`ssh_details`.`name` = 'SSH.KeyPairNames'))))
530528
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`)
531529
AND (`resource_tags`.`resource_type` = 'UserVm'))))
532530
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`)
@@ -646,3 +644,11 @@ CREATE VIEW `cloud`.`domain_router_view` AS
646644

647645
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;
648646
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;
647+
648+
INSERT INTO `cloud`.`user_vm_details`(`vm_id`, `name`, `value`)
649+
SELECT `user_vm_details`.`vm_id`, 'SSH.KeyPairNames', `ssh_keypairs`.`keypair_name`
650+
FROM `cloud`.`user_vm_details`
651+
INNER JOIN `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value
652+
INNER JOIN `cloud`.`vm_instance` ON vm_instance.id = user_vm_details.vm_id
653+
WHERE ssh_keypairs.account_id = vm_instance.account_id;
654+

0 commit comments

Comments
 (0)