public string Build(CloudApplication cloudApplication, Recommendation recommendation) { // General Settings var appSettingsContainer = new RecipeConfiguration <Dictionary <string, object> >() { StackName = cloudApplication.StackName, ProjectPath = new FileInfo(recommendation.ProjectPath).Directory.FullName, ECRRepositoryName = recommendation.DeploymentBundle.ECRRepositoryName ?? "", ECRImageTag = recommendation.DeploymentBundle.ECRImageTag ?? "", DotnetPublishZipPath = recommendation.DeploymentBundle.DotnetPublishZipPath ?? "", DotnetPublishOutputDirectory = recommendation.DeploymentBundle.DotnetPublishOutputDirectory ?? "", Settings = new Dictionary <string, object>() }; appSettingsContainer.RecipeId = recommendation.Recipe.Id; appSettingsContainer.RecipeVersion = recommendation.Recipe.Version; // Option Settings foreach (var optionSetting in recommendation.Recipe.OptionSettings) { appSettingsContainer.Settings[optionSetting.Id] = recommendation.GetOptionSettingValue(optionSetting); } return(JsonConvert.SerializeObject(appSettingsContainer, Formatting.Indented)); }
internal AppStack(Construct scope, RecipeConfiguration <Configuration> recipeConfiguration, IStackProps props = null) : base(scope, recipeConfiguration.StackName, props) { var bucketProps = new BucketProps { WebsiteIndexDocument = recipeConfiguration.Settings.IndexDocument, PublicReadAccess = true, // Turn on delete objects so deployed Blazor application is deleted when the stack is deleted. AutoDeleteObjects = true, RemovalPolicy = RemovalPolicy.DESTROY }; if (recipeConfiguration.Settings.Redirect404ToRoot) { bucketProps.WebsiteRoutingRules = new IRoutingRule[] { new RoutingRule { Condition = new RoutingRuleCondition { HttpErrorCodeReturnedEquals = "404" }, ReplaceKey = ReplaceKey.With("") } }; } if (!string.IsNullOrEmpty(recipeConfiguration.Settings.ErrorDocument)) { bucketProps.WebsiteErrorDocument = recipeConfiguration.Settings.ErrorDocument; } var bucket = new Bucket(this, "BlazorHost", bucketProps); new BucketDeployment(this, "BlazorDeployment", new BucketDeploymentProps { Sources = new ISource[] { Source.Asset(Path.Combine(recipeConfiguration.DotnetPublishOutputDirectory, "wwwroot")) }, DestinationBucket = bucket }); new CfnOutput(this, "EndpointURL", new CfnOutputProps { Value = $"http://{bucket.BucketWebsiteDomainName}/" }); }
internal AppStack(Construct scope, RecipeConfiguration <Configuration> recipeConfiguration, IStackProps props = null) : base(scope, recipeConfiguration.StackName, props) { var settings = recipeConfiguration.Settings; IVpc vpc; if (settings.Vpc.IsDefault) { vpc = Vpc.FromLookup(this, "Vpc", new VpcLookupOptions { IsDefault = true }); } else if (settings.Vpc.CreateNew) { vpc = new Vpc(this, "Vpc", new VpcProps { MaxAzs = 2 }); } else { vpc = Vpc.FromLookup(this, "Vpc", new VpcLookupOptions { VpcId = settings.Vpc.VpcId }); } ICluster cluster; if (settings.ECSCluster.CreateNew) { cluster = new Cluster(this, "Cluster", new ClusterProps { Vpc = vpc, ClusterName = settings.ECSCluster.NewClusterName }); } else { cluster = Cluster.FromClusterAttributes(this, "Cluster", new ClusterAttributes { ClusterArn = settings.ECSCluster.ClusterArn, ClusterName = ECSFargateUtilities.GetClusterNameFromArn(settings.ECSCluster.ClusterArn), SecurityGroups = new ISecurityGroup[0], Vpc = vpc }); } IRole taskRole; if (settings.ApplicationIAMRole.CreateNew) { taskRole = new Role(this, "TaskRole", new RoleProps { AssumedBy = new ServicePrincipal("ecs-tasks.amazonaws.com") }); } else { taskRole = Role.FromRoleArn(this, "TaskRole", settings.ApplicationIAMRole.RoleArn, new FromRoleArnOptions { Mutable = false }); } var taskDefinition = new FargateTaskDefinition(this, "TaskDefinition", new FargateTaskDefinitionProps { TaskRole = taskRole, Cpu = settings.TaskCpu, MemoryLimitMiB = settings.TaskMemory }); var logging = new AwsLogDriver(new AwsLogDriverProps { StreamPrefix = recipeConfiguration.StackName }); var ecrRepository = Repository.FromRepositoryName(this, "ECRRepository", recipeConfiguration.ECRRepositoryName); taskDefinition.AddContainer("Container", new ContainerDefinitionOptions { Image = ContainerImage.FromEcrRepository(ecrRepository, recipeConfiguration.ECRImageTag), Logging = logging }); SubnetSelection subnetSelection = null; if (settings.Vpc.IsDefault) { subnetSelection = new SubnetSelection { SubnetType = SubnetType.PUBLIC }; } new ScheduledFargateTask(this, "FargateService", new ScheduledFargateTaskProps { Cluster = cluster, Schedule = Schedule.Expression(settings.Schedule), Vpc = vpc, ScheduledFargateTaskDefinitionOptions = new ScheduledFargateTaskDefinitionOptions { TaskDefinition = taskDefinition }, SubnetSelection = subnetSelection }); }
internal AppStack(Construct scope, RecipeConfiguration <Configuration> recipeConfiguration, IStackProps props = null) : base(scope, recipeConfiguration.StackName, props) { var settings = recipeConfiguration.Settings; var asset = new Asset(this, "Asset", new AssetProps { Path = recipeConfiguration.DotnetPublishZipPath }); CfnApplication application = null; // Create an app version from the S3 asset defined above // The S3 "putObject" will occur first before CF generates the template var applicationVersion = new CfnApplicationVersion(this, "ApplicationVersion", new CfnApplicationVersionProps { ApplicationName = settings.BeanstalkApplication.ApplicationName, SourceBundle = new CfnApplicationVersion.SourceBundleProperty { S3Bucket = asset.S3BucketName, S3Key = asset.S3ObjectKey } }); if (settings.BeanstalkApplication.CreateNew) { application = new CfnApplication(this, "Application", new CfnApplicationProps { ApplicationName = settings.BeanstalkApplication.ApplicationName }); applicationVersion.AddDependsOn(application); } IRole role; if (settings.ApplicationIAMRole.CreateNew) { role = new Role(this, "Role", new RoleProps { AssumedBy = new ServicePrincipal("ec2.amazonaws.com"), // https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-instanceprofile.html ManagedPolicies = new[] { ManagedPolicy.FromAwsManagedPolicyName("AWSElasticBeanstalkWebTier"), ManagedPolicy.FromAwsManagedPolicyName("AWSElasticBeanstalkWorkerTier") } }); } else { role = Role.FromRoleArn(this, "Role", settings.ApplicationIAMRole.RoleArn); } var instanceProfile = new CfnInstanceProfile(this, "InstanceProfile", new CfnInstanceProfileProps { Roles = new[] { role.RoleName } }); var optionSettingProperties = new List <CfnEnvironment.OptionSettingProperty> { new CfnEnvironment.OptionSettingProperty { Namespace = "aws:autoscaling:launchconfiguration", OptionName = "IamInstanceProfile", Value = instanceProfile.AttrArn }, new CfnEnvironment.OptionSettingProperty { Namespace = "aws:elasticbeanstalk:environment", OptionName = "EnvironmentType", Value = settings.EnvironmentType } }; if (!string.IsNullOrEmpty(settings.InstanceType)) { optionSettingProperties.Add(new CfnEnvironment.OptionSettingProperty { Namespace = "aws:autoscaling:launchconfiguration", OptionName = "InstanceType", Value = settings.InstanceType }); } if (settings.EnvironmentType.Equals(ENVIRONMENTTYPE_LOADBALANCED)) { optionSettingProperties.Add( new CfnEnvironment.OptionSettingProperty { Namespace = "aws:elasticbeanstalk:environment", OptionName = "LoadBalancerType", Value = settings.LoadBalancerType } ); } if (!string.IsNullOrEmpty(settings.EC2KeyPair)) { optionSettingProperties.Add( new CfnEnvironment.OptionSettingProperty { Namespace = "aws:autoscaling:launchconfiguration", OptionName = "EC2KeyName", Value = settings.EC2KeyPair } ); } var environment = new CfnEnvironment(this, "Environment", new CfnEnvironmentProps { EnvironmentName = settings.EnvironmentName, ApplicationName = settings.BeanstalkApplication.ApplicationName, PlatformArn = settings.ElasticBeanstalkPlatformArn, OptionSettings = optionSettingProperties.ToArray(), // This line is critical - reference the label created in this same stack VersionLabel = applicationVersion.Ref, }); var output = new CfnOutput(this, "EndpointURL", new CfnOutputProps { Value = $"http://{environment.AttrEndpointUrl}/" }); }
internal AppStack(Construct scope, RecipeConfiguration <Configuration> recipeConfiguration, IStackProps props = null) : base(scope, recipeConfiguration.StackName, props) { var settings = recipeConfiguration.Settings; IVpc vpc; if (settings.Vpc.IsDefault) { vpc = Vpc.FromLookup(this, "Vpc", new VpcLookupOptions { IsDefault = true }); } else if (settings.Vpc.CreateNew) { vpc = new Vpc(this, "Vpc", new VpcProps { MaxAzs = 2 }); } else { vpc = Vpc.FromLookup(this, "Vpc", new VpcLookupOptions { VpcId = settings.Vpc.VpcId }); } ICluster cluster; if (settings.ECSCluster.CreateNew) { cluster = new Cluster(this, "Cluster", new ClusterProps { Vpc = vpc, ClusterName = settings.ECSCluster.NewClusterName }); } else { cluster = Cluster.FromClusterAttributes(this, "Cluster", new ClusterAttributes { ClusterArn = settings.ECSCluster.ClusterArn, ClusterName = ECSFargateUtilities.GetClusterNameFromArn(settings.ECSCluster.ClusterArn), SecurityGroups = new ISecurityGroup[0], Vpc = vpc }); } IRole taskRole; if (settings.ApplicationIAMRole.CreateNew) { taskRole = new Role(this, "TaskRole", new RoleProps { AssumedBy = new ServicePrincipal("ecs-tasks.amazonaws.com") }); } else { taskRole = Role.FromRoleArn(this, "TaskRole", settings.ApplicationIAMRole.RoleArn, new FromRoleArnOptions { Mutable = false }); } var taskDefinition = new FargateTaskDefinition(this, "TaskDefinition", new FargateTaskDefinitionProps { TaskRole = taskRole, Cpu = settings.TaskCpu, MemoryLimitMiB = settings.TaskMemory }); var ecrRepository = Repository.FromRepositoryName(this, "ECRRepository", recipeConfiguration.ECRRepositoryName); var container = taskDefinition.AddContainer("Container", new ContainerDefinitionOptions { Image = ContainerImage.FromEcrRepository(ecrRepository, recipeConfiguration.ECRImageTag) }); container.AddPortMappings(new PortMapping { ContainerPort = 80, Protocol = Protocol.TCP }); var ecsLoadBalancerAccessSecurityGroup = new SecurityGroup(this, "WebAccessSecurityGroup", new SecurityGroupProps { Vpc = vpc, SecurityGroupName = $"{recipeConfiguration.StackName}-ECSService" }); var ecsServiceSecurityGroups = new List <ISecurityGroup>(); ecsServiceSecurityGroups.Add(ecsLoadBalancerAccessSecurityGroup); if (!string.IsNullOrEmpty(settings.AdditionalECSServiceSecurityGroups)) { var count = 1; foreach (var securityGroupId in settings.AdditionalECSServiceSecurityGroups.Split(',')) { ecsServiceSecurityGroups.Add(SecurityGroup.FromSecurityGroupId(this, $"AdditionalGroup-{count++}", securityGroupId.Trim(), new SecurityGroupImportOptions { Mutable = false })); } } new ApplicationLoadBalancedFargateService(this, "FargateService", new ApplicationLoadBalancedFargateServiceProps { Cluster = cluster, TaskDefinition = taskDefinition, DesiredCount = settings.DesiredCount, ServiceName = settings.ECSServiceName, AssignPublicIp = settings.Vpc.IsDefault, SecurityGroups = ecsServiceSecurityGroups.ToArray() }); }