Пример #1
0
        public async Task GetResouceAsync_ReturnsCorrectResource()
        {
            // arrange
            var group = new AutoScalingGroup
            {
                AutoScalingGroupName = "ASG Name"
            };

            var firstPage = new DescribeAutoScalingGroupsResponse
            {
                AutoScalingGroups = new List <AutoScalingGroup>
                {
                    group
                }
            };

            var client = CreateAutoScalingClientStub(firstPage);

            // act
            var sut    = new AutoScalingGroupSource(client);
            var result = await sut.GetResourceAsync(group.AutoScalingGroupName);

            // assert
            Assert.That(result, Is.EqualTo(group));
        }
Пример #2
0
        public ApplicationLoadBalancerStack(Construct parent, string id, IStackProps props) : base(parent, id, props)
        {
            var vpc = new Vpc(this, "VPC");

            var asg = new AutoScalingGroup(this, "ASG", new AutoScalingGroupProps {
                Vpc          = vpc,
                InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MICRO),
                MachineImage = new AmazonLinuxImage()
            });

            var lb = new Amazon.CDK.AWS.ElasticLoadBalancingV2.ApplicationLoadBalancer(this, "LB", new ApplicationLoadBalancerProps {
                Vpc            = vpc,
                InternetFacing = true
            });

            var listener = lb.AddListener("Listener", new BaseApplicationListenerProps {
                Port = 80
            });

            listener.AddTargets("Target", new AddApplicationTargetsProps {
                Port    = 80,
                Targets = new IApplicationLoadBalancerTarget[] { asg }
            });

            listener.Connections.AllowDefaultPortFromAnyIpv4("Open to the world");

            asg.ScaleOnRequestCount("AModestLoad", new RequestCountScalingProps {
                TargetRequestsPerSecond = 1
            });
        }
        public ClassicLoadBalancerStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var vpc = new Vpc(this, "VPC");

            var asg = new AutoScalingGroup(this, "ASG", new AutoScalingGroupProps
            {
                Vpc          = vpc,
                InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MICRO),
                MachineImage = new AmazonLinuxImage()
            });

            var lb = new LoadBalancer(this, "LB", new LoadBalancerProps
            {
                Vpc            = vpc,
                InternetFacing = true,
                HealthCheck    = new Amazon.CDK.AWS.ElasticLoadBalancing.HealthCheck
                {
                    Port = 80
                }
            });

            lb.AddTarget(asg);
            var listener = lb.AddListener(new LoadBalancerListener {
                ExternalPort = 80
            });

            listener.Connections.AllowDefaultPortFromAnyIpv4("Open to the world");
        }
        public void GetAttribute_KnownAttribute_ReturnsValue()
        {
            //arange
            var sut = new AutoScalingGroupAlarmDataProvider();

            var autoScalingGroup = new AutoScalingGroup
            {
                DesiredCapacity = 30
            };

            //act
            var result = sut.GetValue(autoScalingGroup, "GroupDesiredCapacity");

            //assert
            Assert.That(result, Is.EqualTo(autoScalingGroup.DesiredCapacity));
        }
        public void GetDimensions_KnownDimensions_ReturnsValue()
        {
            //arange
            var sut = new AutoScalingGroupAlarmDataProvider();

            var autoScalingGroup = new AutoScalingGroup
            {
                AutoScalingGroupName = "ASG Name"
            };

            //act
            var result = sut.GetDimensions(autoScalingGroup, new List <string> {
                "AutoScalingGroupName"
            });

            //assert
            Assert.That(result.Count, Is.EqualTo(1));
            var dim = result.Single();

            Assert.That(dim.Value, Is.EqualTo(autoScalingGroup.AutoScalingGroupName));
            Assert.That(dim.Name, Is.EqualTo("AutoScalingGroupName"));
        }
Пример #6
0
        internal AutoScaledInstances(
            CdkStack stack,
            CfnParameter targetPlatform,
            Vpc vpc,
            bool publicAccess,
            SecurityGroup albSecurityGroup,
            SecurityGroup instanceSecurityGroup,
            Database database = null,
            Policy policy     = null,
            ApplicationLoadBalancer restApiLoadBalancer = null)
        {
            IMachineImage selectedImage;

            bool targetWindows = false;

            if (targetWindows)
            {
                var userData = UserData.ForWindows();
                userData.AddCommands(
                    "New-Item -Path c:\\temp -ItemType Directory -Force",
                    $"Read-S3Object -BucketName aws-codedeploy-{stack.Region}/latest -Key codedeploy-agent.msi -File c:\\temp\\codedeploy-agent.msi",
                    "Start-Process -Wait -FilePath c:\\temp\\codedeploy-agent.msi -WindowStyle Hidden"
                    );
                selectedImage = new WindowsImage(
                    WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_CORE_BASE,
                    new WindowsImageProps
                {
                    UserData = userData
                }
                    );
            }
            else
            {
                var userData = UserData.ForLinux(new LinuxUserDataOptions {
                    Shebang = "#!/bin/bash -xe"
                });
                userData.AddCommands(
                    "exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1",
                    "yum install -y aws-cli ruby jq",
                    "yum -y update",
                    "cd /tmp/",
                    $"curl -O https://aws-codedeploy-{stack.Region}.s3.amazonaws.com/latest/install",
                    "chmod +x ./install",
                    "if ./install auto; then",
                    "    echo \"CodeDeploy Agent installation completed successfully!\"",
                    "    exit 0",
                    "else",
                    "    echo \"CodeDeploy Agent installation failed, please investigate.\"",
                    "    rm -f /tmp/install",
                    "    exit 1",
                    "fi",
                    "rm -rf /tmp/*"
                    );
                selectedImage = new AmazonLinuxImage(new AmazonLinuxImageProps
                {
                    Edition        = AmazonLinuxEdition.STANDARD,
                    Virtualization = AmazonLinuxVirt.HVM,
                    Generation     = AmazonLinuxGeneration.AMAZON_LINUX_2,
                    Storage        = AmazonLinuxStorage.EBS,
                    UserData       = userData
                });
            };

            var alb = new ApplicationLoadBalancer(stack, $"ApplicationLoadBalancer-{(publicAccess ? "public" : "private")}", new ApplicationLoadBalancerProps
            {
                InternetFacing = publicAccess,
                Vpc            = vpc,
                VpcSubnets     = new SubnetSelection {
                    SubnetType = publicAccess ? SubnetType.PUBLIC : SubnetType.PRIVATE
                },
                SecurityGroup = albSecurityGroup,
                IpAddressType = IpAddressType.IPV4,
                Http2Enabled  = true
            });

            var albTargetGroup = new ApplicationTargetGroup(stack, $"ApplicationTargetGroup-{(publicAccess ? "public" : "private")}", new ApplicationTargetGroupProps
            {
                Vpc         = vpc,
                Port        = 80,
                Protocol    = ApplicationProtocol.HTTP,
                TargetType  = TargetType.INSTANCE,
                HealthCheck = new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck
                {
                    Timeout  = Duration.Seconds(5),
                    Interval = Duration.Seconds(10),
                    HealthyThresholdCount = 2
                }
            });
            var albListener = new ApplicationListener(stack, $"ApplicationListener-{(publicAccess ? "public" : "private")}", new ApplicationListenerProps
            {
                Port          = 80,
                Protocol      = ApplicationProtocol.HTTP,
                DefaultAction = ListenerAction.Forward(new[] { albTargetGroup }),
                LoadBalancer  = alb
            });

            var asg = new AutoScalingGroup(stack, $"ASG-{(publicAccess ? "public" : "private")}", new AutoScalingGroupProps
            {
                Vpc          = vpc,
                MinCapacity  = 2,
                InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MEDIUM),
                MachineImage = selectedImage,
                BlockDevices = new[] {
                    new Amazon.CDK.AWS.AutoScaling.BlockDevice()
                    {
                        DeviceName = "/dev/xvda",
                        Volume     = Amazon.CDK.AWS.AutoScaling.BlockDeviceVolume.Ebs(
                            targetWindows ? 30: 8,
                            new Amazon.CDK.AWS.AutoScaling.EbsDeviceOptions {
                            VolumeType          = Amazon.CDK.AWS.AutoScaling.EbsDeviceVolumeType.GP2,
                            DeleteOnTermination = true
                        }
                            )
                    }
                },
                AssociatePublicIpAddress = false,
                VpcSubnets = new SubnetSelection {
                    SubnetType = SubnetType.PRIVATE
                }
            });

            if (policy != null)
            {
                asg.Role.AttachInlinePolicy(policy);
            }
            asg.Role.AddToPrincipalPolicy(
                new PolicyStatement(new PolicyStatementProps
            {
                Effect    = Effect.ALLOW,
                Actions   = new[] { "ec2:DescribeTags" },
                Resources = new[] { "*" }
            })
                );
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"));
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSXRayDaemonWriteAccess"));
            asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("CloudWatchAgentServerPolicy"));

            Tag.Add(asg, "Application", stack.StackName);
            if (publicAccess)
            {
                Tag.Add(asg, "ApplicationRole", "Front End");
                Tag.Add(asg, "RESTAPIAddress", restApiLoadBalancer.LoadBalancerDnsName);
            }
            else
            {
                Tag.Add(asg, "ApplicationRole", "REST API");
            }
            if (database != null)
            {
                asg.Node.AddDependency(database.DatabaseResource);
                Tag.Add(asg, "DBSecretArn", database.Password.SecretArn);
            }

            // Enable access from the ALB
            asg.AddSecurityGroup(instanceSecurityGroup);
            Result = new LoadBalancedInstancesResult
            {
                AutoScalingGroup = asg,
                TargetGroup      = albTargetGroup,
                LoadBalancer     = alb
            };
        }
Пример #7
0
 public void AddAutoScalingGroupToCluster(string asgId, AutoScalingGroup autoScalingGroup, Cluster cluster)
 {
     HandlerResources.AwsCdkEcsHandler.AddAutoScalingGroupToCluster(asgId, autoScalingGroup, cluster);
 }
        internal AppdeploymentStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            #region Application hosting resources

            var vpc = new Vpc(this, "appVpc", new VpcProps
            {
                MaxAzs = 3
            });

            var image = new LookupMachineImage(new LookupMachineImageProps
            {
                // maps to "Amazon Linux 2 with .NET Core 3.0 and Mono 5.18"
                Name   = "amzn2-ami-hvm-2.0.*-x86_64-gp2-mono-*",
                Owners = new [] { "amazon" }
            });

            var userData = UserData.ForLinux();
            userData.AddCommands(new string[]
            {
                "sudo yum install -y httpd",
                "sudo systemctl start httpd",
                "sudo systemctl enable httpd"
            });

            var scalingGroup = new AutoScalingGroup(this, "appASG", new AutoScalingGroupProps
            {
                Vpc              = vpc,
                InstanceType     = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MEDIUM),
                MachineImage     = image,
                MinCapacity      = 1,
                MaxCapacity      = 4,
                AllowAllOutbound = true,
                UserData         = userData
            });

            var alb = new ApplicationLoadBalancer(this, "appLB", new ApplicationLoadBalancerProps
            {
                Vpc            = vpc,
                InternetFacing = true
            });

            var albListener = alb.AddListener("Port80Listener", new BaseApplicationListenerProps
            {
                Port = 80
            });

            albListener.AddTargets("Port80ListenerTargets", new AddApplicationTargetsProps
            {
                Port    = 80,
                Targets = new [] { scalingGroup }
            });

            albListener.Connections.AllowDefaultPortFromAnyIpv4("Open access to port 80");

            scalingGroup.ScaleOnRequestCount("ScaleOnModestLoad", new RequestCountScalingProps
            {
                TargetRequestsPerSecond = 1
            });

            #endregion

            #region CI/CD resources

            var _sourceOutput = new Artifact_("Source");
            var _buildOutput  = new Artifact_("Build");

            var build = new PipelineProject(this, "CodeBuild", new PipelineProjectProps
            {
                // relative path to sample app's file (single html page for now)
                BuildSpec   = BuildSpec.FromSourceFilename("talk-demos/appdeployment/SimplePage/buildspec.yml"),
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_2
                },
            });

            var appDeployment = new ServerApplication(this, "appDeployment");
            // we will use CodeDeploy's default one-at-a-time deployment mode as we are
            // not specifying a deployment config
            var deploymentGroup = new ServerDeploymentGroup(this, "appDeploymentGroup", new ServerDeploymentGroupProps
            {
                Application  = appDeployment,
                InstallAgent = true,
                AutoRollback = new AutoRollbackConfig
                {
                    FailedDeployment = true
                },
                AutoScalingGroups = new [] { scalingGroup }
            });

            // SecretValue.SsmSecure is not currently supported for setting OauthToken,
            // and haven't gotten the SecretsManager approach to work either so
            // resorting to keeping my token in an environment var for now!
            var oauthToken = SecretValue.PlainText(System.Environment.GetEnvironmentVariable("GitHubPersonalToken"));

            var pipeline = new Pipeline(this, "sampleappPipeline", new PipelineProps
            {
                Stages = new StageProps[]
                {
                    new StageProps
                    {
                        StageName = "Source",
                        Actions   = new IAction[]
                        {
                            new GitHubSourceAction(new GitHubSourceActionProps
                            {
                                ActionName = "GitHubSource",
                                Branch     = "master",
                                Repo       = this.Node.TryGetContext("repo-name").ToString(),
                                Owner      = this.Node.TryGetContext("repo-owner").ToString(),
                                OauthToken = oauthToken,
                                Output     = _sourceOutput
                            })
                        }
                    },

                    new StageProps
                    {
                        StageName = "Build",
                        Actions   = new IAction[]
                        {
                            new CodeBuildAction(new CodeBuildActionProps
                            {
                                ActionName = "Build-app",
                                Project    = build,
                                Input      = _sourceOutput,
                                Outputs    = new Artifact_[] { _buildOutput },
                                RunOrder   = 1
                            })
                        }
                    },

                    new StageProps
                    {
                        StageName = "Deploy",
                        Actions   = new IAction[]
                        {
                            new CodeDeployServerDeployAction(new CodeDeployServerDeployActionProps
                            {
                                ActionName      = "Deploy-app",
                                Input           = _buildOutput,
                                RunOrder        = 2,
                                DeploymentGroup = deploymentGroup
                            })
                        }
                    }
                }
            });

            #endregion
        }
        public virtual void failover()
        {
            try
            {
                // Modify the autoscaling group to remove the AZ affected which is the AZ passed in the input
                // Find the autoscaling group that this is deployed into
                // Note: This changes the asynchronous call to a synchronous one
                DescribeAutoScalingGroupsResponse autoScalingGroupsResponse = AUTO_SCALING_CLIENT.DescribeAutoScalingGroupsAsync().GetAwaiter().GetResult();

                if (autoScalingGroupsResponse != null && autoScalingGroupsResponse.AutoScalingGroups.Count > 0)
                {
                    // Note: This assumes an Auto Scaling group exists; no error checking for readability
                    AutoScalingGroup autoScalingGroup     = autoScalingGroupsResponse.AutoScalingGroups[0];
                    string           autoScalingGroupName = autoScalingGroup.AutoScalingGroupName;

                    // Find all subnets in the availability zone passed in the input
                    DescribeSubnetsResponse subnetsResult
                        = EC2_CLIENT.DescribeSubnetsAsync(new DescribeSubnetsRequest()
                    {
                        Filters = new List <Amazon.EC2.Model.Filter> {
                            new Amazon.EC2.Model.Filter {
                                Name   = "vpc-id",
                                Values = new List <string> {
                                    vpcId
                                }
                            }
                        }
                    }).GetAwaiter().GetResult();
                    IList <string> desiredSubnetsForASG = new List <string>();
                    foreach (Amazon.EC2.Model.Subnet subnet in subnetsResult.Subnets)
                    {
                        if (!string.Equals(subnet.AvailabilityZone, azId, StringComparison.OrdinalIgnoreCase))
                        {
                            desiredSubnetsForASG.Add(subnet.SubnetId);
                        }
                    }

                    List <string> desiredSubnets = new List <String>(autoScalingGroup.VPCZoneIdentifier.Split(new[] { ',' }, StringSplitOptions.None));

                    var tempList = new List <String>(desiredSubnets);
                    foreach (var subnet in desiredSubnets)
                    {
                        if (!desiredSubnetsForASG.Contains(subnet))
                        {
                            tempList.Remove(subnet);
                        }
                    }
                    desiredSubnets = tempList;

                    Console.WriteLine("Updating the auto scaling group " + autoScalingGroupName + " to remove the subnet in the AZ");

                    // Note: This turns the asynchronous call into a synchronous one
                    UpdateAutoScalingGroupResponse updateAutoScalingGroupResponse
                        = AUTO_SCALING_CLIENT.UpdateAutoScalingGroupAsync(new UpdateAutoScalingGroupRequest
                    {
                        AutoScalingGroupName = autoScalingGroupName,
                        VPCZoneIdentifier    = string.Join(",", desiredSubnets)
                    }).GetAwaiter().GetResult();
                }

                // Find all subnets in the availability zone passed in the input
                // Note: This turns the asynchronous call into a synchronous one
                DescribeSubnetsResponse describeSubnetsResult
                    = EC2_CLIENT.DescribeSubnetsAsync(new DescribeSubnetsRequest
                {
                    Filters = new List <Amazon.EC2.Model.Filter> {
                        new Amazon.EC2.Model.Filter {
                            Name   = "vpc-id",
                            Values = new List <string> {
                                vpcId
                            }
                        },
                        new Amazon.EC2.Model.Filter {
                            Name   = "availabilityZone",
                            Values = new List <string> {
                                azId
                            }
                        }
                    }
                }).GetAwaiter().GetResult();

                IList <string> desiredSubnetsForAddingNewNacl = new List <string>();
                foreach (Amazon.EC2.Model.Subnet subnet in describeSubnetsResult.Subnets)
                {
                    desiredSubnetsForAddingNewNacl.Add(subnet.SubnetId);
                }

                //Find all the network acl associations matching the subnets identified above
                // Note: This turns the asynchronous call into a synchronous one
                DescribeNetworkAclsResponse describeNetworkAclsResult
                    = EC2_CLIENT.DescribeNetworkAclsAsync(new DescribeNetworkAclsRequest()
                {
                    Filters = new List <Amazon.EC2.Model.Filter> {
                        new Amazon.EC2.Model.Filter {
                            Name   = "association.subnet-id",
                            Values = (List <string>)desiredSubnetsForAddingNewNacl
                        }
                    }
                }).GetAwaiter().GetResult();

                IList <NetworkAclAssociation> desiredAclAssociations = new List <NetworkAclAssociation>();
                // Note: This assumes a Network ACL is present for readability
                IList <NetworkAclAssociation> networkAclsAssociatedWithSubnet = describeNetworkAclsResult.NetworkAcls[0].Associations;
                foreach (string subnetId in desiredSubnetsForAddingNewNacl)
                {
                    foreach (NetworkAclAssociation networkAcl in networkAclsAssociatedWithSubnet)
                    {
                        if (string.Equals(networkAcl.SubnetId, subnetId, StringComparison.OrdinalIgnoreCase))
                        {
                            desiredAclAssociations.Add(networkAcl);
                        }
                    }
                }

                //create new network acl association with both ingress and egress denying to all the traffic
                CreateNetworkAclRequest createNetworkAclRequest = new CreateNetworkAclRequest();
                createNetworkAclRequest.VpcId = vpcId;
                // Note: This turns the asynchronous call into a synchronous one
                CreateNetworkAclResponse createNetworkAclResponse = EC2_CLIENT.CreateNetworkAclAsync(createNetworkAclRequest).GetAwaiter().GetResult();
                string networkAclId = createNetworkAclResponse.NetworkAcl.NetworkAclId;
                createNetworkAclEntry(networkAclId, 100, "0.0.0.0/0", true, "-1", createPortRange(0, 65535), RuleAction.Deny);
                createNetworkAclEntry(networkAclId, 101, "0.0.0.0/0", false, "-1", createPortRange(0, 65535), RuleAction.Deny);

                // replace all the network acl associations identified for the above subnets with the new network
                // acl association which will deny all traffic for those subnets in that AZ
                Console.WriteLine("Creating new network ACL associations");
                replaceNetworkAclAssociations(desiredAclAssociations, networkAclId);

                //fail over rds which is in the same AZ
                // Note: This turns the asynchronous call into a synchronous one
                DescribeDBInstancesResponse describeDBInstancesResult = RDS_CLIENT.DescribeDBInstancesAsync().GetAwaiter().GetResult();
                IList <DBInstance>          dbInstances = describeDBInstancesResult.DBInstances;
                string dbInstancedId = null;
                foreach (DBInstance dbInstance in dbInstances)
                {
                    if (string.Equals(dbInstance.DBSubnetGroup.VpcId, vpcId, StringComparison.OrdinalIgnoreCase) &&
                        (string.Equals(dbInstance.AvailabilityZone, azId, StringComparison.OrdinalIgnoreCase)) &&
                        dbInstance.MultiAZ && dbInstance.StatusInfos.Count == 0)
                    {
                        dbInstancedId = dbInstance.DBInstanceIdentifier;
                    }
                }
                // we want to fail over rds if rds is present in the same az where it is affected
                if (!string.IsNullOrEmpty(dbInstancedId))

                {
                    RebootDBInstanceRequest rebootDBInstanceRequest = new RebootDBInstanceRequest();
                    rebootDBInstanceRequest.DBInstanceIdentifier = dbInstancedId;
                    rebootDBInstanceRequest.ForceFailover        = true;
                    Console.WriteLine("Rebooting dbInstanceId to secondary AZ " + dbInstancedId);
                    // Note: This turns the asynchronous call into a synchronous one
                    RDS_CLIENT.RebootDBInstanceAsync(rebootDBInstanceRequest).GetAwaiter().GetResult();
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine("Unkown exception occured " + exception.Message);
            }
        }
Пример #10
0
        internal GrpcBenchmarkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var vpc = new Vpc(this, "vpc", new VpcProps
            {
                MaxAzs              = 1,
                NatGateways         = 0,
                SubnetConfiguration = new[] { new SubnetConfiguration {
                                                  Name = "public", SubnetType = SubnetType.PUBLIC
                                              } },
            });
            var subnets = new SubnetSelection {
                Subnets = vpc.PublicSubnets
            };
            var sg = new SecurityGroup(this, "MasterSg", new SecurityGroupProps
            {
                AllowAllOutbound = true,
                Vpc = vpc,
            });
            var role = new Role(this, "MasterRole", new RoleProps
            {
                AssumedBy = new ServicePrincipal("ec2.amazonaws.com"),
            });

            role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"));

            var spot = new AutoScalingGroup(this, "instances", new AutoScalingGroupProps
            {
                // Monitoring is default DETAILED.
                SpotPrice                = "1.0", // 0.0096 for spot price average for m3.medium
                Vpc                      = vpc,
                SecurityGroup            = sg,
                VpcSubnets               = subnets,
                InstanceType             = InstanceType.Of(InstanceClass.COMPUTE5_AMD, InstanceSize.XLARGE4),
                DesiredCapacity          = 1,
                MaxCapacity              = 1,
                MinCapacity              = 0,
                AssociatePublicIpAddress = true,
                MachineImage             = new AmazonLinuxImage(new AmazonLinuxImageProps
                {
                    CpuType        = AmazonLinuxCpuType.X86_64,
                    Generation     = AmazonLinuxGeneration.AMAZON_LINUX_2,
                    Storage        = AmazonLinuxStorage.GENERAL_PURPOSE,
                    Virtualization = AmazonLinuxVirt.HVM,
                }),
                AllowAllOutbound = true,
                GroupMetrics     = new[] { GroupMetrics.All() },
                Role             = role,
                UpdatePolicy     = UpdatePolicy.ReplacingUpdate(),
            });

            // https://gist.github.com/npearce/6f3c7826c7499587f00957fee62f8ee9
            spot.AddUserData(new[]
            {
                "amazon-linux-extras install docker -y",
                "service docker start",
                "chkconfig docker on",
                "usermod -a -G docker ec2-user",
                "curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose",
                "chmod +x /usr/local/bin/docker-compose",
                "yum install -y git",
                "reboot",
            });
        }
        public virtual async Task Failover()
        {
            try
            {
                Console.WriteLine($"Simulating AZ failure for {azName}");

                // Find all subnets in the availability zone passed in the input
                DescribeSubnetsResponse subnetsInSpecifiedAZandVpc
                    = await ec2Client.DescribeSubnetsAsync(new DescribeSubnetsRequest()
                {
                    Filters = new List <Amazon.EC2.Model.Filter> {
                        new Amazon.EC2.Model.Filter {
                            Name   = "vpc-id",
                            Values = { vpcId }
                        },
                        new Amazon.EC2.Model.Filter {
                            Name   = "availability-zone",
                            Values = { azName }
                        }
                    }
                });

                List <string> subnetIdsInSpecifiedAZ = subnetsInSpecifiedAZandVpc.Subnets.Select(x => x.SubnetId).ToList();

                // Modify the autoscaling group to remove the AZ affected which is the AZ passed in the input
                // Find the autoscaling group that this is deployed into
                DescribeAutoScalingGroupsResponse autoScalingGroupsResponse = await asClient.DescribeAutoScalingGroupsAsync();

                if (autoScalingGroupsResponse != null && autoScalingGroupsResponse.AutoScalingGroups.Count > 0)
                {
                    // Note: This assumes an Auto Scaling group exists; no error checking for readability
                    AutoScalingGroup autoScalingGroup = autoScalingGroupsResponse.AutoScalingGroups[0];

                    Console.WriteLine($"Updating the auto scaling group {autoScalingGroup.AutoScalingGroupName} to remove the subnet in {azName}");

                    UpdateAutoScalingGroupResponse updateAutoScalingGroupResponse
                        = await asClient.UpdateAutoScalingGroupAsync(new UpdateAutoScalingGroupRequest
                    {
                        AutoScalingGroupName = autoScalingGroup.AutoScalingGroupName,
                        VPCZoneIdentifier    = String.Join(",", autoScalingGroup.VPCZoneIdentifier.Split(',').Where(x => !subnetIdsInSpecifiedAZ.Contains(x)))
                    });
                }

                Console.WriteLine("Creating new network ACL associations");
                await BlockSubnetsInAZ(vpcId, subnetIdsInSpecifiedAZ);

                Console.WriteLine("Failing over database");

                //fail over rds which is in the same AZ
                DescribeDBInstancesResponse describeDBInstancesResult = await rdsClient.DescribeDBInstancesAsync();

                string dbInstancedId = describeDBInstancesResult.DBInstances.Where(x => String.Equals(x.DBSubnetGroup.VpcId, vpcId, StringComparison.OrdinalIgnoreCase) &&
                                                                                   String.Equals(x.AvailabilityZone, azName, StringComparison.OrdinalIgnoreCase) &&
                                                                                   x.MultiAZ &&
                                                                                   !x.StatusInfos.Any())?.Select(x => x.DBInstanceIdentifier).FirstOrDefault();

                // we want to fail over rds if rds is present in the same az where it is affected
                if (!String.IsNullOrEmpty(dbInstancedId))
                {
                    Console.WriteLine("Rebooting dbInstanceId to secondary AZ " + dbInstancedId);

                    var response = await rdsClient.RebootDBInstanceAsync(new RebootDBInstanceRequest()
                    {
                        DBInstanceIdentifier = dbInstancedId,
                        ForceFailover        = true
                    });
                }
                else
                {
                    Console.WriteLine($"Didn't find DB in the same AZ as {azName}");
                }

                Console.Write("Done");
            }
            catch (Exception exception)
            {
                Console.WriteLine("Unknown exception occurred " + exception.Message);
            }
        }
Пример #12
0
        internal CdkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var stackProps                = ReportStackProps.ParseOrDefault(props);
            var dframeWorkerLogGroup      = "MagicOnionBenchWorkerLogGroup";
            var dframeMasterLogGroup      = "MagicOnionBenchMasterLogGroup";
            var benchNetwork              = stackProps.GetBenchNetwork();
            var recreateMagicOnionTrigger = stackProps.GetBenchmarkServerBinariesHash();

            // s3
            var s3 = new Bucket(this, "Bucket", new BucketProps
            {
                AutoDeleteObjects = true,
                RemovalPolicy     = RemovalPolicy.DESTROY,
                AccessControl     = BucketAccessControl.PRIVATE,
            });
            var lifecycleRule = new LifecycleRule
            {
                Enabled    = true,
                Prefix     = "reports/",
                Expiration = Duration.Days(stackProps.DaysKeepReports),
                AbortIncompleteMultipartUploadAfter = Duration.Days(1),
            };

            s3.AddLifecycleRule(lifecycleRule);
            s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps
            {
                Sid        = "AllowPublicRead",
                Effect     = Effect.ALLOW,
                Principals = new[] { new AnyPrincipal() },
                Actions    = new[] { "s3:GetObject*" },
                Resources  = new[] { $"{s3.BucketArn}/html/*" },
            }));
            s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps
            {
                Sid        = "AllowAwsAccountAccess",
                Effect     = Effect.ALLOW,
                Principals = new[] { new AccountRootPrincipal() },
                Actions    = new[] { "s3:*" },
                Resources  = new[] { $"{s3.BucketArn}/*" },
            }));

            // s3 deploy
            var masterDllDeployment = new BucketDeployment(this, "DeployMasterDll", new BucketDeploymentProps
            {
                DestinationBucket    = s3,
                Sources              = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), $"out/linux/server")) },
                DestinationKeyPrefix = $"assembly/linux/server"
            });
            var userdataDeployment = new BucketDeployment(this, "UserData", new BucketDeploymentProps
            {
                DestinationBucket    = s3,
                Sources              = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), "userdata/")) },
                DestinationKeyPrefix = "userdata/"
            });

            // docker deploy
            var dockerImage = new DockerImageAsset(this, "dframeWorkerImage", new DockerImageAssetProps
            {
                Directory = Path.Combine(Directory.GetCurrentDirectory(), "app"),
                File      = "ConsoleAppEcs/Dockerfile.Ecs",
            });
            var dframeImage = ContainerImage.FromDockerImageAsset(dockerImage);

            // network
            var vpc = new Vpc(this, "Vpc", new VpcProps
            {
                MaxAzs              = 2,
                NatGateways         = 0,
                SubnetConfiguration = new[] { new SubnetConfiguration {
                                                  Name = "public", SubnetType = SubnetType.PUBLIC
                                              } },
            });
            var allsubnets = new SubnetSelection {
                Subnets = vpc.PublicSubnets
            };
            var singleSubnets = new SubnetSelection {
                Subnets = new[] { vpc.PublicSubnets.First() }
            };
            var sg = new SecurityGroup(this, "MasterSg", new SecurityGroupProps
            {
                AllowAllOutbound = true,
                Vpc = vpc,
            });

            foreach (var subnet in vpc.PublicSubnets)
            {
                sg.AddIngressRule(Peer.Ipv4(vpc.VpcCidrBlock), Port.AllTcp(), "VPC", true);
            }

            // service discovery
            var serviceDiscoveryDomain = "local";
            var serverMapName          = "server";
            var dframeMapName          = "dframe-master";
            var ns = new PrivateDnsNamespace(this, "Namespace", new PrivateDnsNamespaceProps
            {
                Vpc  = vpc,
                Name = serviceDiscoveryDomain,
            });
            var serviceDiscoveryServer = ns.CreateService("server", new DnsServiceProps
            {
                Name          = serverMapName,
                DnsRecordType = DnsRecordType.A,
                RoutingPolicy = RoutingPolicy.MULTIVALUE,
            });

            // alb
            var albDnsName = "benchmark-alb";
            var benchToMagicOnionDnsName = benchNetwork.RequireAlb
                ? $"{benchNetwork.EndpointScheme}://{albDnsName}.{stackProps.AlbDomain.domain}"
                : $"{benchNetwork.EndpointScheme}://{serverMapName}.{serviceDiscoveryDomain}";
            IApplicationTargetGroup grpcTargetGroup  = null;
            IApplicationTargetGroup httpsTargetGroup = null;

            if (benchNetwork.RequireAlb)
            {
                // route53
                var hostedZone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes
                {
                    HostedZoneId = stackProps.AlbDomain.zoneId,
                    ZoneName     = stackProps.AlbDomain.domain,
                });

                // acm
                var certificate = new DnsValidatedCertificate(this, "certificate", new DnsValidatedCertificateProps
                {
                    DomainName = $"{albDnsName}.{hostedZone.ZoneName}",
                    HostedZone = hostedZone,
                });
                // alb
                var lb = new ApplicationLoadBalancer(this, "LB", new ApplicationLoadBalancerProps
                {
                    Vpc           = vpc,
                    VpcSubnets    = allsubnets,
                    SecurityGroup = new SecurityGroup(this, "AlbSg", new SecurityGroupProps
                    {
                        AllowAllOutbound = true,
                        Vpc = vpc,
                    }),
                    InternetFacing = false,
                    Http2Enabled   = true,
                });
                grpcTargetGroup  = AddGrpcTargetGroup(benchNetwork, vpc, certificate, lb);
                httpsTargetGroup = AddHttpsTargetGroup(benchNetwork, vpc, certificate, lb);

                // Dns Record
                _ = new CnameRecord(this, "alb-alias-record", new CnameRecordProps
                {
                    RecordName = $"{albDnsName}.{stackProps.AlbDomain.domain}",
                    Ttl        = Duration.Seconds(60),
                    Zone       = hostedZone,
                    DomainName = lb.LoadBalancerDnsName,
                });
            }

            // iam
            var iamEc2MagicOnionRole  = GetIamEc2MagicOnionRole(s3, serviceDiscoveryServer);
            var iamEcsTaskExecuteRole = GetIamEcsTaskExecuteRole(new[] { dframeWorkerLogGroup, dframeMasterLogGroup });
            var iamDFrameTaskDefRole  = GetIamEcsDframeTaskDefRole(s3);
            var iamWorkerTaskDefRole  = GetIamEcsWorkerTaskDefRole(s3);

            // secrets
            var ddToken = stackProps.UseEc2DatadogAgentProfiler || stackProps.UseFargateDatadogAgentProfiler
                ? Amazon.CDK.AWS.SecretsManager.Secret.FromSecretNameV2(this, "dd-token", "magiconion-benchmark-datadog-token")
                : null;

            // MagicOnion
            var asg = new AutoScalingGroup(this, "MagicOnionAsg", new AutoScalingGroupProps
            {
                // Monitoring is default DETAILED.
                SpotPrice                = "1.0", // 0.0096 for spot price average for m3.medium
                Vpc                      = vpc,
                SecurityGroup            = sg,
                VpcSubnets               = singleSubnets,
                InstanceType             = stackProps.MagicOnionInstanceType,
                DesiredCapacity          = 1,
                MaxCapacity              = 1,
                MinCapacity              = 0,
                AssociatePublicIpAddress = true,
                MachineImage             = new AmazonLinuxImage(new AmazonLinuxImageProps
                {
                    CpuType        = AmazonLinuxCpuType.X86_64,
                    Generation     = AmazonLinuxGeneration.AMAZON_LINUX_2,
                    Storage        = AmazonLinuxStorage.GENERAL_PURPOSE,
                    Virtualization = AmazonLinuxVirt.HVM,
                }),
                AllowAllOutbound = true,
                GroupMetrics     = new[] { GroupMetrics.All() },
                Role             = iamEc2MagicOnionRole,
                UpdatePolicy     = UpdatePolicy.ReplacingUpdate(),
                Signals          = Signals.WaitForCount(1, new SignalsOptions
                {
                    Timeout = Duration.Minutes(10),
                }),
            });

            asg.AddSecretsReadGrant(ddToken, () => stackProps.UseEc2DatadogAgentProfiler);
            var userdata = GetUserData(recreateMagicOnionTrigger, s3.BucketName, stackProps.BenchmarkBinaryNames, serviceDiscoveryServer.ServiceId, stackProps.UseEc2CloudWatchAgentProfiler, stackProps.UseEc2DatadogAgentProfiler);

            asg.AddUserData(userdata);
            asg.UserData.AddSignalOnExitCommand(asg);
            asg.Node.AddDependency(masterDllDeployment);
            asg.Node.AddDependency(userdataDeployment);
            if (stackProps.EnableMagicOnionScaleInCron)
            {
                asg.ScaleOnSchedule("ScheduleOut", new BasicScheduledActionProps
                {
                    DesiredCapacity = 1,
                    MaxCapacity     = 1,
                    // AM9:00 (JST+9) on Monday to Wednesday
                    Schedule = Schedule.Expression("0 0 * 1-3 *"),
                });
                asg.ScaleOnSchedule("ScheduleIn", new BasicScheduledActionProps
                {
                    DesiredCapacity = 0,
                    MaxCapacity     = 0,
                    // PM9:00 (JST+9) on Everyday
                    Schedule = Schedule.Expression("0 12 * 1-7 *"),
                });
            }
            if (benchNetwork.RequireAlb)
            {
                asg.AttachToApplicationTargetGroup(grpcTargetGroup);
                asg.AttachToApplicationTargetGroup(httpsTargetGroup);
            }

            // ECS
            var cluster = new Cluster(this, "WorkerCluster", new ClusterProps
            {
                Vpc = vpc,
            });

            cluster.Node.AddDependency(asg); // wait until asg is up

            // dframe-worker
            var dframeWorkerContainerName = "worker";
            var dframeWorkerTaskDef       = new FargateTaskDefinition(this, "DFrameWorkerTaskDef", new FargateTaskDefinitionProps
            {
                ExecutionRole  = iamEcsTaskExecuteRole,
                TaskRole       = iamWorkerTaskDefRole,
                Cpu            = stackProps.WorkerFargate.CpuSize,
                MemoryLimitMiB = stackProps.WorkerFargate.MemorySize,
            });

            dframeWorkerTaskDef.AddContainer(dframeWorkerContainerName, new ContainerDefinitionOptions
            {
                Image       = dframeImage,
                Command     = new[] { "--worker-flag" },
                Environment = new Dictionary <string, string>
                {
                    { "DFRAME_MASTER_CONNECT_TO_HOST", $"{dframeMapName}.{serviceDiscoveryDomain}" },
                    { "DFRAME_MASTER_CONNECT_TO_PORT", "12345" },
                    { "BENCH_SERVER_HOST", benchToMagicOnionDnsName },
                    { "BENCH_REPORTID", stackProps.ReportId },
                    { "BENCH_S3BUCKET", s3.BucketName },
                },
                Logging = LogDriver.AwsLogs(new AwsLogDriverProps
                {
                    LogGroup = new LogGroup(this, "WorkerLogGroup", new LogGroupProps
                    {
                        LogGroupName  = dframeWorkerLogGroup,
                        RemovalPolicy = RemovalPolicy.DESTROY,
                        Retention     = RetentionDays.TWO_WEEKS,
                    }),
                    StreamPrefix = dframeWorkerLogGroup,
                }),
            });
            dframeWorkerTaskDef.AddDatadogContainer($"{dframeWorkerContainerName}-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler);
            var dframeWorkerService = new FargateService(this, "DFrameWorkerService", new FargateServiceProps
            {
                ServiceName       = "DFrameWorkerService",
                DesiredCount      = 0,
                Cluster           = cluster,
                TaskDefinition    = dframeWorkerTaskDef,
                VpcSubnets        = singleSubnets,
                SecurityGroups    = new[] { sg },
                PlatformVersion   = FargatePlatformVersion.VERSION1_4,
                MinHealthyPercent = 0,
                AssignPublicIp    = true,
            });

            // dframe-master
            var dframeMasterTaskDef = new FargateTaskDefinition(this, "DFrameMasterTaskDef", new FargateTaskDefinitionProps
            {
                ExecutionRole  = iamEcsTaskExecuteRole,
                TaskRole       = iamDFrameTaskDefRole,
                Cpu            = stackProps.MasterFargate.CpuSize,
                MemoryLimitMiB = stackProps.MasterFargate.MemorySize,
            });

            dframeMasterTaskDef.AddContainer("dframe", new ContainerDefinitionOptions
            {
                Image       = dframeImage,
                Environment = new Dictionary <string, string>
                {
                    { "DFRAME_CLUSTER_NAME", cluster.ClusterName },
                    { "DFRAME_MASTER_SERVICE_NAME", "DFrameMasterService" },
                    { "DFRAME_WORKER_CONTAINER_NAME", dframeWorkerContainerName },
                    { "DFRAME_WORKER_SERVICE_NAME", dframeWorkerService.ServiceName },
                    { "DFRAME_WORKER_TASK_NAME", Fn.Select(1, Fn.Split("/", dframeWorkerTaskDef.TaskDefinitionArn)) },
                    { "DFRAME_WORKER_IMAGE", dockerImage.ImageUri },
                    { "BENCH_REPORTID", stackProps.ReportId },
                    { "BENCH_S3BUCKET", s3.BucketName },
                },
                Logging = LogDriver.AwsLogs(new AwsLogDriverProps
                {
                    LogGroup = new LogGroup(this, "MasterLogGroup", new LogGroupProps
                    {
                        LogGroupName  = dframeMasterLogGroup,
                        RemovalPolicy = RemovalPolicy.DESTROY,
                        Retention     = RetentionDays.TWO_WEEKS,
                    }),
                    StreamPrefix = dframeMasterLogGroup,
                }),
            });
            dframeMasterTaskDef.AddDatadogContainer($"dframe-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler);
            var dframeMasterService = new FargateService(this, "DFrameMasterService", new FargateServiceProps
            {
                ServiceName       = "DFrameMasterService",
                DesiredCount      = 1,
                Cluster           = cluster,
                TaskDefinition    = dframeMasterTaskDef,
                VpcSubnets        = singleSubnets,
                SecurityGroups    = new[] { sg },
                PlatformVersion   = FargatePlatformVersion.VERSION1_4,
                MinHealthyPercent = 0,
                AssignPublicIp    = true,
            });

            dframeMasterService.EnableCloudMap(new CloudMapOptions
            {
                CloudMapNamespace = ns,
                Name          = dframeMapName,
                DnsRecordType = DnsRecordType.A,
                DnsTtl        = Duration.Seconds(300),
            });

            // output
            new CfnOutput(this, "ReportUrl", new CfnOutputProps {
                Value = $"https://{s3.BucketRegionalDomainName}/html/{stackProps.ReportId}/index.html"
            });
            new CfnOutput(this, "EndPointStyle", new CfnOutputProps {
                Value = stackProps.BenchmarkEndpoint.ToString()
            });
            new CfnOutput(this, "AsgName", new CfnOutputProps {
                Value = asg.AutoScalingGroupName
            });
            new CfnOutput(this, "EcsClusterName", new CfnOutputProps {
                Value = cluster.ClusterName
            });
            new CfnOutput(this, "DFrameWorkerEcsTaskdefImage", new CfnOutputProps {
                Value = dockerImage.ImageUri
            });
        }