diff --git a/cookbooks/docker_compose/Berksfile b/cookbooks/docker_compose/Berksfile new file mode 100644 index 00000000..fa4b1374 --- /dev/null +++ b/cookbooks/docker_compose/Berksfile @@ -0,0 +1,7 @@ +source 'https://supermarket.chef.io' + +metadata + +group :integration do + cookbook 'docker_compose_test', path: 'test/cookbooks/docker_compose_test' +end \ No newline at end of file diff --git a/cookbooks/docker_compose/HISTORY.md b/cookbooks/docker_compose/HISTORY.md new file mode 100644 index 00000000..ee296164 --- /dev/null +++ b/cookbooks/docker_compose/HISTORY.md @@ -0,0 +1,16 @@ +# Release History + +## vNEXT + +* Added support for specifying the service(s) to start/stop. + +## v0.1.1 + +* Added support for docker-compose's --remove-orphans parameter. +* The cookbook is now compatible with CentOS. +* Improved documentation. + +## v0.1.0 + +* Initial release. + diff --git a/cookbooks/docker_compose/LICENSE b/cookbooks/docker_compose/LICENSE new file mode 100644 index 00000000..8dada3ed --- /dev/null +++ b/cookbooks/docker_compose/LICENSE @@ -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 {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/cookbooks/docker_compose/README.md b/cookbooks/docker_compose/README.md new file mode 100644 index 00000000..0bf6c711 --- /dev/null +++ b/cookbooks/docker_compose/README.md @@ -0,0 +1,156 @@ +# Docker Compose Cookbook + +The Docker Compose Cookbook is a library cookbook that provides custom +resources for use in recipes. + + +## Requirements + +- Working Docker installation. You might want to use the excellent +[docker Cookbook](https://supermarket.chef.io/cookbooks/docker) to provision +Docker. + + +## Usage + +Place a dependency on the docker-compose cookbook in your cookbook's +metadata.rb + +```ruby +depends 'docker_compose', '~> 0.0' +``` + +Create a [Docker Compose file](https://docs.docker.com/compose/compose-file/) +for the application you want to provision. A simple Compose file that uses the +[official nginx Docker image](https://hub.docker.com/_/nginx/) looks like this: + +``` +version: '2' +services: + web_server: + image: nginx + ports: + - "80:80" +``` + +Then, in a recipe: + +```ruby +include_recipe 'docker_compose::installation' + +# Provision Compose file +cookbook_file '/etc/docker-compose_nginx.yml' do + source 'docker-compose_nginx.yml' + owner 'root' + group 'root' + mode 0640 + notifies :up, 'docker_compose_application[nginx]', :delayed +end + +# Provision Compose application +docker_compose_application 'nginx' do + action :up + compose_files [ '/etc/docker-compose_nginx.yml' ] +end +``` + +## Attributes + +- `node['docker_compose']['release']` - The release version of Docker Compose + to install. Defaults to a sane, current default. + +- `node['docker_compose']['command_path']` - The path under which the + `docker-compose` command should be installed. + Defaults to `/usr/local/bin/docker-compose` + + +## Recipes + +### default + +The `default` recipe is simply an alias for the `installation` recipe. + +### installation + +The `installation` recipe installs the `docker-compose` binary by downloading +it from the vendor's servers, as described in the +[official Docker Compose documentation](https://docs.docker.com/compose/install/). + +The path to which the `docker-compose` command is installed can be configured +via the `node['docker_compose']['command_path']` attribute. + + +## Resources + +### docker_compose_application + +The `docker_compose_application` provisions a Docker application (that usually +consists of several services) using a Docker Compose file. + +#### Example + +```ruby +docker_compose_application 'nginx' do + action :up + compose_files [ '/etc/docker-compose_nginx.yml', '/etc/docker-compose_nginx.additional.yml' ] + services ['nginx'] + remove_orphans true +end +``` + +#### Parameters + +- `project_name` - A string to identify the Docker Compose application. + Defaults to the resource name. + +- `compose_files` - The list of Compose files that makes up the Docker Compose + application. The specified file names are passed to the `docker-compose` + command in the order in which they appear in the list. + +- `services` - The list of services to start or stop. + Defaults to all services that are specified in the Compose files. + +- `remove_orphans` - Remove containers for services not defined in the + Compose file. + +#### Actions + +- `:up` - Create and start containers. + Equivalent to calling `docker-compose up -d --build` with the Compose files + that were specified using the `compose_files` parameter. + +- `:down` - Stop and remove containers and networks. + Equivalent to calling `docker-compose down` with the Compose files + that were specified using the `compose_files` parameter. + +- `:restart` - Calls down and up actions. + Useful for notications from changes to Dockerfiles and Compose files. + +- `:create` - Create containers for a service. + Equivalent to calling `docker-compose create` with the Compose files + that were specified using the `compose_files` parameter. + + +## License & Authors + +### Authors + +- Sebastian Boschert () + +### License + +Copyright (c) 2016 Sebastian Boschert. + +``` +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/cookbooks/docker_compose/attributes/default.rb b/cookbooks/docker_compose/attributes/default.rb new file mode 100644 index 00000000..7ba52bb4 --- /dev/null +++ b/cookbooks/docker_compose/attributes/default.rb @@ -0,0 +1,2 @@ +default['docker_compose']['release'] = '1.28.2' +default['docker_compose']['command_path'] = '/usr/local/bin/docker-compose' diff --git a/cookbooks/docker_compose/chefignore b/cookbooks/docker_compose/chefignore new file mode 100644 index 00000000..a9769175 --- /dev/null +++ b/cookbooks/docker_compose/chefignore @@ -0,0 +1,102 @@ +# Put files/directories that should be ignored in this file when uploading +# to a chef-server or supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.dll +*.exe +*/rdoc/ + +# Testing # +########### +.watchr +.rspec +spec/* +spec/fixtures/* +test/* +features/* +examples/* +Guardfile +Procfile +.kitchen* +.rubocop.yml +spec/* +Rakefile +.travis.yml +.foodcritic +.codeclimate.yml + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Cookbooks # +############# +CONTRIBUTING* +CHANGELOG* +TESTING* +MAINTAINERS.toml + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/cookbooks/docker_compose/metadata.rb b/cookbooks/docker_compose/metadata.rb new file mode 100644 index 00000000..763b9061 --- /dev/null +++ b/cookbooks/docker_compose/metadata.rb @@ -0,0 +1,15 @@ +name 'docker_compose' +maintainer 'Sebastian Boschert' +maintainer_email 'sebastian@2007.org' +license 'Apache v2.0' +description 'Installs docker_compose and provides the docker_compose_application resource.' +long_description 'Installs docker_compose and provides the docker_compose_application resource.' +chef_version '>= 12' +source_url 'https://github.com/sboschert/chef-cookbook-docker_compose' +issues_url 'https://github.com/sboschert/chef-cookbook-docker_compose/issues' +version '0.1.2' + +supports 'debian' +supports 'ubuntu' +supports 'redhat' +supports 'centos' diff --git a/cookbooks/docker_compose/recipes/default.rb b/cookbooks/docker_compose/recipes/default.rb new file mode 100644 index 00000000..7fa3b858 --- /dev/null +++ b/cookbooks/docker_compose/recipes/default.rb @@ -0,0 +1,7 @@ +# +# Cookbook Name:: docker_compose +# Recipe:: default +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +include_recipe 'docker_compose::installation' diff --git a/cookbooks/docker_compose/recipes/installation.rb b/cookbooks/docker_compose/recipes/installation.rb new file mode 100644 index 00000000..16013736 --- /dev/null +++ b/cookbooks/docker_compose/recipes/installation.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: docker_compose +# Recipe:: installation +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +def get_install_url + release = node['docker_compose']['release'] + kernel_name = node['kernel']['name'] + machine_hw_name = node['kernel']['machine'] + "https://github.com/docker/compose/releases/download/#{release}/docker-compose-#{kernel_name}-#{machine_hw_name}" +end + +command_path = node['docker_compose']['command_path'] +install_url = get_install_url + +package 'curl' do + action :install +end + +directory '/etc/docker-compose' do + action :create + owner 'root' + group 'docker' + mode '0750' +end + +execute 'install docker-compose' do + action :run + command "curl -sSL #{install_url} > #{command_path} && chmod +x #{command_path}" + user 'root' + group 'docker' + umask '0027' + not_if "#{command_path} --version | grep #{node['docker_compose']['release']}" +end diff --git a/cookbooks/docker_compose/resources/application.rb b/cookbooks/docker_compose/resources/application.rb new file mode 100644 index 00000000..78db264c --- /dev/null +++ b/cookbooks/docker_compose/resources/application.rb @@ -0,0 +1,85 @@ +# +# Cookbook Name:: docker_compose +# Resource:: application +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +property :project_name, kind_of: String, name_property: true +property :compose_files, kind_of: Array, required: true +property :remove_orphans, kind_of: [TrueClass, FalseClass], default: false +property :services, kind_of: Array, default: [] + +default_action :up + +def get_compose_params + "-p #{project_name}" + + ' -f ' + compose_files.join(' -f ') +end + +def get_up_params + # '--build' is ignored if there is nothing in the compose file that uses it and + # will result in no image changes if nothing in the Dockerfile's layers have + # changed + '-d --build' + + (remove_orphans ? ' --remove-orphans' : '') + + (services.nil? ? '' : ' ' + services.join(' ')) +end + +def get_down_params + (remove_orphans ? ' --remove-orphans' : '') + + (services.nil? ? '' : ' ' + services.join(' ')) +end + +action :up do + project_name = new_resource.project_name || current_resource.project_name + compose_files = new_resource.compose_files || current_resource.compose_files + + execute "running docker-compose up for project #{project_name}" do + command "docker-compose #{get_compose_params} up #{get_up_params}" + environment('PATH' => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin') + only_if "[ $(docker-compose -f #{compose_files.join(' -f ')} ps -q | wc -l) -eq 0 ]" + user 'root' + group 'root' + end +end + +action :updateup do + project_name = new_resource.project_name || current_resource.project_name + compose_files = new_resource.compose_files || current_resource.compose_files + + execute "running docker-compose up --force-recreate for project #{project_name}" do + command "docker-compose #{get_compose_params} up --force-recreate #{get_up_params}" + environment('PATH' => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin') + user 'root' + group 'root' + end +end + +action :create do + project_name = new_resource.project_name || current_resource.project_name + + execute "running docker-compose create for project #{project_name}" do + command "docker-compose #{get_compose_params} create #{get_up_params}" + environment('PATH' => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin') + user 'root' + group 'root' + end +end + +action :down do + project_name = new_resource.project_name || current_resource.project_name + compose_files = new_resource.compose_files || current_resource.compose_files + + execute "running docker-compose down for project #{project_name}" do + command "docker-compose #{get_compose_params} down #{get_down_params}" + environment('PATH' => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin') + not_if "[ $(docker-compose -f #{compose_files.join(' -f ')} ps -q | wc -l) -eq 0 ]" + user 'root' + group 'root' + end +end + +action :restart do + action_down + action_up +end diff --git a/cookbooks/docker_compose/spec/spec_helper.rb b/cookbooks/docker_compose/spec/spec_helper.rb new file mode 100644 index 00000000..1dd5126b --- /dev/null +++ b/cookbooks/docker_compose/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'chefspec' +require 'chefspec/berkshelf' diff --git a/cookbooks/docker_compose/spec/unit/recipes/default_spec.rb b/cookbooks/docker_compose/spec/unit/recipes/default_spec.rb new file mode 100644 index 00000000..967fc233 --- /dev/null +++ b/cookbooks/docker_compose/spec/unit/recipes/default_spec.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: docker_compose +# Spec:: default +# +# Copyright (c) 2016 The Authors, All Rights Reserved. + +require 'spec_helper' + +describe 'docker_compose::default' do + context 'When all attributes are default, on an unspecified platform' do + let(:chef_run) do + # This doesn't help if the default attributes are changed. Maybe this should override the defaults + # with new "defaults" just for the test. Then the stubbed command path and version would match. + # That's just a different level of hard-coding, though. + stub_command("/usr/local/bin/docker-compose --version | grep 1.21.2").and_return(true) + + runner = ChefSpec::ServerRunner.new + runner.converge(described_recipe) + end + + it 'converges successfully' do + expect { chef_run }.to_not raise_error + end + end +end diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/README.md b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/README.md new file mode 100644 index 00000000..3d750c3a --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/README.md @@ -0,0 +1,4 @@ +# docker_compose_test + +TODO: Enter the cookbook description here. + diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/Dockerfile.nginx_custom b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/Dockerfile.nginx_custom new file mode 100644 index 00000000..3aab8afb --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/Dockerfile.nginx_custom @@ -0,0 +1,3 @@ +FROM nginx + +COPY Dockerfile / diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_1.yml b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_1.yml new file mode 100644 index 00000000..100e30ff --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_1.yml @@ -0,0 +1,6 @@ +version: '2' +services: + web_server: + image: nginx + ports: + - "8991:80" diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_2.yml b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_2.yml new file mode 100644 index 00000000..950fb337 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_build_2.yml @@ -0,0 +1,6 @@ +version: '2' +services: + web_server: + build: ./nginx_custom + ports: + - "8991:80" diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_nginx.yml b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_nginx.yml new file mode 100644 index 00000000..20cde713 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_nginx.yml @@ -0,0 +1,14 @@ +version: '2' +services: + web_server_1: + image: nginx + ports: + - "8001:80" + web_server_2: + image: nginx + ports: + - "8002:80" + web_server_3: + image: nginx + ports: + - "8003:80" diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_1.yml b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_1.yml new file mode 100644 index 00000000..69223148 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_1.yml @@ -0,0 +1,11 @@ +version: '2' +services: + web_server_1: + image: nginx + ports: + - "8891:80" + + web_server_2: + image: nginx + ports: + - "8892:80" diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_2.yml b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_2.yml new file mode 100644 index 00000000..3eac6c89 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/files/default/docker-compose_remove_orphans_2.yml @@ -0,0 +1,6 @@ +version: '2' +services: + web_server_1: + image: nginx + ports: + - "8891:80" diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/metadata.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/metadata.rb new file mode 100644 index 00000000..b433b40b --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/metadata.rb @@ -0,0 +1,10 @@ +name 'docker_compose_test' +maintainer 'The Authors' +maintainer_email 'you@example.com' +license 'all_rights' +description 'Installs/Configures docker_compose_test' +long_description 'Installs/Configures docker_compose_test' +version '0.1.1' + +depends 'docker' +depends 'docker_compose' \ No newline at end of file diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_build.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_build.rb new file mode 100644 index 00000000..d6ce881f --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_build.rb @@ -0,0 +1,44 @@ +# +# Cookbook Name:: docker_compose_test +# Recipe:: project_up +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +cookbook_file 'compose_build_1.yml' do + action :create + path '/etc/docker-compose/docker-compose_build.yml' + source 'docker-compose_build_1.yml' + owner 'root' + group 'root' + mode 0640 + notifies :up, 'docker_compose_application[builtapp]', :immediate +end + +docker_compose_application 'builtapp' do + action :up + compose_files [ '/etc/docker-compose/docker-compose_build.yml' ] +end + +directory '/etc/docker-compose/nginx_custom' do + owner 'root' + group 'root' + mode '0755' + action :create +end + +cookbook_file '/etc/docker-compose/nginx_custom/Dockerfile' do + source 'Dockerfile.nginx_custom' + owner 'root' + group 'root' + mode '0755' + action :create +end + +cookbook_file 'compose_build_2.yml' do + path '/etc/docker-compose/docker-compose_build.yml' + source 'docker-compose_build_2.yml' + owner 'root' + group 'root' + mode 0640 + notifies :restart, 'docker_compose_application[builtapp]', :immediate +end diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up.rb new file mode 100644 index 00000000..1ef3e948 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: docker_compose_test +# Recipe:: project_up +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +cookbook_file '/etc/docker-compose/docker-compose_nginx.yml' do + action :create + source 'docker-compose_nginx.yml' + owner 'root' + group 'root' + mode 0640 + notifies :up, 'docker_compose_application[nginx]', :delayed +end + +docker_compose_application 'nginx' do + action :up + services %w(web_server_1 web_server_2) + compose_files [ '/etc/docker-compose/docker-compose_nginx.yml' ] +end diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up_remove_orphans.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up_remove_orphans.rb new file mode 100644 index 00000000..e8d8dba4 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/application_up_remove_orphans.rb @@ -0,0 +1,36 @@ +# +# Cookbook Name:: docker_compose_test +# Recipe:: project_up +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +cookbook_file '/etc/docker-compose/docker-compose_remove_orphans_1.yml' do + action :create + source 'docker-compose_remove_orphans_1.yml' + owner 'root' + group 'root' + mode 0640 + notifies :up, 'docker_compose_application[removeorphans1]', :delayed +end + +cookbook_file '/etc/docker-compose/docker-compose_remove_orphans_2.yml' do + action :create + source 'docker-compose_remove_orphans_2.yml' + owner 'root' + group 'root' + mode 0640 + notifies :up, 'docker_compose_application[removeorphans2]', :delayed +end + +docker_compose_application 'removeorphans1' do + action :up + compose_files [ '/etc/docker-compose/docker-compose_remove_orphans_1.yml' ] + project_name 'removeorphans' +end + +docker_compose_application 'removeorphans2' do + action :up + compose_files [ '/etc/docker-compose/docker-compose_remove_orphans_2.yml' ] + remove_orphans true + project_name 'removeorphans' +end diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/default.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/default.rb new file mode 100644 index 00000000..ea070fa8 --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/default.rb @@ -0,0 +1,10 @@ +# +# Cookbook Name:: docker_compose_test +# Recipe:: default +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +include_recipe 'docker_compose_test::installation' +include_recipe 'docker_compose_test::application_up' +include_recipe 'docker_compose_test::application_up_remove_orphans' +include_recipe 'docker_compose_test::application_build' diff --git a/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/installation.rb b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/installation.rb new file mode 100644 index 00000000..8b10a4ad --- /dev/null +++ b/cookbooks/docker_compose/test/cookbooks/docker_compose_test/recipes/installation.rb @@ -0,0 +1,11 @@ +# +# Cookbook Name:: docker_compose_test +# Recipe:: installation +# +# Copyright (c) 2016 Sebastian Boschert, All Rights Reserved. + +docker_service 'default' do + action [:create, :start] +end + +include_recipe 'docker_compose::installation' diff --git a/cookbooks/docker_compose/test/recipes/default/project_up_remove_orphans_spec.rb b/cookbooks/docker_compose/test/recipes/default/project_up_remove_orphans_spec.rb new file mode 100644 index 00000000..3ae8e905 --- /dev/null +++ b/cookbooks/docker_compose/test/recipes/default/project_up_remove_orphans_spec.rb @@ -0,0 +1,28 @@ +# # encoding: utf-8 + +# Inspec test for recipe docker_compose::default + +# The Inspec reference, with examples and extensive documentation, can be +# found at https://docs.chef.io/inspec_reference.html + +# Ensure the nginx container named web_server_1 is up +describe command('docker ps -q -f name=removeorphans_web_server_1 | wc -l') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "1\n" } +end + +# Ensure the nginx container named web_server_2 is down +describe command('docker ps -q -f name=removeorphans_web_server_2 | wc -l') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "0\n" } +end + +# Ensure nginx instance web_server_1 is listening on port 8891 +describe port(8891) do + it { should be_listening } +end + +# Ensure nginx instance web_server_2 is not listening on port 8892 +describe port(8892) do + it { should_not be_listening } +end diff --git a/cookbooks/docker_compose/test/recipes/default/project_up_spec.rb b/cookbooks/docker_compose/test/recipes/default/project_up_spec.rb new file mode 100644 index 00000000..da55f228 --- /dev/null +++ b/cookbooks/docker_compose/test/recipes/default/project_up_spec.rb @@ -0,0 +1,45 @@ +# # encoding: utf-8 + +# Inspec test for recipe docker_compose::default + +# The Inspec reference, with examples and extensive documentation, can be +# found at https://docs.chef.io/inspec_reference.html + +# Ensure the correct image was pulled +describe command('docker ps -f name=nginx_web_server_1 | awk \'BEGIN{FS=" +"} NR > 1 { print $2 }\'') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "nginx\n" } +end + +# Ensure the first specified nginx container is up +describe command('docker ps -q -f name=nginx_web_server_1 | wc -l') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "1\n" } +end + +# Ensure the second specified nginx container is up +describe command('docker ps -q -f name=nginx_web_server_2 | wc -l') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "1\n" } +end + +# Ensure the third specified nginx container is not up +describe command('docker ps -q -f name=nginx_web_server_3 | wc -l') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "0\n" } +end + +# Ensure the first specified nginx instance is listening on port 8001 +describe port(8001) do + it { should be_listening } +end + +# Ensure the second specified nginx instance is listening on port 8002 +describe port(8002) do + it { should be_listening } +end + +# Ensure the second specified nginx instance is listening on port 8003 +describe port(8003) do + it { should_not be_listening } +end