def add_scaling_policy_ondemand_down(self): self.scalingPolicyOndemandDown = self.template.add_resource( autoscaling.ScalingPolicy("CPUUsageScalingPolicyOndemandDown", AdjustmentType="ChangeInCapacity", AutoScalingGroupName=Ref( self.AutoscalingGroupOnDemand), Cooldown="1", ScalingAdjustment="-1"))
def add_scaling_policy_spot_up(self): self.scalingPolicySpotUp = self.template.add_resource( autoscaling.ScalingPolicy("CPUUsageScalingPolicySpotUp", AdjustmentType="ChangeInCapacity", AutoScalingGroupName=Ref( self.AutoscalingGroupSpot), Cooldown="1", ScalingAdjustment="1"))
def set_up_stack(self): """Sets up the stack""" if not self.INPUTS or not self.STACK_NAME_PREFIX or not self.HEALTH_ENDPOINT: raise MKInputError( 'Must define INPUTS, STACK_NAME_PREFIX, and HEALTH_ENDPOINT') super(AppServerStack, self).set_up_stack() tags = self.get_input('Tags').copy() self.add_description('{} App Server Stack for Cac'.format( self.STACK_NAME_PREFIX)) assert isinstance(tags, dict), 'tags must be a dictionary' self.availability_zones = get_availability_zones() tags.update({'StackType': 'AppServer'}) self.default_tags = tags self.app_server_instance_type_parameter = self.add_parameter( Parameter( 'AppServerInstanceType', Type='String', Default='t2.medium', Description='NAT EC2 instance type', AllowedValues=EC2_INSTANCE_TYPES, ConstraintDescription='must be a valid EC2 instance type.'), source='AppServerInstanceType') self.param_app_server_iam_profile = self.add_parameter( Parameter('AppServerIAMProfile', Type='String', Description='IAM Profile for instances'), source='AppServerIAMProfile') self.app_server_ami = self.add_parameter(Parameter( 'AppServerAMI', Type='String', Description='{} Server EC2 AMI'.format(self.STACK_NAME_PREFIX)), source='AppServerAMI') self.keyname_parameter = self.add_parameter(Parameter( 'KeyName', Type='String', Default='cac', Description='Name of an existing EC2 key pair'), source='KeyName') self.param_color = self.add_parameter(Parameter( 'StackColor', Type='String', Description='Stack color', AllowedValues=['Blue', 'Green', 'Orange']), source='StackColor') self.param_stacktype = self.add_parameter(Parameter( 'StackType', Type='String', Description='Stack type', AllowedValues=['Development', 'Staging', 'Production']), source='StackType') self.param_public_hosted_zone_name = self.add_parameter( Parameter('PublicHostedZoneName', Type='String', Description='Public hosted zone name'), source='PublicHostedZoneName') self.param_vpc = self.add_parameter(Parameter( 'VpcId', Type='String', Description='Name of an existing VPC'), source='VpcId') self.param_notification_arn = self.add_parameter( Parameter( 'GlobalNotificationsARN', Type='String', Description='Physical resource ID on an AWS::SNS::Topic for ' 'notifications'), source='GlobalNotificationsARN') self.param_ssl_certificate_arn = self.add_parameter( Parameter('SSLCertificateARN', Type='String', Description= 'Physical resource ID on an AWS::IAM::ServerCertificate ' 'for the application server load balancer'), source='SSLCertificateARN') self.param_public_subnets = self.add_parameter( Parameter('PublicSubnets', Type='CommaDelimitedList', Description='A list of public subnets'), source='AppServerPublicSubnets') self.param_private_subnets = self.add_parameter( Parameter('PrivateSubnets', Type='CommaDelimitedList', Description='A list of private subnets'), source='AppServerPrivateSubnets') self.param_bastion_security_group = self.add_parameter( Parameter('BastionSecurityGroup', Type='String', Description='The ID of the bastion security group'), source='BastionSecurityGroup') self.param_database_security_group = self.add_parameter( Parameter('DatabaseSecurityGroup', Type='String', Description='The ID of the database security group'), source='DatabaseSecurityGroup') self.param_nat_security_group = self.add_parameter( Parameter('NATSecurityGroup', Type='String', Description='The ID of the NAT security group'), source='NATSecurityGroup') self.param_min_size = self.add_parameter(Parameter( 'ASGMinSize', Type='Number', Default='1', Description='Min size of ASG'), source='ASGMinSize') self.param_max_size = self.add_parameter(Parameter( 'ASGMaxSize', Type='Number', Default='1', Description='Max size of ASG'), source='ASGMaxSize') self.param_desired_capacity = self.add_parameter( Parameter('ASGDesiredCapacity', Type='Number', Default='1', Description='Desired capacity of ASG'), source='ASGDesiredCapacity') # # Security Group # app_server_load_balancer_security_group = self.add_resource( ec2.SecurityGroup( 'sgAppServerLoadBalancer', GroupDescription= 'Enables access to app servers via a load balancer', VpcId=Ref(self.param_vpc), SecurityGroupIngress=[ ec2.SecurityGroupRule(IpProtocol='tcp', CidrIp=ALLOW_ALL_CIDR, FromPort=p, ToPort=p) for p in [80, 443] ], Tags=Tags(Name='sgAppServerLoadBalancer', Color=Ref(self.param_color)))) app_server_security_group = self.add_resource( ec2.SecurityGroup( 'sgAppServer', GroupDescription='Enables access to App Servers', VpcId=Ref(self.param_vpc), SecurityGroupIngress=[ ec2.SecurityGroupRule(IpProtocol='tcp', CidrIp=VPC_CIDR, FromPort=p, ToPort=p) for p in [22, 80, 443] ] + [ ec2.SecurityGroupRule(IpProtocol='tcp', SourceSecurityGroupId=Ref(sg), FromPort=80, ToPort=80) for sg in [app_server_load_balancer_security_group] ] + [ ec2.SecurityGroupRule(IpProtocol='tcp', SourceSecurityGroupId=Ref(sg), FromPort=443, ToPort=443) for sg in [app_server_load_balancer_security_group] ], SecurityGroupEgress=[ ec2.SecurityGroupRule(IpProtocol='tcp', CidrIp=ALLOW_ALL_CIDR, FromPort=p, ToPort=p) for p in [80, 443, PAPERTRAIL_PORT] ], Tags=Tags(Name='sgAppServer', Color=Ref(self.param_color)))) # ELB to App Server self.add_resource( ec2.SecurityGroupEgress( 'sgEgressELBtoAppHTTP', GroupId=Ref(app_server_load_balancer_security_group), DestinationSecurityGroupId=Ref(app_server_security_group), IpProtocol='tcp', FromPort=80, ToPort=80)) self.add_resource( ec2.SecurityGroupEgress( 'sgEgressELBtoAppHTTPS', GroupId=Ref(app_server_load_balancer_security_group), DestinationSecurityGroupId=Ref(app_server_security_group), IpProtocol='tcp', FromPort=443, ToPort=443)) # Bastion to App Server, app server to db, app server to inet rules = [(self.param_bastion_security_group, app_server_security_group, [80, 443, 22]), (app_server_security_group, self.param_database_security_group, [POSTGRES]), (app_server_security_group, self.param_nat_security_group, [80, 443, 22, 587, PAPERTRAIL_PORT])] for num, (srcsg, destsg, ports) in enumerate(rules): for port in ports: self.add_resource( ec2.SecurityGroupEgress( 'sgEgress{}p{}'.format(num, port), GroupId=Ref(srcsg), DestinationSecurityGroupId=Ref(destsg), IpProtocol='tcp', FromPort=port, ToPort=port)) self.add_resource( ec2.SecurityGroupIngress('sgIngress{}p{}'.format( num, port), GroupId=Ref(destsg), SourceSecurityGroupId=Ref(srcsg), IpProtocol='tcp', FromPort=port, ToPort=port)) # # ELB # app_server_load_balancer = self.add_resource( elb.LoadBalancer( 'elbAppServer', ConnectionDrainingPolicy=elb.ConnectionDrainingPolicy( Enabled=True, Timeout=300), CrossZone=True, SecurityGroups=[Ref(app_server_load_balancer_security_group)], Listeners=[ elb.Listener(LoadBalancerPort='80', Protocol='HTTP', InstancePort='80', InstanceProtocol='HTTP'), elb.Listener(LoadBalancerPort='443', Protocol='HTTPS', InstancePort='443', InstanceProtocol='HTTP', SSLCertificateId=Ref( self.param_ssl_certificate_arn)) ], HealthCheck=elb.HealthCheck( Target=self.HEALTH_ENDPOINT, HealthyThreshold='3', UnhealthyThreshold='2', Interval='30', Timeout='5', ), Subnets=Ref(self.param_public_subnets), Tags=Tags(Name='elbAppServer', Color=Ref(self.param_color)))) self.add_resource( cw.Alarm('alarmAppServerBackend4xx', AlarmActions=[Ref(self.param_notification_arn)], Statistic='Sum', Period=300, Threshold='5', EvaluationPeriods=1, ComparisonOperator='GreaterThanThreshold', MetricName='HTTPCode_Backend_4XX', Namespace='AWS/ELB', Dimensions=[ cw.MetricDimension( 'metricLoadBalancerName', Name='LoadBalancerName', Value=Ref(app_server_load_balancer)) ])) self.add_resource( cw.Alarm('alarmAppServerBackend5xx', AlarmActions=[Ref(self.param_notification_arn)], Statistic='Sum', Period=60, Threshold='0', EvaluationPeriods=1, ComparisonOperator='GreaterThanThreshold', MetricName='HTTPCode_Backend_5XX', Namespace='AWS/ELB', Dimensions=[ cw.MetricDimension( 'metricLoadBalancerName', Name='LoadBalancerName', Value=Ref(app_server_load_balancer)) ])) # # ASG # app_server_launch_config = self.add_resource( asg.LaunchConfiguration( 'lcAppServer', ImageId=Ref(self.app_server_ami), IamInstanceProfile=Ref(self.param_app_server_iam_profile), InstanceType=Ref(self.app_server_instance_type_parameter), KeyName=Ref(self.keyname_parameter), SecurityGroups=[Ref(app_server_security_group)])) autoscaling_group = self.add_resource( asg.AutoScalingGroup( 'asgAppServer', AvailabilityZones=self.get_input( 'AppServerAvailabilityZones').split(','), Cooldown=300, DesiredCapacity=Ref(self.param_desired_capacity), HealthCheckGracePeriod=600, HealthCheckType='ELB', LaunchConfigurationName=Ref(app_server_launch_config), LoadBalancerNames=[Ref(app_server_load_balancer)], MaxSize=Ref(self.param_max_size), MinSize=Ref(self.param_min_size), NotificationConfiguration=asg.NotificationConfiguration( TopicARN=Ref(self.param_notification_arn), NotificationTypes=[ asg.EC2_INSTANCE_LAUNCH, asg.EC2_INSTANCE_LAUNCH_ERROR, asg.EC2_INSTANCE_TERMINATE, asg.EC2_INSTANCE_TERMINATE_ERROR ]), VPCZoneIdentifier=Ref(self.param_private_subnets), Tags=[ asg.Tag('Name', '{}Server'.format(self.STACK_NAME_PREFIX), True), asg.Tag('Color', Ref(self.param_color), True) ])) # autoscaling policies autoscaling_policy_add = self.add_resource( asg.ScalingPolicy('scalingPolicyAddAppServer', AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(autoscaling_group), Cooldown=600, ScalingAdjustment='1')) autoscaling_policy_remove = self.add_resource( asg.ScalingPolicy('scalingPolicyRemoveAppServer', AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(autoscaling_group), Cooldown=600, ScalingAdjustment='-1')) if self.STACK_NAME_PREFIX == 'Otp': # trigger scale down if CPU avg usage < 10% for 3 consecutive 5 min periods self.add_resource( cw.Alarm('alarmAppServerLowCPU', AlarmActions=[Ref(autoscaling_policy_remove)], Statistic='Average', Period=300, Threshold='10', EvaluationPeriods=3, ComparisonOperator='LessThanThreshold', MetricName='CPUUtilization', Namespace='AWS/EC2', Dimensions=[ cw.MetricDimension('metricAutoScalingGroupName', Name='AutoScalingGroupName', Value=Ref(autoscaling_group)) ])) # trigger scale up if CPU avg usage >= 30% for a 5 min period self.add_resource( cw.Alarm('alarmAppServerHighCPU', AlarmActions=[ Ref(self.param_notification_arn), Ref(autoscaling_policy_add) ], Statistic='Average', Period=300, Threshold='30', EvaluationPeriods=1, ComparisonOperator='GreaterThanOrEqualToThreshold', MetricName='CPUUtilization', Namespace='AWS/EC2', Dimensions=[ cw.MetricDimension('metricAutoScalingGroupName', Name='AutoScalingGroupName', Value=Ref(autoscaling_group)) ])) else: # scale web servers based on network usage self.add_resource( cw.Alarm('alarmAppServerLowNetworkUsage', AlarmActions=[Ref(autoscaling_policy_remove)], Statistic='Average', Period=300, Threshold='500000', EvaluationPeriods=3, ComparisonOperator='LessThanThreshold', MetricName='NetworkOut', Namespace='AWS/EC2', Dimensions=[ cw.MetricDimension('metricAutoScalingGroupName', Name='AutoScalingGroupName', Value=Ref(autoscaling_group)) ])) self.add_resource( cw.Alarm('alarmAppServerHighNetworkUsage', AlarmActions=[ Ref(self.param_notification_arn), Ref(autoscaling_policy_add) ], Statistic='Average', Period=300, Threshold='10000000', EvaluationPeriods=1, ComparisonOperator='GreaterThanOrEqualToThreshold', MetricName='NetworkOut', Namespace='AWS/EC2', Dimensions=[ cw.MetricDimension('metricAutoScalingGroupName', Name='AutoScalingGroupName', Value=Ref(autoscaling_group)) ])) # # DNS name # self.create_resource( route53.RecordSetType( 'dnsName', Name=Join('.', [ Ref(self.param_color), Ref(self.param_stacktype), self.STACK_NAME_PREFIX, Ref(self.param_public_hosted_zone_name) ]), Type='A', AliasTarget=route53.AliasTarget( GetAtt(app_server_load_balancer, 'CanonicalHostedZoneNameID'), GetAtt(app_server_load_balancer, 'DNSName')), HostedZoneName=Ref(self.param_public_hosted_zone_name))) self.add_output([ Output('{}ServerLoadBalancerEndpoint'.format( self.STACK_NAME_PREFIX), Description='Application server endpoint', Value=GetAtt(app_server_load_balancer, 'DNSName')), Output('{}ServerLoadBalancerHostedZoneNameID'.format( self.STACK_NAME_PREFIX), Description='ID of canonical hosted zone name for ELB', Value=GetAtt(app_server_load_balancer, 'CanonicalHostedZoneNameID')) ])
def add_resources(self): metadata = { "AWS::CloudFormation::Init": { "configSets": { "wordpress_install": [ "install_wordpress"] }, "install_wordpress": { "packages": { "apt": { "apache2": [], "php": [], "php-mysql": [], "php7.0": [], "php7.0-mysql": [], "libapache2-mod-php7.0": [], "php7.0-cli": [], "php7.0-cgi": [], "php7.0-gd": [], "mysql-client": [], "sendmail": [] } }, "sources": { "/var/www/html": "http://wordpress.org/latest.tar.gz" }, "files": { "/tmp/create-wp-config": { "content": { "Fn::Join": ["", [ "#!/bin/bash\n", "cp /var/www/html/wordpress/wp-config-sample.php /var/www/html/wordpress/wp-config.php\n", "sed -i \"s/'database_name_here'/'", Ref( self.DBName), "'/g\" wp-config.php\n", "sed -i \"s/'username_here'/'", Ref( self.DBUser), "'/g\" wp-config.php\n", "sed -i \"s/'password_here'/'", Ref( self.DBPass), "'/g\" wp-config.php\n", "sed -i \"s/'localhost'/'", Ref( self.RDSEndpoint), "'/g\" wp-config.php\n" ]] }, "mode": "000500", "owner": "root", "group": "root" } }, "commands": { "01_configure_wordpress": { "command": "/tmp/create-wp-config", "cwd": "/var/www/html/wordpress" } } } } } self.WaitHandle = self.template.add_resource(cloudformation.WaitConditionHandle( "WaitHandle", )) self.WaitCondition = self.template.add_resource(cloudformation.WaitCondition( "WaitCondition", Handle=Ref(self.WaitHandle), Timeout="600", DependsOn="WebServerAutoScalingGroup", )) self.WebServerLaunchConfiguration = self.template.add_resource(autoscaling.LaunchConfiguration( "WebServerLaunchConfiguration", Metadata=metadata, UserData=Base64(Join("", [ "#!/bin/bash -x\n", "apt-get update\n", "apt-get install python-pip nfs-common -y \n", "mkdir -p /var/www/html/\n", "EC2_AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)\n", "echo \"$EC2_AZ.", Ref(self.FileSystemID), ".efs.", Ref( "AWS::Region"), ".amazonaws.com:/ /var/www/html/ nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0\" >> /etc/fstab\n" "mount -a\n", "pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", # "exec > /tmp/userdata.log 2>&1\n", "/usr/local/bin/cfn-init -v --stack ", Ref("AWS::StackName"), " --resource WebServerLaunchConfiguration ", " --configsets wordpress_install ", " --region ", Ref("AWS::Region"), "\n", "/bin/mv /var/www/html/wordpress/* /var/www/html/\n", "/bin/rm -f /var/www/html/index.html\n", "/bin/rm -rf /var/www/html/wordpress/\n", "chown www-data:www-data /var/www/html/* -R\n", "/usr/sbin/service apache2 restart\n", "/usr/bin/curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar\n", "/bin/chmod +x wp-cli.phar\n", "/bin/mv wp-cli.phar /usr/local/bin/wp\n", "cd /var/www/html/\n", "if ! $(sudo -u www-data /usr/local/bin/wp core is-installed); then\n", "sudo -u www-data /usr/local/bin/wp core install ", "--url='", Ref(self.Hostname), ".", Ref(self.Domain), "' ", "--title='Cloudreach Meetup - ", Ref( self.Environment), "' ", "--admin_user='******' ", "--admin_password='******' ", "--admin_email='*****@*****.**'\n", "wget https://s3-eu-west-1.amazonaws.com/sceptre-meetup-munich/header.jpg -O /var/www/html/wp-content/themes/twentyseventeen/assets/images/header.jpg\n", "chown www-data:www-data /var/www/html/wp-content/themes/twentyseventeen/assets/images/header.jpg\n", "fi\n", "/usr/local/bin/cfn-signal -e $? --stack ", Ref( "AWS::StackName"), " -r \"Webserver setup complete\" '", Ref(self.WaitHandle), "'\n" ] )), ImageId=FindInMap("AWSRegion2AMI", Ref("AWS::Region"), "AMI"), KeyName=Ref(self.KeyName), SecurityGroups=[Ref(self.WebSecurityGroup)], InstanceType=Ref(self.InstanceType), AssociatePublicIpAddress=True, )) self.WebServerAutoScalingGroup = self.template.add_resource(autoscaling.AutoScalingGroup( "WebServerAutoScalingGroup", MinSize=Ref(self.WebServerCapacity), DesiredCapacity=Ref(self.WebServerCapacity), MaxSize=Ref(self.WebServerCapacity), VPCZoneIdentifier=[Ref(self.Subnet1), Ref(self.Subnet2)], AvailabilityZones=[Ref(self.AvailabilityZone1), Ref(self.AvailabilityZone2)], Tags=autoscaling.Tags( Name=Join("-", [Ref(self.Project), "web", "asg"]), Environment=Ref(self.Environment), Project=Ref(self.Project), ), LoadBalancerNames=[Ref(self.ElasticLoadBalancer)], LaunchConfigurationName=Ref(self.WebServerLaunchConfiguration), )) self.WebServerScaleUpPolicy = self.template.add_resource(autoscaling.ScalingPolicy( "WebServerScaleUpPolicy", ScalingAdjustment="1", Cooldown="60", AutoScalingGroupName=Ref(self.WebServerAutoScalingGroup), AdjustmentType="ChangeInCapacity", )) self.WebServerScaleDownPolicy = self.template.add_resource(autoscaling.ScalingPolicy( "WebServerScaleDownPolicy", ScalingAdjustment="-1", Cooldown="60", AutoScalingGroupName=Ref(self.WebServerAutoScalingGroup), AdjustmentType="ChangeInCapacity", )) self.CPUAlarmLow = self.template.add_resource(cloudwatch.Alarm( "CPUAlarmLow", EvaluationPeriods="2", Dimensions=[ cloudwatch.MetricDimension( Name="AutoScalingGroupName", Value=Ref(self.WebServerAutoScalingGroup) ), ], AlarmActions=[Ref(self.WebServerScaleDownPolicy)], AlarmDescription="Scale-down if CPU < 70% for 1 minute", Namespace="AWS/EC2", Period="60", ComparisonOperator="LessThanThreshold", Statistic="Average", Threshold="70", MetricName="CPUUtilization", )) self.CPUAlarmHigh = self.template.add_resource(cloudwatch.Alarm( "CPUAlarmHigh", EvaluationPeriods="2", Dimensions=[ cloudwatch.MetricDimension( Name="AutoScalingGroupName", Value=Ref("WebServerAutoScalingGroup") ), ], AlarmActions=[Ref(self.WebServerScaleUpPolicy)], AlarmDescription="Scale-up if CPU > 50% for 1 minute", Namespace="AWS/EC2", Period="60", ComparisonOperator="GreaterThanThreshold", Statistic="Average", Threshold="50", MetricName="CPUUtilization", ))
def AS_ScalingPolicies(key): Out_String = [] Out_Map = {} for n, v in getattr(cfg, key).items(): if not v["IBOX_ENABLED"]: continue resname = f"{key}{n}" # resources if key == "AutoScalingScalingPolicy": r_Policy = asg.ScalingPolicy(resname) else: r_Policy = aas.ScalingPolicy(resname) auto_get_props(r_Policy) add_obj(r_Policy) # for tracking create output if v["PolicyType"] == "TargetTrackingScaling": # Autoscaling if "TargetTrackingConfiguration" in v: TargetTrackingConfigurationName = "TargetTrackingConfiguration" # Application Autoscaling elif "TargetTrackingScalingPolicyConfiguration" in v: TargetTrackingConfigurationName = ( "TargetTrackingScalingPolicyConfiguration" ) basename = f"{resname}{TargetTrackingConfigurationName}" # outputs if v["Type"] == "Cpu" or ( v["Type"] == "Custom" and v[TargetTrackingConfigurationName]["CustomizedMetricSpecification"][ "MetricName" ] == "CPUUtilization" ): # Use Cpu Metric Out_String.append("Cpu${Statistic}:${Cpu}") if v["Type"] == "Custom": statistic = get_endvalue( f"{basename}" "CustomizedMetricSpecificationStatistic" ) else: statistic = "" Out_Map.update( { "Statistic": statistic, "Cpu": get_endvalue(f"{basename}TargetValue"), } ) if Out_String: # Outputs O_Policy = Output(key, Value=Sub(",".join(Out_String), **Out_Map)) add_obj(O_Policy)
def add_ec2(self, ami_name, instance_type, asg_size, cidr, hosted_zone): """ Helper method creates ingress given a source cidr range and a set of ports @param ami_name [string] Name of the AMI for launching the app @param instance_type [string] Instance for the application @param asg_size [int] Sets the size of the asg @param cidr [string] Range of addresses for this vpc @param hosted_zone [string] Name of the hosted zone the elb will be mapped to """ print "Creating EC2" self.internal_security_group = self.add_sg_with_cidr_port_list( "ASGSG", "Security Group for EC2", 'vpcId', cidr, [{"443": "443"}, {"80": "80"}] ) self.public_lb_security_group = self.add_sg_with_cidr_port_list( "ELBSG", "Security Group for accessing EC2 publicly", 'vpcId', '0.0.0.0/0', [{"443": "443"}] ) name = self.env_name.replace('-', '') public_subnet_count = len(self._subnets.get('public').get('public')) public_subnets = [{'Ref': x} for x in ["publicAZ%d" % n for n in range(0, public_subnet_count)]] public_alb = self.add_resource(alb.LoadBalancer( "PublicALB", Scheme='internet-facing', Subnets=public_subnets, SecurityGroups=[Ref(sg) for sg in [self.public_lb_security_group]] )) target_group = self.add_resource(alb.TargetGroup( "AppTargetGroup80", Port=80, Protocol="HTTP", VpcId=self.vpc_id )) certificate = 'arn:aws:acm:us-east-1:422548007577:certificate/d9b8fbd2-13bb-4d6e-aba4-53061b1580f9' alb_ssl_listener = self.add_resource(alb.Listener( "ALBListner", Port=443, Certificates=[alb.Certificate(CertificateArn=certificate)], Protocol="HTTPS", DefaultActions=[alb.Action( Type="forward", TargetGroupArn=Ref(target_group))], LoadBalancerArn=Ref(public_alb) )) self.add_elb_dns_alias(public_alb, '', hosted_zone) policies = ['cloudwatchlogs'] policies_for_profile = [self.get_policy(policy, 'EC2') for policy in policies] asg = self.add_asg( "EC2", min_size=asg_size, max_size=6, ami_name=ami_name, # load_balancer=public_elb, instance_profile=self.add_instance_profile(name, policies_for_profile, name), instance_type=instance_type, security_groups=['commonSecurityGroup', Ref(self.internal_security_group)], subnet_layer='private', update_policy=UpdatePolicy( AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService=1, # The maximum number of instances that are terminated at a given time, left at 1 to ease into updates. # Can be increased at a later time MaxBatchSize='1' ) ), user_data=Base64(Join('', [ '#!/bin/bash\n', 'echo Good to go' ]))) asg.resource['Properties']['TargetGroupARNs'] = [Ref(target_group)] # Cluster Memory Scaling policies asg_scale_up_policy = self.add_resource( autoscaling.ScalingPolicy( name + 'ScaleUpPolicy', AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(asg), Cooldown=300, ScalingAdjustment=1 ) ) # ELB latency above a threshold self.add_resource( cloudwatch.Alarm( name + 'LatencyHigh', MetricName='Latency', ComparisonOperator='GreaterThanThreshold', Period=300, EvaluationPeriods=1, Statistic='Average', Namespace='AWS/ELB', AlarmDescription=name + 'LatencyHigh', Dimensions=[cloudwatch.MetricDimension(Name='LoadBalancerName', Value=Ref(public_alb))], Threshold='6', AlarmActions=[ Ref(asg_scale_up_policy), 'arn:aws:sns:us-east-1:422548007577:notify-pat' ] ) )
def __init__(self, key): ScalingPolicyTrackings_Out_String = [] ScalingPolicyTrackings_Out_Map = {} for n, v in getattr(cfg, key).items(): if not ('Enabled' in v and v['Enabled'] is True): continue resname = f'{key}{n}' # Autoscaling if 'TargetTrackingConfiguration' in v: TargetTrackingConfigurationName = ( 'TargetTrackingConfiguration') p_type = 'autoscaling' # Application Autoscaling elif 'TargetTrackingScalingPolicyConfiguration' in v: TargetTrackingConfigurationName = ( 'TargetTrackingScalingPolicyConfiguration') p_type = 'application_autoscaling' basename = f'{resname}{TargetTrackingConfigurationName}' # parameters p_Value = Parameter(f'{basename}TargetValue') p_Value.Description = (f'Tracking {n} Value - 0 to disable - ' 'empty for default based on env/role') p_Statistic = Parameter( f'{basename}CustomizedMetricSpecificationStatistic') p_Statistic.Description = ( f'Tracking {n} Statistic - 0 to disable - ' 'empty for default based on env/role') add_obj([ p_Value, p_Statistic, ]) # conditions c_TargetValue = get_condition(resname, 'not_equals', '0', f'{basename}TargetValue') add_obj(c_TargetValue) # outputs if v['Type'] == 'Cpu' or ( v['Type'] == 'Custom' and v[TargetTrackingConfigurationName] ['CustomizedMetricSpecification']['MetricName'] == 'CPUUtilization'): # Use Cpu Metric ScalingPolicyTrackings_Out_String.append( 'Cpu${Statistic}:${Cpu}') if v['Type'] == 'Custom': statistic = get_endvalue( f'{basename}CustomizedMetricSpecificationStatistic') else: statistic = '' ScalingPolicyTrackings_Out_Map.update({ 'Statistic': statistic, 'Cpu': get_endvalue(f'{basename}TargetValue'), }) # resources if p_type == 'autoscaling': r_Tracking = asg.ScalingPolicy(resname) else: r_Tracking = aas.ScalingPolicy(resname) auto_get_props(r_Tracking, v, recurse=True) r_Tracking.Condition = resname add_obj(r_Tracking) # Outputs O_Policy = Output(key) O_Policy.Value = Sub(','.join(ScalingPolicyTrackings_Out_String), **ScalingPolicyTrackings_Out_Map) add_obj([ O_Policy, ])
LoadBalancerNames=[Ref("ElasticLoadBalancer")], LaunchConfigurationName=Ref("WebServerLaunchConfiguration"), CreationPolicy=CreationPolicy( ResourceSignal=ResourceSignal(Count=1, Timeout='PT10M')), UpdatePolicy=UpdatePolicy( AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)))) WebServerScaleUpPolicy = t.add_resource( autoscaling.ScalingPolicy( "WebServerScaleUpPolicy", ScalingAdjustment="1", Cooldown="60", AutoScalingGroupName=Ref(WebServerAutoScalingGroup), AdjustmentType="ChangeInCapacity", )) WebServerScaleDownPolicy = t.add_resource( autoscaling.ScalingPolicy( "WebServerScaleDownPolicy", ScalingAdjustment="-1", Cooldown="60", AutoScalingGroupName=Ref(WebServerAutoScalingGroup), AdjustmentType="ChangeInCapacity", )) CPUAlarmLow = t.add_resource( cloudwatch.Alarm(
def __init__(self, parameters, vpc, loadbalancer): """ :type parameters Parameters :type vpc VPC :type loadbalancer LoadBalancer """ super(EC2, self).__init__() # Ec2 instance self.instance_role = iam.Role( "InstanceRole", AssumeRolePolicyDocument=aws.Policy(Statement=[ aws.Statement(Effect=aws.Allow, Action=[sts.AssumeRole], Principal=aws.Principal("Service", ["ec2.amazonaws.com"])) ]), Path="/", ) self.instance_role_policy = iam.PolicyType( "InstanceRolePolicy", PolicyName=Join("-", [Ref("AWS::StackName"), "instance-policy"]), PolicyDocument=aws.Policy(Statement=[ aws.Statement(Effect=aws.Allow, Action=[ aws.Action("logs", "CreateLogGroup"), aws.Action("logs", "CreateLogStream"), aws.Action("logs", "PutLogEvents"), aws.Action("logs", "DescribeLogStreams"), ], Resource=["arn:aws:logs:*:*:*"]) ]), Roles=[Ref(self.instance_role)]) self.instance_profile = iam.InstanceProfile( "InstanceProfile", Path="/", Roles=[Ref(self.instance_role)]) self.launch_configuration = autoscaling.LaunchConfiguration( "LaunchConfiguration", ImageId=FindInMap("AMIMap", Ref(AWS_REGION), "AMI"), InstanceType=Ref(parameters.ec2_instance_type), KeyName=Ref(parameters.key_pair), InstanceMonitoring=True, SecurityGroups=[ GetAtt(loadbalancer.instance_security_group, "GroupId"), ], IamInstanceProfile=Ref(self.instance_profile), ) self.auto_scaling_group = autoscaling.AutoScalingGroup( "AutoScalingGroup", LaunchConfigurationName=Ref(self.launch_configuration), MinSize=1, DesiredCapacity=1, MaxSize=10, HealthCheckType='ELB', HealthCheckGracePeriod=300, VPCZoneIdentifier=[ Ref(vpc.public_subnet_1), Ref(vpc.public_subnet_2) ], LoadBalancerNames=[Ref(loadbalancer.load_balancer)], Tags=[autoscaling.Tag("Name", Ref("AWS::StackName"), True)], UpdatePolicy=policies.UpdatePolicy( AutoScalingRollingUpdate=policies.AutoScalingRollingUpdate( PauseTime="PT30S", MinInstancesInService=1, MaxBatchSize=10, WaitOnResourceSignals=False)), TerminationPolicies=[ 'OldestLaunchConfiguration', 'ClosestToNextInstanceHour', 'Default' ], MetricsCollection=[ autoscaling.MetricsCollection(Granularity="1Minute") ]) self.scale_up_policy = autoscaling.ScalingPolicy( "ScaleUPPolicy", AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(self.auto_scaling_group), PolicyType='StepScaling', MetricAggregationType='Average', StepAdjustments=[ autoscaling.StepAdjustments(MetricIntervalLowerBound=0, ScalingAdjustment=1) ], ) self.scale_down_policy = autoscaling.ScalingPolicy( "ScaleDOWNPolicy", AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(self.auto_scaling_group), PolicyType='StepScaling', MetricAggregationType='Average', StepAdjustments=[ autoscaling.StepAdjustments(MetricIntervalUpperBound=0, ScalingAdjustment=-1) ], ) self.ec2_high_cpu_usage_alarm = cloudwatch.Alarm( "EC2HighCPUUsageAlarm", ActionsEnabled=True, AlarmActions=[Ref(self.scale_up_policy)], ComparisonOperator='GreaterThanThreshold', Dimensions=[ cloudwatch.MetricDimension(Name='AutoScalingGroupName', Value=Ref(self.auto_scaling_group)) ], EvaluationPeriods=3, MetricName='CPUUtilization', Namespace='AWS/EC2', Period=300, Statistic='Average', Threshold='70', ) self.ec2_low_cpu_usage_alarm = cloudwatch.Alarm( "EC2LowCPUUsageAlarm", ActionsEnabled=True, AlarmActions=[Ref(self.scale_down_policy)], ComparisonOperator='LessThanThreshold', Dimensions=[ cloudwatch.MetricDimension(Name='AutoScalingGroupName', Value=Ref(self.auto_scaling_group)) ], EvaluationPeriods=3, MetricName='CPUUtilization', Namespace='AWS/EC2', Period=300, Statistic='Average', Threshold='20', )