def create_autoscaling_resource(name, launchConfig): """[ create simple autoscaling resource ] Arguments: name {[String]} -- [ name ] launchConfig {[LaunchConfiguration]} -- [description] Returns: [ troposphere.resource ] -- [ AutoScalingGroup ] """ return AutoScalingGroup( name + "AutoScalingGroup", DesiredCapacity=10, AutoScalingGroupName=name, LaunchConfigurationName=Ref(launchConfig), MinSize=9, MaxSize=10, AvailabilityZones=[Ref(zone1), Ref(zone2)], HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)), Tags=Tags(Application=Ref('AWS::StackId')))
def _get_autoscaling_group_parameters(self, chain_context, launch_config_name): config = { 'AvailabilityZones': Ref("AvailabilityZones"), # Not really required in this case (yet) 'LaunchConfigurationName': Ref(launch_config_name), 'MinSize': Ref("MinSize"), 'MaxSize': Ref("MaxSize"), 'VPCZoneIdentifier': Ref("PrivateSubnets"), 'Tags': [ASTag('Name', self.name, True)], } if META_TARGET_GROUP_NAME in chain_context.metadata: config['TargetGroupARNs'] = [Ref(chain_context.metadata[META_TARGET_GROUP_NAME])] if self.use_update_policy: update_policy = UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True ) ) config['UpdatePolicy'] = update_policy return config
def elb_asg_lc_template(app, env, nameSGRDS, rdsPort, instanceType, ami, subnets, elbPort, elbCidrBlock, ec2Port, desiredCapacity, minSize, maxSize, region, nameBucket, officeIP): template = Template() sgELB = template.add_resource( SecurityGroup( "SecurityGroupELB" + app + env, GroupDescription="Security group for " + app + "-" + env, VpcId=ImportValue("VPC" + env), SecurityGroupIngress=[ SecurityGroupRule( IpProtocol="tcp", FromPort=elbPort, ToPort=elbPort, CidrIp=elbCidrBlock, ) ], SecurityGroupEgress=[ SecurityGroupRule(IpProtocol="-1", ToPort=0, FromPort=65535, CidrIp="0.0.0.0/0") ], Tags=Tags( env=env, Name="sg-ELB" + app + "-" + env, app=app, ), )) sgEC2 = template.add_resource( SecurityGroup( "SecurityGroupEC2" + app + env, GroupDescription="Security group for EC2 " + app + "-" + env, VpcId=ImportValue("VPC" + env), DependsOn="SecurityGroupELB" + app + env, SecurityGroupIngress=[ SecurityGroupRule( IpProtocol="tcp", FromPort=ec2Port, ToPort=ec2Port, SourceSecurityGroupId=Ref(sgELB), ), SecurityGroupRule( IpProtocol="tcp", FromPort=22, ToPort=22, CidrIp=officeIP, ), ], SecurityGroupEgress=[ SecurityGroupRule(IpProtocol="-1", ToPort=0, FromPort=65535, CidrIp="0.0.0.0/0") ], Tags=Tags( env=env, Name="sg-EC2-" + app + "-" + env, app=app, ), )) addIngressRDS = template.add_resource( SecurityGroupIngress( "ingressSGRDS" + app + env, SourceSecurityGroupId=Ref(sgEC2), Description="From EC2 instances", GroupId=ImportValue("SG-" + nameSGRDS + "-" + app + "-" + env), IpProtocol="tcp", FromPort=rdsPort, ToPort=rdsPort, DependsOn="SecurityGroupEC2" + app + env, )) launchConfig = template.add_resource( LaunchConfiguration("LaunchConfiguration" + app + env, InstanceType=instanceType, ImageId=ami, SecurityGroups=[Ref(sgEC2)], IamInstanceProfile=ImportValue("Role-" + app + "-" + env))) bucketPolicy = template.add_resource( BucketPolicy("BucketPolicy" + nameBucket + app + env, Bucket=ImportValue("Bucket" + nameBucket + app + env), PolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Action": ["s3:PutObject"], "Effect": "Allow", "Resource": Join("", [ "arn:aws:s3:::", ImportValue("Bucket" + nameBucket + app + env), "/AWSLogs/", Ref("AWS::AccountId"), "/*" ]), "Principal": { "AWS": ["156460612806"] } }] })) lb = template.add_resource( LoadBalancer("LoadBalancer" + app + env, ConnectionDrainingPolicy=elb.ConnectionDrainingPolicy( Enabled=True, Timeout=120, ), Subnets=subnets, HealthCheck=elb.HealthCheck( "HealthCheck", Target="TCP:" + str(ec2Port), HealthyThreshold="5", UnhealthyThreshold="5", Interval="30", Timeout="15", ), Listeners=[ elb.Listener( LoadBalancerPort=elbPort, InstancePort=ec2Port, Protocol="HTTP", InstanceProtocol="HTTP", ), ], CrossZone=True, SecurityGroups=[Ref(sgELB)], LoadBalancerName="lb-" + app + "-" + env, Scheme="internet-facing", AccessLoggingPolicy=AccessLoggingPolicy( "LoggingELB" + app + env, EmitInterval=5, Enabled=True, S3BucketName=ImportValue("Bucket" + nameBucket + app + env), ))) asg = template.add_resource( AutoScalingGroup( "AutoscalingGroup" + app + env, DesiredCapacity=desiredCapacity, Tags=[Tag("Environment", env, True)], LaunchConfigurationName=Ref(launchConfig), MinSize=minSize, MaxSize=maxSize, LoadBalancerNames=[Ref(lb)], AvailabilityZones=GetAZs(region), VPCZoneIdentifier=subnets, HealthCheckType="ELB", HealthCheckGracePeriod=300, UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True, )))) return (template.to_json())
"AutoscalingGroup" + f, Cooldown=300, HealthCheckGracePeriod=300, DesiredCapacity=DesiredCapacity, MinSize=MinSize, MaxSize=MaxSize, Tags=[ Tag("Name", environmentString + "AutoscalingGroup" + f, True) ], LaunchConfigurationName=Ref(LaunchConfig), VPCZoneIdentifier=subnetsList, # LoadBalancerNames=[Ref(LoadBalancer)], #AvailabilityZones=subnetsList, HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)))) ScalePolicyUp = template.add_resource( ScalingPolicy("HTTPRequestScalingPolicyUp" + f, AutoScalingGroupName=Ref(AutoscalingGroupX), AdjustmentType="ChangeInCapacity", Cooldown="300", ScalingAdjustment="1")) ScalePolicyDown = template.add_resource( ScalingPolicy("HTTPRequestScalingPolicyDown" + f,
def autoscaling_adder(self, common_tags, min_size, max_size, min_in_service, image_id, instance_size, sec_groups, health_check_type='EC2', loadbalancer=False, keyname=None, targetgroup=False, user_data_file=False): lc_name = "LaunchConfiguration" + str(random.randint(1, 999)) as_name = "AutoScalingGroup" + str(random.randint(1, 999)) if keyname is None: keyname = self.config['keyname'] if user_data_file: userdata = self.__loaduserdata(user_data_file, as_name) else: userdata = self.__loaduserdata("default_userdata.txt", as_name) as_group_tags = self.__tag_as_role_generator(common_tags) blockmap = self.__generate_blockmap() lc_groups = copy.copy(self.sec_groups) lc_groups.append(Ref(sec_groups)) launch_config = self.template.add_resource( LaunchConfiguration(lc_name, ImageId=image_id, KeyName=keyname, InstanceType=instance_size, SecurityGroups=lc_groups, IamInstanceProfile=self.config['iam_role'], UserData=userdata, BlockDeviceMappings=blockmap)) as_group = autoscalinggroup = AutoScalingGroup( as_name, Tags=as_group_tags, LaunchConfigurationName=Ref(lc_name), MinSize=Ref(min_size), MaxSize=Ref(max_size), VPCZoneIdentifier=self.config['subnets'], HealthCheckType=health_check_type, DependsOn=lc_name, CreationPolicy=CreationPolicy( AutoScalingCreationPolicy=AutoScalingCreationPolicy( MinSuccessfulInstancesPercent=80), ResourceSignal=ResourceSignal(Count=1, Timeout='PT10M')), UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=False, ), AutoScalingScheduledAction=AutoScalingScheduledAction( IgnoreUnmodifiedGroupSizeProperties=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( MaxBatchSize="2", MinInstancesInService=Ref(min_in_service), MinSuccessfulInstancesPercent=80, PauseTime='PT10M', WaitOnResourceSignals=True, SuspendProcesses=[ "ReplaceUnHealthy, AZRebalance, AlarmNotifications, " "ScheduledActions, HealthCheck" ]))) if loadbalancer: autoscalinggroup.LoadBalancerNames = loadbalancer if targetgroup: autoscalinggroup.TargetGroupARNs = [targetgroup] self.template.add_resource(autoscalinggroup) # getting a litte funky below. Only reason is to be able to do overrides for k8s. Probably will need to be # revisited as_lc = collections.namedtuple('aslc', 'as_group,launch_config')(as_group, launch_config) return as_lc
def main(): t = Template() t.add_version('2010-09-09') t.set_description("AWS CloudFormation ECS example") # Add the Parameters AMI = t.add_parameter(Parameter( "AMI", Type="String", )) ClusterSize = t.add_parameter(Parameter( "ClusterSize", Type="String", )) ClusterType = t.add_parameter(Parameter( "ClusterType", Type="String", )) InstanceType = t.add_parameter(Parameter( "InstanceType", Type="String", )) IamInstanceProfile = t.add_parameter( Parameter( "IamInstanceProfile", Type="String", )) KeyName = t.add_parameter( Parameter( "KeyName", Type="AWS::EC2::KeyPair::KeyName", )) MaxClusterSize = t.add_parameter( Parameter( "MaxClusterSize", Type="String", )) RollingUpdate = t.add_parameter(Parameter( "RollingUpdate", Type="String", )) Stage = t.add_parameter(Parameter( "Stage", Type="String", )) Subnets = t.add_parameter( Parameter( "Subnets", Type="List<AWS::EC2::Subnet::Id>", )) VpcCidr = t.add_parameter(Parameter( "VpcCidr", Type="String", )) VpcId = t.add_parameter(Parameter( "VpcId", Type="AWS::EC2::VPC::Id", )) ContainerInstances = t.add_resource( LaunchConfiguration( 'ContainerInstances', UserData=Base64( Join('', [ '#!/bin/bash -xe\n', 'echo ECS_CLUSTER=', Ref('AWS::StackName'), '>> /etc/ecs/ecs.config\n', 'systemctl enable [email protected]\n', 'systemctl start [email protected]\n', '/usr/bin/cfn-signal -e $? ', ' --stack ', Ref('AWS::StackName'), ' --resource ECSAutoScalingGroup ', ' --region ', Ref('AWS::Region'), '\n' ])), ImageId=Ref(AMI), KeyName=Ref(KeyName), SecurityGroups=[Ref('EcsSecurityGroup')], IamInstanceProfile=Ref(IamInstanceProfile), InstanceType=Ref(InstanceType))) ECSCluster = t.add_resource( Cluster('EcsCluster', ClusterName=Ref('AWS::StackName'))) ECSAutoScalingGroup = t.add_resource( AutoScalingGroup( 'ECSAutoScalingGroup', DesiredCapacity=Ref(ClusterSize), MinSize=Ref(ClusterSize), MaxSize=Ref(MaxClusterSize), VPCZoneIdentifier=Ref(Subnets), LaunchConfigurationName=Ref('ContainerInstances'), HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService=Ref(ClusterSize), MaxBatchSize='1', WaitOnResourceSignals=True)), Tags=[ Tag("Project", "demo", True), Tag("Stage", Ref(Stage), True), Tag("Name", "home-ecs", True), ])) t.add_resource( ScalingPolicy("EcsAsgScaleDown", AdjustmentType="PercentChangeInCapacity", AutoScalingGroupName=Ref("ECSAutoScalingGroup"), MetricAggregationType="Average", MinAdjustmentMagnitude="1", PolicyType="StepScaling", StepAdjustments=[ StepAdjustments(MetricIntervalLowerBound="-10", MetricIntervalUpperBound="0", ScalingAdjustment="-10"), StepAdjustments(MetricIntervalUpperBound="-10", ScalingAdjustment="-20") ])) t.add_resource( ScalingPolicy('EcsScaleUp', AdjustmentType="PercentChangeInCapacity", AutoScalingGroupName=Ref("ECSAutoScalingGroup"), EstimatedInstanceWarmup="300", MetricAggregationType="Average", MinAdjustmentMagnitude="1", PolicyType="StepScaling", StepAdjustments=[ StepAdjustments(MetricIntervalLowerBound="0", MetricIntervalUpperBound="10", ScalingAdjustment="10"), StepAdjustments(MetricIntervalLowerBound="10", ScalingAdjustment="20") ])) t.add_resource( cloudwatch.Alarm("EcsScaleDownAlarm", ActionsEnabled="True", MetricName="CPUUtilization", AlarmActions=[Ref("EcsAsgScaleDown")], AlarmDescription="Scale down ECS Instances", Namespace="AWS/EC2", Statistic="Average", Period="60", EvaluationPeriods="6", Threshold="25", ComparisonOperator="LessThanThreshold", Dimensions=[ cloudwatch.MetricDimension( Name="AutoScalingGroupName", Value=Ref("ECSAutoScalingGroup")) ])) t.add_resource( cloudwatch.Alarm("EcsAsgScaleUpAlarm", ActionsEnabled="True", MetricName="CPUUtilization", AlarmActions=[Ref("EcsScaleUp")], AlarmDescription="Scale up ECS Instances", Namespace="AWS/EC2", Statistic="Average", Period="60", EvaluationPeriods="3", Threshold="65", ComparisonOperator="GreaterThanThreshold", Dimensions=[ cloudwatch.MetricDimension( Name="AutoScalingGroupName", Value=Ref("ECSAutoScalingGroup")) ])) EC2SecurityGroup = t.add_resource( ec2.SecurityGroup('EcsSecurityGroup', GroupDescription='ECS InstanceSecurityGroup', SecurityGroupIngress=[ ec2.SecurityGroupRule(IpProtocol='tcp', FromPort='22', ToPort='22', CidrIp='0.0.0.0/0'), ec2.SecurityGroupRule(IpProtocol='tcp', FromPort='31000', ToPort='61000', CidrIp='0.0.0.0/0') ], VpcId=Ref(VpcId))) with open("ecs-ec2-cluster-cf.yaml", "w") as yamlout: yamlout.write(t.to_yaml())
def buildStack(bootstrap, env): t = Template() t.add_description("""\ Configures autoscaling group for hello world app""") vpcCidr = t.add_parameter( Parameter( "VPCCidr", Type="String", Description="VPC cidr (x.x.x.x/xx)", )) publicSubnet1 = t.add_parameter( Parameter( "PublicSubnet1", Type="String", Description="A public VPC subnet ID for the api app load balancer.", )) publicSubnet2 = t.add_parameter( Parameter( "PublicSubnet2", Type="String", Description="A public VPC subnet ID for the api load balancer.", )) dbName = t.add_parameter( Parameter( "DBName", Default="HelloWorldApp", Description="The database name", Type="String", MinLength="1", MaxLength="64", AllowedPattern="[a-zA-Z][a-zA-Z0-9]*", ConstraintDescription=("must begin with a letter and contain only" " alphanumeric characters."))) dbUser = t.add_parameter( Parameter( "DBUser", NoEcho=True, Description="The database admin account username", Type="String", MinLength="1", MaxLength="16", AllowedPattern="[a-zA-Z][a-zA-Z0-9]*", ConstraintDescription=("must begin with a letter and contain only" " alphanumeric characters."))) dbPassword = t.add_parameter( Parameter( "DBPassword", NoEcho=True, Description="The database admin account password", Type="String", MinLength="8", MaxLength="41", AllowedPattern="[a-zA-Z0-9]*", ConstraintDescription="must contain only alphanumeric characters.") ) dbType = t.add_parameter( Parameter( "DBType", Default="db.t2.medium", Description="Database instance class", Type="String", AllowedValues=[ "db.m5.large", "db.m5.xlarge", "db.m5.2xlarge", "db.m5.4xlarge", "db.m5.12xlarge", "db.m5.24xlarge", "db.m4.large", "db.m4.xlarge", "db.m4.2xlarge", "db.m4.4xlarge", "db.m4.10xlarge", "db.m4.16xlarge", "db.r4.large", "db.r4.xlarge", "db.r4.2xlarge", "db.r4.4xlarge", "db.r4.8xlarge", "db.r4.16xlarge", "db.x1e.xlarge", "db.x1e.2xlarge", "db.x1e.4xlarge", "db.x1e.8xlarge", "db.x1e.16xlarge", "db.x1e.32xlarge", "db.x1.16xlarge", "db.x1.32xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.t2.micro", "db.t2.small", "db.t2.medium", "db.t2.large", "db.t2.xlarge", "db.t2.2xlarge" ], ConstraintDescription="must select a valid database instance type.", )) dbAllocatedStorage = t.add_parameter( Parameter( "DBAllocatedStorage", Default="5", Description="The size of the database (Gb)", Type="Number", MinValue="5", MaxValue="1024", ConstraintDescription="must be between 5 and 1024Gb.", )) whitelistedCIDR = t.add_parameter( Parameter( "WhitelistedCIDR", Description="CIDR whitelisted to be open on public instances", Type="String", )) #### NETWORK SECTION #### vpc = t.add_resource( VPC("VPC", CidrBlock=Ref(vpcCidr), EnableDnsHostnames=True)) subnet1 = t.add_resource( Subnet("Subnet1", CidrBlock=Ref(publicSubnet1), AvailabilityZone="eu-west-1a", VpcId=Ref(vpc))) subnet2 = t.add_resource( Subnet("Subnet2", CidrBlock=Ref(publicSubnet2), AvailabilityZone="eu-west-1b", VpcId=Ref(vpc))) internetGateway = t.add_resource(InternetGateway('InternetGateway')) gatewayAttachment = t.add_resource( VPCGatewayAttachment('AttachGateway', VpcId=Ref(vpc), InternetGatewayId=Ref(internetGateway))) routeTable = t.add_resource(RouteTable('RouteTable', VpcId=Ref(vpc))) route = t.add_resource( Route( 'Route', DependsOn='AttachGateway', GatewayId=Ref('InternetGateway'), DestinationCidrBlock='0.0.0.0/0', RouteTableId=Ref(routeTable), )) subnetRouteTableAssociation = t.add_resource( SubnetRouteTableAssociation( 'SubnetRouteTableAssociation', SubnetId=Ref(subnet1), RouteTableId=Ref(routeTable), )) subnetRouteTableAssociation2 = t.add_resource( SubnetRouteTableAssociation( 'SubnetRouteTableAssociation2', SubnetId=Ref(subnet2), RouteTableId=Ref(routeTable), )) #### SECURITY GROUP #### loadBalancerSg = t.add_resource( ec2.SecurityGroup( "LoadBalancerSecurityGroup", VpcId=Ref(vpc), GroupDescription="Enable SSH access via port 22", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="80", ToPort="80", CidrIp="0.0.0.0/0", ), ], )) instanceSg = t.add_resource( ec2.SecurityGroup( "InstanceSecurityGroup", VpcId=Ref(vpc), GroupDescription="Enable SSH access via port 22", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp=Ref(whitelistedCIDR), ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="8000", ToPort="8000", SourceSecurityGroupId=Ref(loadBalancerSg), ), ], )) rdsSg = t.add_resource( SecurityGroup("RDSSecurityGroup", GroupDescription="Security group for RDS DB Instance.", VpcId=Ref(vpc), SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="5432", ToPort="5432", SourceSecurityGroupId=Ref(instanceSg), ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="5432", ToPort="5432", CidrIp=Ref(whitelistedCIDR), ), ])) #### DATABASE SECTION #### subnetGroup = t.add_resource( DBSubnetGroup( "SubnetGroup", DBSubnetGroupDescription= "Subnets available for the RDS DB Instance", SubnetIds=[Ref(subnet1), Ref(subnet2)], )) db = t.add_resource( DBInstance( "RDSHelloWorldApp", DBName=Join("", [Ref(dbName), env]), DBInstanceIdentifier=Join("", [Ref(dbName), env]), EnableIAMDatabaseAuthentication=True, PubliclyAccessible=True, AllocatedStorage=Ref(dbAllocatedStorage), DBInstanceClass=Ref(dbType), Engine="postgres", EngineVersion="10.4", MasterUsername=Ref(dbUser), MasterUserPassword=Ref(dbPassword), DBSubnetGroupName=Ref(subnetGroup), VPCSecurityGroups=[Ref(rdsSg)], )) t.add_output( Output("RDSConnectionString", Description="Connection string for database", Value=GetAtt("RDSHelloWorldApp", "Endpoint.Address"))) if (bootstrap): return t #### INSTANCE SECTION #### keyName = t.add_parameter( Parameter( "KeyName", Type="String", Description="Name of an existing EC2 KeyPair to enable SSH access", MinLength="1", AllowedPattern="[\x20-\x7E]*", MaxLength="255", ConstraintDescription="can contain only ASCII characters.", )) scaleCapacityMin = t.add_parameter( Parameter( "ScaleCapacityMin", Default="1", Type="String", Description="Number of api servers to run", )) scaleCapacityMax = t.add_parameter( Parameter( "ScaleCapacityMax", Default="1", Type="String", Description="Number of api servers to run", )) scaleCapacityDesired = t.add_parameter( Parameter( "ScaleCapacityDesired", Default="1", Type="String", Description="Number of api servers to run", )) amiId = t.add_parameter( Parameter( "AmiId", Type="String", Default="ami-09693313102a30b2c", Description="The AMI id for the api instances", )) instanceType = t.add_parameter( Parameter("InstanceType", Description="WebServer EC2 instance type", Type="String", Default="t2.medium", AllowedValues=[ "t2.nano", "t2.micro", "t2.small", "t2.medium", "t2.large", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge" ], ConstraintDescription="must be a valid EC2 instance type.")) assumeRole = t.add_resource( Role("AssumeRole", AssumeRolePolicyDocument=json.loads("""\ { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] }\ """))) instanceProfile = t.add_resource( InstanceProfile("InstanceProfile", Roles=[Ref(assumeRole)])) rolePolicyType = t.add_resource( PolicyType("RolePolicyType", Roles=[Ref(assumeRole)], PolicyName=Join("", ["CloudWatchHelloWorld", "-", env]), PolicyDocument=json.loads("""\ { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:DescribeLogStreams", "logs:PutLogEvents" ], "Effect": "Allow", "Resource": [ "arn:aws:logs:*:*:*" ] } ] }\ """))) appPassword = t.add_parameter( Parameter( "AppPassword", NoEcho=True, Description="The Password for the app user", Type="String", MinLength="8", MaxLength="41", AllowedPattern="[a-zA-Z0-9]*", ConstraintDescription="must contain only alphanumeric characters.") ) launchConfig = t.add_resource( LaunchConfiguration( "LaunchConfiguration", Metadata=autoscaling.Metadata( cloudformation.Init({ "config": cloudformation.InitConfig(files=cloudformation.InitFiles({ "/home/app/environment": cloudformation.InitFile(content=Join( "", [ "SPRING_DATASOURCE_URL=", "jdbc:postgresql://", GetAtt("RDSHelloWorldApp", "Endpoint.Address"), ":5432/HelloWorldApp" + env + "?currentSchema=hello_world", "\n", "SPRING_DATASOURCE_USERNAME=app", "\n", "SPRING_DATASOURCE_PASSWORD="******"\n", "SPRING_PROFILES_ACTIVE=", env, "\n" ]), mode="000600", owner="app", group="app") }), ) }), ), UserData=Base64( Join('', [ "#!/bin/bash\n", "/opt/aws/bin/cfn-init", " --resource LaunchConfiguration", " --stack ", Ref("AWS::StackName"), " --region ", Ref("AWS::Region"), "\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref": "AWS::StackName" }, " --resource AutoscalingGroup ", " --region ", { "Ref": "AWS::Region" }, "\n" ])), ImageId=Ref(amiId), KeyName=Ref(keyName), IamInstanceProfile=Ref(instanceProfile), BlockDeviceMappings=[ ec2.BlockDeviceMapping(DeviceName="/dev/xvda", Ebs=ec2.EBSBlockDevice(VolumeSize="8")), ], SecurityGroups=[Ref(instanceSg)], InstanceType=Ref(instanceType), AssociatePublicIpAddress='True', )) applicationElasticLB = t.add_resource( elb.LoadBalancer("ApplicationElasticLB", Name="ApplicationElasticLB-" + env, Scheme="internet-facing", Type="application", SecurityGroups=[Ref(loadBalancerSg)], Subnets=[Ref(subnet1), Ref(subnet2)])) targetGroup = t.add_resource( elb.TargetGroup("TargetGroupHelloWorld", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="15", HealthyThresholdCount="5", Matcher=elb.Matcher(HttpCode="200,404"), Port="8000", Protocol="HTTP", UnhealthyThresholdCount="3", TargetGroupAttributes=[ elb.TargetGroupAttribute( Key="deregistration_delay.timeout_seconds", Value="120", ) ], VpcId=Ref(vpc))) listener = t.add_resource( elb.Listener("Listener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(applicationElasticLB), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(targetGroup)) ])) t.add_output( Output("URL", Description="URL of the sample website", Value=Join("", ["http://", GetAtt(applicationElasticLB, "DNSName")]))) autoScalingGroup = t.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=Ref(scaleCapacityDesired), LaunchConfigurationName=Ref(launchConfig), MinSize=Ref(scaleCapacityMin), MaxSize=Ref(scaleCapacityMax), VPCZoneIdentifier=[Ref(subnet1), Ref(subnet2)], TargetGroupARNs=[Ref(targetGroup)], HealthCheckType="ELB", HealthCheckGracePeriod=360, UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)), CreationPolicy=CreationPolicy(ResourceSignal=ResourceSignal( Timeout="PT15M", Count=Ref(scaleCapacityDesired))))) # print(t.to_json()) return t
def create_instance(self, subnet1, subnet2, load_balancer, autoscaling_sg, webapp_zip): launch_config = self.t.add_resource( LaunchConfiguration( "LaunchConfiguration", UserData=Base64( Join('', [ "#!/bin/bash\n", "sudo yum install httpd mod_wsgi -y\n", "sudo pip install flask\n", "sudo chkconfig httpd on\n", "sudo service httpd start\n", "sudo service httpd restart\n", "sudo aws s3 cp s3://thivan-sample-data/", Ref(webapp_zip), " .\n", "sudo unzip ", Ref(webapp_zip), "\n", "sudo mv /home/ec2-user/app /var/www/html/\n", "sudo mv app /var/www/html/\n", "sudo mv /var/www/html/app/server_config/wsgi.conf /etc/httpd/conf.d/\n", "sudo groupadd group1\n", "sudo useradd user1 -g group1\n", "sudo usermod -a -G group1 apache\n", "sudo chown -vR :group1 /var/www/\n", "sudo chmod -vR g+w /var/www/\n", "sudo service httpd restart\n", "cfn-signal -e 0", " --resource AutoscalingGroup", " --stack ", Ref("AWS::StackName"), " --region ", Ref("AWS::Region"), "\n" ])), IamInstanceProfile= "arn:aws:iam::205198152101:instance-profile/webapps3", ImageId="ami-b73b63a0", KeyName="thivancf", SecurityGroups=[Ref(autoscaling_sg)], InstanceType="t2.micro", )) asg = self.t.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=2, LaunchConfigurationName=Ref(launch_config), MinSize=1, MaxSize=4, VPCZoneIdentifier=[Ref(subnet1), Ref(subnet2)], LoadBalancerNames=[Ref(load_balancer)], HealthCheckGracePeriod=300, HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', )))) scaling_policy = self.t.add_resource( ScalingPolicy("ScalingPolicy", AdjustmentType="ChangeInCapacity", AutoScalingGroupName=Ref(asg), Cooldown="120", ScalingAdjustment="1")) self.t.add_resource( Alarm( "CPUAlarm", EvaluationPeriods="1", Statistic="Maximum", Threshold="50", AlarmDescription= "Alarm if CPU too high or metric disappears indicating instance is down", Period="60", AlarmActions=[Ref(scaling_policy)], Namespace="AWS/EC2", Dimensions=[ MetricDimension(Name="AutoScalingGroupName", Value=Ref(asg)), ], ComparisonOperator="GreaterThanThreshold", MetricName="CPUUtilization")) return launch_config
def template(): t = Template() keyname_param = t.add_parameter( Parameter( "KeyName", Description= "Name of an existing EC2 KeyPair to enable SSH access to the instance", Type="String")) image_id_param = t.add_parameter( Parameter("ImageId", Description="ImageId of the EC2 instance", Type="String")) instance_type_param = t.add_parameter( Parameter("InstanceType", Description="Type of the EC2 instance", Type="String")) ScaleCapacity = t.add_parameter( Parameter( "ScaleCapacity", Default="1", Type="String", Description="Number of api servers to run", )) VPCAvailabilityZone2 = t.add_parameter( Parameter( "VPCAvailabilityZone2", MinLength="1", Type="String", Description="Second availability zone", MaxLength="255", )) VPCAvailabilityZone1 = t.add_parameter( Parameter( "VPCAvailabilityZone1", MinLength="1", Type="String", Description="First availability zone", MaxLength="255", )) SecurityGroup = t.add_parameter( Parameter( "SecurityGroup", Type="String", Description="Security group.", )) RootStackName = t.add_parameter( Parameter( "RootStackName", Type="String", Description="The root stack name", )) ApiSubnet2 = t.add_parameter( Parameter( "ApiSubnet2", Type="String", Description="Second private VPC subnet ID for the api app.", )) ApiSubnet1 = t.add_parameter( Parameter( "ApiSubnet1", Type="String", Description="First private VPC subnet ID for the api app.", )) ##################################################### # Launch Configuration ##################################################### LaunchConfig = t.add_resource( LaunchConfiguration( "LaunchConfiguration", Metadata=autoscaling.Metadata( cloudformation.Init( cloudformation.InitConfigSets(InstallAndRun=['Install']), Install=cloudformation.InitConfig( packages={ "apt": { "curl": [], "zip": [], "unzip": [], "git": [], "supervisor": [], "sqlite3": [], "nginx": [], "php7.2-fpm": [], "php7.2-cli": [], "php7.2-pgsql": [], "php7.2-sqlite3": [], "php7.2-gd": [], "php7.2-curl": [], "php7.2-memcached": [], "php7.2-imap": [], "php7.2-mysql": [], "php7.2-mbstring": [], "php7.2-xml": [], "php7.2-zip": [], "php7.2-bcmath": [], "php7.2-soap": [], "php7.2-intl": [], "php7.2-readline": [], "php-msgpack": [], "php-igbinary": [] } }, files=cloudformation.InitFiles({ "/etc/nginx/sites-available/default": cloudformation. InitFile(content=Join('', [ "server {\n", " listen 80 default_server;\n", " root /var/www/html/public;\n", " index index.html index.htm index.php;\n", " server_name _;\n", " charset utf-8;\n", " location = /favicon.ico { log_not_found off; access_log off; }\n", " location = /robots.txt { log_not_found off; access_log off; }\n", " location / {\n", " try_files $uri $uri/ /index.php$is_args$args;\n", " }\n", " location ~ \.php$ {\n", " include snippets/fastcgi-php.conf;\n", " fastcgi_pass unix:/run/php/php7.2-fpm.sock;\n", " }\n", " error_page 404 /index.php;\n", "}\n" ])), "/etc/supervisor/conf.d/supervisord.conf": cloudformation. InitFile(content=Join('', [ "[supervisord]\n", "nodaemon=true\n", "[program:nginx]\n", "command=nginx\n", "stdout_logfile=/dev/stdout\n", "stdout_logfile_maxbytes=0\n", "stderr_logfile=/dev/stderr\n", "stderr_logfile_maxbytes=0\n", "[program:php-fpm]\n", "command=php-fpm7.2\n", "stdout_logfile=/dev/stdout\n", "stdout_logfile_maxbytes=0\n", "stderr_logfile=/dev/stderr\n", "stderr_logfile_maxbytes=0\n", "[program:horizon]\n", "process_name=%(program_name)s\n", "command=php /var/www/html/artisan horizon\n", "autostart=true\n", "autorestart=true\n", "user=root\n", "redirect_stderr=true\n", "stdout_logfile=/var/www/html/storage/logs/horizon.log\n", ])), "/etc/php/7.2/fpm/php-fpm.conf": cloudformation.InitFile( content=Join('', [ "[global]\n", "pid = /run/php/php7.2-fpm.pid\n", "error_log = /proc/self/fd/2\n", "include=/etc/php/7.2/fpm/pool.d/*.conf\n" ])) }))), ), UserData=Base64( Join('', [ "#!/bin/bash -xe\n", "apt-get update -y\n", "apt-get install -y language-pack-en-base\n", "export LC_ALL=en_US.UTF-8\n", "export LANG=en_US.UTF-8\n", "apt-get install -y ruby\n", "wget https://aws-codedeploy-ap-south-1.s3.amazonaws.com/latest/install\n", "chmod +x ./install\n", "./install auto\n", "service codedeploy-agent start\n", "apt-get install -y software-properties-common python-software-properties\n", "add-apt-repository -y ppa:ondrej/php\n", "apt-get update -y\n", "apt-get install -y python-setuptools\n", "mkdir -p /opt/aws/bin\n", "wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", "easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-latest.tar.gz\n", "# Install the files and packages from the metadata\n", "/opt/aws/bin/cfn-init -v ", " --stack ", Ref("AWS::StackName"), " --resource LaunchConfiguration", " --configsets InstallAndRun ", " --region ", Ref("AWS::Region"), "\n" ])), ImageId=Ref("ImageId"), KeyName=Ref(keyname_param), BlockDeviceMappings=[ ec2.BlockDeviceMapping(DeviceName="/dev/sda1", Ebs=ec2.EBSBlockDevice(VolumeSize="8")), ], InstanceType=Ref("InstanceType"), IamInstanceProfile="CodeDeployDemo-EC2-Instance-Profile", SecurityGroups=[Ref(SecurityGroup)])) ##################################################### # AutoScaling Groups ##################################################### AutoscalingGroup = t.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=Ref(ScaleCapacity), Tags=[ Tag("App", "cc-worker", True), Tag("Name", "cc-worker", True) ], LaunchConfigurationName=Ref(LaunchConfig), MinSize=Ref(ScaleCapacity), MaxSize=Ref(ScaleCapacity), VPCZoneIdentifier=[Ref(ApiSubnet1), Ref(ApiSubnet2)], AvailabilityZones=[ Ref(VPCAvailabilityZone1), Ref(VPCAvailabilityZone2) ], HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)))) return t.to_json()