├── .gitignore ├── DeployToPipeline.ps1 ├── EnvironmentSetup ├── CloudFormationSetupProject │ ├── CloudFormationSetupProject.cfproj │ ├── CloudFormationSetupProject.sln │ └── cloudformation.template ├── EnvironmentSetup.ps1 └── EnvironmentTearDown.ps1 ├── InstallApp.ps1 ├── LICENSE ├── README.md ├── RemoveApp.ps1 ├── SampleApp ├── SampleApp.sln ├── global.json └── src │ ├── SampleApp │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── SampleApp.xproj │ ├── Startup.cs │ ├── project.json │ └── web.config │ └── SmokeTests │ ├── Properties │ └── AssemblyInfo.cs │ ├── SmokeTests.xproj │ ├── WebsiteTests.cs │ └── project.json ├── ValidateInstall.ps1 └── appspec.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # Visual Studio per-user settings data 3 | ###################################### 4 | *.suo 5 | *.user 6 | 7 | 8 | **/bin/ 9 | **/obj/ 10 | **/TestResults/ 11 | **/Temp/ 12 | **/NuGet.exe 13 | **/buildlogs/ 14 | 15 | **/.vs/ 16 | **/artifacts/ 17 | 18 | **/project.lock.json -------------------------------------------------------------------------------- /DeployToPipeline.ps1: -------------------------------------------------------------------------------- 1 | if ((Get-AWSCredentials) -eq $null) 2 | { 3 | throw "You must set credentials via Set-AWSCredentials before running this cmdlet." 4 | } 5 | if ((Get-DefaultAWSRegion) -eq $null) 6 | { 7 | throw "You must set a region via Set-DefaultAWSRegion before running this cmdlet." 8 | } 9 | 10 | function _deployRepository() 11 | { 12 | $pipelineSourceConfig = (Get-CPPipeline ExploringAspNetCore-Part2).Stages[0].Actions[0].Configuration 13 | $bucketName = $pipelineSourceConfig["S3Bucket"] 14 | $s3Key = $pipelineSourceConfig["S3ObjectKey"] 15 | 16 | Write-Host 'Zipping Repository' 17 | Add-Type -assembly "system.io.compression.filesystem" 18 | $destination = [System.io.Path]::Combine([System.io.Path]::GetTempPath(), 'aws-blog-net-exploring-aspnet-core.zip') 19 | If (Test-Path $destination) 20 | { 21 | Remove-Item $destination 22 | } 23 | 24 | Write-Host 'Zipping up repository for initial deployment in pipeline' 25 | [io.compression.zipfile]::CreateFromDirectory($PSScriptRoot, $destination) 26 | 27 | Write-Host 'Writing zip to S3 ' $bucketName 28 | Write-S3Object -BucketName $bucketName -File $destination -Key $s3Key 29 | 30 | $bucketName 31 | } 32 | 33 | 34 | _deployRepository -------------------------------------------------------------------------------- /EnvironmentSetup/CloudFormationSetupProject/CloudFormationSetupProject.cfproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | {99999999-9999-9999-9999-999999999999} 7 | CloudFormationSetupProject 8 | CloudFormationSetupProject 9 | CloudFormationSetupProject 10 | 11 | 12 | 13 | $(LocalAppData)\Microsoft\VisualStudio\10.0Exp\Extensions\Amazon Web Services\AWSToolkit.VS2010.Core\0.5.0.0 14 | 15 | $(MSBuildExtensionsPath)\Amazon Web Services LLC\AWSToolkit.VS2010 16 | 17 | 18 | 19 | Code 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /EnvironmentSetup/CloudFormationSetupProject/CloudFormationSetupProject.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{22325025-CDA3-4736-83CB-2D32D2FCC215}") = "CloudFormationSetupProject", "CloudFormationSetupProject.cfproj", "{99999999-9999-9999-9999-999999999999}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {99999999-9999-9999-9999-999999999999}.Debug|x86.ActiveCfg = Debug|x86 15 | {99999999-9999-9999-9999-999999999999}.Debug|x86.Build.0 = Debug|x86 16 | {99999999-9999-9999-9999-999999999999}.Release|x86.ActiveCfg = Release|x86 17 | {99999999-9999-9999-9999-999999999999}.Release|x86.Build.0 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /EnvironmentSetup/CloudFormationSetupProject/cloudformation.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion" : "2010-09-09", 3 | 4 | "Description" : "", 5 | 6 | "Parameters" : { 7 | "PipelineBucket" : { 8 | "Type" : "String", 9 | "Description" : "The bucket where versions of the application will be placed and pipeline metadata" 10 | }, 11 | "ImageId" : { 12 | "Type" : "AWS::EC2::Image::Id", 13 | "Description" : "The base AMI to start with. This is expected to be the latest base Windows 2012 R2 AMI" 14 | }, 15 | "BetaInstanceType" : { 16 | "Type" : "String", 17 | "Description" : "The EC2 instance type to use when creating the application servers", 18 | "Default" : "t2.small" 19 | }, 20 | "ProdInstanceType" : { 21 | "Type" : "String", 22 | "Description" : "The EC2 instance type to use when creating the application servers", 23 | "Default" : "t2.medium" 24 | }, 25 | "EC2KeyName" : { 26 | "Type" : "AWS::EC2::KeyPair::KeyName", 27 | "Description" : "The EC2 key pair name to use for remoting into the application servers" 28 | }, 29 | "OpenRemoteDesktopPort" : { 30 | "Type" : "String", 31 | "Description" : "If set to Yes the RDP port will be open. This is useful for debugging but for security reason should not be done for production systems.", 32 | "AllowedValues" : [ 33 | "Yes", 34 | "No" 35 | ] 36 | } 37 | }, 38 | "Conditions" : { 39 | "OpenRemoteDesktopPortCondition" : { 40 | "Fn::Equals" : [ 41 | "Yes", 42 | { 43 | "Ref" : "OpenRemoteDesktopPort" 44 | } 45 | ] 46 | } 47 | }, 48 | "Resources" : { 49 | "WaitHandle" : { 50 | "Type" : "AWS::CloudFormation::WaitConditionHandle" 51 | }, 52 | "WaitCondition" : { 53 | "Type" : "AWS::CloudFormation::WaitCondition", 54 | "Properties" : { 55 | "Count" : 2, 56 | "Handle" : { 57 | "Ref" : "WaitHandle" 58 | }, 59 | "Timeout" : "900" 60 | } 61 | }, 62 | "AppSecurity" : { 63 | "Type" : "AWS::EC2::SecurityGroup", 64 | "Properties" : { 65 | "GroupDescription" : "The security group for the application servers", 66 | "SecurityGroupIngress" : [ 67 | { 68 | "CidrIp" : "0.0.0.0/0", 69 | "IpProtocol" : "tcp", 70 | "FromPort" : "80", 71 | "ToPort" : "80" 72 | }, 73 | { 74 | "CidrIp" : { 75 | "Fn::If" : [ 76 | "OpenRemoteDesktopPortCondition", 77 | "0.0.0.0/0", 78 | "0.0.0.0/32" 79 | ] 80 | }, 81 | "IpProtocol" : "tcp", 82 | "FromPort" : "3389", 83 | "ToPort" : "3389" 84 | } 85 | ] 86 | } 87 | }, 88 | "AppServerBeta" : { 89 | "Type" : "AWS::EC2::Instance", 90 | "Metadata" : { 91 | "AWS::CloudFormation::Init" : { 92 | "config" : { 93 | "commands" : { 94 | "01-download-dotnetcli" : { 95 | "command" : { 96 | "Fn::Join" : [ 97 | "", 98 | [ 99 | "powershell.exe -Command \"((new-object net.webclient).DownloadFile('https://go.microsoft.com/fwlink/?LinkID=798398', 'C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.exe'))\"" 100 | ] 101 | ] 102 | }, 103 | "cwd" : "C:/cfn", 104 | "waitAfterCompletion" : 0 105 | }, 106 | "02-install-dotnetcli" : { 107 | "command" : "C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.exe /install /quiet /log C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.txt", 108 | "ignoreErrors" : "true", 109 | "waitAfterCompletion" : 0 110 | }, 111 | "03-import-service-module" : { 112 | "command" : "powershell.exe -Command Import-Module -Name ServerManager", 113 | "ignoreErrors" : "true", 114 | "waitAfterCompletion" : 0 115 | }, 116 | "04-install-web-server" : { 117 | "command" : "powershell.exe -Command Install-WindowsFeature Web-Server,Application-Server,AS-Web-Support", 118 | "ignoreErrors" : "true", 119 | "waitAfterCompletion" : 0 120 | }, 121 | "05-download-host-agent" : { 122 | "command" : { 123 | "Fn::Join" : [ 124 | "", 125 | [ 126 | "powershell.exe -Command \"Read-S3Object ", 127 | "-BucketName aws-codedeploy-us-east-1 ", 128 | "-Key latest/codedeploy-agent.msi ", 129 | "-File codedeploy-agent.msi\"" 130 | ] 131 | ] 132 | }, 133 | "cwd" : "C:/cfn", 134 | "waitAfterCompletion" : 0 135 | }, 136 | "06-install-host-agent" : { 137 | "command" : "C:\\cfn\\codedeploy-agent.msi /quiet /l C:\\cfn\\host-agent-install-log.txt", 138 | "ignoreErrors" : "true", 139 | "waitAfterCompletion" : 0 140 | }, 141 | "07-download-dotnet-hosting" : { 142 | "command" : { 143 | "Fn::Join" : [ 144 | "", 145 | [ 146 | "powershell.exe -Command \"((new-object net.webclient).DownloadFile('http://go.microsoft.com/fwlink/?LinkId=798480', 'C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.exe'))\"" 147 | ] 148 | ] 149 | }, 150 | "cwd" : "C:/cfn", 151 | "waitAfterCompletion" : 0 152 | }, 153 | "08-install-dotnet-hosting" : { 154 | "command" : "C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.exe /install /quiet /log C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.txt", 155 | "ignoreErrors" : "true", 156 | "waitAfterCompletion" : 0 157 | }, 158 | "09-signal-ready" : { 159 | "command" : { 160 | "Fn::Join" : [ 161 | "", 162 | [ 163 | "\"C:\\Program Files\\Amazon\\cfn-bootstrap\\cfn-signal\"", 164 | " -e 0 \"", 165 | { 166 | "Ref" : "WaitHandle" 167 | }, 168 | "\"" 169 | ] 170 | ] 171 | }, 172 | "waitAfterCompletion" : 0 173 | } 174 | }, 175 | "services" : { 176 | "windows" : { 177 | "codedeploy-agent" : { 178 | "enabled" : "true", 179 | "ensureRunning" : "true", 180 | "commands" : [ 181 | "01-install-host-agent" 182 | ] 183 | } 184 | } 185 | } 186 | } 187 | } 188 | }, 189 | "Properties" : { 190 | "IamInstanceProfile" : { 191 | "Ref" : "InstanceRoleInstanceProfile" 192 | }, 193 | "ImageId" : { 194 | "Ref" : "ImageId" 195 | }, 196 | "InstanceType" : { 197 | "Ref" : "BetaInstanceType" 198 | }, 199 | "KeyName" : { 200 | "Ref" : "EC2KeyName" 201 | }, 202 | "SecurityGroups" : [ 203 | { 204 | "Ref" : "AppSecurity" 205 | } 206 | ], 207 | "Tags" : [ 208 | { 209 | "Key" : "Name", 210 | "Value" : "ExploringAspNetCorePart2-Beta" 211 | } 212 | ], 213 | "UserData" : { 214 | "Fn::Base64" : { 215 | "Fn::Join" : [ 216 | "", 217 | [ 218 | "" 231 | ] 232 | ] 233 | } 234 | } 235 | } 236 | }, 237 | 238 | "ProdLaunchConfiguration" : { 239 | "Type" : "AWS::AutoScaling::LaunchConfiguration", 240 | "Metadata" : { 241 | "AWS::CloudFormation::Init" : { 242 | "config" : { 243 | "commands" : { 244 | "01-download-dotnetcli" : { 245 | "command" : { 246 | "Fn::Join" : [ 247 | "", 248 | [ 249 | "powershell.exe -Command \"((new-object net.webclient).DownloadFile('https://go.microsoft.com/fwlink/?LinkID=798398', 'C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.exe'))\"" 250 | ] 251 | ] 252 | }, 253 | "cwd" : "C:/cfn", 254 | "waitAfterCompletion" : 0 255 | }, 256 | "02-install-dotnetcli" : { 257 | "command" : "C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.exe /install /quiet /log C:\\cfn\\DotNetCore.1.0.0.RC2-SDK.Preview1-x64.txt", 258 | "ignoreErrors" : "true", 259 | "waitAfterCompletion" : 0 260 | }, 261 | "03-import-service-module" : { 262 | "command" : "powershell.exe -Command Import-Module -Name ServerManager", 263 | "ignoreErrors" : "true", 264 | "waitAfterCompletion" : 0 265 | }, 266 | "04-install-web-server" : { 267 | "command" : "powershell.exe -Command Install-WindowsFeature Web-Server,Application-Server,AS-Web-Support", 268 | "ignoreErrors" : "true", 269 | "waitAfterCompletion" : 0 270 | }, 271 | "05-download-host-agent" : { 272 | "command" : { 273 | "Fn::Join" : [ 274 | "", 275 | [ 276 | "powershell.exe -Command \"Read-S3Object ", 277 | "-BucketName aws-codedeploy-us-east-1 ", 278 | "-Key latest/codedeploy-agent.msi ", 279 | "-File codedeploy-agent.msi\"" 280 | ] 281 | ] 282 | }, 283 | "cwd" : "C:/cfn", 284 | "waitAfterCompletion" : 0 285 | }, 286 | "06-install-host-agent" : { 287 | "command" : "C:\\cfn\\codedeploy-agent.msi /quiet /l C:\\cfn\\host-agent-install-log.txt", 288 | "ignoreErrors" : "true", 289 | "waitAfterCompletion" : 0 290 | }, 291 | "07-download-dotnet-hosting" : { 292 | "command" : { 293 | "Fn::Join" : [ 294 | "", 295 | [ 296 | "powershell.exe -Command \"((new-object net.webclient).DownloadFile('http://go.microsoft.com/fwlink/?LinkId=798480', 'C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.exe'))\"" 297 | ] 298 | ] 299 | }, 300 | "cwd" : "C:/cfn", 301 | "waitAfterCompletion" : 0 302 | }, 303 | "08-install-dotnet-hosting" : { 304 | "command" : "C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.exe /install /quiet /log C:\\cfn\\DotNetCore.1.0.0.RC2-WindowsHosting.txt", 305 | "ignoreErrors" : "true", 306 | "waitAfterCompletion" : 0 307 | }, 308 | "09-signal-ready" : { 309 | "command" : { 310 | "Fn::Join" : [ 311 | "", 312 | [ 313 | "\"C:\\Program Files\\Amazon\\cfn-bootstrap\\cfn-signal\"", 314 | " -e 0 \"", 315 | { 316 | "Ref" : "WaitHandle" 317 | }, 318 | "\"" 319 | ] 320 | ] 321 | }, 322 | "waitAfterCompletion" : 0 323 | } 324 | }, 325 | "services" : { 326 | "windows" : { 327 | "codedeploy-agent" : { 328 | "enabled" : "true", 329 | "ensureRunning" : "true", 330 | "commands" : [ 331 | "01-install-host-agent" 332 | ] 333 | } 334 | } 335 | } 336 | } 337 | } 338 | }, 339 | "Properties" : { 340 | "IamInstanceProfile" : { 341 | "Ref" : "InstanceRoleInstanceProfile" 342 | }, 343 | "ImageId" : { 344 | "Ref" : "ImageId" 345 | }, 346 | "InstanceType" : { 347 | "Ref" : "ProdInstanceType" 348 | }, 349 | "KeyName" : { 350 | "Ref" : "EC2KeyName" 351 | }, 352 | "SecurityGroups" : [ 353 | { 354 | "Ref" : "AppSecurity" 355 | } 356 | ], 357 | "UserData" : { 358 | "Fn::Base64" : { 359 | "Fn::Join" : [ 360 | "", 361 | [ 362 | "" 375 | ] 376 | ] 377 | } 378 | } 379 | } 380 | }, 381 | "ProdAutoScalingGroup" : { 382 | "Type" : "AWS::AutoScaling::AutoScalingGroup", 383 | "Properties" : { 384 | "AvailabilityZones" : { 385 | "Fn::GetAZs" : "" 386 | }, 387 | "LaunchConfigurationName" : { 388 | "Ref" : "ProdLaunchConfiguration" 389 | }, 390 | "MinSize" : "1", 391 | "MaxSize" : "4", 392 | "LoadBalancerNames" : [ 393 | { 394 | "Ref" : "ProdLoadBalancer" 395 | } 396 | ], 397 | "Tags" : [{"Key" : "Name", "Value" : "ExploringAspNetCorePart2-Prod", "PropagateAtLaunch" : true} 398 | ] 399 | } 400 | }, 401 | "ScaleUpPolicy" : { 402 | "Type" : "AWS::AutoScaling::ScalingPolicy", 403 | "Properties" : { 404 | "AdjustmentType" : "ChangeInCapacity", 405 | "AutoScalingGroupName" : { 406 | "Ref" : "ProdAutoScalingGroup" 407 | }, 408 | "Cooldown" : "1", 409 | "ScalingAdjustment" : "1" 410 | } 411 | }, 412 | "ScaleDownPolicy" : { 413 | "Type" : "AWS::AutoScaling::ScalingPolicy", 414 | "Properties" : { 415 | "AdjustmentType" : "ChangeInCapacity", 416 | "AutoScalingGroupName" : { 417 | "Ref" : "ProdAutoScalingGroup" 418 | }, 419 | "Cooldown" : "1", 420 | "ScalingAdjustment" : "-1" 421 | } 422 | }, 423 | "CPUAlarmHigh" : { 424 | "Type" : "AWS::CloudWatch::Alarm", 425 | "Properties" : { 426 | "AlarmDescription" : "Scale-up if CPU > 90% for 10 minutes", 427 | "MetricName" : "CPUUtilization", 428 | "Namespace" : "AWS/EC2", 429 | "Statistic" : "Average", 430 | "Period" : "300", 431 | "EvaluationPeriods" : "2", 432 | "Threshold" : "90", 433 | "AlarmActions" : [ 434 | { 435 | "Ref" : "ScaleUpPolicy" 436 | } 437 | ], 438 | "Dimensions" : [ 439 | { 440 | "Name" : "AutoScalingGroupName", 441 | "Value" : { 442 | "Ref" : "ProdAutoScalingGroup" 443 | } 444 | } 445 | ], 446 | "ComparisonOperator" : "GreaterThanThreshold" 447 | } 448 | }, 449 | "CPUAlarmLow" : { 450 | "Type" : "AWS::CloudWatch::Alarm", 451 | "Properties" : { 452 | "AlarmDescription" : "Scale-down if CPU < 70% for 10 minutes", 453 | "MetricName" : "CPUUtilization", 454 | "Namespace" : "AWS/EC2", 455 | "Statistic" : "Average", 456 | "Period" : "300", 457 | "EvaluationPeriods" : "2", 458 | "Threshold" : "70", 459 | "AlarmActions" : [ 460 | { 461 | "Ref" : "ScaleDownPolicy" 462 | } 463 | ], 464 | "Dimensions" : [ 465 | { 466 | "Name" : "AutoScalingGroupName", 467 | "Value" : { 468 | "Ref" : "ProdAutoScalingGroup" 469 | } 470 | } 471 | ], 472 | "ComparisonOperator" : "LessThanThreshold" 473 | } 474 | }, 475 | "ProdLoadBalancer" : { 476 | "Type" : "AWS::ElasticLoadBalancing::LoadBalancer", 477 | "Properties" : { 478 | "AvailabilityZones" : { 479 | "Fn::GetAZs" : "" 480 | }, 481 | "Listeners" : [ 482 | { 483 | "Protocol" : "HTTP", 484 | "InstanceProtocol" : "HTTP", 485 | "InstancePort" : "80", 486 | "LoadBalancerPort" : "80" 487 | } 488 | ], 489 | "HealthCheck" : { 490 | "Timeout" : "5", 491 | "Interval" : "10", 492 | "Target" : "TCP:80", 493 | "HealthyThreshold" : "3", 494 | "UnhealthyThreshold" : "5" 495 | }, 496 | "ConnectionDrainingPolicy" : { 497 | "Enabled" : true, 498 | "Timeout" : 20 499 | }, 500 | "Tags" : [ 501 | { 502 | "Key" : "Name", 503 | "Value" : "ExploringAspNetCorePart2-Prod" 504 | } 505 | ] 506 | } 507 | }, 508 | "CodeDeployTrustRole" : { 509 | "Type" : "AWS::IAM::Role", 510 | "Properties" : { 511 | "AssumeRolePolicyDocument" : { 512 | "Statement" : [ 513 | { 514 | "Sid" : "1", 515 | "Effect" : "Allow", 516 | "Principal" : { 517 | "Service" : [ 518 | "codedeploy.us-east-1.amazonaws.com", 519 | "codedeploy.us-west-2.amazonaws.com" 520 | ] 521 | }, 522 | "Action" : "sts:AssumeRole" 523 | } 524 | ] 525 | }, 526 | "Path" : "/" 527 | } 528 | }, 529 | "CodeDeployRolePolicies" : { 530 | "Type" : "AWS::IAM::Policy", 531 | "Properties" : { 532 | "PolicyName" : "CodeDeployPolicy", 533 | "PolicyDocument" : { 534 | "Statement" : [ 535 | { 536 | "Effect" : "Allow", 537 | "Resource" : [ 538 | "*" 539 | ], 540 | "Action" : [ 541 | "ec2:Describe*" 542 | ] 543 | }, 544 | { 545 | "Effect" : "Allow", 546 | "Resource" : [ 547 | "*" 548 | ], 549 | "Action" : [ 550 | "autoscaling:CompleteLifecycleAction", 551 | "autoscaling:DeleteLifecycleHook", 552 | "autoscaling:DescribeLifecycleHooks", 553 | "autoscaling:DescribeAutoScalingGroups", 554 | "autoscaling:PutLifecycleHook", 555 | "autoscaling:RecordLifecycleActionHeartbeat" 556 | ] 557 | } 558 | ] 559 | }, 560 | "Roles" : [ 561 | { 562 | "Ref" : "CodeDeployTrustRole" 563 | } 564 | ] 565 | } 566 | }, 567 | "CodeDeployAppBeta" : { 568 | "Type" : "AWS::CodeDeploy::Application", 569 | "DependsOn" : "WaitCondition", 570 | "Properties" : { 571 | "ApplicationName" : "ExploringAspNetCorePart2-Beta" 572 | } 573 | }, 574 | "CodeDeployAppBetaFleet" : { 575 | "Type" : "AWS::CodeDeploy::DeploymentGroup", 576 | "DependsOn" : "AppServerBeta", 577 | "Properties" : { 578 | "ApplicationName" : { 579 | "Ref" : "CodeDeployAppBeta" 580 | }, 581 | "DeploymentGroupName" : "ExploringAspNetCorePart2-Beta-Fleet", 582 | "Ec2TagFilters" : [ 583 | { 584 | "Key" : "Name", 585 | "Type" : "KEY_AND_VALUE", 586 | "Value" : "ExploringAspNetCorePart2-Beta" 587 | } 588 | ], 589 | "ServiceRoleArn" : { 590 | "Fn::GetAtt" : [ 591 | "CodeDeployTrustRole", 592 | "Arn" 593 | ] 594 | } 595 | } 596 | }, 597 | "CodeDeployAppProd" : { 598 | "Type" : "AWS::CodeDeploy::Application", 599 | "DependsOn" : "WaitCondition", 600 | "Properties" : { 601 | "ApplicationName" : "ExploringAspNetCorePart2-Prod" 602 | } 603 | }, 604 | "CodeDeployAppProdFleet" : { 605 | "Type" : "AWS::CodeDeploy::DeploymentGroup", 606 | "DependsOn" : "WaitCondition", 607 | "Properties" : { 608 | "ApplicationName" : { 609 | "Ref" : "CodeDeployAppProd" 610 | }, 611 | "DeploymentGroupName" : "ExploringAspNetCorePart2-Prod-Fleet", 612 | "AutoScalingGroups" : [{ "Ref" : "ProdAutoScalingGroup" }], 613 | "ServiceRoleArn" : { 614 | "Fn::GetAtt" : [ 615 | "CodeDeployTrustRole", 616 | "Arn" 617 | ] 618 | } 619 | } 620 | }, 621 | "PipelineRole" : { 622 | "Type" : "AWS::IAM::Role", 623 | "Properties" : { 624 | "AssumeRolePolicyDocument" : { 625 | "Version" : "2012-10-17", 626 | "Statement" : [ 627 | { 628 | "Sid" : "", 629 | "Effect" : "Allow", 630 | "Principal" : { 631 | "Service" : "codepipeline.amazonaws.com" 632 | }, 633 | "Action" : "sts:AssumeRole" 634 | } 635 | ] 636 | } 637 | } 638 | }, 639 | "PipelinePolicy" : { 640 | "Type" : "AWS::IAM::Policy", 641 | "Properties" : { 642 | "PolicyDocument" : { 643 | "Statement" : [ 644 | { 645 | "Action" : [ 646 | "s3:GetObject", 647 | "s3:GetObjectVersion", 648 | "s3:GetBucketVersioning" 649 | ], 650 | "Resource" : "*", 651 | "Effect" : "Allow" 652 | }, 653 | { 654 | "Action" : [ 655 | "s3:PutObject" 656 | ], 657 | "Resource" : [ 658 | "arn:aws:s3:::codepipeline*", 659 | "arn:aws:s3:::elasticbeanstalk*" 660 | ], 661 | "Effect" : "Allow" 662 | }, 663 | { 664 | "Action" : [ 665 | "codedeploy:CreateDeployment", 666 | "codedeploy:GetApplicationRevision", 667 | "codedeploy:GetDeployment", 668 | "codedeploy:GetDeploymentConfig", 669 | "codedeploy:RegisterApplicationRevision" 670 | ], 671 | "Resource" : "*", 672 | "Effect" : "Allow" 673 | }, 674 | { 675 | "Action" : [ 676 | "elasticbeanstalk:*", 677 | "ec2:*", 678 | "elasticloadbalancing:*", 679 | "autoscaling:*", 680 | "cloudwatch:*", 681 | "s3:*", 682 | "sns:*", 683 | "cloudformation:*", 684 | "rds:*", 685 | "sqs:*", 686 | "ecs:*", 687 | "iam:PassRole" 688 | ], 689 | "Resource" : "*", 690 | "Effect" : "Allow" 691 | }, 692 | { 693 | "Action" : [ 694 | "lambda:InvokeFunction", 695 | "lambda:ListFunctions" 696 | ], 697 | "Resource" : "*", 698 | "Effect" : "Allow" 699 | } 700 | ] 701 | }, 702 | "PolicyName" : "PipelinePolicy", 703 | "Roles" : [{ "Ref" : "PipelineRole" }] 704 | } 705 | }, 706 | "Pipeline" : { 707 | "Type" : "AWS::CodePipeline::Pipeline", 708 | "Properties" : { 709 | "Name" : "ExploringAspNetCore-Part2", 710 | "ArtifactStore" : { 711 | "Location" : { 712 | "Ref" : "PipelineBucket" 713 | }, 714 | "Type" : "S3" 715 | }, 716 | "RoleArn" : { "Fn::GetAtt" : ["PipelineRole", "Arn"] }, 717 | "Stages" : [ 718 | { 719 | "Name" : "Source", 720 | "Actions" : [ 721 | { 722 | "Name" : "SourceAction", 723 | "ActionTypeId" : { 724 | "Category" : "Source", 725 | "Owner" : "AWS", 726 | "Version" : "1", 727 | "Provider" : "S3" 728 | }, 729 | "OutputArtifacts" : [ 730 | { 731 | "Name" : "SourceOutput" 732 | } 733 | ], 734 | "Configuration" : { 735 | "S3Bucket" : { 736 | "Ref" : "PipelineBucket" 737 | }, 738 | "S3ObjectKey" : "aws-blog-net-exploring-aspnet-core.zip" 739 | }, 740 | "RunOrder" : 1 741 | } 742 | ] 743 | }, 744 | { 745 | "Name" : "Beta", 746 | "Actions" : [ 747 | { 748 | "Name" : "Beta", 749 | "InputArtifacts" : [ 750 | { 751 | "Name" : "SourceOutput" 752 | } 753 | ], 754 | "ActionTypeId" : { 755 | "Category" : "Deploy", 756 | "Owner" : "AWS", 757 | "Version" : "1", 758 | "Provider" : "CodeDeploy" 759 | }, 760 | "Configuration" : { 761 | "ApplicationName" : { 762 | "Ref" : "CodeDeployAppBeta" 763 | }, 764 | "DeploymentGroupName" : { 765 | "Ref" : "CodeDeployAppBetaFleet" 766 | } 767 | }, 768 | "RunOrder" : 1 769 | } 770 | ] 771 | }, 772 | { 773 | "Name" : "Release", 774 | "Actions" : [ 775 | { 776 | "Name" : "Prod", 777 | "InputArtifacts" : [ 778 | { 779 | "Name" : "SourceOutput" 780 | } 781 | ], 782 | "ActionTypeId" : { 783 | "Category" : "Deploy", 784 | "Owner" : "AWS", 785 | "Version" : "1", 786 | "Provider" : "CodeDeploy" 787 | }, 788 | "Configuration" : { 789 | "ApplicationName" : { 790 | "Ref" : "CodeDeployAppProd" 791 | }, 792 | "DeploymentGroupName" : { 793 | "Ref" : "CodeDeployAppProdFleet" 794 | } 795 | }, 796 | "RunOrder" : 1 797 | } 798 | ] 799 | } 800 | ] 801 | } 802 | }, 803 | "InstanceRole" : { 804 | "Type" : "AWS::IAM::Role", 805 | "Properties" : { 806 | "AssumeRolePolicyDocument" : { 807 | "Statement" : [ 808 | { 809 | "Effect" : "Allow", 810 | "Principal" : { 811 | "Service" : [ 812 | "ec2.amazonaws.com" 813 | ] 814 | }, 815 | "Action" : [ 816 | "sts:AssumeRole" 817 | ] 818 | } 819 | ] 820 | }, 821 | "Path" : "/" 822 | } 823 | }, 824 | "InstanceRolePolicies" : { 825 | "Type" : "AWS::IAM::Policy", 826 | "Properties" : { 827 | "PolicyName" : "InstanceRole", 828 | "PolicyDocument" : { 829 | "Statement" : [ 830 | { 831 | "Effect" : "Allow", 832 | "Action" : [ 833 | "autoscaling:Describe*", 834 | "cloudformation:Describe*", 835 | "cloudformation:GetTemplate", 836 | "s3:Get*" 837 | ], 838 | "Resource" : "*" 839 | } 840 | ] 841 | }, 842 | "Roles" : [ 843 | { 844 | "Ref" : "InstanceRole" 845 | } 846 | ] 847 | } 848 | }, 849 | "InstanceRoleInstanceProfile" : { 850 | "Type" : "AWS::IAM::InstanceProfile", 851 | "Properties" : { 852 | "Path" : "/", 853 | "Roles" : [ 854 | { 855 | "Ref" : "InstanceRole" 856 | } 857 | ] 858 | } 859 | } 860 | }, 861 | "Outputs" : { 862 | "BetaDNS" : { 863 | "Value" : {"Fn::GetAtt" : [ "AppServerBeta", "PublicDnsName"]}, 864 | "Description" : "The DNS for the Beta stage that will have the ASP.NET Core application deployed to." 865 | }, 866 | "ProdDNS" : { 867 | "Value" : {"Fn::GetAtt" : [ "ProdLoadBalancer", "DNSName"]}, 868 | "Description" : "The DNS for the Prod stage that will have the ASP.NET Core application deployed to." 869 | }, 870 | "CodeDeployTrustRoleARN" : { 871 | "Value" : { 872 | "Fn::GetAtt" : [ 873 | "CodeDeployTrustRole", 874 | "Arn" 875 | ] 876 | } 877 | } 878 | } 879 | } 880 | -------------------------------------------------------------------------------- /EnvironmentSetup/EnvironmentSetup.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | # The EC2 key pair assigned to all instances launched. 3 | [Parameter(mandatory=$true)] 4 | [string] 5 | $ec2KeyPair, 6 | 7 | # The instance type for the beta stage 8 | [Parameter()] 9 | [string] 10 | $betaInstanceType = "t2.small", 11 | 12 | # The instance type for the prod stage 13 | [Parameter()] 14 | [string] 15 | $prodInstanceType = "t2.medium", 16 | 17 | # true or false if you want the RDP port opened. 18 | [Parameter()] 19 | [bool] 20 | $openRDPPort 21 | ) 22 | 23 | function _LaunchCloudFormationStack([string]$bucketName, [string]$betaInstanceType, [string]$prodInstanceType, [string]$keyPair, [bool]$openRDP) 24 | { 25 | Write-Host "Creating CloudFormation Stack to launch an EC2 instance and configure it for CodeDeploy deployments" 26 | 27 | $templatePath = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, "./CloudFormationSetupProject/cloudformation.template")) 28 | $templateBody = [System.IO.File]::ReadAllText($templatePath) 29 | 30 | $imageId = (Get-EC2ImageByName WINDOWS_2012R2_BASE).ImageId 31 | 32 | if ($openRDP) 33 | { 34 | $openRDPTranslated = "Yes" 35 | } 36 | else 37 | { 38 | $openRDPTranslated = "No" 39 | } 40 | 41 | $parameters = @( 42 | @{ParameterKey = "ImageId"; ParameterValue = $imageId}, 43 | @{ParameterKey = "BetaInstanceType"; ParameterValue = $betaInstanceType}, 44 | @{ParameterKey = "ProdInstanceType"; ParameterValue = $prodInstanceType}, 45 | @{ParameterKey = "EC2KeyName"; ParameterValue = $keyPair}, 46 | @{ParameterKey = "OpenRemoteDesktopPort"; ParameterValue = $openRDPTranslated}, 47 | @{ParameterKey = "PipelineBucket"; ParameterValue = $bucketName} 48 | ) 49 | 50 | $stackId = New-CFNStack -StackName "ExploringAspNetCore-Part2" -Capability "CAPABILITY_IAM" -Parameter $parameters -TemplateBody $templateBody 51 | $stackId 52 | } 53 | 54 | 55 | function _SetupPipelineBucket() 56 | { 57 | $bucketName = ("ExploringAspNetCore-Part2-" + [System.DateTime]::Now.Ticks).ToLowerInvariant() 58 | $bucket = New-S3Bucket -BucketName $bucketName 59 | Write-S3BucketVersioning -BucketName $bucketName -VersioningConfig_Status Enabled 60 | 61 | Write-Host 'Setting up S3 source for pipeline: ' $bucketName 62 | Add-Type -assembly "system.io.compression.filesystem" 63 | $source = [System.io.Path]::Combine($PSScriptRoot, '..') 64 | $destination = [System.io.Path]::Combine([System.io.Path]::GetTempPath(), 'aws-blog-net-exploring-aspnet-core.zip') 65 | If (Test-Path $destination) 66 | { 67 | Remove-Item $destination 68 | } 69 | 70 | Write-Host 'Zipping up repository for initial deployment in pipeline' 71 | [io.compression.zipfile]::CreateFromDirectory($source, $destination) 72 | 73 | Write-Host 'Writing zip to S3' 74 | Write-S3Object -BucketName $bucketName -File $destination -Key 'aws-blog-net-exploring-aspnet-core.zip' 75 | 76 | $bucketName 77 | } 78 | 79 | function ProcessInput([string]$betaInstanceType,[string]$prodInstanceType,[string]$keyPair,[bool]$openRDPPort) 80 | { 81 | if ((Get-AWSCredentials) -eq $null) 82 | { 83 | throw "You must set credentials via Set-AWSCredentials before running this cmdlet." 84 | } 85 | if ((Get-DefaultAWSRegion) -eq $null) 86 | { 87 | throw "You must set a region via Set-DefaultAWSRegion before running this cmdlet." 88 | } 89 | 90 | $bucketName = _SetupPipelineBucket 91 | $stackId = _LaunchCloudFormationStack $bucketName $betaInstanceType $prodInstanceType $keyPair $openRDPPort 92 | $stack = Get-CFNStack -StackName $stackId 93 | 94 | while ($stack.StackStatus.Value.toLower().EndsWith('in_progress')) 95 | { 96 | $stack = Get-CFNStack -StackName $stackId 97 | "Waiting for CloudFormation Stack to be created" 98 | Start-Sleep -Seconds 10 99 | } 100 | 101 | if ($stack.StackStatus -ne "CREATE_COMPLETE") 102 | { 103 | "CloudFormation Stack was not successfully created, view the stack events for further information on the failure" 104 | Exit 105 | } 106 | 107 | $betaDNS = "" 108 | $prodDNS = "" 109 | 110 | ForEach($output in $stack.Outputs) 111 | { 112 | if($output.OutputKey -eq "CodeDeployTrustRoleARN") 113 | { 114 | $serviceRoleARN = $output.OutputValue 115 | } 116 | elseif($output.OutputKey -eq "BetaDNS") 117 | { 118 | $betaDNS = $output.OutputValue 119 | } 120 | elseif($output.OutputKey -eq "ProdDNS") 121 | { 122 | $prodDNS = $output.OutputValue 123 | } 124 | } 125 | 126 | 127 | ("CodePipeline environment setup complete") 128 | ("Beta Stage DNS: " + $betaDNS) 129 | ("Prod Stage DNS: " + $prodDNS) 130 | ("S3 Bucket for Pipeline Source: " + $bucketName) 131 | ("S3 Object Key for Pipeline Source: aws-blog-net-exploring-aspnet-core.zip") 132 | } 133 | 134 | 135 | ProcessInput $betaInstanceType $prodInstanceType $ec2KeyPair $openRDPPort -------------------------------------------------------------------------------- /EnvironmentSetup/EnvironmentTearDown.ps1: -------------------------------------------------------------------------------- 1 | if ((Get-AWSCredentials) -eq $null) 2 | { 3 | throw "You must set credentials via Set-AWSCredentials before running this cmdlet." 4 | } 5 | if ((Get-DefaultAWSRegion) -eq $null) 6 | { 7 | throw "You must set a region via Set-DefaultAWSRegion before running this cmdlet." 8 | } 9 | 10 | function _deletePipelineBucket() 11 | { 12 | Get-S3Bucket | Where-Object {$_.BucketName.StartsWith("exploringaspnetcore-part2-")} | foreach {Write-Host 'Deleting pipeline bucket:' $_.BucketName; Remove-S3Bucket -BucketName $_.BucketName -DeleteBucketContent -Force} 13 | } 14 | 15 | function _deleteStack() 16 | { 17 | $stack = (Get-CFNStack -StackName "ExploringAspNetCore-Part2" | Where-Object {$_.StackName -eq "ExploringAspNetCore-Part2"}) 18 | if($stack -ne $null) 19 | { 20 | Write-Host "Deleting CloudFormation existing stack" 21 | Remove-CFNStack $stack.StackName -Force 22 | } 23 | } 24 | 25 | 26 | _deletePipelineBucket 27 | _deleteStack -------------------------------------------------------------------------------- /InstallApp.ps1: -------------------------------------------------------------------------------- 1 | sl C:\ExploringAspNetCore\SampleApp\src\SampleApp 2 | 3 | # Restore the nuget references 4 | & "C:\Program Files\dotnet\dotnet.exe" restore 5 | 6 | # Publish application with all of its dependencies and runtime for IIS to use 7 | & "C:\Program Files\dotnet\dotnet.exe" publish --configuration release -o c:\ExploringAspNetCore\publish --runtime active 8 | 9 | 10 | # Point IIS wwwroot of the published folder. CodeDeploy uses 32 bit version of PowerShell. 11 | # To make use the IIS PowerShell CmdLets we need call the 64 bit version of PowerShell. 12 | C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe -Command {Import-Module WebAdministration; Set-ItemProperty 'IIS:\sites\Default Web Site' -Name physicalPath -Value c:\ExploringAspNetCore\publish} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exploring ASP.NET Core on AWS 2 | 3 | This repository goes along with a series of blogs discussing how to deploy ASP.NET Core applications to AWS. Each will have its code in its own branch. with master including the the latest post's code. 4 | 5 | If you wish to discuss topics about ASP.NET Core on AWS feel free to open up an issue. 6 | 7 | ## Posts in the series 8 | 9 | * [Exploring ASP.NET Core Part 2: Continuous Delivery](https://blogs.aws.amazon.com/net/post/Tx2EHIJAM9LIW8G) 10 | * Build a continuous delivery system for ASP.NET Core using CodeDeploy and CodePipelines. 11 | * [Exploring ASP.NET Core Part 1: Deploying from GitHub](http://blogs.aws.amazon.com/net/post/TxSBK1AHRGLHVC) 12 | * Discuss how you can take advantage of ASP.NET Core's ability to run from source and deploy straight from GitHub. -------------------------------------------------------------------------------- /RemoveApp.ps1: -------------------------------------------------------------------------------- 1 | C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe -Command {Import-Module WebAdministration; Set-ItemProperty 'IIS:\sites\Default Web Site' -Name physicalPath -Value C:\inetpub\wwwroot} -------------------------------------------------------------------------------- /SampleApp/SampleApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3D34E576-DF06-4FBE-91A2-55048E33C045}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{081D9228-60A9-456F-892C-757143552368}" 9 | ProjectSection(SolutionItems) = preProject 10 | global.json = global.json 11 | EndProjectSection 12 | EndProject 13 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SampleApp", "src\SampleApp\SampleApp.xproj", "{F2D7C282-50DD-4C72-ABD5-62709477A7F6}" 14 | EndProject 15 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SmokeTests", "src\SmokeTests\SmokeTests.xproj", "{2666FD54-7477-4806-BD40-794CACFA69E3}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {F2D7C282-50DD-4C72-ABD5-62709477A7F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {F2D7C282-50DD-4C72-ABD5-62709477A7F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {F2D7C282-50DD-4C72-ABD5-62709477A7F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {F2D7C282-50DD-4C72-ABD5-62709477A7F6}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {2666FD54-7477-4806-BD40-794CACFA69E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {2666FD54-7477-4806-BD40-794CACFA69E3}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {2666FD54-7477-4806-BD40-794CACFA69E3}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {2666FD54-7477-4806-BD40-794CACFA69E3}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(NestedProjects) = preSolution 36 | {F2D7C282-50DD-4C72-ABD5-62709477A7F6} = {3D34E576-DF06-4FBE-91A2-55048E33C045} 37 | {2666FD54-7477-4806-BD40-794CACFA69E3} = {3D34E576-DF06-4FBE-91A2-55048E33C045} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /SampleApp/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "test" ], 3 | "sdk": { 4 | "version": "1.0.0-preview1-002702" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Hosting; 7 | 8 | namespace SampleApp 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = new WebHostBuilder() 15 | .UseKestrel() 16 | .UseContentRoot(Directory.GetCurrentDirectory()) 17 | .UseIISIntegration() 18 | .UseStartup() 19 | .Build(); 20 | 21 | host.Run(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53727/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "SampleApp": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "launchUrl": "http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/SampleApp.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | f2d7c282-50dd-4c72-abd5-62709477a7f6 11 | SampleApp 12 | .\obj 13 | .\bin\ 14 | v4.6.1 15 | 16 | 17 | 18 | 2.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace SampleApp 11 | { 12 | public class Startup 13 | { 14 | // This method gets called by the runtime. Use this method to add services to the container. 15 | // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 16 | public void ConfigureServices(IServiceCollection services) 17 | { 18 | } 19 | 20 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 21 | public void Configure(IApplicationBuilder app) 22 | { 23 | app.Run(async (context) => 24 | { 25 | await context.Response.WriteAsync("Exploring ASP.NET Core with AWS."); 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.App": { 4 | "version": "1.0.0-rc2-3002702", 5 | "type": "platform" 6 | }, 7 | "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final", 8 | "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final" 9 | }, 10 | 11 | "tools": { 12 | "Microsoft.AspNetCore.Server.IISIntegration.Tools": { 13 | "version": "1.0.0-preview1-final", 14 | "imports": "portable-net45+win8+dnxcore50" 15 | } 16 | }, 17 | 18 | "frameworks": { 19 | "netcoreapp1.0": { 20 | "imports": [ 21 | "dotnet5.6", 22 | "dnxcore50", 23 | "portable-net45+win8" 24 | ] 25 | } 26 | }, 27 | 28 | "buildOptions": { 29 | "emitEntryPoint": true, 30 | "preserveCompilationContext": true 31 | }, 32 | 33 | "runtimeOptions": { 34 | "gcServer": true 35 | }, 36 | 37 | "publishOptions": { 38 | "include": [ 39 | "wwwroot", 40 | "web.config" 41 | ] 42 | }, 43 | 44 | "scripts": { 45 | "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SampleApp/src/SampleApp/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SampleApp/src/SmokeTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("SmokeTests")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("2666fd54-7477-4806-bd40-794cacfa69e3")] 20 | -------------------------------------------------------------------------------- /SampleApp/src/SmokeTests/SmokeTests.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 2666fd54-7477-4806-bd40-794cacfa69e3 10 | SmokeTests 11 | .\obj 12 | .\bin\ 13 | v4.6.1 14 | 15 | 16 | 2.0 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /SampleApp/src/SmokeTests/WebsiteTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | using System.Net.Http; 7 | 8 | using Xunit; 9 | 10 | namespace SmokeTests 11 | { 12 | public class WebsiteTests 13 | { 14 | [Fact] 15 | public async Task PassingTest() 16 | { 17 | using (var client = new HttpClient()) 18 | { 19 | var response = await client.GetStringAsync("http://localhost/"); 20 | 21 | Assert.Equal("Exploring ASP.NET Core with AWS.", response); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SampleApp/src/SmokeTests/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | 4 | "dependencies": { 5 | "NETStandard.Library": "1.5.0-rc2-24027", 6 | "xunit": "2.1.0-rc2-*", 7 | "dotnet-test-xunit": "1.0.0-rc2-*" 8 | }, 9 | "testRunner": "xunit", 10 | 11 | "frameworks": { 12 | "netcoreapp1.0": { 13 | "imports": [ 14 | "dotnet5.4", 15 | "portable-net451+win8" 16 | ] 17 | } 18 | }, 19 | "runtimes": { 20 | "win7-x64": { }, 21 | "win7-x86": { } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ValidateInstall.ps1: -------------------------------------------------------------------------------- 1 | sl C:\ExploringAspNetCore\SampleApp\src\SmokeTests 2 | 3 | # Restore the nuget references 4 | & "C:\Program Files\dotnet\dotnet.exe" restore 5 | 6 | # Run the smoke tests 7 | & "C:\Program Files\dotnet\dotnet.exe" test 8 | 9 | exit $LastExitCode -------------------------------------------------------------------------------- /appspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.0 2 | os: windows 3 | files: 4 | - source: \ 5 | destination: C:\ExploringAspNetCore 6 | hooks: 7 | ApplicationStop: 8 | - location: .\RemoveApp.ps1 9 | timeout: 30 10 | ApplicationStart: 11 | - location: .\InstallApp.ps1 12 | timeout: 300 13 | ValidateService: 14 | - location: .\ValidateInstall.ps1 15 | timeout: 300 --------------------------------------------------------------------------------