166166 - Name of the zone in which the instance should be deployed.
167167 type: str
168168 required: true
169- ssh_key :
169+ ssh_keys :
170170 description:
171- - Name of the SSH key to be deployed on the new instance.
172- type: str
171+ - List of names of SSH keys to be deployed on the new instance.
172+ type: list
173+ elements: str
174+ aliases: [ ssh_key ]
173175 affinity_groups:
174176 description:
175177 - Affinity groups names to be applied to the new instance.
336338 returned: if available
337339 type: str
338340 sample: Ge2oe7Do
339- ssh_key:
340- description: Name of SSH key deployed to instance.
341- returned: if available
342- type: str
343- sample: key@work
344341ssh_keys:
345342 description: Names of SSH key deployed to instance.
346343 returned: if available
@@ -467,7 +464,6 @@ def __init__(self, module):
467464 "isoname" : "iso" ,
468465 "templatename" : "template" ,
469466 "templatedisplaytext" : "template_display_text" ,
470- "keypair" : "ssh_key" ,
471467 "keypairs" : "ssh_keys" ,
472468 "hostname" : "host" ,
473469 }
@@ -587,9 +583,9 @@ def get_template_or_iso(self, key=None):
587583
588584 self .module .fail_json (msg = "ISO '%s' not found" % iso )
589585
590- def get_instance (self ):
586+ def get_instance (self , refresh = False ):
591587 instance = self .instance
592- if not instance :
588+ if not instance or refresh :
593589 instance_name = self .get_or_fallback ("name" , "display_name" )
594590 args = {
595591 "account" : self .get_account (key = "name" ),
@@ -602,8 +598,17 @@ def get_instance(self):
602598 if instances :
603599 for v in instances :
604600 if instance_name .lower () in [v ["name" ].lower (), v ["displayname" ].lower (), v ["id" ]]:
601+
602+ if "keypairs" not in v :
603+ v ["keypairs" ] = list ()
604+
605+ # Workaround for keypairs not a list
606+ if not isinstance (v ["keypairs" ], list ):
607+ v ["keypairs" ] = [v ["keypairs" ]]
608+
605609 self .instance = v
606610 break
611+
607612 return self .instance
608613
609614 def get_user_data_id_by_name (self ):
@@ -654,48 +659,45 @@ def get_iptonetwork_mappings(self):
654659 res .append (dict (networkid = ids [i ], ** data ))
655660 return res
656661
657- def get_ssh_keypair (self , key = None , name = None , fail_on_missing = True ):
658- ssh_key_name = name or self .module .params .get ("ssh_key" )
659- if ssh_key_name is None :
660- return
661-
662+ def get_ssh_keypair (self , name , key = None , fail_on_missing = True ):
662663 args = {
663664 "domainid" : self .get_domain ("id" ),
664665 "account" : self .get_account ("name" ),
665666 "projectid" : self .get_project ("id" ),
666- "name" : ssh_key_name ,
667+ "name" : name ,
667668 }
668669 ssh_key_pairs = self .query_api ("listSSHKeyPairs" , ** args )
669670 if "sshkeypair" in ssh_key_pairs :
670671 return self ._get_by_key (key = key , my_dict = ssh_key_pairs ["sshkeypair" ][0 ])
671672
672673 elif fail_on_missing :
673- self .module .fail_json (msg = "SSH key not found: %s" % ssh_key_name )
674+ self .module .fail_json (msg = "SSH key not found: %s" % name )
674675
675- def ssh_key_has_changed (self ):
676- ssh_key_name = self .module .params .get ("ssh_key " )
677- if ssh_key_name is None :
676+ def ssh_keys_changed (self ):
677+ ssh_keys = self .module .params .get ("ssh_keys " )
678+ if ssh_keys is None :
678679 return False
679680
680- # Fails if keypair for param is inexistent
681- param_ssh_key_fp = self .get_ssh_keypair (key = "fingerprint" )
681+ instance_ssh_keys = self .instance .get ("keypairs" ) or [self .instance .get ("keypair" ) or "" ]
682682
683- # CloudStack 4.5 does return keypair on instance for a non existent key.
684- instance_ssh_key_name = self .instance .get ("keypair" )
685- if instance_ssh_key_name is None :
686- return True
683+ param_ssh_key_fingerprints = [self .get_ssh_keypair (key = "fingerprint" , name = ssh_key ) for ssh_key in ssh_keys ]
687684
688- # Get fingerprint for keypair of instance but do not fail if inexistent.
689- instance_ssh_key_fp = self . get_ssh_keypair ( key = "fingerprint" , name = instance_ssh_key_name , fail_on_missing = False )
690- if not instance_ssh_key_fp :
691- return True
685+ for instance_ssh_key in instance_ssh_keys :
686+
687+ if not ssh_keys :
688+ return True
692689
693- # Compare fingerprints to ensure the keypair changed
694- if instance_ssh_key_fp != param_ssh_key_fp :
695- return True
690+ # Get fingerprint for keypair of instance but do not fail if inexistent.
691+ instance_ssh_key_fingerprint = self .get_ssh_keypair (key = "fingerprint" , name = instance_ssh_key , fail_on_missing = False )
692+ if not instance_ssh_key_fingerprint :
693+ return True
694+
695+ # Compare fingerprints to ensure the keypair changed
696+ if instance_ssh_key_fingerprint not in param_ssh_key_fingerprints :
697+ return True
696698 return False
697699
698- def security_groups_has_changed (self ):
700+ def security_groups_changed (self ):
699701 security_groups = self .module .params .get ("security_groups" )
700702 if security_groups is None :
701703 return False
@@ -758,6 +760,7 @@ def present_instance(self, start_vm=True):
758760
759761 # In check mode, we do not necessarily have an instance
760762 if instance :
763+ instance = self .get_instance (refresh = True )
761764 instance = self .ensure_tags (resource = instance , resource_type = "UserVm" )
762765 # refresh instance data
763766 self .instance = instance
@@ -820,7 +823,7 @@ def deploy_instance(self, start_vm=True):
820823 args ["name" ] = self .module .params .get ("name" )
821824 args ["displayname" ] = self .get_or_fallback ("display_name" , "name" )
822825 args ["group" ] = self .module .params .get ("group" )
823- args ["keypair " ] = self .get_ssh_keypair ( key = "name " )
826+ args ["keypairs " ] = self .module . params . get ( "ssh_keys " )
824827 args ["size" ] = self .module .params .get ("disk_size" )
825828 args ["startvm" ] = start_vm
826829 args ["rootdisksize" ] = self .module .params .get ("root_disk_size" )
@@ -870,9 +873,9 @@ def update_instance(self, instance, start_vm=True):
870873 args_instance_update ["displayname" ] = self .module .params .get ("display_name" )
871874 instance_changed = self .has_changed (args_instance_update , instance )
872875
873- ssh_key_changed = self .ssh_key_has_changed ()
876+ ssh_keys_changed = self .ssh_keys_changed ()
874877
875- security_groups_changed = self .security_groups_has_changed ()
878+ security_groups_changed = self .security_groups_changed ()
876879
877880 # Volume data
878881 args_volume_update = {}
@@ -905,7 +908,7 @@ def update_instance(self, instance, start_vm=True):
905908 service_offering_changed ,
906909 instance_changed ,
907910 security_groups_changed ,
908- ssh_key_changed ,
911+ ssh_keys_changed ,
909912 root_disk_size_changed ,
910913 ]
911914
@@ -936,12 +939,13 @@ def update_instance(self, instance, start_vm=True):
936939 self .instance = instance
937940
938941 # Reset SSH key
939- if ssh_key_changed :
942+ if ssh_keys_changed :
940943 # SSH key data
941- args_ssh_key = {}
942- args_ssh_key ["id" ] = instance ["id" ]
943- args_ssh_key ["projectid" ] = self .get_project (key = "id" )
944- args_ssh_key ["keypair" ] = self .module .params .get ("ssh_key" )
944+ args_ssh_key = {
945+ "id" : instance ["id" ],
946+ "projectid" : self .get_project (key = "id" ),
947+ "keypairs" : self .module .params .get ("ssh_keys" ),
948+ }
945949 instance = self .query_api ("resetSSHKeyForVirtualMachine" , ** args_ssh_key )
946950 instance = self .poll_job (instance , "virtualmachine" )
947951 self .instance = instance
@@ -1091,12 +1095,9 @@ def restore_instance(self):
10911095 return instance
10921096
10931097 def get_result (self , resource ):
1098+ resource = self .get_instance (refresh = True )
10941099 super (AnsibleCloudStackInstance , self ).get_result (resource )
10951100 if resource :
1096- # 4.18 does not return keypairs as list as doc claims
1097- if "ssh_keys" in self .result and not isinstance (self .result ["ssh_keys" ], list ):
1098- self .result ["ssh_keys" ] = [self .result ["ssh_keys" ]]
1099-
11001101 self .result ["user_data" ] = self ._get_instance_user_data (resource )
11011102 if "securitygroup" in resource :
11021103 security_groups = []
@@ -1158,7 +1159,7 @@ def main():
11581159 user_data_name = dict (),
11591160 user_data_details = dict (type = "dict" ),
11601161 zone = dict (required = True ),
1161- ssh_key = dict (no_log = False ),
1162+ ssh_keys = dict (type = "list" , elements = "str" , aliases = [ "ssh_key" ], no_log = False ),
11621163 force = dict (type = "bool" , default = False ),
11631164 tags = dict (type = "list" , elements = "dict" , aliases = ["tag" ]),
11641165 details = dict (type = "dict" ),
0 commit comments