Module onnawscfn.cfn
Expand source code
import boto3
from botocore.exceptions import ClientError
import sys
from pprint import pformat
class Cfn:
def __init__(self, logger, default_resource=None):
"""Description:
Convenience Python module for AWS CloudFormation
Args:
logger (onnlogger.Loggers): An instance of `onnlogger.Loggers`
Example:
Example usage:
from onnlogger import Loggers
logger = Loggers(logger_name='Orgs', console_logger=True, log_level='INFO', log_file_path='/tmp/log')
cfn = Cfn(logger)
"""
self.logger = logger
self.default_cfn_resource = default_resource if default_resource else boto3.resource('cloudformation')
def dict_to_cfn_params(self, dict_params) -> list:
"""Description:
Converts a `dict` to CloudFormation parameters
Args:
dict_params: Dictionary that needs to be converted to CloudFormation parameters
Example:
Example usage:
params = {
'AccountId': '123456789012',
'ExternalId': '098765432109',
}
cfn_params = cfn.dict_to_cfn_params(params)
pprint(cfn_params)
[{'ParameterKey': 'AccountId', 'ParameterValue': '123456789012'},
{'ParameterKey': 'ExternalId', 'ParameterValue': '098765432109'}]
Returns:
List of CloudFormation parameters
"""
self.logger.entry('info', f'Converting dict params to CloudFormation params...')
self.logger.entry('debug', f'Dict params:\n{pformat(dict_params)}')
cfn_params = []
for key, value in dict_params.items():
entry = {
'ParameterKey': key,
'ParameterValue': value,
}
cfn_params.append(entry)
self.logger.entry('debug', f'CloudFormation params:\n{pformat(cfn_params)}')
return cfn_params
def create_stack(self, cfn_resource=None, **cfn_settings):
"""Description:
Creates a CloudFormation stack
Args:
cfn_resource: `cloudformation` resource - used for assumed roles
cfn_settings (**kwargs): [`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) request parameters
Example:
Example usage:
params = {
'AccountId': account_id,
'ExternalId': org_id,
}
cfn_params = onn_cfn.dict_to_cfn_params(params)
result = onn_cfn.create_stack(StackName=STACK_NAME, TemplateURL=TEMPLATE_URL, Parameters=cfn_params, Capabilities=['CAPABILITY_NAMED_IAM'])
pprint(result)
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '385',
'content-type': 'text/xml',
'date': 'Fri, 27 Mar 2020 04:21:24 GMT',
'x-amzn-requestid': '457fg2347fd-2353-32g4-dfsk93jha1'},
'HTTPStatusCode': 200,
'RequestId': '457fg2347fd-2353-32g4-dfsk93jha1',
'RetryAttempts': 0},
'StackId': 'arn:aws:cloudformation:us-east-1:123456789012:stack/StackName/'457fg2347fd-2353-32g4-dfsk93jha1'}
Returns:
[`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) response or `False` if a template with this name already exists
"""
cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource
stack_name = cfn_settings['StackName']
self.logger.entry('info', f'Creating "{stack_name}" stack...')
try:
stack_details = cfn_resource.create_stack(**cfn_settings)
self.logger.entry('debug', f'Stack details:\n{pformat(stack_details)}')
return stack_details
except ClientError as e:
msg = e.response['Error']['Message']
if 'already exists' in msg:
self.logger.entry('info', f'Stack "{stack_name}" already exists')
return False
else:
self._aws_exception_msg(e)
def waiter(self, wait_for_status, stack_name, cfn_resource=None):
"""Description:
CloudFormation waiter
Args:
wait_for_status (str): Wait for status, e.g `stack_create_complete`
stack_name (str): Name of the CloudFormation stack
cfn_resource: (Optional) `cloudformation` resource - used for assumed roles
Example:
Example usage:
cfn.waiter(wait_for_status='stack_create_complete')
Returns:
None
"""
cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource
try:
waiter = cfn_resource.get_waiter(wait_for_status)
waiter.wait(StackName=stack_name)
except ClientError as e:
self._aws_exception_msg(e)
@staticmethod
def _aws_exception_msg(e):
msg = e.response['Error']['Message']
sys.exit(f'Error: {msg}')
def outputs_to_dict(self, cfn_outputs):
"""Description:
Converts a CloudFormation outputs to a `dict`
Args:
cfn_outputs (list): CFN outputs
Example:
Example usage:
cfn_outputs = cf_client.describe_stacks(StackName=STACK_NAME)['Stacks'][0]['Outputs']
dict_outputs = cfn.outputs_to_dict(cfn_outputs)
pprint(dict_outputs)
{'Hostname': 'TestHost',
'Version': '1.18'}
Returns:
CloudFormation outputs as a dictionary
"""
self.logger.entry('debug', 'Converting CloudFormation outputs to dict...')
self.logger.entry('debug', f'CloudFormation outputs:\n{pformat(cfn_outputs)}')
output = {}
for entry in cfn_outputs:
key = entry['OutputKey']
value = entry['OutputValue']
output[key] = value
self.logger.entry('debug', f'Dict outputs:\n{pformat(output)}')
return output
Classes
class Cfn (logger, default_resource=None)
-
Description
Convenience Python module for AWS CloudFormation
Args
logger
:onnlogger.Loggers
- An instance of
onnlogger.Loggers
Example
Example usage:
from onnlogger import Loggers logger = Loggers(logger_name='Orgs', console_logger=True, log_level='INFO', log_file_path='/tmp/log') cfn = Cfn(logger)
Expand source code
class Cfn: def __init__(self, logger, default_resource=None): """Description: Convenience Python module for AWS CloudFormation Args: logger (onnlogger.Loggers): An instance of `onnlogger.Loggers` Example: Example usage: from onnlogger import Loggers logger = Loggers(logger_name='Orgs', console_logger=True, log_level='INFO', log_file_path='/tmp/log') cfn = Cfn(logger) """ self.logger = logger self.default_cfn_resource = default_resource if default_resource else boto3.resource('cloudformation') def dict_to_cfn_params(self, dict_params) -> list: """Description: Converts a `dict` to CloudFormation parameters Args: dict_params: Dictionary that needs to be converted to CloudFormation parameters Example: Example usage: params = { 'AccountId': '123456789012', 'ExternalId': '098765432109', } cfn_params = cfn.dict_to_cfn_params(params) pprint(cfn_params) [{'ParameterKey': 'AccountId', 'ParameterValue': '123456789012'}, {'ParameterKey': 'ExternalId', 'ParameterValue': '098765432109'}] Returns: List of CloudFormation parameters """ self.logger.entry('info', f'Converting dict params to CloudFormation params...') self.logger.entry('debug', f'Dict params:\n{pformat(dict_params)}') cfn_params = [] for key, value in dict_params.items(): entry = { 'ParameterKey': key, 'ParameterValue': value, } cfn_params.append(entry) self.logger.entry('debug', f'CloudFormation params:\n{pformat(cfn_params)}') return cfn_params def create_stack(self, cfn_resource=None, **cfn_settings): """Description: Creates a CloudFormation stack Args: cfn_resource: `cloudformation` resource - used for assumed roles cfn_settings (**kwargs): [`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) request parameters Example: Example usage: params = { 'AccountId': account_id, 'ExternalId': org_id, } cfn_params = onn_cfn.dict_to_cfn_params(params) result = onn_cfn.create_stack(StackName=STACK_NAME, TemplateURL=TEMPLATE_URL, Parameters=cfn_params, Capabilities=['CAPABILITY_NAMED_IAM']) pprint(result) {'ResponseMetadata': {'HTTPHeaders': {'content-length': '385', 'content-type': 'text/xml', 'date': 'Fri, 27 Mar 2020 04:21:24 GMT', 'x-amzn-requestid': '457fg2347fd-2353-32g4-dfsk93jha1'}, 'HTTPStatusCode': 200, 'RequestId': '457fg2347fd-2353-32g4-dfsk93jha1', 'RetryAttempts': 0}, 'StackId': 'arn:aws:cloudformation:us-east-1:123456789012:stack/StackName/'457fg2347fd-2353-32g4-dfsk93jha1'} Returns: [`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) response or `False` if a template with this name already exists """ cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource stack_name = cfn_settings['StackName'] self.logger.entry('info', f'Creating "{stack_name}" stack...') try: stack_details = cfn_resource.create_stack(**cfn_settings) self.logger.entry('debug', f'Stack details:\n{pformat(stack_details)}') return stack_details except ClientError as e: msg = e.response['Error']['Message'] if 'already exists' in msg: self.logger.entry('info', f'Stack "{stack_name}" already exists') return False else: self._aws_exception_msg(e) def waiter(self, wait_for_status, stack_name, cfn_resource=None): """Description: CloudFormation waiter Args: wait_for_status (str): Wait for status, e.g `stack_create_complete` stack_name (str): Name of the CloudFormation stack cfn_resource: (Optional) `cloudformation` resource - used for assumed roles Example: Example usage: cfn.waiter(wait_for_status='stack_create_complete') Returns: None """ cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource try: waiter = cfn_resource.get_waiter(wait_for_status) waiter.wait(StackName=stack_name) except ClientError as e: self._aws_exception_msg(e) @staticmethod def _aws_exception_msg(e): msg = e.response['Error']['Message'] sys.exit(f'Error: {msg}') def outputs_to_dict(self, cfn_outputs): """Description: Converts a CloudFormation outputs to a `dict` Args: cfn_outputs (list): CFN outputs Example: Example usage: cfn_outputs = cf_client.describe_stacks(StackName=STACK_NAME)['Stacks'][0]['Outputs'] dict_outputs = cfn.outputs_to_dict(cfn_outputs) pprint(dict_outputs) {'Hostname': 'TestHost', 'Version': '1.18'} Returns: CloudFormation outputs as a dictionary """ self.logger.entry('debug', 'Converting CloudFormation outputs to dict...') self.logger.entry('debug', f'CloudFormation outputs:\n{pformat(cfn_outputs)}') output = {} for entry in cfn_outputs: key = entry['OutputKey'] value = entry['OutputValue'] output[key] = value self.logger.entry('debug', f'Dict outputs:\n{pformat(output)}') return output
Methods
def create_stack(self, cfn_resource=None, **cfn_settings)
-
Description
Creates a CloudFormation stack
Args
cfn_resource
cloudformation
resource - used for assumed roles
cfn_settings (**kwargs):
create_stack
request parametersExample
Example usage:
params = { 'AccountId': account_id, 'ExternalId': org_id, } cfn_params = onn_cfn.dict_to_cfn_params(params) result = onn_cfn.create_stack(StackName=STACK_NAME, TemplateURL=TEMPLATE_URL, Parameters=cfn_params, Capabilities=['CAPABILITY_NAMED_IAM']) pprint(result) {'ResponseMetadata': {'HTTPHeaders': {'content-length': '385', 'content-type': 'text/xml', 'date': 'Fri, 27 Mar 2020 04:21:24 GMT', 'x-amzn-requestid': '457fg2347fd-2353-32g4-dfsk93jha1'}, 'HTTPStatusCode': 200, 'RequestId': '457fg2347fd-2353-32g4-dfsk93jha1', 'RetryAttempts': 0}, 'StackId': 'arn:aws:cloudformation:us-east-1:123456789012:stack/StackName/'457fg2347fd-2353-32g4-dfsk93jha1'}
Returns
create_stack
response orFalse
if a template with this name already existsExpand source code
def create_stack(self, cfn_resource=None, **cfn_settings): """Description: Creates a CloudFormation stack Args: cfn_resource: `cloudformation` resource - used for assumed roles cfn_settings (**kwargs): [`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) request parameters Example: Example usage: params = { 'AccountId': account_id, 'ExternalId': org_id, } cfn_params = onn_cfn.dict_to_cfn_params(params) result = onn_cfn.create_stack(StackName=STACK_NAME, TemplateURL=TEMPLATE_URL, Parameters=cfn_params, Capabilities=['CAPABILITY_NAMED_IAM']) pprint(result) {'ResponseMetadata': {'HTTPHeaders': {'content-length': '385', 'content-type': 'text/xml', 'date': 'Fri, 27 Mar 2020 04:21:24 GMT', 'x-amzn-requestid': '457fg2347fd-2353-32g4-dfsk93jha1'}, 'HTTPStatusCode': 200, 'RequestId': '457fg2347fd-2353-32g4-dfsk93jha1', 'RetryAttempts': 0}, 'StackId': 'arn:aws:cloudformation:us-east-1:123456789012:stack/StackName/'457fg2347fd-2353-32g4-dfsk93jha1'} Returns: [`create_stack`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) response or `False` if a template with this name already exists """ cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource stack_name = cfn_settings['StackName'] self.logger.entry('info', f'Creating "{stack_name}" stack...') try: stack_details = cfn_resource.create_stack(**cfn_settings) self.logger.entry('debug', f'Stack details:\n{pformat(stack_details)}') return stack_details except ClientError as e: msg = e.response['Error']['Message'] if 'already exists' in msg: self.logger.entry('info', f'Stack "{stack_name}" already exists') return False else: self._aws_exception_msg(e)
def dict_to_cfn_params(self, dict_params)
-
Description
Converts a
dict
to CloudFormation parametersArgs
dict_params
- Dictionary that needs to be converted to CloudFormation parameters
Example
Example usage:
params = { 'AccountId': '123456789012', 'ExternalId': '098765432109', } cfn_params = cfn.dict_to_cfn_params(params) pprint(cfn_params) [{'ParameterKey': 'AccountId', 'ParameterValue': '123456789012'}, {'ParameterKey': 'ExternalId', 'ParameterValue': '098765432109'}]
Returns
List
ofCloudFormation
parameters
Expand source code
def dict_to_cfn_params(self, dict_params) -> list: """Description: Converts a `dict` to CloudFormation parameters Args: dict_params: Dictionary that needs to be converted to CloudFormation parameters Example: Example usage: params = { 'AccountId': '123456789012', 'ExternalId': '098765432109', } cfn_params = cfn.dict_to_cfn_params(params) pprint(cfn_params) [{'ParameterKey': 'AccountId', 'ParameterValue': '123456789012'}, {'ParameterKey': 'ExternalId', 'ParameterValue': '098765432109'}] Returns: List of CloudFormation parameters """ self.logger.entry('info', f'Converting dict params to CloudFormation params...') self.logger.entry('debug', f'Dict params:\n{pformat(dict_params)}') cfn_params = [] for key, value in dict_params.items(): entry = { 'ParameterKey': key, 'ParameterValue': value, } cfn_params.append(entry) self.logger.entry('debug', f'CloudFormation params:\n{pformat(cfn_params)}') return cfn_params
def outputs_to_dict(self, cfn_outputs)
-
Description
Converts a CloudFormation outputs to a
dict
Args
cfn_outputs
:list
- CFN outputs
Example
Example usage:
cfn_outputs = cf_client.describe_stacks(StackName=STACK_NAME)['Stacks'][0]['Outputs'] dict_outputs = cfn.outputs_to_dict(cfn_outputs) pprint(dict_outputs) {'Hostname': 'TestHost', 'Version': '1.18'}
Returns
CloudFormation
outputs
as
a
dictionary
Expand source code
def outputs_to_dict(self, cfn_outputs): """Description: Converts a CloudFormation outputs to a `dict` Args: cfn_outputs (list): CFN outputs Example: Example usage: cfn_outputs = cf_client.describe_stacks(StackName=STACK_NAME)['Stacks'][0]['Outputs'] dict_outputs = cfn.outputs_to_dict(cfn_outputs) pprint(dict_outputs) {'Hostname': 'TestHost', 'Version': '1.18'} Returns: CloudFormation outputs as a dictionary """ self.logger.entry('debug', 'Converting CloudFormation outputs to dict...') self.logger.entry('debug', f'CloudFormation outputs:\n{pformat(cfn_outputs)}') output = {} for entry in cfn_outputs: key = entry['OutputKey'] value = entry['OutputValue'] output[key] = value self.logger.entry('debug', f'Dict outputs:\n{pformat(output)}') return output
def waiter(self, wait_for_status, stack_name, cfn_resource=None)
-
Description
CloudFormation waiter
Args
wait_for_status
:str
- Wait for status, e.g
stack_create_complete
stack_name
:str
- Name of the CloudFormation stack
cfn_resource
- (Optional)
cloudformation
resource - used for assumed roles
Example
Example usage:
cfn.waiter(wait_for_status='stack_create_complete')
Returns
None
Expand source code
def waiter(self, wait_for_status, stack_name, cfn_resource=None): """Description: CloudFormation waiter Args: wait_for_status (str): Wait for status, e.g `stack_create_complete` stack_name (str): Name of the CloudFormation stack cfn_resource: (Optional) `cloudformation` resource - used for assumed roles Example: Example usage: cfn.waiter(wait_for_status='stack_create_complete') Returns: None """ cfn_resource = cfn_resource if cfn_resource else self.default_cfn_resource try: waiter = cfn_resource.get_waiter(wait_for_status) waiter.wait(StackName=stack_name) except ClientError as e: self._aws_exception_msg(e)