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)); }
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")); }
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 }; }
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); } }
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); } }
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 }); }