diff --git a/sample/.bundle/config b/sample/.bundle/config
new file mode 100644
index 00000000..0fe0ab90
--- /dev/null
+++ b/sample/.bundle/config
@@ -0,0 +1,3 @@
+---
+BUNDLE_PATH: gems
+BUNDLE_DISABLE_SHARED_GEMS: '1'
diff --git a/sample/Gemfile b/sample/Gemfile
new file mode 100644
index 00000000..3b174dea
--- /dev/null
+++ b/sample/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gem 'moonshot', git: 'git@github.com:acquia/moonshot', ref: 'master'
diff --git a/sample/Gemfile.lock b/sample/Gemfile.lock
new file mode 100644
index 00000000..955de8e7
--- /dev/null
+++ b/sample/Gemfile.lock
@@ -0,0 +1,65 @@
+GIT
+ remote: git@github.com:acquia/moonshot
+ revision: 2413a55a250ee63514c92bf107679f4e38bcc8d4
+ ref: master
+ specs:
+ moonshot (0.6.0)
+ aws-sdk (~> 2.2.0)
+ colorize
+ highline (~> 1.7.2)
+ interactive-logger (~> 0.1.1)
+ rotp (~> 2.1.1)
+ ruby-duration
+ semantic
+ thor (~> 0.19.1)
+ vandamme
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (4.2.6)
+ i18n (~> 0.7)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ aws-sdk (2.2.25)
+ aws-sdk-resources (= 2.2.25)
+ aws-sdk-core (2.2.25)
+ jmespath (~> 1.0)
+ aws-sdk-resources (2.2.25)
+ aws-sdk-core (= 2.2.25)
+ colorize (0.7.7)
+ github-markup (1.4.0)
+ highline (1.7.8)
+ i18n (0.7.0)
+ interactive-logger (0.1.1)
+ colorize (~> 0.7.7)
+ ruby-duration (~> 3.2, >= 3.2.1)
+ iso8601 (0.9.0)
+ jmespath (1.1.3)
+ json (1.8.3)
+ minitest (5.8.4)
+ redcarpet (3.3.4)
+ rotp (2.1.1)
+ ruby-duration (3.2.3)
+ activesupport (>= 3.0.0)
+ i18n
+ iso8601
+ semantic (1.4.1)
+ thor (0.19.1)
+ thread_safe (0.3.5)
+ tzinfo (1.2.2)
+ thread_safe (~> 0.1)
+ vandamme (0.0.11)
+ github-markup (~> 1.3)
+ redcarpet (~> 3.3.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ moonshot!
+
+BUNDLED WITH
+ 1.11.2
diff --git a/sample/README.md b/sample/README.md
new file mode 100644
index 00000000..6da53eb2
--- /dev/null
+++ b/sample/README.md
@@ -0,0 +1,78 @@
+# Moonshot Sample Application
+
+A small PHP application that is used to demo the
+[Moonshot](https://github.com/acquia/moonshot) deployment tool.
+
+## So, what's in it for me?
+
+After setup, you will be able to repeatedly deploy a PHP app to one or more
+isolated environments on AWS by running the following command:
+
+```
+bundle exec bin/environment deploy-code
+```
+
+You will also be able to update the OS and supporting software by pulling the
+latest changes in this repository and updating the stack with following command:
+
+```
+bundle exec bin/environment update
+```
+
+Lastly, you get a disposable, light-weight application that can be used to learn
+and hack on Moonshot without having to muck with applications that actually
+matter.
+
+## Setup
+
+1. Create a service role for Code Deploy in your AWS account.
+
+ Run the commands in the [Configuring an AWS account](https://github.com/acquia/moonshot#codedeploy-role)
+ section of Moonshot's README. If you wish to do this manually, follow the
+ [Create a Service Role for AWS CodeDeploy](http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-create-service-role.html)
+ documentation, and make sure to name the role `CodeDeployRole` as that is
+ what Moonshot expects.
+
+2. Install Moonshot and it's dependencies.
+
+ This step assumes that you have [Bundler](http://bundler.io/) and a modern
+ version of Ruby installed on your system.
+
+ ```shell
+ bundle install
+ ```
+
+3. Run the setup script to create a provisioning script, a parameters file for
+ your default environment, and a default `index.php` file. Change
+ `[S3_BUCKET]` to an S3 bucket you can write to, e.g. `my-s3-bucket`.
+
+ ```shell
+ ./bin/setup.sh [S3-BUCKET]
+ ```
+
+4. [OPTIONAL] Modify `./docroot/index.php` accordingly.
+
+ By default, a simple phpinfo() page is displayed.
+
+## Usage
+
+Run the following commands to create your environment and deploy code to it.
+Note that you will likely have to set the `AWS_REGION` environment variable
+prior to running these commands.
+
+```
+bundle exec bin/environment create
+bundle exec bin/environment deploy-code
+```
+
+Visit the AWS console, view your Cloud Formation stack, and click on the link in
+the "URL" key's value in the "Outputs" tab to view your app.
+
+Tear down your stack by running the following command:
+
+```
+bundle exec bin/environment delete
+```
+
+See https://github.com/acquia/moonshot#basic-usage for more advanced
+usage of Moonshot.
diff --git a/sample/appspec.yml b/sample/appspec.yml
new file mode 100644
index 00000000..02d0f3cc
--- /dev/null
+++ b/sample/appspec.yml
@@ -0,0 +1,19 @@
+version: 0.0
+os: linux
+files:
+ - source: docroot
+ destination: /usr/share/nginx/docroot
+permissions:
+ - object: /usr/share/nginx
+ pattern: "**"
+ owner: root
+ group: root
+hooks:
+ ApplicationStop:
+ - location: bin/aws-codedeploy-samples/load-balancing/elb/deregister_from_elb.sh
+ - location: bin/stop.sh
+ BeforeInstall:
+ - location: bin/clean.sh
+ ApplicationStart:
+ - location: bin/start.sh
+ - location: bin/aws-codedeploy-samples/load-balancing/elb/register_with_elb.sh
diff --git a/sample/bin/aws-codedeploy-samples/LICENSE b/sample/bin/aws-codedeploy-samples/LICENSE
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/sample/bin/aws-codedeploy-samples/README.md b/sample/bin/aws-codedeploy-samples/README.md
new file mode 100644
index 00000000..f1c7ef3f
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/README.md
@@ -0,0 +1,16 @@
+AWS CodeDeploy Samples
+======================
+
+The samples in the repository each demonstrate one of a few different scenarios.
+These fall into one of a few different categories, including:
+
+- Sample Applications
+- Integrations and templates for configuration management systems
+- Integrations with load-balancers like Elastic Load Balancing
+- Sample hooks for version control systems like Git.
+
+License
+=======
+
+These samples and templates are all licensed under Apache 2.0.
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/LICENSE.txt b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/LICENSE.txt
new file mode 100755
index 00000000..1eac78a6
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/appspec.yml b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/appspec.yml
new file mode 100755
index 00000000..7f0cdf94
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/appspec.yml
@@ -0,0 +1,18 @@
+version: 0.0
+os: linux
+files:
+ - source: /index.html
+ destination: /var/www/html/
+hooks:
+ BeforeInstall:
+ - location: scripts/install_dependencies
+ timeout: 300
+ runas: root
+ - location: scripts/start_server
+ timeout: 300
+ runas: root
+ ApplicationStop:
+ - location: scripts/stop_server
+ timeout: 300
+ runas: root
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/index.html b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/index.html
new file mode 100755
index 00000000..34b7341d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+ Sample Deployment
+
+
+
+
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/install_dependencies b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/install_dependencies
new file mode 100755
index 00000000..3d372993
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/install_dependencies
@@ -0,0 +1,3 @@
+#!/bin/bash
+yum install -y httpd
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/start_server b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/start_server
new file mode 100755
index 00000000..203194f2
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/start_server
@@ -0,0 +1,3 @@
+#!/bin/bash
+service httpd start
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/stop_server b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/stop_server
new file mode 100755
index 00000000..aef258ba
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Linux/scripts/stop_server
@@ -0,0 +1,6 @@
+#!/bin/bash
+isExistApp=`pgrep httpd`
+if [[ -n $isExistApp ]]; then
+ service httpd stop
+fi
+
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/LICENSE.txt b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/LICENSE.txt
new file mode 100755
index 00000000..7b080346
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/appspec.yml b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/appspec.yml
new file mode 100755
index 00000000..9df98df6
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/appspec.yml
@@ -0,0 +1,9 @@
+version: 0.0
+os: windows
+files:
+ - source: \index.html
+ destination: C:\inetpub\wwwroot
+hooks:
+ BeforeInstall:
+ - location: \before-install.bat
+ timeout: 900
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/before-install.bat b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/before-install.bat
new file mode 100755
index 00000000..fb2600e6
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/before-install.bat
@@ -0,0 +1,3 @@
+REM Install Internet Information Server (IIS).
+c:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -Command Import-Module -Name ServerManager
+c:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -Command Install-WindowsFeature Web-Server
\ No newline at end of file
diff --git a/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/index.html b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/index.html
new file mode 100755
index 00000000..ca5a6e90
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/applications/SampleApp_Windows/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+ Sample Deployment
+
+
+
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/README.md
new file mode 100644
index 00000000..bc83520f
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/README.md
@@ -0,0 +1,12 @@
+Ansible and AWS CodeDeploy
+--------------------------
+
+[Ansible](http://www.ansible.com) is a radically simple IT automation platform that makes your
+applications and systems easier to deploy. If you already have a set of Ansible playbooks, but just
+need somewhere to run them, our first template for Ansible and AWS CodeDeploy will demonstrate how a
+couple of simple deployment hooks will ensure Ansible is available on the local deployment instance
+and run the given playbooks. Alternatively, if you already have a process for building and
+maintaining your inventory, we've also built an Ansible module that you can use to install and run
+the AWS CodeDeploy host agent.
+
+[Learn more >](https://github.com/awslabs/aws-codedeploy-samples)
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/application_start.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/application_start.sh
new file mode 100755
index 00000000..c4bcd0d5
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/application_start.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Deploy hooks are run via absolute path, so taking dirname of this script will give us the path to
+# our deploy_hooks directory.
+. $(dirname $0)/common_variables.sh
+
+ansible-playbook $DESTINATION_PATH/lamp_simple/site.yml -i $DESTINATION_PATH/lamp_simple/hosts --connection=local
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/appspec.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/appspec.yml
new file mode 100644
index 00000000..fdf28303
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/appspec.yml
@@ -0,0 +1,18 @@
+version: 0.0
+os: linux
+files:
+ - source: /
+ destination: /etc/ansible/codedeploy
+hooks:
+ BeforeInstall:
+ - location: before_install.sh
+ timeout: 300
+ runas: root
+ ApplicationStart:
+ - location: application_start.sh
+ timeout: 300
+ runas: root
+ ValidateService:
+ - location: verify_service.sh
+ timeout: 300
+ runas: root
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/before_install.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/before_install.sh
new file mode 100755
index 00000000..9bafb3bc
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/before_install.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Check for ansible tools, and attempt to install if not
+
+yum list installed python-pip &> /dev/null
+if [ $? != 0 ]; then
+ yum install -y python-pip
+fi
+
+pip list | grep -q ansible
+if [ $? != 0 ]; then
+ pip install ansible
+fi
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/common_variables.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/common_variables.sh
new file mode 100644
index 00000000..ea921f5f
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/common_variables.sh
@@ -0,0 +1,15 @@
+#!/bin/true
+#
+# This is not an executable script, just a set of names and variable declarations.
+#
+# Use it with:
+# source common_variables.sh
+# Or:
+# . common_variables.sh
+
+APPLICATION_NAME="AnsibleApp"
+DEPLOY_GROUP="ansible"
+BUCKET=""
+BUNDLE_PATH="ansible-playbooks.zip"
+
+DESTINATION_PATH="/etc/ansible/codedeploy"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/LICENSE.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/LICENSE.md
new file mode 100644
index 00000000..2b437ec8
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/LICENSE.md
@@ -0,0 +1,4 @@
+Copyright (C) 2013 AnsibleWorks, Inc.
+
+This work is licensed under the Creative Commons Attribution 3.0 Unported License.
+To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/deed.en_US.
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/README.md
new file mode 100644
index 00000000..d800ff8d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/README.md
@@ -0,0 +1,27 @@
+Building a simple LAMP stack and deploying Application using Ansible Playbooks.
+-------------------------------------------
+
+These playbooks require Ansible 1.2.
+
+These playbooks are meant to be a reference and starter's guide to building
+Ansible Playbooks. These playbooks were tested on CentOS 6.x so we recommend
+that you use CentOS or RHEL to test these modules.
+
+This LAMP stack can be on a single node or multiple nodes. The inventory file
+'hosts' defines the nodes in which the stacks should be configured.
+
+ [webservers]
+ localhost
+
+ [dbservers]
+ bensible
+
+Here the webserver would be configured on the local host and the dbserver on a
+server called "bensible". The stack can be deployed using the following
+command:
+
+ ansible-playbook -i hosts site.yml
+
+Once done, you can check the results by browsing to http://localhost/index.php.
+You should see a simple test page and a list of databases retrieved from the
+database server.
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/all b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/all
new file mode 100644
index 00000000..698c2e43
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/all
@@ -0,0 +1,6 @@
+---
+# Variables listed here are applicable to all host groups
+
+httpd_port: 80
+ntpserver: localhost
+repository: https://github.com/bennojoy/mywebapp.git
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/dbservers b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/dbservers
new file mode 100644
index 00000000..bb60d44b
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/group_vars/dbservers
@@ -0,0 +1,9 @@
+---
+# The variables file used by the playbooks in the dbservers group.
+# These don't have to be explicitly imported by vars_files: they are autopopulated.
+
+mysqlservice: mysqld
+mysql_port: 3306
+dbuser: root
+dbname: foodb
+upassword: abc
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/hosts b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/hosts
new file mode 100644
index 00000000..bd573cc0
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/hosts
@@ -0,0 +1,5 @@
+[webservers]
+localhost
+
+[dbservers]
+localhost
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/handlers/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/handlers/main.yml
new file mode 100644
index 00000000..2235e75d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/handlers/main.yml
@@ -0,0 +1,9 @@
+---
+# Handler to handle common notifications. Handlers are called by other plays.
+# See http://ansible.cc/docs/playbooks.html for more information about handlers.
+
+- name: restart ntp
+ service: name=ntpd state=restarted
+
+- name: restart iptables
+ service: name=iptables state=restarted
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/tasks/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/tasks/main.yml
new file mode 100644
index 00000000..317d954c
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+# This playbook contains common plays that will be run on all nodes.
+
+- name: Install ntp
+ yum: name=ntp state=present
+ tags: ntp
+
+- name: Configure ntp file
+ template: src=ntp.conf.j2 dest=/etc/ntp.conf
+ tags: ntp
+ notify: restart ntp
+
+- name: Start the ntp service
+ service: name=ntpd state=started enabled=true
+ tags: ntp
+
+- name: Check if /etc/sysconfig/iptables exists
+ stat: path=/etc/sysconfig/iptables
+ register: ipt
+
+- name: Place basic iptables rules
+ template: src=iptables.j2 dest=/etc/sysconfig/iptables
+ notify: restart iptables
+ when: ipt is defined and ipt.stat.exists == false
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/iptables.j2 b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/iptables.j2
new file mode 100644
index 00000000..074a9ba7
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/iptables.j2
@@ -0,0 +1,36 @@
+# {{ ansible_managed }}
+*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+
+#Syn-flood protection
+-A INPUT -p tcp ! --syn -m state --state NEW -j DROP
+
+#Force SYN packets check
+-A INPUT -f -j DROP
+
+#Force Fragments packets check
+-A INPUT -p tcp --tcp-flags ALL ALL -j DROP
+
+#XMAS packets
+-A INPUT -p tcp --tcp-flags ALL NONE -j DROP
+
+# Accept packets belonging to established and related connections
+-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+
+# Allow pings
+-A INPUT -p icmp --icmp-type any -j ACCEPT
+
+# Set access for localhost
+-A INPUT -i lo -j ACCEPT
+
+# Allow SSH connections on tcp port 22
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
+
+# Set default policies for INPUT, FORWARD and OUTPUT chains
+-P INPUT DROP
+-P FORWARD DROP
+-P OUTPUT ACCEPT
+
+COMMIT
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/ntp.conf.j2 b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/ntp.conf.j2
new file mode 100644
index 00000000..6336c2ea
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/common/templates/ntp.conf.j2
@@ -0,0 +1,12 @@
+
+driftfile /var/lib/ntp/drift
+
+restrict 127.0.0.1
+restrict -6 ::1
+
+server {{ ntpserver }}
+
+includefile /etc/ntp/crypto/pw
+
+keys /etc/ntp/keys
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/handlers/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/handlers/main.yml
new file mode 100644
index 00000000..fffc0d57
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/handlers/main.yml
@@ -0,0 +1,8 @@
+---
+# Handler to handle DB tier notifications
+
+- name: restart mysql
+ service: name=mysqld state=restarted
+
+- name: restart iptables
+ service: name=iptables state=restarted
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/tasks/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/tasks/main.yml
new file mode 100644
index 00000000..4e09e55d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/tasks/main.yml
@@ -0,0 +1,27 @@
+---
+# This playbook will install mysql and create db user and give permissions.
+
+- name: Install Mysql package
+ yum: name={{ item }} state=installed
+ with_items:
+ - mysql-server
+ - MySQL-python
+
+- name: Create Mysql configuration file
+ template: src=my.cnf.j2 dest=/etc/my.cnf
+ notify:
+ - restart mysql
+
+- name: Start Mysql Service
+ service: name=mysqld state=started enabled=true
+
+- name: insert iptables rule
+ lineinfile: dest=/etc/sysconfig/iptables state=present regexp="{{ mysql_port }}"
+ insertafter="^:OUTPUT " line="-A INPUT -p tcp --dport {{ mysql_port }} -j ACCEPT"
+ notify: restart iptables
+
+- name: Create Application Database
+ mysql_db: name={{ dbname }} state=present
+
+- name: Create Application DB User
+ mysql_user: name={{ dbuser }} password={{ upassword }} priv=*.*:ALL host='%' state=present
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/templates/my.cnf.j2 b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/templates/my.cnf.j2
new file mode 100644
index 00000000..3944d063
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/db/templates/my.cnf.j2
@@ -0,0 +1,11 @@
+[mysqld]
+datadir=/var/lib/mysql
+socket=/var/lib/mysql/mysql.sock
+user=mysql
+# Disabling symbolic-links is recommended to prevent assorted security risks
+symbolic-links=0
+port={{ mysql_port }}
+
+[mysqld_safe]
+log-error=/var/log/mysqld.log
+pid-file=/var/run/mysqld/mysqld.pid
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/handlers/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/handlers/main.yml
new file mode 100644
index 00000000..79f13f91
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+# Handler for the webtier: handlers are called by other plays.
+# See http://ansible.cc/docs/playbooks.html for more information about handlers.
+
+- name: restart iptables
+ service: name=iptables state=restarted
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/copy_code.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/copy_code.yml
new file mode 100644
index 00000000..d1834e8d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/copy_code.yml
@@ -0,0 +1,9 @@
+---
+# These tasks are responsible for copying the latest dev/production code from
+# the version control system.
+
+- name: Copy the code from repository
+ git: repo={{ repository }} dest=/var/www/html/ansible
+
+- name: Creates the index.php file
+ template: src=index.php.j2 dest=/var/www/html/ansible/index.php
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/install_httpd.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/install_httpd.yml
new file mode 100644
index 00000000..a5d718e1
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/install_httpd.yml
@@ -0,0 +1,18 @@
+---
+# These tasks install http and the php modules.
+
+- name: Install http and php etc
+ yum: name={{ item }} state=present
+ with_items:
+ - httpd
+ - php
+ - php-mysql
+ - git
+
+- name: insert iptables rule for httpd
+ lineinfile: dest=/etc/sysconfig/iptables create=yes state=present regexp="{{ httpd_port }}" insertafter="^:OUTPUT "
+ line="-A INPUT -p tcp --dport {{ httpd_port }} -j ACCEPT"
+ notify: restart iptables
+
+- name: http service state
+ service: name=httpd state=started enabled=yes
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/main.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/main.yml
new file mode 100644
index 00000000..796842ed
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- include: install_httpd.yml
+- include: copy_code.yml
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/templates/index.php.j2 b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/templates/index.php.j2
new file mode 100644
index 00000000..61fdb5d3
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/roles/web/templates/index.php.j2
@@ -0,0 +1,24 @@
+
+
+ Ansible Application
+
+
+
+ Homepage
+
+";
+ echo "List of Databases: ";
+ {% for host in groups['dbservers'] %}
+ $link = mysql_connect('{{ hostvars[host].ansible_eth0.ipv4.address }}', '{{ hostvars[host].dbuser }}', '{{ hostvars[host].upassword }}') or die(mysql_error());
+ {% endfor %}
+ $res = mysql_query("SHOW DATABASES");
+ while ($row = mysql_fetch_assoc($res)) {
+ echo $row['Database'] . "\n";
+ }
+?>
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/site.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/site.yml
new file mode 100644
index 00000000..f395725b
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/lamp_simple/site.yml
@@ -0,0 +1,23 @@
+---
+# This playbook deploys the whole application stack in this site.
+
+- name: apply common configuration to all nodes
+ hosts: all
+ remote_user: root
+
+ roles:
+ - common
+
+- name: configure and deploy the webservers and application code
+ hosts: webservers
+ remote_user: root
+
+ roles:
+ - web
+
+- name: deploy MySQL and configure the databases
+ hosts: dbservers
+ remote_user: root
+
+ roles:
+ - db
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/verify_service.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/verify_service.sh
new file mode 100755
index 00000000..081b55b4
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/local-only/verify_service.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Deploy hooks are run via absolute path, so taking dirname of this script will give us the path to
+# our deploy_hooks directory.
+. $(dirname $0)/common_variables.sh
+
+curl -s http://localhost:80/ansible/index.php
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/library/aws_codedeploy b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/library/aws_codedeploy
new file mode 100755
index 00000000..edbff32b
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/library/aws_codedeploy
@@ -0,0 +1,129 @@
+#!/usr/bin/python
+
+import sys
+import os
+import urlparse
+import shutil
+from subprocess import Popen
+from subprocess import PIPE
+
+DOCUMENTATION = '''
+---
+module: aws_codedeploy
+short_description: Installs and starts the AWS CodeDeploy Agent
+description:
+ - Installs and starts the AWS CodeDeploy Agent
+version_added: 0.0
+author: Andrew Fitz Gibbon
+options:
+ enabled:
+ description:
+ - Enable the agent
+ choices: [ "yes", "no" ]
+ required: true
+'''
+
+try:
+ import boto
+ from boto.s3.connection import Location
+ from boto.utils import get_instance_metadata
+except ImportError:
+ print "failed=True msg='boto required for this module'"
+ sys.exit(1)
+
+# Determine if we're running on an EC2 instance
+def on_ec2():
+ try:
+ instance_metadata = boto.utils.get_instance_metadata(timeout=2, num_retries=2)
+ if 'instance-id' in instance_metadata.keys() and len(instance_metadata['instance-id']) > 0:
+ return True
+ else:
+ return False
+ except:
+ return False
+
+# Determine what kind of instance
+def os_type():
+ os = 'na'
+ release = ''
+
+ try:
+ release = str(Popen(['lsb_release', '-a'], stdout=PIPE).communicate())
+ except:
+ release = str(Popen(['cat', '/etc/system-release'], stdout=PIPE).communicate())
+
+ if 'AmazonAMI' in release or 'Amazon Linux AMI' in release:
+ return 'amzn'
+ elif 'Debian' in release or 'Ubuntu' in release:
+ return 'deb'
+ else:
+ return os
+
+def get_package(module, pkg_type):
+ dest = '/tmp/codedeploy_package.' + pkg_type
+
+ pkg_url = 'https://s3.amazonaws.com/aws-codedeploy-us-east-1/latest/codedeploy-agent'
+ if pkg_type == 'deb':
+ pkg_url += '_all.deb'
+ elif pkg_type == 'rpm':
+ pkg_url += '.noarch.rpm'
+ else:
+ raise ValueError('unknown package type')
+
+ body, info = fetch_url(module, pkg_url)
+
+ if info['status'] != 200:
+ module.fail_json(msg="Failed to download agent",
+ status_code=info['status'],
+ respose=info['msg'],
+ url=pkg_url)
+
+ try:
+ f = open(dest, 'wb')
+ shutil.copyfileobj(body, f)
+ except Exception, e:
+ module.fail_json(msg="failed to write agent package to disk: %s" % str(e))
+
+ return dest
+
+def install_pacakge(source, pkg_type):
+ cmd = ''
+ if pkg_type == 'deb':
+ cmd = 'dpkg -i ' + source + '; apt-get -q -y -f install'
+ elif pkg_type == 'rpm':
+ cmd = 'yum install -q -y ' + source
+ else:
+ raise ValueError('unknown package type')
+
+ os.system(cmd) # TODO catch return
+
+def main():
+ module = AnsibleModule(
+ argument_spec = dict(
+ enabled = dict(required=True, choices=BOOLEANS) # TODO actually use this
+ )
+ )
+
+ if not on_ec2():
+ module.fail_json(msg="must install the AWS CodeDeploy on an EC2 instance")
+
+ try:
+ os = os_type()
+ pkg_type = ''
+ if os == 'deb':
+ pkg_type = 'deb'
+ elif os == 'amzn':
+ pkg_type = 'rpm'
+ else:
+ module.fail_json(msg="must install the AWS CodeDeploy on a supported OS type")
+
+ pkg = get_package(module, pkg_type)
+ install_pacakge(pkg, pkg_type)
+ except Exception, e:
+ module.fail_json(msg=str(e))
+
+ module.exit_json(installed=True)
+
+from ansible.module_utils.basic import *
+from ansible.module_utils.urls import *
+main()
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/site.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/site.yml
new file mode 100644
index 00000000..9d6115d6
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/ansible/module/site.yml
@@ -0,0 +1,6 @@
+---
+- hosts: all
+ tasks:
+ - name: install codedeploy agent
+ sudo: yes
+ action: aws_codedeploy enabled=true
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/README.md
new file mode 100644
index 00000000..c9987dc8
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/README.md
@@ -0,0 +1,12 @@
+Chef and AWS CodeDeploy
+-----------------------
+
+[Chef](https://www.getchef.com) is a configuration management tool that enables users to write
+recipes that describe how the instances in their fleet are configured. AWS provides two template
+samples for integrating Chef and AWS CodeDeploy. The first is a Chef cookbook that will install and
+start the AWS CodeDeploy host agent, giving you the ability to continue managing your host
+infrastructure via Chef while also being able to take advantage of the power of AWS CodeDeploy. The
+second sample template demonstrates how to use CodeDeploy to orchestrate running cookbooks and
+recipes via chef-solo on each node.
+
+[Learn more >](https://github.com/awslabs/aws-codedeploy-samples)
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/README.md
new file mode 100644
index 00000000..66702891
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/README.md
@@ -0,0 +1,31 @@
+Installing the AWS CodeDeploy Agent with Chef
+=============================================
+
+In the previous post, we learned how to use the power of AWS CodeDeploy to orchestrate chef-solo. It took
+the perspective of having half of your dependencies already installed – namely, the CodeDeploy agent. For
+this post, we'll look at it from a different angle: the CodeDeploy host agent isn't installed yet, but you
+have a pre-existing Chef environment running on Amazon EC2 instances.
+
+Setup and Preconditions
+-----------------------
+
+The post below makes a few assumptions about your environment that may or may not be true. First and
+foremost is that you have a working Chef environment. We'll assume that you've worked through your
+own workflow for managing that environment and your chef-repo. If you are still new to Chef, their
+documentation has a lot of very helpful information: [http://docs.getchef.com](http://docs.getchef.com)
+
+AWS CodeDeploy Host Agent Cookbook
+----------------------------------
+
+We've built a custom Chef cookbook to help ease the process of installing the CodeDeploy agent. You
+can download that cookbook
+[here](https://github.com/awslabs/aws-codedeploy-samples/tree/master/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/recipes).
+To install the CodeDeploy agent, simply download the linked archive, copy the codedeploy-agent
+directory into your chef-repo, and add `recipe[codedeploy-agent]` to your run list. If you just want
+to test this out with a chef-solo instance, we've included a sample configuration for you.
+
+The cookbook has three simple steps:
+
+1. Download the package for the CodeDeploy host agent.
+1. Install the agent.
+1. Start the agent.
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/metadata.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/metadata.rb
new file mode 100644
index 00000000..0132dcae
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/metadata.rb
@@ -0,0 +1,2 @@
+name 'codedeploy-agent'
+recipe 'codedeploy-agent::default', 'Fetches, installs, and starts the AWS CodeDeploy host agent'
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/recipes/default.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/recipes/default.rb
new file mode 100644
index 00000000..ba4604ff
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/cookbooks/codedeploy-agent/recipes/default.rb
@@ -0,0 +1,14 @@
+remote_file "#{Chef::Config[:file_cache_path]}/codedeploy-agent-install" do
+ source "https://s3.amazonaws.com/aws-codedeploy-us-east-1/latest/install"
+ mode 0755
+end
+
+bash "install-codedeploy-agent" do
+ code <<-EOH
+ #{Chef::Config[:file_cache_path]}/codedeploy-agent-install auto
+ EOH
+end
+
+service "codedeploy-agent" do
+ action [:enable, :start]
+end
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/node.json b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/node.json
new file mode 100644
index 00000000..6cfdecfb
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/node.json
@@ -0,0 +1,3 @@
+{
+ "run_list": [ "recipe[codedeploy-agent]" ]
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/solo.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/solo.rb
new file mode 100644
index 00000000..2669c908
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/aws-codedeploy-agent/solo.rb
@@ -0,0 +1,4 @@
+# These are here just for testing only.
+file_cache_path "/etc/chef"
+cookbook_path "/etc/chef/cookbooks"
+json_attribs "/etc/chef/node.json"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/README.md
new file mode 100644
index 00000000..87ff5738
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/README.md
@@ -0,0 +1,218 @@
+Using AWS CodeDeploy to Orchestrate chef-solo
+=============================================
+
+[Chef](http://www.getchef.com/chef/) is a great tool for automating infrastructure management, but
+sometimes running and maintaining a central Chef server – and ensuring that it's highly available –
+can be cost-prohibitive. So you turn to chef-solo, where you are fully responsible for orchestrating
+the distribution of cookbooks and running chef-solo. Up until now, you've used a set of custom
+scripts (perhaps built on top of tools like Capistrano) to do that orchestration. Here, we'll show
+you how AWS CodeDeploy can do all of the heavy lifting for you with almost no custom scripting.
+
+For this post, we'll start with an instance that already has the CodeDeploy agent installed. If you
+haven't already – or cleaned up afterwards – please complete *Step 1: Set Up a New Amazon EC2 Instance*
+in the [AWS CodeDeploy Getting Started Guide](http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-set-up-new-instance.html).
+
+*Note: The CloudFormation example is a lot easier to use: http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-use-cloud-formation-template.html*
+
+Prepare the bundle
+------------------
+
+Next, we prepare the bundle, or source content, that will contain our Chef cookbooks and
+configuration. Here, we use a simple "hello world" cookbook, but you're free to substitute your own.
+The full source for this example bundle is also available
+[here](https://github.com/awslabs/aws-codedeploy-samples/tree/master/conf-mgmt/chef/solo).
+
+Note: You will have to use the Apache Maven command, "mvn package" to create the target/hello.war file.
+
+First, create directories for our application and deploy hooks. The base of these will be the root
+of our CodeDeploy revision:
+
+```bash
+mkdir -p chef-solo-example/deploy_hooks
+cd chef-solo-example
+```
+
+Then create a simple AppSpec as `./appspec.yml`:
+
+```yml
+version: 0.0
+os: linux
+files:
+ - source: chef/
+ destination: /etc/chef/codedeploy
+ - source: target/hello.war
+ destination: /var/lib/tomcat6/webapps
+hooks:
+ BeforeInstall:
+ - location: deploy_hooks/install-chef.sh
+ timeout: 1800
+ runas: root
+ ApplicationStart:
+ - location: deploy_hooks/chef-solo.sh
+ runas: root
+ ValidateService:
+ - location: deploy_hooks/verify_service.sh
+ runas: root
+```
+
+This AppSpec tells AWS CodeDeploy that we want all of our chef configurations to be installed into
+`/etc/chef/codedeploy`, the war file for our app should be installed into the default tomcat6
+webapps directory, and that it should run the scripts in `deploy_hooks/` on the appropriate
+deployment events. Specifically: one to ensure that Chef is properly installed and one to initiate
+the chef-solo run.
+
+Before we run anything, our `BeforeInstall` checks that Chef and RubyGems are installed and attempts
+to install them. It also runs `knife install` to fetch the tomcat cookbook (in a normal application,
+it's more likely that you'd already have done this; we're doing it as part of the deployment to keep
+the sample bundle small):
+
+```bash
+#!/bin/bash
+
+yum list installed rubygems &> /dev/null
+if [ $? != 0 ]; then
+ yum -y install gcc-c++ ruby-devel make autoconf automake rubygems
+fi
+
+gem list | grep -q chef
+if [ $? != 0 ]; then
+ gem install chef ohai
+fi
+
+# Install the tomcat cookbook
+yum list installed git &> /dev/null
+if [ $? != 0 ]; then
+ yum install -y git
+fi
+
+cd /etc/chef/codedeploy/
+if ! test -r .git; then
+ git init .; git add -A .; git commit -m "Init commit"
+fi
+if ! test -r ./cookbooks/tomcat; then
+ /usr/local/bin/knife cookbook site install tomcat -o ./cookbooks
+fi
+```
+
+Then, once our files are installed into the correct locations, our `ApplicationStart` lifecycle hook
+actually initiates the chef-solo run::
+
+```bash
+#!/bin/bash
+/usr/local/bin/chef-solo -c /etc/chef/codedeploy/chef/solo.rb
+```
+
+Finally, the `ValidateService` hook checks to see whether or not our app is responding as expected:
+
+```bash
+#!/bin/bash
+
+result=$(curl -s http://localhost/hello/)
+
+if [[ "$result" =~ "Hello World" ]]; then
+ exit 0
+else
+ exit 1
+fi
+```
+
+Our chef configuration in this case is simply to set a couple of default tomcat options:
+
+```ruby
+node.default["tomcat"]["user"] = "root"
+node.default["tomcat"]["port"] = 80
+```
+
+And the node.json and solo.rb configurations are similarly straightforward, just running the tomcat
+default recipe and our own configuration (which we've titled `homesite`):
+
+node.json:
+
+```javascript
+{
+ "run_list": [ "recipe[homesite]", "recipe[tomcat]" ]
+}
+```
+
+solo.rb:
+
+```ruby
+file_cache_path "/etc/chef/codedeploy/"
+cookbook_path "/etc/chef/codedeploy/cookbooks"
+json_attribs "/etc/chef/codedeploy/node.json"
+```
+
+The java app does nothing more than respond with 'Hello World' at the root of the app. You can take
+a closer look by downloading the source at the link above.
+
+Now that we've set up our bundle, we're ready to get things set up in AWS CodeDeploy.
+
+Set Up the AWS CodeDeploy Application
+------------------------------
+
+Even though we might have an application and deployment group set up already set up on this
+instance, it's a good practice to create new ones. First, we create the new application:
+
+```sh
+aws deploy create-application --application-name chef-solo-example
+```
+
+Then, using the ***CodeDeployTrustRoleArn*** that was assigned to our AWS CloudFormation stack, we create a
+new deployment group for the chef-solo-example application:
+
+```sh
+aws deploy create-deployment-group \
+ --application-name chef-solo-example \
+ --deployment-group-name ChefSolo_DeploymentGroup \
+ --deployment-config-name CodeDeployDefault.AllAtOnce \
+ --ec2-tag-filters Key=Name,Value=CodeDeployDeployment,Type=KEY_AND_VALUE \
+ --service-role-arn CodeDeployTrustRoleArn
+```
+
+In this deployment group, we've set the default deployment configuration to
+`CodeDeployDefault.AllAtOnce`. This will deploy to all of our instances at the same time. In a real
+production app, you'd probably want to set it to something more conservative like
+`CodeDeployDefault.OneAtATime` or a custom configuration.
+
+Push and Deploy the Application
+-------------------------------
+
+At this point, we have a running Amazon EC2 instance that has the AWS CodeDeploy agent installed, an
+application bundle containing our Chef cookbooks, and an AWS CodeDeploy application ready to accept
+deployments.
+
+We next need to upload our bundle and register it as a new revision in AWS CodeDeploy. The `aws deploy push` command in
+the AWS CLI will take care of that for us (make sure you replace ***bucket-name*** with the name of
+an Amazon S3 bucket you have set up for AWS CodeDeploy):
+
+```sh
+aws deploy push \
+ --application-name chef-solo-example \
+ --s3-location s3://bucket-name/chef-solo.zip \
+ --ignore-hidden-files
+```
+
+And now we're ready for a deployment:
+
+```sh
+aws deploy create-deployment \
+ --application-name chef-solo-example \
+ --deployment-config-name CodeDeployDefault.AllAtOnce \
+ --deployment-group-name ChefSolo_DeploymentGroup \
+ --s3-location bucket=bucket-name,key=chef-solo.zip,bundleType=zip
+```
+
+Note here that we specify the deployment configuration again. This is so that we can override any
+default that we might have set on the deployment group.
+
+Once the deployment finishes (which you can check with either the AWS CodeDeploy console, or the `aws deploy
+get-deployment` CLI command), you should be able to log into the instance and verify that your
+cookbooks were applied.
+
+Wrapping up
+-----------
+
+Now you're ready to use the power of AWS CodeDeploy to orchestrate your fleet of chef-solo nodes. In our
+next post, we'll demonstrate how you can use a Chef recipe to install the AWS CodeDeploy agent, thus
+allowing your infrastructure to continue to be managed by Chef while your application deployments
+are managed via AWS CodeDeploy.
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/appspec.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/appspec.yml
new file mode 100644
index 00000000..8a2f97ce
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/appspec.yml
@@ -0,0 +1,18 @@
+version: 0.0
+os: linux
+files:
+ - source: chef/
+ destination: /etc/chef/codedeploy
+ - source: target/hello.war
+ destination: /var/lib/tomcat6/webapps
+hooks:
+ BeforeInstall:
+ - location: deploy_hooks/install-chef.sh
+ timeout: 1800
+ runas: root
+ ApplicationStart:
+ - location: deploy_hooks/chef-solo.sh
+ runas: root
+ ValidateService:
+ - location: deploy_hooks/verify_service.sh
+ runas: root
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/Cheffile b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/Cheffile
new file mode 100644
index 00000000..cb87cd2b
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/Cheffile
@@ -0,0 +1,3 @@
+site "https://supermarket.getchef.com/api/v1"
+
+cookbook "tomcat"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/node.json b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/node.json
new file mode 100644
index 00000000..aa686923
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/node.json
@@ -0,0 +1,3 @@
+{
+ "run_list": [ "recipe[homesite]", "recipe[tomcat]" ]
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/site-cookbooks/homesite/recipes/default.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/site-cookbooks/homesite/recipes/default.rb
new file mode 100644
index 00000000..f3fa2ff6
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/site-cookbooks/homesite/recipes/default.rb
@@ -0,0 +1,2 @@
+node.default["tomcat"]["user"] = "root"
+node.default["tomcat"]["port"] = 8888
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/solo.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/solo.rb
new file mode 100644
index 00000000..6ad67bc4
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/chef/solo.rb
@@ -0,0 +1,6 @@
+file_cache_path "/etc/chef/codedeploy/"
+cookbook_path [
+ "/etc/chef/codedeploy/cookbooks",
+ "/etc/chef/codedeploy/site-cookbooks"
+ ]
+json_attribs "/etc/chef/codedeploy/node.json"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/chef-solo.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/chef-solo.sh
new file mode 100755
index 00000000..c34ada90
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/chef-solo.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# First, make sure the tomcat cookbook is installed
+cd /etc/chef/codedeploy/
+/usr/local/bin/librarian-chef install
+
+/usr/local/bin/chef-solo -c /etc/chef/codedeploy/solo.rb
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/install-chef.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/install-chef.sh
new file mode 100755
index 00000000..ac4e1f5a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/install-chef.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+if [ ! -z "`which yum`" ]; then
+
+ # On rpm-based system, use yum to install rubygems and related packages for building native
+ # extensions
+
+ for pkg in rubygems20 gcc-c++ ruby20-devel make autoconf automake; do
+ yum list installed $pkg &> /dev/null
+ if [ $? != 0 ]; then
+ yum -y install $pkg
+ fi
+ done
+
+elif [ ! -z "`which apt-get`" ]; then
+ # On debian-like system, use apt-get to install
+
+ for pkg in ruby2.0-dev ruby2.0 make autoconf g++; do
+ aptitude show $pkg | grep -q 'State: installed'
+ if [ $? != 0 ]; then
+ apt-get -y install $pkg
+ fi
+ done
+fi
+
+# Now, we can install the required gems
+for gem in chef ohai librarian-chef io-console; do
+ gem2.0 list | grep -q $gem
+ if [ $? != 0 ]; then
+ gem2.0 install $gem
+
+ if [ $? != 0 ]; then
+ echo "Failed to install required gems. Cannot continue with deployment"
+ exit 1
+ fi
+ fi
+done
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/verify_service.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/verify_service.sh
new file mode 100755
index 00000000..c4100989
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/deploy_hooks/verify_service.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+result=$(curl -s http://localhost:8888/hello/)
+
+if [[ "$result" =~ "Hello World" ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/pom.xml b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/pom.xml
new file mode 100644
index 00000000..e65844c2
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+ com.amazonaws.sample
+ hello
+ war
+ 1.0-SNAPSHOT
+ hello Maven Webapp
+ http://maven.apache.org
+
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.0.1
+ provided
+
+
+
+
+ hello
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/java/com/amazonaws/sample/HelloServlet.java b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/java/com/amazonaws/sample/HelloServlet.java
new file mode 100644
index 00000000..ba2a298a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/java/com/amazonaws/sample/HelloServlet.java
@@ -0,0 +1,20 @@
+package com.amazonaws.sample;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class HelloServlet extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ PrintWriter writer = response.getWriter();
+ writer.print("Hello World
");
+ }
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/webapp/WEB-INF/web.xml b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..d105e7aa
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/chef/solo/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,19 @@
+
+
+
+ Hello World Web Application
+
+
+ HelloServlet
+ com.amazonaws.sample.HelloServlet
+
+
+
+ HelloServlet
+ /
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/README.md
new file mode 100644
index 00000000..702d7a0f
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/README.md
@@ -0,0 +1,12 @@
+Puppet and AWS CodeDeploy
+-----------------------
+
+[Puppet](http://puppetlabs.com/) is a configuration management system that allows you to define the
+state of your IT infrastructure, then automatically enforces the correct state. AWS provides a
+couple of sample templates to get you working with Puppet and AWS CodeDeploy faster. The first is a
+Puppet module that will install and start the AWS CodeDeploy host agent, giving you the ability to
+continue managing your host infrastructure via Puppet while also being able to take advantage of the
+power of AWS CodeDeploy. The second sample template demonstrates how to use CodeDeploy to
+orchestrate running modules and manifests via masterless puppet on each node.
+
+[Learn more >](https://github.com/awslabs/aws-codedeploy-samples)
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.fixtures.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.fixtures.yml
new file mode 100644
index 00000000..e7227119
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.fixtures.yml
@@ -0,0 +1,5 @@
+fixtures:
+ repositories:
+ stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
+ symlinks:
+ codedeploy: "#{source_dir}"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.gitignore b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.gitignore
new file mode 100644
index 00000000..641e153a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.gitignore
@@ -0,0 +1,7 @@
+.*.sw?
+pkg
+spec/fixtures
+.rspec_system
+.vagrant
+.bundle
+vendor
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.rspec b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.rspec
new file mode 100644
index 00000000..8c18f1ab
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/.rspec
@@ -0,0 +1,2 @@
+--format documentation
+--color
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Guardfile b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Guardfile
new file mode 100644
index 00000000..fd50602a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Guardfile
@@ -0,0 +1,5 @@
+notification :off
+
+guard 'rake', :task => 'test' do
+ watch(%r{^manifests\/(.+)\.pp$})
+end
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/LICENSE b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/LICENSE
new file mode 100644
index 00000000..9f710553
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Modulefile b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Modulefile
new file mode 100644
index 00000000..47b968fc
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Modulefile
@@ -0,0 +1,10 @@
+name 'aws-codedeploy'
+version '0.1.0'
+source ''
+author 'Amazon Web Services'
+license 'Apache 2.0'
+summary ''
+description ''
+project_page ''
+
+dependency 'puppetlabs/stdlib'
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/README.md
new file mode 100644
index 00000000..1fa108cd
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/README.md
@@ -0,0 +1,50 @@
+AWS CodeDeploy Puppet Module
+============================
+
+#### Table of Contents
+
+1. [Overview](#overview)
+2. [Module Description - What the module does and why it is useful](#module-description)
+3. [Usage - Configuration options and additional functionality](#usage)
+4. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
+5. [Limitations - OS compatibility, etc.](#limitations)
+6. [Development - Guide for contributing to the module](#development)
+
+## Overview
+
+This module installs the AWS CodeDeploy Agent.
+
+## Module Description
+
+The AWS CodeDeploy agent will copy packages to an EC2 instance from a configured S3 bucket. This
+module should be used on an EC2 instance that already has Puppet installed. At this time, the only
+supported operating systems are RedHat variants and Amazon Linux, through the installation of an RPM
+package.
+
+## Usage
+
+Put the classes, types, and resources for customizing, configuring, and doing the fancy stuff with
+your module here.
+
+
+```puppet
+ codedeploy {}
+```
+
+##Reference
+
+###Class: codedeploy
+
+####Parameters
+
+* **package_source** - The url to install the CodeDeploy package from. Defaults to
+`https://s3.amazonaws.com/aws-codedeploy-us-east-1/latest/codedeploy-agent.noarch.rpm`
+
+##Limitations
+
+ * This module requires a RedHat or Amazon Linux based operating system that is capable of
+ installing RPM packages.
+
+##Development
+
+Please see our [GitHub repositories](https://github.com/awslabs)
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Rakefile b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Rakefile
new file mode 100644
index 00000000..d913e842
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/Rakefile
@@ -0,0 +1,36 @@
+require 'puppetlabs_spec_helper/rake_tasks'
+require 'puppet-lint/tasks/puppet-lint'
+require 'puppet-syntax/tasks/puppet-syntax'
+
+# These gems aren't always present, for instance
+# if run with --without development
+begin
+ require 'puppet_blacksmith/rake_tasks'
+rescue LoadError
+end
+
+PuppetLint.configuration.relative = true
+PuppetLint.configuration.send("disable_80chars")
+PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
+PuppetLint.configuration.fail_on_warnings = true
+
+# Forsake support for Puppet 2.6.2 for the benefit of cleaner code.
+# http://puppet-lint.com/checks/class_parameter_defaults/
+PuppetLint.configuration.send('disable_class_parameter_defaults')
+# http://puppet-lint.com/checks/class_inherits_from_params_class/
+PuppetLint.configuration.send('disable_class_inherits_from_params_class')
+
+exclude_paths = [
+ "pkg/**/*",
+ "vendor/**/*",
+ "spec/**/*",
+]
+PuppetLint.configuration.ignore_paths = exclude_paths
+PuppetSyntax.exclude_paths = exclude_paths
+
+desc "Run syntax, lint, and spec tests."
+task :test => [
+ :syntax,
+ :lint,
+ :spec,
+]
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/init.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/init.pp
new file mode 100644
index 00000000..274c6439
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/init.pp
@@ -0,0 +1,19 @@
+# == Class: codedeploy
+#
+# Install and manage the AWS CodeDeploy agent
+#
+# === Parameters
+#
+# [*package_source*]
+# URL or filepath passed to package provider to install agent
+#
+class codedeploy (
+ $package_source = $codedeploy::params::package_source,
+) inherits codedeploy::params {
+
+ validate_string($package_source)
+
+ class { 'codedeploy::install': } ~>
+ class { 'codedeploy::service': } ->
+ Class['codedeploy']
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/install.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/install.pp
new file mode 100644
index 00000000..6c87c571
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/install.pp
@@ -0,0 +1,10 @@
+# == Class codedeploy::install
+#
+class codedeploy::install {
+
+ package { 'codedeploy-agent':
+ ensure => present,
+ source => $codedeploy::package_source,
+ provider => rpm,
+ }
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/params.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/params.pp
new file mode 100644
index 00000000..e805bb17
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/params.pp
@@ -0,0 +1,15 @@
+# == Class codedeploy::params
+#
+# This class is meant to be called from codedeploy
+# It sets variables according to platform
+#
+class codedeploy::params {
+ case $::osfamily {
+ 'RedHat', 'Linux': {
+ $package_source = 'https://s3.amazonaws.com/aws-codedeploy-us-east-1/latest/codedeploy-agent.noarch.rpm'
+ }
+ default: {
+ fail("${::operatingsystem} not supported")
+ }
+ }
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/service.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/service.pp
new file mode 100644
index 00000000..db9fb755
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/manifests/service.pp
@@ -0,0 +1,12 @@
+# == Class codedeploy::service
+#
+# This class is meant to be called from codedeploy
+# It ensure the service is running
+#
+class codedeploy::service {
+
+ service { 'codedeploy-agent':
+ ensure => running,
+ enable => true,
+ }
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/metadata.json b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/metadata.json
new file mode 100644
index 00000000..d11c250c
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/metadata.json
@@ -0,0 +1,16 @@
+{
+ "name": "aws-codedeploy",
+ "version": "0.1.0",
+ "author": "Amazon Web Services",
+ "summary": "",
+ "license": "Apache 2.0",
+ "source": "",
+ "project_page": "",
+ "issues_url": "",
+ "dependencies": [
+ {
+ "name": "puppetlabs-stdlib",
+ "version_requirement": ">= 1.0.0"
+ }
+ ]
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/coverage_spec.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/coverage_spec.rb
new file mode 100644
index 00000000..12513b83
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/coverage_spec.rb
@@ -0,0 +1 @@
+at_exit { RSpec::Puppet::Coverage.report! }
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/example_spec.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/example_spec.rb
new file mode 100644
index 00000000..c707ba98
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/classes/example_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe 'codedeploy' do
+ let(:facts) {{
+ :osfamily => 'RedHat',
+ }}
+ describe "codedeploy class without any parameters" do
+
+ it { should compile.with_all_deps }
+
+ it { should contain_class('codedeploy::params') }
+ it { should contain_class('codedeploy::install') }
+ it { should contain_class('codedeploy::service').that_subscribes_to('codedeploy::install') }
+
+ it { should contain_service('codedeploy-agent') }
+ it { should contain_package('codedeploy-agent')
+ .with_ensure('present')
+ .with_source('https://s3.amazonaws.com/aws-codedeploy-us-east-1/latest/codedeploy-agent.noarch.rpm')
+ }
+ end
+
+ describe "codedeploy class with custom package source" do
+ let(:params) {{ :package_source => 'https://example.com/package.rpm' }}
+ it { should contain_package('codedeploy-agent').with_source('https://example.com/package.rpm') }
+ end
+
+ context 'unsupported operating system' do
+ describe 'codedeploy class without any parameters on Solaris/Nexenta' do
+ let(:facts) {{
+ :osfamily => 'Solaris',
+ :operatingsystem => 'Nexenta',
+ }}
+
+ it { expect { should contain_package('codedeploy') }.to raise_error(Puppet::Error, /Nexenta not supported/) }
+ end
+ end
+end
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/spec_helper.rb b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/spec_helper.rb
new file mode 100644
index 00000000..2c6f5664
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/spec/spec_helper.rb
@@ -0,0 +1 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/tests/init.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/tests/init.pp
new file mode 100644
index 00000000..bdcaade2
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/aws-codedeploy/tests/init.pp
@@ -0,0 +1,12 @@
+# The baseline for module testing used by Puppet Labs is that each manifest
+# should have a corresponding test manifest that declares that class or defined
+# type.
+#
+# Tests are then run by using puppet apply --noop (to check for compilation
+# errors and view a log of events) or by fully applying the test in a virtual
+# environment (to compare the resulting system state to the desired state).
+#
+# Learn more about module testing here:
+# http://docs.puppetlabs.com/guides/tests_smoke.html
+#
+include codedeploy
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/README.md
new file mode 100644
index 00000000..b5d3b36d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/README.md
@@ -0,0 +1,202 @@
+Using AWS CodeDeploy to Orchestrate Masterless Puppet
+=====================================================
+
+[Puppet](http://puppetlabs.com/) is a great tool for automating infrastructure management. You may
+be familiar with using custom scripts (perhaps built on top of tools like Capistrano) to orchestrate
+application deployments. Here, we'll show you how AWS CodeDeploy can do all of the heavy lifting for
+you with almost no custom scripting.
+
+For this post, we'll start with an instance that already has the CodeDeploy agent installed. If you
+haven't already – or cleaned up afterwards – please complete *Step 1: Set Up an Amazon EC2 Instance*
+in the [AWS CodeDeploy Getting Started Guide](http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-set-up-new-instance.html).
+
+Prepare the bundle
+------------------
+
+To start, we prepare the bundle, or source content, that will contain our Puppet modules and
+configuration. The sample app we use here is a simple Java web app, but you're free to substitute
+your own. The full source for this example bundle is also available [here](https://github.com/awslabs/aws-codedeploy-samples/tree/master/conf-mgmt/puppet/masterless).
+
+First, create directories for our application and deploy hooks. The base of these will be the root
+of our CodeDeploy revision:
+
+```bash
+mkdir -p puppet-example/deploy_hooks
+cd puppet-example
+```
+
+Then create a simple AppSpec as `./appspec.yml`:
+
+```yml
+version: 0.0
+os: linux
+files:
+ - source: puppet/
+ destination: /etc/puppet/codedeploy
+ - source: target/hello.war
+ destination: /var/lib/tomcat6/webapps
+hooks:
+ BeforeInstall:
+ - location: deploy_hooks/install-puppet.sh
+ timeout: 1800
+ runas: root
+ ApplicationStart:
+ - location: deploy_hooks/puppet-apply.sh
+ runas: root
+ ValidateService:
+ - location: deploy_hooks/verify_service.sh
+ runas: root
+```
+
+This AppSpec tells AWS CodeDeploy that we want all of our Puppet manifests to be installed into
+`/etc/puppet/codedeploy`, the war file for our app should be installed into the default tomcat6
+webapps directory, and that it should run the scripts in `deploy_hooks/` on the appropriate
+deployment events. Specifically: one to ensure that Puppet is properly installed and one to run
+`puppet apply`.
+
+Before we run anything though, our `BeforeInstall` checks that Puppet is installed and attempts to
+install it. It also runs `puppet module install` for the tomcat module and its dependencies.
+
+```bash
+#!/bin/bash
+
+# Check to see that Puppet itself is installed
+yum list installed puppet &> /dev/null
+if [ $? != 0 ]; then
+ yum -y install puppet
+fi
+
+# Create the base directory for the system-wide Puppet modules
+mkdir -p /etc/puppet/modules
+
+puppet="/usr/bin/puppet"
+
+# Check for each of the modules we need. If they're not installed, install them.
+for module in puppetlabs/stdlib puppetlabs/java puppetlabs/tomcat stahnma/epel; do
+ $puppet module list | grep -q $(basename $module)
+ if [ $? != 0 ]; then
+ $puppet module install $module
+ fi
+done
+
+exit 0
+```
+
+Then, once our files are installed into the correct locations, our `ApplicationStart` lifecycle hook
+actually runs `puppet apply`:
+
+```bash
+#!/bin/bash
+
+BASE_DIR="/etc/puppet/"
+
+/usr/bin/puppet apply --modulepath=${BASE_DIR}/modules ${BASE_DIR}/codedeploy/manifests/hello_world.pp
+```
+
+Finally, the `ValidateService` hook checks to see whether or not our app is responding as expected:
+
+```bash
+#!/bin/bash
+
+result=$(curl -s http://localhost:8080/hello/)
+
+if [[ "$result" =~ "Hello World" ]]; then
+ exit 0
+else
+ exit 1
+fi
+```
+
+Our Puppet manifest in this case is simply to set a couple of default tomcat options and start a
+tomcat instance:
+
+```
+class { 'tomcat': }
+
+class { 'epel': }->
+tomcat::instance{ 'default':
+ install_from_source => false,
+ package_name => 'tomcat6',
+ package_ensure => 'present',
+}->
+tomcat::service { 'default':
+ use_jsvc => false,
+ use_init => true,
+ service_name => 'tomcat6',
+}
+```
+
+The java app does nothing more than respond with 'Hello World' at the root of the app. You can take
+a closer look by downloading the source at the link above.
+
+Now that we've set up our bundle, we're ready to get things set up in AWS CodeDeploy.
+
+Set Up the AWS CodeDeploy Application
+-------------------------------------
+
+Even though we might have an application and deployment group already set up on this
+instance, it's a good practice to create new ones. First, we create the new application:
+
+```sh
+aws deploy create-application --application-name puppet-example
+```
+
+Then, using the ***CodeDeployTrustRoleArn*** that was assigned to our AWS CloudFormation stack, we create a
+new deployment group for the puppet-example application:
+
+```sh
+aws deploy create-deployment-group \
+ --application-name puppet-example \
+ --deployment-group-name puppet_DeploymentGroup \
+ --deployment-config-name CodeDeployDefault.AllAtOnce \
+ --ec2-tag-filters Key=Name,Value=CodeDeployDeployment,Type=KEY_AND_VALUE \
+ --service-role-arn CodeDeployTrustRoleArn
+```
+
+In this deployment group, we've set the default deployment configuration to
+`CodeDeployDefault.AllAtOnce`. This will deploy to all of our instances at the same time. In a real
+production app, you'd probably want to set it to something more conservative like
+`CodeDeployDefault.OneAtATime` or a custom configuration.
+
+Push and Deploy the Application
+-------------------------------
+
+At this point, we have a running Amazon EC2 instance that has the AWS CodeDeploy agent installed, an
+application bundle containing our Puppet manifests, and an AWS CodeDeploy application ready to accept
+deployments.
+
+We next need to upload our bundle and register it as a new revision in AWS CodeDeploy. The `aws deploy push` command in
+the AWS CLI will take care of that for us (make sure you replace ***bucket-name*** with the name of
+an Amazon S3 bucket you have set up for AWS CodeDeploy):
+
+```sh
+aws deploy push \
+ --application-name puppet-example \
+ --s3-location s3://bucket-name/puppet-example.zip \
+ --ignore-hidden-files true
+```
+
+And now we're ready for a deployment:
+
+```sh
+aws deploy create-deployment \
+ --application-name puppet-example \
+ --deployment-config-name CodeDeployDefault.AllAtOnce \
+ --deployment-group-name puppet_DeploymentGroup \
+ --revision bucket=bucket-name,key=puppet-example.zip,bundleType=zip
+```
+
+Note here that we specify the deployment configuration again. This is so that we can override any
+default that we might have set on the deployment group.
+
+Once the deployment finishes (which you can check with either the AWS CodeDeploy console, or the `aws deploy
+get-deployment` CLI command), you should be able to log into the instance and verify that the app is
+up and running.
+
+Wrapping up
+-----------
+
+Now you're ready to use the power of AWS CodeDeploy to orchestrate your fleet of Puppet nodes. In our
+next post, we'll demonstrate how you can use a Puppet module to install the AWS CodeDeploy agent, thus
+allowing your infrastructure to continue to be managed by Puppet while your application deployments
+are managed via AWS CodeDeploy.
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/application_vars.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/application_vars.sh
new file mode 100644
index 00000000..ba84062a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/application_vars.sh
@@ -0,0 +1,6 @@
+APPLICATION_NAME="PuppetMasterless"
+DEPLOY_GROUP="PuppetMasterless"
+BUCKET=""
+BUNDLE_PATH="puppet-masterless.tar"
+EC2_TAG_KEY='Puppet'
+EC2_TAG_VALUE='Masterless'
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/appspec.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/appspec.yml
new file mode 100644
index 00000000..7d25ba01
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/appspec.yml
@@ -0,0 +1,17 @@
+version: 0.0
+os: linux
+files:
+ - source: puppet/
+ destination: /etc/puppet/codedeploy
+ - source: target/hello.war
+ destination: /var/lib/tomcat6/webapps
+hooks:
+ BeforeInstall:
+ - location: deploy_hooks/install-puppet.sh
+ runas: root
+ ApplicationStart:
+ - location: deploy_hooks/puppet-apply.sh
+ runas: root
+ ValidateService:
+ - location: deploy_hooks/verify_service.sh
+ runas: root
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/install-puppet.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/install-puppet.sh
new file mode 100755
index 00000000..5b5132ff
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/install-puppet.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# Check to see that puppet itself is installed
+yum list installed puppet &> /dev/null
+if [ $? != 0 ]; then
+ yum -y install puppet
+fi
+
+# Create the base directory for the system-wide puppet modules
+mkdir -p /etc/puppet/modules
+
+puppet="/usr/bin/puppet"
+
+# Check for each of the modules we need. If they're not installed, install them.
+for module in puppetlabs/stdlib puppetlabs/java puppetlabs/tomcat stahnma/epel; do
+ $puppet module list | grep -q $(basename $module)
+ if [ $? != 0 ]; then
+ $puppet module install $module
+ fi
+done
+
+exit 0
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/puppet-apply.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/puppet-apply.sh
new file mode 100755
index 00000000..fb2115b1
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/puppet-apply.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+BASE_DIR="/etc/puppet/"
+
+/usr/bin/puppet apply --modulepath=${BASE_DIR}/modules ${BASE_DIR}/codedeploy/manifests/hello_world.pp
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/verify_service.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/verify_service.sh
new file mode 100755
index 00000000..138138cf
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/deploy_hooks/verify_service.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+result=$(curl -s http://localhost:8080/hello/)
+
+if [[ "$result" =~ "Hello World" ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/pom.xml b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/pom.xml
new file mode 100644
index 00000000..e65844c2
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+ com.amazonaws.sample
+ hello
+ war
+ 1.0-SNAPSHOT
+ hello Maven Webapp
+ http://maven.apache.org
+
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.0.1
+ provided
+
+
+
+
+ hello
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/puppet/manifests/hello_world.pp b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/puppet/manifests/hello_world.pp
new file mode 100644
index 00000000..b8770e45
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/puppet/manifests/hello_world.pp
@@ -0,0 +1,13 @@
+class { 'tomcat': }
+
+class { 'epel': }->
+tomcat::instance{ 'default':
+ install_from_source => false,
+ package_name => 'tomcat6',
+ package_ensure => 'present',
+}->
+tomcat::service { 'default':
+ use_jsvc => false,
+ use_init => true,
+ service_name => 'tomcat6',
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/java/com/amazonaws/sample/HelloServlet.java b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/java/com/amazonaws/sample/HelloServlet.java
new file mode 100644
index 00000000..ba2a298a
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/java/com/amazonaws/sample/HelloServlet.java
@@ -0,0 +1,20 @@
+package com.amazonaws.sample;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class HelloServlet extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ PrintWriter writer = response.getWriter();
+ writer.print("Hello World
");
+ }
+}
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/webapp/WEB-INF/web.xml b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..d105e7aa
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/puppet/masterless/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,19 @@
+
+
+
+ Hello World Web Application
+
+
+ HelloServlet
+ com.amazonaws.sample.HelloServlet
+
+
+
+ HelloServlet
+ /
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/README.md b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/README.md
new file mode 100644
index 00000000..676cc8cd
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/README.md
@@ -0,0 +1,12 @@
+SaltStack and AWS CodeDeploy
+----------------------------
+
+[Salt](http://www.saltstack.com) is a fast, scalable and flexible systems management software for
+data center automation, cloud orchestration, server provisioning, configuration management and more.
+The two sample templates AWS provides offer examples for how you can integrate existing Salt
+infrastructure with AWS CodeDeploy. On the one hand, you can use the AWS CodeDeploy module to
+install and run the CodeDeploy host agent on your minions. On the other hand, you can use AWS
+CodeDeploy via a couple of simple deployment hooks to orchestrate running your Salt States. Either
+way, you get to take advantage of the power of both Salt and AWS CodeDeploy.
+
+[Learn more >](https://github.com/awslabs/aws-codedeploy-samples)
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/TODO.txt b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/TODO.txt
new file mode 100644
index 00000000..2f141c18
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/TODO.txt
@@ -0,0 +1 @@
+* write scripts for running salt modules in masterless mode via CodeDeploy
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/application_vars.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/application_vars.sh
new file mode 100644
index 00000000..07354dad
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/application_vars.sh
@@ -0,0 +1,8 @@
+APPLICATION_NAME="SaltMasterless"
+DEPLOY_GROUP="Salt"
+BUCKET=""
+BUNDLE_PATH="salt-masterless.tar"
+EC2_TAG_KEY='Salt'
+EC2_TAG_VALUE='Masterless'
+
+DESTINATION_PATH="/etc/salt/codedeploy"
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/appspec.yml b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/appspec.yml
new file mode 100644
index 00000000..7dc99d68
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/appspec.yml
@@ -0,0 +1,17 @@
+version: 0.0
+os: linux
+files:
+ - source: salt/
+ destination: /etc/salt/codedeploy/
+ - source: index.html
+ destination: /var/www/html/salt/
+hooks:
+ BeforeInstall:
+ - location: deploy_hooks/before_install.sh
+ runas: root
+ ApplicationStart:
+ - location: deploy_hooks/application_start.sh
+ runas: root
+ ValidateService:
+ - location: deploy_hooks/verify_service.sh
+ runas: root
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/application_start.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/application_start.sh
new file mode 100755
index 00000000..17394ce5
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/application_start.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Deploy hooks are run via absolute path, so taking dirname of this script will give us the path to
+# our deploy_hooks directory.
+. $(dirname $0)/../application_vars.sh
+
+salt-call --local --file-root=$DESTINATION_PATH state.highstate
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/before_install.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/before_install.sh
new file mode 100755
index 00000000..e1c11f76
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/before_install.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Check for salt, and attempt to install if not
+
+yum list installed | grep salt-minion &> /dev/null
+if [ $? != 0 ]; then
+ yum install -y --enablerepo=epel salt-minion
+fi
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/verify_service.sh b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/verify_service.sh
new file mode 100755
index 00000000..8282c010
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/deploy_hooks/verify_service.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Deploy hooks are run via absolute path, so taking dirname of this script will give us the path to
+# our deploy_hooks directory.
+. $(dirname $0)/../application_vars.sh
+
+result=$(curl -s http://localhost/salt/index.html)
+
+if [[ "$result" =~ "Hello World" ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/index.html b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/index.html
new file mode 100644
index 00000000..04a5e97f
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/index.html
@@ -0,0 +1,9 @@
+
+
+ AWS CodeDeploy with Salt Masterless
+
+
+ Hello World
+
+
+
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/top.sls b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/top.sls
new file mode 100644
index 00000000..53f2952d
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/top.sls
@@ -0,0 +1,3 @@
+base:
+ '*':
+ - webserver
diff --git a/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/webserver.sls b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/webserver.sls
new file mode 100644
index 00000000..3585a425
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/conf-mgmt/salt/local-only/salt/webserver.sls
@@ -0,0 +1,3 @@
+httpd:
+ pkg:
+ - installed
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/README.md b/sample/bin/aws-codedeploy-samples/load-balancing/elb/README.md
new file mode 100644
index 00000000..69938c4e
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/README.md
@@ -0,0 +1,52 @@
+# ELB and ASG lifecycle event scripts
+
+Often when running a web service, you'll have your instances behind a load balancer. But when
+deploying new code to these instances, you don't want the load balancer to continue sending customer
+traffic to an instance while the deployment is in progress. Lifecycle event scripts give you the
+ability to integrate your AWS CodeDeploy deployments with instances that are behind an Elastic Load
+Balancer or in an Auto Scaling group. Simply set the name (or names) of the Elastic Load Balancer
+your instances are a part of, set the scripts in the appropriate lifecycle events, and the scripts
+will take care of deregistering the instance, waiting for connection draining, and re-registering
+after the deployment finishes.
+
+## Requirements
+
+The register and deregister scripts have a couple of dependencies in order to properly interact with
+Elastic Load Balancing and AutoScaling:
+
+1. The [AWS CLI](http://aws.amazon.com/cli/). In order to take advantage of
+AutoScaling's Standby feature, the CLI must be at least version 1.3.25. If you
+have Python and PIP already installed, the CLI can simply be installed with `pip
+install awscli`. Otherwise, follow the [installation instructions](http://docs.aws.amazon.com/cli/latest/userguide/installing.html)
+in the CLI's user guide.
+1. An instance profile with a policy that allows, at minimum, the following actions:
+
+```
+ elasticloadbalancing:Describe*
+ elasticloadbalancing:DeregisterInstancesFromLoadBalancer
+ elasticloadbalancing:RegisterInstancesWithLoadBalancer
+ autoscaling:Describe*
+ autoscaling:EnterStandby
+ autoscaling:ExitStandby
+ autoscaling:UpdateAutoScalingGroup
+```
+
+Note: the AWS CodeDeploy Agent requires that an instance profile be attached to all instances that
+are to participate in AWS CodeDeploy deployments. For more information on creating an instance
+profile for AWS CodeDeploy, see the [Create an IAM Instance Profile for Your Amazon EC2 Instances]()
+topic in the documentation.
+1. All instances are assumed to already have the AWS CodeDeploy Agent installed.
+
+## Installing the Scripts
+
+To use these scripts in your own application:
+
+1. Install the AWS CLI on all your instances.
+1. Update the policies on the EC2 instance profile to allow the above actions.
+1. Copy the `.sh` files in this directory into your application source.
+1. Edit your application's `appspec.yml` to run `deregister_from_elb.sh` on the ApplicationStop event,
+and `register_with_elb.sh` on the ApplicationStart event.
+1. Edit `common_functions.sh` to set `ELB_LIST` to contain the name(s) of the Elastic Load
+Balancer(s) your deployment group is a part of. Make sure the entries in ELB_LIST are separated by space.
+1. Deploy!
+
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/appspec.yml b/sample/bin/aws-codedeploy-samples/load-balancing/elb/appspec.yml
new file mode 100644
index 00000000..6d6c58aa
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/appspec.yml
@@ -0,0 +1,12 @@
+version: 0.0
+os: linux
+files:
+ - source: /
+ destination: /tmp/elb-test
+hooks:
+ ApplicationStop:
+ - location: deregister_from_elb.sh
+ - location: stop_httpd.sh
+ ApplicationStart:
+ - location: start_httpd.sh
+ - location: register_with_elb.sh
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/common_functions.sh b/sample/bin/aws-codedeploy-samples/load-balancing/elb/common_functions.sh
new file mode 100644
index 00000000..6442d8a9
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/common_functions.sh
@@ -0,0 +1,499 @@
+#!/bin/bash
+#
+# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+# ELB_LIST defines which Elastic Load Balancers this instance should be part of.
+# The elements in ELB_LIST should be seperated by space.
+ELB_LIST=""
+
+# Under normal circumstances, you shouldn't need to change anything below this line.
+# -----------------------------------------------------------------------------
+
+export PATH="$PATH:/usr/bin:/usr/local/bin"
+
+# If true, all messages will be printed. If false, only fatal errors are printed.
+DEBUG=true
+
+# Number of times to check for a resouce to be in the desired state.
+WAITER_ATTEMPTS=60
+
+# Number of seconds to wait between attempts for resource to be in a state.
+WAITER_INTERVAL=1
+
+# AutoScaling Standby features at minimum require this version to work.
+MIN_CLI_VERSION='1.3.25'
+
+# Usage: get_instance_region
+#
+# Writes to STDOUT the AWS region as known by the local instance.
+get_instance_region() {
+ if [ -z "$AWS_REGION" ]; then
+ AWS_REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document \
+ | grep -i region \
+ | awk -F\" '{print $4}')
+ fi
+
+ echo $AWS_REGION
+}
+
+AWS_CLI="aws --region $(get_instance_region)"
+
+# Usage: autoscaling_group_name
+#
+# Prints to STDOUT the name of the AutoScaling group this instance is a part of and returns 0. If
+# it is not part of any groups, then it prints nothing. On error calling autoscaling, returns
+# non-zero.
+autoscaling_group_name() {
+ local instance_id=$1
+
+ # This operates under the assumption that instances are only ever part of a single ASG.
+ local autoscaling_name=$($AWS_CLI autoscaling describe-auto-scaling-instances \
+ --instance-ids $instance_id \
+ --output text \
+ --query AutoScalingInstances[0].AutoScalingGroupName)
+
+ if [ $? != 0 ]; then
+ return 1
+ elif [ "$autoscaling_name" == "None" ]; then
+ echo ""
+ else
+ echo $autoscaling_name
+ fi
+
+ return 0
+}
+
+# Usage: autoscaling_enter_standby
+#
+# Move into the Standby state in AutoScaling group . Doing so will
+# pull it out of any Elastic Load Balancer that might be in front of the group.
+#
+# Returns 0 if the instance was successfully moved to standby. Non-zero otherwise.
+autoscaling_enter_standby() {
+ local instance_id=$1
+ local asg_name=$2
+
+ msg "Checking if this instance has already been moved in the Standby state"
+ local instance_state=$(get_instance_state_asg $instance_id)
+ if [ $? != 0 ]; then
+ msg "Unable to get this instance's lifecycle state."
+ return 1
+ fi
+
+ if [ "$instance_state" == "Standby" ]; then
+ msg "Instance is already in Standby; nothing to do."
+ return 0
+ fi
+
+ if [ "$instance_state" == "Pending:Wait" ]; then
+ msg "Instance is Pending:Wait; nothing to do."
+ return 0
+ fi
+
+ msg "Checking to see if ASG $asg_name will let us decrease desired capacity"
+ local min_desired=$($AWS_CLI autoscaling describe-auto-scaling-groups \
+ --auto-scaling-group-name $asg_name \
+ --query 'AutoScalingGroups[0].[MinSize, DesiredCapacity]' \
+ --output text)
+
+ local min_cap=$(echo $min_desired | awk '{print $1}')
+ local desired_cap=$(echo $min_desired | awk '{print $2}')
+
+ if [ -z "$min_cap" -o -z "$desired_cap" ]; then
+ msg "Unable to determine minimum and desired capacity for ASG $asg_name."
+ msg "Attempting to put this instance into standby regardless."
+ elif [ $min_cap == $desired_cap -a $min_cap -gt 0 ]; then
+ local new_min=$(($min_cap - 1))
+ msg "Decrementing ASG $asg_name's minimum size to $new_min"
+ msg $($AWS_CLI autoscaling update-auto-scaling-group \
+ --auto-scaling-group-name $asg_name \
+ --min-size $new_min)
+ if [ $? != 0 ]; then
+ msg "Failed to reduce ASG $asg_name's minimum size to $new_min. Cannot put this instance into Standby."
+ return 1
+ else
+ msg "ASG $asg_name's minimum size has been decremented, creating flag file /tmp/asgmindecremented"
+ # Create a "flag" file to denote that the ASG min has been decremented
+ touch /tmp/asgmindecremented
+ fi
+ fi
+
+ msg "Putting instance $instance_id into Standby"
+ $AWS_CLI autoscaling enter-standby \
+ --instance-ids $instance_id \
+ --auto-scaling-group-name $asg_name \
+ --should-decrement-desired-capacity
+ if [ $? != 0 ]; then
+ msg "Failed to put instance $instance_id into Standby for ASG $asg_name."
+ return 1
+ fi
+
+ msg "Waiting for move to Standby to finish"
+ wait_for_state "autoscaling" $instance_id "Standby"
+ if [ $? != 0 ]; then
+ local wait_timeout=$(($WAITER_INTERVAL * $WAITER_ATTEMPTS))
+ msg "Instance $instance_id did not make it to standby after $wait_timeout seconds"
+ return 1
+ fi
+
+ return 0
+}
+
+# Usage: autoscaling_exit_standby
+#
+# Attempts to move instance out of Standby and into InService. Returns 0 if
+# successful.
+autoscaling_exit_standby() {
+ local instance_id=$1
+ local asg_name=$2
+
+ msg "Checking if this instance has already been moved out of Standby state"
+ local instance_state=$(get_instance_state_asg $instance_id)
+ if [ $? != 0 ]; then
+ msg "Unable to get this instance's lifecycle state."
+ return 1
+ fi
+
+ if [ "$instance_state" == "InService" ]; then
+ msg "Instance is already InService; nothing to do."
+ return 0
+ fi
+
+ if [ "$instance_state" == "Pending:Wait" ]; then
+ msg "Instance is Pending:Wait; nothing to do."
+ return 0
+ fi
+
+ msg "Moving instance $instance_id out of Standby"
+ $AWS_CLI autoscaling exit-standby \
+ --instance-ids $instance_id \
+ --auto-scaling-group-name $asg_name
+ if [ $? != 0 ]; then
+ msg "Failed to put instance $instance_id back into InService for ASG $asg_name."
+ return 1
+ fi
+
+ msg "Waiting for exit-standby to finish"
+ wait_for_state "autoscaling" $instance_id "InService"
+ if [ $? != 0 ]; then
+ local wait_timeout=$(($WAITER_INTERVAL * $WAITER_ATTEMPTS))
+ msg "Instance $instance_id did not make it to InService after $wait_timeout seconds"
+ return 1
+ fi
+
+ if [ -a /tmp/asgmindecremented ]; then
+ local min_desired=$($AWS_CLI autoscaling describe-auto-scaling-groups \
+ --auto-scaling-group-name $asg_name \
+ --query 'AutoScalingGroups[0].[MinSize, DesiredCapacity]' \
+ --output text)
+
+ local min_cap=$(echo $min_desired | awk '{print $1}')
+
+ local new_min=$(($min_cap + 1))
+ msg "Incrementing ASG $asg_name's minimum size to $new_min"
+ msg $($AWS_CLI autoscaling update-auto-scaling-group \
+ --auto-scaling-group-name $asg_name \
+ --min-size $new_min)
+ if [ $? != 0 ]; then
+ msg "Failed to increase ASG $asg_name's minimum size to $new_min."
+ return 1
+ else
+ msg "Successfully incremented ASG $asg_name's minimum size"
+ msg "Removing /tmp/asgmindecremented flag file"
+ rm -f /tmp/asgmindecremented
+ fi
+ else
+ msg "Auto scaling group was not decremented previously, not incrementing min value"
+ fi
+
+ return 0
+}
+
+# Usage: get_instance_state_asg
+#
+# Gets the state of the given as known by the AutoScaling group it's a part of.
+# Health is printed to STDOUT and the function returns 0. Otherwise, no output and return is
+# non-zero.
+get_instance_state_asg() {
+ local instance_id=$1
+
+ local state=$($AWS_CLI autoscaling describe-auto-scaling-instances \
+ --instance-ids $instance_id \
+ --query "AutoScalingInstances[?InstanceId == \`$instance_id\`].LifecycleState | [0]" \
+ --output text)
+ if [ $? != 0 ]; then
+ return 1
+ else
+ echo $state
+ return 0
+ fi
+}
+
+reset_waiter_timeout() {
+ local elb=$1
+
+ local health_check_values=$($AWS_CLI elb describe-load-balancers \
+ --load-balancer-name $elb \
+ --query 'LoadBalancerDescriptions[0].HealthCheck.[HealthyThreshold, Interval]' \
+ --output text)
+
+ WAITER_ATTEMPTS=$(echo $health_check_values | awk '{print $1}')
+ WAITER_INTERVAL=$(echo $health_check_values | awk '{print $2}')
+}
+
+# Usage: wait_for_state [ELB name]
+#
+# Waits for the state of to be in as seen by . Returns 0 if
+# it successfully made it to that state; non-zero if not. By default, checks $WAITER_ATTEMPTS
+# times, every $WAITER_INTERVAL seconds. If giving an [ELB name] to check under, these are reset
+# to that ELB's HealthThreshold and Interval values.
+wait_for_state() {
+ local service=$1
+ local instance_id=$2
+ local state_name=$3
+ local elb=$4
+
+ local instance_state_cmd
+ if [ "$service" == "elb" ]; then
+ instance_state_cmd="get_instance_health_elb $instance_id $elb"
+ reset_waiter_timeout $elb
+ elif [ "$service" == "autoscaling" ]; then
+ instance_state_cmd="get_instance_state_asg $instance_id"
+ else
+ msg "Cannot wait for instance state; unknown service type, '$service'"
+ return 1
+ fi
+
+ msg "Checking $WAITER_ATTEMPTS times, every $WAITER_INTERVAL seconds, for instance $instance_id to be in state $state_name"
+
+ local instance_state=$($instance_state_cmd)
+ local count=1
+
+ msg "Instance is currently in state: $instance_state"
+ while [ "$instance_state" != "$state_name" ]; do
+ if [ $count -ge $WAITER_ATTEMPTS ]; then
+ local timeout=$(($WAITER_ATTEMPTS * $WAITER_INTERVAL))
+ msg "Instance failed to reach state, $state_name within $timeout seconds"
+ return 1
+ fi
+
+ sleep $WAITER_INTERVAL
+
+ instance_state=$($instance_state_cmd)
+ count=$(($count + 1))
+ msg "Instance is currently in state: $instance_state"
+ done
+
+ return 0
+}
+
+# Usage: get_instance_health_elb
+#
+# Gets the health of the given as known by . If it's a valid health
+# status (one of InService|OutOfService|Unknown), then the health is printed to STDOUT and the
+# function returns 0. Otherwise, no output and return is non-zero.
+get_instance_health_elb() {
+ local instance_id=$1
+ local elb_name=$2
+
+ msg "Checking status of instance '$instance_id' in load balancer '$elb_name'"
+
+ # If describe-instance-health for this instance returns an error, then it's not part of
+ # this ELB. But, if the call was successful let's still double check that the status is
+ # valid.
+ local instance_status=$($AWS_CLI elb describe-instance-health \
+ --load-balancer-name $elb_name \
+ --instances $instance_id \
+ --query 'InstanceStates[].State' \
+ --output text 2>/dev/null)
+
+ if [ $? == 0 ]; then
+ case "$instance_status" in
+ InService|OutOfService|Unknown)
+ echo -n $instance_status
+ return 0
+ ;;
+ *)
+ msg "Instance '$instance_id' not part of ELB '$elb_name'"
+ return 1
+ esac
+ fi
+}
+
+# Usage: validate_elb
+#
+# Validates that the Elastic Load Balancer with name exists, is describable, and
+# contains as one of its instances.
+#
+# If any of these checks are false, the function returns non-zero.
+validate_elb() {
+ local instance_id=$1
+ local elb_name=$2
+
+ # Get the list of active instances for this LB.
+ local elb_instances=$($AWS_CLI elb describe-load-balancers \
+ --load-balancer-name $elb_name \
+ --query 'LoadBalancerDescriptions[*].Instances[*].InstanceId' \
+ --output text)
+ if [ $? != 0 ]; then
+ msg "Couldn't describe ELB instance named '$elb_name'"
+ return 1
+ fi
+
+ msg "Checking health of '$instance_id' as known by ELB '$elb_name'"
+ local instance_health=$(get_instance_health_elb $instance_id $elb_name)
+ if [ $? != 0 ]; then
+ return 1
+ fi
+
+ return 0
+}
+
+# Usage: get_elb_list
+#
+# Finds all the ELBs that this instance is registered to. After execution, the variable
+# "ELB_LIST" will contain the list of load balancers for the given instance.
+#
+# If the given instance ID isn't found registered to any ELBs, the function returns non-zero
+get_elb_list() {
+ local instance_id=$1
+
+ local asg_name=$($AWS_CLI autoscaling describe-auto-scaling-instances \
+ --instance-ids $instance_id \
+ --query AutoScalingInstances[*].AutoScalingGroupName \
+ --output text | sed -e $'s/\t/ /g')
+ local elb_list=""
+
+ if [ -z "$asg_name" ]; then
+ msg "Instance is not part of an ASG. Looking up from ELB."
+ local all_balancers=$($AWS_CLI elb describe-load-balancers \
+ --query LoadBalancerDescriptions[*].LoadBalancerName \
+ --output text | sed -e $'s/\t/ /g')
+ for elb in $all_balancers; do
+ local instance_health
+ instance_health=$(get_instance_health_elb $instance_id $elb)
+ if [ $? == 0 ]; then
+ elb_list="$elb_list $elb"
+ fi
+ done
+ else
+ elb_list=$($AWS_CLI autoscaling describe-auto-scaling-groups \
+ --auto-scaling-group-names $asg_name \
+ --query AutoScalingGroups[*].LoadBalancerNames \
+ --output text | sed -e $'s/\t/ /g')
+ fi
+
+ if [ -z "$elb_list" ]; then
+ return 1
+ else
+ msg "Got load balancer list of: $elb_list"
+ ELB_LIST=$elb_list
+ return 0
+ fi
+}
+
+# Usage: deregister_instance
+#
+# Deregisters from .
+deregister_instance() {
+ local instance_id=$1
+ local elb_name=$2
+
+ $AWS_CLI elb deregister-instances-from-load-balancer \
+ --load-balancer-name $elb_name \
+ --instances $instance_id 1> /dev/null
+
+ return $?
+}
+
+# Usage: register_instance
+#
+# Registers to .
+register_instance() {
+ local instance_id=$1
+ local elb_name=$2
+
+ $AWS_CLI elb register-instances-with-load-balancer \
+ --load-balancer-name $elb_name \
+ --instances $instance_id 1> /dev/null
+
+ return $?
+}
+
+# Usage: check_cli_version [version-to-check] [desired version]
+#
+# Without any arguments, checks that the installed version of the AWS CLI is at least at version
+# $MIN_CLI_VERSION. Returns non-zero if the version is not high enough.
+check_cli_version() {
+ if [ -z $1 ]; then
+ version=$($AWS_CLI --version 2>&1 | cut -f1 -d' ' | cut -f2 -d/)
+ else
+ version=$1
+ fi
+
+ if [ -z "$2" ]; then
+ min_version=$MIN_CLI_VERSION
+ else
+ min_version=$2
+ fi
+
+ x=$(echo $version | cut -f1 -d.)
+ y=$(echo $version | cut -f2 -d.)
+ z=$(echo $version | cut -f3 -d.)
+
+ min_x=$(echo $min_version | cut -f1 -d.)
+ min_y=$(echo $min_version | cut -f2 -d.)
+ min_z=$(echo $min_version | cut -f3 -d.)
+
+ msg "Checking minimum required CLI version (${min_version}) against installed version ($version)"
+
+ if [ $x -lt $min_x ]; then
+ return 1
+ elif [ $y -lt $min_y ]; then
+ return 1
+ elif [ $y -gt $min_y ]; then
+ return 0
+ elif [ $z -ge $min_z ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Usage: msg
+#
+# Writes to STDERR only if $DEBUG is true, otherwise has no effect.
+msg() {
+ local message=$1
+ $DEBUG && echo $message 1>&2
+}
+
+# Usage: error_exit
+#
+# Writes to STDERR as a "fatal" and immediately exits the currently running script.
+error_exit() {
+ local message=$1
+
+ echo "[FATAL] $message" 1>&2
+ exit 1
+}
+
+# Usage: get_instance_id
+#
+# Writes to STDOUT the EC2 instance ID for the local instance. Returns non-zero if the local
+# instance metadata URL is inaccessible.
+get_instance_id() {
+ curl -s http://169.254.169.254/latest/meta-data/instance-id
+ return $?
+}
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/deregister_from_elb.sh b/sample/bin/aws-codedeploy-samples/load-balancing/elb/deregister_from_elb.sh
new file mode 100755
index 00000000..54063156
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/deregister_from_elb.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+. $(dirname $0)/common_functions.sh
+
+msg "Running AWS CLI with region: $(get_instance_region)"
+
+# get this instance's ID
+INSTANCE_ID=$(get_instance_id)
+if [ $? != 0 -o -z "$INSTANCE_ID" ]; then
+ error_exit "Unable to get this instance's ID; cannot continue."
+fi
+
+# Get current time
+msg "Started $(basename $0) at $(/bin/date "+%F %T")"
+start_sec=$(/bin/date +%s.%N)
+
+msg "Checking if instance $INSTANCE_ID is part of an AutoScaling group"
+asg=$(autoscaling_group_name $INSTANCE_ID)
+if [ $? == 0 -a -n "$asg" ]; then
+ msg "Found AutoScaling group for instance $INSTANCE_ID: $asg"
+
+ msg "Checking that installed CLI version is at least at version required for AutoScaling Standby"
+ check_cli_version
+ if [ $? != 0 ]; then
+ error_exit "CLI must be at least version ${MIN_CLI_X}.${MIN_CLI_Y}.${MIN_CLI_Z} to work with AutoScaling Standby"
+ fi
+
+ msg "Attempting to put instance into Standby"
+ autoscaling_enter_standby $INSTANCE_ID $asg
+ if [ $? != 0 ]; then
+ error_exit "Failed to move instance into standby"
+ else
+ msg "Instance is in standby"
+ exit 0
+ fi
+fi
+
+msg "Instance is not part of an ASG, continuing..."
+
+msg "Checking that user set at least one load balancer"
+if test -z "$ELB_LIST"; then
+ error_exit "Must have at least one load balancer to deregister from"
+fi
+
+# Loop through all LBs the user set, and attempt to deregister this instance from them.
+for elb in $ELB_LIST; do
+ msg "Checking validity of load balancer named '$elb'"
+ validate_elb $INSTANCE_ID $elb
+ if [ $? != 0 ]; then
+ msg "Error validating $elb; cannot continue with this LB"
+ continue
+ fi
+
+ msg "Deregistering $INSTANCE_ID from $elb"
+ deregister_instance $INSTANCE_ID $elb
+
+ if [ $? != 0 ]; then
+ error_exit "Failed to deregister instance $INSTANCE_ID from ELB $elb"
+ fi
+done
+
+# Wait for all Deregistrations to finish
+msg "Waiting for instance to de-register from its load balancers"
+for elb in $ELB_LIST; do
+ wait_for_state "elb" $INSTANCE_ID "OutOfService" $elb
+ if [ $? != 0 ]; then
+ error_exit "Failed waiting for $INSTANCE_ID to leave $elb"
+ fi
+done
+
+msg "Finished $(basename $0) at $(/bin/date "+%F %T")"
+
+end_sec=$(/bin/date +%s.%N)
+elapsed_seconds=$(echo "$end_sec - $start_sec" | /usr/bin/bc)
+
+msg "Elapsed time: $elapsed_seconds"
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/register_with_elb.sh b/sample/bin/aws-codedeploy-samples/load-balancing/elb/register_with_elb.sh
new file mode 100755
index 00000000..cfca1556
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/register_with_elb.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+. $(dirname $0)/common_functions.sh
+
+msg "Running AWS CLI with region: $(get_instance_region)"
+
+# get this instance's ID
+INSTANCE_ID=$(get_instance_id)
+if [ $? != 0 -o -z "$INSTANCE_ID" ]; then
+ error_exit "Unable to get this instance's ID; cannot continue."
+fi
+
+# Get current time
+msg "Started $(basename $0) at $(/bin/date "+%F %T")"
+start_sec=$(/bin/date +%s.%N)
+
+msg "Checking if instance $INSTANCE_ID is part of an AutoScaling group"
+asg=$(autoscaling_group_name $INSTANCE_ID)
+if [ $? == 0 -a -n "$asg" ]; then
+ msg "Found AutoScaling group for instance $INSTANCE_ID: $asg"
+
+ msg "Checking that installed CLI version is at least at version required for AutoScaling Standby"
+ check_cli_version
+ if [ $? != 0 ]; then
+ error_exit "CLI must be at least version ${MIN_CLI_X}.${MIN_CLI_Y}.${MIN_CLI_Z} to work with AutoScaling Standby"
+ fi
+
+ msg "Attempting to move instance out of Standby"
+ autoscaling_exit_standby $INSTANCE_ID $asg
+ if [ $? != 0 ]; then
+ error_exit "Failed to move instance out of standby"
+ else
+ msg "Instance is no longer in Standby"
+ exit 0
+ fi
+fi
+
+msg "Instance is not part of an ASG, continuing..."
+
+msg "Checking that user set at least one load balancer"
+if test -z "$ELB_LIST"; then
+ error_exit "Must have at least one load balancer to register to"
+fi
+
+# Loop through all LBs the user set, and attempt to register this instance to them.
+for elb in $ELB_LIST; do
+ msg "Checking validity of load balancer named '$elb'"
+ validate_elb $INSTANCE_ID $elb
+ if [ $? != 0 ]; then
+ msg "Error validating $elb; cannot continue with this LB"
+ continue
+ fi
+
+ msg "Registering $INSTANCE_ID to $elb"
+ register_instance $INSTANCE_ID $elb
+
+ if [ $? != 0 ]; then
+ error_exit "Failed to register instance $INSTANCE_ID from ELB $elb"
+ fi
+done
+
+# Wait for all Registrations to finish
+msg "Waiting for instance to register to its load balancers"
+for elb in $ELB_LIST; do
+ wait_for_state "elb" $INSTANCE_ID "InService" $elb
+ if [ $? != 0 ]; then
+ error_exit "Failed waiting for $INSTANCE_ID to return to $elb"
+ fi
+done
+
+msg "Finished $(basename $0) at $(/bin/date "+%F %T")"
+
+end_sec=$(/bin/date +%s.%N)
+elapsed_seconds=$(echo "$end_sec - $start_sec" | /usr/bin/bc)
+
+msg "Elapsed time: $elapsed_seconds"
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/start_httpd.sh b/sample/bin/aws-codedeploy-samples/load-balancing/elb/start_httpd.sh
new file mode 100755
index 00000000..20177145
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/start_httpd.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Here is where you'd want to start your http daemon. For example:
+#service httpd start
+#exit $?
+
+# In this case, since it's just a placeholder, we don't need to do anything.
+exit 0
diff --git a/sample/bin/aws-codedeploy-samples/load-balancing/elb/stop_httpd.sh b/sample/bin/aws-codedeploy-samples/load-balancing/elb/stop_httpd.sh
new file mode 100755
index 00000000..814d8fea
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/load-balancing/elb/stop_httpd.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Here is where you'd want to stop your http daemon. For example:
+#service httpd stop
+#exit $?
+
+# In this case, since it's just a placeholder, we don't need to do anything.
+exit 0
diff --git a/sample/bin/aws-codedeploy-samples/version-control/git/README.md b/sample/bin/aws-codedeploy-samples/version-control/git/README.md
new file mode 100755
index 00000000..cdbcf659
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/version-control/git/README.md
@@ -0,0 +1,25 @@
+Git Hooks
+=========
+
+The scripts here provide basic functionality to hook AWS CodeDeploy into git
+events. The primary script is provided as a `pre-push` hook, which executes the
+`aws deploy push` command for the local repository before git finishes pushing
+to the remote. It then starts a new deployment of the revision. Both the AWS
+CodeDeploy Application and Deployment Group must already exist.
+
+ !!! CAUTION !!! Because this does an S3 upload on every push, you may incur S3 transfer charges.
+
+ --Note, you need to make this script executable ( chmod +x pre-push ) after installing it in ./.git/hooks/pre-push
+
+No changes to the script itself should be required. Instead, it pulls the
+necessary information from git config. The required keys are
+`aws-codedeploy.application-name`, `aws-codedeploy.s3bucket`, and
+`aws-codedeploy.deployment-group`. They can be set with the following commands
+(replace values with your own):
+
+ git config aws-codedeploy.application-name MyApplication
+ git config aws-codedeploy.s3bucket MyS3Bucket
+ git config aws-codedeploy.deployment-group MyDeploymentGroup
+
+The deployment created with this script will use the default deployment
+configuration for the configured deployment group.
diff --git a/sample/bin/aws-codedeploy-samples/version-control/git/pre-push b/sample/bin/aws-codedeploy-samples/version-control/git/pre-push
new file mode 100755
index 00000000..93342c1b
--- /dev/null
+++ b/sample/bin/aws-codedeploy-samples/version-control/git/pre-push
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+AWS="/usr/local/bin/aws"
+
+APPLICATION_NAME=$(git config --get aws-codedeploy.application-name)
+DEPLOYMENT_GROUP=$(git config --get aws-codedeploy.deployment-group)
+BUCKET_NAME=$(git config --get aws-codedeploy.s3bucket)
+BUNDLE_NAME=$(echo $(basename `pwd`).zip)
+
+# `aws deploy push` will overwrite the bundle in S3. If you'd rather ensure that you have a unique
+# object for each push, you could, for example, append the commit hash:
+#BUNDLE_NAME=$(echo $(basename `pwd`)-$(git log -n 1 --format=%H).zip)
+
+# Call `aws deploy push` to create a new revision of the current repo
+echo "Pushing $BUNDLE_NAME to s3://${BUCKET_NAME} and registering with application '${APPLICATION_NAME}'" 1>&2
+$AWS deploy push \
+ --application-name ${APPLICATION_NAME} \
+ --s3-location s3://${BUCKET_NAME}/${BUNDLE_NAME} \
+ --ignore-hidden-files \
+ --source .
+
+revision_json="{\"revisionType\":\"S3\",\"s3Location\":{\"bucket\":\"${BUCKET_NAME}\",\"bundleType\":\"zip\",\"key\":\"${BUNDLE_NAME}\"}}"
+
+if [ $? != 0 ]; then
+ echo "Push to codedeploy failed; skipping create-deployment" 1>&2
+else
+ echo "Deploying s3://${BUCKET_NAME}/${BUNDLE_NAME} to application ${APPLICATION_NAME} and deployment group ${DEPLOYMENT_GROUP}" 1>&2
+ $AWS deploy create-deployment \
+ --application-name ${APPLICATION_NAME} \
+ --deployment-group-name ${DEPLOYMENT_GROUP} \
+ --revision $revision_json
+fi
diff --git a/sample/bin/build.sh b/sample/bin/build.sh
new file mode 100755
index 00000000..88a8f7f3
--- /dev/null
+++ b/sample/bin/build.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+CWD=$(pwd)
+PROJECT_DIR=$(dirname $0)/..
+BUILD_DIR=$PROJECT_DIR/build/$(date +"%s")
+
+mkdir $BUILD_DIR
+cp $PROJECT_DIR/appspec.yml $BUILD_DIR
+cp -r $PROJECT_DIR/bin $BUILD_DIR
+cp -r $PROJECT_DIR/docroot $BUILD_DIR
+rm -f $BUILD_DIR/docroot/index.php.dist
+
+cd $BUILD_DIR
+tar -zcvf output.tar.gz ./
+cd $CWD
+
+mv $BUILD_DIR/output.tar.gz $PROJECT_DIR
+rm -rf $BUILD_DIR
diff --git a/sample/bin/clean.sh b/sample/bin/clean.sh
new file mode 100755
index 00000000..78f526d3
--- /dev/null
+++ b/sample/bin/clean.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm -rf /usr/share/nginx/docroot
diff --git a/sample/bin/environment.dist b/sample/bin/environment.dist
new file mode 100755
index 00000000..e5c34f17
--- /dev/null
+++ b/sample/bin/environment.dist
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+require 'moonshot'
+
+# Set up Moonshot tooling for our environment.
+class MoonshotSampleApp < Moonshot::CLI
+ self.application_name = 'moonshot-sample-app'
+ self.artifact_repository = S3Bucket.new('{{bucket}}')
+ self.build_mechanism = Script.new('bin/build.sh')
+ self.deployment_mechanism = CodeDeploy.new(asg: 'AutoScalingGroup')
+end
+
+begin
+ MoonshotSampleApp.start
+rescue => e
+ warn "Uncaught exception: #{e.class}: #{e.message}"
+ warn "at: #{e.backtrace.first}"
+ exit(1)
+end
diff --git a/sample/bin/setup.sh b/sample/bin/setup.sh
new file mode 100755
index 00000000..d9444967
--- /dev/null
+++ b/sample/bin/setup.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash -e
+
+if [ -z "$1" ]; then
+ >&2 echo "Usage: $0 [S3-BUCKET]"
+ exit 1
+fi
+
+# The project's root directory.
+PROJECT_DIR=$(dirname $0)/..
+
+# Name of the user's default environment.
+STACK_NAME=moonshot-sample-app-dev-$(echo $USER | sed 's/[^a-zA-Z0-9_]*//g')
+
+# Creates the provisioning script and parameters file.
+cp $PROJECT_DIR/bin/environment.dist $PROJECT_DIR/bin/environment
+cp $PROJECT_DIR/cloud_formation/parameters/moonshot-sample-app.yml.dist $PROJECT_DIR/cloud_formation/parameters/$STACK_NAME.yml
+
+# Changes the S3 bucket in the provisioning script and parameters file.
+sed -i '' "s#{{bucket}}#$1#" "$PROJECT_DIR/bin/environment"
+sed -i '' "s#{{bucket}}#$1#" "$PROJECT_DIR/cloud_formation/parameters/$STACK_NAME.yml"
+
+# Create an index.php file, which is the "application".
+cp $PROJECT_DIR/docroot/index.php.dist $PROJECT_DIR/docroot/index.php
diff --git a/sample/bin/start.sh b/sample/bin/start.sh
new file mode 100755
index 00000000..4f07f4fd
--- /dev/null
+++ b/sample/bin/start.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+service nginx start
diff --git a/sample/bin/stop.sh b/sample/bin/stop.sh
new file mode 100755
index 00000000..eac2e66c
--- /dev/null
+++ b/sample/bin/stop.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+service nginx stop
diff --git a/sample/build/.placeholder b/sample/build/.placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/sample/cloud_formation/moonshot-sample-app.json b/sample/cloud_formation/moonshot-sample-app.json
new file mode 100644
index 00000000..c06d9fdd
--- /dev/null
+++ b/sample/cloud_formation/moonshot-sample-app.json
@@ -0,0 +1,287 @@
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Parameters" : {
+ "ArtifactBucket" : {
+ "Type" : "String",
+ "Description" : "The S3 bucket that contains the build artifacts that CodeDeploy will deploy."
+ },
+ "AvailabilityZone1" : {
+ "Type" : "AWS::EC2::AvailabilityZone::Name"
+ },
+ "AvailabilityZone2" : {
+ "Type" : "AWS::EC2::AvailabilityZone::Name"
+ },
+ "DesiredCapacity" : {
+ "Type" : "Number",
+ "Default" : "2",
+ "Description" : "The desired number of EC2 instances used for the application."
+ }
+ },
+ "Outputs" : {
+ "URL" : {
+ "Description" : "The application's URL",
+ "Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "LoadBalancer", "DNSName" ] } ] ] }
+ }
+ },
+ "Mappings" : {
+ "RegionMap" : {
+ "ap-northeast-1" : { "AMI" : "" },
+ "ap-southeast-1" : { "AMI" : "" },
+ "ap-southeast-2" : { "AMI" : "" },
+ "eu-central-1" : { "AMI" : "" },
+ "eu-west-1" : { "AMI" : "" },
+ "us-east-1" : { "AMI" : "" },
+ "us-west-2" : { "AMI" : "" }
+ }
+ },
+ "Resources" : {
+
+ "VPC" : {
+ "Type" : "AWS::EC2::VPC",
+ "Properties" : {
+ "CidrBlock" : "10.176.0.0/16",
+ "Tags" : [
+ { "Key" : "Name", "Value" : { "Ref" : "AWS::StackName" } }
+ ]
+ }
+ },
+
+ "InternetGateway" : {
+ "Type" : "AWS::EC2::InternetGateway"
+ },
+ "VPCGatewayAttachment" : {
+ "Type" : "AWS::EC2::VPCGatewayAttachment",
+ "Properties" : {
+ "InternetGatewayId" : { "Ref" : "InternetGateway" },
+ "VpcId" : { "Ref" : "VPC" }
+ }
+ },
+
+ "SubnetZone1" : {
+ "Type" : "AWS::EC2::Subnet",
+ "Properties" : {
+ "AvailabilityZone" : { "Ref" : "AvailabilityZone1" },
+ "CidrBlock" : "10.176.10.0/26",
+ "VpcId" : { "Ref" : "VPC" }
+ }
+ },
+ "SubnetZone2" : {
+ "Type" : "AWS::EC2::Subnet",
+ "Properties" : {
+ "AvailabilityZone" : { "Ref" : "AvailabilityZone2" },
+ "CidrBlock" : "10.176.10.64/26",
+ "VpcId" : { "Ref" : "VPC" }
+ }
+ },
+ "RouteTable" : {
+ "Type" : "AWS::EC2::RouteTable",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" }
+ }
+ },
+ "Route" : {
+ "Type" : "AWS::EC2::Route",
+ "Properties" : {
+ "RouteTableId" : { "Ref" : "RouteTable" },
+ "DestinationCidrBlock" : "0.0.0.0/0",
+ "GatewayId" : { "Ref" : "InternetGateway" }
+ }
+ },
+ "SubnetRouteTableAssociationZone1" : {
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties" : {
+ "RouteTableId" : { "Ref" : "RouteTable" },
+ "SubnetId" : { "Ref" : "SubnetZone1" }
+ }
+ },
+ "SubnetRouteTableAssociationZone2" : {
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties" : {
+ "RouteTableId" : { "Ref" : "RouteTable" },
+ "SubnetId" : { "Ref" : "SubnetZone2" }
+ }
+ },
+
+ "SecurityGroupElb" : {
+ "Type" : "AWS::EC2::SecurityGroup",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "GroupDescription" : "SecurityGroupElb",
+ "SecurityGroupIngress" : [
+ {
+ "IpProtocol" : "tcp",
+ "FromPort" : "80",
+ "ToPort" : "80",
+ "CidrIp" : "0.0.0.0/0"
+ }
+ ]
+ }
+ },
+ "LoadBalancer" : {
+ "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
+ "Properties" : {
+ "Listeners" : [
+ {
+ "InstancePort" : "80",
+ "LoadBalancerPort" : "80",
+ "Protocol" : "HTTP"
+ }
+ ],
+ "CrossZone" : true,
+ "ConnectionDrainingPolicy" : {
+ "Enabled" : true,
+ "Timeout" : 15
+ },
+ "Scheme" : "internet-facing",
+ "SecurityGroups" : [
+ { "Ref" : "SecurityGroupElb" }
+ ],
+ "HealthCheck" : {
+ "HealthyThreshold" : "3",
+ "Interval" : "15",
+ "Target" : "HTTP:80/index.php",
+ "Timeout" : "5",
+ "UnhealthyThreshold" : "3"
+ },
+ "Subnets" : [
+ { "Ref" : "SubnetZone1" },
+ { "Ref" : "SubnetZone2" }
+ ]
+ }
+ },
+
+ "Role" : {
+ "Type" : "AWS::IAM::Role",
+ "Properties" : {
+ "Path" : "/",
+ "AssumeRolePolicyDocument" : {
+ "Version" : "2012-10-17",
+ "Statement" : [
+ {
+ "Effect" : "Allow",
+ "Principal" : {
+ "Service" : [ "ec2.amazonaws.com" ]
+ },
+ "Action" : [ "sts:AssumeRole" ]
+ }
+ ]
+ },
+ "Policies" : [
+ {
+ "PolicyName" : "ArtifactAccess",
+ "PolicyDocument" : {
+ "Version" : "2012-10-17",
+ "Statement" : [
+ {
+ "Effect" : "Allow",
+ "Action" : [
+ "s3:GetObject"
+ ],
+ "Resource" : { "Fn::Join" : [ "", [ "arn:aws:s3:::", { "Ref" : "ArtifactBucket" }, "/*" ] ] }
+ }
+ ]
+ }
+ },
+ {
+ "PolicyName" : "ElbAutoDrainAccess",
+ "PolicyDocument" : {
+ "Version" : "2012-10-17",
+ "Statement" : [
+ {
+ "Effect" : "Allow",
+ "Action" : [
+ "elasticloadbalancing:Describe*",
+ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
+ "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
+ "autoscaling:Describe*",
+ "autoscaling:EnterStandby",
+ "autoscaling:ExitStandby",
+ "autoscaling:UpdateAutoScalingGroup"
+ ],
+ "Resource" : "*"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ "InstanceProfile" : {
+ "Type" : "AWS::IAM::InstanceProfile",
+ "Properties" : {
+ "Path" : "/",
+ "Roles" : [
+ { "Ref" : "Role" }
+ ]
+ }
+ },
+ "SecurityGroup" : {
+ "Type" : "AWS::EC2::SecurityGroup",
+ "Properties" : {
+ "VpcId" : { "Ref" : "VPC" },
+ "GroupDescription" : "SecurityGroup",
+ "SecurityGroupIngress" : [
+ {
+ "IpProtocol" : "tcp",
+ "FromPort" : "80",
+ "ToPort" : "80",
+ "SourceSecurityGroupId" : { "Ref" : "SecurityGroupElb" }
+ }
+ ],
+ "SecurityGroupEgress" : [
+ {
+ "IpProtocol" : "-1",
+ "FromPort" : "-1",
+ "ToPort" : "-1",
+ "CidrIp" : "0.0.0.0/0"
+ }
+ ]
+ }
+ },
+
+ "LaunchConfiguration" : {
+ "Type" : "AWS::AutoScaling::LaunchConfiguration",
+ "Properties" : {
+ "AssociatePublicIpAddress" : true,
+ "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "AMI" ] },
+ "IamInstanceProfile" : { "Ref" : "InstanceProfile" },
+ "InstanceType" : "t2.micro",
+ "SecurityGroups" : [ { "Ref" : "SecurityGroup" } ],
+ "UserData" : {
+ "Fn::Base64" : { "Fn::Join" : [ "", [
+ "#!/bin/bash -v",
+ "\necho '<:3)~~ eek! a mouse!'"
+ ] ] }
+ }
+ }
+ },
+ "AutoScalingGroup" : {
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
+ "DependsOn" : [ "VPCGatewayAttachment" ],
+ "Properties" : {
+ "AvailabilityZones" : [
+ { "Ref" : "AvailabilityZone1" },
+ { "Ref" : "AvailabilityZone2" }
+ ],
+ "DesiredCapacity" : { "Ref" : "DesiredCapacity" },
+ "HealthCheckGracePeriod" : "600",
+ "HealthCheckType" : "ELB",
+ "LaunchConfigurationName" : { "Ref" : "LaunchConfiguration" },
+ "LoadBalancerNames" : [ { "Ref" : "LoadBalancer" } ],
+ "MaxSize" : 5,
+ "MinSize" : { "Ref" : "DesiredCapacity" },
+ "TerminationPolicies" : [ "OldestLaunchConfiguration" ],
+ "VPCZoneIdentifier" : [
+ { "Ref" : "SubnetZone1" },
+ { "Ref" : "SubnetZone2" }
+ ]
+ },
+ "UpdatePolicy" : {
+ "AutoScalingRollingUpdate" : {
+ "MaxBatchSize" : "1",
+ "MinInstancesInService" : { "Ref" : "DesiredCapacity" }
+ }
+ }
+ }
+ }
+}
diff --git a/sample/cloud_formation/parameters/moonshot-sample-app.yml.dist b/sample/cloud_formation/parameters/moonshot-sample-app.yml.dist
new file mode 100644
index 00000000..4febbf1d
--- /dev/null
+++ b/sample/cloud_formation/parameters/moonshot-sample-app.yml.dist
@@ -0,0 +1,5 @@
+---
+ArtifactBucket: "{{bucket}}"
+AvailabilityZone1: "us-east-1a"
+AvailabilityZone2: "us-east-1b"
+DesiredCapacity: "2"
diff --git a/sample/docroot/index.php.dist b/sample/docroot/index.php.dist
new file mode 100644
index 00000000..83f15493
--- /dev/null
+++ b/sample/docroot/index.php.dist
@@ -0,0 +1,3 @@
+