├── .gitignore ├── .travis.yml ├── Dockerfile ├── Dockerfile.Python3.test ├── Dockerfile.check ├── Dockerfile.coverage ├── Dockerfile.test ├── LICENSE ├── PyStacks ├── PyStacks │ ├── __init__.py │ ├── acm.py │ ├── acmtasks.py │ ├── apigateway.py │ ├── apitasks.py │ ├── auth.py │ ├── autoscaling.py │ ├── awsinputs.py │ ├── beanstalk.py │ ├── beanstalktasks.py │ ├── cloudformation.py │ ├── cloudformation_helpers.py │ ├── cloudformationtasks.py │ ├── configs.py │ ├── configtasks.py │ ├── database.py │ ├── ec2.py │ ├── ec2tasks.py │ ├── ecs.py │ ├── greengrass.py │ ├── greengrasstasks.py │ ├── iam.py │ ├── iot.py │ ├── kms.py │ ├── kmstasks.py │ ├── lambdaapi.py │ ├── lambdatasks.py │ ├── logger.py │ ├── organizations.py │ ├── organizationstasks.py │ ├── output.py │ ├── recordsets.py │ ├── rekognition.py │ ├── rekognitiontasks.py │ ├── route53.py │ ├── route53tasks.py │ ├── s3.py │ ├── s3tasks.py │ ├── serverless_tasks.py │ ├── tasks.py │ ├── template.py │ ├── test.py │ ├── verification.py │ └── zonefile.py ├── __init__.py ├── bin │ ├── get_pystacks_location.py │ └── pystacks ├── configs │ ├── cftemplates │ │ ├── mappings │ │ │ └── mappings.json │ │ ├── outputs │ │ │ ├── alb.json │ │ │ ├── apigateway.json │ │ │ ├── asg.json │ │ │ ├── asg_policy.json │ │ │ ├── asg_scheduledaction.json │ │ │ ├── athena_namedquery.json │ │ │ ├── certificatemanager.json │ │ │ ├── cloudfront.json │ │ │ ├── cloudtrail.json │ │ │ ├── cloudwatch.json │ │ │ ├── codecommit_repo.json │ │ │ ├── config_rule.json │ │ │ ├── dms_instance.json │ │ │ ├── dms_subnetgroup.json │ │ │ ├── dynamodb_tables.json │ │ │ ├── ebs_volume.json │ │ │ ├── ec2.json │ │ │ ├── ec2_flowlog.json │ │ │ ├── ec2_flowlogs.json │ │ │ ├── ec2_metadata.json │ │ │ ├── ecr.json │ │ │ ├── ecs.json │ │ │ ├── ecs_service.json │ │ │ ├── ecs_task_definition.json │ │ │ ├── efs.json │ │ │ ├── efs_filesystem.json │ │ │ ├── efs_mounttarget.json │ │ │ ├── efsmount.json │ │ │ ├── eip.json │ │ │ ├── elasticache.json │ │ │ ├── elasticachesubnet.json │ │ │ ├── elasticsearch.json │ │ │ ├── elb.json │ │ │ ├── events.json │ │ │ ├── iam_policies.json │ │ │ ├── iam_roles.json │ │ │ ├── iam_users.json │ │ │ ├── kinesis_firehose.json │ │ │ ├── kinesis_stream.json │ │ │ ├── kms.json │ │ │ ├── lambda.json │ │ │ ├── lambda_events.json │ │ │ ├── lambda_permissions.json │ │ │ ├── launch_configuration.json │ │ │ ├── logs_group.json │ │ │ ├── microsoftad.json │ │ │ ├── network_interface.json │ │ │ ├── nlb.json │ │ │ ├── rds.json │ │ │ ├── rdscluster.json │ │ │ ├── rdsclusterparamsgroup.json │ │ │ ├── rdsoptiongroup.json │ │ │ ├── rdsparamsgroup.json │ │ │ ├── rdssubnet.json │ │ │ ├── redshift.json │ │ │ ├── redshift_paramsgroup.json │ │ │ ├── redshift_subnetgroup.json │ │ │ ├── route53_record.json │ │ │ ├── route53_zone.json │ │ │ ├── s3.json │ │ │ ├── s3_policies.json │ │ │ ├── securitygroups.json │ │ │ ├── sns.json │ │ │ ├── snstopic.json │ │ │ ├── sqs.json │ │ │ ├── stepfunctions.json │ │ │ ├── stepfunctoins_activity.json │ │ │ └── vpc.json │ │ ├── params │ │ │ └── params.json │ │ └── resources │ │ │ ├── alb.json │ │ │ ├── apigateway.json │ │ │ ├── asg.json │ │ │ ├── asg_policy.json │ │ │ ├── asg_scheduledaction.json │ │ │ ├── athena_namedquery.json │ │ │ ├── certificatemanager.json │ │ │ ├── cloudfront.json │ │ │ ├── cloudtrail.json │ │ │ ├── cloudwatch.json │ │ │ ├── codecommit_repo.json │ │ │ ├── config_rule.json │ │ │ ├── dms_instance.json │ │ │ ├── dms_subnetgroup.json │ │ │ ├── dynamodb.json │ │ │ ├── dynamodb_tables.json │ │ │ ├── ebs_volume.json │ │ │ ├── ec2.json │ │ │ ├── ec2_flowlog.json │ │ │ ├── ec2_metadata.json │ │ │ ├── ecr.json │ │ │ ├── ecs.json │ │ │ ├── ecs_service.json │ │ │ ├── ecs_task_definition.json │ │ │ ├── efs.json │ │ │ ├── efs_filesystem.json │ │ │ ├── efs_mounttarget.json │ │ │ ├── efsmount.json │ │ │ ├── eip.json │ │ │ ├── elasticache.json │ │ │ ├── elasticachesubnet.json │ │ │ ├── elasticsearch.json │ │ │ ├── elb.json │ │ │ ├── events.json │ │ │ ├── iam_policies.json │ │ │ ├── iam_roles.json │ │ │ ├── iam_users.json │ │ │ ├── kinesis_firehose.json │ │ │ ├── kinesis_stream.json │ │ │ ├── kms.json │ │ │ ├── lambda.json │ │ │ ├── lambda_events.json │ │ │ ├── lambda_permissions.json │ │ │ ├── launch_configuration.json │ │ │ ├── logs_group.json │ │ │ ├── microsoftad.json │ │ │ ├── network_interface.json │ │ │ ├── nlb.json │ │ │ ├── rds.json │ │ │ ├── rdscluster.json │ │ │ ├── rdsclusterparamsgroup.json │ │ │ ├── rdsoptiongroup.json │ │ │ ├── rdsparamsgroup.json │ │ │ ├── rdssubnet.json │ │ │ ├── redshift.json │ │ │ ├── redshift_paramsgroup.json │ │ │ ├── redshift_subnetgroup.json │ │ │ ├── route53_record.json │ │ │ ├── route53_zone.json │ │ │ ├── s3.json │ │ │ ├── s3_policies.json │ │ │ ├── securitygroups.json │ │ │ ├── sns.json │ │ │ ├── snstopic.json │ │ │ ├── sqs.json │ │ │ ├── stepfunctions.json │ │ │ ├── stepfunctions_activity.json │ │ │ └── vpc.json │ └── user │ │ ├── dns │ │ ├── test.zone │ │ ├── test_blank.zone │ │ └── test_writezonezone │ │ ├── dns_test │ │ └── test_writezonezone │ │ └── region │ │ ├── aps2 │ │ ├── acm.yml │ │ ├── activedirectory.yml │ │ ├── alb.yml │ │ ├── apigateway.yml │ │ ├── dns_records.yml │ │ ├── ecs.yml │ │ ├── efs.yml │ │ ├── elasticache.yml │ │ ├── elasticachesubnet.yml │ │ ├── greengrass.yml │ │ ├── iam_policies.yml │ │ ├── iam_roles.yml │ │ ├── iam_users.yml │ │ ├── missing_stackname_test.yml │ │ ├── rds-subnetgroups.yml │ │ ├── rds.yml │ │ ├── redshift.yml │ │ ├── s3_lambda.yml │ │ ├── s3_policies.yml │ │ ├── securitygroups.yml │ │ ├── squidservers.yml │ │ ├── test_stack.yml │ │ └── vpc.yml │ │ └── global │ │ ├── test.zone │ │ └── test_parse.zone ├── contributors.txt ├── setup.py └── test │ ├── __init__.py │ ├── templates │ ├── __init__.py │ ├── test_acm.py │ ├── test_apigateway.py │ ├── test_athena_namedquery.py │ ├── test_cloudfront.py │ ├── test_cloudwatch.py │ ├── test_config_rule.py │ ├── test_dms.py │ ├── test_dynamodb_tables.py │ ├── test_efs.py │ ├── test_eip.py │ ├── test_elasticache.py │ ├── test_elasticsearch.py │ ├── test_elb.py │ ├── test_events.py │ ├── test_iam.py │ ├── test_kms.py │ ├── test_lambda.py │ ├── test_lambda_events.py │ ├── test_microsoftad.py │ ├── test_nlb.py │ ├── test_rds.py │ ├── test_redshift.py │ ├── test_route53.py │ ├── test_s3.py │ ├── test_securitygroups.py │ ├── test_sns.py │ ├── test_sqs.py │ └── test_vpc.py │ ├── test_cloudformation.py │ ├── test_cloudformation_helpers.py │ ├── test_configs.py │ ├── test_ec2tasks.py │ ├── test_greengrass.py │ ├── test_iot.py │ ├── test_organizationstasks.py │ ├── test_output.py │ ├── test_route53.py │ ├── test_route53tasks.py │ ├── test_template.py │ ├── test_verification.py │ └── test_zonefile.py ├── README.md ├── bin └── pystacks ├── bitbucket-pipelines.yml ├── build_local.sh ├── ci ├── build_deploy.sh ├── code_check.sh ├── code_coverage.sh ├── get_commit_json.sh ├── slack_alert.py ├── unit_test.sh └── version.txt ├── commit_check.sh ├── contributors.txt ├── makefile ├── pystacks.spdx ├── requirements.txt └── requirements_test.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | *egg-info/ 3 | build/ 4 | dist/ 5 | *.pyc 6 | PyStacks/configs/user/compiled/* 7 | credentials.yml 8 | .coverage 9 | coverage 10 | .DS_Store 11 | .idea/* 12 | .idea/ 13 | .vscode/ 14 | .vscode/* 15 | .hypothesis/ 16 | .hypothesis/* 17 | PyStacks/.cache/ 18 | PyStacks/.cache/* 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | script: pip install -r requirements_test.txt && pytest --pyargs PyStacks -s 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | ENV http_proxy ${http_proxy} 3 | ENV https_proxy ${https_proxy} 4 | 5 | RUN apk add --no-cache python && \ 6 | python -m ensurepip && \ 7 | rm -r /usr/lib/python*/ensurepip && \ 8 | pip install --upgrade pip setuptools && \ 9 | rm -r /root/.cache 10 | 11 | COPY ./requirements.txt /tmp/ 12 | RUN pip install -r /tmp/requirements.txt 13 | 14 | WORKDIR /opt/app 15 | COPY ./PyStacks /opt/app/ 16 | WORKDIR /opt/app/PyStacks 17 | ENTRYPOINT ["invoke"] 18 | -------------------------------------------------------------------------------- /Dockerfile.Python3.test: -------------------------------------------------------------------------------- 1 | FROM python:3.6.0-alpine 2 | ENV http_proxy ${http_proxy} 3 | ENV https_proxy ${https_proxy} 4 | 5 | RUN apk add --no-cache python && \ 6 | python -m ensurepip && \ 7 | rm -r /usr/lib/python*/ensurepip && \ 8 | pip install --upgrade pip setuptools && \ 9 | rm -r /root/.cache 10 | 11 | COPY ./requirements_test.txt /tmp/ 12 | RUN pip install -r /tmp/requirements_test.txt 13 | 14 | COPY ./ /opt/app/ 15 | WORKDIR /opt/app/ 16 | RUN sh ./ci/unit_test.sh -------------------------------------------------------------------------------- /Dockerfile.check: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | ENV http_proxy ${http_proxy} 3 | ENV https_proxy ${https_proxy} 4 | 5 | RUN apk add --no-cache python && \ 6 | python -m ensurepip && \ 7 | rm -r /usr/lib/python*/ensurepip && \ 8 | pip install --upgrade pip setuptools && \ 9 | rm -r /root/.cache 10 | 11 | COPY ./requirements_test.txt /tmp/ 12 | RUN pip install -r /tmp/requirements_test.txt 13 | 14 | COPY ./ /opt/app/ 15 | WORKDIR /opt/app/ 16 | RUN sh ./ci/code_check.sh -------------------------------------------------------------------------------- /Dockerfile.coverage: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | ENV http_proxy ${http_proxy} 3 | ENV https_proxy ${https_proxy} 4 | 5 | RUN apk add --no-cache python && \ 6 | python -m ensurepip && \ 7 | rm -r /usr/lib/python*/ensurepip && \ 8 | pip install --upgrade pip setuptools && \ 9 | rm -r /root/.cache 10 | 11 | COPY ./requirements_test.txt /tmp/ 12 | RUN pip install -r /tmp/requirements_test.txt 13 | 14 | COPY ./ /opt/app/ 15 | WORKDIR /opt/app/ 16 | RUN sh ./ci/code_coverage.sh -------------------------------------------------------------------------------- /Dockerfile.test: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | ENV http_proxy ${http_proxy} 3 | ENV https_proxy ${https_proxy} 4 | 5 | RUN apk add --no-cache python && \ 6 | python -m ensurepip && \ 7 | rm -r /usr/lib/python*/ensurepip && \ 8 | pip install --upgrade pip setuptools && \ 9 | rm -r /root/.cache 10 | 11 | COPY ./requirements_test.txt /tmp/ 12 | RUN pip install -r /tmp/requirements_test.txt 13 | 14 | COPY ./ /opt/app/ 15 | WORKDIR /opt/app/ 16 | 17 | 18 | RUN pytest --pyargs PyStacks -s -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Kablamo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KablamoOSS/PyStacks/001feefad093499face7918933fa0bba24a05c8c/PyStacks/PyStacks/__init__.py -------------------------------------------------------------------------------- /PyStacks/PyStacks/acm.py: -------------------------------------------------------------------------------- 1 | class acm: 2 | 3 | def __init__(self, session): 4 | self.acmClient = session.client('acm') 5 | 6 | def requestCertificate(self, domain, atlnames, token, domainoptions): 7 | self.acmClient.request_certificate( 8 | DomainName=domain, 9 | SubjectAlternativeNames=atlnames, 10 | IdempotencyToken=token, 11 | DomainValidationOptions=domainoptions 12 | ) 13 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/acmtasks.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | import acm 4 | from botocore.exceptions import ClientError 5 | 6 | 7 | class acmtasks: 8 | 9 | def __init__(self): 10 | pass 11 | 12 | def requestCert(self, domain, altnames, githash, certarn, domainoptions, session): 13 | api = acm.acm(session) 14 | try: 15 | api.request_certificate(domain=domain, atlnames=altnames, token=githash, domainoptions=domainoptions) 16 | except ClientError as err: 17 | logging.warn(err) 18 | sys.exit(1) 19 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/apigateway.py: -------------------------------------------------------------------------------- 1 | class apigateway: 2 | 3 | def __init__(self, session): 4 | self.apiClient = session.client('apigateway') 5 | 6 | def createCustomDomain(self, domain, certarn): 7 | self.apiClient.create_domain_name( 8 | domainName=domain, 9 | certificateArn=certarn 10 | ) 11 | 12 | def deleteCustomDomain(self, domain): 13 | self.apiClient.delete_domain_name( 14 | domainName=domain 15 | ) 16 | 17 | def getBasePathbyName(self, domain, basePath): 18 | self.apiClient.get_base_path_mapping( 19 | domainName=domain, 20 | basePath=basePath 21 | ) 22 | 23 | def getBasePaths(self, domain, position=None): 24 | self.apiClient.get_base_path_mappings( 25 | domainName=domain, 26 | position=position, 27 | limit=500 28 | ) 29 | 30 | def createStage(self, config): 31 | self.apiClient.create_stage( 32 | restApiId=config["restapiid"], 33 | stageName=config["stage"], 34 | deploymentId=config["deploymentid"], 35 | description=config["description"], 36 | cacheClusterEnabled=config["cacheclusterenabled"], 37 | cacheClusterSize=config["cachesize"], 38 | variables=config["variables"], 39 | documentationVersion=config["version"] 40 | ) 41 | 42 | def updateStage(self, domain, stage, patchoperations): 43 | self.apiClient.update_stage( 44 | domainName=domain, 45 | stage=stage, 46 | patchoperations=patchoperations 47 | ) 48 | 49 | def deleteStage(self, restapiid, stage): 50 | self.apiClient.update_stage( 51 | restApiId=restapiid, 52 | stageName=stage 53 | ) 54 | 55 | def createBasePathMapping(self, domain, basePath, restApiId, stage): 56 | self.apiClient.create_base_path_mapping( 57 | domainName=domain, 58 | basePath=basePath, 59 | restApiId=restApiId, 60 | stage=stage 61 | ) 62 | 63 | def updateBasePathMapping(self, domain, basepath, patchoperations): 64 | self.apiClient.update_base_path_mapping( 65 | domainName=domain, 66 | basePath=basepath, 67 | patchOperations=patchoperations 68 | ) 69 | 70 | def deleteBasePathMapping(self, domain, basePath): 71 | self.apiClient.delete_base_path_mapping( 72 | domainName=domain, 73 | basePath=basePath 74 | ) 75 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/auth.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | 4 | 5 | class authenticate: 6 | 7 | def __init__(self, region): 8 | self.stsClient = boto3.client('sts') 9 | self.assumedRole = os.environ.get('ASSUMED_ROLE') 10 | self.mfaSerial = os.environ.get('MFA_SERIAL') 11 | self.awsMfaToken = os.environ.get('TOKEN') 12 | self.awsRegion = region 13 | self.sess = None 14 | 15 | def getSession(self): 16 | if self.sess is None: 17 | self.sess = self.newSession() 18 | return self.sess 19 | 20 | def newSession(self): 21 | 22 | if self.assumedRole is not None: 23 | if self.mfaSerial is None: 24 | creds = self.stsClient.assume_role( 25 | RoleArn=self.assumedRole, 26 | RoleSessionName='ecs-deploy-session', 27 | DurationSeconds=3600 28 | ) 29 | else: 30 | creds = self.stsClient.assume_role( 31 | RoleArn=self.assumedRole, 32 | RoleSessionName='ecs-deploy-session', 33 | DurationSeconds=3600, 34 | SerialNumber=self.mfaSerial, 35 | TokenCode=self.awsMfaToken 36 | ) 37 | 38 | session = boto3.session.Session( 39 | aws_access_key_id=creds['Credentials']['AccessKeyId'], 40 | aws_secret_access_key=creds['Credentials']['SecretAccessKey'], 41 | aws_session_token=creds['Credentials']['SessionToken'], 42 | region_name=self.awsRegion 43 | ) 44 | else: 45 | session = boto3.session.Session( 46 | region_name=self.awsRegion 47 | ) 48 | return session 49 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/autoscaling.py: -------------------------------------------------------------------------------- 1 | class AutoScaling: 2 | 3 | def __init__(self, session): 4 | self.as_client = session.client('autoscaling') 5 | 6 | def get_instance_ids_from_auto_scaling_group(self, autoscaling_groups): 7 | instance_ids = [] 8 | 9 | asg_groups_response = self.as_client.describe_auto_scaling_groups(AutoScalingGroupNames=autoscaling_groups) 10 | 11 | for asg_group in asg_groups_response["AutoScalingGroups"]: 12 | instance_ids += [instance['InstanceId'] for instance in asg_group["Instances"]] 13 | return instance_ids 14 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/beanstalk.py: -------------------------------------------------------------------------------- 1 | 2 | class beanstalk: 3 | 4 | def __init__(self, session): 5 | self.bsClient = session.client('elasticbeanstalk') 6 | 7 | def createApplication(self, appname, description, resourcelifecycle): 8 | self.bsClient.create_application( 9 | ApplicationName=appname, 10 | Description=description, 11 | ResourceLifecycleConfig=resourcelifecycle 12 | ) 13 | 14 | def createApplicationVersion(self, appname, version, description, sourcebuild, buildconfig, autocreate=True, process=True): 15 | self.bsClient.create_application_version( 16 | ApplicationName=appname, 17 | VersionLabel=version, 18 | Description=description, 19 | SourceBuildInformation=sourcebuild, 20 | BuildConfiguration=buildconfig, 21 | AutoCreateApplication=autocreate, 22 | Process=process 23 | ) 24 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/beanstalktasks.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | import beanstalk 4 | import s3tasks 5 | from botocore.exceptions import ClientError 6 | 7 | 8 | class beanstalktasks: 9 | 10 | def __init__(self): 11 | pass 12 | 13 | def createApplication(self, session, config, logoutput=None): 14 | bs = beanstalk.beanstalk(session) 15 | try: 16 | bs.createApplication(appname=config["appname"], description=config["description"], resourcelifecycle=config["resourcelifecycle"]) 17 | except ClientError as err: 18 | print "Error setting Resolver to Delegation Set." 19 | logging.warn(err) 20 | sys.exit(1) 21 | 22 | def createApplicationVersion(self, session, config, logoutput=None): 23 | bs = beanstalk.beanstalk(session) 24 | if config["sourcebuld"]["Type"] == "S3": 25 | sourcebuild = self.SourceBuildInformationZip(session=session, config=config["sourcebuld"]) 26 | else: 27 | sourcebuild = self.SourceBuildInformationGit(config=config["sourcebuld"]) 28 | buildconfig = self.BuildConfiguration(config=config["BuildConfig"]) 29 | try: 30 | bs.createApplicationVersion(appname=config["appname"], version=config["version"], description=config["description"], sourcebuild=sourcebuild, buildconfig=buildconfig) 31 | except ClientError as err: 32 | print "Error setting Resolver to Delegation Set." 33 | logging.warn(err) 34 | sys.exit(1) 35 | 36 | def SourceBuildInformationZip(self, session, config): 37 | buildinfo = {} 38 | sourceinfo = [] 39 | sourceinfo["SourceType"] = "Zip" 40 | sourceinfo["SourceType"] = "S3" 41 | s3 = s3tasks.S3tasks() 42 | s3.uploadFile(session, config["filename"], config["bucket"], key=config["project"] + config["filename"]) 43 | response = s3.checkForFileV2(filename=config["filename"], bucket=config["bucket"]) 44 | if response: 45 | sourceinfo["SourceLocation"] = config["bucket"] + config["project"] + config["filename"] 46 | buildinfo.append(sourceinfo) 47 | 48 | return buildinfo 49 | 50 | def SourceBuildInformationGit(self, config): 51 | buildinfo = {} 52 | sourceinfo = [] 53 | sourceinfo["SourceType"] = "Git" 54 | sourceinfo["SourceType"] = "CodeCommit" 55 | sourceinfo["SourceLocation"] = config["projectname"] 56 | buildinfo.append(sourceinfo) 57 | 58 | return buildinfo 59 | 60 | def BuildConfiguration(self, config): 61 | buildconfig = {} 62 | configvar = [] 63 | configvar['CodeBuildServiceRole'] = config["BuildRole"] 64 | configvar['ComputeType'] = 'BUILD_GENERAL1_MEDIUM' 65 | configvar['Image'] = config["Image"] 66 | configvar['TimeoutInMinutes'] = 10 67 | buildconfig.append(configvar) 68 | 69 | return buildconfig 70 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/configs.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import os 3 | import jinja2 4 | import output 5 | import json 6 | 7 | 8 | def preprocess(env_path, conf_path, region, githash, environment, customParams): 9 | directory = os.path.dirname(__file__) 10 | envconfig = None 11 | 12 | with open(os.path.join(directory, env_path), 'r') as f: 13 | envconfig = yaml.safe_load(f) 14 | 15 | # Ensure the below items are dicts if not exists 16 | if '_default' not in envconfig.keys(): 17 | envconfig['_default'] = {} 18 | if environment not in envconfig.keys(): 19 | envconfig[environment] = {} 20 | 21 | if environment: 22 | context = dict(envconfig['_default'].items() + envconfig[environment].items()) # Append _default to env overwritting 23 | context['environment'] = environment 24 | else: 25 | context = envconfig['_default'] 26 | 27 | if githash: 28 | context['githash'] = githash 29 | 30 | context['region'] = region 31 | 32 | for key, value in customParams.iteritems(): 33 | context[key] = value 34 | 35 | with open(os.path.join(directory, conf_path), 'r') as f: 36 | jinja_template = jinja2.Template(f.read()) 37 | processed_yaml = jinja_template.render(context) 38 | config = yaml.safe_load(processed_yaml) 39 | 40 | return config 41 | 42 | 43 | def loadConfig(file_name, region, githash=None, environment=None, customConfig=None): 44 | directory = os.path.dirname(__file__) 45 | 46 | env_path = '../configs/user/region/{region}/environment.yml'.format(**locals()) 47 | conf_path = '../configs/user/region/{region}/{file_name}.yml'.format(**locals()) 48 | 49 | # Allow running inside a stack config dir without a docker container 50 | running_in_stack_directory = True 51 | conf_file = os.path.join(os.getcwd(), 'region/{region}/{file_name}.yml'.format(**locals())) 52 | if not os.path.exists(conf_file): # allow to continue as before 53 | conf_file = os.path.join(directory, conf_path) 54 | running_in_stack_directory = False 55 | 56 | customParams = {} 57 | if customConfig: 58 | try: 59 | customParams = json.loads(customConfig) 60 | except: 61 | print 'error parsing customConfig. Should be valid json' 62 | 63 | config = None 64 | # If running inside the stack directory, source the environment file locally. 65 | # If running from a docker container with configs mounted to `configs/user/...` 66 | if running_in_stack_directory and os.path.isfile(os.path.join(os.getcwd(), 'region/{region}/environment.yml'.format(**locals()))): 67 | config = preprocess(env_path, conf_path, region, githash, environment, customParams) 68 | elif not running_in_stack_directory and os.path.isfile(os.path.join(directory, env_path)): 69 | config = preprocess(env_path, conf_path, region, githash, environment, customParams) 70 | else: 71 | try: 72 | with open(conf_file, 'r') as f: 73 | config = yaml.safe_load(f) 74 | except IOError as err: 75 | print 76 | print output.piesay(text='The file {file_name} does not exist'.format(file_name=os.path.join(directory, conf_path))) 77 | print 78 | raise err 79 | 80 | if 'stackname' not in config: 81 | raise ValueError('Expected value "stackname" not in template ' + conf_path) 82 | 83 | return config 84 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/configtasks.py: -------------------------------------------------------------------------------- 1 | import configs 2 | import kmstasks 3 | import auth 4 | import json 5 | 6 | 7 | def getConfig(region, stack, githash=None, environment=None, customConfig=None): 8 | conf = configs.loadConfig(stack, region, githash, environment, customConfig) 9 | kmsclient = kmstasks.kmstasks() 10 | authentication = auth.authenticate(conf["region"]) 11 | session = authentication.getSession() 12 | if 'secrets' in conf: 13 | conf['secrets'] = kmsclient.decrypt_secrets(session, **conf['secrets']) 14 | for k, v in conf['secrets'].iteritems(): 15 | param = {'NoEcho': True, 'Description': k, 'Type': 'String', 'Default': v} 16 | conf['parameters'][k] = param 17 | return session, conf 18 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/ecs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import yaml 3 | from jinja2 import Environment, FileSystemLoader 4 | 5 | 6 | class task: 7 | def __init__(self, session): 8 | self.conf = loadServiceConfigs() 9 | self.ecsClient = session.client('ecs') 10 | 11 | def createContDef(self): 12 | '''Create Container Definition''' 13 | containers = [] 14 | for container in self.conf.task['container']: 15 | contDef = {} 16 | contDef.update((k, v) for k, v in self.conf.defaults.iteritems() if v is not None) 17 | contDef.update((k, v) for k, v in container.iteritems() if v is not None) 18 | containers.append(contDef) 19 | return containers 20 | 21 | def registerTaskDef(self, contDef, version): 22 | task = self.ecsClient.register_task_definition( 23 | family=self.conf.task["family"] + "-" + version, 24 | containerDefinitions=contDef, 25 | taskRoleArn=self.conf.task["taskRole"] if self.conf.task[ 26 | "taskRole"] is not None else "", 27 | volumes=self.conf.task['volumes'] 28 | ) 29 | return task['taskDefinition']['taskDefinitionArn'] 30 | 31 | 32 | class loadServiceConfigs: 33 | def __init__(self): 34 | self.task = self.loadFile("user/ecs/task") 35 | self.defaults = self.loadFile("ecs_defaults/defaults") 36 | self.deploy = self.loadFile("user/ecs/deploy") 37 | 38 | def loadFile(self, file): 39 | directory = os.path.dirname(__file__) 40 | f = open(os.path.join(directory, "../configs/" + file + ".yml")) 41 | config = yaml.safe_load(f) 42 | f.close() 43 | return config 44 | 45 | 46 | class loadClusterConfigs: 47 | def __init__(self): 48 | self.cluster = self.loadFile("user/cluster") 49 | 50 | def loadFile(self, file): 51 | directory = os.path.dirname(__file__) 52 | f = open(os.path.join(directory, "../configs/" + file + ".yml")) 53 | config = yaml.safe_load(f) 54 | f.close() 55 | return config 56 | 57 | 58 | def template_configs(**kwargs): 59 | directory = os.path.dirname(__file__) 60 | j2env = Environment(loader=FileSystemLoader(os.path.join(directory, "../configs/user/ecs")), trim_blocks=True) 61 | for f in os.listdir(os.path.join(directory, "../configs/user/ecs/")): 62 | templatized = j2env.get_template(f).render(kwargs) 63 | with open(os.path.join(directory, "../configs/user/ecs/" + f), "wb") as fh: 64 | fh.write(templatized) 65 | 66 | 67 | def template_service_cf(taskArn, **kwargs): 68 | directory = os.path.dirname(__file__) 69 | j2env = Environment(loader=FileSystemLoader(os.path.join(directory, "../configs/cftemplates/ecs/")), trim_blocks=True) 70 | f = "ecs_service.json" 71 | templatized = j2env.get_template(f).render(service=kwargs, TASK_ARN=taskArn) 72 | return templatized 73 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/iam.py: -------------------------------------------------------------------------------- 1 | class task: 2 | 3 | def __init__(self, session): 4 | # self.conf = configs.loadServiceConfigs() 5 | # self.ecsClient = session.client('ecs') 6 | pass 7 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/kms.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | 4 | class kms: 5 | def __init__(self, session): 6 | self.kmsClient = session.client('kms') 7 | 8 | def encrypt(self, secret, alias): 9 | ciphertext = self.kmsClient.encrypt( 10 | KeyId=alias, 11 | Plaintext=bytes(secret), 12 | ) 13 | return base64.b64encode(ciphertext["CiphertextBlob"]) 14 | 15 | def decrypt(self, secret): 16 | plaintext = self.kmsClient.decrypt( 17 | CiphertextBlob=bytes(base64.b64decode(secret)) 18 | ) 19 | return plaintext["Plaintext"] 20 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/kmstasks.py: -------------------------------------------------------------------------------- 1 | import kms 2 | 3 | 4 | class kmstasks: 5 | 6 | def __init__(self): 7 | pass 8 | 9 | def decrypt_secrets(self, session, **secrets): 10 | config = {} 11 | for k, v in secrets.iteritems(): 12 | vde = self.decrypt(session, v) 13 | config[k] = vde 14 | return config 15 | 16 | def decrypt(self, session, string): 17 | crypto = kms.kms(session) 18 | decrypted = crypto.decrypt(string) 19 | return decrypted 20 | 21 | def encrypt(self, string, session, key_alias): 22 | crypto = kms.kms(session) 23 | encrypted = crypto.encrypt(string, key_alias) 24 | print encrypted 25 | return encrypted 26 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/lambdaapi.py: -------------------------------------------------------------------------------- 1 | from verification import ensure_http_success 2 | 3 | 4 | class LambdaAPI(object): 5 | 6 | def __init__(self, session): 7 | self.client = session.client('lambda') 8 | 9 | @ensure_http_success 10 | def list_versions_by_function(self, function_name, **_): 11 | return self.client.list_versions_by_function( 12 | FunctionName=function_name, 13 | ) 14 | 15 | @ensure_http_success 16 | def list_aliases(self, function_name, **_): 17 | return self.client.list_aliases(FunctionName=function_name) 18 | 19 | @ensure_http_success 20 | def update_alias(self, function_name, alias_name, function_version, alias_desc=None, **_): 21 | params = { 22 | "FunctionName": function_name, 23 | "Name": alias_name, 24 | "FunctionVersion": function_version, 25 | "Description": alias_desc, 26 | } 27 | return self.client.update_alias(**{k: v for k, v in params.items() if v}) 28 | 29 | @ensure_http_success 30 | def create_alias(self, function_name, alias_name, function_version, alias_desc=None, **_): 31 | params = { 32 | "FunctionName": function_name, 33 | "Name": alias_name, 34 | "FunctionVersion": function_version, 35 | "Description": alias_desc, 36 | } 37 | return self.client.create_alias(**{k: v for k, v in params.items() if v}) 38 | 39 | @ensure_http_success 40 | def publish_version(self, function_name, latest_hash=None, version_desc=None, **_): 41 | params = { 42 | "FunctionName": function_name, 43 | "CodeSha256": latest_hash, # update_function_code_response['CodeSha256'], # Use to ensure matches $LATEST 44 | "Description": version_desc, 45 | } 46 | return self.client.publish_version(**{k: v for k, v in params.items() if v}) 47 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/lambdatasks.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | from lambdaapi import LambdaAPI 4 | from botocore.exceptions import ClientError 5 | 6 | from logger import get_pystacks_log 7 | log = get_pystacks_log() 8 | 9 | 10 | class lambdatasks: 11 | 12 | def __init__(self): 13 | pass 14 | 15 | def invokeLambda(self, function, payload, session): 16 | client = session.client('lambda') 17 | b = bytearray() 18 | b.extend(payload) 19 | try: 20 | client.invoke( 21 | FunctionName=function, 22 | Payload=b 23 | ) 24 | except ClientError as err: 25 | logging.warn(err) 26 | sys.exit(1) 27 | 28 | 29 | def upsert_alias(session, function_name, alias_name, alias_desc, function_version=None): 30 | lapi = LambdaAPI(session) 31 | 32 | # Publish a version from $LATEST. Assumes deployment made to lambda without version 33 | if not function_version: 34 | function_version = lapi.publish_version(function_name)['Version'] 35 | 36 | alias_exists = False 37 | for a in lapi.list_aliases(function_name)['Aliases']: 38 | if a['Name'] == alias_name: 39 | alias_exists = True 40 | break 41 | 42 | if alias_exists: 43 | log.info("alias exists. Updating ...") 44 | response = lapi.update_alias(**locals()) 45 | else: 46 | log.info("alias does not exist. Creating ...") 47 | response = lapi.create_alias(**locals()) 48 | 49 | log.info("Alias '{Name}' for: '{Description}' is setup: Function version {FunctionVersion} used for Alias ARN: {AliasArn}".format(**response)) 50 | return response 51 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class Logger: 5 | 6 | log = None 7 | 8 | @staticmethod 9 | def create_logger(): 10 | logger = logging.getLogger('pystacks') 11 | logger.setLevel(logging.DEBUG) 12 | 13 | # create file handler which logs even debug messages 14 | # fh = logging.FileHandler('pystacks.log') 15 | # fh.setLevel(logging.DEBUG) 16 | 17 | # create console handler 18 | ch = logging.StreamHandler() 19 | ch.setLevel(logging.DEBUG) 20 | 21 | # create formatter and add it to the handlers 22 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 23 | # fh.setFormatter(formatter) 24 | ch.setFormatter(formatter) 25 | 26 | # add the handlers to the log 27 | # logger.addHandler(fh) 28 | logger.addHandler(ch) 29 | 30 | # Do some logging 31 | logger.debug('Pystacks logger initialised') 32 | 33 | Logger.log = logger 34 | 35 | def __init__(self): 36 | if not Logger.log: 37 | Logger.create_logger() 38 | 39 | 40 | def get_pystacks_log(): 41 | logger = Logger() 42 | return logger.log 43 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/output.py: -------------------------------------------------------------------------------- 1 | formatters = { 2 | 'RED': '\033[91m', 3 | 'GREEN': '\033[92m', 4 | 'END': '\033[0m', 5 | } 6 | 7 | 8 | def boxwrap(text, linenumbers=True): 9 | '''Wraps text in a box''' 10 | response = '' 11 | text = text.encode('utf-8') 12 | 13 | split = text.splitlines() 14 | if len(split) == 0: 15 | return response 16 | 17 | total = max([len(x) for x in split]) 18 | if linenumbers: 19 | total += 7 20 | else: 21 | total += 3 22 | 23 | response = '+' + ('-' * total) + '+' + '\n' 24 | 25 | for index, line in enumerate(text.splitlines()): 26 | if linenumbers: 27 | newline = '| {index}. {line}'.format(index=index + 1, line=line) 28 | else: 29 | newline = '| {line}'.format(index=index + 1, line=line) 30 | 31 | if len(newline) < total: 32 | newline += ' ' * (total - len(newline) + 1) 33 | newline += '|' 34 | 35 | response += newline + '\n' 36 | 37 | response += '+' + ('-' * total) + '+' 38 | return response 39 | 40 | 41 | def writecolour(text, colour='RED'): 42 | response = '{' + colour + '}' + text + '{END}' 43 | response = response.format(**formatters) 44 | return response 45 | 46 | 47 | def whalesay(text): 48 | response = boxwrap(text=text, linenumbers=False) 49 | response += ''' 50 | \ 51 | \ == 52 | \ === 53 | /""""""""""""""""\___/ === 54 | { / 55 | \______ o __/ 56 | \ \ __/ 57 | \____\______/''' 58 | return response 59 | 60 | 61 | def piesay(text): 62 | response = boxwrap(text=text, linenumbers=False) 63 | response += ''' 64 | 65 | ( 66 | ) 67 | __..---..__ 68 | ,-=' / | \ `=-. 69 | :--..___________..--; 70 | \.,_____________,./ ''' 71 | return response 72 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/recordsets.py: -------------------------------------------------------------------------------- 1 | class recordsets(): 2 | 3 | def __init__(self, name, rectype, value, ttl): 4 | self.name = name 5 | self.rectype = rectype 6 | self.value = value 7 | self.ttl = ttl 8 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/rekognitiontasks.py: -------------------------------------------------------------------------------- 1 | 2 | class rekognitiontasks: 3 | 4 | def __init__(self): 5 | pass 6 | 7 | def buildImageObject(self, image, bucket, name, version=None): 8 | image_object = {} 9 | image_object["Bytes"] = image 10 | image_object["S3Object"] = self.builds3_object(bucket=bucket, name=name, version=version) 11 | 12 | return image_object 13 | 14 | def builds3_object(self, bucket, name, version=None): 15 | s3_object = {} 16 | s3_object["Bucket"] = bucket 17 | s3_object["Name"] = name 18 | if version: 19 | s3_object["Version"] = version 20 | 21 | return s3_object 22 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/route53.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pprint 3 | 4 | 5 | class route53: 6 | 7 | def __init__(self, session): 8 | self.dnsClient = session.client('route53') 9 | 10 | def waiterRecordSet(self, session, Id): 11 | waiter = self.dnsClient.get_waiter('resource_record_sets_changed') 12 | waiter.wait(Id=Id) 13 | 14 | def listRecords(self, zoneid, logging=None): 15 | recordset = [] 16 | response = self.dnsClient.list_resource_record_sets( 17 | HostedZoneId=zoneid) 18 | recordset.extend(response["ResourceRecordSets"]) 19 | while response["IsTruncated"]: 20 | response = self.dnsClient.list_resource_record_sets( 21 | HostedZoneId=zoneid, 22 | StartRecordName=response["NextRecordName"], 23 | StartRecordType=response["NextRecordType"]) 24 | recordset.extend(response["ResourceRecordSets"]) 25 | return recordset 26 | 27 | def getZoneID(self, zonename=None, logging=None): 28 | zoneids = [] 29 | response = self.dnsClient.list_hosted_zones() 30 | if logging == 'Full': 31 | pprint.pprint(response) 32 | zoneids.extend(response["HostedZones"]) 33 | while response["IsTruncated"]: 34 | response = self.dnsClient.list_hosted_zones( 35 | Marker=response["Marker"]) 36 | zoneids.extend(response["HostedZones"]) 37 | if logging: 38 | pprint.pprint(response) 39 | if zonename: 40 | for x in zoneids: 41 | if x["Name"] == zonename: 42 | return [x] 43 | else: 44 | return zoneids 45 | 46 | def getDelegationSets(self): 47 | response = self.dnsClient.list_reusable_delegation_sets() 48 | sets = response["DelegationSets"] 49 | print(json.dumps(sets)) 50 | return sets 51 | 52 | def getNameServers(self, setid): 53 | response = self.dnsClient.get_hosted_zone(Id=setid) 54 | return response["DelegationSet"]["NameServers"] 55 | 56 | def createDelegationSet(self, caller): 57 | self.dnsClient.create_reusable_delegation_set( 58 | CallerReference='string' 59 | ) 60 | 61 | def createZone(self, zonename, caller, setid): 62 | self.dnsClient.create_hosted_zone( 63 | Name=zonename, CallerReference=caller, HostedZoneConfig={'Comment': caller}, DelegationSetId=setid 64 | ) 65 | 66 | def createRecord(self, changebatch, hostzoneid, logging=None): 67 | if logging: 68 | pprint.pprint(changebatch) 69 | pprint.pprint(hostzoneid) 70 | self.dnsClient.change_resource_record_sets( 71 | HostedZoneId=hostzoneid, 72 | ChangeBatch=changebatch 73 | ) 74 | 75 | def createChangeBatch(self, batchset, action, comment, logging=None): 76 | changeset = {} 77 | if logging: 78 | pprint.pprint(batchset) 79 | recordset = json.loads(batchset) 80 | changeset["Comment"] = comment 81 | changeset["Changes"] = [] 82 | for x in recordset: 83 | temprec = {} 84 | temprec["Action"] = action 85 | temprec["ResourceRecordSet"] = x 86 | changeset["Changes"].append(temprec) 87 | 88 | if logging: 89 | pprint.pprint(changeset) 90 | return changeset 91 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/s3.py: -------------------------------------------------------------------------------- 1 | class S3: 2 | 3 | def __init__(self, session): 4 | self.client = session.client('s3') 5 | self.resource = session.resource('s3') 6 | 7 | def list_buckets(self): 8 | return self.client.list_buckets() 9 | 10 | def checkForFile(self, bucket, key): 11 | response = self.client.list_objects( 12 | Bucket=bucket, 13 | Delimiter=key, 14 | ) 15 | return response 16 | 17 | def uploadFile(self, filename, bucket, key): 18 | self.client.upload_file( 19 | Filename=filename, 20 | Bucket=bucket, 21 | Key=key 22 | ) 23 | 24 | def create_bucket(self, bucket, region): 25 | ret = self.client.create_bucket( 26 | ACL='private', 27 | Bucket=bucket, 28 | CreateBucketConfiguration={ 29 | 'LocationConstraint': region 30 | } 31 | ) 32 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/template.py: -------------------------------------------------------------------------------- 1 | '''template stuff''' 2 | import os 3 | import json 4 | import demjson 5 | import sys 6 | import output 7 | from jinja2 import Environment, FileSystemLoader 8 | 9 | 10 | def template(template, **kwargs): 11 | currentdirectory = os.path.dirname(__file__) 12 | 13 | templatedirectory = os.path.join( 14 | currentdirectory, '../configs/cftemplates/') 15 | jinjaenvironment = Environment( 16 | loader=FileSystemLoader(templatedirectory), trim_blocks=True) 17 | 18 | jinjatemplate = jinjaenvironment.get_template(template + '.json') 19 | mergedoutput = jinjatemplate.render(kwargs) 20 | 21 | return mergedoutput 22 | 23 | 24 | def getResources(**kwargs): 25 | stacks = [] 26 | for i in kwargs['resources']: 27 | stacks.append(i) 28 | return stacks 29 | 30 | 31 | def templateCF(resources, path): 32 | compiled = {} 33 | resconf = {} 34 | for resource in resources: 35 | resconf[resource] = resources[resource] 36 | cfres = (template(path + "/" + resource, **resconf)) 37 | try: 38 | compiled.update(demjson.decode(cfres)) 39 | except demjson.JSONError as err: 40 | print output.boxwrap(text=cfres) 41 | print output.writecolour(str(err)) 42 | print err.position 43 | sys.exit(1) 44 | 45 | return compiled 46 | 47 | 48 | def voltron(stack, **kwargs): 49 | ''' form up the cloudformation ''' 50 | conf = kwargs 51 | cf = {} 52 | cf['Description'] = conf['description'] 53 | cf['AWSTemplateFormatVersion'] = '2010-09-09' 54 | cf['Resources'] = templateCF(conf['resources'], 'resources') 55 | cf['Outputs'] = templateCF(conf['resources'], 'outputs') 56 | cf['Parameters'] = conf['parameters'] 57 | cf['Mappings'] = conf['mappings'] 58 | return cf 59 | 60 | 61 | def writecompiled(data, name, region, logoutput=None): 62 | 63 | # Allow for local running from a stacks directory 64 | local_compiled = os.path.join(os.getcwd(), 'compiled') 65 | if os.path.exists(local_compiled): 66 | filedirectory = local_compiled 67 | targetdirectory = os.path.join(local_compiled, '{region}'.format(region=region)) 68 | path = '{region}/{file}.json'.format(region=region, file=name) 69 | else: 70 | filedirectory = os.path.dirname(os.path.realpath(__file__)) 71 | targetdirectory = os.path.join( 72 | filedirectory, '../configs/user/compiled/{region}/'.format( 73 | region=region)) 74 | path = '../configs/user/compiled/{region}/{file}.json'.format( 75 | region=region, file=name) 76 | 77 | if not os.path.exists(targetdirectory): 78 | os.makedirs(targetdirectory) 79 | 80 | with open(os.path.join(filedirectory, path), "wb") as fh: 81 | fh.write(json.dumps(data, sort_keys=True, indent=4, separators=(',', ': '))) 82 | 83 | if logoutput: 84 | print json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')) 85 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/test.py: -------------------------------------------------------------------------------- 1 | # import tasks 2 | # from pprint import pprint 3 | 4 | # conf = tasks.getConfig('aps2', 'puppetdb-postgres-2016-4-2') 5 | # pprint(conf) 6 | 7 | pass 8 | -------------------------------------------------------------------------------- /PyStacks/PyStacks/verification.py: -------------------------------------------------------------------------------- 1 | def ensure_http_success(func): 2 | """May be used as a method decorator. Raises a RuntimeError if the input function does not return a 3 | successful HTTPStatusCode. KeyError input function is not a Boto3 API call. 4 | 5 | Args: 6 | func (func): This should be a boto3 API call. 7 | 8 | Returns: 9 | func 10 | """ 11 | def wrapper(*args, **kwargs): 12 | response = func(*args, **kwargs) 13 | if not 200 <= response['ResponseMetadata']['HTTPStatusCode'] < 300: 14 | raise RuntimeError("API call failed! :", response['ResponseMetadata']) 15 | return response 16 | return wrapper 17 | -------------------------------------------------------------------------------- /PyStacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KablamoOSS/PyStacks/001feefad093499face7918933fa0bba24a05c8c/PyStacks/__init__.py -------------------------------------------------------------------------------- /PyStacks/bin/get_pystacks_location.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import os 3 | import PyStacks 4 | 5 | install_dir = os.path.dirname(os.path.realpath(PyStacks.__file__)) 6 | print(install_dir) 7 | -------------------------------------------------------------------------------- /PyStacks/bin/pystacks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | export PYSTACKS_DIR=$(python ${SCRIPT_PATH}/get_pystacks_location.py) 6 | 7 | if [ -z ${PYSTACKS_DIR+x} ]; 8 | then 9 | echo "PyStacks module cannot be found. Exiting ..." 10 | exit 1 11 | else 12 | invoke -r ${PYSTACKS_DIR}/tasks.py $@; 13 | fi 14 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/mappings/mappings.json: -------------------------------------------------------------------------------- 1 | {% for map, mapkey in mappings.iteritems() %} 2 | "{{map}}": { 3 | "{{mapkey}}": { 4 | {% for k, v in mapkey.iteritems() %} 5 | "{{k}}":"{{v}}" 6 | {% if loop.index != loop.length %},{% endif %} 7 | {% endfor %} 8 | } 9 | {% if loop.index != loop.length %},{% endif %} 10 | } 11 | {% endfor %} 12 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/alb.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for alb, settings in alb.iteritems() %} 3 | "{{alb}}": { 4 | "Description": "{{alb}} Object", 5 | "Value": { "Ref": "{{alb}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-alb-{{alb}}" }} 7 | }, 8 | "{{alb}}dns": { 9 | "Description": "{{alb}} Object", 10 | "Value": { "Fn::GetAtt" : [ "{{alb}}", "DNSName" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-alb-{{alb}}-DNSName" }} 12 | } 13 | {% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | } 16 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/apigateway.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for apigateway, settings in apigateway.iteritems() %} 3 | "{{apigateway}}": { 4 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-API-{{apigateway}}" }}, 5 | "Value": { "Ref": "{{apigateway}}" }, 6 | "Description": "{{apigateway}} API gateway" 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/asg.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for asg, settings in asg.iteritems() %} 3 | "{{asg}}": { 4 | "Description": "{{asg}} Object", 5 | "Value": { "Ref": "{{asg}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ASG-{{asg}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/asg_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for policy, settings in asg_policy.iteritems() %} 3 | "{{policy}}": { 4 | "Description": "{{policy}} Object", 5 | "Value": { "Ref": "{{policy}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ASGPolicy-{{policy}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/asg_scheduledaction.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for asg_action, settings in asg_scheduledaction.iteritems() %} 3 | "{{asg_action}}": { 4 | "Description": "{{asg_action}} Scheduled Action", 5 | "Value": { "Ref": "{{asg_action}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ASG-ScheduledAction-{{asg_action}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/athena_namedquery.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for query, settings in athena_namedquery.iteritems() %} 3 | "{{query}}": { 4 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Athena-{{query}}-NamedQuery" }}, 5 | "Value": { "Ref": "{{query}}" }, 6 | "Description": "{{query}} Athena Named Query" 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/certificatemanager.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cert, settings in certificatemanager.iteritems() %} 3 | "{{cert}}": { 4 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ACM-{{cert}}" }}, 5 | "Value": { "Ref": "{{cert}}" }, 6 | "Description": "{{cert}} ACM Certificate" 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/cloudfront.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cfn, settings in cloudfront.iteritems() %} 3 | "{{cfn}}": { 4 | "Description": "{{cfn}} Object", 5 | "Value": { "Ref": "{{cfn}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-CFN-{{cfn}}" }} 7 | }, 8 | "{{cfn}}DomainName": { 9 | "Description": "{{cfn}} DNS", 10 | "Value": { "Fn::GetAtt" : [ "{{cfn}}", "DomainName" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-CFN-{{cfn}}-DomainName" }} 12 | } 13 | {% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/cloudtrail.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cloudtrail, settings in cloudtrail.iteritems() %} 3 | "{{cloudtrail}}": { 4 | "Description": "{{cloudtrail}} Object", 5 | "Value": { "Ref": "{{cloudtrail}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-CloudTrail-{{cloudtrail}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/cloudwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cw, settings in cloudwatch.iteritems() %} 3 | "{{cw}}": { 4 | "Description": "{{cw}} Object", 5 | "Value": { "Ref": "{{cw}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-cw-{{cw}}" }} 7 | }, 8 | "{{cw}}ARN": { 9 | "Description": "{{cw}} ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{cw}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Cloudwatch-{{cw}}-ARN" }} 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/codecommit_repo.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for repo, settings in codecommit_repo.iteritems() %} 3 | "{{repo}}": { 4 | "Description": "{{repo}} Object", 5 | "Value": { "Ref": "{{repo}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-REPO-{{repo}}" }} 7 | }, 8 | "{{repo}}Arn": { 9 | "Description": "{{repo}} DNS", 10 | "Value": { "Fn::GetAtt" : [ "{{repo}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-REPO-{{repo}}-Arn" }} 12 | }, 13 | "{{repo}}CloneUrlHttp": { 14 | "Description": "{{repo}} CloneUrlHttp", 15 | "Value": { "Fn::GetAtt" : [ "{{repo}}", "CloneUrlHttp" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-REPO-{{repo}}-CloneHTTP" }} 17 | }, 18 | "{{repo}}CloneUrlSsh": { 19 | "Description": "{{repo}} CloneUrlSsh", 20 | "Value": { "Fn::GetAtt" : [ "{{repo}}", "CloneUrlSsh" ] }, 21 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-REPO-{{repo}}-CloneUrlSsh" }} 22 | }, 23 | "{{repo}}Name": { 24 | "Description": "{{repo}} Name", 25 | "Value": { "Fn::GetAtt" : [ "{{repo}}", "Name" ] }, 26 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-REPO-{{repo}}-Name" }} 27 | }{% if not loop.last %},{% endif %} 28 | {% endfor %} 29 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/config_rule.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for config_rule, settings in config_rule.iteritems() %} 3 | "{{config_rule}}": { 4 | "Description": "{{config_rule}} Object", 5 | "Value": { "Ref": "{{config_rule}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ConfigRule-{{config_rule}}" }} 7 | }, 8 | "{{config_rule}}ARN": { 9 | "Description": "{{config_rule}} ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{config_rule}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ConfigRule-{{config_rule}}-ARN" }} 12 | }, 13 | "{{config_rule}}ConfigRuleId": { 14 | "Description": "{{config_rule}} ConfigRule ID", 15 | "Value": { "Fn::GetAtt" : [ "{{config_rule}}", "ConfigRuleId" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ConfigRule-{{config_rule}}-ConfigRuleId" }} 17 | }, 18 | "{{config_rule}}ComplianceType": { 19 | "Description": "{{config_rule}} Compliance Type", 20 | "Value": { "Fn::GetAtt" : [ "{{config_rule}}", "Compliance.Type" ] }, 21 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ConfigRule-{{config_rule}}-ComplianceType" }} 22 | }{% if not loop.last %},{% endif %} 23 | {% endfor %} 24 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/dms_instance.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for dms, settings in dms_instance.iteritems() %} 3 | "{{dms}}": { 4 | "Description": "{{dms}} DMS Instance", 5 | "Value": { "Ref": "{{dms}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-dmsinstance-{{dms}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/dms_subnetgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for dmssubnetgroup, settings in dms_subnetgroup.iteritems() %} 3 | "{{dmssubnetgroup}}": { 4 | "Description": "{{dmssubnetgroup}} DMS Subnet Group", 5 | "Value": { "Ref": "{{dmssubnetgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-dmsSubnetGroup-{{dmssubnetgroup}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/dynamodb_tables.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for table, settings in dynamodb_tables.iteritems() %} 3 | "{{table}}": { 4 | "Description": "{{table}} Dynamo DB Table", 5 | "Value": { "Ref": "{{table}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-dynamodb-{{table}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ebs_volume.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ebs, settings in ebs_volume.iteritems() %} 3 | "{{ebs}}": { 4 | "Description": "{{ebs}} Object", 5 | "Value": { "Ref": "{{ebs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ebs-{{ebs}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ec2.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ec2, settings in ec2.iteritems() %} 3 | "{{ec2|replace("-", "")|replace(".", "")}}": { 4 | "Description": "{{ec2}} Object", 5 | "Value": { "Ref": "{{ec2}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}" }} 7 | }, 8 | {% if settings["eip"] %} 9 | "{{ec2|replace("-", "")|replace(".", "")}}PublicIP": { 10 | "Description": "{{ec2}} Public IP", 11 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PublicIp" ] }, 12 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PublicIp" }} 13 | }, 14 | "{{ec2|replace("-", "")|replace(".", "")}}PublicDnsName": { 15 | "Description": "{{ec2}} Public DNS", 16 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PublicDnsName" ] }, 17 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PublicDnsName" }} 18 | }, 19 | {% endif %} 20 | "{{ec2|replace("-", "")|replace(".", "")}}PrivateIP": { 21 | "Description": "{{ec2}} Private IP", 22 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PrivateIp" ] }, 23 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PrivateIp" }} 24 | }, 25 | "{{ec2|replace("-", "")|replace(".", "")}}PrivateDnsName": { 26 | "Description": "{{ec2}} Private DNS", 27 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PrivateDnsName" ] }, 28 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PrivateDns" }} 29 | } 30 | {% if not loop.last %},{% endif %} 31 | {% endfor %} 32 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ec2_flowlog.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ec2_flowlog, settings in ec2_flowlog.iteritems() %} 3 | "{{ec2_flowlog}}": { 4 | "Description": "{{ec2_flowlog}} Object", 5 | "Value": { "Ref": "{{ec2_flowlog}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Flowlog-{{ec2_flowlog}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ec2_flowlogs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for c, settings in ec2_flowlog.iteritems() %} 3 | "{{ec2_flowlog}}": { 4 | "Description": "{{ec2_flowlog}} Object", 5 | "Value": { "Ref": "{{ec2_flowlog}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Flowlog-{{ec2_flowlog}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ec2_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ec2, settings in ec2.iteritems() %} 3 | "{{ec2|replace("-", "")|replace(".", "")}}": { 4 | "Description": "{{ec2}} Object", 5 | "Value": { "Ref": "{{ec2}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}" }} 7 | }, 8 | {% if settings["eip"] %} 9 | "{{ec2|replace("-", "")|replace(".", "")}}PublicIP": { 10 | "Description": "{{ec2}} Public IP", 11 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PublicIp" ] }, 12 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PublicIp" }} 13 | }, 14 | "{{ec2|replace("-", "")|replace(".", "")}}PublicDnsName": { 15 | "Description": "{{ec2}} Public DNS", 16 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PublicDnsName" ] }, 17 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PublicDnsName" }} 18 | }, 19 | {% endif %} 20 | "{{ec2|replace("-", "")|replace(".", "")}}PrivateIP": { 21 | "Description": "{{ec2}} Private IP", 22 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PrivateIp" ] }, 23 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PrivateIp" }} 24 | }, 25 | "{{ec2|replace("-", "")|replace(".", "")}}PrivateDnsName": { 26 | "Description": "{{ec2}} Private DNS", 27 | "Value": { "Fn::GetAtt" : [ "{{ec2}}", "PrivateDnsName" ] }, 28 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Instance-{{ec2}}-PrivateDns" }} 29 | } 30 | {% if not loop.last %},{% endif %} 31 | {% endfor %} 32 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ecr.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ecr_repo, settings in ecr.iteritems() %} 3 | "{{ecr_repo}}": { 4 | "Description": "{{ecr_repo}} Cluster", 5 | "Value": { "Ref": "{{ecr_repo}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ecr-repo-{{ecr_repo}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ecs, settings in ecs.iteritems() %} 3 | "{{ecs}}": { 4 | "Description": "{{ecs}} Cluster", 5 | "Value": { "Ref": "{{ecs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ECS-{{ecs}}" }} 7 | }, 8 | "{{ecs}}ARN": { 9 | "Description": "{{ecs}} Cluster ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{ecs}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ECS-{{ecs}}-ARN" }} 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ecs_service.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ecs_service, settings in ecs_service.iteritems() %} 3 | "{{ecs_service}}": { 4 | "Description": "{{ecs_service}} Object", 5 | "Value": { "Ref": "{{ecs_service}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ecs-service-{{ecs_service}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/ecs_task_definition.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for taskdef, settings in ecs_task_definition.iteritems() %} 3 | "{{taskdef}}": { 4 | "Description": "{{taskdef}} Object", 5 | "Value": { "Ref": "{{taskdef}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ecs-task-definition-{{taskdef}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/efs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efs, settings in efs.iteritems() %} 3 | "{{efs}}": { 4 | "Description": "{{efs}} Object", 5 | "Value": { "Ref": "{{efs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-EFS-{{efs}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/efs_filesystem.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efs, settings in efs_filesystem.iteritems() %} 3 | "{{efs}}": { 4 | "Description": "{{efs}} FileSystem", 5 | "Value": { "Ref": "{{efs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-EFS-{{efs}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } 10 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/efs_mounttarget.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efs, settings in efs_mounttarget.iteritems() %} 3 | "{{efs}}": { 4 | "Description": "{{efs}} Mount Target", 5 | "Value": { "Ref": "{{efs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-EFS-{{efs}}-Mounttarget" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } 10 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/efsmount.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efsmount, settings in efsmount.iteritems() %} 3 | "{{efsmount}}": { 4 | "Description": "{{efsmount}} Mount", 5 | "Value": { "Ref": "{{efsmount}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-EFSMount-{{efsmount}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/eip.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for eip in eip %} 3 | "{{eip}}": { 4 | "Description": "{{eip}}EIP", 5 | "Value": { "Ref" : "{{eip}}EIP" }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-EIP-{{eip}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/elasticache.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for elasticache, settings in elasticache.iteritems() %} 3 | "{{elasticache}}": { 4 | "Description": "{{elasticache}} ElastiCache ParamsGroup", 5 | "Value": { "Ref": "{{elasticache}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ElastiCache-{{elasticache}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/elasticachesubnet.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for elasticachesubnet, settings in elasticachesubnet.iteritems() %} 3 | "{{elasticachesubnet}}": { 4 | "Description": "{{elasticachesubnet}} ElastiCache ParamsGroup", 5 | "Value": { "Ref": "{{elasticachesubnet}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ElastiCache-{{elasticachesubnet}}-Subnet" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/elasticsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for es, settings in elasticsearch.iteritems() %} 3 | "{{es}}": { 4 | "Description": "{{es}}", 5 | "Value": { "Ref" : "{{es}}" }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ES-{{es}}" }} 7 | }, 8 | "{{es}}ARN": { 9 | "Description": "{{es}}-ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{es}}", "DomainArn"] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ES-ARN-{{es}}" }} 12 | }, 13 | "{{es}}EndPoint": { 14 | "Description": "{{es}}-EndPoint", 15 | "Value": { "Fn::GetAtt" : [ "{{es}}", "DomainEndpoint"] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ES-EndPoint-{{es}}" }} 17 | } 18 | {% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } 21 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/elb.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for elb, settings in elb.iteritems() %} 3 | "{{elb}}": { 4 | "Description": "{{elb}} Object", 5 | "Value": { "Ref": "{{elb}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ELB-{{elb}}" }} 7 | }, 8 | "{{elb}}DNSName": { 9 | "Description": "{{elb}} DNS Name", 10 | "Value": { "Fn::GetAtt" : [ "{{elb}}", "DNSName" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-ELB-{{elb}}-DNSName" }} 12 | } 13 | {% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/events.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for event, settings in events.iteritems() %} 3 | "{{event}}": { 4 | "Description": "{{event}} Object", 5 | "Value": { "Ref": "{{event}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Event-{{event}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/iam_policies.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/iam_roles.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for role in iam_roles["Roles"] %} 3 | "{{role}}": { 4 | "Description": "IAM Roles {{role}}", 5 | "Value": { "Ref": "{{role}}" }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-{{role}}" }} 7 | }, 8 | "{{role}}ARN": { 9 | "Description": "{{role}} ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{role}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Role-{{role}}-ARN" }} 12 | }, 13 | {% endfor %} 14 | {% if iam_roles["InstanceProfiles"] %} 15 | {% for profile in iam_roles["InstanceProfiles"] %} 16 | "{{profile}}": { 17 | "Description": "IAM Roles {{profile}}", 18 | "Value": { "Ref": "{{profile}}" }, 19 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-{{profile}}" }} 20 | }, 21 | "{{profile}}ARN": { 22 | "Description": "{{profile}} ARN", 23 | "Value": { "Fn::GetAtt" : [ "{{profile}}", "Arn" ] }, 24 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Role-{{profile}}-ARN" }} 25 | }, 26 | {% endfor %} 27 | {% endif %} 28 | } 29 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/iam_users.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for user in iam_users["Users"] %} 3 | "{{ user|replace("-", "")|replace(".", "") }}": { 4 | "Description": "IAM User {{user}}", 5 | "Value": { "Fn::GetAtt" : [ "{{ user|replace("-", "")|replace(".", "") }}", "Arn" ] }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-User-{{ user|replace("-", "")|replace(".", "") }}-ARN" }} 7 | }, 8 | {% endfor %} 9 | {% for group in iam_users["Groups"] %} 10 | "{{group}}": { 11 | "Description": "IAM Group {{group}}", 12 | "Value": { "Ref": "{{group}}" }, 13 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Group-{{group}}" }} 14 | }{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/kinesis_firehose.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for firehose, settings in kinesis_firehose.iteritems() %} 3 | "{{firehose}}": { 4 | "Description": "{{firehose}} Object", 5 | "Value": { "Ref": "{{firehose}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Firehose-{{firehose}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/kinesis_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for kinesis_stream, settings in kinesis_stream.iteritems() %} 3 | "{{kinesis_stream}}": { 4 | "Description": "{{kinesis_stream}} Arn", 5 | "Value": { "Fn::GetAtt" : [ "{{kinesis_stream}}", "Arn" ] }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-KinesisStream-{{kinesis_stream}}-Arn" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/kms.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for key, settings in kms.iteritems() %} 3 | "{{key}}": { 4 | "Description": "{{key}} Object", 5 | "Value": { "Ref": "{{key}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-KMS-{{key}}" }} 7 | }, 8 | "{{key}}ARN": { 9 | "Description": "{{key}} Private IP", 10 | "Value": { "Fn::GetAtt" : [ "{{key}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-KMS-{{key}}-ARN" }} 12 | }, 13 | "{{key}}Alias": { 14 | "Description": "{{key}} Alias", 15 | "Value": { "Ref": "{{key}}Alias"}, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-KMS-{{key}}-Alias" }} 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/lambda.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for lambda, settings in lambda.iteritems() %} 3 | "{{lambda}}": { 4 | "Description": "{{lambda}} Object", 5 | "Value": { "Ref": "{{lambda}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Lambda-{{lambda}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/lambda_events.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/lambda_permissions.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/launch_configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for lc, settings in launch_configuration.iteritems() %} 3 | "{{lc}}": { 4 | "Description": "{{lc}} Object", 5 | "Value": { "Ref": "{{lc}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-LaunchConfiguration-{{lc}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/logs_group.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for loggroup, settings in logs_group.iteritems() %} 3 | "{{loggroup}}": { 4 | "Description": "{{loggroup}} LogGroup", 5 | "Value": { "Ref": "{{loggroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-LogGroup-{{loggroup}}" }} 7 | }, 8 | "{{loggroup}}ARN": { 9 | "Description": "{{loggroup}} Arn", 10 | "Value": { "Fn::GetAtt" : [ "{{loggroup}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-LogGroup-{{loggroup}}-ARN" }} 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/microsoftad.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for microsoftad, settings in microsoftad.iteritems() %} 3 | "{{microsoftad}}": { 4 | "Description": "{{microsoftad}} Object", 5 | "Value": { "Ref": "{{microsoftad}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-MSAD-{{microsoftad}}" }} 7 | }, 8 | "{{microsoftad}}Alias": { 9 | "Description": "{{microsoftad}} Alias", 10 | "Value": { "Fn::GetAtt" : [ "{{microsoftad}}", "Alias" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-MSAD-{{microsoftad}}-Alias" }} 12 | }, 13 | "{{microsoftad}}DnsIpAddresses": { 14 | "Description": "{{microsoftad}} DNS IP Addresses", 15 | "Value": { "Fn::GetAtt" : [ "{{microsoftad}}", "DnsIpAddresses" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-MSAD-{{microsoftad}}-DNSIP" }} 17 | } 18 | {% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/network_interface.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for eni, settings in network_interface.iteritems() %} 3 | "{{eni}}": { 4 | "Description": "{{eni}} Object", 5 | "Value": { "Ref": "{{eni}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-eni-{{eni}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } 11 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/nlb.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for nlb, settings in nlb.iteritems() %} 3 | "{{nlb}}": { 4 | "Description": "{{nlb}} Object", 5 | "Value": { "Ref": "{{nlb}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-NLB-{{nlb}}" }} 7 | } 8 | {% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rds.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rds, settings in rds.iteritems() %} 3 | "{{rds}}": { 4 | "Description": "{{rds}} RDS", 5 | "Value": { "Ref": "{{rds}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rds}}" }} 7 | }, 8 | "{{rds}}EndPoint": { 9 | "Description": "{{rds}} Endpoint", 10 | "Value": { "Fn::GetAtt" : [ "{{rds}}", "Endpoint.Address" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rds}}-EndPoint" }} 12 | }, 13 | "{{rds}}Port": { 14 | "Description": "{{rds}} Port", 15 | "Value": { "Fn::GetAtt" : [ "{{rds}}", "Endpoint.Port" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rds}}-Port" }} 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rdscluster.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdscluster, settings in rdscluster.iteritems() %} 3 | "{{rdscluster}}": { 4 | "Description": "{{rrdsclusterds}} RDS", 5 | "Value": { "Ref": "{{rdscluster}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdscluster}}" }} 7 | }, 8 | "{{rdscluster}}EndPoint": { 9 | "Description": "{{rdscluster}} Endpoint", 10 | "Value": { "Fn::GetAtt" : [ "{{rdscluster}}", "Endpoint.Address" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdscluster}}-EndPoint" }} 12 | }, 13 | "{{rdscluster}}Port": { 14 | "Description": "{{rdscluster}} Port", 15 | "Value": { "Fn::GetAtt" : [ "{{rdscluster}}", "Endpoint.Port" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdscluster}}-Port" }} 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rdsclusterparamsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsclusterparamsgroup, settings in rdsclusterparamsgroup.iteritems() %} 3 | "{{rdsclusterparamsgroup}}": { 4 | "Description": "{{rdsclusterparamsgroup}} RDS ParamsGroup", 5 | "Value": { "Ref": "{{rdsclusterparamsgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdsclusterparamsgroup}}-ParamsGroup" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rdsoptiongroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsoptiongroup, settings in rdsoptiongroup.iteritems() %} 3 | "{{rdsoptiongroup}}": { 4 | "Description": "{{rdsoptiongroup}} RDS Options Group", 5 | "Value": { "Ref": "{{rdsoptiongroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdsoptiongroup}}-OptionGroup" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rdsparamsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsparamsgroup, settings in rdsparamsgroup.iteritems() %} 3 | "{{rdsparamsgroup}}": { 4 | "Description": "{{rdsparamsgroup}} RDS ParamsGroup", 5 | "Value": { "Ref": "{{rdsparamsgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdsparamsgroup}}-ParamsGroup" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/rdssubnet.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdssubnet, settings in rdssubnet.iteritems() %} 3 | "{{rdssubnet}}": { 4 | "Description": "{{rdssubnet}} RDS ParamsGroup", 5 | "Value": { "Ref": "{{rdssubnet}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RDS-{{rdssubnet}}-Subnet" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/redshift.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for redshift, settings in redshift.iteritems() %} 3 | "{{redshift}}": { 4 | "Description": "{{redshift}} Redshift Cluster", 5 | "Value": { "Ref": "{{redshift}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RS-{{redshift}}" }} 7 | }, 8 | "{{redshift}}EndPoint": { 9 | "Description": "{{redshift}} Endpoint", 10 | "Value": { "Fn::GetAtt" : [ "{{redshift}}", "Endpoint.Address" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RS-{{redshift}}-EndPoint" }} 12 | }, 13 | "{{redshift}}Port": { 14 | "Description": "{{redshift}} Port", 15 | "Value": { "Fn::GetAtt" : [ "{{redshift}}", "Endpoint.Port" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RS-{{redshift}}-Port" }} 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/redshift_paramsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for paramsgroup, settings in redshift_paramsgroup.iteritems() %} 3 | "{{paramsgroup}}": { 4 | "Description": "{{paramsgroup}} RS Parameters Group", 5 | "Value": { "Ref": "{{paramsgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RSParamGroup-{{paramsgroup}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/redshift_subnetgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for redshiftsubnetgroup, settings in redshift_subnetgroup.iteritems() %} 3 | "{{redshiftsubnetgroup}}": { 4 | "Description": "{{redshiftsubnetgroup}} Redshift Subnet Group", 5 | "Value": { "Ref": "{{redshiftsubnetgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RedshiftSubnetGroup-{{redshiftsubnetgroup}}" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/route53_record.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for record, settings in route53_record.iteritems() %} 3 | "{{record}}": { 4 | "Description": "{{record}} Zone", 5 | "Value": { "Ref": "{{record}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Route53-{{record}}-RecordSet" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/route53_zone.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for zone, settings in route53_zone.iteritems() %} 3 | "{{zone}}": { 4 | "Description": "{{zone}} Zone", 5 | "Value": { "Ref": "{{zone}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Route53-{{zone}}-Zone" }} 7 | }{% if not loop.last %},{% endif %} 8 | {% endfor %} 9 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/s3.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for s3, settings in s3.iteritems() %} 3 | "{{s3}}": { 4 | "Description": "{{s3}} Object", 5 | "Value": { "Ref": "{{s3}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-S3-{{s3}}" }} 7 | }, 8 | "{{s3}}ARN": { 9 | "Description": "{{s3}} ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{s3}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-S3-{{s3}}-ARN" }} 12 | }, 13 | {% if settings["website"] %} 14 | "{{s3}}WebsiteURL": { 15 | "Description": "{{s3}} Website URL", 16 | "Value": { "Fn::GetAtt" : [ "{{s3}}", "WebsiteURL" ] }, 17 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-S3-{{s3}}-WebsiteURL" }} 18 | }, 19 | {% endif %} 20 | "{{s3}}DomainName": { 21 | "Description": "{{s3}} Domain Name", 22 | "Value": { "Fn::GetAtt" : [ "{{s3}}", "DomainName" ] }, 23 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-S3-{{s3}}-DomainName" }} 24 | }{% if not loop.last %},{% endif %} 25 | {% endfor %} 26 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/s3_policies.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/securitygroups.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for secgroup, settings in securitygroups.iteritems() %} 3 | "{{secgroup}}": { 4 | "Description": "{{secgroup[sg_description]}} Object", 5 | "Value": { "Ref": "{{secgroup}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SecGroup-{{secgroup}}" }} 7 | } 8 | {% if loop.index != loop.length %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/sns.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for sns, settings in sns.iteritems() %} 3 | "{{sns}}": { 4 | "Description": "{{sns}} Object", 5 | "Value": { "Ref": "{{sns}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SNS-{{sns}}" }} 7 | }, 8 | "{{sns}}TopicName": { 9 | "Description": "{{sns}} TopicName", 10 | "Value": { "Fn::GetAtt" : [ "{{sns}}", "TopicName" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SNS-{{sns}}-TopicName" }} 12 | } 13 | {% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/snstopic.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/sqs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for sqs, settings in sqs.iteritems() %} 3 | "{{sqs}}": { 4 | "Description": "{{sqs}} Object", 5 | "Value": { "Ref": "{{sqs}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SQS-{{sqs}}" }} 7 | }, 8 | "{{sqs}}ARN": { 9 | "Description": "{{sqs}} ARN", 10 | "Value": { "Fn::GetAtt" : [ "{{sqs}}", "Arn" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SQS-{{sqs}}-ARN" }} 12 | }, 13 | "{{sqs}}QueueName": { 14 | "Description": "{{sqs}} Queue Name", 15 | "Value": { "Fn::GetAtt" : [ "{{sqs}}", "QueueName" ] }, 16 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SQS-{{sqs}}-QueueName" }} 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/stepfunctions.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for stepfunction, settings in stepfunctions.iteritems() %} 3 | "{{stepfunction}}": { 4 | "Description": "{{stepfunction}} Object", 5 | "Value": { "Ref": "{{stepfunction}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-StepFunction-{{stepfunction}}" }} 7 | }, 8 | "{{stepfunction}}dns": { 9 | "Description": "{{stepfunction}} Name", 10 | "Value": { "Fn::GetAtt" : [ "{{stepfunction}}", "Name" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-StepFunction-{{stepfunction}}-Name" }} 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/stepfunctoins_activity.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for step_activity, settings in stepfunctions_activity.iteritems() %} 3 | "{{step_activity}}": { 4 | "Description": "{{step_activity}} Object", 5 | "Value": { "Ref": "{{step_activity}}"}, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-StepFunction-{{step_activity}}-Activity" }} 7 | }, 8 | "{{step_activity}}dns": { 9 | "Description": "{{step_activity}} Name", 10 | "Value": { "Fn::GetAtt" : [ "{{step_activity}}", "Name" ] }, 11 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-StepFunction-{{step_activity}}-ActivityName" }} 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/outputs/vpc.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for subnet, settings in vpc["Subnets"].iteritems() %} 3 | "{{subnet}}": { 4 | "Description": "{{subnet}}", 5 | "Value": { "Ref" : "{{subnet}}" }, 6 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-Subnet-{{subnet}}" }} 7 | }, 8 | {% endfor %} 9 | {% for table, routename in vpc["Routetables"].iteritems() %} 10 | "{{table}}": { 11 | "Description": "{{table}}", 12 | "Value": { "Ref" : "{{table}}" }, 13 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-RouteTable-{{table}}" }} 14 | }, 15 | {% endfor %} 16 | "VPCid": { 17 | "Description": "{{vpc["Details"]["VPC_Name"]}}", 18 | "Value": { "Ref" : "{{vpc["Details"]["VPC_Name"]}}" }, 19 | "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-VPCid" }} 20 | } 21 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/params/params.json: -------------------------------------------------------------------------------- 1 | {% for param, settings in params.iteritems() %} 2 | "{{param}}": { 3 | "Description": "{{settings["description"]}}", 4 | "Type": "{{settings["type"]}}", 5 | {% if settings["noecho"] %} 6 | "NoEcho": "true", 7 | {% endif %} 8 | "Default": {{settings["value"]}} 9 | }{% if loop.index != loop.length %},{% endif %} 10 | {% endfor %} 11 | 12 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/asg_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for policy, settings in asg_policy.iteritems() %} 3 | "{{policy}}": { 4 | "Type" : "AWS::AutoScaling::ScalingPolicy", 5 | "Properties" : { 6 | {% if settings["adjustment_type"] %} 7 | "AdjustmentType" : "{{settings["adjustment_type"]}}", 8 | {% endif %} 9 | {% if settings["policy_type"] %} 10 | "PolicyType" : "{{settings["policy_type"]}}", 11 | {% endif %} 12 | {% if settings["cooldown"] %} 13 | "Cooldown" : "{{settings["cooldown"]}}", 14 | {% endif %} 15 | {% if settings["instance_warmup"] %} 16 | "EstimatedInstanceWarmup" : {{settings["instance_warmup"]}}, 17 | {% endif %} 18 | {% if settings["aggregation_type"] %} 19 | "MetricAggregationType" : "{{settings["aggregation_type"]}}", 20 | {% endif %} 21 | {% if settings["adjustment_magnitude"] %} 22 | "MinAdjustmentMagnitude" : {{settings["adjustment_magnitude"]}}, 23 | {% endif %} 24 | {% if settings["policy_type"] == "StepScaling" %} 25 | "StepAdjustments" : [ 26 | {% for step in settings["stepadjustments"] %} 27 | { 28 | "MetricIntervalLowerBound" : "{{step["lower"]}}", 29 | "MetricIntervalUpperBound" : "{{step["upper"]}}", 30 | "ScalingAdjustment" : {{step["adjustment"]}} 31 | } 32 | {% endfor %} 33 | ], 34 | {% elif settings["policy_type"] == "TargetTrackingScaling" %} 35 | "TargetTrackingConfiguration" : 36 | { 37 | {% if settings["targettracking"]["custom_metric"] %} 38 | "CustomizedMetricSpecification" : { 39 | "Dimensions" : [ 40 | {% for k, v in settings["targettracking"]["custom_metric"]["dimensions"].iteritems() %} 41 | {"Name": "{{ k }}", "Value": {"Ref": "{{v}}"}}{% if not loop.last %},{% endif %} 42 | {% endfor %} 43 | ], 44 | {% if settings["targettracking"]["custom_metric"]["unit"] %} 45 | "Unit" : "{{settings["targettracking"]["custom_metric"]["unit"]}}", 46 | {% endif %} 47 | "Namespace" : "{{settings["targettracking"]["custom_metric"]["namespace"]}}", 48 | "Statistic" : "{{settings["targettracking"]["custom_metric"]["statistic"]}}", 49 | "MetricName" : "{{settings["targettracking"]["custom_metric"]["metric_name"]}}" 50 | }, 51 | {% endif %} 52 | {% if settings["targettracking"]["disable_scalein"] %} 53 | "DisableScaleIn" : {{settings["targettracking"]["disable_scalein"]}}, 54 | {% endif %} 55 | {% if settings["targettracking"]["predefined_metric"] %} 56 | "PredefinedMetricSpecification" : { 57 | "PredefinedMetricType" : "{{settings["targettracking"]["predefined_metric"]["metric_type"]}}", 58 | "ResourceLabel" : "{{settings["targettracking"]["predefined_metric"]["label"]}}" 59 | }, 60 | {% endif %} 61 | "TargetValue" : "{{[settings["targettracking"]]}}" 62 | }, 63 | {% else %} 64 | "ScalingAdjustment" : {{settings["scaling_adjustment"]}}, 65 | {% endif %} 66 | "AutoScalingGroupName" : { "Ref": "{{settings["group_name"]}}" } 67 | } 68 | }{% if not loop.last %},{% endif %} 69 | {% endfor %} 70 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/asg_scheduledaction.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for asg_action, settings in asg_scheduledaction.iteritems() %} 3 | "{{asg_action}}": { 4 | "Type" : "AWS::AutoScaling::ScheduledAction", 5 | "Properties" : { 6 | {% if settings["desiredcapacity"] is not none %} 7 | "DesiredCapacity" : {{settings["desiredcapacity"]}}, 8 | {% endif %} 9 | {% if settings["endtime"] %} 10 | "EndTime" : "{{settings["endtime"]}}", 11 | {% endif %} 12 | {% if settings["maxsize"] is not none %} 13 | "MaxSize" : {{settings["maxsize"]}}, 14 | {% endif %} 15 | {% if settings["minsize"] is not none %} 16 | "MinSize" : {{settings["minsize"]}}, 17 | {% endif %} 18 | {% if settings["recurrence"] %} 19 | "Recurrence" : "{{settings["recurrence"]}}", 20 | {% endif %} 21 | {% if settings["starttime"] %} 22 | "StartTime" : "{{settings["starttime"]}}", 23 | {% endif %} 24 | "AutoScalingGroupName" : { 25 | "Ref" : "{{settings["autoscalinggroupname"]}}" 26 | } 27 | } 28 | }{% if not loop.last %},{% endif %} 29 | {% endfor %} 30 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/athena_namedquery.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for query, settings in athena_namedquery.iteritems() %} 3 | "{{query}}": { 4 | "Type" : "AWS::Athena::NamedQuery", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "QueryString" : "{{settings["querystring"]}}", 8 | "Database" : "{{settings["database"]}}", 9 | "Name" : "{{settings["name"]}}" 10 | } 11 | }{% if not loop.last %},{% endif %} 12 | {% endfor %} 13 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/certificatemanager.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cert, settings in certificatemanager.iteritems() %} 3 | "{{cert}}": { 4 | "Type" : "AWS::CertificateManager::Certificate", 5 | "Properties" : { 6 | {% if settings["domainvalidationoptions"] %} 7 | "DomainValidationOptions" : [ 8 | {% for domainname, validationdomain in settings["domainvalidationoptions"].iteritems() %} 9 | { 10 | "DomainName" : "{{domainname}}", 11 | "ValidationDomain" : "{{validationdomain}}" 12 | }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | ], 15 | {% endif %} 16 | {% if settings["subjectalternativenames"] %} 17 | "SubjectAlternativeNames" : [ 18 | {% for san in settings["subjectalternativenames"] %} 19 | "{{san}}"{% if not loop.last %},{% endif %} 20 | {% endfor %} 21 | ], 22 | {% endif %} 23 | {% if settings["tags"] %} 24 | "Tags" : [ 25 | {% for k, v in settings["tags"].iteritems() %} 26 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 27 | {% endfor %} 28 | ], 29 | {% endif %} 30 | "DomainName" : "{{settings["domainname"]}}" 31 | } 32 | }{% if not loop.last %},{% endif %} 33 | {% endfor %} 34 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/cloudtrail.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cloudtrail, settings in cloudtrail.iteritems() %} 3 | "{{cloudtrail}}": { 4 | "Type" : "AWS::CloudTrail::Trail", 5 | "Properties" : { 6 | {% if settings["cloudwatch"]["loggroup"] and settings["cloudwatch"]["rolearn"] %} 7 | "CloudWatchLogsLogGroupArn" : { "Fn::ImportValue" : {"Fn::Sub" : ["${LogGroupsStack}-LogGroup-{{settings["cloudwatch"]["loggroup"]}}-ARN", {"LogGroupsStack": {"Ref": "LogGroupsStack"}}] }}, 8 | "CloudWatchLogsRoleArn" : { "Fn::ImportValue" : {"Fn::Sub" : ["${RoleStack}-SecGroup-{{settings["cloudwatch"]["rolearn"]}}", {"RoleStack": {"Ref": "RoleStack"}}] }}, 9 | {% endif %} 10 | {% if settings["filevalidation"] %} 11 | "EnableLogFileValidation" : {{settings["filevalidation"]}}, 12 | {% endif %} 13 | {% if settings["globalevents"] %} 14 | "IncludeGlobalServiceEvents" : {{settings["globalevents"]}}, 15 | {% endif %} 16 | "IsLogging" : {{settings["islogging"]}}, 17 | {% if settings["multiregion"] %} 18 | "IsMultiRegionTrail" : {{settings["multiregion"]}}, 19 | {% endif %} 20 | {% if settings["kmskey"] %} 21 | "KMSKeyId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${KMSStack}-KMS-{{settings["kmskey"]}}-ARN", {"KMSStack": {"Ref": "KMSStack"}}] }}, 22 | {% endif %} 23 | "S3BucketName" : {{settings["s3"]["name"]}}, 24 | {% if settings["S3"]["prefix"] %} 25 | "S3KeyPrefix" : {{settings["s3"]["prefix"]}}, 26 | {% endif %} 27 | {% if settings["sns"] %} 28 | "SnsTopicName" : { "Fn::ImportValue" : {"Fn::Sub" : ["${SNSStack}-SNS-{{settings["sns"]}}", {"SNSStack": {"Ref": "SNSStack"}}] }}, 29 | {% endif %} 30 | "Tags" : [ 31 | {% for k, v in settings["tags"].iteritems() %} 32 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 33 | {% endfor %} 34 | ], 35 | "TrailName" : {{settings["trailname"]}} 36 | } 37 | } 38 | {% endfor %} 39 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/cloudwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for cloudwatch, settings in cloudwatch.iteritems() %} 3 | "{{cloudwatch}}": { 4 | "Type" : "AWS::CloudWatch::Alarm", 5 | "Properties" : { 6 | {% if settings['actionsenabled'] %} 7 | "ActionsEnabled" : "{{settings['actionsenabled']|lower}}", 8 | {% endif %} 9 | {% if settings['alarmactions'] %} 10 | "AlarmActions" : [ 11 | {% for actions in settings['alarmactions'] %} 12 | {"Ref": "{{actions}}" }{% if not loop.last %},{% endif %} 13 | {% endfor %} 14 | ], 15 | {% endif %} 16 | {% if settings['alarmdescription'] %} 17 | "AlarmDescription" : "{{settings['alarmdescription']}}", 18 | {% endif %} 19 | {% if settings['alarmname'] %} 20 | "AlarmName" : "{{settings['alarmname']}}", 21 | {% endif %} 22 | "ComparisonOperator" : "{{settings['comparisonoperator']}}", 23 | {% if settings['dimensions'] %} 24 | "Dimensions" : [ 25 | {% for k, v in settings['dimensions'].iteritems() %} 26 | { 27 | "Name" : "{{ k }}", 28 | "Value" : "{{ v }}" 29 | }{% if not loop.last %},{% endif %} 30 | {% endfor %} 31 | ], 32 | {% endif %} 33 | "EvaluationPeriods" : "{{settings['evalationperiods']}}", 34 | {% if settings['insufficientdataactions'] %} 35 | "InsufficientDataActions" : [ 36 | {% for actions in settings['insufficientdataactions'] %} 37 | "{{actions}}"{% if not loop.last %},{% endif %} 38 | {% endfor %} 39 | ], 40 | {% endif %} 41 | "MetricName" : "{{settings['metricname']}}", 42 | "Namespace" : "{{settings['namespace']}}", 43 | {% if settings['okactions'] %} 44 | "OKActions" : [ 45 | {% for actions in settings['okactions'] %} 46 | "{{actions}}"{% if not loop.last %},{% endif %} 47 | {% endfor %} 48 | ], 49 | {% endif %} 50 | "Period" : "{{settings['period']}}", 51 | "Statistic" : "{{settings['statistic']}}", 52 | "Threshold" : "{{settings['threshold']}}" 53 | {% if settings['unit'] %} 54 | ,"Unit" : "{{settings['unit']}}" 55 | {% endif %} 56 | } 57 | }{% if not loop.last %},{% endif %} 58 | {% endfor %} 59 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/codecommit_repo.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for repo, settings in codecommit_repo.iteritems() %} 3 | "{{repo}}": { 4 | "Type" : "AWS::CodeCommit::Repository", 5 | "Properties" : { 6 | {% if settings["description"] %} 7 | "RepositoryDescription" : "{{settings["description"]}}", 8 | {% endif %} 9 | "RepositoryName" : "{{settings["name"]}}", 10 | {% if settings["triggers"] %} 11 | "Triggers" : [ 12 | {% for trigger in settings["triggers"].iteritems() %} 13 | { 14 | {% if trigger["branches"] %} 15 | "Branches" : [ 16 | {% for branch in trigger["branches"] %} 17 | "{{branch}}"{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | ], 20 | {% endif %} 21 | {% if trigger["customdata"] %} 22 | "CustomData" : "{{trigger["customdata"]}}", 23 | {% endif %} 24 | "DestinationArn" : "{{trigger["destinationarn"]}}", 25 | {% if trigger["events"] %} 26 | "Events" : [ 27 | {% for event in trigger["events"] %} 28 | "{{event}}"{% if not loop.last %},{% endif %} 29 | {% endfor %} 30 | ], 31 | {% endif %} 32 | "Name" : "{{trigger["name"]}}" 33 | }{% if not loop.last %},{% endif %} 34 | {% endfor %} 35 | ] 36 | {% endif %} 37 | } 38 | }{% if not loop.last %},{% endif %} 39 | {% endfor %} 40 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/config_rule.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for config_rule, settings in config_rule.iteritems() %} 3 | "{{config_rule}}": { 4 | "Type" : "AWS::Config::ConfigRule", 5 | "Properties" : { 6 | "ConfigRuleName" : "{{settings["name"]}}", 7 | {% if settings["description"] %} 8 | "Description" : "{{settings["description"]}}", 9 | {% endif %} 10 | {% if settings["inputparams"] %} 11 | "InputParameters" : { 12 | {% for k, v in settings["inputparams"].iteritems() %} 13 | "{{ k }}" : 14 | {% if v is iterable %} 15 | {{v}} 16 | {% else %} 17 | "{{v}}" 18 | {% endif %} 19 | {% if not loop.last %},{% endif %} 20 | {% endfor %} 21 | }, 22 | {% endif %} 23 | {% if settings["maxfrequency"] %} 24 | "MaximumExecutionFrequency" : "{{settings["maxfrequency"]}}", 25 | {% endif %} 26 | {% if settings["scope"] %} 27 | "Scope" : { 28 | {% if settings["scope"]["resourceid"] and settings["scope"]["resourcetype"] %} 29 | "ComplianceResourceId" : "{{settings["scope"]["resourceid"]}}", 30 | "ComplianceResourceTypes" : [ 31 | {% for resourcetype in settings["scope"]["resourcetype"] %} 32 | "{{resourcetype}}"{% if not loop.last %},{% endif %} 33 | ], 34 | {% endfor %} 35 | {% endif %} 36 | {% if settings["scope"]["tagkey"] and settings["scope"]["tagvalue"] %} 37 | "TagKey" : "{{settings["scope"]["tagkey"]}}", 38 | "TagValue" : "{{settings["scope"]["tagvalue"]}}" 39 | }, 40 | {% endif %} 41 | {% endif %} 42 | "Source" : { 43 | "Owner" : "{{settings["source"]["owner"]}}", 44 | {% if settings["source"]["details"] %} 45 | "SourceDetails" : [ 46 | {% for source, source_settings in settings["source"]["details"].iteritems() %} 47 | { 48 | "EventSource" : "{{source}}", 49 | {% if source_settings["frequency"] %} 50 | "MaximumExecutionFrequency" : "{{source_settings["frequency"]}}", 51 | {% endif %} 52 | "MessageType" : "{{source_settings["messagetype"]}}" 53 | }{% if not loop.last %},{% endif %} 54 | {% endfor %} 55 | ], 56 | {% endif %} 57 | "SourceIdentifier" : "{{settings["source"]["sourceid"]}}", 58 | } 59 | } 60 | } 61 | {% endfor %} 62 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/dms_instance.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for dms, settings in dms_instance.iteritems() %} 3 | "{{dms|replace("-", "")|replace(".", "")}}Instance": { 4 | {% if settings["dependsOn"] %} 5 | "DependsOn" : [ 6 | {% for v in settings["dependsOn"] %} 7 | "{{ v }}", 8 | {% endfor %} 9 | ], 10 | {% endif %} 11 | "Type" : "AWS::DMS::ReplicationInstance", 12 | "Properties" : { 13 | {% if settings["allocatedstorage"] %} 14 | "AllocatedStorage" : "{{ settings["allocatedstorage"] }}", 15 | {% endif %} 16 | {% if settings["autominorversionupgrade"] %} 17 | "AutoMinorVersionUpgrade" : "{{ settings["autominorversionupgrade"]|lower }}", 18 | {% endif %} 19 | {% if settings["az"] %} 20 | "AvailabilityZone" : "{{ settings["az"] }}", 21 | {% endif %} 22 | {% if settings["engineversion"] %} 23 | "EngineVersion" : "{{ settings["engineversion"] }}", 24 | {% endif %} 25 | {% if settings["kmskeyid"] %} 26 | "KmsKeyId" : "{{ settings["kmskeyid"] }}", 27 | {% endif %} 28 | {% if settings["multiaz"] %} 29 | "MultiAZ" : "{{ settings["multiaz"]|lower }}", 30 | {% endif %} 31 | {% if settings["preferredmaintenancewindow"] %} 32 | "PreferredMaintenanceWindow" : "{{ settings["preferredmaintenancewindow"] }}", 33 | {% endif %} 34 | {% if settings["publiclyaccessible"] %} 35 | "PubliclyAccessible" : "{{ settings["publiclyaccessible"]|lower }}", 36 | {% endif %} 37 | {% if settings["replicationinstanceid"] %} 38 | "ReplicationInstanceIdentifier" : "{{ settings["replicationinstanceid"] }}", 39 | {% endif %} 40 | {% if settings["replicationsubnetgroupid"] %} 41 | "ReplicationSubnetGroupIdentifier" : "{{ settings["replicationsubnetgroupid"] }}", 42 | {% endif %} 43 | {% if settings["tags"] %} 44 | "Tags" : [ 45 | {% for k, v in settings["tags"].iteritems() %} 46 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 47 | {% endfor %} 48 | ],{% endif %} 49 | {% if settings["securitygroupid"] %} 50 | "VpcSecurityGroupIds" : [{ "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{settings["securitygroupid"]}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}], 51 | {% endif %} 52 | "ReplicationInstanceClass" : "{{ settings["replicationinstanceclass"] }}" 53 | } 54 | } 55 | {% if not loop.last %},{% endif %} 56 | {% endfor %} 57 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/dms_subnetgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for dmssubnet, settings in dms_subnetgroup.iteritems() %} 3 | "{{dmssubnet}}": { 4 | "Type" : "AWS::DMS::ReplicationSubnetGroup", 5 | "Properties" : { 6 | "ReplicationSubnetGroupIdentifier": "{{dmssubnet}}", 7 | "ReplicationSubnetGroupDescription": "{{settings["description"]}}", 8 | "SubnetIds" : [ 9 | {% for subnet in settings["subnets"] %} 10 | { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{subnet}}", {"VPCStack": {"Ref": "VPCStack"}}] }}{% if not loop.last %},{% endif %} 11 | {% endfor %} 12 | ], 13 | "Tags" : [ 14 | {% for k, v in settings["tags"].iteritems() %} 15 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | ] 18 | } 19 | }{% if not loop.last %},{% endif %} 20 | {% endfor %} 21 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/dynamodb.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for dynamodb, settings in dynamodb.iteritems() %} 3 | "{{dynamodb}}": { 4 | "Type" : "AWS::DynamoDB::Table", 5 | "Properties" : { 6 | "AttributeDefinitions" : [ 7 | {% for k, v in settings["tags"].iteritems() %} 8 | {"AttributeName": "{{ k }}", "AttributeType": "{{v}}"}{% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | ], 11 | {% if settings["secondaryindexes"] %} 12 | "GlobalSecondaryIndexes" : [ 13 | {% for index, index_settings in settings["secondaryindexes"].iteritems() %} 14 | { 15 | "IndexName" : "{{index}}", 16 | "KeySchema" : [ 17 | {% for k, v in index_settings["keyschema"].iteritems() %} 18 | {"AttributeName": "{{ k }}", "KeyType": "{{v}}"}{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | ], 21 | "Projection" : { 22 | "NonKeyAttributes" : [ 23 | {% for attribute in index_settings["projection"]["attribute"] %} 24 | "{{attribute}}"{% if not loop.last %},{% endif %} 25 | {% endfor %} 26 | ], 27 | "ProjectionType" : "{{index_settings["projection"]["type"]}}" 28 | }, 29 | "ProvisionedThroughput" : { 30 | "ReadCapacityUnits" : {{index_settings["throughput"]["read"]}}, 31 | "WriteCapacityUnits" : {{index_settings["throughput"]["write"]}} 32 | } 33 | } 34 | ], 35 | "KeySchema" : [ KeySchema, ... ], 36 | "LocalSecondaryIndexes" : [ LocalSecondaryIndexes, ... ], 37 | "ProvisionedThroughput" : ProvisionedThroughput, 38 | "StreamSpecification" : StreamSpecification, 39 | "TableName" : String, 40 | "Tags" : [ 41 | {% for k, v in settings["tags"].iteritems() %} 42 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 43 | {% endfor %} 44 | ], 45 | "TimeToLiveSpecification" : TimeToLiveSpecification 46 | } 47 | } 48 | {% endfor %} 49 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/ebs_volume.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for volume, settings in ebs_volume.iteritems() %} 3 | "{{volume}}": { 4 | "Type":"AWS::EC2::Volume", 5 | "Properties" : { 6 | "AvailabilityZone" : "{{settings["availability_zone"]}}", 7 | "Encrypted" : "{{settings["encrypted"]}}", 8 | {% if settings["iops"] %} 9 | "Iops" : "{{settings["iops"]}}", 10 | {% endif %} 11 | {% if settings["kms_key"] %} 12 | "KmsKeyId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${KmsStack}-KMS-{{settings["kms_key"]}}-ARN", {"KmsStack": {"Ref": "KmsStack"}}] }}, 13 | {% endif %} 14 | "Size" : "{{settings["size"]}}", 15 | {% if settings["source_snapshot"] %} 16 | "SnapshotId" : "{{settings["source_snapshot"]}}", 17 | {% endif %} 18 | {% if settings["tags"] %} 19 | "Tags" : [ 20 | {% for k, v in settings["tags"].iteritems() %} 21 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | ], 24 | {% endif %} 25 | "VolumeType" : "{{settings["volume_type"]}}" 26 | } 27 | } 28 | {% if not loop.last %},{% endif %} 29 | {% endfor %} 30 | } 31 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/ec2_flowlog.json: -------------------------------------------------------------------------------- 1 | {# 2 | 3 | ResourceType { VPC | Subnet | NetworkInterface } 4 | TrafficType { ACCEPT | REJECT | ALL } 5 | 6 | #} 7 | { 8 | {% for flowlog, settings in ec2_flowlog.iteritems() %} 9 | "{{flowlog}}": { 10 | "Type" : "AWS::EC2::FlowLog", 11 | "Properties" : { 12 | "DeliverLogsPermissionArn" : { "Fn::ImportValue" : {"Fn::Sub" : ["${RolesStack}-Role-{{settings["rolearn"]}}-ARN", {"RolesStack": {"Ref": "RolesStack"}}] }}, 13 | "LogGroupName" : "{{settings["loggroupname"]}}", 14 | "ResourceId" : "{{settings["resourceid"]}}", 15 | "ResourceType" : "{{settings["resourcetype"]}}", 16 | "TrafficType" : "{{settings["traffictype"]}}" 17 | } 18 | } 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/ecr.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ecr_repo, settings in ecr.iteritems() %} 3 | "{{ecr_repo}}":{ 4 | "Type" : "AWS::ECR::Repository", 5 | "Properties" : { 6 | "RepositoryName" : "{{settings["name"]}}", 7 | "RepositoryPolicyText" : { 8 | "Version": "2012-10-17", 9 | "Statement": [ 10 | {{settings["policy_document"]}} 11 | ] 12 | } 13 | } 14 | }{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/ecs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for ecs, settings in ecs.iteritems() %} 3 | "{{ecs}}":{ 4 | "Type" : "AWS::ECS::Cluster", 5 | "Properties" : { 6 | "ClusterName" : "{{settings["clustername"]}}" 7 | } 8 | }{% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/ecs_service.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | {% for service, settings in ecs_service.iteritems() %} 4 | {{service}}:{ 5 | "Type" : "AWS::ECS::Service", 6 | "Properties" : { 7 | "Cluster" : "{{settings["cluster"]}}", 8 | {% if settings["deploy_config"]%} 9 | "DeploymentConfiguration" : { 10 | "MaximumPercent": {{settings["deploy_config"]["max_percent"]}}, 11 | "MinimumHealthyPercent": {{settings["deploy_config"]["min_healthy_percent"]}} 12 | }, 13 | {% endif %} 14 | "DesiredCount" : {{settings["desired_count"]}}, 15 | {% if settings["load_balancer"] %} 16 | "LoadBalancers" : [ 17 | { 18 | "ContainerName": "{{settings["load_balancer"]["container_name"]}}", 19 | "ContainerPort": {{settings["load_balancer"]["container_port"]}} 20 | {% if settings["load_balancer"]["load_balancer_name"] %} 21 | ,"LoadBalancerName": "{{settings["load_balancer"]["load_balancer_name"]}}" 22 | {% endif %} 23 | {% if settings["load_balancer"]["target_group_arn"] %} 24 | ,"TargetGroupArn": {"Ref": "{{settings["load_balancer"]["target_group_arn"]}}" } 25 | {% endif %} 26 | } 27 | ], 28 | {% endif %} 29 | {% if settings["service_role"] %} 30 | "Role" : "{{settings["service_role"]}}", 31 | {% endif %} 32 | "ServiceName" : "{{settings["service_name"]}}", 33 | "TaskDefinition" : {"Ref": "{{settings["task_def"]}}" }, 34 | } 35 | {% if settings["depends_on"] %} 36 | ,"DependsOn" : [ 37 | {% for dep in settings["depends_on"] %} 38 | "{{dep}}", 39 | {% endfor %} 40 | ] 41 | {% endif %} 42 | }{% if not loop.last %},{% endif %} 43 | {% endfor %} 44 | } 45 | 46 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/efs.json: -------------------------------------------------------------------------------- 1 | {# Not included in Spec #### 2 | 3 | PerformanceMode: generalPurpose | maxIO 4 | 5 | #} 6 | { 7 | {% for efs, settings in efs.iteritems() %} 8 | "{{ efs }}": { 9 | "Type" : "AWS::EFS::FileSystem", 10 | "Properties" : { 11 | "FileSystemTags" : [ 12 | {% for k, v in settings["tags"].iteritems() %} 13 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | ], 16 | "PerformanceMode" : "{{settings["performancemode"]}}" 17 | } 18 | }{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/efs_filesystem.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efs_filesystem, settings in efs_filesystem.iteritems() %} 3 | "{{efs_filesystem}}": { 4 | "Type": "AWS::EFS::FileSystem", 5 | "Properties": { 6 | {% if settings["filesystemtags"] %} 7 | "FileSystemTags": [ 8 | {% for k, v in settings["filesystemtags"].iteritems() %} 9 | { "Key": "{{k}}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 10 | {% endfor %} 11 | ], 12 | {% endif %} 13 | {% if settings["encrypted"] %} 14 | "Encrypted": {{settings["encrypted"]}}, 15 | {% endif %} 16 | {% if settings["kmskeyid"] %} 17 | "KmsKeyId": "{{settings["kmskeyid"]}}", 18 | {% endif %} 19 | {% if settings["performancemode"] %} 20 | "PerformanceMode": "{{settings["performancemode"]}}", 21 | {% endif %} 22 | } 23 | }{% if not loop.last %},{% endif %} 24 | {% endfor %} 25 | } 26 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/efs_mounttarget.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efs_mounttarget, settings in efs_mounttarget.iteritems() %} 3 | "{{efs_mounttarget}}": { 4 | "Type": "AWS::EFS::MountTarget", 5 | "Properties": { 6 | "SubnetId": { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{settings["subnetid"]}}", {"VPCStack": {"Ref": "VPCStack"}}] }}, 7 | {% if settings["ipaddress"] %} 8 | "IpAddress": "{{settings["ipaddress"]}}", 9 | {% endif %} 10 | "FileSystemId": { "Ref": "{{settings["filesystemid"]}}"}, 11 | "SecurityGroups": [ 12 | {% for k in settings["securitygroups"] %} 13 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{k}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}{% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | ], 16 | } 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } 20 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/efsmount.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for efsmount, settings in efsmount.iteritems() %} 3 | "{{ efsmount }}": { 4 | "Type" : "AWS::EFS::MountTarget", 5 | "Properties" : { 6 | "FileSystemId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${EFSStack}-EFS-{{settings["filesystemid"]}}", {"EFSStack": {"Ref": "EFSStack"}}] }}, 7 | {% if settings["ipaddress"] %} 8 | "IpAddress" : "{{settings["ipaddress"]}}", 9 | {% endif %} 10 | "SecurityGroups" : [{ "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{settings["securitygroupid"]}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}], 11 | "SubnetId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{settings["subnetid"]}}", {"VPCStack": {"Ref": "VPCStack"}}] }} 12 | } 13 | }{% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/eip.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for eip in eip %} 3 | "{{eip|replace("-", "")|replace(".", "")}}EIP": { 4 | "Type" : "AWS::EC2::EIP", 5 | "Properties" : { 6 | "InstanceId" : {"Ref" : "{{eip|replace("-", "")|replace(".", "")}}"}, 7 | "Domain" : "vpc" 8 | } 9 | } 10 | {% if not loop.last %},{% endif %} 11 | {% endfor %} 12 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/elasticache.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for elasticache, settings in elasticache.iteritems() %} 3 | "{{ elasticache }}": { 4 | "Type" : "AWS::ElastiCache::CacheCluster", 5 | "Properties" : { 6 | {% if settings["nodeType"] %} 7 | "CacheNodeType" : "{{settings["nodeType"]}}", 8 | {% else %} 9 | "CacheNodeType" : "cache.t2.micro", 10 | {% endif %} 11 | {% if settings["name"] %} 12 | "ClusterName" : "{{settings["name"]}}", 13 | {% endif %} 14 | {% if settings["engine"] %} 15 | "Engine" : "{{settings["engine"]}}", 16 | {% if settings["numCacheNodes"] %} 17 | "NumCacheNodes" : {{settings["numCacheNodes"]}}, 18 | {% else %} 19 | "NumCacheNodes" : 1, 20 | {% endif %} 21 | {% else %} 22 | "Engine" : "redis", 23 | "NumCacheNodes" : 1, 24 | {% endif %} 25 | {% if settings["engineVersion"] %} 26 | "EngineVersion" : "{{settings["engineVersion"]}}", 27 | {% endif %} 28 | {% if settings["notificationTopicArn"] %} 29 | "NotificationTopicArn" : "{{settings["notificationTopicArn"]}}", 30 | {% endif %} 31 | {% if settings["port"] %} 32 | "Port" : {{settings["port"]}}, 33 | {% endif %} 34 | {% if settings["snapshotName"] %} 35 | "SnapshotName" : "{{settings["snapshotName"]}}", 36 | {% endif %} 37 | {% if settings["snapshotRetentionLimit"] %} 38 | "SnapshotRetentionLimit" : "{{settings["snapshotRetentionLimit"]}}", 39 | {% endif %} 40 | {% if settings["snapshotWindow"] %} 41 | "SnapshotWindow" : "{{settings["snapshotWindow"]}}", 42 | {% endif %} 43 | "CacheSubnetGroupName" : { "Fn::ImportValue" : {"Fn::Sub" : ["${CacheSubnetStack}-ElastiCache-{{settings["cacheSubnetGroup"]}}-Subnet", {"CacheSubnetStack": {"Ref": "CacheSubnetStack"}}] }}, 44 | "VpcSecurityGroupIds" : [ 45 | {% for secgroup in settings["secgroups"] %} 46 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{secgroup}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}{% if not loop.last %},{% endif %} 47 | {% endfor %} 48 | ]{% if settings["tags"] %}, 49 | "Tags" : [ 50 | {% for k, v in settings["tags"].iteritems() %} 51 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 52 | {% endfor %} 53 | ]{% endif %} 54 | } 55 | } 56 | {% if not loop.last %},{% endif %} 57 | {% endfor %} 58 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/elasticachesubnet.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for elasticachesubnet, settings in elasticachesubnet.iteritems() %} 3 | "{{elasticachesubnet}}": { 4 | "Type" : "AWS::ElastiCache::SubnetGroup", 5 | "Properties" : { 6 | "CacheSubnetGroupName" : "{{settings["name"]}}", 7 | "Description" : "{{settings["description"]}}", 8 | "SubnetIds" : [ 9 | {% for subnet in settings["subnets"] %} 10 | { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{subnet}}", {"VPCStack": {"Ref": "VPCStack"}}] }}{% if not loop.last %},{% endif %} 11 | {% endfor %} 12 | ] 13 | } 14 | }{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/elasticsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for es, settings in elasticsearch.iteritems() %} 3 | "{{es}}": { 4 | "Type": "AWS::Elasticsearch::Domain", 5 | "Properties": { 6 | "ElasticsearchClusterConfig": { 7 | "DedicatedMasterEnabled": "{{settings["dedicatedmaster"]|lower}}", 8 | {% if settings["dedicatedmaster"] == true %} 9 | "DedicatedMasterType": "{{settings["mastertype"]}}", 10 | "DedicatedMasterCount": "{{settings["mastercount"]}}", 11 | {% endif %} 12 | "InstanceCount": "{{settings["instancecount"]}}", 13 | "ZoneAwarenessEnabled": "true", 14 | "InstanceType": "{{settings["instancetype"]}}" 15 | }, 16 | {% if settings["ebsoptions"] %} 17 | "EBSOptions": { 18 | "EBSEnabled": "true", 19 | "Iops": {{settings["ebsoptions"]["iops"]}}, 20 | "VolumeSize": {{settings["ebsoptions"]["size"]}}, 21 | "VolumeType": "{{settings["ebsoptions"]["type"]}}" 22 | }, 23 | {% else %} 24 | "EBSOptions": { 25 | "EBSEnabled": "true", 26 | "Iops": 0, 27 | "VolumeSize": 20, 28 | "VolumeType": "gp2" 29 | }, 30 | {% endif %} 31 | "ElasticsearchVersion": "{{settings["version"]}}", 32 | {% if settings["snapshotoptions"] %} 33 | "SnapshotOptions": { 34 | {% for k, v in settings["snapshotoptions"].iteritems() %} 35 | "{{k}}": "{{v}}"{% if not loop.last %},{% endif %} 36 | {% endfor %} 37 | }, 38 | {% endif %} 39 | {% if settings["advancedoptions"] %} 40 | "AdvancedOptions": { 41 | {% for k, v in settings["advancedoptions"].iteritems() %} 42 | "{{k}}" : "{{v}}"{% if not loop.last %},{% endif %} 43 | {% endfor %} 44 | }, 45 | {% endif %} 46 | "AccessPolicies": { 47 | "Version": "2012-10-17", 48 | "Statement": [ {{settings["policy"]}} ] 49 | }, 50 | "DomainName": "{{es}}" 51 | } 52 | } 53 | {% if settings["zoneid"] %}, 54 | "{{es|replace("-", "")|replace(".", "")}}DNS": { 55 | "Type" : "AWS::Route53::RecordSetGroup", 56 | "Properties" : { 57 | "Comment" : "{{es}} Records by default", 58 | "HostedZoneId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${DNSStack}-Route53-{{settings["zoneid"]}}-Zone", {"DNSStack": {"Ref": "DNSStack"}}] }}, 59 | "RecordSets" : [{ 60 | "Name" : "{{es}}.es.{{settings["zonesuffix"]}}", 61 | "Type" : "CNAME", 62 | "ResourceRecords" : [ 63 | { "Fn::GetAtt" : [ "{{es}}", "DomainEndpoint" ] } 64 | ], 65 | "TTL" : "60", 66 | "Weight" : "10", 67 | "SetIdentifier" : "{{es}}.es.{{settings["zonesuffix"]}}" 68 | } 69 | ] 70 | } 71 | }{% endif %} 72 | {% if not loop.last %},{% endif %} 73 | {% endfor %} 74 | } 75 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/events.json: -------------------------------------------------------------------------------- 1 | {# 2 | EventPattern not currently implemented 3 | #} 4 | { 5 | {% for event, settings in events.iteritems() %} 6 | "{{ event }}": { 7 | "Type" : "AWS::Events::Rule", 8 | "Properties" : { 9 | {% if settings['role'] %} 10 | "RoleArn" : "{{settings['role']}}", 11 | {% endif %} 12 | {% if settings["schedule"] %} 13 | "ScheduleExpression" : "{{settings['schedule']}}", 14 | {% endif %} 15 | {% if settings["eventpattern"] %} 16 | "EventPattern": {{settings["eventpattern"]}}, 17 | {% endif %} 18 | {% if settings['state'] %} 19 | "State" : "{{settings['state']}}", 20 | {% endif %} 21 | {% if settings['targets'] %} 22 | "Targets" : [ 23 | {% for target in settings['targets'] %} 24 | { 25 | {% if target['input'] %} 26 | "Input" : '{{target['input']}}', 27 | {% endif %} 28 | {% if target['inputpath'] %} 29 | "InputPath" : "{{target['inputpath']}}" 30 | {% endif %} 31 | "Arn" : { "Fn::GetAtt": ["{{target['arn']}}","Arn"] }, 32 | "Id" : "{{target['id']}}" 33 | } 34 | {% endfor %} 35 | ], 36 | {% endif %} 37 | "Description" : "{{settings['description']}}", 38 | "Name" : "{{settings['name']}}" 39 | } 40 | } 41 | {% if not loop.last %},{% endif %} 42 | {% endfor %} 43 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/iam_policies.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for policy in iam_policies["Policies"] %} 3 | "{{policy["Name"]}}": { 4 | "Type": "AWS::IAM::Policy", 5 | "Properties": { 6 | "PolicyName": "{{policy["Name"]}}", 7 | "PolicyDocument": { 8 | "Version": "2012-10-17", 9 | "Statement": [ 10 | {{policy["PolicyDocument"]}} 11 | ] 12 | }{% if policy["ManagedPolicys"] %}, 13 | "ManagedPolicyArns": [ 14 | {% for managedpolicys in policy["ManagedPolicys"] %} 15 | "arn:aws:iam::aws:policy/{{managedpolicys}}"{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | ] 18 | {% endif %} 19 | 20 | {% if policy["Roles"] %}, 21 | "Roles": [ 22 | {% for role in policy["Roles"] %} 23 | {"Fn::ImportValue" : {"Fn::Sub" : "{{role}}"}}{% if not loop.last %},{% endif %} 24 | {% endfor %} 25 | ] 26 | {% endif %} 27 | {% if policy["Groups"] %}, 28 | "Groups": [ 29 | {% for group in policy["Groups"] %} 30 | {"Fn::ImportValue" : {"Fn::Sub" : "{{group}}"}}{% if not loop.last %},{% endif %} 31 | {% endfor %} 32 | ] 33 | {% endif %} 34 | 35 | } 36 | }{% if not loop.last %},{% endif %} 37 | {% endfor %} 38 | } 39 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/iam_users.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for user, settings in iam_users["Users"].iteritems() %} 3 | "{{ user|replace("-", "")|replace(".", "") }}": { 4 | "Type": "AWS::IAM::User", 5 | "Properties": { 6 | "Groups": [ 7 | {% for group in settings["Groups"] %} 8 | {"Ref": "{{group}}"}{% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | ], 11 | "Path": {"Fn::Join" : [ "", ["/",{ "Ref" : "AccountName" }, "/IAM/Users/"] ]}, 12 | "UserName": "{{user}}" 13 | } 14 | }, 15 | {% endfor %} 16 | {% for group, settings in iam_users["Groups"].iteritems() %} 17 | "{{group}}": { 18 | "Type": "AWS::IAM::Group", 19 | "Properties": { 20 | "GroupName": "{{group}}", 21 | "Path": {"Fn::Join" : [ "", ["/",{ "Ref" : "AccountName" }, "/IAM/Groups/"] ]} 22 | } 23 | }{% if not loop.last %},{% endif %} 24 | {% endfor %} 25 | } 26 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/kinesis_firehose.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for firehose, settings in kinesis_firehose.iteritems() %} 3 | "{{firehose}}": { 4 | "Type": "AWS::KinesisFirehose::DeliveryStream", 5 | "Properties": { 6 | {% if settings["type"]=="elasticsearch" %} 7 | {% elif settings["type"]=="s3" %} 8 | S3DestinationConfiguration: { 9 | {# "BucketARN" : { "Fn::ImportValue" : {"Fn::Sub" : ["${S3Stack}-S3-{{settings["bucketarn"]}}-ARN", {"S3Stack": {"Ref": "S3Stack"}}] }}, #} 10 | "BucketARN" : "{{settings["bucketarn"]}}", 11 | "BufferingHints" : { 12 | "IntervalInSeconds" : 60, 13 | "SizeInMBs" : 5 14 | }, 15 | {% if settings["loggingoptions"] %} 16 | "CloudWatchLoggingOptions" : { 17 | "Enabled" : true, 18 | "LogGroupName" : "{{settings["loggingoptions"]["loggroup"]}}", 19 | "LogStreamName" : "{{settings["loggingoptions"]["streamgroup"]}}" 20 | }, 21 | {% endif %} 22 | "CompressionFormat" : "{{settings["compression"]}}", 23 | {% if settings["encryption"] %} 24 | "EncryptionConfiguration" : { 25 | "KMSEncryptionConfig" : { 26 | {# "AWSKMSKeyARN" : { "Fn::ImportValue" : {"Fn::Sub" : ["${KMSStack}-KMS-{{settings["encryption"]["kmskey"]}}-ARN", {"KMSStack": {"Ref": "KMSStack"}}] }}, #} 27 | "AWSKMSKeyARN" : "{{settings["encryption"]["kmskey"]}}", 28 | } 29 | }, 30 | {% endif %} 31 | "Prefix" : "{{settings["prefix"]}}", 32 | {# "RoleARN" : { "Fn::ImportValue" : {"Fn::Sub" : ["${RolesStack}-Role-{{settings["rolearn"]}}-ARN", {"RolesStack": {"Ref": "RolesStack"}}] }}, #} 33 | "RoleARN" : "{{settings["rolearn"]}}" 34 | } 35 | {% endif %} 36 | } 37 | }{% if not loop.last %},{% endif %} 38 | {% endfor %} 39 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/kinesis_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for kinesis_stream, settings in kinesis_stream.iteritems() %} 3 | "{{kinesis_stream}}" : { 4 | "Type" : "AWS::Kinesis::Stream", 5 | "Properties" : { 6 | "Name": "{{kinesis_stream}}", 7 | "RetentionPeriodHours": "{{settings["RetentionPeriodHours"]}}", 8 | "ShardCount": "{{settings["ShardCount"]}}", 9 | "Tags" : [ 10 | {% for k, v in settings["tags"].iteritems() %} 11 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 12 | {% endfor %} 13 | ]} 14 | }{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | } 17 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/kms.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for key, settings in kms.iteritems() %} 3 | "{{ key }}": { 4 | "Type" : "AWS::KMS::Key", 5 | "Properties" : { 6 | "Description" : "{{ settings["description"] }}", 7 | "Enabled" : "{{ settings["enabled"]|lower }}", 8 | "EnableKeyRotation" : "{{ settings["rotation"]|lower }}" 9 | {% if settings["policy"] %} 10 | ,"KeyPolicy" : 11 | {{ settings["policy"] }} 12 | {% endif %} 13 | } 14 | }, 15 | "{{key}}Alias": { 16 | "Type" : "AWS::KMS::Alias", 17 | "Properties" : { 18 | "AliasName": "alias/{{ settings["aliasname"] }}", 19 | "TargetKeyId": {"Ref": "{{ key }}"} 20 | } 21 | }{% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/lambda_events.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for event, settings in lambda_events.iteritems() %} 3 | "{{event}}": { 4 | "Type": "AWS::Lambda::EventSourceMapping", 5 | "Properties": { 6 | {% if settings["batchsize"] %} 7 | "BatchSize" : "{{ settings["batchsize"] }}", 8 | {% endif %} 9 | {% if settings["enabled"] %} 10 | "Enabled" : "{{ settings["enabled"] }}", 11 | {% endif %} 12 | "EventSourceArn" : "{{ settings["sourcearn"] }}", 13 | "FunctionName" : "{{ settings["lambda"] }}", 14 | "StartingPosition" : "{{ settings["startingposition"] }}" 15 | } 16 | }{% if not loop.last %},{% endif %} 17 | {% endfor %} 18 | } 19 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/lambda_permissions.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | {% for permission, settings in lambda_permissions.iteritems() %} 4 | "{{ permission }}": { 5 | "Type": "AWS::Lambda::Permission", 6 | "Properties": { 7 | "Action": "lambda:InvokeFunction", 8 | "FunctionName": {"Fn::GetAtt": ["{{ settings["lambdaname"] }}", "Arn"]}, 9 | {% if settings['principal'] %} 10 | "Principal": "{{settings['principal']}}.amazonaws.com", 11 | {% elif settings['principalraw'] %} 12 | "Principal": "{{settings['principalraw']}}", 13 | {% else %} 14 | "Principal": "apigateway.amazonaws.com", 15 | {% endif %} 16 | {% if settings['sourceaccount'] %} 17 | "SourceAccount": { "Ref" : "AWS::AccountId" }, 18 | {% else %} 19 | {% if settings['sourcearn'] %} 20 | "SourceArn": "{{settings['sourcearn']}}", 21 | {% else %} 22 | {% if settings['principal']=="events" %} 23 | "SourceArn": {"Fn::GetAtt": ["{{ settings["events"] }}", "Arn"]} 24 | {% elif settings['principal']=="s3" %} 25 | {% if settings['s3arn'] %} 26 | "SourceArn": "{{settings['s3arn']}}", 27 | {% else %} 28 | "SourceArn": {"Fn::GetAtt": ["{{ settings["s3"] }}", "Arn"]} 29 | {% endif %} 30 | {% elif settings['principal']=="lambda" %} 31 | "SourceArn": {"Fn::GetAtt": ["{{ settings["lambda"] }}", "Arn"]} 32 | {% elif settings['principal']=="config" %} 33 | "SourceArn": {"Fn::GetAtt": ["{{ settings["config"] }}", "Arn"]} 34 | {% else %} 35 | "SourceArn": {"Fn::Join": ["", 36 | ["arn:aws:execute-api:", {"Ref": "AWS::Region"}, ":", {"Ref": "AWS::AccountId"}, ":", {"Ref": "{{ settings["apigateway"] }}"}, "/*"] 37 | ]} 38 | {% endif %} 39 | {% endif %} 40 | {% endif %} 41 | } 42 | }{% if not loop.last %},{% endif %} 43 | {% endfor %} 44 | } 45 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/launch_configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for lc, settings in launch_configuration.iteritems() %} 3 | "{{lc}}": { 4 | "Type": "AWS::AutoScaling::LaunchConfiguration", 5 | "Properties": { 6 | "AssociatePublicIpAddress" : "{{settings["public_ip"]}}", 7 | "EbsOptimized" : "{{settings["ebs_optimised"]}}", 8 | {% if settings["instance_profile"] %} 9 | "IamInstanceProfile" : "{{settings['instance_profile']}}", 10 | {% endif %} 11 | "ImageId" : "{{settings["image_id"]}}", 12 | "InstanceType" : "{{settings["instance_type"]}}", 13 | "SecurityGroups" : [ 14 | {% for sg in settings["security_groups"] %} 15 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{sg}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | ], 18 | {% if settings["blockdevice"] %} 19 | "BlockDeviceMappings" : [ 20 | {% for name, size in settings["blockdevice"].iteritems() %} 21 | { 22 | "DeviceName" : "{{name}}", 23 | "Ebs" : { "VolumeSize" : "{{size}}", "VolumeType": "gp2"} 24 | }{% if not loop.last %},{% endif %} 25 | {% endfor %} 26 | ], 27 | {% endif %} 28 | "KeyName" : "{{settings["key_name"]}}", 29 | "UserData" : { "Fn::Base64": { "Fn::Join": ["",[ 30 | {% for userdata in settings["user_data"] %} 31 | "{{userdata}}"{% if not loop.last %},{% endif %} 32 | {% endfor %} 33 | ]]}}, 34 | } 35 | }{% if not loop.last %},{% endif %} 36 | {% endfor %} 37 | } 38 | 39 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/logs_group.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for loggroup, settings in logs_group.iteritems() %} 3 | "{{loggroup}}": { 4 | "Type": "AWS::Logs::LogGroup", 5 | "Properties": { 6 | "LogGroupName": "{{settings["name"]}}", 7 | "RetentionInDays": {{settings["retention"]}} 8 | } 9 | }{% if not loop.last %},{% endif %} 10 | {% endfor %} 11 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/microsoftad.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for microsoftad, settings in microsoftad.iteritems() %} 3 | "{{ microsoftad }}": { 4 | "Type" : "AWS::DirectoryService::MicrosoftAD", 5 | "Properties" : { 6 | "CreateAlias" : "{{settings["createalias"]|lower}}", 7 | "EnableSso" : "{{settings["enablesso"]|lower}}", 8 | "Name" : "{{settings["name"]}}", 9 | "Password" : "{{settings["password"]}}", 10 | "ShortName" : "{{settings["shortname"]}}", 11 | "VpcSettings" : { 12 | "SubnetIds" : [ 13 | {% for subnet in settings["subnets"] %} 14 | { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{subnet}}", {"VPCStack": {"Ref": "VPCStack"}}] }}{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | ], 17 | "VpcId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-VPC-VPCid", {"VPCStack": {"Ref": "VPCStack"}}] }} 18 | } 19 | } 20 | } 21 | {% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/network_interface.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for eni, settings in network_interface.iteritems() %} 3 | "{{eni}}": { 4 | "Type" : "AWS::EC2::NetworkInterface", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "PrivateIpAddress" : "{{settings["private_ip"]}}", 8 | "SourceDestCheck" : "{{settings["source_dest_check"]}}", 9 | "GroupSet" : [ 10 | {% for sg in settings["security_groups"] %} 11 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{sg}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}{% if not loop.last %},{% endif %} 12 | {% endfor %} 13 | ], 14 | "SubnetId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{settings["subnet"]}}", {"VPCStack": {"Ref": "VPCStack"}}] }}, 15 | {% if settings["tags"] %} 16 | "Tags" : [ 17 | {% for k, v in settings["tags"].iteritems() %} 18 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | ], 21 | {% endif %} 22 | } 23 | }{% if not loop.last %},{% endif %} 24 | {% endfor %} 25 | } 26 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/rdscluster.json: -------------------------------------------------------------------------------- 1 | {# 2 | # WIP 3 | #} 4 | { 5 | {% for rdscluster, settings in rdscluster.iteritems() %} 6 | "{{rdscluster}}":{ 7 | "Type" : "AWS::RDS::DBCluster", 8 | {% if settings["deletionpolicy"] %} 9 | "DeletionPolicy" : "{{settings["deletionpolicy"]}}", 10 | {% endif %} 11 | "Properties" : 12 | { 13 | {% if settings["az"] %} 14 | "AvailabilityZones": { "Fn::Join": [ "", [ { "Ref" : "AWS::Region" }, "{{settings["az"]}}" ] ] }, 15 | {% endif %} 16 | {% if settings["backupretention"] %} 17 | "BackupRetentionPeriod" : "{{settings["backupretention"]}}", 18 | {% endif %} 19 | {% if settings['dbname'] %} 20 | "DatabaseName" : "{{settings["dbname"]}}", 21 | {% endif %} 22 | {% if settings['rdsparamgroup'] %} 23 | "DBClusterParameterGroupName" : { "Fn::ImportValue" : {"Fn::Sub" : ["${RDSClusterParamGroupStack}-RDS-{{settings["rdsparamgroup"]}}-ParamsGroup", {"RDSClusterParamGroupStack": {"Ref": "RDSClusterParamGroupStack"}}] }}, 24 | {% endif %} 25 | "DBSubnetGroupName" : { "Fn::ImportValue" : {"Fn::Sub" : ["${RDSSubnetStack}-RDS-{{settings["rdssubnetgroup"]}}-Subnet", {"RDSSubnetStack": {"Ref": "RDSSubnetStack"}}] }}, 26 | "Engine" : "{{settings["engine"]}}", 27 | "EngineVersion" : "{{settings["engineversion"]}}", 28 | {% if settings["kmskeyid"] %} 29 | "KmsKeyId" : "{{settings["kmskeyid"]}}", 30 | {% endif %} 31 | {% if settings["snapshotid"] %} 32 | "SnapshotIdentifier" : "{{settings["snapshotid"]}}", 33 | {% else %} 34 | {% if settings["masterusername"] %} 35 | "MasterUsername" : "{{settings["masterusername"]}}", 36 | {% endif %} 37 | "MasterUserPassword" : {"Ref": "DBPassword"}, 38 | {% endif %} 39 | "Port" : "{{settings["port"]}}", 40 | "PreferredBackupWindow" : "{{settings["backupwindow"]}}", 41 | "PreferredMaintenanceWindow" : "{{settings["maintenancewindow"]}}", 42 | "StorageEncrypted" : "{{settings["storageencryption"]|lower}}", 43 | "VpcSecurityGroupIds" : [ 44 | {% for secgroup in settings["secgroups"] %} 45 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SecurityStack}-SecGroup-{{secgroup}}", {"SecurityStack": {"Ref": "SecurityStack"}}] }}{% if not loop.last %},{% endif %} 46 | {% endfor %} 47 | ]{% if settings["tags"] %}, 48 | "Tags" : [ 49 | {% for k, v in settings["tags"].iteritems() %} 50 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 51 | {% endfor %} 52 | ]{% endif %}} 53 | }{% if settings["zoneid"] %}, 54 | "{{rdscluster|replace("-", "")|replace(".", "")}}DNS": { 55 | "Type" : "AWS::Route53::RecordSetGroup", 56 | "Properties" : { 57 | "Comment" : "{{rdscluster}} Records by default", 58 | "HostedZoneId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${DNSStack}-Route53-{{settings["zoneid"]}}-Zone", {"DNSStack": {"Ref": "DNSStack"}}] }}, 59 | "RecordSets" : [{ 60 | "Name" : "{{settings["zoneprefix"]}}.{{settings["zonesuffix"]}}", 61 | "Type" : "CNAME", 62 | "ResourceRecords" : [ 63 | { "Fn::GetAtt" : [ "{{rdscluster}}", "Endpoint.Address" ] } 64 | ], 65 | "TTL" : "60", 66 | "Weight" : "10", 67 | "SetIdentifier" : "{{rdscluster}}.{{settings["zonesuffix"]}}" 68 | } 69 | ] 70 | } 71 | }{% endif %}{% if not loop.last %},{% endif %} 72 | {% endfor %} 73 | } 74 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/rdsclusterparamsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsclusterparamsgroup, settings in rdsclusterparamsgroup.iteritems() %} 3 | "{{rdsclusterparamsgroup}}":{ 4 | "Type" : "AWS::RDS::DBClusterParameterGroup", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "Family" : "{{settings["family"]}}", 8 | "Parameters" : { 9 | {% for k, v in settings["parameters"].iteritems() %} 10 | "{{ k }}" : "{{v}}"{% if not loop.last %},{% endif %} 11 | {% endfor %} 12 | }{% if settings["tags"] %}, 13 | "Tags" : [ 14 | {% for k, v in settings["tags"].iteritems() %} 15 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | ]{% endif %}} 18 | }{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/rdsoptiongroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsoptiongroup, settings in rdsoptiongroup.iteritems() %} 3 | "{{rdsoptiongroup}}":{ 4 | "Type" : "AWS::RDS::OptionGroup", 5 | "Properties" : { 6 | "EngineName": "{{settings["engine"]}}", 7 | "MajorEngineVersion": "{{settings["engineversion"]}}", 8 | "OptionGroupDescription": "{{settings["description"]}}", 9 | "OptionConfigurations": [ 10 | {% for optionconfig, optionconfigsettings in settings["options"].iteritems() %} 11 | { 12 | "OptionName" : "{{optionconfig}}", 13 | "OptionSettings": [ 14 | {% for optionsetting, optionsettingvalue in optionconfigsettings["settings"].iteritems() %} 15 | { 16 | "Name": "{{optionsetting}}", 17 | "Value": "{{optionsettingvalue}}" 18 | }{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | ] 21 | }{% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | ], 24 | "Tags" : [ 25 | {% for k, v in settings["tags"].iteritems() %} 26 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 27 | {% endfor %} 28 | ]{% endif %}} 29 | }{% if not loop.last %},{% endif %} 30 | {% endfor %} 31 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/rdsparamsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdsparamsgroup, settings in rdsparamsgroup.iteritems() %} 3 | "{{rdsparamsgroup}}":{ 4 | "Type" : "AWS::RDS::DBParameterGroup", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "Family" : "{{settings["family"]}}", 8 | "Parameters" : { 9 | {% for k, v in settings["parameters"].iteritems() %} 10 | "{{ k }}" : "{{v}}"{% if not loop.last %},{% endif %} 11 | {% endfor %} 12 | }{% if settings["tags"] %}, 13 | "Tags" : [ 14 | {% for k, v in settings["tags"].iteritems() %} 15 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | ]{% endif %}} 18 | }{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/rdssubnet.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for rdssubnet, settings in rdssubnet.iteritems() %} 3 | "{{rdssubnet}}": { 4 | "Type" : "AWS::RDS::DBSubnetGroup", 5 | "Properties" : { 6 | "DBSubnetGroupDescription" : "{{settings["description"]}}", 7 | "SubnetIds" : [ 8 | {% for subnet in settings["subnets"] %} 9 | { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{subnet}}", {"VPCStack": {"Ref": "VPCStack"}}] }}{% if not loop.last %},{% endif %} 10 | {% endfor %} 11 | ], 12 | "Tags" : [ 13 | {% for k, v in settings["tags"].iteritems() %} 14 | {"Key": "{{ k }}", "Value": "{{v}}"}{% if not loop.last %},{% endif %} 15 | {% endfor %} 16 | ] 17 | } 18 | }{% if not loop.last %},{% endif %} 19 | {% endfor %} 20 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/redshift_paramsgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for paramsgroup, settings in redshift_paramsgroup.iteritems() %} 3 | "{{paramsgroup}}": { 4 | "Type" : "AWS::Redshift::ClusterParameterGroup", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "ParameterGroupFamily" : "{{settings["groupfamily"]}}", 8 | "Parameters" : [ 9 | {% for k, v in settings["parameters"].iteritems() %} 10 | { 11 | "ParameterName" : "{{ k }}", 12 | "ParameterValue" : "{{ v }}" 13 | }{% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | ] 16 | } 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/redshift_subnetgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for redshiftsubnet, settings in redshift_subnetgroup.iteritems() %} 3 | "{{redshiftsubnet}}": { 4 | "Type" : "AWS::Redshift::ClusterSubnetGroup", 5 | "Properties" : { 6 | "Description" : "{{settings["description"]}}", 7 | "SubnetIds" : [ 8 | {% for subnet in settings["subnets"] %} 9 | { "Fn::ImportValue" : {"Fn::Sub" : ["${VPCStack}-Subnet-{{subnet}}", {"VPCStack": {"Ref": "VPCStack"}}] }}{% if not loop.last %},{% endif %} 10 | {% endfor %} 11 | ] 12 | } 13 | } 14 | {% endfor %} 15 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/route53_record.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for record, settings in route53_record.iteritems() %} 3 | "{{record}}": { 4 | "Type" : "AWS::Route53::RecordSetGroup", 5 | "Properties" : { 6 | "Comment" : "{{settings["comment"]}}", 7 | "HostedZoneId" : { "Fn::ImportValue" : {"Fn::Sub" : ["${DNSStack}-Route53-{{settings["zoneid"]}}-Zone", {"DNSStack": {"Ref": "DNSStack"}}] }}, 8 | "RecordSets" : [ 9 | {% for set in settings["recordsets"] %} 10 | { 11 | "Name" : "{{set[0]}}", 12 | "Type" : "{{set[1]}}", 13 | {% if 'Fn' in set[2] %} 14 | "ResourceRecords" : [{{set[2]}}], 15 | {% else %} 16 | "ResourceRecords" : ["{{set[2]}}"], 17 | {% endif %} 18 | "TTL" : "{{set[3]}}", 19 | "Weight" : "{{set[4]}}", 20 | "SetIdentifier" : "{{set[5]}}" 21 | }{% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | ] 24 | } 25 | }{% if not loop.last %},{% endif %} 26 | {% endfor %} 27 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/route53_zone.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for zone, settings in route53_zone.iteritems() %} 3 | "{{zone}}": { 4 | "Type" : "AWS::Route53::HostedZone", 5 | "Properties" : { 6 | "HostedZoneConfig": { 7 | "Comment": "{{settings["comment"]}}" 8 | }, 9 | {% if settings["hostedzone"] %} 10 | "HostedZoneTags" : [ 11 | {% for k, v in settings["hostedzone"].iteritems() %} 12 | {"Key": "{{k}}", "Value": "{{v}}"} 13 | {% if not loop.last %},{% endif %} 14 | {% endfor %} 15 | ], 16 | {% endif %} 17 | {% if settings["vpcs"] %} 18 | "VPCs" : [ 19 | {% for k, v in settings["vpcs"].iteritems() %} 20 | {"VPCId": "{{k}}", "VPCRegion": "{{v}}"} 21 | {% if not loop.last %},{% endif %} 22 | {% endfor %} 23 | ], 24 | {% endif %} 25 | "Name" : "{{settings["name"]}}" 26 | } 27 | } 28 | {% if not loop.last %},{% endif %} 29 | {% endfor %} 30 | } 31 | -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/s3_policies.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for policy, settings in s3_policies.iteritems() %} 3 | "{{policy}}": { 4 | "Type": "AWS::S3::BucketPolicy", 5 | "Properties" : { 6 | {{ settings["policy"]}} 7 | } 8 | } 9 | {% if not loop.last %},{% endif %} 10 | {% endfor %} 11 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/sns.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for sns, settings in sns.iteritems() %} 3 | "{{sns}}": { 4 | "Type" : "AWS::SNS::Topic", 5 | "Properties" : { 6 | "DisplayName" : "{{settings['displayname']}}", 7 | "Subscription" : [ 8 | {% for sub in settings['subscription'] %} 9 | { 10 | {% if sub['endpointtype']=="export" and sub['protocol']=="lambda" %} 11 | "Endpoint" : { "Fn::ImportValue" : {"Fn::Sub" : ["${LambdaStack}-Lambda-{{sub["value"]}}-ARN", {"LambdaStack": {"Ref": "LambdaStack"}}] }}, 12 | {% elif sub['endpointtype']=="export" and sub['protocol']=="sqs" %} 13 | "Endpoint" : { "Fn::ImportValue" : {"Fn::Sub" : ["${SQSStack}-SQS-{{sub["value"]}}-ARN", {"SQSStack": {"Ref": "SQSStack"}}] }}, 14 | {% else %} 15 | "Endpoint" : { "Ref": "{{sub["value"]}}" }, 16 | {% endif %} 17 | "Protocol" : "{{sub['protocol']}}" 18 | } 19 | {% if not loop.last %},{% endif %} 20 | {% endfor %} 21 | ], 22 | "TopicName" : "{{settings['topicname']}}" 23 | } 24 | } 25 | {% if not loop.last %},{% endif %} 26 | {% endfor %} 27 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/snstopic.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for snstopic, settings in snstopic.iteritems() %} 3 | "{{snstopic}}": { 4 | "Type" : "AWS::SNS::TopicPolicy", 5 | "Properties" : 6 | { 7 | "PolicyDocument" : "{{settings['policy']}}", 8 | "Topics" : [ 9 | {% for topics in settings['topics'] %} 10 | { "Fn::ImportValue" : {"Fn::Sub" : ["${SNSStack}-SNS-{{topics}}", {"SNSStack": {"Ref": "SNSStack"}}] }} 11 | {% if not loop.last %},{% endif %} 12 | {% endfor %} 13 | ] 14 | } 15 | }{% if not loop.last %},{% endif %} 16 | {% endfor %} 17 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/sqs.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for sqs, settings in sqs.iteritems() %} 3 | "{{sqs}}" : { 4 | "Type" : "AWS::SQS::Queue", 5 | "Properties" : { 6 | {% if settings["delay"] %} 7 | "DelaySeconds": "{{settings["delay"]}}", 8 | {% endif %} 9 | {% if settings["maxsize"] %} 10 | "MaximumMessageSize": "{{settings["maxsize"]}}", 11 | {% endif %} 12 | {% if settings["fifoqueue"] %} 13 | "FifoQueue": "{{settings["fifoqueue"]}}", 14 | {% endif %} 15 | {% if settings["retention"] %} 16 | "MessageRetentionPeriod": "{{settings["retention"]}}", 17 | {% endif %} 18 | "QueueName": "{{settings["name"]}}", 19 | {% if settings["waittime"] %} 20 | "ReceiveMessageWaitTimeSeconds": "{{settings["waittime"]}}", 21 | {% endif %} 22 | {% if settings["redirectpolicy"] %} 23 | "RedrivePolicy": { 24 | "deadLetterTargetArn" : { "Fn::GetAtt" : ["{{settings["redirectpolicy"]["deadletterqueue"]}}", "Arn"]}, 25 | "maxReceiveCount" : "{{settings["redirectpolicy"]["count"]}}" 26 | }, 27 | {% endif %} 28 | "VisibilityTimeout": "{{settings["visibilitytimeout"]}}" 29 | } 30 | }{% if not loop.last %},{% endif %} 31 | {% endfor %} 32 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/stepfunctions.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | {% for stepfunction, settings in stepfunctions.iteritems() %} 4 | "{{stepfunction}}": { 5 | "Type": "AWS::StepFunctions::StateMachine", 6 | "Properties": { 7 | {% if settings["statemachinename"] %} 8 | "StateMachineName": "{{settings["statemachinename"]}}", 9 | {% endif %} 10 | "DefinitionString": "{{forceescape(settings["definitionstring"])}}", 11 | {% if 'Fn::' in settings["rolearn"] %} 12 | "RoleArn": { {{settings["rolearn"]}} } 13 | {% else %} 14 | "RoleArn": "{{settings["rolearn"]}}" 15 | {% endif %} 16 | } 17 | }{% if not loop.last %},{% endif %} 18 | {% endfor %} 19 | } -------------------------------------------------------------------------------- /PyStacks/configs/cftemplates/resources/stepfunctions_activity.json: -------------------------------------------------------------------------------- 1 | { 2 | {% for step_activity, settings in stepfunctions_activity.iteritems() %} 3 | "{{step_activity}}": { 4 | "Type": "AWS::StepFunctions::Activity", 5 | "Properties": { 6 | "Name": "{{settings["name"]}}" 7 | } 8 | }{% if not loop.last %},{% endif %} 9 | {% endfor %} 10 | } -------------------------------------------------------------------------------- /PyStacks/configs/user/dns/test.zone: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "example.com.au.", 4 | "ResourceRecords": [ 5 | { 6 | "Value": "8.8.8.8" 7 | } 8 | ], 9 | "TTL": 86400, 10 | "Type": "A" 11 | }, 12 | { 13 | "Name": "example.com.au.", 14 | "ResourceRecords": [ 15 | { 16 | "Value": "ns.rackspace.com." 17 | }, 18 | { 19 | "Value": "ns2.rackspace.com." 20 | } 21 | ], 22 | "TTL": 86400, 23 | "Type": "NS" 24 | }, 25 | { 26 | "Name": "example.com.au.", 27 | "ResourceRecords": [ 28 | { 29 | "Value": "10 cluster5.us.messagelabs.com." 30 | }, 31 | { 32 | "Value": "20 cluster5a.us.messagelabs.com." 33 | } 34 | ], 35 | "TTL": 86400, 36 | "Type": "MX" 37 | }, 38 | { 39 | "Name": "example.com.au.", 40 | "ResourceRecords": [ 41 | { 42 | "Value": "MS=ms78757645" 43 | }, 44 | { 45 | "Value": "O0R1I39671" 46 | } 47 | ], 48 | "TTL": 86400, 49 | "Type": "TXT" 50 | }, 51 | { 52 | "Name": "example.com.au.", 53 | "ResourceRecords": [ 54 | { 55 | "Value": "05 5060 sipserver.example.com." 56 | } 57 | ], 58 | "TTL": 86400, 59 | "Type": "SRV" 60 | } 61 | ] -------------------------------------------------------------------------------- /PyStacks/configs/user/dns/test_blank.zone: -------------------------------------------------------------------------------- 1 | [{ 2 | 3 | this is malformed json -------------------------------------------------------------------------------- /PyStacks/configs/user/dns/test_writezonezone: -------------------------------------------------------------------------------- 1 | {"foo": "bar"} -------------------------------------------------------------------------------- /PyStacks/configs/user/dns_test/test_writezonezone: -------------------------------------------------------------------------------- 1 | {"foo": "bar"} -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/acm.yml: -------------------------------------------------------------------------------- 1 | description: "ExampleStacks ACM List" 2 | stackname: "ExampleStacks-ACM-Certs" 3 | region: "ap-southeast-2" 4 | parameters: {} 5 | mappings: {} 6 | resources: 7 | certificatemanager: 8 | shopexamplecom: 9 | domainname: shop.example.com 10 | domainvalidationoptions: {shop.example.com: example.com, www.shop.example.com: example.com} 11 | subjectalternativenames: ["www.shop.example.com"] 12 | tags: {Name : Shop Certificate} -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/activedirectory.yml: -------------------------------------------------------------------------------- 1 | description: "Micorosft AD Servers" 2 | stackname: "ExampleStacks-Microsoft-AD" 3 | region: "ap-southeast-2" 4 | parameters: 5 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 6 | SecurityStack: {Description: Security Group Stack, Type: String, Default: ExampleStacks-SecurityGroups} 7 | mappings: {} 8 | resources: 9 | microsoftad: 10 | demotest: 11 | createalias: true 12 | enablesso: true 13 | name: demo.test 14 | password: examplepassword 15 | shortname: demo 16 | subnets: ["Internal1", "Internal2", "Internal3"] -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/alb.yml: -------------------------------------------------------------------------------- 1 | description: "Ecs Stack Sample" 2 | region: "ap-southeast-2" 3 | stackname: ExampleStacks-ECS 4 | parameters: 5 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 6 | SecurityStack: {Description: Security Group Stack, Type: String, Default: ExampleStacks-SecurityGroups} 7 | mappings: {} 8 | resources: 9 | alb: 10 | name: 11 | scheme: 12 | securitygroups: ["secgroup1", "secgroup2"] 13 | subnets: ["Internal1", "Internal2"] 14 | listeners: 15 | listener1: {port: } 16 | tags: 17 | targetgroup: 18 | hccode: 19 | hcpath: 20 | -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/dns_records.yml: -------------------------------------------------------------------------------- 1 | description: "Example DNS Records" 2 | stackname: "ExampleStacks-DNS-Records" 3 | region: "ap-southeast-2" 4 | parameters: 5 | DNSStack: {Description: DNS Stack, Type: String, Default: ExampleStacks-DNS-Zone} 6 | mappings: {} 7 | resources: 8 | route53_record: 9 | ExampleRecord: 10 | comment: Example Record 11 | zoneid: examplecom 12 | recordsets: 13 | - [test.example.com, A, 10.0.0.1, 10, 5, example-record] -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/efs.yml: -------------------------------------------------------------------------------- 1 | description: "Example EFS" 2 | stackname: "ExampleStacks-EFS" 3 | region: "ap-southeast-2" 4 | parameters: 5 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 6 | SecurityStack: {Description: Security Group Stack, Type: String, Default: ExampleStacks-SecurityGroups} 7 | mappings: {} 8 | resources: 9 | efs_filesystem: 10 | exampleefs: 11 | filesystemtags: {Name: example-efs} 12 | efs_mounttarget: 13 | exampleefsmt1: 14 | filesystemid: exampleefs 15 | subnetid: "Internal1" 16 | securitygroups: 17 | - EFSSecurity 18 | exampleefsmt2: 19 | filesystemid: exampleefs 20 | subnetid: "Internal2" 21 | securitygroups: 22 | - EFSSecurity 23 | exampleefsmt3: 24 | filesystemid: exampleefs 25 | subnetid: "Internal3" 26 | securitygroups: 27 | - EFSSecurity -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/elasticache.yml: -------------------------------------------------------------------------------- 1 | description: "Example elasticache" 2 | region: "ap-southeast-2" 3 | stackname: "ExampleStacks-Elasticache" 4 | parameters: 5 | SecurityStack: {Description: Security Group Stack, type: String, value: ExampleStacks-SecurityGroups} 6 | CacheSubnetStack: {Description: Cache Subnet Stack, Type: String, Default: ExampleStacks-ElastiCache-SubnetGroups} 7 | mappings: {} 8 | resources: 9 | elasticache: 10 | exampleCache: 11 | name: example-cache 12 | cacheSubnetGroup: elasticacheinternal 13 | secgroups: 14 | - ExampleRedisSecurity -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/elasticachesubnet.yml: -------------------------------------------------------------------------------- 1 | description: "ElastiCache Subnet Groups" 2 | stackname: "ExampleStacks-ElastiCache-SubnetGroups" 3 | region: "ap-southeast-2" 4 | parameters: 5 | VPCStack: {Description: VPC Stack, type: String, value: ExampleStacks-VPC} 6 | mappings: {} 7 | resources: 8 | elasticachesubnet: 9 | elasticacheinternal: 10 | name: ExampleStacks-ElastiCache-SubnetGroups 11 | description: Internal ElastiCache Subnet 12 | subnets: ["Internal1", "Internal2", "Internal3"] -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/iam_policies.yml: -------------------------------------------------------------------------------- 1 | region: ap-southeast-2 2 | description: "IAM Policies" 3 | stackname: ExampleStacks-IAM-Policies 4 | parameters: 5 | VPCStack: {Description: VPC Stack, type: String, value: ExampleStacks-VPC} 6 | mappings: {} 7 | resources: 8 | iam_policies: 9 | Policies: 10 | - Name: "God" 11 | Roles: ["roles-Roles-StackCreator"] 12 | Groups: [] 13 | PolicyDocument: | 14 | { 15 | "Effect": "Allow", 16 | "Action": "*", 17 | "Resource": "*" 18 | } -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/iam_roles.yml: -------------------------------------------------------------------------------- 1 | region: ap-southeast-2 2 | description: rolling 3 | stackname: ExampleStacks-IAM-Roles 4 | parameters: 5 | VPCStack: {Description: VPC Stack, type: String, value: ExampleStacks-VPC} 6 | mappings: {} 7 | resources: 8 | iam_roles: 9 | Roles: 10 | StackCreatorAssume: 11 | StackCreator: 12 | MFA_Required: "True" 13 | ReverseTrust: ["arn:aws:iam::012345678910:root"] 14 | DependsOn: "StackCreatorAssume" 15 | InstanceProfiles: 16 | BuildAgentRole: 17 | Type: ec2 18 | ManagedPolicys: ["AmazonEC2ContainerServiceFullAccess","AmazonEC2FullAccess","AmazonS3FullAccess","AmazonRoute53FullAccess"] 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/iam_users.yml: -------------------------------------------------------------------------------- 1 | region: ap-southeast-2 2 | description: "IAM User" 3 | stackname: ExampleStacks-IAM-Users 4 | parameters: 5 | VPCStack: {Description: VPC Stack, type: String, value: ExampleStacks-VPC} 6 | mappings: {} 7 | resources: 8 | iam_users: 9 | Users: 10 | IAM-F.Last: {Groups: ["StackCreators"]} 11 | IAM-First.Last: {Groups: ["StackCreators"]} 12 | Groups: 13 | StackCreators: {} 14 | 15 | -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/missing_stackname_test.yml: -------------------------------------------------------------------------------- 1 | description: "Test Account VPC" 2 | region: "ap-southeast-2" -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/rds-subnetgroups.yml: -------------------------------------------------------------------------------- 1 | description: "RDS Subnet Groups" 2 | stackname: "ExampleStacks-RDS-SubnetGroups" 3 | region: "ap-southeast-2" 4 | parameters: 5 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 6 | mappings: {} 7 | resources: 8 | rdssubnet: 9 | rdsinternal: 10 | description: Internal RDS Subnet 11 | subnets: ["Internal1", "Internal2", "Internal3"] 12 | tags: {Name : InternalRDSSubnet} -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/rds.yml: -------------------------------------------------------------------------------- 1 | description: "Test Database Instance" 2 | region: "ap-southeast-2" 3 | stackname: ExampleStacks-RDS 4 | parameters: 5 | VPCStack: {Description: VPC Stack, type: String, value: ExampleStacks-VPC} 6 | SecurityStack: {Description: Security Group Stack, type: String, value: ExampleStacks-SecurityGroups} 7 | RDSParasGroupStack: {Description: RDS Params Stack, type: String, value: ExampleStacks-RDS-ParamsGroup} 8 | RDSSubnetStack: {Description: RDS Subnet Stack, type: String, value: ExampleStacks-RDS-SubnetGroup} 9 | mappings: 10 | AMIRegionMap: 11 | us-east-1: { "32" : "ami-6411e20d", "64" : "ami-6411e20d"} 12 | us-west-1: { "32" : "ami-c9c7978c", "64" : "ami-6411e20d"} 13 | eu-west-1: { "32" : "ami-37c2f643", "64" : "ami-6411e20d"} 14 | ap-southeast-1: { "32" : "ami-66f28c34", "64" : "ami-6411e20d"} 15 | ap-northeast-1: { "32" : "ami-9c03a89d", "64" : "ami-6411e20d"} 16 | resources: 17 | rds: 18 | examplemysql: 19 | allocatedstorage: "100" 20 | allowmajorupgrade: true 21 | allowminorupgrade: true 22 | backupretention: "15" 23 | backupwindow: 24 | clustername: RandomMySQL 25 | engine: mysql 26 | engineversion: 5.5 27 | instanceclass: db.m3.xlarge 28 | iops: 100 29 | kmskeyid: kmsmaster 30 | rdsparamsgroup: 31 | rdssubnetgroup: 32 | multiaz: true 33 | masterusername: admin 34 | masterpassword: password 35 | monitorinterval: 5 36 | monitorarn: aws:arn:012345678901:/role/namespace/rolename 37 | port: 1443 38 | maintenancewindow: 39 | storagetype: standard 40 | secgroup: randommysql 41 | tags: {Name : SquidELB, Taking : care of moar business} -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/redshift.yml: -------------------------------------------------------------------------------- 1 | description: "ExampleStacks Demo Redshift Definition" 2 | stackname: "ExampleStacks-RS-Demo" 3 | region: "ap-southeast-2" 4 | secrets: 5 | DBPassword: shiafijijwf9398yap970afo8a0sfh0as 6 | parameters: 7 | IAMRoleStack: {Description: IAM Role Stack, Type: String, Default: ExampleStacks-IAM-Roles} 8 | KMSStack: {Description: KMS Keys Stack, Type: String, Default: ExampleStacks-KMS-RedShift} 9 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 10 | SecurityStack: {Description: Security Group Stack, Type: String, Default: ExampleStacks-SecurityGroups} 11 | RedshiftSubnetGroupStack: {Description: RDS Subnet Group Stack, Type: String, Default: ExampleStacks-RS-SubnetGroups} 12 | RedshiftParamsGroupStack: {Description: RS Params Group Stack, Type: String, Default: ExampleStacks-RS-ParamsGroup} 13 | mappings: {} 14 | resources: 15 | rds: 16 | testExampleStacks: 17 | allowupgrade: "150" 18 | automatedsnapshotretentionperiod: true 19 | az: true 20 | clusterparamsgroup: "15" 21 | clustersecgroups: "02:00-03:00" 22 | clustersubnetgroupname: Internal 23 | clustertype: multi-node 24 | clusterversion: 25 | dbname: ExampleStacks Test 26 | #eip: 27 | encrypted: true 28 | #hsmclientcertificateidentifier: 29 | #hsmconfigurationidentifier: 30 | iamroles: ["RSUserRole"] 31 | kmskeyid: RedshiftKey 32 | masterusername: master 33 | nodetype: dw.hs1.xlarge 34 | numberofnodes: 3 35 | #owneraccount: 36 | port: 5439 37 | maintenancewindow: "Sun:03:00-Sun:04:00" 38 | public: false 39 | #snapshotidentifier: 40 | #snapshotclusteridentifier 41 | vpcsecgroupid: ["RSBaselineSecGroup"] -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/s3_lambda.yml: -------------------------------------------------------------------------------- 1 | description: "S3 For Lambda Functions" 2 | region: "ap-southeast-2" 3 | stackname: "ExampleStacks-S3-Lambda-Functions" 4 | parameters: {} 5 | mappings: {} 6 | resources: 7 | s3: 8 | ExampleLambdaFuctions: 9 | name: example.lambda.functions 10 | accesscontrol: PublicRead 11 | versioning: false 12 | tags: { Name : Example Lambda Functions } -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/s3_policies.yml: -------------------------------------------------------------------------------- 1 | description: "S3 Policy Example" 2 | region: "ap-southeast-2" 3 | stackname: "ExampleStacks-S3-Policy-Example" 4 | parameters: {} 5 | mappings: {} 6 | resources: 7 | s3_policies: 8 | example.lambda.functions: 9 | policy: | 10 | "Bucket" : {"Ref" : "myExampleBucket"}, 11 | "PolicyDocument": { 12 | "Statement":[{ 13 | "Action":["s3:GetObject"], 14 | "Effect":"Allow", 15 | "Resource": "arn:aws:s3:::your-bucket-name/*" 16 | "Principal":"*", 17 | "Condition":{ 18 | "StringLike":{ 19 | "aws:Referer":[ 20 | "http://www.example.com/*", 21 | "http://example.com/*" 22 | ] 23 | } 24 | } 25 | }] 26 | } -------------------------------------------------------------------------------- /PyStacks/configs/user/region/aps2/securitygroups.yml: -------------------------------------------------------------------------------- 1 | description: "Example SecurityGroups" 2 | region: "ap-southeast-2" 3 | stackname: ExampleStacks-SecurityGroups 4 | parameters: 5 | CoreIpRange: {Description: Core, Type: String, Default: 10.0.0.0/8} 6 | ServerIpRange: {Description: Mi9 Equinix,Type: String,Default: 192.168.96.0/20} 7 | GlobalIpRange: {Description: Global IPRange, Type: String, Default: 0.0.0.0/0} 8 | DirectConnectIpRange: {Description: Direct Connect Peer IPRange, Type: String, Default: 169.254.247.0/24} 9 | VPCStack: {Description: VPC Stack, Type: String, Default: ExampleStacks-VPC} 10 | mappings: {} 11 | resources: 12 | securitygroups: 13 | SquidSecurity: 14 | sg_description: Squid Firewall Rules 15 | ingress: 16 | - [icmp,-1,-1,CoreIpRange] 17 | - [icmp,-1,-1,ServerIpRange] 18 | - [icmp,-1,-1,DirectConnectIpRange] 19 | - [tcp,22,22,CoreIpRange] 20 | - [tcp,53,53,CoreIpRange] 21 | - [udp,53,53,CoreIpRange] 22 | - [tcp,80,80,CoreIpRange] 23 | - [tcp,443,443,CoreIpRange] 24 | - [udp,123,123,CoreIpRange] 25 | egress: 26 | - [icmp,-1,-1,CoreIpRange] 27 | - [icmp,-1,-1,ServerIpRange] 28 | - [icmp,-1,-1,DirectConnectIpRange] 29 | - [tcp,53,53,GlobalIpRange] 30 | - [udp,53,53,GlobalIpRange] 31 | - [udp,123,123,GlobalIpRange] 32 | - [tcp,80,80,GlobalIpRange] 33 | - [tcp,443,443,GlobalIpRange] 34 | BindSecurity: 35 | sg_description: Bind Firewall Rules 36 | ingress: 37 | - [icmp,-1,-1,CoreIpRange] 38 | - [icmp,-1,-1,ServerIpRange] 39 | - [icmp,-1,-1,DirectConnectIpRange] 40 | - [tcp,22,22,CoreIpRange] 41 | - [tcp,22,22,ServerIpRange] 42 | - [tcp,53,53,CoreIpRange] 43 | - [udp,53,53,CoreIpRange] 44 | - [tcp,53,53,ServerIpRange] 45 | - [udp,53,53,ServerIpRange] 46 | egress: 47 | - [icmp,-1,-1,CoreIpRange] 48 | - [icmp,-1,-1,ServerIpRange] 49 | - [icmp,-1,-1,DirectConnectIpRange] 50 | - [tcp,80,80,GlobalIpRange] 51 | - [tcp,443,443,GlobalIpRange] 52 | - [tcp,53,53,GlobalIpRange] 53 | - [udp,53,53,GlobalIpRange] 54 | - [udp,123,123,GlobalIpRange] 55 | EFSSecurity: 56 | sg_description: TeamCityServer Rules 57 | ingress: 58 | - [tcp,22,22,ServerIpRange] 59 | - [tcp,2049,2049,ServerIpRange] 60 | - [udp,2049,2049,ServerIpRange] 61 | - [tcp,111,111,ServerIpRange] 62 | - [udp,111,111,ServerIpRange] 63 | - [tcp,4045,4045,ServerIpRange] 64 | - [udp,4045,4045,ServerIpRange] 65 | - [tcp,32765,32768,ServerIpRange] 66 | - [udp,32765,32768,ServerIpRange] 67 | egress: 68 | - [tcp,22,22,ServerIpRange] 69 | - [tcp,2049,2049,ServerIpRange] 70 | - [udp,2049,2049,ServerIpRange] 71 | - [tcp,111,111,ServerIpRange] 72 | - [udp,111,111,ServerIpRange] 73 | - [tcp,4045,4045,ServerIpRange] 74 | - [udp,4045,4045,ServerIpRange] 75 | - [tcp,32765,32768,ServerIpRange] 76 | - [udp,32765,32768,ServerIpRange] -------------------------------------------------------------------------------- /PyStacks/configs/user/region/global/test.zone: -------------------------------------------------------------------------------- 1 | ; PLEASE TO NOT REMOVE USED FOR TESTS 2 | ;Configuration for DNS Zone example.com 3 | 4 | example.com. 300 IN SOA r53.aws.amazon.com. hostmaster.r53.aws.amazon.com. ( 1481695633 3600 300 1814400 300 ) 5 | example.com. 300 IN A 8.8.8.8 6 | skypeweb.example.com. 300 IN A 8.8.8.8 7 | example.com. 300 IN NS ns.rackspace.com. 8 | example.com. 300 IN NS ns2.rackspace.com. 9 | example.com. 300 IN MX 10 cluster5.us.messagelabs.com. 10 | example.com. 300 IN MX 20 cluster5a.us.messagelabs.com. 11 | example.com. 300 IN TXT "MS=msexample" 12 | example.com. 300 IN TXT "EXAMPLE" 13 | example.com. 300 IN SRV 0 5 5060 sipserver.example.com. -------------------------------------------------------------------------------- /PyStacks/configs/user/region/global/test_parse.zone: -------------------------------------------------------------------------------- 1 | ; PLEASE TO NOT REMOVE USED FOR TESTS 2 | ;Configuration for DNS Zone example.com 3 | 4 | example.com. 300 IN SOA r53.aws.amazon.com. hostmaster.r53.aws.amazon.com. ( 1481695633 3600 300 1814400 300 ) 5 | example.com. 300 IN A 8.8.8.8 6 | skypeweb.example.com. 300 IN A 8.8.8.8 7 | example.com. 300 IN NS ns.rackspace.com. 8 | example.com. 300 IN NS ns2.rackspace.com. 9 | example.com. 300 IN MX 10 cluster5.us.messagelabs.com. 10 | example.com. 300 IN MX 20 cluster5a.us.messagelabs.com. 11 | example.com. 300 IN TXT "MS=msexample" 12 | example.com. 300 IN TXT "EXAMPLE" 13 | example.com. 300 IN SRV 0 5 5060 sipserver.example.com. -------------------------------------------------------------------------------- /PyStacks/contributors.txt: -------------------------------------------------------------------------------- 1 | Marley Venerosa 2 | Ian McKay 3 | Ben Boyter 4 | Josh Wales 5 | David Wales 6 | Irena Kuntsevich 7 | Owen Kelly 8 | Rob Amos 9 | Stewart Leach 10 | Tim Elson 11 | Liam Dixon 12 | Damian Steele 13 | Michael Ransley 14 | -------------------------------------------------------------------------------- /PyStacks/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='PyStacks', 5 | version='0.1', 6 | description='AWS automation tool.', 7 | url='https://github.com/KablamoOSS/PyStacks.git', 8 | author='DevOps @ Kablamo', 9 | author_email='devops@kablamo.com.au', 10 | license='MIT', 11 | packages=['PyStacks'], 12 | install_requires=[ 13 | 'boto3==1.4.7', 14 | 'botocore>=1.8.26', 15 | 'PyYAML==3.12', 16 | 'invoke==0.14.0', 17 | 'Jinja2==2.8', 18 | 'pynt==0.8.1', 19 | 'demjson==2.2.3', 20 | 'dnspython==1.15.0', 21 | 'jsonschema==2.6.0', 22 | 'deepdiff==3.3.0', 23 | ], 24 | scripts=['bin/pystacks', 'bin/get_pystacks_location.py'], 25 | zip_safe=False, 26 | ) 27 | -------------------------------------------------------------------------------- /PyStacks/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KablamoOSS/PyStacks/001feefad093499face7918933fa0bba24a05c8c/PyStacks/test/__init__.py -------------------------------------------------------------------------------- /PyStacks/test/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KablamoOSS/PyStacks/001feefad093499face7918933fa0bba24a05c8c/PyStacks/test/templates/__init__.py -------------------------------------------------------------------------------- /PyStacks/test/templates/test_acm.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_ACM(self): 9 | resources = { 10 | "certificatemanager": { 11 | "shopkablamocomau": { 12 | "domainname": "shop.kablamo.com.au", 13 | "domainvalidationoptions": { 14 | "shop.kablamo.com.au": "kablamo.com.au", 15 | "www.shop.kablamo.com.au": "kablamo.com.au" 16 | }, 17 | "subjectalternativenames": [ 18 | "www.shop.kablamo.com.au" 19 | ], 20 | "tags": { 21 | "Name": "Shop Certificate" 22 | } 23 | } 24 | } 25 | } 26 | expected = { 27 | "shopkablamocomau": { 28 | "Properties": { 29 | "DomainName": "shop.kablamo.com.au", 30 | "DomainValidationOptions": [ 31 | { 32 | "DomainName": "www.shop.kablamo.com.au", 33 | "ValidationDomain": "kablamo.com.au" 34 | }, 35 | { 36 | "DomainName": "shop.kablamo.com.au", 37 | "ValidationDomain": "kablamo.com.au" 38 | } 39 | ], 40 | "SubjectAlternativeNames": [ 41 | "www.shop.kablamo.com.au" 42 | ], 43 | "Tags": [ 44 | { 45 | "Key": "Name", 46 | "Value": "Shop Certificate" 47 | } 48 | ] 49 | }, 50 | "Type": "AWS::CertificateManager::Certificate" 51 | } 52 | } 53 | 54 | actual = templateCF(resources, 'resources') 55 | self.assertDictEqual(actual, expected) 56 | 57 | 58 | if __name__ == '__main__': 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_athena_namedquery.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_Athena_NamedQuery(self): 9 | resources = { 10 | "athena_namedquery": { 11 | "samplequery": { 12 | "description": "samplequery", 13 | "querystring": "SELECT workflowname, AVG(activitytaskstarted) AS AverageWorkflow FROM swfmetadata WHERE year='17' AND GROUP BY workflowname ORDER BY AverageWorkflow DESC LIMIT 10", 14 | "database": "sampledb", 15 | "name": "SampleQuery" 16 | } 17 | } 18 | } 19 | expected = { 20 | "samplequery": { 21 | "Properties": { 22 | "Database": "sampledb", 23 | "Description": "samplequery", 24 | "Name": "SampleQuery", 25 | "QueryString": "SELECT workflowname, AVG(activitytaskstarted) AS AverageWorkflow FROM swfmetadata WHERE year='17' AND GROUP BY workflowname ORDER BY AverageWorkflow DESC LIMIT 10" 26 | }, 27 | "Type": "AWS::Athena::NamedQuery" 28 | } 29 | } 30 | 31 | actual = templateCF(resources, 'resources') 32 | self.assertDictEqual(actual, expected) 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_config_rule.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_ConfigRule(self): 9 | resources = { 10 | 'config_rule': { 11 | 'ConfigPublicPortCheck': { 12 | 'name': 'ConfigPublicPortCheck', 13 | 'description': 'Check for Public Ports on Security Groups', 14 | 'inputparams': { 15 | "AllowedPorts": [80, 443] 16 | }, 17 | 'maxfrequency': 'One_Hour', 18 | 'source': { 19 | 'owner': 'CUSTOM_LAMBDA', 20 | 'details': { 21 | 'aws.config': { 22 | 'frequency': 'One_Hour', 23 | 'messagetype': 'ScheduledNotification' 24 | } 25 | }, 26 | 'sourceid': 'configpublicportscheck' 27 | } 28 | } 29 | } 30 | } 31 | expected = { 32 | "ConfigPublicPortCheck": { 33 | "Properties": { 34 | "ConfigRuleName": "ConfigPublicPortCheck", 35 | "Description": "Check for Public Ports on Security Groups", 36 | "InputParameters": { 37 | "AllowedPorts": [ 38 | 80, 39 | 443 40 | ] 41 | }, 42 | "MaximumExecutionFrequency": "One_Hour", 43 | "Source": { 44 | "Owner": "CUSTOM_LAMBDA", 45 | "SourceDetails": [ 46 | { 47 | "EventSource": "aws.config", 48 | "MaximumExecutionFrequency": "One_Hour", 49 | "MessageType": "ScheduledNotification" 50 | } 51 | ], 52 | "SourceIdentifier": "configpublicportscheck" 53 | } 54 | }, 55 | "Type": "AWS::Config::ConfigRule" 56 | } 57 | } 58 | 59 | actual = templateCF(resources, 'resources') 60 | self.assertDictEqual(actual, expected) 61 | 62 | 63 | if __name__ == '__main__': 64 | unittest.main() 65 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_dms.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_DMSInstance(self): 9 | resources = { 10 | 'dms_instance': { 11 | 'myDMS': { 12 | 'replicationinstanceclass': 'dms.t2.small' 13 | }, 14 | }, 15 | } 16 | expected = { 17 | "myDMSInstance": { 18 | "Type": "AWS::DMS::ReplicationInstance", 19 | "Properties": { 20 | "ReplicationInstanceClass": "dms.t2.small" 21 | } 22 | } 23 | } 24 | 25 | actual = templateCF(resources, 'resources') 26 | self.assertDictEqual(actual, expected) 27 | 28 | def test_templateCF_DMSSubnet(self): 29 | resources = { 30 | 'dms_subnetgroup': { 31 | 'TestDMSSubnetGroup': { 32 | 'description': 'Some Description...', 33 | 'subnets': [ 34 | 'testsubnet1', 35 | 'testsubnet2' 36 | ], 37 | 'tags': { 38 | 'testtagkey1': 'testtagval1', 39 | 'testtagkey2': 'testtagval2' 40 | } 41 | } 42 | } 43 | } 44 | expected = { 45 | 'TestDMSSubnetGroup': { 46 | 'Type': 'AWS::DMS::ReplicationSubnetGroup', 47 | 'Properties': { 48 | 'ReplicationSubnetGroupIdentifier': 'TestDMSSubnetGroup', 49 | 'ReplicationSubnetGroupDescription': 'Some Description...', 50 | 'SubnetIds': [ 51 | { 52 | "Fn::ImportValue": { 53 | "Fn::Sub": [ 54 | "${VPCStack}-Subnet-testsubnet1", 55 | { 56 | "VPCStack": { 57 | "Ref": "VPCStack" 58 | } 59 | } 60 | ] 61 | } 62 | }, 63 | { 64 | "Fn::ImportValue": { 65 | "Fn::Sub": [ 66 | "${VPCStack}-Subnet-testsubnet2", 67 | { 68 | "VPCStack": { 69 | "Ref": "VPCStack" 70 | } 71 | } 72 | ] 73 | } 74 | } 75 | ], 76 | 'Tags': [ 77 | { 78 | 'Key': 'testtagkey1', 79 | 'Value': 'testtagval1' 80 | }, 81 | { 82 | 'Key': 'testtagkey2', 83 | 'Value': 'testtagval2' 84 | } 85 | ] 86 | } 87 | } 88 | } 89 | 90 | actual = templateCF(resources, 'resources') 91 | self.assertDictEqual(actual, expected) 92 | 93 | 94 | if __name__ == '__main__': 95 | unittest.main() 96 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_dynamodb_tables.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_GenericDynamoDbTables(self): 9 | resources = { 10 | 'dynamodb_tables': { 11 | 'testTable': { 12 | 'name': 'testTable', 13 | 'attributes': [ 14 | { 15 | 'name': 'keyAttribute', 16 | 'type': 'S' 17 | } 18 | ], 19 | 'key_schema': [ 20 | { 21 | 'name': 'keyAttribute', 22 | 'type': 'HASH' 23 | }, 24 | ], 25 | 'throughput': { 26 | 'read_units': 10, 27 | 'write_units': 1 28 | }, 29 | 'stream': { 30 | 'type': "NEW_IMAGE" 31 | }, 32 | }, 33 | }, 34 | } 35 | expected = { 36 | "testTable": { 37 | "Type": "AWS::DynamoDB::Table", 38 | "Properties": { 39 | "AttributeDefinitions": [ 40 | { 41 | "AttributeName": "keyAttribute", 42 | "AttributeType": "S" 43 | }, 44 | ], 45 | "KeySchema": [ 46 | { 47 | "AttributeName": "keyAttribute", 48 | "KeyType": "HASH" 49 | }, 50 | ], 51 | "ProvisionedThroughput": { 52 | "ReadCapacityUnits": "10", 53 | "WriteCapacityUnits": "1" 54 | }, 55 | "StreamSpecification": { 56 | "StreamViewType": "NEW_IMAGE" 57 | }, 58 | "TableName": "testTable" 59 | } 60 | } 61 | } 62 | 63 | actual = templateCF(resources, 'resources') 64 | self.assertDictEqual(actual, expected) 65 | 66 | 67 | if __name__ == '__main__': 68 | unittest.main() 69 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_eip.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_EIP(self): 9 | resources = { 10 | 'eip': { 11 | 'test1', 12 | 'test2.3-4' 13 | } 14 | } 15 | expected = { 16 | 'test1EIP': { 17 | 'Type': 'AWS::EC2::EIP', 18 | 'Properties': { 19 | 'InstanceId': {'Ref': 'test1'}, 20 | 'Domain': 'vpc' 21 | } 22 | }, 23 | 'test234EIP': { 24 | 'Type': 'AWS::EC2::EIP', 25 | 'Properties': { 26 | 'InstanceId': {'Ref': 'test234'}, 27 | 'Domain': 'vpc' 28 | } 29 | } 30 | } 31 | 32 | actual = templateCF(resources, 'resources') 33 | self.assertDictEqual(actual, expected) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_events.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | EVENT_NAME = 'TestEventName' 6 | 7 | 8 | class TestTemplate(unittest.TestCase): 9 | 10 | def test_templateCF_TestEvent(self): 11 | target = { 12 | 'id': 'fooId', 13 | 'arn': 'fooRef', 14 | } 15 | resources = { 16 | 'events': { 17 | 'testevent': { 18 | 'name': EVENT_NAME, 19 | 'description': 'test description', 20 | 'schedule': 'rate(10 minutes)', 21 | 'targets': [target], 22 | } 23 | } 24 | } 25 | testevent = resources['events']['testevent'] 26 | expected = { 27 | 'testevent': { 28 | 'Type': 'AWS::Events::Rule', 29 | 'Properties': { 30 | 'ScheduleExpression': testevent['schedule'], 31 | 'Targets': [ 32 | { 33 | 'Id': target['id'], 34 | 'Arn': {'Fn::GetAtt': [target['arn'], "Arn"]}, 35 | } 36 | ], 37 | 'Description': testevent['description'], 38 | 'Name': testevent['name'], 39 | }, 40 | } 41 | } 42 | actual = templateCF(resources, 'resources') 43 | self.assertDictEqual(actual, expected) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_kms.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_KMS(self): 9 | resources = { 10 | 'kms': { 11 | 'testkey': { 12 | 'description': 'testkeydescription', 13 | 'enabled': True, 14 | 'rotation': True, 15 | 'policy': '{ "somejsonobj": "something" }', 16 | 'aliasname': 'testkeyalias' 17 | } 18 | } 19 | } 20 | expected = { 21 | 'testkey': { 22 | 'Type': 'AWS::KMS::Key', 23 | 'Properties': { 24 | 'Description': 'testkeydescription', 25 | 'Enabled': 'true', 26 | 'EnableKeyRotation': 'true', 27 | 'KeyPolicy': { 28 | 'somejsonobj': 'something' 29 | } 30 | } 31 | }, 32 | 'testkeyAlias': { 33 | 'Type': 'AWS::KMS::Alias', 34 | 'Properties': { 35 | 'AliasName': 'alias/testkeyalias', 36 | 'TargetKeyId': { 37 | 'Ref': 'testkey' 38 | } 39 | } 40 | } 41 | } 42 | 43 | actual = templateCF(resources, 'resources') 44 | self.assertDictEqual(actual, expected) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_lambda.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_GenericLambda(self): 9 | resources = { 10 | 'lambda': { 11 | 'testLambda': { 12 | 'code': { 13 | 's3bucket': 'testS3Bucket', 14 | 'key': 's3-key', 15 | }, 16 | 'description': 'test description', 17 | 'environment': { 18 | 'envvar': 'value', 19 | }, 20 | 'functionName': 'lambdaName', 21 | 'handler': 'main.Handle', 22 | 'memorySize': 256, 23 | 'role': 'testRole', 24 | 'runTime': 'python2.7', 25 | 'timeout': 30, 26 | 'permission': 'testPerm', 27 | 'vpcConfig': { 28 | 'securityGroups': [ 29 | 'SquidSecurity', 30 | ], 31 | 'subnetIds': [ 32 | 'Internal1', 33 | 'Internal2', 34 | 'Internal3', 35 | ], 36 | }, 37 | }, 38 | }, 39 | } 40 | expected = { 41 | "testLambda": { 42 | "Type": "AWS::Lambda::Function", 43 | "Properties": { 44 | "Handler": "main.Handle", 45 | "Description": "test description", 46 | "Code": { 47 | "S3Bucket": "testS3Bucket", 48 | "S3Key": "s3-key" 49 | }, 50 | "FunctionName": "lambdaName", 51 | "MemorySize": "256", 52 | "Timeout": "30", 53 | "Environment": { 54 | "Variables": { 55 | "envvar": "value" 56 | } 57 | }, 58 | "Role": "testRole", 59 | "VpcConfig": { 60 | "SecurityGroupIds": [ 61 | {"Fn::ImportValue": {"Fn::Sub": [ 62 | "${SecurityStack}-SecGroup-SquidSecurity", {"SecurityStack": {"Ref": "SecurityStack"}}]}} 63 | ], 64 | "SubnetIds": [ 65 | {"Fn::ImportValue": {"Fn::Sub": [ 66 | "${VPCStack}-Subnet-Internal1", {"VPCStack": {"Ref": "VPCStack"}}]}}, 67 | {"Fn::ImportValue": {"Fn::Sub": [ 68 | "${VPCStack}-Subnet-Internal2", {"VPCStack": {"Ref": "VPCStack"}}]}}, 69 | {"Fn::ImportValue": {"Fn::Sub": [ 70 | "${VPCStack}-Subnet-Internal3", {"VPCStack": {"Ref": "VPCStack"}}]}} 71 | ] 72 | } 73 | } 74 | } 75 | } 76 | 77 | actual = templateCF(resources, 'resources') 78 | self.assertDictEqual(actual, expected) 79 | 80 | 81 | if __name__ == '__main__': 82 | unittest.main() 83 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_lambda_events.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_GenericLambdaEvents(self): 9 | resources = { 10 | 'lambda_events': { 11 | 'testLambdaEvent': { 12 | 'batchsize': '100', 13 | 'enabled': 'true', 14 | 'sourcearn': 'someArn', 15 | 'lambda': 'lambdaFunctionName', 16 | 'startingposition': "LATEST", 17 | }, 18 | }, 19 | } 20 | expected = { 21 | "testLambdaEvent": { 22 | "Type": "AWS::Lambda::EventSourceMapping", 23 | "Properties": { 24 | "BatchSize": "100", 25 | "Enabled": "true", 26 | "EventSourceArn": "someArn", 27 | "FunctionName": "lambdaFunctionName", 28 | "StartingPosition": "LATEST" 29 | } 30 | } 31 | } 32 | 33 | actual = templateCF(resources, 'resources') 34 | self.maxDiff = None 35 | self.assertDictEqual(actual, expected) 36 | 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_microsoftad.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_MicrosoftAD(self): 9 | resources = { 10 | 'microsoftad': { 11 | 'testad': { 12 | 'createalias': True, 13 | 'enablesso': True, 14 | 'name': 'example.com', 15 | 'password': 'supers3cur3', 16 | 'shortname': 'ABC', 17 | 'subnets': [ 18 | 'subnet1', 19 | 'subnet2' 20 | ] 21 | } 22 | } 23 | } 24 | expected = { 25 | 'testad': { 26 | 'Type': 'AWS::DirectoryService::MicrosoftAD', 27 | 'Properties': { 28 | 'CreateAlias': 'true', 29 | 'EnableSso': 'true', 30 | 'Name': 'example.com', 31 | 'Password': 'supers3cur3', 32 | 'ShortName': 'ABC', 33 | 'VpcSettings': { 34 | 'SubnetIds': [ 35 | { 36 | 'Fn::ImportValue': { 37 | 'Fn::Sub': [ 38 | '${VPCStack}-Subnet-subnet1', 39 | { 40 | 'VPCStack': { 41 | 'Ref': 'VPCStack' 42 | } 43 | } 44 | ] 45 | } 46 | }, 47 | { 48 | 'Fn::ImportValue': { 49 | 'Fn::Sub': [ 50 | '${VPCStack}-Subnet-subnet2', 51 | { 52 | 'VPCStack': { 53 | 'Ref': 'VPCStack' 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | ], 60 | 'VpcId': { 61 | 'Fn::ImportValue': { 62 | 'Fn::Sub': [ 63 | '${VPCStack}-VPC-VPCid', 64 | { 65 | 'VPCStack': { 66 | 'Ref': 'VPCStack' 67 | } 68 | } 69 | ] 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | actual = templateCF(resources, 'resources') 78 | self.assertDictEqual(actual, expected) 79 | 80 | 81 | if __name__ == '__main__': 82 | unittest.main() 83 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_s3.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_S3(self): 9 | resources = { 10 | 's3': { 11 | 'S3Bucket': { 12 | 'name': 'stuff.holder', 13 | 'accesscontrol': 'PublicRead', 14 | 'versioning': True, 15 | 'tags': { 16 | 'Name': 'Api' 17 | }, 18 | 'notices': { 19 | 'lamda': [{ 20 | 'event': 's3:ObjectCreated:*', 21 | 'function': 'somelambdaarn' 22 | }] 23 | } 24 | } 25 | }, 26 | 's3_policies': { 27 | 'S3BucketPolicies': { 28 | 'policy': '"what": "on earth"' 29 | } 30 | } 31 | } 32 | expected = { 33 | 'S3BucketPolicies': { 34 | 'Type': 'AWS::S3::BucketPolicy', 35 | 'Properties': { 36 | 'what': 'on earth' 37 | } 38 | }, 39 | 'S3Bucket': { 40 | 'Type': 'AWS::S3::Bucket', 41 | 'Properties': { 42 | 'AccessControl': 'PublicRead', 43 | 'NotificationConfiguration': { 44 | 'LambdaConfigurations': [ 45 | { 46 | 'Event': 's3:ObjectCreated:*', 47 | 'Function': 'somelambdaarn' 48 | } 49 | ] 50 | }, 51 | 'VersioningConfiguration': { 52 | 'Status': 'Enabled' 53 | }, 54 | 'BucketName': 'stuff.holder', 55 | 'Tags': [ 56 | { 57 | 'Key': 'Name', 58 | 'Value': 'Api' 59 | } 60 | ] 61 | } 62 | } 63 | } 64 | self.maxDiff = 'None' 65 | actual = templateCF(resources, 'resources') 66 | self.assertDictEqual(actual, expected) 67 | 68 | 69 | if __name__ == '__main__': 70 | unittest.main() 71 | -------------------------------------------------------------------------------- /PyStacks/test/templates/test_sqs.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyStacks.PyStacks.template import templateCF 4 | 5 | 6 | class TestTemplate(unittest.TestCase): 7 | 8 | def test_templateCF_SQS(self): 9 | resources = { 10 | 'sqs': { 11 | 'testQueue': { 12 | 'name': 'testQueueName', 13 | 'delay': 20, 14 | 'maxsize': 10, 15 | 'retention': 1024, 16 | 'waittime': 30, 17 | 'redirectpolicy': { 18 | 'deadletterqueue': 'abc', 19 | 'count': 3 20 | }, 21 | 'visibilitytimeout': 60 22 | } 23 | } 24 | } 25 | expected = { 26 | "testQueue": { 27 | "Type": "AWS::SQS::Queue", 28 | "Properties": { 29 | "DelaySeconds": "20", 30 | "MaximumMessageSize": "10", 31 | "MessageRetentionPeriod": "1024", 32 | "QueueName": "testQueueName", 33 | "ReceiveMessageWaitTimeSeconds": "30", 34 | "RedrivePolicy": { 35 | "deadLetterTargetArn": {"Fn::GetAtt": ["abc", "Arn"]}, 36 | "maxReceiveCount": "3" 37 | }, 38 | "VisibilityTimeout": "60" 39 | } 40 | } 41 | } 42 | 43 | actual = templateCF(resources, 'resources') 44 | self.assertDictEqual(actual, expected) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /PyStacks/test/test_cloudformation_helpers.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dateutil.tz import tzlocal 3 | import datetime 4 | from PyStacks.PyStacks.cloudformation_helpers import load_cf_params_from_string, load_stack_file, display_cf_events 5 | 6 | 7 | class TestConfig(unittest.TestCase): 8 | def test_load_cf_params_from_string_value_error(self): 9 | with self.assertRaises(IndexError): 10 | load_cf_params_from_string("bar=baz,foo:far") 11 | 12 | def test_load_cf_params_from_string(self): 13 | actual = load_cf_params_from_string("bar=baz,foo=far") 14 | self.assertTrue(len(actual) == 2) 15 | 16 | def test_load_cf_params_from_string_previous(self): 17 | actual = load_cf_params_from_string("bar=baz,foo=UsePreviousValue") 18 | self.assertTrue(actual == [{'ParameterValue': 'baz', 'ParameterKey': 'bar'}, {'UsePreviousValue': True, 'ParameterKey': 'foo'}]) 19 | 20 | def test_load_stack_file_io_error(self): 21 | with self.assertRaises(IOError): 22 | load_stack_file("missing_stack_file", "ap-southeast-2") 23 | 24 | def test_display_cf_events(self): 25 | events = [{u'StackId': 'arn:aws:cloudformation:ap-southeast-2:686755470412:stack/googlechat-gateway-dev/55410590-991f-11e7-ba9a-50fae94fac4a', u'EventId': '901386f0-9cd7-11e7-9320-50fae94fac82', u'ResourceStatus': 'UPDATE_ROLLBACK_COMPLETE', u'ResourceType': 'AWS::CloudFormation::Stack', u'Timestamp': datetime.datetime(2017, 9, 19, 1, 12, 10, 680000, tzinfo=tzlocal()), u'StackName': 'googlechat-gateway-dev', u'PhysicalResourceId': 'arn:aws:cloudformation:ap-southeast-2:686755470412:stack/googlechat-gateway-dev/55410590-991f-11e7-ba9a-50fae94fac4a', u'LogicalResourceId': 'googlechat-gateway-dev'}, {u'StackId': 'arn:aws:cloudformation:ap-southeast-2:686755470412:stack/googlechat-gateway-dev/55410590-991f-11e7-ba9a-50fae94fac4a', u'EventId': 'AGDeployment-e6b6d880-9aba-4dbb-8061-f89a4801f13e', u'ResourceStatus': 'DELETE_COMPLETE', u'ResourceType': 'AWS::ApiGateway::Deployment', u'Timestamp': datetime.datetime(2017, 9, 19, 1, 12, 10, 72000, tzinfo=tzlocal()), u'StackName': 'googlechat-gateway-dev', u'PhysicalResourceId': '7u0xsk', u'LogicalResourceId': 'AGDeployment'}, {u'StackId': 'arn:aws:cloudformation:ap-southeast-2:686755470412:stack/googlechat-gateway-dev/55410590-991f-11e7-ba9a-50fae94fac4a', u'EventId': 'AGDeployment-2ebf0b9b-e526-4240-8a40-732c6d8ce29c', u'ResourceStatus': 'DELETE_IN_PROGRESS', u'ResourceType': 'AWS::ApiGateway::Deployment', u'Timestamp': datetime.datetime(2017, 9, 19, 1, 12, 9, 555000, tzinfo=tzlocal()), u'StackName': 'googlechat-gateway-dev', u'PhysicalResourceId': '7u0xsk', u'LogicalResourceId': 'AGDeployment'}] 26 | actual = display_cf_events(events) 27 | self.assertTrue(actual) 28 | 29 | def test_display_cf_events_zero(self): 30 | actual = display_cf_events([]) 31 | self.assertFalse(actual) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /PyStacks/test/test_configs.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import json 3 | import os 4 | 5 | from PyStacks.PyStacks.configs import loadConfig 6 | 7 | 8 | class TestConfig(unittest.TestCase): 9 | 10 | def test_loadConfig_region_exist_file_not_expect_exception(self): 11 | with self.assertRaises(IOError): 12 | loadConfig(file_name='THISFILESHOULDNOTEXIST', region='aps2') 13 | 14 | def test_loadConfig_region_not_exist_expect_exception(self): 15 | with self.assertRaises(IOError): 16 | loadConfig(file_name='vpc', region='NOTREGION') 17 | 18 | def test_loadConfig_region_file_exist_expect_value(self): 19 | actual = loadConfig(file_name='vpc', region='aps2') 20 | self.assertIsNotNone(actual) 21 | 22 | def test_loadConfig_all_types(self): 23 | path = './PyStacks/configs/user/region/aps2/' 24 | types = [file_name.replace('.yml', '') for file_name in os.listdir(path) if file_name != 'environment.yml'] 25 | types = [x for x in types if 'missing_stackname' not in x] 26 | 27 | for file_name in types: 28 | actual = loadConfig(file_name=file_name, region='aps2') 29 | self.assertIsNotNone(actual) 30 | self.assertTrue(len(json.dumps(actual)) > 50) 31 | 32 | def test_loadConfig_no_stack_name_exception(self): 33 | with self.assertRaises(ValueError) as err: 34 | loadConfig(file_name='missing_stackname_test', region='aps2') 35 | self.assertTrue( 36 | 'Expected value "stackname" not in template' in str(err.exception)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /PyStacks/test/test_ec2tasks.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from mock import MagicMock 4 | 5 | from PyStacks.PyStacks.ec2tasks import ec2tasks 6 | 7 | 8 | class TestEC2TasksSetup(unittest.TestCase): 9 | def setUp(self): 10 | self.mocksession = MagicMock() 11 | self.mockec2Client = MagicMock() 12 | 13 | self.mocksession.client.return_value = self.mockec2Client 14 | 15 | self.ec2tasks = ec2tasks() 16 | 17 | 18 | class TestEC2Tasks(TestEC2TasksSetup): 19 | def test_filter(self): 20 | assertfilters = [{"Name": "vpc-id", "Values": ["vpc-73de4917"]}] 21 | testfilter = self.ec2tasks.buildFilters("vpc-id", ["vpc-73de4917"]) 22 | self.assertEquals(testfilter, assertfilters) 23 | 24 | def test_filters(self): 25 | assertfilters = [{"Name": "vpc-id", "Values": ["vpc-73de4917", "vpc-73de4918"]}] 26 | testfilter = self.ec2tasks.buildFilters("vpc-id", ["vpc-73de4917", "vpc-73de4918"]) 27 | self.assertEquals(testfilter, assertfilters) 28 | 29 | def test_routelist(self): 30 | routelist = { 31 | "Routes": [ 32 | { 33 | "DestinationCidrBlock": "172.31.0.0/16", 34 | "GatewayId": "local", 35 | "Origin": "CreateRouteTable", 36 | "State": "active" 37 | }, 38 | { 39 | "DestinationCidrBlock": "0.0.0.0/0", 40 | "GatewayId": "igw-6d253308", 41 | "Origin": "CreateRoute", 42 | "State": "active" 43 | } 44 | ] 45 | } 46 | assertroutelist = ["172.31.0.0/16", "0.0.0.0/0"] 47 | testroutelist = self.ec2tasks.buildRoutelist(routelist) 48 | self.assertEquals(testroutelist, assertroutelist) 49 | 50 | def test_routelist_empty(self): 51 | routelist = { 52 | "Routes": [ 53 | ] 54 | } 55 | assertroutelist = [] 56 | testroutelist = self.ec2tasks.buildRoutelist(routelist) 57 | self.assertEquals(testroutelist, assertroutelist) 58 | 59 | def test_vpcpeeroptions_true(self): 60 | noop = True 61 | assertoptions = {'AllowDnsResolutionFromRemoteVpc': True} 62 | testoptions = self.ec2tasks.buildVPCPeerOptions(noop) 63 | self.assertEquals(testoptions, assertoptions) 64 | 65 | def test_vpcpeeroptions_false(self): 66 | noop = False 67 | assertoptions = {'AllowDnsResolutionFromRemoteVpc': False} 68 | testoptions = self.ec2tasks.buildVPCPeerOptions(noop) 69 | self.assertEquals(testoptions, assertoptions) 70 | 71 | def test_vpcpeeroptions_default(self): 72 | assertoptions = {'AllowDnsResolutionFromRemoteVpc': True} 73 | testoptions = self.ec2tasks.buildVPCPeerOptions() 74 | self.assertEquals(testoptions, assertoptions) 75 | -------------------------------------------------------------------------------- /PyStacks/test/test_iot.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from mock import MagicMock 3 | 4 | from PyStacks.PyStacks.iot import IoTAPI 5 | 6 | 7 | class TestIot(unittest.TestCase): 8 | 9 | def test_create_thing(self): 10 | pass 11 | 12 | def test_create_keys_and_certificate(self): 13 | pass 14 | 15 | def test_attach_thing_principal(self): 16 | pass 17 | 18 | def test_attach_policy(self): 19 | pass 20 | -------------------------------------------------------------------------------- /PyStacks/test/test_output.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from hypothesis import given 3 | from hypothesis.strategies import text 4 | 5 | from PyStacks.PyStacks.output import boxwrap 6 | from PyStacks.PyStacks.output import writecolour 7 | from PyStacks.PyStacks.output import whalesay 8 | from PyStacks.PyStacks.output import piesay 9 | 10 | 11 | class TestOutput(unittest.TestCase): 12 | 13 | def test_boxwrap(self): 14 | result = boxwrap('this is some text') 15 | self.assertEqual(result, '+------------------------+\n| 1. this is some text |\n+------------------------+') 16 | 17 | def test_boxwrap_nolinenos(self): 18 | result = boxwrap('this is some text', linenumbers=False) 19 | self.assertEqual(result, '+--------------------+\n| this is some text |\n+--------------------+') 20 | 21 | def test_whalesay(self): 22 | result = whalesay('Whale, whale whale, whats all this then?') 23 | self.assertTrue('+\n| Whale, whale whale, whats all this then? |\n+' in result) 24 | 25 | def test_piesay(self): 26 | result = piesay('A stack of pies') 27 | self.assertTrue('stack of pies' in result) 28 | 29 | def test_colour(self): 30 | result = writecolour('VGVycnkgd2FzIGhlcmU=') 31 | self.assertTrue('VGVycnkgd2FzIGhlcmU=' in result) 32 | 33 | @given(text()) 34 | def test_decode_inverts_encode(self, s): 35 | assert '""""""""""""""""' in whalesay(s) 36 | 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /PyStacks/test/test_verification.py: -------------------------------------------------------------------------------- 1 | from mock import MagicMock 2 | 3 | import PyStacks.PyStacks.verification as verification 4 | 5 | 6 | class TestVerification: 7 | 8 | def test_ensure_http_success(self): 9 | pass 10 | -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | pipelines: 2 | branches: 3 | master: 4 | - step: 5 | name: Run tests 6 | image: python:2.7.14 7 | script: 8 | - python --version 9 | - echo "Testing" 10 | - pip install requests # for slack_alert 11 | - bash ci/get_commit_json.sh > /tmp/commit.json 12 | - pip install -r requirements_test.txt 13 | - pytest && echo "Test pass" || (python ci/slack_alert.py; exit 1) 14 | #- echo "Packaging" 15 | #- pip install twine wheel 16 | #- bash ci/build_deploy.sh # Deploy to pip 17 | -------------------------------------------------------------------------------- /build_local.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t pystacks -f Dockerfile . 3 | -------------------------------------------------------------------------------- /ci/build_deploy.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if [[ -z "$PYPI_USERNAME" || -z "$PYPI_PASSWORD" || -z "$PYPI_URL" ]]; then 4 | echo "You must set PYPI_USERNAME, PYPI_PASSWORD, and PYPI_URL to run this script" 5 | exit 1 6 | fi 7 | echo "Required environment variables are set ..." 8 | 9 | SHORT_HASH=$(git rev-parse --short HEAD) 10 | BUILD_VERSION=$(cat version.txt).${BITBUCKET_BUILD_NUMBER} 11 | echo $BUILD_VERSION > version.txt 12 | BUILD_VERSION=${BUILD_VERSION}-${SHORT_HASH} 13 | echo "Building with version number: $BUILD_VERSION" 14 | 15 | echo "Setting up pypi connection info ..." 16 | cat << EOF > /root/.pypirc 17 | [distutils] 18 | index-servers=pypi 19 | 20 | [pypi] 21 | repository=${PYPI_URL} 22 | username=${PYPI_USERNAME} 23 | password=${PYPI_PASSWORD} 24 | EOF 25 | 26 | echo "Building pip package ..." 27 | python setup.py sdist bdist_wheel # Building package 28 | echo "Uploading to pypi ($PYPI_URL) ..." 29 | twine upload dist/* # Uploading to pypi 30 | -------------------------------------------------------------------------------- /ci/code_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -x 3 | 4 | # This file is the entrypoint for tests for local, docker and ci so be sure if you modify it that it works in all! 5 | 6 | # If running locally we don't need to step into the pystacks directory 7 | if [ $# -eq 0 ] 8 | then 9 | pushd pystacks 2> /dev/null || true 10 | fi 11 | 12 | if [ -f ./requirements_test.txt ]; then 13 | pip install -q -r ./requirements_test.txt 14 | else 15 | pip install -q -r ../requirements_test.txt 16 | fi 17 | 18 | # Disable long line warnings because they are annoying 19 | pycodestyle --ignore=E501 . 20 | 21 | # If running locally we don't need to drop down 22 | if [ $# -eq 0 ] 23 | then 24 | popd 2> /dev/null || true 25 | fi 26 | -------------------------------------------------------------------------------- /ci/code_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -x 3 | 4 | if [ -f ./requirements_test.txt ]; then 5 | pip install -q -r ./requirements_test.txt 6 | else 7 | pip install -q -r ../requirements_test.txt 8 | fi 9 | 10 | pytest --cov=PyStacks --pyargs PyStacks -s -------------------------------------------------------------------------------- /ci/get_commit_json.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # bitbucket-pipelines yaml can't handle this command 4 | 5 | git log -1 --format='{ "hash": "%H", "date": "%ci", "committer": "%cn", "email":"%ce" }' 6 | -------------------------------------------------------------------------------- /ci/slack_alert.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | # Change: 5 | # 1. webhook url 6 | # 2. channel field 7 | 8 | SLACK_CHANNEL = '' 9 | SLACK_WEBHOOK_URL = '' 10 | REPO_URL = '' # EG https://github.com/github/github/ 11 | 12 | # ## Richly formatted 13 | 14 | # Get a commit file with the following bash command: 15 | # $ git slack -1 > /tmp/commit.json 16 | 17 | commit = {} 18 | with open('/tmp/commit.json', 'r') as f: 19 | commit = json.loads(f.read()) 20 | commit['repository'] = REPO_URL 21 | 22 | attachments = [ 23 | { 24 | "fallback": "The following commit just broke the PyStacks build: <{repository}/commits/{hash}|{hash}>".format(**commit), 25 | "color": "danger", # Can either be one of 'good', 'warning', 'danger', or any hex color code 26 | # Fields are displayed in a table on the message 27 | "fields": [ 28 | { 29 | "title": "Test failed - PyStack", 30 | "value": "The following commit just broke the PyStacks build: <{repository}/commits/{hash}|{hash}>".format(**commit), 31 | } 32 | ] 33 | }, 34 | { 35 | "pretext": "<{repository}/addon/pipelines/home#!|Github Pipelines>".format(**commit) 36 | } 37 | ] 38 | 39 | message_json = {'channel': SLACK_CHANNEL, "username": "Github-Pipelines", 40 | # "text": "", 41 | "link_names": "1", 42 | "icon_emoji": ":speak_no_evil:", 43 | "attachments": attachments, 44 | } 45 | 46 | response = requests.post( 47 | url=SLACK_WEBHOOK_URL, 48 | json=message_json, 49 | ) 50 | 51 | # return "response.status_code" 52 | -------------------------------------------------------------------------------- /ci/unit_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set -e -x 3 | 4 | # This file is the entrypoint for tests for local, docker and ci so be sure if you modify it that it works in all! 5 | 6 | # If running locally we don't need to step into the pystacks directory 7 | if [ $# -eq 0 ] 8 | then 9 | pushd pystacks 2> /dev/null || true 10 | fi 11 | 12 | if [ -f ./requirements_test.txt ]; then 13 | pip install -q -r ./requirements_test.txt 14 | else 15 | pip install -q -r ../requirements_test.txt 16 | fi 17 | 18 | echo "+--------------------+" 19 | echo "| Running Unit Tests |" 20 | echo "+--------------------+" 21 | 22 | pytest --pyargs PyStacks -s 23 | 24 | -------------------------------------------------------------------------------- /ci/version.txt: -------------------------------------------------------------------------------- 1 | 1.0 2 | -------------------------------------------------------------------------------- /commit_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | make imageLocal 3 | make testLocal 4 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | Marley Venerosa 2 | Ian McKay 3 | Ben Boyter 4 | Josh Wales 5 | David Wales 6 | Irena Kuntsevich 7 | Owen Kelly 8 | Rob Amos 9 | Stewart Leach 10 | Tim Elson 11 | Liam Dixon 12 | Damian Steele 13 | Michael Ransley 14 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Makefile for building publishing container 2 | PROJECT = pystacks 3 | VERSION = $(shell whoami) 4 | REGISTRY = local 5 | APP_IMAGE = $(PROJECT):$(VERSION) 6 | CONTAINER_TAG = latest 7 | 8 | imageLocal: 9 | docker build -t $(APP_IMAGE) . 10 | .PHONY: imageLocal 11 | 12 | imageOnly: 13 | docker build -t $(APP_IMAGE) . 14 | .PHONY: image 15 | 16 | image: imageOnly 17 | docker push $(APP_IMAGE) 18 | .PHONY: image 19 | 20 | publish-image: image 21 | docker tag $(APP_IMAGE) $(REGISTRY)/ops/$(PROJECT):$(CONTAINER_TAG) 22 | docker push $(APP_IMAGE) 23 | docker push $(REGISTRY)/ops/$(PROJECT):$(CONTAINER_TAG) 24 | .PHONY: publish-image 25 | 26 | testLocal: 27 | docker build -f Dockerfile.test -t pystacks-local-test . 28 | docker build -f Dockerfile.check -t pystacks-local-check . 29 | .PHONY: testLocal 30 | 31 | coverageLocal: 32 | nosetests --with-coverage -v --cover-package=PyStacks --cover-html --cover-html-dir=coverage 33 | open ./coverage/index.html 34 | .PHONY:coverageLocal 35 | 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | boto3>=1.4.7 2 | botocore>=1.8.26 3 | PyYAML==3.12 4 | invoke==0.14.0 5 | Jinja2==2.8 6 | pynt==0.8.1 7 | demjson==2.2.3 8 | dnspython==1.15.0 9 | jsonschema==2.6.0 10 | deepdiff==3.3.0 11 | -------------------------------------------------------------------------------- /requirements_test.txt: -------------------------------------------------------------------------------- 1 | boto3>=1.4.7 2 | botocore>=1.8.26 3 | PyYAML==3.12 4 | invoke==0.14.0 5 | Jinja2==2.8 6 | pynt==0.8.1 7 | mock==1.0.1 8 | coverage==4.3.4 9 | nose==1.3.7 10 | demjson==2.2.3 11 | dnspython==1.15.0 12 | jsonschema==2.6.0 13 | deepdiff==3.3.0 14 | pytest==3.2.1 15 | pytest-cov==2.5.1 16 | hypothesis==3.27.1 17 | pycodestyle==2.2.0 18 | --------------------------------------------------------------------------------