def the_lot(self, skip_zip, skip_build, skip_upload): if skip_build: print(warn('Skipping building of lambdas')) else: self.do_work('build', self.build_one) if skip_zip: print(warn('Skipping zipping of lambdas')) else: self.do_work('zip', self.zip_one) if skip_upload: print(warn('Skipping uploading of lambdas')) print('using latest versions of zips currently in S3') lambdas = self.list_local_lambdas() with Pool(3) as p: versions_raw = p.map(self.latest_version, lambdas) versions = [{ 'name': lam, 'S3Version': v } for (lam, v) in zip(lambdas, versions_raw)] else: # check code bucket exists client = boto3.client('s3') response = client.list_buckets() buckets = [b['Name'] for b in response['Buckets']] if self.code_bucket not in buckets: print('Bucket %s does not exist, creating it now' % self.code_bucket) response = client.create_bucket(ACL='private', Bucket=self.code_bucket, CreateBucketConfiguration={ 'LocationConstraint': self.region }) print('Created bucket %s' % self.code_bucket) response = client.put_bucket_versioning( Bucket=self.code_bucket, VersioningConfiguration={ 'MFADelete': 'Disabled', 'Status': 'Enabled' }) print('Versioning turned on for bucket %s' % self.code_bucket) # list of {'name':x,'return_val':s3version} results = self.do_work('upload', self.upload_one) versions = [{ 'name': x['name'], 'S3Version': x['return_val'] } for x in results] assert (not any([x['S3Version'] == None for x in versions])) self.versions = versions
def test_lambdas(self, skip_test, stack_name): if skip_test: print(warn('Skipping testing of lambdas')) else: self.stack_name = stack_name self.do_work('test', self.test_one)
def deploy(self, lambda_versions): assert (not any([x['S3Version'] == None for x in lambda_versions])) self.lambda_versions = lambda_versions client = boto3.client('cloudformation') stack_name_short = 'stack' fname = os.path.join('data', 'cloudformation', '%s.yaml' % stack_name_short) if not os.path.isfile(fname): print(error('Error: I expect a yaml template at %s' % fname)) self.stack_name = self.project_name + '-' + self.stage print('About to deploy file %s as stack %s' % (fname, self.stack_name)) client = boto3.client('cloudformation') print('Checking template file %s' % fname) with open(fname, "rb") as f: response = client.validate_template( TemplateBody=f.read().decode("utf-8")) print(good('Template %s is valid' % fname)) params = [{ 'ParameterKey': 'prjName', 'ParameterValue': self.project_name }, { 'ParameterKey': 'codebucket', 'ParameterValue': self.code_bucket }, { 'ParameterKey': 'stage', 'ParameterValue': self.stage }] # versions of S3 zips version_params = [{'ParameterKey':'%sS3Version' % v['name'], \ 'ParameterValue':v['S3Version'] \ } \ for v in self.lambda_versions] assert (not any([x['ParameterValue'] == None for x in version_params])) params.extend(version_params) if any([x['ParameterValue'] == None for x in params]): print(error('Error: some parameters are None')) pp.pprint([ x['ParameterKey'] for x in params if x['ParameterValue'] == None ]) exit(1) if self.stack_exists(self.stack_name): # update stack print('Stack %s already exists. Updating it' % self.stack_name) change_set_name = 'update-%d' % int(time.time()) with open(fname, "rb") as f: print('Creating change set for %s' % self.stack_name) response = client.create_change_set( StackName=self.stack_name, TemplateBody=f.read().decode("utf-8"), Parameters=params, Capabilities=['CAPABILITY_NAMED_IAM'], ChangeSetName=change_set_name, Description='Update of %s' % fname, ChangeSetType='UPDATE') try: waiter = client.get_waiter('change_set_create_complete') waiter.wait(StackName=self.stack_name, ChangeSetName=change_set_name, WaiterConfig={ 'Delay': 10, 'MaxAttempts': 100 }) except Exception as e: response = client.describe_change_set( ChangeSetName=change_set_name, StackName=self.stack_name) pp.pprint(response) expected = 'The submitted information didn\'t contain changes.' if (response['Status'] == 'FAILED') and (expected in response['StatusReason']): print('No changes to make to stack %s' % self.stack_name) response = client.delete_change_set( ChangeSetName=change_set_name, StackName=self.stack_name) return () pp.pprint(e) print( err('Could not create change set %s for stack %s' % (change_set_name, self.stack_name))) raise (e) print( good('change set created sucessfully for %s' % self.stack_name)) print('Applying change set to stack %s' % self.stack_name) response = client.execute_change_set( ChangeSetName=change_set_name, StackName=self.stack_name, ) waiter = client.get_waiter('stack_update_complete') waiter.wait(StackName=self.stack_name, WaiterConfig={ 'Delay': 10, 'MaxAttempts': 100 }) print(good('Stack %s updated sucessfully' % self.stack_name)) else: print('Stack %s does not exist. Creating it' % self.stack_name) # create stack with open(fname, "rb") as f: response = client.create_stack( StackName=self.stack_name, TemplateBody=f.read().decode("utf-8"), Parameters=params, Capabilities=['CAPABILITY_NAMED_IAM']) stack_id = response['StackId'] waiter = client.get_waiter('stack_create_complete') waiter.wait(StackName=self.stack_name, WaiterConfig={ 'Delay': 10, 'MaxAttempts': 20 }) response = client.describe_stacks(StackName=self.stack_name) assert (len(response['Stacks']) == 1) assert (response['Stacks'][0]['StackName'] == self.stack_name) status = response['Stacks'][0]['StackStatus'] if status in ['CREATE_COMPLETE']: print(good('Stack %s sucessfully created' % self.stack_name)) else: print(error('Failed to create stack %s')) print(warn('status %s' % status)) print( 'Check cloudformation in the browser to see what went wrong' ) # TODO: add option to delete stack exit(1)