comparison contrib/automation/hgautomation/aws.py @ 42278:8dc22a209420

automation: wait for instance profiles and roles Otherwise there is a race condition between creating the resources and us attempting to use them / them becoming available. The role waiter API was recently introduced, so we had to upgrade the boto3 package to get it. Other packages were also updated to latest versions just because. Even with this change, I still run into issues with the IAM instance profile not being available when we attempt to create an EC2 instance using a just-created profile. I'm not sure what's going on. Possibly a bug on Amazon's end. But the new behavior is "more correct." Differential Revision: https://phab.mercurial-scm.org/D6286
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 27 Apr 2019 11:38:58 -0700
parents dd6a9723ae2b
children e570106beda1
comparison
equal deleted inserted replaced
42277:dd6a9723ae2b 42278:8dc22a209420
194 self.security_groups = {} 194 self.security_groups = {}
195 195
196 if ensure_ec2_state: 196 if ensure_ec2_state:
197 ensure_key_pairs(automation.state_path, self.ec2resource) 197 ensure_key_pairs(automation.state_path, self.ec2resource)
198 self.security_groups = ensure_security_groups(self.ec2resource) 198 self.security_groups = ensure_security_groups(self.ec2resource)
199 ensure_iam_state(self.iamresource) 199 ensure_iam_state(self.iamclient, self.iamresource)
200 200
201 def key_pair_path_private(self, name): 201 def key_pair_path_private(self, name):
202 """Path to a key pair private key file.""" 202 """Path to a key pair private key file."""
203 return self.local_state_path / 'keys' / ('keypair-%s' % name) 203 return self.local_state_path / 'keys' / ('keypair-%s' % name)
204 204
323 323
324 print('deleting instance profile %s' % profile.name) 324 print('deleting instance profile %s' % profile.name)
325 profile.delete() 325 profile.delete()
326 326
327 327
328 def ensure_iam_state(iamresource, prefix='hg-'): 328 def ensure_iam_state(iamclient, iamresource, prefix='hg-'):
329 """Ensure IAM state is in sync with our canonical definition.""" 329 """Ensure IAM state is in sync with our canonical definition."""
330 330
331 remote_profiles = {} 331 remote_profiles = {}
332 332
333 for profile in iamresource.instance_profiles.all(): 333 for profile in iamresource.instance_profiles.all():
359 359
360 profile = iamresource.create_instance_profile( 360 profile = iamresource.create_instance_profile(
361 InstanceProfileName=actual) 361 InstanceProfileName=actual)
362 remote_profiles[name] = profile 362 remote_profiles[name] = profile
363 363
364 waiter = iamclient.get_waiter('instance_profile_exists')
365 waiter.wait(InstanceProfileName=actual)
366 print('IAM instance profile %s is available' % actual)
367
364 for name in sorted(set(IAM_ROLES) - set(remote_roles)): 368 for name in sorted(set(IAM_ROLES) - set(remote_roles)):
365 entry = IAM_ROLES[name] 369 entry = IAM_ROLES[name]
366 370
367 actual = '%s%s' % (prefix, name) 371 actual = '%s%s' % (prefix, name)
368 print('creating IAM role %s' % actual) 372 print('creating IAM role %s' % actual)
370 role = iamresource.create_role( 374 role = iamresource.create_role(
371 RoleName=actual, 375 RoleName=actual,
372 Description=entry['description'], 376 Description=entry['description'],
373 AssumeRolePolicyDocument=ASSUME_ROLE_POLICY_DOCUMENT, 377 AssumeRolePolicyDocument=ASSUME_ROLE_POLICY_DOCUMENT,
374 ) 378 )
379
380 waiter = iamclient.get_waiter('role_exists')
381 waiter.wait(RoleName=actual)
382 print('IAM role %s is available' % actual)
375 383
376 remote_roles[name] = role 384 remote_roles[name] = role
377 385
378 for arn in entry['policy_arns']: 386 for arn in entry['policy_arns']:
379 print('attaching policy %s to %s' % (arn, role.name)) 387 print('attaching policy %s to %s' % (arn, role.name))