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"))
Exemple #3
0
    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'))
        ])
Exemple #4
0
    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",
        ))
Exemple #5
0
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'
                ]
            )
        )
Exemple #7
0
    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',
        )