From c238a6a46d1277ce39e9894ad0980a3233f329a8 Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Sun, 17 Feb 2019 00:02:05 -0600 Subject: [PATCH] update with chef-cookbook/docker v4.9.2 --- chef/cookbooks/docker/Berksfile | 7 + chef/cookbooks/docker/CHANGELOG.md | 501 ++++++- chef/cookbooks/docker/Gemfile | 13 + chef/cookbooks/docker/LICENSE | 202 +++ chef/cookbooks/docker/MAINTAINERS.md | 20 - chef/cookbooks/docker/README.md | 894 ++++++------ chef/cookbooks/docker/TESTING.md | 2 + chef/cookbooks/docker/chefignore | 106 ++ .../vendor/cache/docker-api-1.33.2.gem | Bin 27648 -> 0 bytes .../default/vendor/cache/excon-0.54.0.gem | Bin 236032 -> 0 bytes .../files/default/vendor/cache/json-2.0.3.gem | Bin 138752 -> 0 bytes .../vendor/gems/excon-0.54.0/Gemfile.lock | 301 ---- .../vendor/gems/json-2.0.3/ext/json/Makefile | 196 --- .../ext/json/ext/generator/Makefile | 262 ---- .../ext/json/ext/generator/generator.bundle | Bin 49508 -> 0 bytes .../ext/json/ext/generator/generator.o | Bin 114500 -> 0 bytes .../json-2.0.3/ext/json/ext/parser/Makefile | 262 ---- .../ext/json/ext/parser/parser.bundle | Bin 32908 -> 0 bytes .../json-2.0.3/ext/json/ext/parser/parser.o | Bin 54384 -> 0 bytes .../json-2.0.3/lib/json/ext/generator.bundle | Bin 49508 -> 0 bytes .../json-2.0.3/lib/json/ext/parser.bundle | Bin 32908 -> 0 bytes chef/cookbooks/docker/kitchen.yml | 175 +++ chef/cookbooks/docker/libraries/_autoload.rb | 13 - .../cookbooks/docker/libraries/docker_base.rb | 129 +- .../docker/libraries/docker_container.rb | 776 ++++++++--- .../cookbooks/docker/libraries/docker_exec.rb | 13 +- .../docker/libraries/docker_image.rb | 137 +- .../docker/libraries/docker_image_prune.rb | 39 + .../libraries/docker_installation_binary.rb | 40 - .../libraries/docker_installation_package.rb | 158 ++- .../libraries/docker_installation_script.rb | 17 +- .../libraries/docker_installation_tarball.rb | 64 +- .../docker/libraries/docker_network.rb | 160 ++- .../docker/libraries/docker_plugin.rb | 125 ++ .../docker/libraries/docker_registry.rb | 30 +- .../docker/libraries/docker_service.rb | 51 +- .../docker/libraries/docker_service_base.rb | 103 +- .../docker_service_manager_execute.rb | 2 - .../docker_service_manager_systemd.rb | 98 +- .../docker_service_manager_sysvinit_debian.rb | 19 +- .../docker_service_manager_sysvinit_rhel.rb | 21 +- .../docker_service_manager_upstart.rb | 31 +- chef/cookbooks/docker/libraries/docker_tag.rb | 10 +- .../docker/libraries/docker_volume.rb | 21 +- .../docker/libraries/helpers_auth.rb | 10 - .../docker/libraries/helpers_base.rb | 110 -- .../docker/libraries/helpers_container.rb | 236 ---- .../docker/libraries/helpers_image.rb | 104 -- .../libraries/helpers_installation_binary.rb | 66 - .../libraries/helpers_installation_package.rb | 105 -- .../libraries/helpers_installation_tarball.rb | 50 - .../docker/libraries/helpers_network.rb | 118 -- .../docker/libraries/helpers_service.rb | 42 +- chef/cookbooks/docker/libraries/matchers.rb | 339 ----- chef/cookbooks/docker/metadata.json | 1 - chef/cookbooks/docker/metadata.rb | 21 + .../docker/spec/docker_test/container_spec.rb | 925 ++++++++++++ .../docker/spec/docker_test/exec_spec.rb | 41 + .../spec/docker_test/image_prune_spec.rb | 24 + .../docker/spec/docker_test/image_spec.rb | 271 ++++ .../docker_test/installation_package_spec.rb | 140 ++ .../docker/spec/docker_test/network_spec.rb | 174 +++ .../docker/spec/docker_test/plugin_spec.rb | 118 ++ .../docker/spec/docker_test/registry_spec.rb | 125 ++ .../docker/spec/docker_test/service_spec.rb | 55 + .../docker/spec/docker_test/volume_spec.rb | 47 + .../docker/spec/helpers_container_spec.rb | 82 ++ .../docker/spec/helpers_network_spec.rb | 49 + .../spec/libraries/container_networks_spec.rb | 55 + .../docker/spec/libraries/container_spec.rb | 126 ++ .../docker/spec/libraries/image_prune_spec.rb | 27 + .../docker/spec/libraries/registry_spec.rb | 88 ++ chef/cookbooks/docker/spec/spec_helper.rb | 21 + .../templates/default/default/docker.erb | 6 - .../templates/default/sysconfig/docker.erb | 6 - .../systemd/docker.service-override.erb | 28 +- .../default/systemd/docker.service.erb | 30 +- .../systemd/docker.socket-override.erb | 3 +- .../default/systemd/docker.socket.erb | 2 +- .../default/sysvinit/docker-debian.erb | 10 +- .../templates/default/upstart/docker.conf.erb | 10 +- .../test/cookbooks/docker_test/CHANGELOG.md | 35 + .../cookbooks/docker_test/files/Dockerfile_1 | 2 + .../cookbooks/docker_test/files/Dockerfile_2 | 4 + .../cookbooks/docker_test/files/Dockerfile_4 | 32 + .../cookbooks/docker_test/files/image_3.tar | Bin 0 -> 2560 bytes .../docker_test/files/image_3/Dockerfile | 2 + .../test/cookbooks/docker_test/metadata.rb | 9 + .../cookbooks/docker_test/recipes/auto.rb | 21 + .../docker_test/recipes/container.rb | 1238 +++++++++++++++++ .../cookbooks/docker_test/recipes/default.rb | 145 ++ .../cookbooks/docker_test/recipes/exec.rb | 25 + .../cookbooks/docker_test/recipes/image.rb | 317 +++++ .../docker_test/recipes/image_prune.rb | 15 + .../recipes/installation_package.rb | 4 + .../recipes/installation_script.rb | 4 + .../recipes/installation_tarball.rb | 4 + .../cookbooks/docker_test/recipes/network.rb | 251 ++++ .../cookbooks/docker_test/recipes/plugin.rb | 94 ++ .../cookbooks/docker_test/recipes/registry.rb | 192 +++ .../cookbooks/docker_test/recipes/service.rb | 7 + .../cookbooks/docker_test/recipes/smoke.rb | 84 ++ .../cookbooks/docker_test/recipes/timeout.rb | 35 + .../cookbooks/docker_test/recipes/volume.rb | 54 + .../nginx_forward_proxy/proxy.conf.erb | 7 + .../templates/registry/auth/registry.conf.erb | 38 + .../registry/auth/registry.password.erb | 1 + .../squid_forward_proxy/squid.conf.erb | 44 + .../inspec/assert_functioning_spec.rb | 10 + .../inspec/assert_functioning_spec.rb | 3 + .../inspec/assert_functioning_spec.rb | 3 + .../inspec/assert_functioning_spec.rb | 3 + .../inspec/assert_functioning_spec.rb | 4 + .../network/inspec/assert_functioning_spec.rb | 277 ++++ .../inspec/assert_functioning_spec.rb | 962 +++++++++++++ .../smoke/inspec/assert_functioning_spec.rb | 23 + .../volume/inspec/assert_functioning_spec.rb | 43 + 117 files changed, 9305 insertions(+), 3350 deletions(-) create mode 100644 chef/cookbooks/docker/Berksfile create mode 100644 chef/cookbooks/docker/Gemfile create mode 100644 chef/cookbooks/docker/LICENSE delete mode 100644 chef/cookbooks/docker/MAINTAINERS.md create mode 100644 chef/cookbooks/docker/TESTING.md create mode 100644 chef/cookbooks/docker/chefignore delete mode 100644 chef/cookbooks/docker/files/default/vendor/cache/docker-api-1.33.2.gem delete mode 100644 chef/cookbooks/docker/files/default/vendor/cache/excon-0.54.0.gem delete mode 100644 chef/cookbooks/docker/files/default/vendor/cache/json-2.0.3.gem delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/excon-0.54.0/Gemfile.lock delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/Makefile delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/Makefile delete mode 100755 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.bundle delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.o delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/Makefile delete mode 100755 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.bundle delete mode 100644 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.o delete mode 100755 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/lib/json/ext/generator.bundle delete mode 100755 chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/lib/json/ext/parser.bundle create mode 100644 chef/cookbooks/docker/kitchen.yml delete mode 100644 chef/cookbooks/docker/libraries/_autoload.rb create mode 100644 chef/cookbooks/docker/libraries/docker_image_prune.rb delete mode 100644 chef/cookbooks/docker/libraries/docker_installation_binary.rb create mode 100644 chef/cookbooks/docker/libraries/docker_plugin.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_auth.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_base.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_container.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_image.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_installation_binary.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_installation_package.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_installation_tarball.rb delete mode 100644 chef/cookbooks/docker/libraries/helpers_network.rb delete mode 100644 chef/cookbooks/docker/libraries/matchers.rb delete mode 100644 chef/cookbooks/docker/metadata.json create mode 100644 chef/cookbooks/docker/metadata.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/container_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/exec_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/image_prune_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/image_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/installation_package_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/network_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/plugin_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/registry_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/service_spec.rb create mode 100644 chef/cookbooks/docker/spec/docker_test/volume_spec.rb create mode 100644 chef/cookbooks/docker/spec/helpers_container_spec.rb create mode 100644 chef/cookbooks/docker/spec/helpers_network_spec.rb create mode 100644 chef/cookbooks/docker/spec/libraries/container_networks_spec.rb create mode 100644 chef/cookbooks/docker/spec/libraries/container_spec.rb create mode 100644 chef/cookbooks/docker/spec/libraries/image_prune_spec.rb create mode 100644 chef/cookbooks/docker/spec/libraries/registry_spec.rb create mode 100644 chef/cookbooks/docker/spec/spec_helper.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/CHANGELOG.md create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_1 create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_2 create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_4 create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3.tar create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3/Dockerfile create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/metadata.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/auto.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/container.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/default.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/exec.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image_prune.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_package.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_script.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_tarball.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/network.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/plugin.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/registry.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/service.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/smoke.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/timeout.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/recipes/volume.rb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/templates/nginx_forward_proxy/proxy.conf.erb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.conf.erb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.password.erb create mode 100644 chef/cookbooks/docker/test/cookbooks/docker_test/templates/squid_forward_proxy/squid.conf.erb create mode 100644 chef/cookbooks/docker/test/integration/installation_package/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/installation_script_experimental/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/installation_script_main/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/installation_script_test/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/installation_tarball/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/network/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/resources/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/smoke/inspec/assert_functioning_spec.rb create mode 100644 chef/cookbooks/docker/test/integration/volume/inspec/assert_functioning_spec.rb diff --git a/chef/cookbooks/docker/Berksfile b/chef/cookbooks/docker/Berksfile new file mode 100644 index 0000000..5079b3c --- /dev/null +++ b/chef/cookbooks/docker/Berksfile @@ -0,0 +1,7 @@ +source 'https://supermarket.chef.io' + +metadata + +group :integration do + cookbook 'docker_test', path: 'test/cookbooks/docker_test' +end diff --git a/chef/cookbooks/docker/CHANGELOG.md b/chef/cookbooks/docker/CHANGELOG.md index 7235bec..5cab017 100644 --- a/chef/cookbooks/docker/CHANGELOG.md +++ b/chef/cookbooks/docker/CHANGELOG.md @@ -2,111 +2,470 @@ This file is used to list changes made in each version of the docker cookbook. -## 12.15.2 (2017-02-15) +## 4.9.2 (2019-02-15) + +- Support setting shared memory size. + +## 4.9.1 (2019-02-01) + +- added systemd_socket_opts for additional configuration of the systemd socket file + +## 4.9.0 (2018-12-17) + +- Add support for windows - [@smcavallo](https://github.com/smcavallo) +- Expand ChefSpec testing - [@smcavallo](https://github.com/smcavallo) +- Fix for when HealthCheck is used - [@smcavallo](https://github.com/smcavallo) + +## 4.8.0 (2018-12-09) + +- Fix issues with network_mode in docker_container - [@smcavallo](https://github.com/smcavallo) +- Add support for container health_check options - [@smcavallo](https://github.com/smcavallo) +- Add new docker_image_prune resource - [@smcavallo](https://github.com/smcavallo) + +## 4.7.0 (2018-12-05) + +- Added 17.03 support on RHEL 7. Thanks @smcavallo +- Added 18.09 support. Thanks @smcavallo + +## 4.6.8 (2018-11-27) + +- add missing new_resource reference that prevented docker_container's reload action from running + +## 4.6.7 (2018-10-10) + +- Add :default_address_pool property to docker_service +- Import docker.com repository gpg key via HTTPS directly from docker to avoid timeouts with Ubuntu's key registry + +## 4.6.6 (unreleased) + +- :default_ip_address_pool property added to configure default address pool for networks created by Docker. + +## 4.6.5 (2018-09-04) + +- package names changed again. looks like they swapped xenial and bionic name schema. + +## 4.6.4 (2018-08-29) + +- xenial 18.03 contains the new test version format + +## 4.6.3 (2018-08-23) + +- refactor version_string + +## 4.6.2 (2018-08-23) + +- Use different version string on .deb packages + +## 4.6.1 (2018-08-21) + +- Include setup_docker_repo in docker_service and allow old docker-ce versions for centos + +## 4.6.0 (2018-08-19) + +- Bump docker version to 18.06.0 + +## 4.5.0 (2018-08-16) + +- sets the default log_level for the systemd docker service back to nil +- change require relative to library path +- docker_execute -> docker_exec +- Loosen up the requirement on docker-api gem +- Add new docker_plugin resource + +## 4.4.1 (2018-07-23) + +- Adding tests for docker_container detach == false (container is attached) +- Add new_resource and current_resource objects as context for methods when telling a container to wait (when detach is false) + +## 4.4.0 (2018-07-17) + +- docker service :log_level property converted to String. +- Use new package versioning scheme for Ubuntu bionic +- Bump the docker version everywhere + +## 4.3.0 (2018-06-19) + +- Remove the zesty? helper +- Initial support for Debian Buster (10) +- Bump the package default to 18.03.0 +- Remove old integration tests +- Update package specs to pass on Amazon Linux + +## 4.2.0 (2018-04-09) + +- Initial support for Chef 14 +- Remove unused api_version helper +- Support additional sysv RHEL like platforms by using platform_family +- Added oom_kill_disable and oom_score_adj support to docker_container +- ENV returns nil if the variable isn't found +- Remove the TLS default helpers +- Move coerce_labels into docker_container where its used +- Add desired_state false to a few more properties +- If the ENV values are nil don't use them to build busted defaults for TLS +- Remove a giant pile of Chef 12-isms +- Kill off ArrayType and NonEmptyArray types +- Don't require docker all over the place +- Kill the ShellCommand type +- Fix undefined method `v' for DockerContainer +- Make to_shellwords idempotent in DockerContainer +- Fix(Chef14): Use property_is_set with new_resource +- Use try-restart for systemd & retry start one time + +## 4.1.1 (2018-03-11) + +- Move to_snake_case to the container resource where it's used +- Reduce the number of coerce helpers in the the container resource +- Remove the Boolean type and instead just use TrueClass,FalseClass +- Use an actual integer in the memory_swappiness test since after reworking the coerce helpers we're requiring what we always stated we required here + +## 4.1.0 (2018-03-10) + +- Remove required from the name property. This resolves Foodcritic warnings in Foodcritic 13 +- Resolve a pile of Chef 14 deprecation warnings in the container and images resources +- Remove support for Ubuntu 17.04 from the installation_package resource +- Moved all the helper libraries into the resources themselves. This is part 1 of the work to get these resources ready for inclusion in Chef 14 +- Removed the version logic from installation_package when on Amazon Linux. Since we don't setup the repo we only have a single version available to us and we should just install that version. This resolves the constant need to update the hardcoded version in the cookbook every time Amazon releases a new Docker version. + +## 4.0.2 (2018-03-05) + +- Flag registry password property as sensitive in docker_registry resource + +## 4.0.1 (2018-02-07) + +- allow labels to have colons in the value + +## 4.0.0 (2018-01-15) + +### Breaking Changes + +- Default to Docker 17.12.0 +- Remove previously deprecated support for Debian 7 / CentOS 6\. Currently supported released of Docker do not run on these platforms. +- Removed support for the EOL Docker 1.12.3 +- Removed the ChefSpec matchers which are no longer needed with ChefDK 2.X +- Remove the broken legacy binary installation resource. This was only used by very old EOL docker releases +- By default setup the apt/yum repos in the package install resource so that out of the box there's no need for additional cookbooks. If you would like to manage your own docker repos or other internal repos this may be disabled by property. Due to this change the cookbook now requires Chef 12.15+ + +### Other Changes + +- Greatly expand Travis CI testing of the cookbook and use new InSpec resources for Docker instead of shelling out +- Add support for Ubuntu 17.10 +- Update Fedora support for new DNF support in Chef +- Minor correctness and formatting updates to the readme +- load internal and ipv6 status for existing docker_network resources +- Update Amazon Linux to default to 17.09.1, which is the current version in their repos +- Fix the remove action in docker_installation_script +- Replace deprecated graph with data_root. Graph will now silently map to data_root +- Pass --host instead of -H in docker_service for clarity +- Make sure tar is installed to decompress the tarball in the docker_installation_tarball resource +- Update the download path for Docker CE to unbreak docker_installation_tarball +- Allow specifying channels in the docker_installation_tarball resource so you can install non-stable releases + +## 3.0.0 (2017-12-22) + +- Install docker-api via gem metadata. This bumps the required chef release for this cookbook to 12.10+ +- Removed support for Ubuntu Precise +- Reworked the init system detection logic to work on additional platforms and without hardcoded distro version numbers +- Removed shasums from the binary installation resource for Docker 1.6-1.9.1 which are long ago EOL Docker releases +- Test on newer releases of openSUSE and Fedora and test on the latest Docker release + +## 2.17.0 (2017-11-10) + +- Update Amazon Linux to default to 17.06.2 + +## 2.16.4 (2017-10-30) + +- quote log_opt + +## 2.16.3 (2017-10-26) + +- add init support to docker_container + +## 2.16.2 (2017-10-05) + +- fix for ip_address not being set + +## 2.16.1 (2017-10-05) + +- added support for env_file property +- bumping to 17.09.0 + +## 2.16.0 (2017-09-18) + +- Use docker-api 1.33.6 which includes a few fixes +- This cookbook actually requires Chef 12.7+ so make sure that's mentioned everywhere +- Simplify debian/ubuntu detection code +- Remove support for long ago EOL Ubuntu distros like 15.04/15.10 +- Update Amazon Linux to default to 17.03.2 + +## 2.15.29 (2017-09-12) + +- Resolve Chef 14 deprecation warnings in docker_network +- Resolve new_resource warnings in docker_service +- Remove yum from the Berksfile + +## 2.15.28 (2017-09-07) + +- bumping to 17.06.2 +- GH-910 image push needs to pass the credentials and a specific tag + +## 2.15.27 (2017-08-31) + +- restart docker on rhel sysvinit changes + +## 2.15.26 (2017-08-25) + +- bumping to 17.06.1 +- support for debian 9 + +## 2.15.25 (2017-08-24) + +- notifying :stop and :start instead of :restart in upstart service manager + +## 2.15.24 (2017-08-20) + +- Supporting env_vars and using in systemd + +## 2.15.23 (2017-08-20) + +- Fixing bug in volumes introduced with namespacing fixes + +## 2.15.22 (2017-08-20) + +- Fixing up deprecation warnings + +## 2.15.21 (2017-08-07) + +- fix to_bytes parsing +- host port can now be a range and matches properly with container port range +- typo on security_opt +- fix for docker_service not containing a listening socket + +## 2.15.20 (2017-08-04) + +- Using stable docker package version numbers + +## 2.15.19 (2017-08-04) + +- reverting default_group +- adding docker group to README + +## 2.15.18 (2017-07-20) + +- create the socket first so restarts on the service unit file don't fail +- redhat defaults to a different group name +- socket group shouldn't be hardcoded +- docker_network: support ipv6 & internal + +## 2.15.17 (2017-07-18) + +- adding restart notifications to upstart and cleaning house on the configs +- fix docker socket group being empty +- bring systemd unit file closer to stock + +## 2.15.16 (2017-07-14) + +- Issue #849 Fix service restarts on OS using systemd + +## 2.15.15 (2017-07-10) + +- upstream systemd config no longer contains the slave mount flag + +## 2.15.14 (2017-07-03) + +- Simplifying kitchen config +- Using dokken-images to speed up tests +- Updating Amazon Linux to default to 17.03.1 +- Package helper for Debian 9 + +## 2.15.13 (2017-06-15) + +- kill_after property default value to nil +- only use --raw-logs argument in versions which support it + +## 2.15.12 (2017-06-13) + +- reverting gem metadata for now as it requires build tools dependency for the json gem + +## 2.15.11 (2017-06-13) + +- make docker.service override match closer to stock + +## 2.15.10 (2017-06-13) + +- adding support for chef >= 12.8 metadata gem installs +- using docker-api 1.33.4 + +## 2.15.9 (2017-06-13) + +- updating systemd docker.service with changes from official docker install +- 12.04 doesn't support docker 17.05.0 + +## 2.15.8 (2017-06-12) + +- Bumping to latest docker version + +## 2.15.7 (2017-06-12) + +- Adding Ubuntu Zesty 17.04 support + +## 2.15.6 (2017-05-01) + +- # 853 - Add network_aliases support + +- # 854 - Expose package_name through the docker_service resource + +## 2.15.5 (2017-04-19) + +- Fixing up memory related API keys +- Adding KernelMemory +- Adding MemorySwappiness +- Adding MemoryReservation +- Fixing MemorySwap convergatude (bug #833) +- Allowing for both integer and string input for all memory values + +## 2.15.4 (2017-04-19) + +- Fixing security_opt property + +## 2.15.3 (2017-04-18) + +- Updating for 17.04.0 + +## 2.15.2 (2017-02-15) + - Reverting 12.15.1 changes -## 12.15.1 (2017-02-15) +## 2.15.1 (2017-02-15) + - 799 - Adding service restarts to systemd template resources -## 12.15.0 (2017-02-15) +## 2.15.0 (2017-02-15) + - Removing dependency on compat_resource. - Now requires Chef 12.5 or higher. -## 12.14.3 (2017-02-14) +## 2.14.3 (2017-02-14) + - Defaulting package installation version to docker 1.13.1 -## 12.14.3 (2017-02-06) +## 2.14.3 (2017-02-06) + - Reverting gem vendor due to c extensions in json dep. - Using docker-api-1.33.2 in _autoload -## 12.14.2 (2017-01-31) +## 2.14.2 (2017-01-31) + - Vendoring docker-api-1.33.2 -## 12.14.1 (2017-01-31) -- defaulting to package installation on amazonlinux +## 2.14.1 (2017-01-31) + +- defaulting to package installation on Amazon Linux ## 2.14.0 (2017-01-31) + - various updates for Docker 1.13.0 - defaulting to 1.13.0 for docker_installation - package name fixes for new debian/ubuntu schemes - defaulting restart_policy to nil in docker_resource ## 2.13.11 (2017-01-25) -- #798 - Temporary "fix" for delayed service restart: using :immediate + +- # 798 - Temporary "fix" for delayed service restart: using :immediate + notification in docker_service resource ## 2.13.10 (2017-01-13) -- #800 - fixing ubuntu startup script -- #802 - using chef_version methong only in 12.6.0 and higher + +- # 800 - fixing ubuntu startup script + +- # 802 - using chef_version metadata property only in 12.6.0 and higher ## 2.13.9 (2016-12-29) + - 793 - Removing service restarts due to chef-client behavior changes. ## 2.13.8 (2016-12-28) -- #794 - network mode bridge + +- # 794 - network mode bridge + - removing emacs package in upstart provider + - Adding dokken / travis test matrix ## 2.13.7 (2016-12-24) + - adding additional logging drivers - adding action :reload ## 2.13.6 (2016-12-22) + - adding ip_address support for docker_containers - adding volume_driver support ## 2.13.5 (2016-12-21) + - Temporary work around for broke upstart provider in chef-client - Fixing package name for ubuntu version later than 1.12.3 ## 2.13.4 (2016-12-20) + - Fixing comparison operator docker daemon args for versions < 1.12 ## 2.13.3 (2016-12-20) + - 792 - Reverting 791 fix ## 2.13.2 (2016-12-20) + - 791 - Fix logic bug in docker_service daemon args calculation ## 2.13.1 (2016-12-19) -- #786 - Adding options hash to docker_volume connection -- #787 - Adding wait loop to docker_service_manager_execute :stop + +- # 786 - Adding options hash to docker_volume connection + +- # 787 - Adding wait loop to docker_service_manager_execute :stop ## 2.13.0 (2016-11-25) + - Adding sysctl property to docker_container resource ## 2.12.0 (2016-11-25) + - Updating compat_resource dep to 12.16.2 - Updating docker-api gem dep 1.32.1 ## 2.11.1 (2016-11-24) + - Fix for #701 - Revert commit that caused restart loops in systemd provider ## 2.11.0 (2016-11-23) + - make systemd MountFlags configurable - make running wait time configurable ## 2.10.0 (2016-11-23) + - Implement network connect/disconnect - Fixed dns options mutual exclusion - Misc test harness cleanup ## 2.9.10 (2016-11-14) + -renaming systemd_conf to systemd_args due to a conflict with systemd cookbook ## 2.9.9 (2016-11-14) --Fixing resource idempotence in labels property --Fix regression introduced by #741, breaking Debian installation --Added ro_rootfs => ReadonlyRootfs special cases mapping --Enable systemd options as a docker_service attribute + +-Fixing resource idempotence in labels property -Fix regression introduced by #741, breaking Debian installation -Added ro_rootfs => ReadonlyRootfs special cases mapping -Enable systemd options as a docker_service attribute ## 2.9.8 (2016-11-08) + - Fixed a typo in an error message - Enable tarball install through docker_service - option log_opt is defined as --log-opt value1 --log-opt value2 instead of --log-opt=value1 --log-opt=value2 - Depend on a working compat_resource cookbook ## 2.9.7 (2016-10-14) + - Require the most recent compat_resource - Get foodcritic passing - Update the Rakefile and use cookstyle @@ -114,34 +473,42 @@ This file is used to list changes made in each version of the docker cookbook. - Add matchers for docker_installation_tarball ## v2.9.6 + - entrypoint not entry_point README - dockerd binary on 1.12+ for upstart - fix docker.socket for systemd ## v2.9.5 + - bumping docker-api gem ## v2.9.4 + - Switch to the dockerd binary on 1.12+ - Add links to resources overview list ## v2.9.3 + - add uts_mode support for docker_container provider (#730) ## v2.9.2 + - adding feature ReadonlyRootfs - bumping docker version to 1.11.2 - removing etcd, fails tests for xenial and swarm will have it builtin in 1.12 ## v2.9.1 + - implement userns_mode for containers ## v2.9.0 + - Feature - docker_installation_tarball resource - Patch - Adding missing http_proxy support to rhel/sysvinit - Patch #705 - Avoid installing docker-api gem in ChefSpec ## v2.8.0 + - Feature - User namespace configuration capability for docker_service ## v2.7.1 @@ -845,7 +1212,7 @@ switching systemd unit MountFlags from slave to private ## v1.0.17 - Fixing up regressions in older Docker API versions introduced in cookbook release 1.0.15 -- _ Adding @api_version instance variable +- Adding @api_version instance variable - Adding serialized_log_config - Adding parsed_network_mode @@ -1518,54 +1885,6 @@ Lots of community contributions this release -- thanks! - Initial release -[#22]: https://github.com/bflad/chef-docker/issues/22 -[#24]: https://github.com/bflad/chef-docker/issues/24 -[#25]: https://github.com/bflad/chef-docker/issues/25 -[#26]: https://github.com/bflad/chef-docker/issues/26 -[#27]: https://github.com/bflad/chef-docker/issues/27 -[#28]: https://github.com/bflad/chef-docker/issues/28 -[#30]: https://github.com/bflad/chef-docker/issues/30 -[#31]: https://github.com/bflad/chef-docker/issues/31 -[#35]: https://github.com/bflad/chef-docker/issues/35 -[#37]: https://github.com/bflad/chef-docker/issues/37 -[#38]: https://github.com/bflad/chef-docker/issues/38 -[#39]: https://github.com/bflad/chef-docker/issues/39 -[#42]: https://github.com/bflad/chef-docker/issues/42 -[#43]: https://github.com/bflad/chef-docker/issues/43 -[#44]: https://github.com/bflad/chef-docker/issues/44 -[#46]: https://github.com/bflad/chef-docker/issues/46 -[#47]: https://github.com/bflad/chef-docker/issues/47 -[#48]: https://github.com/bflad/chef-docker/issues/48 -[#49]: https://github.com/bflad/chef-docker/issues/49 -[#51]: https://github.com/bflad/chef-docker/issues/51 -[#52]: https://github.com/bflad/chef-docker/issues/52 -[#55]: https://github.com/bflad/chef-docker/issues/55 -[#56]: https://github.com/bflad/chef-docker/issues/56 -[#57]: https://github.com/bflad/chef-docker/issues/57 -[#58]: https://github.com/bflad/chef-docker/issues/58 -[#59]: https://github.com/bflad/chef-docker/issues/59 -[#60]: https://github.com/bflad/chef-docker/issues/60 -[#62]: https://github.com/bflad/chef-docker/issues/62 -[#63]: https://github.com/bflad/chef-docker/issues/63 -[#64]: https://github.com/bflad/chef-docker/issues/64 -[#65]: https://github.com/bflad/chef-docker/issues/65 -[#67]: https://github.com/bflad/chef-docker/issues/67 -[#68]: https://github.com/bflad/chef-docker/issues/68 -[#72]: https://github.com/bflad/chef-docker/issues/72 -[#77]: https://github.com/bflad/chef-docker/issues/77 -[#78]: https://github.com/bflad/chef-docker/issues/78 -[#80]: https://github.com/bflad/chef-docker/issues/80 -[#81]: https://github.com/bflad/chef-docker/issues/81 -[#82]: https://github.com/bflad/chef-docker/issues/82 -[#83]: https://github.com/bflad/chef-docker/issues/83 -[#84]: https://github.com/bflad/chef-docker/issues/84 -[#85]: https://github.com/bflad/chef-docker/issues/85 -[#86]: https://github.com/bflad/chef-docker/issues/86 -[#88]: https://github.com/bflad/chef-docker/issues/88 -[#89]: https://github.com/bflad/chef-docker/issues/89 -[#90]: https://github.com/bflad/chef-docker/issues/90 -[#91]: https://github.com/bflad/chef-docker/issues/91 -[#98]: https://github.com/bflad/chef-docker/issues/98 [#101]: https://github.com/bflad/chef-docker/issues/101 [#103]: https://github.com/bflad/chef-docker/issues/103 [#104]: https://github.com/bflad/chef-docker/issues/104 @@ -1634,6 +1953,7 @@ Lots of community contributions this release -- thanks! [#208]: https://github.com/bflad/chef-docker/issues/208 [#217]: https://github.com/bflad/chef-docker/issues/217 [#219]: https://github.com/bflad/chef-docker/issues/219 +[#22]: https://github.com/bflad/chef-docker/issues/22 [#220]: https://github.com/bflad/chef-docker/issues/220 [#221]: https://github.com/bflad/chef-docker/issues/221 [#223]: https://github.com/bflad/chef-docker/issues/223 @@ -1644,14 +1964,17 @@ Lots of community contributions this release -- thanks! [#237]: https://github.com/bflad/chef-docker/issues/237 [#238]: https://github.com/bflad/chef-docker/issues/238 [#239]: https://github.com/bflad/chef-docker/issues/239 +[#24]: https://github.com/bflad/chef-docker/issues/24 [#240]: https://github.com/bflad/chef-docker/issues/240 [#242]: https://github.com/bflad/chef-docker/issues/242 [#244]: https://github.com/bflad/chef-docker/issues/244 [#245]: https://github.com/bflad/chef-docker/issues/245 [#246]: https://github.com/bflad/chef-docker/issues/246 +[#25]: https://github.com/bflad/chef-docker/issues/25 [#250]: https://github.com/bflad/chef-docker/issues/250 [#258]: https://github.com/bflad/chef-docker/issues/258 [#259]: https://github.com/bflad/chef-docker/issues/259 +[#26]: https://github.com/bflad/chef-docker/issues/26 [#260]: https://github.com/bflad/chef-docker/issues/260 [#263]: https://github.com/bflad/chef-docker/issues/263 [#264]: https://github.com/bflad/chef-docker/issues/264 @@ -1660,8 +1983,10 @@ Lots of community contributions this release -- thanks! [#267]: https://github.com/bflad/chef-docker/issues/267 [#268]: https://github.com/bflad/chef-docker/issues/268 [#269]: https://github.com/bflad/chef-docker/issues/269 +[#27]: https://github.com/bflad/chef-docker/issues/27 [#276]: https://github.com/bflad/chef-docker/issues/276 [#279]: https://github.com/bflad/chef-docker/issues/279 +[#28]: https://github.com/bflad/chef-docker/issues/28 [#280]: https://github.com/bflad/chef-docker/issues/280 [#281]: https://github.com/bflad/chef-docker/issues/281 [#284]: https://github.com/bflad/chef-docker/issues/284 @@ -1672,5 +1997,47 @@ Lots of community contributions this release -- thanks! [#296]: https://github.com/bflad/chef-docker/issues/296 [#297]: https://github.com/bflad/chef-docker/issues/297 [#298]: https://github.com/bflad/chef-docker/issues/298 +[#30]: https://github.com/bflad/chef-docker/issues/30 +[#31]: https://github.com/bflad/chef-docker/issues/31 +[#35]: https://github.com/bflad/chef-docker/issues/35 +[#37]: https://github.com/bflad/chef-docker/issues/37 +[#38]: https://github.com/bflad/chef-docker/issues/38 +[#39]: https://github.com/bflad/chef-docker/issues/39 +[#42]: https://github.com/bflad/chef-docker/issues/42 +[#43]: https://github.com/bflad/chef-docker/issues/43 +[#44]: https://github.com/bflad/chef-docker/issues/44 +[#46]: https://github.com/bflad/chef-docker/issues/46 +[#47]: https://github.com/bflad/chef-docker/issues/47 +[#48]: https://github.com/bflad/chef-docker/issues/48 +[#49]: https://github.com/bflad/chef-docker/issues/49 +[#51]: https://github.com/bflad/chef-docker/issues/51 +[#52]: https://github.com/bflad/chef-docker/issues/52 +[#55]: https://github.com/bflad/chef-docker/issues/55 +[#56]: https://github.com/bflad/chef-docker/issues/56 +[#57]: https://github.com/bflad/chef-docker/issues/57 +[#58]: https://github.com/bflad/chef-docker/issues/58 +[#59]: https://github.com/bflad/chef-docker/issues/59 +[#60]: https://github.com/bflad/chef-docker/issues/60 +[#62]: https://github.com/bflad/chef-docker/issues/62 +[#63]: https://github.com/bflad/chef-docker/issues/63 +[#64]: https://github.com/bflad/chef-docker/issues/64 +[#65]: https://github.com/bflad/chef-docker/issues/65 +[#67]: https://github.com/bflad/chef-docker/issues/67 +[#68]: https://github.com/bflad/chef-docker/issues/68 +[#72]: https://github.com/bflad/chef-docker/issues/72 +[#77]: https://github.com/bflad/chef-docker/issues/77 +[#78]: https://github.com/bflad/chef-docker/issues/78 +[#80]: https://github.com/bflad/chef-docker/issues/80 +[#81]: https://github.com/bflad/chef-docker/issues/81 +[#82]: https://github.com/bflad/chef-docker/issues/82 +[#83]: https://github.com/bflad/chef-docker/issues/83 +[#84]: https://github.com/bflad/chef-docker/issues/84 +[#85]: https://github.com/bflad/chef-docker/issues/85 +[#86]: https://github.com/bflad/chef-docker/issues/86 +[#88]: https://github.com/bflad/chef-docker/issues/88 +[#89]: https://github.com/bflad/chef-docker/issues/89 +[#90]: https://github.com/bflad/chef-docker/issues/90 +[#91]: https://github.com/bflad/chef-docker/issues/91 +[#98]: https://github.com/bflad/chef-docker/issues/98 [@jcrobak]: https://github.com/jcrobak [@wingrunr21]: https://github.com/wingrunr21 diff --git a/chef/cookbooks/docker/Gemfile b/chef/cookbooks/docker/Gemfile new file mode 100644 index 0000000..5492f0d --- /dev/null +++ b/chef/cookbooks/docker/Gemfile @@ -0,0 +1,13 @@ +# This gemfile provides additional gems for testing and releasing this cookbook +# It is meant to be installed on top of ChefDK which provides the majority +# of the necessary gems for testing this cookbook +# +# Run 'chef exec bundle install' to install these dependencies + +source 'https://rubygems.org' + +gem 'berkshelf' +gem 'community_cookbook_releaser' +gem 'kitchen-dokken' +gem 'kitchen-inspec' +gem 'test-kitchen' diff --git a/chef/cookbooks/docker/LICENSE b/chef/cookbooks/docker/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/chef/cookbooks/docker/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/chef/cookbooks/docker/MAINTAINERS.md b/chef/cookbooks/docker/MAINTAINERS.md deleted file mode 100644 index a7645b9..0000000 --- a/chef/cookbooks/docker/MAINTAINERS.md +++ /dev/null @@ -1,20 +0,0 @@ - - -# Maintainers - -This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. - -# Project Maintainer -* [Sean OMeara](https://github.com/someara) - -# Maintainers -* [Jennifer Davis](https://github.com/sigje) -* [Sean OMeara](https://github.com/someara) -* [Tim Smith](https://github.com/tas50) -* [Thom May](https://github.com/thommay) -* [Anthony Scalisi](https://github.com/scalp42) -* [Chase Bolt](https://github.com/chasebolt) -* [Brian Flad](https://github.com/bflad) -* [Tom Duffield](https://github.com/tduffield) diff --git a/chef/cookbooks/docker/README.md b/chef/cookbooks/docker/README.md index e6ac39b..05bbbda 100644 --- a/chef/cookbooks/docker/README.md +++ b/chef/cookbooks/docker/README.md @@ -1,56 +1,46 @@ # Docker Cookbook -[![Build Status](https://travis-ci.org/chef-cookbooks/docker.svg?branch=master)](https://travis-ci.org/chef-cookbooks/docker) -[![Cookbook Version](https://img.shields.io/cookbook/v/docker.svg)](https://supermarket.chef.io/cookbooks/docker) -[![Gitter](https://badges.gitter.im/Join -Chat.svg)](https://gitter.im/someara/chef-docker?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Build Status](https://travis-ci.org/chef-cookbooks/docker.svg?branch=master)](https://travis-ci.org/chef-cookbooks/docker) [![Cookbook Version](https://img.shields.io/cookbook/v/docker.svg)](https://supermarket.chef.io/cookbooks/docker) -The Docker Cookbook is a library cookbook that provides custom -resources for use in recipes. +The Docker Cookbook provides resources for installing docker as well as building, managing, and running docker containers. ## Scope -This cookbook is concerned with the [Docker](http://docker.io) -container engine as distributed by Docker, Inc. It does not address -Docker ecosystem tooling or prerequisite technology such as cgroups or -aufs. - +This cookbook is concerned with the [Docker](http://docker.io) container engine as distributed by Docker, Inc. It does not address Docker ecosystem tooling or prerequisite technology such as cgroups or aufs. ## Requirements -- Chef 12.5.x or higher. Chef 11 is NOT SUPPORTED, please do not open issues about it. -- Ruby 2.1 or higher (preferably, the Chef full-stack installer) +- Chef 12.15 or later - Network accessible web server hosting the docker binary. - SELinux permissive/disabled if CentOS [Docker Issue #15498](https://github.com/docker/docker/issues/15498) ## Platform Support -The following platforms have been tested with Test Kitchen: You may be -able to get it working on other platforms, with appropriate -configuration of cgroups and storage back ends. - -| | 1.7.1 | 1.8.3 | 1.9.1 | 1.10.3 | 1.11.1 | 1.12.3 | 1.13.0 | -|--------------|:-----:|:------|:-----:|:------:|:------:|:------:|:-------| -| amazon linux | | | | | | | ✔ | -| debian-7 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| debian-8 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| centos-7 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| fedora | | | ✔ | ✔ | ✔ | ✔ | ✔ | -| ubuntu-12.04 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| ubuntu-14.04 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| ubuntu-16.04 | | | | | ✔ | ✔ | ✔ | - +- Amazon Linux +- Debian 8/9 +- Fedora +- Ubuntu 14.04/16.04 +- CentOS 7 ## Cookbook Dependencies -- [compat_resource](https://supermarket.chef.io/cookbooks/compat_resource) +This cookbook automatically sets up the upstream Docker package repositories. If you would like to use your own repositories this functionality can be disabled and you can instead setup the repos yourself with yum_repository/apt_repository resources or the [chef-apt-docker](https://supermarket.chef.io/cookbooks/chef-apt-docker) / [chef-yum-docker](https://supermarket.chef.io/cookbooks/chef-yum-docker) cookbooks. + +## Docker Group + +If you are not using the official docker repositories you may run into issues with the docker group being different. RHEL is a known issue that defaults to using `dockerroot` for the service group. Add the `group` property to the `docker_service`. + +```ruby +docker_service 'default' do + group 'dockerroot' + action [:create, :start] +end +``` ## Usage -- Add `depends 'docker', '~> 2.0'` to your cookbook's metadata.rb -- Use the resources shipped in cookbook in a recipe, the same way - you'd use core Chef resources (file, template, directory, package, - etc). +- Add `depends 'docker'` to your cookbook's metadata.rb +- Use the resources shipped in cookbook in a recipe, the same way you'd use core Chef resources (file, template, directory, package, etc). ```ruby docker_service 'default' do @@ -74,60 +64,32 @@ The cookbooks ran under test-kitchen make excellent usage examples. The test recipes are found at: -```ruby +``` test/cookbooks/docker_test/ ``` -## Cgroups, Execution and Storage drivers - -Beginning in chef-docker 1.0, support for LXC execution driver has -been removed in favor of native. Cgroups and storage drivers are now -loosely coupled dependencies and should be configured using other -cookbooks if needed. - -Storage drivers can be selected with the `storage_driver` property on -the `docker_service` resource like this: - -```ruby -docker_service 'default' do - storage_driver 'zfs' -end -``` - -Configuration of the backing storage driver, including kernel module loading, is out of scope for this cookbook. - ## Resources Overview -- [docker_service](#docker_service): composite resource that uses - docker_installation and docker_service_manager -- [docker_installation](#docker_installation): automatically select an - installation method -- [docker_service_manager](#docker_service_manager): automatically - selects a service manager -- [docker_installation_binary](#docker_installation_binary): copies a - pre-compiled docker binary onto disk +- [docker_service](#docker_service): composite resource that uses docker_installation and docker_service_manager +- [docker_installation](#docker_installation): automatically select an installation method +- [docker_service_manager](#docker_service_manager): automatically selects a service manager - [docker_installation_script](#docker_installation_script): curl | bash -- [docker_installation_package](#docker_installation_package): package - 'docker-engine' -- [docker_service_manager_execute](#docker_service_manager_execute): - manage docker daemon with Chef -- [docker_service_manager_sysvinit](#docker_service_manager_sysvinit): - manage docker daemon with a sysvinit script -- [docker_service_manager_upstart](#docker_service_manager_upstart): - manage docker daemon with upstart script -- [docker_service_manager_systemd](#docker_service_manager_systemd): - manage docker daemon with systemd unit files +- [docker_installation_package](#docker_installation_package): package 'docker-ce' +- [docker_service_manager_execute](#docker_service_manager_execute): manage docker daemon with Chef +- [docker_service_manager_sysvinit](#docker_service_manager_sysvinit): manage docker daemon with a sysvinit script +- [docker_service_manager_upstart](#docker_service_manager_upstart): manage docker daemon with upstart script +- [docker_service_manager_systemd](#docker_service_manager_systemd): manage docker daemon with systemd unit files - [docker_image](#docker_image): image/repository operations - [docker_container](#docker_container): container operations - [docker_tag](#docker_tag): image tagging operations - [docker_registry](#docker_registry): registry operations - [docker_network](#docker_network): network operations - [docker_volume](#docker_volume): volume operations +- [docker_plugin](#docker_plugin): plugin operations ## Getting Started -Here's a quick example of pulling the latest image and running a -container with exposed ports. +Here's a quick example of pulling the latest image and running a container with exposed ports. ```ruby # Pull latest image @@ -137,7 +99,7 @@ docker_image 'nginx' do notifies :redeploy, 'docker_container[my_nginx]' end -# Run container exposing ports +# Run container mapping containers port 80 to the host's port 80 docker_container 'my_nginx' do repo 'nginx' tag 'latest' @@ -203,49 +165,21 @@ end See full documentation for each resource and action below for more information. -## Resources Details +## Resources + ## docker_installation -The `docker_installation` resource auto-selects one of the below -resources with the provider resolution system. +The `docker_installation` resource auto-selects one of the below resources with the provider resolution system. ### Example ```ruby -docker_installation 'default' do - action :create -end +docker_installation 'default' ``` -## docker_installation_binary - -The `docker_installation_binary` resource copies the precompiled Go -binary onto the disk. It exists to help run older Docker versions. It -should not be used in production, especially with devicemapper. - -### Example - -```ruby -docker_installation_binary 'default' do - version '1.8.2' - source 'https://my.computers.biz/dist/docker' - checksum '97a3f5924b0b831a310efa8bf0a4c91956cd6387c4a8667d27e2b2dd3da67e4d' - action :create -end -``` - -### Properties - -- `version` - The desired version of docker. Used to calculate source. -- `source` - Path to network accessible Docker binary. Ignores version -- `checksum` - SHA-256 - ## docker_installation_tarball -The `docker_installation_tarball` resource copies the precompiled Go -binary tarball onto the disk. It exists to help run newer Docker -versions from 1.11.0 onwards. It should not be used in production, -especially with devicemapper. +The `docker_installation_tarball` resource copies the precompiled Go binary tarball onto the disk. It should not be used in production, especially with devicemapper. ### Example @@ -260,16 +194,14 @@ end ### Properties -- `version` - The desired version of docker. Used to calculate source. -- `source` - Path to network accessible Docker binary tarball. Ignores - version -- `checksum` - SHA-256 +- `version` - The desired version of docker to fetch. +- `channel` - The docker channel to fetch the tarball from. Default: stable +- `source` - Path to network accessible Docker binary tarball. Ignores version when set. +- `checksum` - SHA-256 checksum of the tarball file. ## docker_installation_script -The `docker_installation_script` resource runs the script hosted by -Docker, Inc at . It configures package -repositories and installs a dynamically compiled binary. +The `docker_installation_script` resource runs the script hosted by Docker, Inc at . It configures package repositories and installs a dynamically compiled binary. ### Example @@ -283,17 +215,12 @@ end ### Properties -- `repo` - One of 'main', 'test', or 'experimental'. Used to calculate - script_url in its absense. Defaults to 'main' +- `repo` - One of 'main', 'test', or 'experimental'. Used to calculate script_url in its absence. Defaults to 'main' - `script_url` - 'URL of script to pipe into /bin/sh as root. ## docker_installation_package -The `docker_installation_package` resource uses the system package -manager to install Docker. It relies on the pre-configuration of the -system's package repositories. The `chef-yum-docker` and -`chef-apt-docker` Supermarket cookbooks are used to do this in -test-kitchen. +The `docker_installation_package` resource uses the system package manager to install Docker. It relies on the pre-configuration of the system's package repositories. The `chef-yum-docker` and `chef-apt-docker` Supermarket cookbooks can be used to use Docker's own repositories. **_This is the recommended production installation method._** @@ -311,16 +238,14 @@ end - `version` - Used to calculate package_version string - `package_version` - Manually specify the package version string -- `package_name` - Name of package to install. Defaults to - 'docker-engine' -- `package_options` - Manually specify additional options, like - apt-get directives for example +- `package_name` - Name of package to install. Defaults to 'docker-ce' +- `package_options` - Manually specify additional options, like apt-get directives for example +- `setup_docker_repo` - Setup the download.docker.com repo. If you would like to manage the repo yourself so you can use an internal repo then set this to false. default: true on all platforms except Amazon Linux. +- `repo_channel` - The channel of docker to setup from download.docker.com. Only used if `setup_docker_repo` is true. default: 'stable' ## docker_service_manager -The `docker_service_manager` resource auto-selects a strategy from the -`docker_service_manager_*` group of resources based on platform and -version. The `docker_service` family share a common set of properties. +The `docker_service_manager` resource auto-selects a strategy from the `docker_service_manager_*` group of resources based on platform and version. The `docker_service` family share a common set of properties. ### Example @@ -376,22 +301,21 @@ docker_service_manager_systemd 'default' do tls_client_cert "/path/to/cert.pem" tls_client_key "/path/to/key.pem" systemd_opts ["TasksMax=infinity","MountFlags=private"] + systemd_socket_opts ["Accept=yes"] action :start end ``` ## docker_service -The `docker_service`: resource is a composite resource that uses -`docker_installation` and `docker_service_manager` resources. +The `docker_service`: resource is a composite resource that uses `docker_installation` and `docker_service_manager` resources. - The `:create` action uses a `docker_installation` - The `:delete` action uses a `docker_installation` - The `:start` action uses a `docker_service_manager` - The `:stop` action uses a `docker_service_manager` -The service management strategy for the host platform is dynamically -chosen based on platform, but can be overridden. +The service management strategy for the host platform is dynamically chosen based on platform, but can be overridden. ### Example @@ -408,91 +332,82 @@ docker_service 'tls_test:2376' do end ``` -WARNING - When creating multiple `docker_service` resources on the -same machine, you will need to specify unique graph properties to -avoid unexpected behavior and possible data corruption. +WARNING - When creating multiple `docker_service` resources on the same machine, you will need to specify unique data_root properties to avoid unexpected behavior and possible data corruption. ### Properties -The `docker_service` resource property list mostly corresponds to the -options found in the -[Docker Command Line Reference](https://docs.docker.com/reference/commandline/cli/) +The `docker_service` resource property list mostly corresponds to the options found in the [Docker Command Line Reference](https://docs.docker.com/engine/reference/commandline/docker/) -- `install_method` - Select binary, script, package, tarball, none, or auto. Defaults to `auto`. -- `source` - URL to the pre-compiled Docker binary used for installation. Defaults to a calculated URL based on kernel version, Docker version, and platform arch. By default, this will try to get to "". -- `version` - Docker version to install -- `checksum` - sha256 checksum of Docker binary - `api_cors_header` - Set CORS headers in the remote API -- `bridge` - Attach containers to a network bridge +- `auto_restart` +- `exec_opts` - `bip` - Specify network bridge IP -- `debug` - Enable debug mode -- `cluster_store` - Cluster store to use -- `cluster_advertise` - IP and port that this daemon should advertise - to the cluster +- `bridge` - Attach containers to a network bridge +- `checksum` - sha256 checksum of Docker binary +- `cluster_advertise` - IP and port that this daemon should advertise to the cluster - `cluster_store_opts` - Cluster store options +- `cluster_store` - Cluster store to use - `daemon` - Enable daemon mode -- `dns` - DNS server(s) to use -- `dns_search` - DNS search domains to use -- `exec_driver` - Exec driver to use -- `fixed_cidr` - IPv4 subnet for fixed IPs -- `fixed_cidr_v6` - IPv6 subnet for fixed IPs -- `group` - Posix group for the unix socket -- `graph` - Root of the Docker runtime - Effectively, the "data - directory" -- `host` - Daemon socket(s) to connect to - `tcp://host:port`, - `unix:///path/to/socket`, `fd://*` or `fd://socketfd` -- `icc` - Enable inter-container communication -- `insecure_registry` - Enable insecure registry communication -- `ip` - Default IP when binding container ports -- `ip_forward` - Enable ip forwarding -- `ipv4_forward` - Enable net.ipv4.ip_forward -- `ipv6_forward` - Enable net.ipv6.ip_forward -- `ip_masq` - Enable IP masquerading -- `iptables` - Enable addition of iptables rules -- `ipv6` - Enable IPv6 networking -- `log_level` - Set the logging level -- `labels` A string or array to set metadata on the daemon in the form ['foo:bar', 'hello:world']` -- `log_driver` - Container's logging driver (json-file/syslog/journald/gelf/fluentd/none) -- `labels` A string or array to set metadata on the daemon in the form ['foo:bar', 'hello:world']` -- `log_driver` - Container's logging driver (json-file/syslog/journald/gelf/fluentd/awslogs/splunk/etwlogs/gcplogs/none) -- `log_opts` - Container's logging driver options (driver-specific) -- `mtu` - Set the containers network MTU -- `pidfile` - Path to use for daemon PID file -- `registry_mirror` - Preferred Docker registry mirror -- `storage_driver` - Storage driver to use -- `selinux_enabled` - Enable selinux support -- `storage_opts` - Set storage driver options -- `tls` - Use TLS; implied by --tlsverify. Defaults to ENV['DOCKER_TLS'] if set -- `tls_verify` - Use TLS and verify the remote. Defaults to ENV['DOCKER_TLS_VERIFY'] if set -- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to ENV['DOCKER_CERT_PATH'] if set -- `tls_server_cert` - Path to TLS certificate file for docker service -- `tls_server_key` - Path to TLS key file for docker service -- `tls_client_cert` - Path to TLS certificate file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set -- `tls_client_key` - Path to TLS key file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `data_root` - Root of the Docker runtime +- `debug` - Enable debug mode +- `default_ip_address_pool` - Set the default address pool for networks creates by docker - `default_ulimit` - Set default ulimit settings for containers +- `disable_legacy_registry` - Do not contact legacy registries +- `dns_search` - DNS search domains to use +- `dns` - DNS server(s) to use +- `exec_driver` - Exec driver to use +- `fixed_cidr_v6` - IPv6 subnet for fixed IPs +- `fixed_cidr` - IPv4 subnet for fixed IPs +- `group` - Posix group for the unix socket. Default to `docker` +- `host` - Daemon socket(s) to connect to - `tcp://host:port`, `unix:///path/to/socket`, `fd://*` or `fd://socketfd` - `http_proxy` - ENV variable set before for Docker daemon starts - `https_proxy` - ENV variable set before for Docker daemon starts -- `no_proxy` - ENV variable set before for Docker daemon starts -- `tmpdir` - ENV variable set before for Docker daemon starts +- `icc` - Enable inter-container communication +- `insecure_registry` - Enable insecure registry communication +- `install_method` - Select script, package, tarball, none, or auto. Defaults to `auto`. +- `instance`- Optional property used to override the name provided in the resource. +- `ip_forward` - Enable ip forwarding +- `ip_masq` - Enable IP masquerading +- `ip` - Default IP when binding container ports +- `iptables` - Enable addition of iptables rules +- `ipv4_forward` - Enable net.ipv4.ip_forward +- `ipv6_forward` - Enable net.ipv6.ip_forward +- `ipv6` - Enable IPv6 networking +- `labels` A string or array to set metadata on the daemon in the form ['foo:bar', 'hello:world']` +- `log_driver` - Container's logging driver (json-file/syslog/journald/gelf/fluentd/awslogs/splunk/etwlogs/gcplogs/none) +- `log_level` - Set the logging level +- `log_opts` - Container's logging driver options (driver-specific) - `logfile` - Location of Docker daemon log file +- `mount_flags` - Set the systemd mount propagation flag. +- `mtu` - Set the containers network MTU +- `no_proxy` - ENV variable set before for Docker daemon starts +- `package_name` - Set the package name. Defaults to `docker-ce` +- `pidfile` - Path to use for daemon PID file +- `registry_mirror` - Preferred Docker registry mirror +- `selinux_enabled` - Enable selinux support +- `source` - URL to the pre-compiled Docker binary used for installation. Defaults to a calculated URL based on kernel version, Docker version, and platform arch. By default, this will try to get to "". +- `storage_driver` - Storage driver to use +- `storage_opts` - Set storage driver options +- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `tls_client_cert` - Path to TLS certificate file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `tls_client_key` - Path to TLS key file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `tls_server_cert` - Path to TLS certificate file for docker service +- `tls_server_key` - Path to TLS key file for docker service +- `tls_verify` - Use TLS and verify the remote. Defaults to ENV['DOCKER_TLS_VERIFY'] if set +- `tls` - Use TLS; implied by --tlsverify. Defaults to ENV['DOCKER_TLS'] if set +- `tmpdir` - ENV variable set before for Docker daemon starts - `userland_proxy`- Enables or disables docker-proxy -- `disable_legacy_registry` - Do not contact legacy registries -- `userns_remap` - Enable user namespace remapping options - - `default`, `uid`, `uid:gid`, `username`, `username:groupname` (see: [Docker User Namespaces](see: https://docs.docker.com/v1.10/engine/reference/commandline/daemon/#daemon-user-namespace-options)) -- `mount_flags` - Set the systemd mount propagation flag. Defaults to slave. +- `userns_remap` - Enable user namespace remapping options - `default`, `uid`, `uid:gid`, `username`, `username:groupname` (see: [Docker User Namespaces](see: https://docs.docker.com/v1.10/engine/reference/commandline/daemon/#daemon-user-namespace-options)) +- `version` - Docker version to install #### Miscellaneous Options -- `misc_opts` - Pass the docker daemon any other options bypassing - flag validation, supplied as `--flag=value` +- `misc_opts` - Pass the docker daemon any other options bypassing flag validation, supplied as `--flag=value` #### Systemd-specific Options -- `systemd_opts` - An array of strings that will be included as - individual lines in the systemd service unit for Docker. *Note*: - This option is only relevant for systems where systemd is the - default service manager or where systemd is specified explicitly as - the service manager. +- `systemd_opts` - An array of strings that will be included as individual lines in the systemd service unit for Docker. _Note_: This option is only relevant for systems where systemd is the default service manager or where systemd is specified explicitly as the service manager. +- `systemd_socket_opts` - An array of strings that will be included as individual lines in the systemd socket unit for Docker. _Note_: This option is only relevant for systems where systemd is the default service manager or where systemd is specified explicitly as the service manager. ### Actions @@ -504,20 +419,51 @@ options found in the ### `docker_service` implementations -- `docker_service_execute` - The simplest docker_service. Just starts - a process. Fire and forget. -- `docker_service_sysvinit` - Uses a SystemV init script to manage the - service state. -- `docker_service_upstart` - Uses an Upstart script to manage the - service state. -- `docker_service_systemd` - Uses an Systemd unit file to manage the - service state. NOTE: This does NOT enable systemd socket activation. +- `docker_service_execute` - The simplest docker_service. Just starts a process. Fire and forget. +- `docker_service_sysvinit` - Uses a SystemV init script to manage the service state. +- `docker_service_upstart` - Uses an Upstart script to manage the service state. +- `docker_service_systemd` - Uses an Systemd unit file to manage the service state. NOTE: This does NOT enable systemd socket activation. ## docker_image -The `docker_image` is responsible for managing Docker image pulls, -builds, and deletions. It speaks directly to the -[Docker remote API](https://docs.docker.com/reference/api/docker_remote_api_v1.20/). +The `docker_image` is responsible for managing Docker image pulls, builds, and deletions. It speaks directly to the [Docker Engine API](https://docs.docker.com/engine/api/v1.35/#tag/Image). + +### Actions + +- `:pull` - Pulls an image from the registry. Default action. +- `:pull_if_missing` - Pulls an image from the registry, only if it missing +- `:build` - Builds an image from a Dockerfile, directory, or tarball +- `:build_if_missing` - Same build, but only if it is missing +- `:save` - Exports an image to a tarball at `destination` +- `:import` - Imports an image from a tarball at `destination` +- `:remove` - Removes (untags) an image +- `:push` - Pushes an image to the registry + +### Properties + +The `docker_image` resource properties mostly corresponds to the [Docker Engine API](https://docs.docker.com/engine/api/v1.35/#tag/Image) as driven by the [docker-api Ruby gem](https://github.com/swipely/docker-api) + +A `docker_image`'s full identifier is a string in the form "\ + +:\". There is some nuance around naming using the +public registry vs a private one. + +- `repo` - aka `image_name` - The first half of a Docker image's identity. This is a string in the form: `registry:port/owner/image_name`. If the `registry:port` portion is left off, Docker will implicitly use the Docker public registry. "Official Images" omit the owner part. This means a repo id can be as short as `busybox`, `alpine`, or `centos`. These names refer to official images on the public registry. Names can be as long as `my.computers.biz:5043/what/ever` to refer to custom images on an private registry. Often you'll see something like `chef/chef` to refer to private images on the public registry. - Defaults to resource name. +- `tag` - The second half of a Docker image's identity. - Defaults to `latest` +- `source` - Path to input for the `:import`, `:build` and `:build_if_missing` actions. For building, this can be a Dockerfile, a tarball containing a Dockerfile in its root, or a directory containing a Dockerfile. For `:import`, this should be a tarball containing Docker formatted image, as generated with `:save`. +- `destination` - Path for output from the `:save` action. +- `force` - A force boolean used in various actions - Defaults to false +- `nocache` - Used in `:build` operations. - Defaults to false +- `noprune` - Used in `:remove` operations - Defaults to false +- `rm` - Remove intermediate containers after a successful build (default behavior) - Defaults to `true` +- `read_timeout` - May need to increase for long image builds/pulls +- `write_timeout` - May need to increase for long image builds/pulls +- `host` - A string containing the host the API should communicate with. Defaults to `ENV['DOCKER_HOST']` if set. +- `tls` - Use TLS; implied by --tlsverify. Defaults to ENV['DOCKER_TLS'] if set. +- `tls_verify` - Use TLS and verify the remote. Defaults to `ENV['DOCKER_TLS_VERIFY']` if set +- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to `ENV['DOCKER_CERT_PATH']` if set. +- `tls_client_cert` - Path to TLS certificate file for docker cli. Defaults to `ENV['DOCKER_CERT_PATH']` if set +- `tls_client_key` - Path to TLS key file for docker cli. Defaults to `ENV['DOCKER_CERT_PATH']` if set. ### Examples @@ -527,7 +473,7 @@ builds, and deletions. It speaks directly to the docker_image 'hello-world' ``` -- non-default name attribute +- non-default name property ```ruby docker_image "Tom's container" do @@ -598,9 +544,7 @@ docker_image 'image_2' do end ``` -- build from a tarball NOTE: this is not an "export" tarball generated - from an an image save. The contents should be a Dockerfile, and - anything it references to COPY or ADD +- build from a tarball NOTE: this is not an "export" tarball generated from an an image save. The contents should be a Dockerfile, and anything it references to COPY or ADD ```ruby docker_image 'image_3' do @@ -624,7 +568,7 @@ end docker_image 'my.computers.biz:5043/someara/hello-again' do action :push end - ``` +``` - Connect to an external docker daemon and pull an image @@ -635,77 +579,58 @@ docker_image 'alpine' do end ``` -### Properties +## docker_image_prune -The `docker_image` resource properties mostly corresponds to the -[Docker Remote API](https://docs.docker.com/reference/api/docker_remote_api_v1.20/#2-2-images) -as driven by the -[Swipley docker-api Ruby gem](https://github.com/swipely/docker-api) - - -A `docker_image`'s full identifier is a string in the form -"\:\". There is some nuance around naming using the -public registry vs a private one. - -- `repo` - aka `image_name` - The first half of a Docker image's - identity. This is a string in the form: - `registry:port/owner/image_name`. If the `registry:port` portion is - left off, Docker will implicitly use the Docker public - registry. "Official Images" omit the owner part. This means a repo - id can be as short as `busybox`, `alpine`, or `centos`. These names refer - to official images on the public registry. Names can be as long as - `my.computers.biz:5043/what/ever` to refer to custom images on an - private registry. Often you'll see something like `chef/chef` to - refer to private images on the public registry. - Defaults to - resource name. -- `tag` - The second half of a Docker image's identity. - Defaults to - `latest` -- `source` - Path to input for the `:import`, `:build` and - `:build_if_missing` actions. For building, this can be a Dockerfile, - a tarball containing a Dockerfile in its root, or a directory - containing a Dockerfile. For `:import`, this should be a tarball - containing Docker formatted image, as generated with `:save`. -- `destination` - Path for output from the `:save` action. -- `force` - A force boolean used in various actions - Defaults to - false -- `nocache` - Used in `:build` operations. - Defaults to false -- `noprune` - Used in `:remove` operations - Defaults to false -- `rm` - Remove intermediate containers after a successful build - (default behavior) - Defaults to `true` -- `read_timeout` - May need to increase for long image builds/pulls -- `write_timeout` - May need to increase for long image builds/pulls -- `host` - A string containing the host the API should communicate - with. Defaults to `ENV['DOCKER_HOST']` if set. -- `tls` - Use TLS; implied by --tlsverify. Defaults to - ENV['DOCKER_TLS'] if set. -- `tls_verify` - Use TLS and verify the remote. Defaults to - `ENV['DOCKER_TLS_VERIFY']` if set -- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to - `ENV['DOCKER_CERT_PATH']` if set. -- `tls_client_cert` - Path to TLS certificate file for docker - cli. Defaults to `ENV['DOCKER_CERT_PATH']` if set -- `tls_client_key` - Path to TLS key file for docker cli. Defaults to - `ENV['DOCKER_CERT_PATH']` if set. +The `docker_image_prune` is responsible for pruning Docker images from the system. It speaks directly to the [Docker Engine API](https://docs.docker.com/engine/api/v1.35/#operation/ImagePrune). +Note - this is best implemented by subscribing to `docker_image` changes. There is no need to to clean up old images upon each converge. It is best done at the end of a chef run (delayed) only if a new image was pulled. ### Actions -The following actions are available for a `docker_image` -resource. Defaults to `pull_if_missing` +- `:prune` - Delete unused images -- `:pull` - Pulls an image from the registry -- `:pull_if_missing` - Pulls an image from the registry, only if it missing -- `:build` - Builds an image from a Dockerfile, directory, or tarball -- `:build_if_missing` - Same build, but only if it is missing -- `:save` - Exports an image to a tarball at `destination` -- `:import` - Imports an image from a tarball at `destination` -- `:remove` - Removes (untags) an image -- `:push` - Pushes an image to the registry +### Properties + +The `docker_image_prune` resource properties map to filters + +- `dangling` - When set to true (or 1), prune only unused and untagged images. When set to false (or 0), all unused images are pruned +- `prune_until` - Prune images created before this timestamp. The can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time. +- `with_label/without_label` - (label=, label==, label!=, or label!==) Prune images with (or without, in case label!=... is used) the specified labels. +- `host` - A string containing the host the API should communicate with. Defaults to `ENV['DOCKER_HOST']` if set. + +### Examples + +- default action, default properties + +```ruby +docker_image_prune 'prune-old-images' +``` + +- All filters + +```ruby +docker_image_prune "prune-old-images" do + dangling true + prune_until '1h30m' + with_label 'com.example.vendor=ACME' + without_label 'no_prune' + action :prune +end +``` ## docker_tag -Docker tags work very much like hard links in a Unix filesystem. They -are just references to an existing image. Therefore, the docker_tag -resource has taken inspiration from the Chef `link` resource. +Docker tags work very much like hard links in a Unix filesystem. They are just references to an existing image. Therefore, the docker_tag resource has taken inspiration from the Chef `link` resource. + +### Actions + +- `:tag` - Tags the image + +### Properties + +- `target_repo` - The repo half of the source image identifier. +- `target_tag` - The tag half of the source image identifier. +- `to_repo` - The repo half of the new image identifier +- `to_tag`- The tag half of the new image identifier ### Examples @@ -719,29 +644,100 @@ docker_tag 'private repo tag for hello-again:1.0.1' do end ``` -### Properties +## docker_container -- `target_repo` - The repo half of the source image identifier. -- `target_tag` - The tag half of the source image identifier. -- `to_repo` - The repo half of the new image identifier -- `to_tag`- The tag half of the new image identifier +The `docker_container` is responsible for managing Docker container actions. It speaks directly to the [Docker remote API](https://docs.docker.com/reference/api/docker_remote_api_v1.20/). + +Containers are process oriented, and move through an event cycle. Thanks to [Glider Labs](http://gliderlabs.com/) for this excellent diagram. ![alt tag](https://gliderlabs.com/images/2015/docker_events.png) ### Actions -- `:tag` - Tags the image +- `:create` - Creates the container but does not start it. Useful for Volume containers. +- `:start` - Starts the container. Useful for containers that run jobs.. command that exit. +- `:run` - The default action. Both `:create` and `:start` the container in one action. Redeploys the container on resource change. +- `:run_if_missing` - Runs a container only once. +- `:stop` - Stops the container. +- `:restart` - Stops and then starts the container. +- `:kill` - Send a signal to the container process. Defaults to `SIGKILL`. +- `:pause` - Pauses the container. +- `:unpause` - Unpauses the container. +- `:delete` - Deletes the container. +- `:redeploy` - Deletes and runs the container. +- `:reload` - Sends SIGHUP to pid 1 in the container -## docker_container +### Properties -The `docker_container` is responsible for managing Docker container -actions. It speaks directly to the -[Docker remote API](https://docs.docker.com/reference/api/docker_remote_api_v1.20/). - - -Containers are process oriented, and move through an event -cycle. Thanks to [Glider Labs](http://gliderlabs.com/) for this -excellent -diagram. ![alt tag](http://gliderlabs.com/images/docker_events.png) +Most `docker_container` properties are the `snake_case` version of the `CamelCase` keys found in the [Docker Remote Api](https://docs.docker.com/reference/api/docker_remote_api_v1.20/) +- `container_name` - The name of the container. Defaults to the name of the `docker_container` resource. +- `repo` - aka `image_name`. The first half of a the complete identifier for a Docker Image. +- `tag` - The second half of a Docker image's identity. - Defaults to `latest`. +- `command` - The command to run when starting the container. +- `autoremove` - Boolean - Automatically delete a container when it's command exits. Defaults to `false`. +- `volumes` - An array of volume bindings for this container. Each volume binding is a string in one of these forms: `container_path` to create a new volume for the container. `host_path:container_path` to bind-mount a host path into the container. `host_path:container_path:ro` to make the bind-mount read-only inside the container. +- `cap_add` - An array Linux Capabilities (`man 7 capabilities`) to add to grant the container beyond what it normally gets. +- `cap_drop` - An array Linux Capabilities (`man 7 capabilities`) to revoke that the container normally has. +- `cpu_shares` - An integer value containing the CPU Shares for the container. +- `devices` - A Hash of devices to add to the container. +- `dns` - An array of DNS servers the container will use for name resolution. +- `dns_search` - An array of domains the container will search for name resolution. +- `domain_name` - Set's the container's dnsdomainname as returned by the `dnsdomainname` command. +- `entrypoint` - Set the entry point for the container as a string or an array of strings. +- `env` - Set environment variables in the container in the form `['FOO=bar', 'BIZ=baz']` +- `env_file` - Read environment variables from a file and set in the container. Accepts an Array or String to the file location. lazy evaluator must be set if the file passed is created by Chef. +- `extra_hosts` - An array of hosts to add to the container's `/etc/hosts` in the form `['host_a:10.9.8.7', 'host_b:10.9.8.6']` +- `force` - A boolean to use in container operations that support a `force` option. Defaults to `false` +- `health_check` - A hash containing the health check options - https://docs.docker.com/engine/reference/run/#healthcheck +- `host` - A string containing the host the API should communicate with. Defaults to ENV['DOCKER_HOST'] if set +- `host_name` - The hostname for the container. +- `labels` A string, array, or hash to set metadata on the container in the form ['foo:bar', 'hello:world']` +- `links` - An array of source container/alias pairs to link the container to in the form `[container_a:www', container_b:db']` +- `log_driver` - Sets a custom logging driver for the container (json-file/syslog/journald/gelf/fluentd/none). +- `log_opts` - Configures the above logging driver options (driver-specific). +- `init` - Run an init inside the container that forwards signals and reaps processes. +- `ip_address` - Container IPv4 address (e.g. 172.30.100.104) +- `mac_address` - The mac address for the container to use. +- `memory` - Memory limit in bytes. +- `memory_swap` - Total memory limit (memory + swap); set `-1` to disable swap limit (unlimited). You must use this with memory and make the swap value larger than memory. +- `network_disabled` - Boolean to disable networking. Defaults to `false`. +- `network_mode` - Sets the networking mode for the container. One of `bridge`, `host`, `container`. +- `network_aliases` - Adds network-scoped alias for the container in form `['alias-1', 'alias-2']`. +- `oom_kill_disable` - Whether to disable OOM Killer for the container or not. +- `oom_score_adj` - Tune container's OOM preferences (-1000 to 1000). +- `open_stdin` - Boolean value, opens stdin. Defaults to `false`. +- `outfile` - The path to write the file when using `:export` action. +- `port` - The port configuration to use in the container. Matches the syntax used by the `docker` CLI tool. +- `privileged` - Boolean to start the container in privileged more. Defaults to `false` +- `publish_all_ports` - Allocates a random host port for all of a container's exposed ports. +- `remove_volumes` - A boolean to clean up "dangling" volumes when removing the last container with a reference to it. Default to `false` to match the Docker CLI behavior. +- `restart_policy` - One of `no`, `on-failure`, `unless-stopped`, or `always`. Use `always` if you want a service container to survive a Dockerhost reboot. Defaults to `no`. +- `restart_maximum_retry_count` - Maximum number of restarts to try when `restart_policy` is `on-failure`. Defaults to an ever increasing delay (double the previous delay, starting at 100mS), to prevent flooding the server. +- `running_wait_time` - Amount of seconds `docker_container` wait to determine if a process is running. +- `runtime` - Runtime to use when running container. Defaults to `runc`. +- `security_opt` - A list of string values to customize labels for MLS systems, such as SELinux. +- `shm_size` - The size of `/dev/shm`. The format is ``, where number must be greater than 0. Unit is optional and can be b (bytes), k (kilobytes), m(megabytes), or g (gigabytes). The default is `64m`. +- `signal` - The signal to send when using the `:kill` action. Defaults to `SIGTERM`. +- `sysctls` - A hash of sysctls to set on the container. Defaults to `{}`. +- `tty` - Boolean value to allocate a pseudo-TTY. Defaults to `false`. +- `user` - A string value specifying the user inside the container. +- `volumes` - An Array of paths inside the container to expose. Does the same thing as the `VOLUME` directive in a Dockerfile, but works on container creation. +- `volumes_from` - A list of volumes to inherit from another container. Specified in the form `[:]` +- `volume_driver` - Driver that this container users to mount volumes. +- `working_dir` - A string specifying the working directory for commands to run in. +- `read_timeout` - May need to increase for commits or exports that are slow +- `write_timeout` - May need to increase for commits or exports that are slow +- `kill_after` - Number of seconds to wait before killing the container. Defaults to wait indefinitely; eventually will hit read_timeout limit. +- `timeout` - Seconds to wait for an attached container to return +- `tls` - Use TLS; implied by --tlsverify. Defaults to ENV['DOCKER_TLS'] if set +- `tls_verify` - Use TLS and verify the remote. Defaults to ENV['DOCKER_TLS_VERIFY'] if set +- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `tls_client_cert` - Path to TLS certificate file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `tls_client_key` - Path to TLS key file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set +- `userns_mode` - Modify the user namespace mode - Defaults to `nil`, example option: `host` +- `pid_mode` - Set the PID (Process) Namespace mode for the container. `host`: use the host's PID namespace inside the container. +- `ipc_mode` - Set the IPC mode for the container - Defaults to `nil`, example option: `host` +- `uts_mode` - Set the UTS namespace mode for the container. The UTS namespace is for setting the hostname and the domain that is visible to running processes in that namespace. By default, all containers, including those with `--network=host`, have their own UTS namespace. The host setting will result in the container using the same UTS namespace as the host. Note that --hostname is invalid in host UTS mode. +- `ro_rootfs` - Mount the container's root filesystem as read only using the `--read-only` flag. Defaults to `false` ### Examples @@ -786,6 +782,15 @@ docker_container 'env' do end ``` +```ruby +docker_container 'env_files' do + repo 'debian' + env_file lazy { ['/env_file1', '/env_file2'] } + command 'env' + action :run +end +``` + - This process remains running between chef-client runs, :run will do nothing on subsequent converges. ```ruby @@ -1113,7 +1118,7 @@ docker_container 'syslogger' do tag '3.1' command 'nc -ll -p 780 -e /bin/cat' log_driver 'syslog' - log_opts 'syslog-tag=container-syslogger' + log_opts 'tag=container-syslogger' end ``` @@ -1127,93 +1132,42 @@ docker_container 'external_daemon' do end ``` -### Properties +- Run a container with health_check options -Most `docker_container` properties are the `snake_case` version of the `CamelCase` keys found in the [Docker Remote Api](https://docs.docker.com/reference/api/docker_remote_api_v1.20/) - -- `container_name` - The name of the container. Defaults to the name of the `docker_container` resource. -- `repo` - aka `image_name`. The first half of a the complete identifier for a Docker Image. -- `tag` - The second half of a Docker image's identity. - Defaults to `latest`. -- `command` - The command to run when starting the container. -- `autoremove` - Boolean - Automatically delete a container when it's command exits. Defaults to `false`. -- `volumes` - An array of volume bindings for this container. Each volume binding is a string in one of these forms: `container_path` to create a new volume for the container. `host_path:container_path` to bind-mount a host path into the container. `host_path:container_path:ro` to make the bind-mount read-only inside the container. -- `cap_add` - An array Linux Capabilities (`man 7 capabilities`) to add to grant the container beyond what it normally gets. -- `cap_drop` - An array Linux Capabilities (`man 7 capabilities`) to revoke that the container normally has. -- `cpu_shares` - An integer value containing the CPU Shares for the container. -- `devices` - A Hash of devices to add to the container. -- `dns` - An array of DNS servers the container will use for name resolution. -- `dns_search` - An array of domains the container will search for name resolution. -- `domain_name` - Set's the container's dnsdomainname as returned by the `dnsdomainname` command. -- `entrypoint` - Set the entry point for the container as a string or an array of strings. -- `env` - Set environment variables in the container in the form `['FOO=bar', 'BIZ=baz']` -- `extra_hosts` - An array of hosts to add to the container's `/etc/hosts` in the form `['host_a:10.9.8.7', 'host_b:10.9.8.6']` -- `force` - A boolean to use in container operations that support a `force` option. Defaults to `false` -- `host` - A string containing the host the API should communicate with. Defaults to ENV['DOCKER_HOST'] if set -- `host_name` - The hostname for the container. -- `labels` A string, array, or hash to set metadata on the container in the form ['foo:bar', 'hello:world']` -- `links` - An array of source container/alias pairs to link the container to in the form `[container_a:www', container_b:db']` -- `log_driver` - Sets a custom logging driver for the container (json-file/syslog/journald/gelf/fluentd/none). -- `log_opts` - Configures the above logging driver options (driver-specific). -- `ip_address` - Container IPv4 address (e.g. 172.30.100.104) -- `mac_address` - The mac address for the container to use. -- `memory` - Memory limit in bytes. -- `memory_swap` - Total memory limit (memory + swap); set `-1` to disable swap limit (unlimited). You must use this with memory and make the swap value larger than memory. -- `network_disabled` - Boolean to disable networking. Defaults to `false`. -- `network_mode` - Sets the networking mode for the container. One of `bridge`, `host`, `container`. -- `open_stdin` - Boolean value, opens stdin. Defaults to `false`. -- `outfile` - The path to write the file when using `:export` action. -- `port` - The port configuration to use in the container. Matches the syntax used by the `docker` CLI tool. -- `privileged` - Boolean to start the container in privileged more. Defaults to `false` -- `publish_all_ports` - Allocates a random host port for all of a container's exposed ports. -- `remove_volumes` - A boolean to clean up "dangling" volumes when removing the last container with a reference to it. Default to `false` to match the Docker CLI behavior. -- `restart_policy` - One of `no`, `on-failure`, `unless-stopped`, or `always`. Use `always` if you want a service container to survive a Dockerhost reboot. Defaults to `no`. -- `restart_maximum_retry_count` - Maximum number of restarts to try when `restart_policy` is `on-failure`. Defaults to an ever increasing delay (double the previous delay, starting at 100mS), to prevent flooding the server. -- `running_wait_time` - Amount of seconds `docker_container` wait to determine if a process is running.` -- `security_opts` - A list of string values to customize labels for MLS systems, such as SELinux. -- `signal` - The signal to send when using the `:kill` action. Defaults to `SIGTERM`. -- `sysctls` - A hash of sysctls to set on the container. Defaults to `{}`. -- `tty` - Boolean value to allocate a pseudo-TTY. Defaults to `false`. -- `user` - A string value specifying the user inside the container. -- `volumes` - An Array of paths inside the container to expose. Does the same thing as the `VOLUME` directive in a Dockerfile, but works on container creation. -- `volumes_from` - A list of volumes to inherit from another container. Specified in the form `[:]` -- `volume_driver` - Driver that this container users to mount volumes. -- `working_dir` - A string specifying the working directory for commands to run in. -- `read_timeout` - May need to increase for commits or exports that are slow -- `write_timeout` - May need to increase for commits or exports that are slow -- `kill_after` - Number of seconds to wait before killing the container. Defaults to wait indefinitely; eventually will hit read_timeout limit. -- `timeout` - Seconds to wait for an attached container to return -- `tls` - Use TLS; implied by --tlsverify. Defaults to ENV['DOCKER_TLS'] if set -- `tls_verify` - Use TLS and verify the remote. Defaults to ENV['DOCKER_TLS_VERIFY'] if set -- `tls_ca_cert` - Trust certs signed only by this CA. Defaults to ENV['DOCKER_CERT_PATH'] if set -- `tls_client_cert` - Path to TLS certificate file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set -- `tls_client_key` - Path to TLS key file for docker cli. Defaults to ENV['DOCKER_CERT_PATH'] if set -- `userns_mode` - Modify the user namespace mode - Defaults to `nil`, example option: `host` -- `pid_mode` - Set the PID (Process) Namespace mode for the container. `host`: use the host's PID namespace inside the container. -- `ipc_mode` - Set the IPC mode for the container - Defaults to `nil`, example option: `host` -- `uts_mode` - Set the UTS namespace mode for the container. The UTS namespace is for setting the hostname and the domain that is visible to running processes in that namespace. By default, all containers, including those with `--network=host`, have their own UTS namespace. The host setting will result in the container using the same UTS namespace as the host. Note that --hostname is invalid in host UTS mode. -- `ro_rootfs` - Mount the container's root filesystem as read only. Defaults to `false` - -### Actions - -- `:create` - Creates the container but does not start it. Useful for Volume containers. -- `:start` - Starts the container. Useful for containers that run jobs.. command that exit. -- `:run` - The default action. Both `:create` and `:start` the container in one action. Redeploys the container on resource change. -- `:run_if_missing` - Runs a container only once. -- `:stop` - Stops the container. -- `:restart` - Stops the starts the container. -- `:kill` - Send a signal to the container process. Defaults to `SIGKILL`. -- `:pause` - Pauses the container. -- `:unpause` - Unpauses the container. -- `:delete` - Deletes the container. -- `:redeploy` - Deletes and runs the container. -- `:reload` - Sends SIGHUP to pid 1 in the container +```ruby +docker_container 'health_check' do + repo 'alpine' + tag '3.1' + health_check ({ + "Test" => + [ + "string" + ], + "Interval" => 0, + "Timeout" => 0, + "Retries" => 0, + "StartPeriod" => 0 + }) + action :run +end +``` ## docker_registry -The `docker_registry` resource is responsible for managing the -connection auth information to a Docker registry. +The `docker_registry` resource is responsible for managing the connection auth information to a Docker registry. -### docker_registry action :login +### Actions + +- `:login` - Login to the Docker Registry + +### Properties + +- `email` +- `password` +- `serveraddress` +- `username` + +### Examples - Log into or register with public registry: @@ -1238,47 +1192,28 @@ end ## docker_network -The `docker_network` resource is responsible for managing Docker named -networks. Usage of `overlay` driver requires the `docker_service` to -be configured to use a distributed key/value store like `etcd`, -`consul`, or `zookeeper`. +The `docker_network` resource is responsible for managing Docker named networks. Usage of `overlay` driver requires the `docker_service` to be configured to use a distributed key/value store like `etcd`, `consul`, or `zookeeper`. -### docker_network action :create +### Actions -```ruby -docker_network 'my_network' do - subnet '192.168.88.0/24' - gateway '192.168.88.1' - action :create -end - -docker_container 'echo-base' do - repo 'alpine' - tag '3.1' - command 'nc -ll -p 1337 -e /bin/cat' - port '1337' - network_mode 'my_network' - action :run -end -``` +- `:create` - create a network +- `:delete` - delete a network +- `:connect` - connect a container to a network +- `:disconnect` - disconnect a container from a network ### Properties -- `driver` - The network driver to use. Defaults to `bridge`, other - options include `overlay`. -- `subnet` - Specify the subnet(s) for the network. Ex: - `192.168.0.0/16` -- `gateway` - Specify the gateway(s) for the network. Ex: - `192.168.0.1` -- `ip_range` - Specify a range of IPs to allocate for containers. Ex: - `192.168.1.0/24` -- `aux_address` - Auxillary addresses for the network. Ex: - `['a=192.168.1.5', 'b=192.168.1.6']` -- `container` - Container-id/name to be connected/disconnected to/from - the network. Used only by `:connect` and `:disconnect` actions +- `aux_address` - Auxiliary addresses for the network. Ex: `['a=192.168.1.5', 'b=192.168.1.6']` +- `container` - Container-id/name to be connected/disconnected to/from the network. Used only by `:connect` and `:disconnect` actions +- `driver` - The network driver to use. Defaults to `bridge`, other options include `overlay`. +- `enable_ipv6` - Enable IPv6 on the network. Ex: true +- `gateway` - Specify the gateway(s) for the network. Ex: `192.168.0.1` +- `ip_range` - Specify a range of IPs to allocate for containers. Ex: `192.168.1.0/24` +- `subnet` - Specify the subnet(s) for the network. Ex: `192.168.0.0/16` +### Examples -### Example +Create a network and use it in a container ```ruby docker_network 'network_g' do @@ -1288,6 +1223,15 @@ docker_network 'network_g' do ip_range '192.168.1.0/24' aux_address ['a=192.168.1.5', 'b=192.168.1.6', 'a=192.170.1.5', 'b=192.170.1.6'] end + +docker_container 'echo-base' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 1337 -e /bin/cat' + port '1337' + network_mode 'network_g' + action :run +end ``` Connect to multiple networks @@ -1316,19 +1260,36 @@ docker_network 'network_h2' do end ``` -### Actions +IPv6 enabled network -- `:create` - create a network -- `:delete` - delete a network -- `:connect` - connect a container to a network -- `:disconnect` - disconnect a container from a network +```ruby +docker_network 'network_i1' do + enable_ipv6 true + subnet 'fd00:dead:beef::/48' + action :create +end +``` ## docker_volume -The `docker_volume` resource is responsible for managing Docker named -volumes. +The `docker_volume` resource is responsible for managing Docker named volumes. -### docker_volume action :create +### Actions + +- `:create` - create a volume +- `:remove` - remove a volume + +### Properties + +- `driver` - Name of the volume driver to use. Only used for `:create`. +- `host` +- `opts` - Options to pass to the volume driver. Only used for `:create`. +- `volume` +- `volume_name` - Name of the volume to operate on (defaults to the resource name). + +### Examples + +Create a volume named 'hello' ```ruby docker_volume 'hello' do @@ -1344,15 +1305,55 @@ docker_container 'file_writer' do end ``` +## docker_plugin + +The `docker_plugin` resource allows you to install, configure, enable, disable and remove [Docker Engine managed plugins](https://docs.docker.com/engine/extend/). + ### Actions -- `:create` - create a volume -- `:remove` - remove a volume +- `:install` - Install and configure a plugin if it is not already installed +- `:update` - Re-configure a plugin +- `:enable` - Enable a plugin (needs to be done after `:install` before it can + be used) +- `:disable` - Disable a plugin (needs to be done before removing a plugin) +- `:remove` - Remove a disabled plugin -## docker_execute +### Properties -The `docker_execute` resource allows you to execute commands inside of -a running container. +- `local_alias` - Local name for the plugin (defaults to the resource name). +- `remote` - Ref of the plugin (e.g. `vieux/sshfs`). Defaults to `local_alias` or the resource name. Only used for `:install`. +- `remote_tag` - Remote tag of the plugin to pull (e.g. `1.0.1`, defaults to `latest`) Only used for `:install`. +- `options` - Hash of options to set on the plugin. Only used for `:update` and `:install`. +- `grant_privileges` - Array of privileges or true. If it is true, all privileges requested by the plugin will be automatically granted (potentially dangerous). Otherwise, this must be an array in the same format as returned by the [`/plugins/privileges` docker API](https://docs.docker.com/engine/api/v1.37/#operation/GetPluginPrivileges) endpoint. If the array of privileges is not sufficient for the plugin, docker will reject it and the installation will fail. Defaults to `[]` (empty array => no privileges). Only used for `:install`. Does not modify the privileges of already-installed plugins. + +### Examples + +```ruby +docker_plugin 'rbd' do + remote 'wetopi/rbd' + remote_tag '1.0.1' + grant_privileges true + options( + 'RBD_CONF_POOL' => 'docker_volumes' + ) +end +``` + +## docker_exec + +The `docker_exec` resource allows you to execute commands inside of a running container. + +### Actions + +- `:run` - Runs the command + +### Properties + +- `host` - Daemon socket(s) to connect to - `tcp://host:port`, `unix:///path/to/socket`, `fd://*` or `fd://socketfd`. +- `command` - A command structured as an Array similar to `CMD` in a Dockerfile. +- `container` - Name of the container to execute the command in. +- `timeout`- Seconds to wait for an attached container to return. Defaults to 60 seconds. +- `container_obj` ### Examples @@ -1363,55 +1364,26 @@ docker_exec 'touch_it' do end ``` -### Properties - -- `host` - Daemon socket(s) to connect to - `tcp://host:port`, - `unix:///path/to/socket`, `fd://*` or `fd://socketfd`. -- `command` - A command structured as an Array similar to `CMD` in a - Dockerfile. -- `container` - Name of the container to execute the command in. -- `timeout`- Seconds to wait for an attached container to - return. Defaults to 60 seconds. - -### Actions - -- `:run` - Runs the command - -## Testing and Development - -- Full development and testing workflow with Test Kitchen and friends: - - - - -## Contributing - -Please see contributing information in: - - - - ## Maintainers - Sean OMeara ([sean@sean.io](mailto:sean@sean.io)) - Brian Flad ([bflad417@gmail.com](mailto:bflad417@gmail.com)) -- Tom Duffield () -- Fletcher Nichol ([fnichol@nichol.ca](mailto:fnichol@nichol.ca)) - Chase Bolt ([chase.bolt@gmail.com](mailto:chase.bolt@gmail.com)) ## License -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 - +**Copyright:** 2015-2018, Chef Software, Inc. ``` -http://www.apache.org/licenses/LICENSE-2.0 -``` +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. +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/chef/cookbooks/docker/TESTING.md b/chef/cookbooks/docker/TESTING.md new file mode 100644 index 0000000..ca524ab --- /dev/null +++ b/chef/cookbooks/docker/TESTING.md @@ -0,0 +1,2 @@ +Please refer to +https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD diff --git a/chef/cookbooks/docker/chefignore b/chef/cookbooks/docker/chefignore new file mode 100644 index 0000000..cd4830c --- /dev/null +++ b/chef/cookbooks/docker/chefignore @@ -0,0 +1,106 @@ +# 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 + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Cookbooks # +############# +CONTRIBUTING* +CHANGELOG* +TESTING* + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/chef/cookbooks/docker/files/default/vendor/cache/docker-api-1.33.2.gem b/chef/cookbooks/docker/files/default/vendor/cache/docker-api-1.33.2.gem deleted file mode 100644 index 3ea1b66252b159f697423012a9b021a2d7ab38b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27648 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 diff --git a/chef/cookbooks/docker/files/default/vendor/cache/excon-0.54.0.gem b/chef/cookbooks/docker/files/default/vendor/cache/excon-0.54.0.gem deleted file mode 100644 index dd686c6f02fadf313345e85288fb03a751f05e28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236032 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

VRg@gG}>dmf#$Ue;0x=}29{bV|l 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

>JBJ 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

eAkBUTJTHR=;Jl-^qkIwd1 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

p&ovc%+37hrBl5;Am8oNgIt2{M^cOeQ2Fb# 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%0D4^W19MiAN_sO>zF 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

qK%tD$?p`vZ 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 P$a?JGgb~xgcZ{|0*_2C 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 diff --git a/chef/cookbooks/docker/files/default/vendor/gems/excon-0.54.0/Gemfile.lock b/chef/cookbooks/docker/files/default/vendor/gems/excon-0.54.0/Gemfile.lock deleted file mode 100644 index 80a6583..0000000 --- a/chef/cookbooks/docker/files/default/vendor/gems/excon-0.54.0/Gemfile.lock +++ /dev/null @@ -1,301 +0,0 @@ -PATH - remote: . - specs: - excon (0.54.0) - -GEM - remote: http://rubygems.org/ - specs: - activesupport (3.2.6) - i18n (~> 0.6) - multi_json (~> 1.0) - backports (3.6.4) - chronic (0.6.7) - delorean (2.0.0) - chronic - diff-lcs (1.2.5) - eventmachine (1.0.4) - eventmachine (1.0.4-java) - ffi2-generators (0.1.1) - formatador (0.2.3) - i18n (0.6.0) - jruby-openssl (0.9.17-java) - json (1.8.2) - json (1.8.2-java) - kgio (2.9.2) - minitest (4.7.5) - multi_json (1.3.6) - open4 (1.3.0) - puma (3.6.0) - puma (3.6.0-java) - rack (1.6.0) - rack-protection (1.2.0) - rack - rack-test (0.6.3) - rack (>= 1.0) - raindrops (0.13.0) - rake (0.9.2.2) - rdoc (3.12) - json (~> 1.4) - rspec (3.5.0) - rspec-core (~> 3.5.0) - rspec-expectations (~> 3.5.0) - rspec-mocks (~> 3.5.0) - rspec-core (3.5.0) - rspec-support (~> 3.5.0) - rspec-expectations (3.5.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-mocks (3.5.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-support (3.5.0) - rubysl (2.0.14) - rubysl-abbrev (~> 2.0) - rubysl-base64 (~> 2.0) - rubysl-benchmark (~> 2.0) - rubysl-bigdecimal (~> 2.0) - rubysl-cgi (~> 2.0) - rubysl-cgi-session (~> 2.0) - rubysl-cmath (~> 2.0) - rubysl-complex (~> 2.0) - rubysl-continuation (~> 2.0) - rubysl-coverage (~> 2.0) - rubysl-csv (~> 2.0) - rubysl-curses (~> 2.0) - rubysl-date (~> 2.0) - rubysl-delegate (~> 2.0) - rubysl-digest (~> 2.0) - rubysl-drb (~> 2.0) - rubysl-e2mmap (~> 2.0) - rubysl-english (~> 2.0) - rubysl-enumerator (~> 2.0) - rubysl-erb (~> 2.0) - rubysl-etc (~> 2.0) - rubysl-expect (~> 2.0) - rubysl-fcntl (~> 2.0) - rubysl-fiber (~> 2.0) - rubysl-fileutils (~> 2.0) - rubysl-find (~> 2.0) - rubysl-forwardable (~> 2.0) - rubysl-getoptlong (~> 2.0) - rubysl-gserver (~> 2.0) - rubysl-io-console (~> 2.0) - rubysl-io-nonblock (~> 2.0) - rubysl-io-wait (~> 2.0) - rubysl-ipaddr (~> 2.0) - rubysl-irb (~> 2.0) - rubysl-logger (~> 2.0) - rubysl-mathn (~> 2.0) - rubysl-matrix (~> 2.0) - rubysl-mkmf (~> 2.0) - rubysl-monitor (~> 2.0) - rubysl-mutex_m (~> 2.0) - rubysl-net-ftp (~> 2.0) - rubysl-net-http (~> 2.0) - rubysl-net-imap (~> 2.0) - rubysl-net-pop (~> 2.0) - rubysl-net-protocol (~> 2.0) - rubysl-net-smtp (~> 2.0) - rubysl-net-telnet (~> 2.0) - rubysl-nkf (~> 2.0) - rubysl-observer (~> 2.0) - rubysl-open-uri (~> 2.0) - rubysl-open3 (~> 2.0) - rubysl-openssl (~> 2.0) - rubysl-optparse (~> 2.0) - rubysl-ostruct (~> 2.0) - rubysl-pathname (~> 2.0) - rubysl-prettyprint (~> 2.0) - rubysl-prime (~> 2.0) - rubysl-profile (~> 2.0) - rubysl-profiler (~> 2.0) - rubysl-pstore (~> 2.0) - rubysl-pty (~> 2.0) - rubysl-rational (~> 2.0) - rubysl-readline (~> 2.0) - rubysl-resolv (~> 2.0) - rubysl-rexml (~> 2.0) - rubysl-rinda (~> 2.0) - rubysl-rss (~> 2.0) - rubysl-scanf (~> 2.0) - rubysl-securerandom (~> 2.0) - rubysl-set (~> 2.0) - rubysl-shellwords (~> 2.0) - rubysl-singleton (~> 2.0) - rubysl-socket (~> 2.0) - rubysl-stringio (~> 2.0) - rubysl-strscan (~> 2.0) - rubysl-sync (~> 2.0) - rubysl-syslog (~> 2.0) - rubysl-tempfile (~> 2.0) - rubysl-test-unit (~> 2.0) - rubysl-thread (~> 2.0) - rubysl-thwait (~> 2.0) - rubysl-time (~> 2.0) - rubysl-timeout (~> 2.0) - rubysl-tmpdir (~> 2.0) - rubysl-tsort (~> 2.0) - rubysl-un (~> 2.0) - rubysl-uri (~> 2.0) - rubysl-weakref (~> 2.0) - rubysl-webrick (~> 2.0) - rubysl-xmlrpc (~> 2.0) - rubysl-yaml (~> 2.0) - rubysl-zlib (~> 2.0) - rubysl-abbrev (2.0.4) - rubysl-base64 (2.0.0) - rubysl-benchmark (2.0.1) - rubysl-bigdecimal (2.0.2) - rubysl-cgi (2.0.1) - rubysl-cgi-session (2.0.1) - rubysl-cmath (2.0.0) - rubysl-complex (2.0.0) - rubysl-continuation (2.0.0) - rubysl-coverage (2.0.3) - rubysl-csv (2.0.2) - rubysl-english (~> 2.0) - rubysl-curses (2.0.0) - rubysl-date (2.0.6) - rubysl-delegate (2.0.1) - rubysl-digest (2.0.3) - rubysl-drb (2.0.1) - rubysl-e2mmap (2.0.0) - rubysl-english (2.0.0) - rubysl-enumerator (2.0.0) - rubysl-erb (2.0.1) - rubysl-etc (2.0.3) - ffi2-generators (~> 0.1) - rubysl-expect (2.0.0) - rubysl-fcntl (2.0.4) - ffi2-generators (~> 0.1) - rubysl-fiber (2.0.0) - rubysl-fileutils (2.0.3) - rubysl-find (2.0.1) - rubysl-forwardable (2.0.1) - rubysl-getoptlong (2.0.0) - rubysl-gserver (2.0.0) - rubysl-socket (~> 2.0) - rubysl-thread (~> 2.0) - rubysl-io-console (2.0.0) - rubysl-io-nonblock (2.0.0) - rubysl-io-wait (2.0.0) - rubysl-ipaddr (2.0.0) - rubysl-irb (2.0.4) - rubysl-e2mmap (~> 2.0) - rubysl-mathn (~> 2.0) - rubysl-readline (~> 2.0) - rubysl-thread (~> 2.0) - rubysl-logger (2.0.0) - rubysl-mathn (2.0.0) - rubysl-matrix (2.1.0) - rubysl-e2mmap (~> 2.0) - rubysl-mkmf (2.0.1) - rubysl-fileutils (~> 2.0) - rubysl-shellwords (~> 2.0) - rubysl-monitor (2.0.0) - rubysl-mutex_m (2.0.0) - rubysl-net-ftp (2.0.1) - rubysl-net-http (2.0.4) - rubysl-cgi (~> 2.0) - rubysl-erb (~> 2.0) - rubysl-singleton (~> 2.0) - rubysl-net-imap (2.0.1) - rubysl-net-pop (2.0.1) - rubysl-net-protocol (2.0.1) - rubysl-net-smtp (2.0.1) - rubysl-net-telnet (2.0.0) - rubysl-nkf (2.0.1) - rubysl-observer (2.0.0) - rubysl-open-uri (2.0.0) - rubysl-open3 (2.0.0) - rubysl-openssl (2.0.4) - rubysl-optparse (2.0.1) - rubysl-shellwords (~> 2.0) - rubysl-ostruct (2.0.4) - rubysl-pathname (2.0.0) - rubysl-prettyprint (2.0.2) - rubysl-prime (2.0.0) - rubysl-profile (2.0.0) - rubysl-profiler (2.0.1) - rubysl-pstore (2.0.0) - rubysl-pty (2.0.2) - rubysl-rational (2.0.1) - rubysl-readline (2.0.2) - rubysl-resolv (2.0.0) - rubysl-rexml (2.0.2) - rubysl-rinda (2.0.0) - rubysl-rss (2.0.0) - rubysl-scanf (2.0.0) - rubysl-securerandom (2.0.0) - rubysl-set (2.0.1) - rubysl-shellwords (2.0.0) - rubysl-singleton (2.0.0) - rubysl-socket (2.0.1) - rubysl-stringio (2.0.0) - rubysl-strscan (2.0.0) - rubysl-sync (2.0.0) - rubysl-syslog (2.0.1) - ffi2-generators (~> 0.1) - rubysl-tempfile (2.0.1) - rubysl-test-unit (2.0.1) - minitest (~> 4.7) - rubysl-thread (2.0.2) - rubysl-thwait (2.0.0) - rubysl-time (2.0.3) - rubysl-timeout (2.0.0) - rubysl-tmpdir (2.0.0) - rubysl-tsort (2.0.1) - rubysl-un (2.0.0) - rubysl-fileutils (~> 2.0) - rubysl-optparse (~> 2.0) - rubysl-uri (2.0.0) - rubysl-weakref (2.0.0) - rubysl-webrick (2.0.0) - rubysl-xmlrpc (2.0.0) - rubysl-yaml (2.0.3) - rubysl-zlib (2.0.1) - shindo (0.3.4) - formatador (>= 0.1.1) - sinatra (1.3.2) - rack (~> 1.3, >= 1.3.6) - rack-protection (~> 1.2) - tilt (~> 1.3, >= 1.3.3) - sinatra-contrib (1.3.2) - backports (>= 2.0) - eventmachine - rack-protection - rack-test - sinatra (~> 1.3.0) - tilt (~> 1.3) - tilt (1.3.3) - unicorn (4.8.3) - kgio (~> 2.6) - rack - raindrops (~> 0.7) - -PLATFORMS - java - ruby - -DEPENDENCIES - activesupport - delorean - eventmachine (>= 1.0.4) - excon! - jruby-openssl (~> 0.9) - json (>= 1.8.2) - open4 - puma - rack (~> 1.6) - rake - rdoc - rspec (>= 3.5.0) - rubysl (~> 2.0) - shindo - sinatra - sinatra-contrib - unicorn - -BUNDLED WITH - 1.13.1 diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/Makefile b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/Makefile deleted file mode 100644 index db374b9..0000000 --- a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/Makefile +++ /dev/null @@ -1,196 +0,0 @@ - -SHELL = /bin/sh - -# V=0 quiet, V=1 verbose. other values don't work. -V = 0 -Q1 = $(V:1=) -Q = $(Q1:0=@) -ECHO1 = $(V:1=@:) -ECHO = $(ECHO1:0=@echo) -NULLCMD = : - -#### Start of system configuration section. #### - -srcdir = . -topdir = /opt/chefdk/embedded/include/ruby-2.3.0 -hdrdir = $(topdir) -arch_hdrdir = /opt/chefdk/embedded/include/ruby-2.3.0/x86_64-darwin13 -PATH_SEPARATOR = : -VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby -prefix = $(DESTDIR)/opt/chefdk/embedded -rubysitearchprefix = $(rubylibprefix)/$(sitearch) -rubyarchprefix = $(rubylibprefix)/$(arch) -rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) -exec_prefix = $(prefix) -vendorarchhdrdir = $(vendorhdrdir)/$(sitearch) -sitearchhdrdir = $(sitehdrdir)/$(sitearch) -rubyarchhdrdir = $(rubyhdrdir)/$(arch) -vendorhdrdir = $(rubyhdrdir)/vendor_ruby -sitehdrdir = $(rubyhdrdir)/site_ruby -rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) -vendorarchdir = $(vendorlibdir)/$(sitearch) -vendorlibdir = $(vendordir)/$(ruby_version) -vendordir = $(rubylibprefix)/vendor_ruby -sitearchdir = $(DESTDIR)./.gem.20170131-68034-1687ce7 -sitelibdir = $(DESTDIR)./.gem.20170131-68034-1687ce7 -sitedir = $(rubylibprefix)/site_ruby -rubyarchdir = $(rubylibdir)/$(arch) -rubylibdir = $(rubylibprefix)/$(ruby_version) -sitearchincludedir = $(includedir)/$(sitearch) -archincludedir = $(includedir)/$(arch) -sitearchlibdir = $(libdir)/$(sitearch) -archlibdir = $(libdir)/$(arch) -ridir = $(datarootdir)/$(RI_BASE_NAME) -mandir = $(datarootdir)/man -localedir = $(datarootdir)/locale -libdir = $(exec_prefix)/lib -psdir = $(docdir) -pdfdir = $(docdir) -dvidir = $(docdir) -htmldir = $(docdir) -infodir = $(datarootdir)/info -docdir = $(datarootdir)/doc/$(PACKAGE) -oldincludedir = $(DESTDIR)/usr/include -includedir = $(SDKROOT)$(prefix)/include -localstatedir = $(prefix)/var -sharedstatedir = $(prefix)/com -sysconfdir = $(prefix)/etc -datadir = $(datarootdir) -datarootdir = $(prefix)/share -libexecdir = $(exec_prefix)/libexec -sbindir = $(exec_prefix)/sbin -bindir = $(exec_prefix)/bin -archdir = $(rubyarchdir) - - -CC = clang -CXX = g++ -LIBRUBY = $(LIBRUBY_SO) -LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a -LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) -LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation -empty = -OUTFLAG = -o $(empty) -COUTFLAG = -o $(empty) - -RUBY_EXTCONF_H = -cflags = $(optflags) $(debugflags) $(warnflags) -cxxflags = $(optflags) $(debugflags) $(warnflags) -optflags = -O3 -fno-fast-math -debugflags = -ggdb3 -warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -diag-disable=2259 -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens -CCDLFLAGS = -fno-common -CFLAGS = $(CCDLFLAGS) -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -O3 -g -pipe -Qunused-arguments -fno-common $(ARCH_FLAG) -INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -DEFS = -CPPFLAGS = -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -arch x86_64 -m64 -O3 -g -pipe -Qunused-arguments -I/opt/chefdk/embedded/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags) -CXXFLAGS = $(CCDLFLAGS) -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -O3 -g -pipe -Qunused-arguments $(ARCH_FLAG) -ldflags = -L. -L/opt/chefdk/embedded/lib -fstack-protector -L/opt/chefdk/embedded/lib -dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -L/opt/chefdk/embedded/lib -ARCH_FLAG = -m64 -DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) -LDSHARED = $(CC) -dynamic -bundle -LDSHAREDXX = $(CXX) -dynamic -bundle -AR = ar -EXEEXT = - -RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) -RUBY_SO_NAME = ruby.2.3.0 -RUBYW_INSTALL_NAME = -RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) -RUBYW_BASE_NAME = rubyw -RUBY_BASE_NAME = ruby - -arch = x86_64-darwin13 -sitearch = $(arch) -ruby_version = 2.3.0 -ruby = $(bindir)/$(RUBY_BASE_NAME) -RUBY = $(ruby) -ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h - -RM = rm -f -RM_RF = $(RUBY) -run -e rm -- -rf -RMDIRS = rmdir -p -MAKEDIRS = mkdir -p -INSTALL = /usr/bin/install -c -INSTALL_PROG = $(INSTALL) -m 0755 -INSTALL_DATA = $(INSTALL) -m 644 -COPY = cp -TOUCH = exit > - -#### End of system configuration section. #### - -preload = - -libpath = . $(libdir) /opt/chefdk/embedded/lib -LIBPATH = -L. -L$(libdir) -L/opt/chefdk/embedded/lib -DEFFILE = - -CLEANFILES = mkmf.log -DISTCLEANFILES = -DISTCLEANDIRS = - -extout = -extout_prefix = -target_prefix = -LOCAL_LIBS = -LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc -ORIG_SRCS = -SRCS = $(ORIG_SRCS) -OBJS = -HDRS = -TARGET = -TARGET_NAME = -TARGET_ENTRY = Init_$(TARGET_NAME) -DLLIB = -EXTSTATIC = -STATIC_LIB = - -TIMESTAMP_DIR = . -BINDIR = $(bindir) -RUBYCOMMONDIR = $(sitedir)$(target_prefix) -RUBYLIBDIR = $(sitelibdir)$(target_prefix) -RUBYARCHDIR = $(sitearchdir)$(target_prefix) -HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) -ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) - -TARGET_SO = $(DLLIB) -CLEANLIBS = $(TARGET).bundle -CLEANOBJS = *.o *.bak - -all: Makefile -static: $(STATIC_LIB) install-rb -.PHONY: all install static install-so install-rb -.PHONY: clean clean-so clean-static clean-rb - -clean-static:: -clean-rb-default:: -clean-rb:: -clean-so:: -clean: clean-so clean-static clean-rb-default clean-rb - -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time - -distclean-rb-default:: -distclean-rb:: -distclean-so:: -distclean-static:: -distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb - -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log - -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) - -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true - -realclean: distclean -install: install-so install-rb - -install-so: Makefile -install-rb: pre-install-rb install-rb-default -install-rb-default: pre-install-rb-default -pre-install-rb: Makefile -pre-install-rb-default: Makefile -pre-install-rb-default: - @$(NULLCMD) - -site-install: site-install-so site-install-rb -site-install-so: install-so -site-install-rb: install-rb - diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/Makefile b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/Makefile deleted file mode 100644 index 0e1776b..0000000 --- a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/Makefile +++ /dev/null @@ -1,262 +0,0 @@ - -SHELL = /bin/sh - -# V=0 quiet, V=1 verbose. other values don't work. -V = 0 -Q1 = $(V:1=) -Q = $(Q1:0=@) -ECHO1 = $(V:1=@:) -ECHO = $(ECHO1:0=@echo) -NULLCMD = : - -#### Start of system configuration section. #### - -srcdir = . -topdir = /opt/chefdk/embedded/include/ruby-2.3.0 -hdrdir = $(topdir) -arch_hdrdir = /opt/chefdk/embedded/include/ruby-2.3.0/x86_64-darwin13 -PATH_SEPARATOR = : -VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby -prefix = $(DESTDIR)/opt/chefdk/embedded -rubysitearchprefix = $(rubylibprefix)/$(sitearch) -rubyarchprefix = $(rubylibprefix)/$(arch) -rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) -exec_prefix = $(prefix) -vendorarchhdrdir = $(vendorhdrdir)/$(sitearch) -sitearchhdrdir = $(sitehdrdir)/$(sitearch) -rubyarchhdrdir = $(rubyhdrdir)/$(arch) -vendorhdrdir = $(rubyhdrdir)/vendor_ruby -sitehdrdir = $(rubyhdrdir)/site_ruby -rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) -vendorarchdir = $(vendorlibdir)/$(sitearch) -vendorlibdir = $(vendordir)/$(ruby_version) -vendordir = $(rubylibprefix)/vendor_ruby -sitearchdir = $(DESTDIR)./.gem.20170131-68034-12q3abg -sitelibdir = $(DESTDIR)./.gem.20170131-68034-12q3abg -sitedir = $(rubylibprefix)/site_ruby -rubyarchdir = $(rubylibdir)/$(arch) -rubylibdir = $(rubylibprefix)/$(ruby_version) -sitearchincludedir = $(includedir)/$(sitearch) -archincludedir = $(includedir)/$(arch) -sitearchlibdir = $(libdir)/$(sitearch) -archlibdir = $(libdir)/$(arch) -ridir = $(datarootdir)/$(RI_BASE_NAME) -mandir = $(datarootdir)/man -localedir = $(datarootdir)/locale -libdir = $(exec_prefix)/lib -psdir = $(docdir) -pdfdir = $(docdir) -dvidir = $(docdir) -htmldir = $(docdir) -infodir = $(datarootdir)/info -docdir = $(datarootdir)/doc/$(PACKAGE) -oldincludedir = $(DESTDIR)/usr/include -includedir = $(SDKROOT)$(prefix)/include -localstatedir = $(prefix)/var -sharedstatedir = $(prefix)/com -sysconfdir = $(prefix)/etc -datadir = $(datarootdir) -datarootdir = $(prefix)/share -libexecdir = $(exec_prefix)/libexec -sbindir = $(exec_prefix)/sbin -bindir = $(exec_prefix)/bin -archdir = $(rubyarchdir) - - -CC = clang -CXX = g++ -LIBRUBY = $(LIBRUBY_SO) -LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a -LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) -LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation -empty = -OUTFLAG = -o $(empty) -COUTFLAG = -o $(empty) - -RUBY_EXTCONF_H = -cflags = $(optflags) $(debugflags) $(warnflags) -cxxflags = $(optflags) $(debugflags) $(warnflags) -optflags = -O3 -fno-fast-math -debugflags = -ggdb3 -warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -diag-disable=2259 -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens -CCDLFLAGS = -fno-common -CFLAGS = $(CCDLFLAGS) -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -O3 -g -pipe -Qunused-arguments -fno-common $(ARCH_FLAG) -INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -DEFS = -CPPFLAGS = -DJSON_GENERATOR -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -arch x86_64 -m64 -O3 -g -pipe -Qunused-arguments -I/opt/chefdk/embedded/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags) -CXXFLAGS = $(CCDLFLAGS) -I/opt/chefdk/embedded/include -O2 -I/opt/chefdk/embedded/include/ncurses -O3 -g -pipe -Qunused-arguments $(ARCH_FLAG) -ldflags = -L. -L/opt/chefdk/embedded/lib -fstack-protector -L/opt/chefdk/embedded/lib -dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -L/opt/chefdk/embedded/lib -ARCH_FLAG = -m64 -DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) -LDSHARED = $(CC) -dynamic -bundle -LDSHAREDXX = $(CXX) -dynamic -bundle -AR = ar -EXEEXT = - -RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) -RUBY_SO_NAME = ruby.2.3.0 -RUBYW_INSTALL_NAME = -RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) -RUBYW_BASE_NAME = rubyw -RUBY_BASE_NAME = ruby - -arch = x86_64-darwin13 -sitearch = $(arch) -ruby_version = 2.3.0 -ruby = $(bindir)/$(RUBY_BASE_NAME) -RUBY = $(ruby) -ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h - -RM = rm -f -RM_RF = $(RUBY) -run -e rm -- -rf -RMDIRS = rmdir -p -MAKEDIRS = mkdir -p -INSTALL = /usr/bin/install -c -INSTALL_PROG = $(INSTALL) -m 0755 -INSTALL_DATA = $(INSTALL) -m 644 -COPY = cp -TOUCH = exit > - -#### End of system configuration section. #### - -preload = - -libpath = . $(libdir) /opt/chefdk/embedded/lib -LIBPATH = -L. -L$(libdir) -L/opt/chefdk/embedded/lib -DEFFILE = - -CLEANFILES = mkmf.log -DISTCLEANFILES = -DISTCLEANDIRS = - -extout = -extout_prefix = -target_prefix = /json/ext -LOCAL_LIBS = -LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc -ORIG_SRCS = generator.c -SRCS = $(ORIG_SRCS) -OBJS = generator.o -HDRS = $(srcdir)/generator.h -TARGET = generator -TARGET_NAME = generator -TARGET_ENTRY = Init_$(TARGET_NAME) -DLLIB = $(TARGET).bundle -EXTSTATIC = -STATIC_LIB = - -TIMESTAMP_DIR = . -BINDIR = $(bindir) -RUBYCOMMONDIR = $(sitedir)$(target_prefix) -RUBYLIBDIR = $(sitelibdir)$(target_prefix) -RUBYARCHDIR = $(sitearchdir)$(target_prefix) -HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) -ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) - -TARGET_SO = $(DLLIB) -CLEANLIBS = $(TARGET).bundle -CLEANOBJS = *.o *.bak - -all: $(DLLIB) -static: $(STATIC_LIB) install-rb -.PHONY: all install static install-so install-rb -.PHONY: clean clean-so clean-static clean-rb - -clean-static:: -clean-rb-default:: -clean-rb:: -clean-so:: -clean: clean-so clean-static clean-rb-default clean-rb - -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time - -distclean-rb-default:: -distclean-rb:: -distclean-so:: -distclean-static:: -distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb - -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log - -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) - -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true - -realclean: distclean -install: install-so install-rb - -install-so: $(DLLIB) $(TIMESTAMP_DIR)/.RUBYARCHDIR.-.json.-.ext.time - $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) -clean-static:: - -$(Q)$(RM) $(STATIC_LIB) -install-rb: pre-install-rb install-rb-default -install-rb-default: pre-install-rb-default -pre-install-rb: Makefile -pre-install-rb-default: Makefile -pre-install-rb-default: - @$(NULLCMD) -$(TIMESTAMP_DIR)/.RUBYARCHDIR.-.json.-.ext.time: - $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) - $(Q) $(TOUCH) $@ - -site-install: site-install-so site-install-rb -site-install-so: install-so -site-install-rb: install-rb - -.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S - -.cc.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cc.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.mm.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.mm.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.cxx.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cxx.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.cpp.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cpp.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.c.o: - $(ECHO) compiling $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $< - -.c.S: - $(ECHO) translating $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $< - -.m.o: - $(ECHO) compiling $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $< - -.m.S: - $(ECHO) translating $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $< - -$(DLLIB): $(OBJS) Makefile - $(ECHO) linking shared-object json/ext/$(DLLIB) - -$(Q)$(RM) $(@) - $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) - $(Q) $(POSTLINK) - - - -### -generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.bundle b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.bundle deleted file mode 100755 index 58caf84dacda8c113a410bc832f5c4a625c02142..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49508 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 N{&bW1KW=(z{4Y0Bh1>uD diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.o b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/generator/generator.o deleted file mode 100644 index 8d72eda80bd9580ae4e63f38f1abdb4f4d5d25c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114500 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 - -#### End of system configuration section. #### - -preload = - -libpath = . $(libdir) /opt/chefdk/embedded/lib -LIBPATH = -L. -L$(libdir) -L/opt/chefdk/embedded/lib -DEFFILE = - -CLEANFILES = mkmf.log -DISTCLEANFILES = -DISTCLEANDIRS = - -extout = -extout_prefix = -target_prefix = /json/ext -LOCAL_LIBS = -LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc -ORIG_SRCS = parser.c -SRCS = $(ORIG_SRCS) -OBJS = parser.o -HDRS = $(srcdir)/parser.h -TARGET = parser -TARGET_NAME = parser -TARGET_ENTRY = Init_$(TARGET_NAME) -DLLIB = $(TARGET).bundle -EXTSTATIC = -STATIC_LIB = - -TIMESTAMP_DIR = . -BINDIR = $(bindir) -RUBYCOMMONDIR = $(sitedir)$(target_prefix) -RUBYLIBDIR = $(sitelibdir)$(target_prefix) -RUBYARCHDIR = $(sitearchdir)$(target_prefix) -HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) -ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) - -TARGET_SO = $(DLLIB) -CLEANLIBS = $(TARGET).bundle -CLEANOBJS = *.o *.bak - -all: $(DLLIB) -static: $(STATIC_LIB) install-rb -.PHONY: all install static install-so install-rb -.PHONY: clean clean-so clean-static clean-rb - -clean-static:: -clean-rb-default:: -clean-rb:: -clean-so:: -clean: clean-so clean-static clean-rb-default clean-rb - -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time - -distclean-rb-default:: -distclean-rb:: -distclean-so:: -distclean-static:: -distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb - -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log - -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) - -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true - -realclean: distclean -install: install-so install-rb - -install-so: $(DLLIB) $(TIMESTAMP_DIR)/.RUBYARCHDIR.-.json.-.ext.time - $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) -clean-static:: - -$(Q)$(RM) $(STATIC_LIB) -install-rb: pre-install-rb install-rb-default -install-rb-default: pre-install-rb-default -pre-install-rb: Makefile -pre-install-rb-default: Makefile -pre-install-rb-default: - @$(NULLCMD) -$(TIMESTAMP_DIR)/.RUBYARCHDIR.-.json.-.ext.time: - $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) - $(Q) $(TOUCH) $@ - -site-install: site-install-so site-install-rb -site-install-so: install-so -site-install-rb: install-rb - -.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S - -.cc.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cc.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.mm.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.mm.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.cxx.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cxx.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.cpp.o: - $(ECHO) compiling $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cpp.S: - $(ECHO) translating $(<) - $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $< - -.c.o: - $(ECHO) compiling $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $< - -.c.S: - $(ECHO) translating $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $< - -.m.o: - $(ECHO) compiling $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $< - -.m.S: - $(ECHO) translating $(<) - $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $< - -$(DLLIB): $(OBJS) Makefile - $(ECHO) linking shared-object json/ext/$(DLLIB) - -$(Q)$(RM) $(@) - $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) - $(Q) $(POSTLINK) - - - -### -parser.o: parser.c parser.h $(srcdir)/../fbuffer/fbuffer.h diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.bundle b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.bundle deleted file mode 100755 index 49a099e537dfa9a3bbdd7dfa4289c495e499949e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32908 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 diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.o b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/ext/json/ext/parser/parser.o deleted file mode 100644 index 3dfeb765306e081097c6c21e3c452869d7c4cef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54384 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 N{&bW1KW=(z{4Y0Bh1>uD diff --git a/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/lib/json/ext/parser.bundle b/chef/cookbooks/docker/files/default/vendor/gems/json-2.0.3/lib/json/ext/parser.bundle deleted file mode 100755 index 49a099e537dfa9a3bbdd7dfa4289c495e499949e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32908 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 diff --git a/chef/cookbooks/docker/kitchen.yml b/chef/cookbooks/docker/kitchen.yml new file mode 100644 index 0000000..650fff3 --- /dev/null +++ b/chef/cookbooks/docker/kitchen.yml @@ -0,0 +1,175 @@ +--- +driver: + name: dokken + chef_version: latest + privileged: true + volumes: [ + '/var/lib/docker', '/var/lib/docker-one', '/var/lib/docker-two' + ] + +transport: + name: dokken + +provisioner: + name: dokken + deprecations_as_errors: true + +verifier: + name: inspec + +platforms: +- name: amazonlinux + driver: + image: dokken/amazonlinux + pid_one_command: /sbin/init + +- name: amazonlinux-2 + driver: + image: dokken/amazonlinux-2 + pid_one_command: /usr/lib/systemd/systemd + +- name: debian-8 + driver: + image: dokken/debian-8 + pid_one_command: /bin/systemd + +- name: debian-9 + driver: + image: dokken/debian-9 + pid_one_command: /bin/systemd + +- name: centos-7 + driver: + image: dokken/centos-7 + pid_one_command: /usr/lib/systemd/systemd + +- name: fedora-28 + driver: + image: dokken/fedora-28 + pid_one_command: /usr/lib/systemd/systemd + +- name: ubuntu-16.04 + driver: + image: dokken/ubuntu-16.04 + pid_one_command: /bin/systemd + +- name: ubuntu-18.04 + driver: + image: dokken/ubuntu-18.04 + pid_one_command: /bin/systemd + +suites: + +############################### +# docker_installation resources +############################### +- name: installation_script_main + includes: [ + 'ubuntu-16.04', + 'ubuntu-18.04' + ] + attributes: + docker: + repo: 'main' + run_list: + - recipe[docker_test::installation_script] + +- name: installation_script_test + includes: [ + 'ubuntu-16.04', + 'ubuntu-18.04' + ] + attributes: + docker: + repo: 'test' + run_list: + - recipe[docker_test::installation_script] + +- name: installation_script_experimental + includes: [ + 'ubuntu-16.04', + 'ubuntu-18.04' + ] + attributes: + docker: + repo: 'experimental' + run_list: + - recipe[docker_test::installation_script] + +- name: installation_package + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::installation_package] + +- name: installation_tarball + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::installation_tarball] + includes: [ + 'ubuntu-16.04', + 'ubuntu-18.04' + ] + +################## +# resource testing +################## + +- name: resources + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::default] + - recipe[docker_test::image] + - recipe[docker_test::container] + - recipe[docker_test::exec] + - recipe[docker_test::plugin] + +- name: network + includes: [ + 'ubuntu-16.04', + ] + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::default] + - recipe[docker_test::network] + +- name: volume + includes: [ + 'ubuntu-16.04', + ] + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::default] + - recipe[docker_test::volume] + +- name: registry + includes: [ + 'ubuntu-16.04', + ] + attributes: + docker: + version: '18.06.0' + run_list: + - recipe[docker_test::default] + - recipe[docker_test::registry] + +############################# +# quick service smoke testing +############################# + +- name: smoke + includes: [ + 'ubuntu-16.04', + 'ubuntu-18.04' + ] + run_list: + - recipe[docker_test::smoke] diff --git a/chef/cookbooks/docker/libraries/_autoload.rb b/chef/cookbooks/docker/libraries/_autoload.rb deleted file mode 100644 index 3c007fd..0000000 --- a/chef/cookbooks/docker/libraries/_autoload.rb +++ /dev/null @@ -1,13 +0,0 @@ -begin - gem 'docker-api', '= 1.33.2' -rescue LoadError - unless defined?(ChefSpec) - run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new) - - require 'chef/resource/chef_gem' - - docker = Chef::Resource::ChefGem.new('docker-api', run_context) - docker.version '= 1.33.2' - docker.run_action(:install) - end -end diff --git a/chef/cookbooks/docker/libraries/docker_base.rb b/chef/cookbooks/docker/libraries/docker_base.rb index b7cd1a6..3efa423 100644 --- a/chef/cookbooks/docker/libraries/docker_base.rb +++ b/chef/cookbooks/docker/libraries/docker_base.rb @@ -1,9 +1,46 @@ module DockerCookbook class DockerBase < Chef::Resource - require_relative 'helpers_auth' - require_relative 'helpers_base' + require 'docker' + require 'shellwords' - include DockerHelpers::Base + ################ + # Helper methods + ################ + + def connection + @connection ||= begin + opts = {} + opts[:read_timeout] = read_timeout if read_timeout + opts[:write_timeout] = write_timeout if write_timeout + + if host =~ /^tcp:/ + opts[:scheme] = 'https' if tls || !tls_verify.nil? + opts[:ssl_ca_file] = tls_ca_cert if tls_ca_cert + opts[:client_cert] = tls_client_cert if tls_client_cert + opts[:client_key] = tls_client_key if tls_client_key + end + Docker::Connection.new(host || Docker.url, opts) + end + end + + def with_retries(&_block) + tries = api_retries + begin + yield + # Only catch errors that can be fixed with retries. + rescue Docker::Error::ServerError, # 500 + Docker::Error::UnexpectedResponseError, # 400 + Docker::Error::TimeoutError, + Docker::Error::IOError + tries -= 1 + retry if tries > 0 + raise + end + end + + def call_action(_action) + new_resource.run_action + end ######### # Classes @@ -16,12 +53,6 @@ module DockerCookbook end end - class ShellCommandString < String - def ==(other) - other.is_a?(String) && Shellwords.shellwords(self) == Shellwords.shellwords(other) - end - end - class PartialHash < Hash def ==(other) other.is_a?(Hash) && all? { |key, val| other.key?(key) && other[key] == val } @@ -36,26 +67,6 @@ module DockerCookbook # ################ - ArrayType = property_type( - is: [Array, nil], - coerce: proc { |v| v.nil? ? nil : Array(v) } - ) unless defined?(ArrayType) - - Boolean = property_type( - is: [true, false], - default: false - ) unless defined?(Boolean) - - NonEmptyArray = property_type( - is: [Array, nil], - coerce: proc { |v| Array(v).empty? ? nil : Array(v) } - ) unless defined?(NonEmptyArray) - - ShellCommand = property_type( - is: [String], - coerce: proc { |v| coerce_shell_command(v) } - ) unless defined?(ShellCommand) - UnorderedArrayType = property_type( is: [UnorderedArray, nil], coerce: proc { |v| v.nil? ? nil : UnorderedArray.new(Array(v)) } @@ -70,21 +81,57 @@ module DockerCookbook # Resource properties ##################### - property :api_retries, Integer, default: 3, desired_state: false - property :read_timeout, [Integer, nil], default: 60, desired_state: false - property :write_timeout, [Integer, nil], desired_state: false - property :running_wait_time, [Integer, nil], default: 20, desired_state: false + property :api_retries, Integer, + default: 3, + desired_state: false - property :tls, [Boolean, nil], default: lazy { default_tls }, desired_state: false - property :tls_verify, [Boolean, nil], default: lazy { default_tls_verify }, desired_state: false - property :tls_ca_cert, [String, nil], default: lazy { default_tls_cert_path('ca') }, desired_state: false - property :tls_server_cert, [String, nil], desired_state: false - property :tls_server_key, [String, nil], desired_state: false - property :tls_client_cert, [String, nil], default: lazy { default_tls_cert_path('cert') }, desired_state: false - property :tls_client_key, [String, nil], default: lazy { default_tls_cert_path('key') }, desired_state: false + property :read_timeout, Integer, + default: 60, + desired_state: false + + property :write_timeout, Integer, + desired_state: false + + property :running_wait_time, Integer, + default: 20, + desired_state: false + + property :tls, [TrueClass, FalseClass, nil], + default: lazy { ENV['DOCKER_TLS'] }, + desired_state: false + + property :tls_verify, [TrueClass, FalseClass, nil], + default: lazy { ENV['DOCKER_TLS_VERIFY'] }, + desired_state: false + + property :tls_ca_cert, [String, nil], + default: lazy { ENV['DOCKER_CERT_PATH'] ? "#{ENV['DOCKER_CERT_PATH']}/ca.pem" : nil }, + desired_state: false + + property :tls_server_cert, String, + desired_state: false + + property :tls_server_key, String, + desired_state: false + + property :tls_client_cert, [String, nil], + default: lazy { ENV['DOCKER_CERT_PATH'] ? "#{ENV['DOCKER_CERT_PATH']}/cert.pem" : nil }, + desired_state: false + + property :tls_client_key, [String, nil], + default: lazy { ENV['DOCKER_CERT_PATH'] ? "#{ENV['DOCKER_CERT_PATH']}/key.pem" : nil }, + desired_state: false + + alias_method :tlscacert, :tls_ca_cert + alias_method :tlscert, :tls_server_cert + alias_method :tlskey, :tls_server_key + alias_method :tlsverify, :tls_verify declare_action_class.class_eval do - include DockerHelpers::Authentication + # https://github.com/docker/docker/blob/4fcb9ac40ce33c4d6e08d5669af6be5e076e2574/registry/auth.go#L231 + def parse_registry_host(val) + val.sub(%r{https?://}, '').split('/').first + end end end end diff --git a/chef/cookbooks/docker/libraries/docker_container.rb b/chef/cookbooks/docker/libraries/docker_container.rb index 1a8f0a6..f9b27e7 100644 --- a/chef/cookbooks/docker/libraries/docker_container.rb +++ b/chef/cookbooks/docker/libraries/docker_container.rb @@ -1,93 +1,78 @@ module DockerCookbook class DockerContainer < DockerBase - require 'docker' - require 'shellwords' - require_relative 'helpers_container' - - include DockerHelpers::Container - resource_name :docker_container - ########################################################### - # In Chef 12.5 and later, we no longer have to use separate - # classes for resource and providers. Instead, we have - # everything in a single class. - # - # For the purposes of my own sanity, I'm going to place all the - # "resource" related bits at the top of the files, and the - # providerish bits at the bottom. - # - # - # Methods for default values and coersion are found in - # helpers_container.rb - ########################################################### - - # ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ - # Begin classic Chef "resource" section - # ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ - - # The non-standard types Boolean, ArrayType, ShellCommand, etc - # are found in the DockerBase class. property :container_name, String, name_property: true property :repo, String, default: lazy { container_name } property :tag, String, default: 'latest' - property :command, ShellCommand - property :attach_stderr, Boolean, default: false, desired_state: false - property :attach_stdin, Boolean, default: false, desired_state: false - property :attach_stdout, Boolean, default: false, desired_state: false - property :autoremove, Boolean, desired_state: false - property :cap_add, NonEmptyArray - property :cap_drop, NonEmptyArray + property :command, [Array, String, nil], coerce: proc { |v| v.is_a?(String) ? ::Shellwords.shellwords(v) : v } + property :attach_stderr, [TrueClass, FalseClass], default: false, desired_state: false + property :attach_stdin, [TrueClass, FalseClass], default: false, desired_state: false + property :attach_stdout, [TrueClass, FalseClass], default: false, desired_state: false + property :autoremove, [TrueClass, FalseClass], default: false, desired_state: false + property :cap_add, [Array, nil], coerce: proc { |v| Array(v).empty? ? nil : Array(v) } + property :cap_drop, [Array, nil], coerce: proc { |v| Array(v).empty? ? nil : Array(v) } property :cgroup_parent, String, default: '' - property :cpu_shares, [Integer, nil], default: 0 + property :cpu_shares, Integer, default: 0 property :cpuset_cpus, String, default: '' - property :detach, Boolean, default: true, desired_state: false + property :detach, [TrueClass, FalseClass], default: true, desired_state: false property :devices, Array, default: [] property :dns, Array, default: [] property :dns_search, Array, default: [] property :domain_name, String, default: '' - property :entrypoint, ShellCommand + property :entrypoint, [Array, String, nil], coerce: proc { |v| v.is_a?(String) ? ::Shellwords.shellwords(v) : v } property :env, UnorderedArrayType, default: [] - property :extra_hosts, NonEmptyArray + property :env_file, [Array, String], coerce: proc { |v| coerce_env_file(v) }, default: [], desired_state: false + property :extra_hosts, [Array, nil], coerce: proc { |v| Array(v).empty? ? nil : Array(v) } property :exposed_ports, PartialHashType, default: {} - property :force, Boolean, desired_state: false - property :host, [String, nil], default: lazy { default_host }, desired_state: false + property :force, [TrueClass, FalseClass], default: false, desired_state: false + property :health_check, Hash, default: {} + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false property :hostname, String property :ipc_mode, String, default: '' + property :kernel_memory, [String, Integer], coerce: proc { |v| coerce_to_bytes(v) }, default: 0 property :labels, [String, Array, Hash], default: {}, coerce: proc { |v| coerce_labels(v) } property :links, UnorderedArrayType, coerce: proc { |v| coerce_links(v) } property :log_driver, %w( json-file syslog journald gelf fluentd awslogs splunk etwlogs gcplogs none ), default: 'json-file', desired_state: false property :log_opts, [Hash, nil], coerce: proc { |v| coerce_log_opts(v) }, desired_state: false + property :init, [TrueClass, FalseClass, nil] property :ip_address, String property :mac_address, String - property :memory, Integer, default: 0 - property :memory_swap, Integer, default: 0 - property :network_disabled, Boolean, default: false - property :network_mode, [String, NilClass], default: 'bridge' - property :open_stdin, Boolean, default: false, desired_state: false - property :outfile, [String, NilClass] + property :memory, [String, Integer], coerce: proc { |v| coerce_to_bytes(v) }, default: 0 + property :memory_swap, [String, Integer], coerce: proc { |v| coerce_to_bytes(v) }, default: 0 + property :memory_swappiness, Integer, default: 0 + property :memory_reservation, Integer, coerce: proc { |v| coerce_to_bytes(v) }, default: 0 + property :network_disabled, [TrueClass, FalseClass], default: false + property :network_mode, String, default: 'bridge' + property :network_aliases, [String, Array], default: [], coerce: proc { |v| Array(v) } + property :oom_kill_disable, [TrueClass, FalseClass], default: false + property :oom_score_adj, Integer, default: -500 + property :open_stdin, [TrueClass, FalseClass], default: false, desired_state: false + property :outfile, String property :port_bindings, PartialHashType, default: {} property :pid_mode, String, default: '' - property :privileged, Boolean, default: false - property :publish_all_ports, Boolean, default: false - property :remove_volumes, Boolean + property :privileged, [TrueClass, FalseClass], default: false + property :publish_all_ports, [TrueClass, FalseClass], default: false + property :remove_volumes, [TrueClass, FalseClass], default: false property :restart_maximum_retry_count, Integer, default: 0 property :restart_policy, String - property :ro_rootfs, Boolean, default: false - property :security_opts, [String, ArrayType] + property :runtime, String, default: 'runc' + property :ro_rootfs, [TrueClass, FalseClass], default: false + property :security_opt, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :shm_size, [String, Integer], default: '64m', coerce: proc { |v| coerce_to_bytes(v) } property :signal, String, default: 'SIGTERM' - property :stdin_once, Boolean, default: false, desired_state: false + property :stdin_once, [TrueClass, FalseClass], default: false, desired_state: false property :sysctls, Hash, default: {} - property :timeout, [Integer, nil], desired_state: false - property :tty, Boolean, default: false + property :timeout, Integer, desired_state: false + property :tty, [TrueClass, FalseClass], default: false property :ulimits, [Array, nil], coerce: proc { |v| coerce_ulimits(v) } property :user, String, default: '' property :userns_mode, String, default: '' property :uts_mode, String, default: '' property :volumes, PartialHashType, default: {}, coerce: proc { |v| coerce_volumes(v) } - property :volumes_from, ArrayType + property :volumes_from, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } property :volume_driver, String - property :working_dir, [String, NilClass], default: '' + property :working_dir, String, default: '' # Used to store the bind property since binds is an alias to volumes property :volumes_binds, Array @@ -95,32 +80,324 @@ module DockerCookbook # Used to store the state of the Docker container property :container, Docker::Container, desired_state: false + # Used to store the state of the Docker container create options + property :create_options, Hash, default: {}, desired_state: false + # Used by :stop action. If the container takes longer than this - # many seconds to stop, kill itinstead. -1 (the default) means + # many seconds to stop, kill it instead. A nil value (the default) means # never kill the container. - property :kill_after, Numeric, default: -1, desired_state: false + property :kill_after, [Integer, NilClass], default: nil, desired_state: false - alias cmd command - alias additional_host extra_hosts - alias rm autoremove - alias remove_automatically autoremove - alias host_name hostname - alias domainname domain_name - alias dnssearch dns_search - alias restart_maximum_retries restart_maximum_retry_count - alias volume volumes - alias binds volumes - alias volume_from volumes_from - alias destination outfile - alias workdir working_dir + alias_method :cmd, :command + alias_method :additional_host, :extra_hosts + alias_method :rm, :autoremove + alias_method :remove_automatically, :autoremove + alias_method :host_name, :hostname + alias_method :domainname, :domain_name + alias_method :dnssearch, :dns_search + alias_method :restart_maximum_retries, :restart_maximum_retry_count + alias_method :volume, :volumes + alias_method :binds, :volumes + alias_method :volume_from, :volumes_from + alias_method :destination, :outfile + alias_method :workdir, :working_dir - # ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ - # Begin classic Chef "provider" section - # ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ + ################### + # Property helpers + ################### - ######################################################## + def coerce_labels(v) + case v + when Hash, nil + v + else + Array(v).each_with_object({}) do |label, h| + parts = label.split(':') + h[parts[0]] = parts[1..-1].join(':') + end + end + end + + def coerce_links(v) + case v + when DockerBase::UnorderedArray, nil + v + else + return nil if v.empty? + # Parse docker input of /source:/container_name/dest into source:dest + DockerBase::UnorderedArray.new(Array(v)).map! do |link| + if link =~ %r{^/(?.+):/#{name}/(?.+)} + link = "#{Regexp.last_match[:source]}:#{Regexp.last_match[:dest]}" + end + link + end + end + end + + def to_bytes(v) + n = v.to_i + u = v.gsub(/\d/, '').upcase + + multiplier = case u + when 'B' + 1 + when 'K' + 1024**1 + when 'M' + 1024**2 + when 'G' + 1024**3 + when 'T' + 1024**4 + when 'P' + 1024**5 + when 'E' + 1024**6 + when 'Z' + 1024**7 + when 'Y' + 1024**8 + else + 1 + end + + n * multiplier + end + + def coerce_to_bytes(v) + case v + when Integer, nil + v + else + to_bytes(v) + end + end + + def coerce_log_opts(v) + case v + when Hash, nil + v + else + Array(v).each_with_object({}) do |log_opt, memo| + key, value = log_opt.split('=', 2) + memo[key] = value + end + end + end + + def coerce_ulimits(v) + return v if v.nil? + Array(v).map do |u| + u = "#{u['Name']}=#{u['Soft']}:#{u['Hard']}" if u.is_a?(Hash) + u + end + end + + def coerce_volumes(v) + case v + when DockerBase::PartialHash, nil + v + when Hash + DockerBase::PartialHash[v] + else + b = [] + v = Array(v).to_a # in case v.is_A?(Chef::Node::ImmutableArray) + v.delete_if do |x| + parts = x.split(':') + b << x if parts.length > 1 + end + b = nil if b.empty? + volumes_binds b + return DockerBase::PartialHash.new if v.empty? + v.each_with_object(DockerBase::PartialHash.new) { |volume, h| h[volume] = {} } + end + end + + def state + # Always return the latest state, see #510 + Docker::Container.get(container_name, {}, connection).info['State'] + rescue StandardError + {} + end + + def wait_running_state(v) + tries = running_wait_time + tries.times do + return if state['Running'] == v + sleep 1 + end + return if state['Running'] == v + + # Container failed to reach correct state: Throw an error + desired_state_str = v ? 'running' : 'not running' + raise Docker::Error::TimeoutError, "Container #{container_name} failed to change to #{desired_state_str} state after #{tries} seconds" + end + + def port(v = nil) + return @port if v.nil? + exposed_ports coerce_exposed_ports(v) + port_bindings coerce_port_bindings(v) + @port = v + @port + end + + def parse_port(v) + _, protocol = v.split('/') + parts = v.split(':') + case parts.length + when 3 + host_ip = parts[0] + host_port = parts[1].split('-') + container_port = parts[2].split('-') + when 2 + host_ip = '0.0.0.0' + host_port = parts[0].split('-') + container_port = parts[1].split('-') + when 1 + host_ip = '' + host_port = [''] + container_port = parts[0].split('-') + end + host_port.map!(&:to_i) unless host_port == [''] + container_port.map!(&:to_i) + if host_port.count > 1 + Chef::Log.fatal("FATAL: Invalid port range! #{host_port}") if host_port[0] > host_port[1] + host_port = (host_port[0]..host_port[1]).to_a + end + if container_port.count > 1 + Chef::Log.fatal("FATAL: Invalid port range! #{container_port}") if container_port[0] > container_port[1] + container_port = (container_port[0]..container_port[1]).to_a + end + Chef::Log.fatal('FATAL: Port range size does not match!') if host_port.count > 1 && host_port.count != container_port.count + # qualify the port-binding protocol even when it is implicitly tcp #427. + protocol = 'tcp' if protocol.nil? + Array(container_port).map.with_index do |_, i| + { + 'host_ip' => host_ip, + 'host_port' => host_port[i].to_s, + 'container_port' => "#{container_port[i]}/#{protocol}", + } + end + end + + def coerce_exposed_ports(v) + case v + when Hash, nil + v + else + x = Array(v).map { |a| parse_port(a) } + x.flatten! + x.each_with_object({}) do |y, h| + h[y['container_port']] = {} + end + end + end + + def coerce_port_bindings(v) + case v + when Hash, nil + v + else + x = Array(v).map { |a| parse_port(a) } + x.flatten! + x.each_with_object({}) do |y, h| + h[y['container_port']] = [] unless h[y['container_port']] + h[y['container_port']] << { + 'HostIp' => y['host_ip'], + 'HostPort' => y['host_port'], + } + end + end + end + + def coerce_env_file(v) + return v if v.empty? + Array(v).map { |f| ::File.readlines(f).map(&:strip) }.flatten + end + + # log_driver and log_opts really handle this + def log_config(value = Chef::NOT_PASSED) + if value != Chef::NOT_PASSED + @log_config = value + log_driver value['Type'] + log_opts value['Config'] + end + return @log_config if defined?(@log_config) + def_logcfg = {} + def_logcfg['Type'] = log_driver if property_is_set?(:log_driver) + def_logcfg['Config'] = log_opts if property_is_set?(:log_opts) + def_logcfg = nil if def_logcfg.empty? + def_logcfg + end + + # TODO: test image property in serverspec and kitchen, not only in rspec + # for full specs of image parsing, see spec/helpers_container_spec.rb + # + # If you say: `repo 'blah'` + # Image will be: `blah:latest` + # + # If you say: `repo 'blah'; tag '3.1'` + # Image will be: `blah:3.1` + # + # If you say: `image 'blah'` + # Repo will be: `blah` + # Tag will be: `latest` + # + # If you say: `image 'blah:3.1'` + # Repo will be: `blah` + # Tag will be: `3.1` + # + # If you say: `image 'repo/blah'` + # Repo will be: `repo/blah` + # Tag will be: `latest` + # + # If you say: `image 'repo/blah:3.1'` + # Repo will be: `repo/blah` + # Tag will be: `3.1` + # + # If you say: `image 'repo:1337/blah'` + # Repo will be: `repo:1337/blah` + # Tag will be: `latest' + # + # If you say: `image 'repo:1337/blah:3.1'` + # Repo will be: `repo:1337/blah` + # Tag will be: `3.1` + # + def image(image = nil) + if image + if image.include?('/') + # pathological case, a ':' may be present which starts the 'port' + # part of the image name and not a tag. example: 'host:1337/blah' + # fortunately, tags are only found in the 'basename' part of image + # so we can split on '/' and rebuild once the tag has been parsed. + dirname, _, basename = image.rpartition('/') + r, t = basename.split(':', 2) + r = [dirname, r].join('/') + else + # normal case, the ':' starts the tag part + r, t = image.split(':', 2) + end + repo r + tag t if t + end + "#{repo}:#{tag}" + end + + def to_shellwords(command) + command.is_a?(String) ? ::Shellwords.shellwords(command) : command + end + + ###################### # Load Current Value - ######################################################## + ###################### + + def to_snake_case(name) + # ExposedPorts -> _exposed_ports + name = name.gsub(/[A-Z]/) { |x| "_#{x.downcase}" } + # _exposed_ports -> exposed_ports + name = name[1..-1] if name.start_with?('_') + name + end load_current_value do # Grab the container and assign the container property @@ -149,6 +426,27 @@ module DockerCookbook restart_maximum_retry_count container.info['HostConfig']['RestartPolicy']['MaximumRetryCount'] volumes_binds container.info['HostConfig']['Binds'] ro_rootfs container.info['HostConfig']['ReadonlyRootfs'] + ip_address ip_address_from_container_networks(container) unless ip_address_from_container_networks(container).nil? + end + + # Gets the ip address from the existing container + # current docker api of 1.16 does not have ['NetworkSettings']['Networks'] + # For docker > 1.21 - use ['NetworkSettings']['Networks'] + # + # @param container [Docker::Container] A container object + # @returns [String] An ip_address + def ip_address_from_container_networks(container) + # We use the first value in 'Networks' + # We can't assume it will be 'bridged' + # It might also not match the new_resource value + if container.info['NetworkSettings'] && + container.info['NetworkSettings']['Networks'] && + container.info['NetworkSettings']['Networks'].values[0] && + container.info['NetworkSettings']['Networks'].values[0]['IPAMConfig'] && + container.info['NetworkSettings']['Networks'].values[0]['IPAMConfig']['IPv4Address'] + # Return the ip address listed + container.info['NetworkSettings']['Networks'].values[0]['IPAMConfig']['IPv4Address'] + end end ######### @@ -158,23 +456,6 @@ module DockerCookbook # Super handy visual reference! # http://gliderlabs.com/images/docker_events.png - default_action :run - - declare_action_class.class_eval do - def whyrun_supported? - true - end - - def call_action(action) - send("action_#{action}") - load_current_resource - end - - def state - current_resource ? current_resource.state : {} - end - end - # Loads container specific labels excluding those of engine or image. # This insures idempotency. def load_container_labels @@ -189,56 +470,11 @@ module DockerCookbook public_send(:labels, labels) end - def validate_container_create - if property_is_set?(:restart_policy) && - restart_policy != 'no' && - restart_policy != 'always' && - restart_policy != 'unless-stopped' && - restart_policy != 'on-failure' - raise Chef::Exceptions::ValidationFailed, 'restart_policy must be either no, always, unless-stopped, or on-failure.' - end - - if autoremove == true && (property_is_set?(:restart_policy) && restart_policy != 'no') - raise Chef::Exceptions::ValidationFailed, 'Conflicting options restart_policy and autoremove.' - end - - if detach == true && - ( - attach_stderr == true || - attach_stdin == true || - attach_stdout == true || - stdin_once == true - ) - raise Chef::Exceptions::ValidationFailed, 'Conflicting options detach, attach_stderr, attach_stdin, attach_stdout, stdin_once.' - end - - if network_mode == 'host' && - ( - !(hostname.nil? || hostname.empty?) || - !(mac_address.nil? || mac_address.empty?) - ) - raise Chef::Exceptions::ValidationFailed, 'Cannot specify hostname or mac_address when network_mode is host.' - end - - if network_mode == 'container' && - ( - !(hostname.nil? || hostname.empty?) || - !(dns.nil? || dns.empty?) || - !(dns_search.nil? || dns_search.empty?) || - !(mac_address.nil? || mac_address.empty?) || - !(extra_hosts.nil? || extra_hosts.empty?) || - !(exposed_ports.nil? || exposed_ports.empty?) || - !(port_bindings.nil? || port_bindings.empty?) || - !(publish_all_ports.nil? || publish_all_ports.empty?) || - !port.nil? - ) - raise Chef::Exceptions::ValidationFailed, 'Cannot specify hostname, dns, dns_search, mac_address, extra_hosts, exposed_ports, port_bindings, publish_all_ports, port when network_mode is container.' - end - end - - def parsed_hostname - return nil if network_mode == 'host' - hostname + action :run do + validate_container_create + call_action(:create) + call_action(:start) + call_action(:delete) if new_resource.autoremove end action :create do @@ -249,73 +485,94 @@ module DockerCookbook with_retries do config = { - 'name' => container_name, - 'Image' => "#{repo}:#{tag}", - 'Labels' => labels, - 'Cmd' => to_shellwords(command), - 'AttachStderr' => attach_stderr, - 'AttachStdin' => attach_stdin, - 'AttachStdout' => attach_stdout, - 'Domainname' => domain_name, - 'Entrypoint' => to_shellwords(entrypoint), - 'Env' => env, - 'ExposedPorts' => exposed_ports, + 'name' => new_resource.container_name, + 'Image' => "#{new_resource.repo}:#{new_resource.tag}", + 'Labels' => new_resource.labels, + 'Cmd' => to_shellwords(new_resource.command), + 'AttachStderr' => new_resource.attach_stderr, + 'AttachStdin' => new_resource.attach_stdin, + 'AttachStdout' => new_resource.attach_stdout, + 'Domainname' => new_resource.domain_name, + 'Entrypoint' => to_shellwords(new_resource.entrypoint), + 'Env' => new_resource.env + new_resource.env_file, + 'ExposedPorts' => new_resource.exposed_ports, 'Hostname' => parsed_hostname, - 'MacAddress' => mac_address, - 'NetworkDisabled' => network_disabled, - 'OpenStdin' => open_stdin, - 'StdinOnce' => stdin_once, - 'Tty' => tty, - 'User' => user, - 'Volumes' => volumes, - 'WorkingDir' => working_dir, + 'MacAddress' => new_resource.mac_address, + 'NetworkDisabled' => new_resource.network_disabled, + 'OpenStdin' => new_resource.open_stdin, + 'StdinOnce' => new_resource.stdin_once, + 'Tty' => new_resource.tty, + 'User' => new_resource.user, + 'Volumes' => new_resource.volumes, + 'WorkingDir' => new_resource.working_dir, 'HostConfig' => { - 'Binds' => volumes_binds, - 'CapAdd' => cap_add, - 'CapDrop' => cap_drop, - 'CgroupParent' => cgroup_parent, - 'CpuShares' => cpu_shares, - 'CpusetCpus' => cpuset_cpus, - 'Devices' => devices, - 'Dns' => dns, - 'DnsSearch' => dns_search, - 'ExtraHosts' => extra_hosts, - 'IpcMode' => ipc_mode, - 'Links' => links, + 'Binds' => new_resource.volumes_binds, + 'CapAdd' => new_resource.cap_add, + 'CapDrop' => new_resource.cap_drop, + 'CgroupParent' => new_resource.cgroup_parent, + 'CpuShares' => new_resource.cpu_shares, + 'CpusetCpus' => new_resource.cpuset_cpus, + 'Devices' => new_resource.devices, + 'Dns' => new_resource.dns, + 'DnsSearch' => new_resource.dns_search, + 'ExtraHosts' => new_resource.extra_hosts, + 'IpcMode' => new_resource.ipc_mode, + 'Init' => new_resource.init, + 'KernelMemory' => new_resource.kernel_memory, + 'Links' => new_resource.links, 'LogConfig' => log_config, - 'Memory' => memory, - 'MemorySwap' => memory_swap, - 'NetworkMode' => network_mode, - 'Privileged' => privileged, - 'PidMode' => pid_mode, - 'PortBindings' => port_bindings, - 'PublishAllPorts' => publish_all_ports, + 'Memory' => new_resource.memory, + 'MemorySwap' => new_resource.memory_swap, + 'MemorySwappiness' => new_resource.memory_swappiness, + 'MemoryReservation' => new_resource.memory_reservation, + 'NetworkMode' => new_resource.network_mode, + 'OomKillDisable' => new_resource.oom_kill_disable, + 'OomScoreAdj' => new_resource.oom_score_adj, + 'Privileged' => new_resource.privileged, + 'PidMode' => new_resource.pid_mode, + 'PortBindings' => new_resource.port_bindings, + 'PublishAllPorts' => new_resource.publish_all_ports, 'RestartPolicy' => { - 'Name' => restart_policy, - 'MaximumRetryCount' => restart_maximum_retry_count, + 'Name' => new_resource.restart_policy, + 'MaximumRetryCount' => new_resource.restart_maximum_retry_count, }, - 'ReadonlyRootfs' => ro_rootfs, - 'Sysctls' => sysctls, + 'ReadonlyRootfs' => new_resource.ro_rootfs, + 'Runtime' => new_resource.runtime, + 'SecurityOpt' => new_resource.security_opt, + 'ShmSize' => new_resource.shm_size, + 'Sysctls' => new_resource.sysctls, 'Ulimits' => ulimits_to_hash, - 'UsernsMode' => userns_mode, - 'UTSMode' => uts_mode, - 'VolumesFrom' => volumes_from, - 'VolumeDriver' => volume_driver, + 'UsernsMode' => new_resource.userns_mode, + 'UTSMode' => new_resource.uts_mode, + 'VolumesFrom' => new_resource.volumes_from, + 'VolumeDriver' => new_resource.volume_driver, }, } net_config = { 'NetworkingConfig' => { 'EndpointsConfig' => { - network_mode => { + new_resource.network_mode => { 'IPAMConfig' => { - 'IPv4Address' => ip_address, + 'IPv4Address' => new_resource.ip_address, }, + 'Aliases' => new_resource.network_aliases, }, }, }, - } if network_mode + } if new_resource.network_mode config.merge! net_config + # Remove any options not supported in windows + if platform?('windows') + config['HostConfig'].delete('MemorySwappiness') + end + + unless new_resource.health_check.empty? + config['Healthcheck'] = new_resource.health_check + end + + # Store the state of the options and create the container + new_resource.create_options = config Docker::Container.create(config, connection) end end @@ -324,44 +581,40 @@ module DockerCookbook action :start do return if state['Restarting'] return if state['Running'] - converge_by "starting #{container_name}" do + converge_by "starting #{new_resource.container_name}" do with_retries do - container.start - timeout ? container.wait(timeout) : container.wait unless detach + current_resource.container.start + + unless new_resource.detach + new_resource.timeout ? current_resource.container.wait(new_resource.timeout) : current_resource.container.wait + end end - wait_running_state(true) if detach + wait_running_state(true) if new_resource.detach end end action :stop do return unless state['Running'] - kill_after_str = " (will kill after #{kill_after}s)" if kill_after != -1 - converge_by "stopping #{container_name} #{kill_after_str}" do + kill_after_str = "(will kill after #{new_resource.kill_after}s)" if new_resource.kill_after + converge_by "stopping #{new_resource.container_name} #{kill_after_str}" do begin with_retries do - container.stop!('timeout' => kill_after) + current_resource.container.stop!('timeout' => new_resource.kill_after) wait_running_state(false) end rescue Docker::Error::TimeoutError - raise Docker::Error::TimeoutError, "Container failed to stop, consider adding kill_after to the container #{container_name}" + raise Docker::Error::TimeoutError, "Container failed to stop, consider adding kill_after to the container #{new_resource.container_name}" end end end action :kill do return unless state['Running'] - converge_by "killing #{container_name}" do - with_retries { container.kill(signal: signal) } + converge_by "killing #{new_resource.container_name}" do + with_retries { current_resource.container.kill(signal: new_resource.signal) } end end - action :run do - validate_container_create - call_action(:create) - call_action(:start) - call_action(:delete) if autoremove - end - action :run_if_missing do return if current_resource call_action(:run) @@ -369,28 +622,28 @@ module DockerCookbook action :pause do return if state['Paused'] - converge_by "pausing #{container_name}" do - with_retries { container.pause } + converge_by "pausing #{new_resource.container_name}" do + with_retries { current_resource.container.pause } end end action :unpause do return if current_resource && !state['Paused'] - converge_by "unpausing #{container_name}" do - with_retries { container.unpause } + converge_by "unpausing #{new_resource.container_name}" do + with_retries { current_resource.container.unpause } end end action :restart do - kill_after_str = " (will kill after #{kill_after}s)" if kill_after != -1 - converge_by "restarting #{container_name} #{kill_after_str}" do - current_resource ? container.restart('timeout' => kill_after) : call_action(:run) + kill_after_str = " (will kill after #{new_resource.kill_after}s)" if new_resource.kill_after != -1 + converge_by "restarting #{new_resource.container_name} #{kill_after_str}" do + current_resource ? current_resource.container.restart('timeout' => new_resource.kill_after) : call_action(:run) end end action :reload do - converge_by "reloading #{container_name}" do - with_retries { container.kill(signal: 'SIGHUP') } + converge_by "reloading #{new_resource.container_name}" do + with_retries { current_resource.container.kill(signal: 'SIGHUP') } end end @@ -407,8 +660,8 @@ module DockerCookbook return unless current_resource call_action(:unpause) call_action(:stop) - converge_by "deleting #{container_name}" do - with_retries { container.delete(force: force, v: remove_volumes) } + converge_by "deleting #{new_resource.container_name}" do + with_retries { current_resource.container.delete(force: new_resource.force, v: new_resource.remove_volumes) } end end @@ -417,19 +670,92 @@ module DockerCookbook end action :commit do - converge_by "committing #{container_name}" do + converge_by "committing #{new_resource.container_name}" do with_retries do - new_image = container.commit - new_image.tag('repo' => repo, 'tag' => tag, 'force' => force) + new_image = current_resource.container.commit + new_image.tag('repo' => new_resource.repo, 'tag' => new_resource.tag, 'force' => new_resource.force) end end end action :export do - raise "Please set outfile property on #{container_name}" if outfile.nil? - converge_by "exporting #{container_name}" do + raise "Please set outfile property on #{new_resource.container_name}" if new_resource.outfile.nil? + converge_by "exporting #{new_resource.container_name}" do with_retries do - ::File.open(outfile, 'w') { |f| container.export { |chunk| f.write(chunk) } } + ::File.open(new_resource.outfile, 'w') { |f| current_resource.container.export { |chunk| f.write(chunk) } } + end + end + end + + declare_action_class.class_eval do + def validate_container_create + if new_resource.property_is_set?(:restart_policy) && + new_resource.restart_policy != 'no' && + new_resource.restart_policy != 'always' && + new_resource.restart_policy != 'unless-stopped' && + new_resource.restart_policy != 'on-failure' + raise Chef::Exceptions::ValidationFailed, 'restart_policy must be either no, always, unless-stopped, or on-failure.' + end + + if new_resource.autoremove == true && (new_resource.property_is_set?(:restart_policy) && restart_policy != 'no') + raise Chef::Exceptions::ValidationFailed, 'Conflicting options restart_policy and autoremove.' + end + + if new_resource.detach == true && + ( + new_resource.attach_stderr == true || + new_resource.attach_stdin == true || + new_resource.attach_stdout == true || + new_resource.stdin_once == true + ) + raise Chef::Exceptions::ValidationFailed, 'Conflicting options detach, attach_stderr, attach_stdin, attach_stdout, stdin_once.' + end + + if new_resource.network_mode == 'host' && + ( + !(new_resource.hostname.nil? || new_resource.hostname.empty?) || + !(new_resource.mac_address.nil? || new_resource.mac_address.empty?) + ) + raise Chef::Exceptions::ValidationFailed, 'Cannot specify hostname or mac_address when network_mode is host.' + end + + if new_resource.network_mode == 'container' && + ( + !(new_resource.hostname.nil? || new_resource.hostname.empty?) || + !(new_resource.dns.nil? || new_resource.dns.empty?) || + !(new_resource.dns_search.nil? || new_resource.dns_search.empty?) || + !(new_resource.mac_address.nil? || new_resource.mac_address.empty?) || + !(new_resource.extra_hosts.nil? || new_resource.extra_hosts.empty?) || + !(new_resource.exposed_ports.nil? || new_resource.exposed_ports.empty?) || + !(new_resource.port_bindings.nil? || new_resource.port_bindings.empty?) || + !(new_resource.publish_all_ports.nil? || new_resource.publish_all_ports.empty?) || + !new_resource.port.nil? + ) + raise Chef::Exceptions::ValidationFailed, 'Cannot specify hostname, dns, dns_search, mac_address, extra_hosts, exposed_ports, port_bindings, publish_all_ports, port when network_mode is container.' + end + end + + def parsed_hostname + return nil if new_resource.network_mode == 'host' + new_resource.hostname + end + + def call_action(action) + send("action_#{action}") + load_current_resource + end + + def state + current_resource ? current_resource.state : {} + end + + def ulimits_to_hash + return nil if new_resource.ulimits.nil? + new_resource.ulimits.map do |u| + name = u.split('=')[0] + soft = u.split('=')[1].split(':')[0] + hard = u.split('=')[1].split(':')[1] + { 'Name' => name, 'Soft' => soft.to_i, 'Hard' => hard.to_i } end end end diff --git a/chef/cookbooks/docker/libraries/docker_exec.rb b/chef/cookbooks/docker/libraries/docker_exec.rb index 0491d0d..3957e41 100644 --- a/chef/cookbooks/docker/libraries/docker_exec.rb +++ b/chef/cookbooks/docker/libraries/docker_exec.rb @@ -2,19 +2,18 @@ module DockerCookbook class DockerExec < DockerBase resource_name :docker_exec - property :host, [String, nil], default: lazy { default_host } + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false property :command, Array property :container, String - property :timeout, Numeric, default: 60 - + property :timeout, Numeric, default: 60, desired_state: false property :container_obj, Docker::Container, desired_state: false - alias cmd command + alias_method :cmd, :command action :run do - converge_by "executing #{command} on #{container}" do - with_retries { container_obj Docker::Container.get(container, {}, connection) } - container_obj.exec(command, wait: timeout) + converge_by "executing #{new_resource.command} on #{new_resource.container}" do + with_retries { new_resource.container_obj Docker::Container.get(new_resource.container, {}, connection) } + new_resource.container_obj.exec(new_resource.command, wait: new_resource.timeout) end end end diff --git a/chef/cookbooks/docker/libraries/docker_image.rb b/chef/cookbooks/docker/libraries/docker_image.rb index 8455194..2521083 100644 --- a/chef/cookbooks/docker/libraries/docker_image.rb +++ b/chef/cookbooks/docker/libraries/docker_image.rb @@ -1,28 +1,25 @@ module DockerCookbook class DockerImage < DockerBase - require 'docker' - require_relative 'helpers_image' - resource_name :docker_image # Modify the default of read_timeout from 60 to 120 property :read_timeout, default: 120, desired_state: false - # https://docs.docker.com/reference/api/docker_remote_api_v1.20/ - property :destination, [String, nil] - property :force, Boolean, default: false - property :host, [String, nil], default: lazy { default_host }, desired_state: false - property :nocache, Boolean, default: false - property :noprune, Boolean, default: false + # https://docs.docker.com/engine/api/v1.35/#tag/Image + property :destination, String + property :force, [TrueClass, FalseClass], default: false, desired_state: false + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false + property :nocache, [TrueClass, FalseClass], default: false + property :noprune, [TrueClass, FalseClass], default: false property :repo, String, name_property: true - property :rm, Boolean, default: true + property :rm, [TrueClass, FalseClass], default: true property :source, String property :tag, String, default: 'latest' - alias image repo - alias image_name repo - alias no_cache nocache - alias no_prune noprune + alias_method :image, :repo + alias_method :image_name, :repo + alias_method :no_cache, :nocache + alias_method :no_prune, :noprune ######### # Actions @@ -30,13 +27,6 @@ module DockerCookbook default_action :pull - declare_action_class.class_eval do - include DockerHelpers::Image - def whyrun_supported? - true - end - end - action :build do converge_by "Build image #{image_identifier}" do build_image @@ -90,5 +80,110 @@ module DockerCookbook load_image end end + + declare_action_class.class_eval do + ################ + # Helper methods + ################ + + def build_from_directory + i = Docker::Image.build_from_dir( + new_resource.source, + { + 'nocache' => new_resource.nocache, + 'rm' => new_resource.rm, + }, + connection + ) + i.tag('repo' => new_resource.repo, 'tag' => new_resource.tag, 'force' => new_resource.force) + end + + def build_from_dockerfile + i = Docker::Image.build( + IO.read(new_resource.source), + { + 'nocache' => new_resource.nocache, + 'rm' => new_resource.rm, + }, + connection + ) + i.tag('repo' => new_resource.repo, 'tag' => new_resource.tag, 'force' => new_resource.force) + end + + def build_from_tar + i = Docker::Image.build_from_tar( + ::File.open(new_resource.source, 'r'), + { + 'nocache' => new_resource.nocache, + 'rm' => new_resource.rm, + }, + connection + ) + i.tag('repo' => new_resource.repo, 'tag' => new_resource.tag, 'force' => new_resource.force) + end + + def build_image + if ::File.directory?(new_resource.source) + build_from_directory + elsif ::File.extname(new_resource.source) == '.tar' + build_from_tar + else + build_from_dockerfile + end + end + + def image_identifier + "#{new_resource.repo}:#{new_resource.tag}" + end + + def import_image + with_retries do + i = Docker::Image.import(new_resource.source, {}, connection) + i.tag('repo' => new_resource.repo, 'tag' => new_resource.tag, 'force' => new_resource.force) + end + end + + def pull_image + with_retries do + creds = credentails + original_image = Docker::Image.get(image_identifier, {}, connection) if Docker::Image.exist?(image_identifier, {}, connection) + new_image = Docker::Image.create({ 'fromImage' => image_identifier }, creds, connection) + + !(original_image && original_image.id.start_with?(new_image.id)) + end + end + + def push_image + with_retries do + creds = credentails + i = Docker::Image.get(image_identifier, {}, connection) + i.push(creds, repo_tag: image_identifier) + end + end + + def remove_image + with_retries do + i = Docker::Image.get(image_identifier, {}, connection) + i.remove(force: new_resource.force, noprune: new_resource.noprune) + end + end + + def save_image + with_retries do + Docker::Image.save(new_resource.repo, new_resource.destination, connection) + end + end + + def load_image + with_retries do + Docker::Image.load(new_resource.source, {}, connection) + end + end + + def credentails + registry_host = parse_registry_host(new_resource.repo) + node.run_state['docker_auth'] && node.run_state['docker_auth'][registry_host] || (node.run_state['docker_auth'] ||= {})['index.docker.io'] + end + end end end diff --git a/chef/cookbooks/docker/libraries/docker_image_prune.rb b/chef/cookbooks/docker/libraries/docker_image_prune.rb new file mode 100644 index 0000000..2cc6f8c --- /dev/null +++ b/chef/cookbooks/docker/libraries/docker_image_prune.rb @@ -0,0 +1,39 @@ +module DockerCookbook + class DockerImagePrune < DockerBase + resource_name :docker_image_prune + # Requires docker API v1.25 + # Modify the default of read_timeout from 60 to 120 + property :read_timeout, default: 120, desired_state: false + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false + + # https://docs.docker.com/engine/api/v1.35/#operation/ImagePrune + property :dangling, [TrueClass, FalseClass], default: true + property :prune_until, String + # https://docs.docker.com/engine/reference/builder/#label + property :with_label, String + property :without_label, String + + ######### + # Actions + ######### + + default_action :prune + + action :prune do + # Have to call this method ourselves due to + # https://github.com/swipely/docker-api/pull/507 + json = generate_json(new_resource) + # Post + res = connection.post('/images/prune', json) + Chef::Log.info res + end + + def generate_json(new_resource) + opts = { filters: ["dangling=#{new_resource.dangling}"] } + opts[:filters].push("until=#{new_resource.prune_until}") if new_resource.property_is_set?(:prune_until) + opts[:filters].push("label=#{new_resource.with_label}") if new_resource.property_is_set?(:with_label) + opts[:filters].push("label!=#{new_resource.without_label}") if new_resource.property_is_set?(:without_label) + opts.to_json + end + end +end diff --git a/chef/cookbooks/docker/libraries/docker_installation_binary.rb b/chef/cookbooks/docker/libraries/docker_installation_binary.rb deleted file mode 100644 index 041dab4..0000000 --- a/chef/cookbooks/docker/libraries/docker_installation_binary.rb +++ /dev/null @@ -1,40 +0,0 @@ -module DockerCookbook - class DockerInstallationBinary < DockerBase - require_relative 'helpers_installation_binary' - - include DockerHelpers::InstallationBinary - - ##################### - # Resource properties - ##################### - resource_name :docker_installation_binary - - property :checksum, String, default: lazy { default_checksum }, desired_state: false - property :source, String, default: lazy { default_source }, desired_state: false - property :version, String, default: lazy { default_version }, desired_state: false - - default_action :create - - ######### - # Actions - ######### - - action :create do - # Pull a precompiled binary off the network - remote_file docker_bin do - source new_resource.source - checksum new_resource.checksum - owner 'root' - group 'root' - mode '0755' - action :create - end - end - - action :delete do - file docker_bin do - action :delete - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/docker_installation_package.rb b/chef/cookbooks/docker/libraries/docker_installation_package.rb index 6d789cd..baab075 100644 --- a/chef/cookbooks/docker/libraries/docker_installation_package.rb +++ b/chef/cookbooks/docker/libraries/docker_installation_package.rb @@ -1,14 +1,12 @@ module DockerCookbook class DockerInstallationPackage < DockerBase - require_relative 'helpers_installation_package' - - include DockerHelpers::InstallationPackage - # Resource properties resource_name :docker_installation_package provides :docker_installation, platform: 'amazon' + property :setup_docker_repo, [TrueClass, FalseClass], default: lazy { platform?('amazon') ? false : true }, desired_state: false + property :repo_channel, String, default: 'stable' property :package_name, String, default: lazy { default_package_name }, desired_state: false property :package_version, String, default: lazy { version_string(version) }, desired_state: false property :version, String, default: lazy { default_docker_version }, desired_state: false @@ -16,17 +14,161 @@ module DockerCookbook # Actions action :create do - package package_name do - version package_version - options package_options + if new_resource.setup_docker_repo + if platform_family?('rhel', 'fedora') + platform = platform?('fedora') ? 'fedora' : 'centos' + + yum_repository 'Docker' do + baseurl "https://download.docker.com/linux/#{platform}/#{node['platform_version'].to_i}/x86_64/#{new_resource.repo_channel}" + gpgkey "https://download.docker.com/linux/#{platform}/gpg" + description "Docker #{new_resource.repo_channel.capitalize} repository" + gpgcheck true + enabled true + end + elsif platform_family?('debian') + apt_repository 'Docker' do + components Array(new_resource.repo_channel) + uri "https://download.docker.com/linux/#{node['platform']}" + arch 'amd64' + keyserver 'keyserver.ubuntu.com' + key "https://download.docker.com/linux/#{node['platform']}/gpg" + action :add + end + else + Chef::Log.warn("Cannot setup the Docker repo for platform #{node['platform']}. Skipping.") + end + end + + package new_resource.package_name do + version new_resource.package_version unless amazon? + options new_resource.package_options action :install end end action :delete do - package package_name do + package new_resource.package_name do action :remove end end + + # These are helpers for the properties so they are not in an action class + def default_docker_version + '18.06.0' + end + + def default_package_name + return 'docker' if amazon? + 'docker-ce' + end + + def el7? + return true if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 7 + false + end + + def fedora? + return true if node['platform'] == 'fedora' + false + end + + def debuntu? + return true if node['platform_family'] == 'debian' + false + end + + def debian? + return true if node['platform'] == 'debian' + false + end + + def ubuntu? + return true if node['platform'] == 'ubuntu' + false + end + + def jessie? + return true if node['platform'] == 'debian' && node['platform_version'].to_i == 8 + false + end + + def stretch? + return true if node['platform'] == 'debian' && node['platform_version'].to_i == 9 + false + end + + def buster? + return true if node['platform'] == 'debian' && node['platform_version'].to_i == 10 + false + end + + def trusty? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '14.04' + false + end + + def xenial? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '16.04' + false + end + + def artful? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '17.10' + false + end + + def bionic? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '18.04' + false + end + + def amazon? + return true if node['platform'] == 'amazon' + false + end + + # https://github.com/chef/chef/issues/4103 + def version_string(v) + codename = if jessie? + 'jessie' + elsif stretch? + 'stretch' + elsif buster? + 'buster' + elsif trusty? + 'trusty' + elsif xenial? + 'xenial' + elsif artful? + 'artful' + elsif bionic? + 'bionic' + end + + # https://github.com/seemethere/docker-ce-packaging/blob/9ba8e36e8588ea75209d813558c8065844c953a0/deb/gen-deb-ver#L16-L20 + test_version = '3' + + if v.to_f < 17.06 && debuntu? + return "#{v}~ce-0~debian-#{codename}" if debian? + return "#{v}~ce-0~ubuntu-#{codename}" if ubuntu? + elsif v == '17.03.3' && el7? + return "#{v}.ce-1.el7" + elsif v.to_f < 18.06 && !bionic? + return "#{v}.ce-1.el7.centos" if el7? + return "#{v}~ce-0~debian" if debian? + return "#{v}~ce-0~ubuntu" if ubuntu? + elsif v.to_f >= 18.09 && debuntu? + return "5:#{v}~#{test_version}-0~debian-#{codename}" if debian? + return "5:#{v}~#{test_version}-0~ubuntu-#{codename}" if ubuntu? + elsif v.to_f >= 18.09 && el7? + return "#{v}-#{test_version}.el7" + else + return "#{v}.ce" if fedora? + return "#{v}.ce-#{test_version}.el7" if el7? + return "#{v}~ce~#{test_version}-0~debian" if debian? + return "#{v}~ce~#{test_version}-0~ubuntu" if ubuntu? + v + end + end end end diff --git a/chef/cookbooks/docker/libraries/docker_installation_script.rb b/chef/cookbooks/docker/libraries/docker_installation_script.rb index 305031a..76063c2 100644 --- a/chef/cookbooks/docker/libraries/docker_installation_script.rb +++ b/chef/cookbooks/docker/libraries/docker_installation_script.rb @@ -1,8 +1,5 @@ module DockerCookbook class DockerInstallationScript < DockerBase - ##################### - # Resource properties - ##################### resource_name :docker_installation_script provides :docker_installation, os: 'linux' @@ -12,9 +9,9 @@ module DockerCookbook default_action :create - ################ - # helper methods - ################ + ######################### + # property helper methods + ######################### def default_script_url case repo @@ -32,18 +29,16 @@ module DockerCookbook ######### action :create do - package 'curl' do - action :install - end + package 'curl' execute 'install docker' do - command "curl -sSL #{script_url} | sh" + command "curl -sSL #{new_resource.script_url} | sh" creates '/usr/bin/docker' end end action :delete do - package 'docker-engine' do + package %w(docker-ce docker-engine) do action :remove end end diff --git a/chef/cookbooks/docker/libraries/docker_installation_tarball.rb b/chef/cookbooks/docker/libraries/docker_installation_tarball.rb index d9b1d31..896aa59 100644 --- a/chef/cookbooks/docker/libraries/docker_installation_tarball.rb +++ b/chef/cookbooks/docker/libraries/docker_installation_tarball.rb @@ -1,25 +1,54 @@ module DockerCookbook class DockerInstallationTarball < DockerBase - require_relative 'helpers_installation_tarball' - - include DockerHelpers::InstallationTarball - - ##################### - # Resource properties - ##################### resource_name :docker_installation_tarball property :checksum, String, default: lazy { default_checksum }, desired_state: false property :source, String, default: lazy { default_source }, desired_state: false - property :version, String, default: lazy { default_version }, desired_state: false + property :channel, String, default: 'stable', desired_state: false + property :version, String, default: '18.06.0', desired_state: false - default_action :create + ################## + # Property Helpers + ################## + + def docker_kernel + node['kernel']['name'] + end + + def docker_arch + node['kernel']['machine'] + end + + def default_source + "https://download.docker.com/#{docker_kernel.downcase}/static/#{channel}/#{docker_arch}/docker-#{version}-ce.tgz" + end + + def default_checksum + case docker_kernel + when 'Darwin' + case version + when '17.12.0' then 'dc673421e0368c2c970203350a9d0cb739bc498c897e832779369b0b2a9c6192' + when '18.03.0' then '2d44ed2ac1e24cb22b6e72cb16d74fc9e60245a8ac1d4f79475604b804f46d38' + when '18.03.1' then 'bbfb9c599a4fdb45523496c2ead191056ff43d6be90cf0e348421dd56bc3dcf0' + when '18.06.0' then '5489360ae1894375a56255fb821fcf368b33027cd4f4bbaebf5176c05b79f420' + end + when 'Linux' + case version + when '17.12.0' then '692e1c72937f6214b1038def84463018d8e320c8eaf8530546c84c2f8f9c767d' + when '18.03.0' then 'e5dff6245172081dbf14285dafe4dede761f8bc1750310156b89928dbf56a9ee' + when '18.03.1' then '0e245c42de8a21799ab11179a4fce43b494ce173a8a2d6567ea6825d6c5265aa' + when '18.06.0' then '1c2fa625496465c68b856db0ba850eaad7a16221ca153661ca718de4a2217705' + end + end + end ######### # Actions ######### action :create do + package 'tar' + # Pull a precompiled binary off the network remote_file docker_tarball do source new_resource.source @@ -43,5 +72,22 @@ module DockerCookbook action :delete end end + + ################ + # Action Helpers + ################ + declare_action_class.class_eval do + def docker_bin_prefix + '/usr/bin' + end + + def docker_bin + "#{docker_bin_prefix}/docker" + end + + def docker_tarball + "#{Chef::Config[:file_cache_path]}/docker-#{new_resource.version}.tgz" + end + end end end diff --git a/chef/cookbooks/docker/libraries/docker_network.rb b/chef/cookbooks/docker/libraries/docker_network.rb index 050db8a..2bf347e 100644 --- a/chef/cookbooks/docker/libraries/docker_network.rb +++ b/chef/cookbooks/docker/libraries/docker_network.rb @@ -1,25 +1,62 @@ module DockerCookbook class DockerNetwork < DockerBase - require 'docker' - require_relative 'helpers_network' - include DockerHelpers::Network - resource_name :docker_network property :auxiliary_addresses, [String, Array, nil], coerce: proc { |v| coerce_auxiliary_addresses(v) } property :container, String, desired_state: false property :driver, String property :driver_opts, PartialHashType + property :enable_ipv6, [TrueClass, FalseClass] property :gateway, [String, Array, nil], coerce: proc { |v| coerce_gateway(v) } - property :host, [String, nil], default: lazy { default_host }, desired_state: false + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false property :id, String + property :internal, [TrueClass, FalseClass] property :ip_range, [String, Array, nil], coerce: proc { |v| coerce_ip_range(v) } property :ipam_driver, String property :network, Docker::Network, desired_state: false property :network_name, String, name_property: true property :subnet, [String, Array, nil], coerce: proc { |v| coerce_subnet(v) } - alias aux_address auxiliary_addresses + alias_method :aux_address, :auxiliary_addresses + + ################### + # property helpers + ################### + + def coerce_auxiliary_addresses(v) + ray = [] + Array(v).each do |e| + case e + when String, Array, nil + ray += Array(e) + when Hash + e.each { |key, val| ray << "#{key}=#{val}" } + end + end + ray.length == 1 ? ray[0] : ray + end + + def coerce_gateway(v) + case v + when String + v.split('/')[0] + when Array + ray = Array(v).map { |a| a.split('/')[0] } + ray.length == 1 ? ray[0] : ray + end + end + + def coerce_subnet(v) + Array(v).length == 1 ? Array(v)[0] : v + end + + def coerce_ip_range(v) + Array(v).length == 1 ? Array(v)[0] : v + end + + #################### + # load current value + #################### load_current_value do begin @@ -55,6 +92,8 @@ module DockerCookbook driver network.info['Driver'] driver_opts network.info['Options'] + internal network.info['Internal'] + enable_ipv6 network.info['EnableIPv6'] end action :create do @@ -63,21 +102,23 @@ module DockerCookbook with_retries do options = {} - options['Driver'] = driver if driver - options['Options'] = driver_opts if driver_opts - ipam_options = consolidate_ipam(subnet, ip_range, gateway, aux_address) + options['Driver'] = new_resource.driver if new_resource.driver + options['Options'] = new_resource.driver_opts if new_resource.driver_opts + ipam_options = consolidate_ipam(new_resource.subnet, new_resource.ip_range, new_resource.gateway, new_resource.aux_address) options['IPAM'] = { 'Config' => ipam_options } unless ipam_options.empty? - options['IPAM']['Driver'] = ipam_driver if ipam_driver - Docker::Network.create(network_name, options) + options['IPAM']['Driver'] = new_resource.ipam_driver if new_resource.ipam_driver + options['EnableIPv6'] = new_resource.enable_ipv6 if new_resource.enable_ipv6 + options['Internal'] = new_resource.internal if new_resource.internal + Docker::Network.create(new_resource.network_name, options) end end end action :delete do return unless current_resource - converge_by "deleting #{network_name}" do + converge_by "deleting #{new_resource.network_name}" do with_retries do - network.delete + current_resource.network.delete end end end @@ -87,16 +128,16 @@ module DockerCookbook end action :connect do - unless container + unless new_resource.container raise Chef::Exceptions::ValidationFailed, 'Container id or name is required for action :connect' end if current_resource - container_index = network.info['Containers'].values.index { |c| c['Name'] == container } + container_index = current_resource.network.info['Containers'].values.index { |c| c['Name'] == new_resource.container } if container_index.nil? - converge_by("connect #{container}") do + converge_by("connect #{new_resource.container}") do with_retries do - network.connect(container) + current_resource.network.connect(new_resource.container) end end end @@ -106,16 +147,16 @@ module DockerCookbook end action :disconnect do - unless container + unless new_resource.container raise Chef::Exceptions::ValidationFailed, 'Container id or name is required for action :disconnect' end if current_resource - container_index = network.info['Containers'].values.index { |c| c['Name'] == container } + container_index = current_resource.network.info['Containers'].values.index { |c| c['Name'] == new_resource.container } unless container_index.nil? - converge_by("disconnect #{container}") do + converge_by("disconnect #{new_resource.container}") do with_retries do - network.disconnect(container) + current_resource.network.disconnect(new_resource.container) end end end @@ -123,5 +164,82 @@ module DockerCookbook Chef::Log.warn("Cannot disconnect from #{network_name}: network does not exist") end end + + declare_action_class.class_eval do + require 'ipaddr' + + ###### + # IPAM + ###### + + def consolidate_ipam(subnets, ranges, gateways, auxaddrs) + subnets = Array(subnets) + ranges = Array(ranges) + gateways = Array(gateways) + auxaddrs = Array(auxaddrs) + subnets = [] if subnets.empty? + ranges = [] if ranges.empty? + gateways = [] if gateways.empty? + auxaddrs = [] if auxaddrs.empty? + if subnets.size < ranges.size || subnets.size < gateways.size + raise 'every ip-range or gateway myust have a corresponding subnet' + end + + data = {} + + # Check overlapping subnets + subnets.each do |s| + data.each do |k, _| + if subnet_matches(s, k) || subnet_matches(k, s) + raise 'multiple overlapping subnet configuration is not supported' + end + end + data[s] = { 'Subnet' => s, 'AuxiliaryAddresses' => {} } + end + + ranges.each do |r| + match = false + subnets.each do |s| + ok = subnet_matches(s, r) + next unless ok + if data[s].fetch('IPRange', '') != '' + raise 'cannot configure multiple ranges on the same subnet' + end + data[s]['IPRange'] = r + match = true + end + raise "no matching subnet for range #{r}" unless match + end + + gateways.each do |g| + subnets.each do |s| + ok = subnet_matches(s, g) + next unless ok + unless data[s].fetch('Gateway', '').empty? + raise "cannot configure multiple gateways (#{g}, #{data[s]['Gateway']}) for the same subnet (#{s})" + end + data[s]['Gateway'] = g + end + end + + auxaddrs.each do |aa| + key, a = aa.split('=') + match = false + subnets.each do |s| + # require 'pry' ; binding.pry + ok = subnet_matches(s, a) + next unless ok + data[s]['AuxiliaryAddresses'][key] = a + match = true + end + raise "no matching subnet for aux-address #{a}" unless match + end + data.values + end + + def subnet_matches(subnet, data) + IPAddr.new(subnet).include?(IPAddr.new(data)) + end + end end end diff --git a/chef/cookbooks/docker/libraries/docker_plugin.rb b/chef/cookbooks/docker/libraries/docker_plugin.rb new file mode 100644 index 0000000..fa273e8 --- /dev/null +++ b/chef/cookbooks/docker/libraries/docker_plugin.rb @@ -0,0 +1,125 @@ +module DockerCookbook + class DockerPlugin < DockerBase + resource_name :docker_plugin + + property :local_alias, String, name_property: true + property :remote_tag, String, default: 'latest' + property :remote, [String, nil], default: nil + property :grant_privileges, [Array, TrueClass], default: [] + property :options, Hash, default: {} + + default_action :install + + action :install do + return if plugin_exists?(local_name) + converge_by "Install plugin #{plugin_identifier} as #{local_name}" do + install_plugin + configure_plugin + end + end + + action :enable do + converge_by "Enable plugin #{local_name}" do + enable_plugin + end unless plugin_enabled?(local_name) + end + + action :disable do + converge_by "Disable plugin #{local_name}" do + disable_plugin + end if plugin_enabled?(local_name) + end + + action :update do + converge_by "Configure plugin #{local_name}" do + configure_plugin + end + end + + action :remove do + converge_by "Remove plugin #{local_name}" do + remove_plugin + end + end + + declare_action_class.class_eval do + def remote_name + return new_resource.remote unless new_resource.remote.nil? || new_resource.remote.empty? + new_resource.local_alias + end + + def plugin_identifier + "#{remote_name}:#{new_resource.remote_tag}" + end + + def local_name + new_resource.local_alias + end + + def plugin_exists?(name) + Docker.connection.get("/plugins/#{name}/json") + true + rescue Docker::Error::NotFoundError + false + end + + def plugin_enabled?(name) + JSON.parse(Docker.connection.get("/plugins/#{name}/json"))['Enabled'] + end + + def install_plugin + privileges = \ + if new_resource.grant_privileges == true + # user gave a blanket statement about privileges; fetch required privileges from Docker + # we pass the identifier as both :name and :remote to accomodate different API versions + JSON.parse Docker.connection.get('/plugins/privileges', + name: plugin_identifier, + remote: plugin_identifier) + else + # user gave a specific list of privileges + new_resource.grant_privileges + end + + # actually do the plugin install + body = '' + + opts = { remote: plugin_identifier, name: local_name } + Chef::Log.info("pulling plugin #{opts} with privileges #{privileges}") + Docker.connection.post('/plugins/pull', opts, + body: JSON.generate(privileges), + response_block: response_block(body)) + + last_line = body.split("\n").select { |item| !item.empty? }.last + info = JSON.parse last_line + raise info['error'] if info.key?('error') + end + + def response_block(body) + lambda do |chunk, _remaining, _total| + body << chunk + end + end + + def configure_plugin + options_for_json = [] + new_resource.options.each_pair do |k, v| + options_for_json.push("#{k}=#{v}") + end + + Docker.connection.post("/plugins/#{local_name}/set", {}, body: JSON.generate(options_for_json)) + end + + def enable_plugin + Docker.connection.post("/plugins/#{local_name}/enable", timeout: new_resource.read_timeout) + end + + def disable_plugin + Docker.connection.post("/plugins/#{local_name}/disable", timeout: new_resource.read_timeout) + end + + def remove_plugin + Docker.connection.delete("/plugins/#{local_name}") + end + end + end +end diff --git a/chef/cookbooks/docker/libraries/docker_registry.rb b/chef/cookbooks/docker/libraries/docker_registry.rb index 58eeff6..ab05845 100644 --- a/chef/cookbooks/docker/libraries/docker_registry.rb +++ b/chef/cookbooks/docker/libraries/docker_registry.rb @@ -1,25 +1,29 @@ module DockerCookbook class DockerRegistry < DockerBase - require 'docker' - require_relative 'helpers_auth' - resource_name :docker_registry - property :email, [String, nil] - property :password, [String, nil] - property :serveraddress, [String, nil], name_property: true - property :username, [String, nil] + property :email, String + + property :password, String, + sensitive: true + + property :serveraddress, String, + name_property: true + + property :username, String + + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false action :login do - tries = api_retries + tries = new_resource.api_retries - registry_host = parse_registry_host(serveraddress) + registry_host = parse_registry_host(new_resource.serveraddress) (node.run_state['docker_auth'] ||= {})[registry_host] = { 'serveraddress' => registry_host, - 'username' => username, - 'password' => password, - 'email' => email, + 'username' => new_resource.username, + 'password' => new_resource.password, + 'email' => new_resource.email, } begin @@ -28,7 +32,7 @@ module DockerCookbook body: node.run_state['docker_auth'][registry_host].to_json ) rescue Docker::Error::ServerError, Docker::Error::UnauthorizedError - raise Docker::Error::AuthenticationError, "#{username} failed to authenticate with #{serveraddress}" if (tries -= 1) == 0 + raise Docker::Error::AuthenticationError, "#{new_resource.username} failed to authenticate with #{new_resource.serveraddress}" if (tries -= 1) == 0 retry end diff --git a/chef/cookbooks/docker/libraries/docker_service.rb b/chef/cookbooks/docker/libraries/docker_service.rb index 10725c2..324eba0 100644 --- a/chef/cookbooks/docker/libraries/docker_service.rb +++ b/chef/cookbooks/docker/libraries/docker_service.rb @@ -8,37 +8,30 @@ module DockerCookbook provides :docker_service # installation type and service_manager - property :install_method, %w(binary script package tarball none auto), default: 'auto', desired_state: false + property :install_method, %w(script package tarball none auto), default: 'auto', desired_state: false property :service_manager, %w(execute sysvinit upstart systemd auto), default: 'auto', desired_state: false # docker_installation_script property :repo, desired_state: false property :script_url, String, desired_state: false - # docker_installation_binary and tarball + # docker_installation_tarball property :checksum, String, desired_state: false property :docker_bin, String, desired_state: false property :source, String, desired_state: false # docker_installation_package property :package_version, String, desired_state: false + property :package_name, String, desired_state: false + property :setup_docker_repo, [TrueClass, FalseClass], desired_state: false - # binary, package and tarball + # package and tarball property :version, String, desired_state: false - property :package_options, [String, nil], desired_state: false + property :package_options, String, desired_state: false ################ # Helper Methods ################ - def validate_install_method - if property_is_set?(:version) && - install_method != 'binary' && - install_method != 'package' && - install_method != 'tarball' - raise Chef::Exceptions::ValidationFailed, 'Version property only supported for binary, package and tarball installation methods' - end - end - def copy_properties_to(to, *properties) properties = self.class.properties.keys if properties.empty? properties.each do |p| @@ -51,18 +44,24 @@ module DockerCookbook end action_class.class_eval do + def validate_install_method + if new_resource.property_is_set?(:version) && + new_resource.install_method != 'package' && + new_resource.install_method != 'tarball' + raise Chef::Exceptions::ValidationFailed, 'Version property only supported for package and tarball installation methods' + end + end + def installation(&block) - case install_method + case new_resource.install_method when 'auto' - install = docker_installation(name, &block) - when 'binary' - install = docker_installation_binary(name, &block) + install = docker_installation(new_resource.name, &block) when 'script' - install = docker_installation_script(name, &block) + install = docker_installation_script(new_resource.name, &block) when 'package' - install = docker_installation_package(name, &block) + install = docker_installation_package(new_resource.name, &block) when 'tarball' - install = docker_installation_tarball(name, &block) + install = docker_installation_tarball(new_resource.name, &block) when 'none' Chef::Log.info('Skipping Docker installation. Assuming it was handled previously.') return @@ -72,17 +71,17 @@ module DockerCookbook end def svc_manager(&block) - case service_manager + case new_resource.service_manager when 'auto' - svc = docker_service_manager(name, &block) + svc = docker_service_manager(new_resource.name, &block) when 'execute' - svc = docker_service_manager_execute(name, &block) + svc = docker_service_manager_execute(new_resource.name, &block) when 'sysvinit' - svc = docker_service_manager_sysvinit(name, &block) + svc = docker_service_manager_sysvinit(new_resource.name, &block) when 'upstart' - svc = docker_service_manager_upstart(name, &block) + svc = docker_service_manager_upstart(new_resource.name, &block) when 'systemd' - svc = docker_service_manager_systemd(name, &block) + svc = docker_service_manager_systemd(new_resource.name, &block) end copy_properties_to(svc) svc diff --git a/chef/cookbooks/docker/libraries/docker_service_base.rb b/chef/cookbooks/docker/libraries/docker_service_base.rb index fa2393e..b4ba636 100644 --- a/chef/cookbooks/docker/libraries/docker_service_base.rb +++ b/chef/cookbooks/docker/libraries/docker_service_base.rb @@ -3,7 +3,6 @@ module DockerCookbook ################ # Helper Methods ################ - require 'docker' require_relative 'helpers_service' include DockerHelpers::Service @@ -16,64 +15,69 @@ module DockerCookbook # register with the resource resolution system provides :docker_service_manager + # Environment variables to docker service + property :env_vars, Hash + # daemon management - property :instance, String, name_property: true, required: true, desired_state: false - property :auto_restart, Boolean, default: false - property :api_cors_header, [String, nil] - property :bridge, [String, nil] + property :instance, String, name_property: true, desired_state: false + property :auto_restart, [TrueClass, FalseClass], default: false + property :api_cors_header, String + property :bridge, String property :bip, [IPV4_ADDR, IPV4_CIDR, IPV6_ADDR, IPV6_CIDR, nil] - property :cluster_store, [String, nil] - property :cluster_advertise, [String, nil] - property :cluster_store_opts, ArrayType - property :debug, [Boolean, nil] - property :daemon, Boolean, default: true - property :dns, ArrayType - property :dns_search, [Array, nil] + property :cluster_store, String + property :cluster_advertise, String + property :cluster_store_opts, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :daemon, [TrueClass, FalseClass], default: true + property :data_root, String + property :debug, [TrueClass, FalseClass], default: false + property :dns, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :dns_search, Array property :exec_driver, ['native', 'lxc', nil] - property :exec_opts, ArrayType - property :fixed_cidr, [String, nil] - property :fixed_cidr_v6, [String, nil] - property :group, [String, nil] - property :graph, [String, nil] - property :host, [String, Array], coerce: proc { |v| coerce_host(v) } - property :icc, [Boolean, nil] + property :exec_opts, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :fixed_cidr, String + property :fixed_cidr_v6, String + property :group, String, default: 'docker' + property :host, [String, Array], coerce: proc { |v| coerce_host(v) }, desired_state: false + property :icc, [TrueClass, FalseClass] property :insecure_registry, [Array, String, nil], coerce: proc { |v| coerce_insecure_registry(v) } property :ip, [IPV4_ADDR, IPV6_ADDR, nil] - property :ip_forward, [Boolean, nil] - property :ipv4_forward, Boolean, default: true - property :ipv6_forward, Boolean, default: true - property :ip_masq, [Boolean, nil] - property :iptables, [Boolean, nil] - property :ipv6, [Boolean, nil] - property :log_level, [:debug, :info, :warn, :error, :fatal, nil] + property :ip_forward, [TrueClass, FalseClass] + property :ipv4_forward, [TrueClass, FalseClass], default: true + property :ipv6_forward, [TrueClass, FalseClass], default: true + property :ip_masq, [TrueClass, FalseClass] + property :iptables, [TrueClass, FalseClass] + property :ipv6, [TrueClass, FalseClass] + property :default_ip_address_pool, String + property :log_level, %w(debug info warn error fatal) property :labels, [String, Array], coerce: proc { |v| coerce_daemon_labels(v) }, desired_state: false - property :log_driver, %w( json-file syslog journald gelf fluentd awslogs splunk none ) - property :log_opts, ArrayType - property :mount_flags, String, default: 'slave' - property :mtu, [String, nil] + property :log_driver, %w(json-file syslog journald gelf fluentd awslogs splunk none) + property :log_opts, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :mount_flags, String + property :mtu, String property :pidfile, String, default: lazy { "/var/run/#{docker_name}.pid" } - property :registry_mirror, [String, nil] - property :storage_driver, ArrayType - property :selinux_enabled, [Boolean, nil] - property :storage_opts, ArrayType - property :default_ulimit, ArrayType - property :userland_proxy, [Boolean, nil] - property :disable_legacy_registry, [Boolean, nil] - property :userns_remap, [String, nil] + property :registry_mirror, String + property :storage_driver, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :selinux_enabled, [TrueClass, FalseClass] + property :storage_opts, Array + property :default_ulimit, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :userland_proxy, [TrueClass, FalseClass] + property :disable_legacy_registry, [TrueClass, FalseClass] + property :userns_remap, String # These are options specific to systemd configuration such as # LimitNOFILE or TasksMax that you may wannt to use to customize # the environment in which Docker runs. - property :systemd_opts, ArrayType + property :systemd_opts, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } + property :systemd_socket_opts, [String, Array], coerce: proc { |v| v.nil? ? nil : Array(v) } # These are unvalidated daemon arguments passed in as a string. - property :misc_opts, [String, nil] + property :misc_opts, String # environment variables to set before running daemon - property :http_proxy, [String, nil] - property :https_proxy, [String, nil] - property :no_proxy, [String, nil] - property :tmpdir, [String, nil] + property :http_proxy, String + property :https_proxy, String + property :no_proxy, String + property :tmpdir, String # logging property :logfile, String, default: '/var/log/docker.log' @@ -83,12 +87,9 @@ module DockerCookbook allowed_actions :start, :stop, :restart - alias label labels - alias tlscacert tls_ca_cert - alias tlscert tls_server_cert - alias tlskey tls_server_key - alias tlsverify tls_verify - alias run_group group + alias_method :label, :labels + alias_method :run_group, :group + alias_method :graph, :data_root declare_action_class.class_eval do def libexec_dir @@ -112,7 +113,7 @@ module DockerCookbook variables( docker_cmd: docker_cmd, libexec_dir: libexec_dir, - service_timeout: service_timeout + service_timeout: new_resource.service_timeout ) cookbook 'docker' action :create diff --git a/chef/cookbooks/docker/libraries/docker_service_manager_execute.rb b/chef/cookbooks/docker/libraries/docker_service_manager_execute.rb index 01dc20e..6652eb2 100644 --- a/chef/cookbooks/docker/libraries/docker_service_manager_execute.rb +++ b/chef/cookbooks/docker/libraries/docker_service_manager_execute.rb @@ -2,8 +2,6 @@ module DockerCookbook class DockerServiceManagerExecute < DockerServiceBase resource_name :docker_service_manager_execute - provides :docker_service_manager, os: 'linux' - # Start the service action :start do # enable ipv4 forwarding diff --git a/chef/cookbooks/docker/libraries/docker_service_manager_systemd.rb b/chef/cookbooks/docker/libraries/docker_service_manager_systemd.rb index f26994c..b07da07 100644 --- a/chef/cookbooks/docker/libraries/docker_service_manager_systemd.rb +++ b/chef/cookbooks/docker/libraries/docker_service_manager_systemd.rb @@ -2,85 +2,78 @@ module DockerCookbook class DockerServiceManagerSystemd < DockerServiceBase resource_name :docker_service_manager_systemd - provides :docker_service_manager, platform: 'fedora' - - provides :docker_service_manager, platform: %w(redhat centos scientific oracle) do |node| # ~FC005 - node['platform_version'].to_f >= 7.0 - end - - provides :docker_service_manager, platform: 'debian' do |node| - node['platform_version'].to_f >= 8.0 - end - - provides :docker_service_manager, platform: 'ubuntu' do |node| - node['platform_version'].to_f >= 15.04 + provides :docker_service_manager, os: 'linux' do |_node| + Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd) end action :start do create_docker_wait_ready - # stock systemd unit file - template "/lib/systemd/system/#{docker_name}.service" do - source 'systemd/docker.service.erb' - owner 'root' - group 'root' - mode '0644' - variables( - docker_name: docker_name, - docker_socket: connect_socket.sub(%r{unix://|fd://}, ''), - docker_mount_flags: mount_flags - ) - cookbook 'docker' - action :create - not_if { docker_name == 'default' && ::File.exist?('/lib/systemd/system/docker.service') } - end - # stock systemd socket file template "/lib/systemd/system/#{docker_name}.socket" do source 'systemd/docker.socket.erb' - owner 'root' - group 'root' - mode '0644' - variables( - docker_name: docker_name, - docker_socket: connect_socket.sub(%r{unix://|fd://}, '') - ) cookbook 'docker' - action :create - not_if { docker_name == 'default' && ::File.exist?('/lib/systemd/system/docker.socket') } - end - - template "/etc/systemd/system/#{docker_name}.service" do - source 'systemd/docker.service-override.erb' owner 'root' group 'root' mode '0644' variables( config: new_resource, - docker_daemon_cmd: docker_daemon_cmd, - systemd_args: systemd_args, - docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready", - docker_mount_flags: mount_flags + docker_name: docker_name, + docker_socket: connect_socket ) + action connect_socket.nil? ? :delete : :create + not_if { docker_name == 'default' && ::File.exist?('/lib/systemd/system/docker.socket') } + end + + # stock systemd unit file + template "/lib/systemd/system/#{docker_name}.service" do + source 'systemd/docker.service.erb' cookbook 'docker' - notifies :run, 'execute[systemctl daemon-reload]', :immediately - action :create + owner 'root' + group 'root' + mode '0644' + variables( + docker_name: docker_name, + docker_daemon_cmd: docker_daemon_cmd, + docker_socket: connect_socket + ) + not_if { docker_name == 'default' && ::File.exist?('/lib/systemd/system/docker.service') } end # this overrides the main systemd socket template "/etc/systemd/system/#{docker_name}.socket" do source 'systemd/docker.socket-override.erb' + cookbook 'docker' owner 'root' group 'root' mode '0644' variables( config: new_resource, docker_name: docker_name, - docker_socket: connect_socket.sub(%r{unix://|fd://}, '') + docker_socket: connect_socket, + systemd_socket_args: systemd_socket_args ) + action connect_socket.nil? ? :delete : :create + end + + # this overrides the main systemd service + template "/etc/systemd/system/#{docker_name}.service" do + source 'systemd/docker.service-override.erb' cookbook 'docker' + owner 'root' + group 'root' + mode '0644' + variables( + config: new_resource, + docker_name: docker_name, + docker_socket: connect_socket, + docker_daemon_cmd: docker_daemon_cmd, + systemd_args: systemd_args, + docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready", + env_vars: new_resource.env_vars + ) notifies :run, 'execute[systemctl daemon-reload]', :immediately - action :create + notifies :run, "execute[systemctl try-restart #{docker_name}]", :immediately end # avoid 'Unit file changed on disk' warning @@ -89,12 +82,19 @@ module DockerCookbook action :nothing end + # restart if changes in template resources + execute "systemctl try-restart #{docker_name}" do + command "/bin/systemctl try-restart #{docker_name}" + action :nothing + end + # service management resource service docker_name do provider Chef::Provider::Service::Systemd supports status: true action [:enable, :start] only_if { ::File.exist?("/lib/systemd/system/#{docker_name}.service") } + retries 1 end end diff --git a/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_debian.rb b/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_debian.rb index 12e0b0c..682ac3f 100644 --- a/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_debian.rb +++ b/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_debian.rb @@ -2,22 +2,14 @@ module DockerCookbook class DockerServiceManagerSysvinitDebian < DockerServiceBase resource_name :docker_service_manager_sysvinit_debian - provides :docker_service_manager, platform: 'debian' do |node| + provides :docker_service_manager, platform: 'debian' do |node| # ~FC005 node['platform_version'].to_f < 8.0 end - provides :docker_service_manager, platform: 'ubuntu' do |node| - node['platform_version'].to_f < 12.04 - end - provides :docker_service_manager_sysvinit, platform: 'debian' do |node| node['platform_version'].to_f < 8.0 end - provides :docker_service_manager_sysvinit, platform: 'ubuntu' do |node| - node['platform_version'].to_f < 12.04 - end - action :start do create_docker_wait_ready create_init @@ -50,6 +42,7 @@ module DockerCookbook template "/etc/init.d/#{docker_name}" do source 'sysvinit/docker-debian.erb' + cookbook 'docker' owner 'root' group 'root' mode '0755' @@ -57,20 +50,16 @@ module DockerCookbook docker_name: docker_name, dockerd_bin_link: dockerd_bin_link, docker_daemon_arg: docker_daemon_arg, + docker_daemon_opts: docker_daemon_opts.join(' '), docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready" ) - cookbook 'docker' action :create end template "/etc/default/#{docker_name}" do source 'default/docker.erb' - variables( - config: new_resource, - dockerd_bin_link: dockerd_bin_link, - docker_daemon_opts: docker_daemon_opts.join(' ') - ) cookbook 'docker' + variables(config: new_resource) action :create end end diff --git a/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_rhel.rb b/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_rhel.rb index 6480d04..39c8022 100644 --- a/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_rhel.rb +++ b/chef/cookbooks/docker/libraries/docker_service_manager_sysvinit_rhel.rb @@ -4,13 +4,13 @@ module DockerCookbook provides :docker_service_manager, platform: 'amazon' provides :docker_service_manager, platform: 'suse' - provides :docker_service_manager, platform: %w(redhat centos scientific oracle) do |node| # ~FC005 + provides :docker_service_manager, platform_family: 'rhel' do |node| node['platform_version'].to_f <= 7.0 end provides :docker_service_manager_sysvinit, platform: 'amazon' provides :docker_service_manager_sysvinit, platform: 'suse' - provides :docker_service_manager_sysvinit, platform: %w(redhat centos scientific oracle) do |node| # ~FC005 + provides :docker_service_manager_sysvinit, platform_family: 'rhel' do |node| node['platform_version'].to_f <= 7.0 end @@ -41,10 +41,10 @@ module DockerCookbook link dockerd_bin_link do to dockerd_bin link_type :hard - action :create end template "/etc/init.d/#{docker_name}" do + cookbook 'docker' source 'sysvinit/docker-rhel.erb' owner 'root' group 'root' @@ -55,18 +55,17 @@ module DockerCookbook docker_daemon_cmd: docker_daemon_cmd, docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready" ) - cookbook 'docker' - action :create + notifies :restart, "service[#{docker_name}]", :immediately end template "/etc/sysconfig/#{docker_name}" do - source 'sysconfig/docker.erb' - variables( - config: new_resource, - docker_daemon_opts: docker_daemon_opts.join(' ') - ) cookbook 'docker' - action :create + source 'sysconfig/docker.erb' + owner 'root' + group 'root' + mode '0644' + variables(config: new_resource) + notifies :restart, "service[#{docker_name}]", :immediately end end diff --git a/chef/cookbooks/docker/libraries/docker_service_manager_upstart.rb b/chef/cookbooks/docker/libraries/docker_service_manager_upstart.rb index 93997c1..c5ecaaa 100644 --- a/chef/cookbooks/docker/libraries/docker_service_manager_upstart.rb +++ b/chef/cookbooks/docker/libraries/docker_service_manager_upstart.rb @@ -2,8 +2,10 @@ module DockerCookbook class DockerServiceManagerUpstart < DockerServiceBase resource_name :docker_service_manager_upstart - provides :docker_service_manager, platform: 'ubuntu' - provides :docker_service_manager, platform: 'linuxmint' + provides :docker_service_manager, platform_family: 'debian' do |_node| + Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) && + !Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd) + end action :start do create_docker_wait_ready @@ -16,33 +18,30 @@ module DockerCookbook template "/etc/init/#{docker_name}.conf" do source 'upstart/docker.conf.erb' + cookbook 'docker' owner 'root' group 'root' mode '0644' variables( - docker_name: docker_name, - dockerd_bin_link: dockerd_bin_link, - docker_daemon_arg: docker_daemon_arg, - docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready" + docker_daemon_cmd: [dockerd_bin_link, docker_daemon_arg, docker_daemon_opts].join(' '), + docker_raw_logs_arg: docker_raw_logs_arg, + docker_wait_ready: "#{libexec_dir}/#{docker_name}-wait-ready", + docker_socket: connect_socket ) - cookbook 'docker' - action :create + notifies :stop, "service[#{docker_name}]", :immediately + notifies :start, "service[#{docker_name}]", :immediately end template "/etc/default/#{docker_name}" do source 'default/docker.erb' - variables( - config: new_resource, - dockerd_bin_link: dockerd_bin_link, - docker_daemon_opts: docker_daemon_opts.join(' ') - ) cookbook 'docker' - action :create + variables(config: new_resource) + notifies :restart, "service[#{docker_name}]", :immediately end service docker_name do provider Chef::Provider::Service::Upstart - supports status: true + supports status: true, restart: false action :start end end @@ -50,7 +49,7 @@ module DockerCookbook action :stop do service docker_name do provider Chef::Provider::Service::Upstart - supports status: true + supports status: true, restart: false action :stop end end diff --git a/chef/cookbooks/docker/libraries/docker_tag.rb b/chef/cookbooks/docker/libraries/docker_tag.rb index e9fc471..7f819af 100644 --- a/chef/cookbooks/docker/libraries/docker_tag.rb +++ b/chef/cookbooks/docker/libraries/docker_tag.rb @@ -6,18 +6,18 @@ module DockerCookbook property :target_tag, String property :to_repo, String property :to_tag, String - property :force, Boolean, default: false + property :force, [TrueClass, FalseClass], default: false, desired_state: false ######### # Actions ######### action :tag do - return if force == false && Docker::Image.exist?("#{to_repo}:#{to_tag}") + return if new_resource.force == false && Docker::Image.exist?("#{new_resource.to_repo}:#{new_resource.to_tag}") begin - converge_by "update #{target_repo}:#{target_tag} to #{to_repo}:#{to_tag}" do - i = Docker::Image.get("#{target_repo}:#{target_tag}") - i.tag('repo' => to_repo, 'tag' => to_tag, 'force' => force) + converge_by "update #{new_resource.target_repo}:#{new_resource.target_tag} to #{new_resource.to_repo}:#{new_resource.to_tag}" do + i = Docker::Image.get("#{new_resource.target_repo}:#{new_resource.target_tag}") + i.tag('repo' => new_resource.to_repo, 'tag' => new_resource.to_tag, 'force' => new_resource.force) end rescue Docker::Error => e raise e.message diff --git a/chef/cookbooks/docker/libraries/docker_volume.rb b/chef/cookbooks/docker/libraries/docker_volume.rb index 9bc735f..5ca73cf 100644 --- a/chef/cookbooks/docker/libraries/docker_volume.rb +++ b/chef/cookbooks/docker/libraries/docker_volume.rb @@ -1,12 +1,10 @@ module DockerCookbook class DockerVolume < DockerBase - require 'docker' - resource_name :docker_volume property :driver, String, desired_state: false - property :host, [String, nil], default: lazy { default_host }, desired_state: false - property :opts, [String, Array, nil], desired_state: false + property :host, [String, nil], default: lazy { ENV['DOCKER_HOST'] }, desired_state: false + property :opts, Hash, desired_state: false property :volume, Docker::Volume, desired_state: false property :volume_name, String, name_property: true @@ -19,15 +17,18 @@ module DockerCookbook end action :create do - converge_by "creating volume #{volume_name}" do - Docker::Volume.create(volume_name, {}, connection) - end if volume.nil? + converge_by "creating volume #{new_resource.volume_name}" do + opts = {} + opts['Driver'] = driver if property_is_set?(:driver) + opts['DriverOpts'] = opts if property_is_set?(:opts) + Docker::Volume.create(new_resource.volume_name, opts, connection) + end if current_resource.nil? end action :remove do - converge_by "removing volume #{volume_name}" do - volume.remove - end unless volume.nil? + converge_by "removing volume #{new_resource.volume_name}" do + current_resource.volume.remove + end unless current_resource.nil? end end end diff --git a/chef/cookbooks/docker/libraries/helpers_auth.rb b/chef/cookbooks/docker/libraries/helpers_auth.rb deleted file mode 100644 index 40b3654..0000000 --- a/chef/cookbooks/docker/libraries/helpers_auth.rb +++ /dev/null @@ -1,10 +0,0 @@ -module DockerCookbook - module DockerHelpers - module Authentication - # https://github.com/docker/docker/blob/4fcb9ac40ce33c4d6e08d5669af6be5e076e2574/registry/auth.go#L231 - def parse_registry_host(val) - val.sub(%r{https?://}, '').split('/').first - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_base.rb b/chef/cookbooks/docker/libraries/helpers_base.rb deleted file mode 100644 index 43b8f30..0000000 --- a/chef/cookbooks/docker/libraries/helpers_base.rb +++ /dev/null @@ -1,110 +0,0 @@ -module DockerCookbook - module DockerHelpers - module Base - require 'shellwords' - - # Misc - def to_snake_case(name) - # ExposedPorts -> _exposed_ports - name = name.gsub(/[A-Z]/) { |x| "_#{x.downcase}" } - # _exposed_ports -> exposed_ports - name = name[1..-1] if name.start_with?('_') - name - end - - ########## - # coersion - ########## - - def coerce_labels(v) - case v - when Hash, nil - v - else - Array(v).each_with_object({}) do |label, h| - parts = label.split(':') - h[parts[0]] = parts[1] - end - end - end - - def coerce_shell_command(v) - return nil if v.nil? - return DockerBase::ShellCommandString.new( - ::Shellwords.join(v) - ) if v.is_a?(Array) - DockerBase::ShellCommandString.new(v) - end - - ################ - # Helper methods - ################ - - def api_version - @api_version ||= Docker.version(connection)['ApiVersion'] - end - - def connection - @connection ||= begin - opts = {} - opts[:read_timeout] = read_timeout if read_timeout - opts[:write_timeout] = write_timeout if write_timeout - - if host =~ /^tcp:/ - opts[:scheme] = 'https' if tls || !tls_verify.nil? - opts[:ssl_ca_file] = tls_ca_cert if tls_ca_cert - opts[:client_cert] = tls_client_cert if tls_client_cert - opts[:client_key] = tls_client_key if tls_client_key - end - Docker::Connection.new(host || Docker.url, opts) - end - end - - def with_retries(&_block) - tries = api_retries - begin - yield - # Only catch errors that can be fixed with retries. - rescue Docker::Error::ServerError, # 404 - Docker::Error::UnexpectedResponseError, # 400 - Docker::Error::TimeoutError, - Docker::Error::IOError - tries -= 1 - retry if tries > 0 - raise - end - end - - def call_action(_action) - new_resource.run_action - end - - def default_host - return nil unless ENV['DOCKER_HOST'] - ENV['DOCKER_HOST'] - end - - def default_tls - return nil unless ENV['DOCKER_TLS'] - ENV['DOCKER_TLS'] - end - - def default_tls_verify - return nil unless ENV['DOCKER_TLS_VERIFY'] - ENV['DOCKER_TLS_VERIFY'] - end - - def default_tls_cert_path(v) - return nil unless ENV['DOCKER_CERT_PATH'] - case v - when 'ca' - "#{ENV['DOCKER_CERT_PATH']}/ca.pem" - when 'cert' - "#{ENV['DOCKER_CERT_PATH']}/cert.pem" - when 'key' - "#{ENV['DOCKER_CERT_PATH']}/key.pem" - end - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_container.rb b/chef/cookbooks/docker/libraries/helpers_container.rb deleted file mode 100644 index 66e8dca..0000000 --- a/chef/cookbooks/docker/libraries/helpers_container.rb +++ /dev/null @@ -1,236 +0,0 @@ -module DockerCookbook - module DockerHelpers - module Container - def coerce_links(v) - case v - when DockerBase::UnorderedArray, nil - v - else - return nil if v.empty? - # Parse docker input of /source:/container_name/dest into source:dest - DockerBase::UnorderedArray.new(Array(v)).map! do |link| - if link =~ %r{^/(?.+):/#{name}/(?.+)} - link = "#{Regexp.last_match[:source]}:#{Regexp.last_match[:dest]}" - end - link - end - end - end - - def coerce_log_opts(v) - case v - when Hash, nil - v - else - Array(v).each_with_object({}) do |log_opt, memo| - key, value = log_opt.split('=', 2) - memo[key] = value - end - end - end - - def coerce_ulimits(v) - return v if v.nil? - Array(v).map do |u| - u = "#{u['Name']}=#{u['Soft']}:#{u['Hard']}" if u.is_a?(Hash) - u - end - end - - def coerce_volumes(v) - case v - when DockerBase::PartialHash, nil - v - when Hash - DockerBase::PartialHash[v] - else - b = [] - v = Array(v).to_a # in case v.is_A?(Chef::Node::ImmutableArray) - v.delete_if do |x| - parts = x.split(':') - b << x if parts.length > 1 - end - b = nil if b.empty? - volumes_binds b - return DockerBase::PartialHash.new if v.empty? - v.each_with_object(DockerBase::PartialHash.new) { |volume, h| h[volume] = {} } - end - end - - def state - # Always return the latest state, see #510 - return Docker::Container.get(container_name, {}, connection).info['State'] - rescue - return {} - end - - def wait_running_state(v) - tries = running_wait_time - tries.times do - return if state['Running'] == v - sleep 1 - end - return if state['Running'] == v - - # Container failed to reach correct state: Throw an error - desired_state_str = v ? 'running' : 'not running' - raise Docker::Error::TimeoutError, "Container #{container_name} failed to change to #{desired_state_str} state after #{tries} seconds" - end - - def port(v = nil) - return @port if v.nil? - exposed_ports coerce_exposed_ports(v) - port_bindings coerce_port_bindings(v) - @port = v - @port - end - - def parse_port(v) - parts = v.split(':') - case parts.length - when 3 - host_ip = parts[0] - host_port = parts[1] - container_port = parts[2] - when 2 - host_ip = '0.0.0.0' - host_port = parts[0] - container_port = parts[1] - when 1 - host_ip = '' - host_port = '' - container_port = parts[0] - end - port_range, protocol = container_port.split('/') - if port_range.include?('-') - port_range = container_port.split('-') - port_range.map!(&:to_i) - Chef::Log.fatal("FATAL: Invalid port range! #{container_port}") if port_range[0] > port_range[1] - port_range = (port_range[0]..port_range[1]).to_a - end - # qualify the port-binding protocol even when it is implicitly tcp #427. - protocol = 'tcp' if protocol.nil? - Array(port_range).map do |port| - { - 'host_ip' => host_ip, - 'host_port' => host_port, - 'container_port' => "#{port}/#{protocol}", - } - end - end - - def coerce_exposed_ports(v) - case v - when Hash, nil - v - else - x = Array(v).map { |a| parse_port(a) } - x.flatten! - x.each_with_object({}) do |y, h| - h[y['container_port']] = {} - end - end - end - - def coerce_port_bindings(v) - case v - when Hash, nil - v - else - x = Array(v).map { |a| parse_port(a) } - x.flatten! - x.each_with_object({}) do |y, h| - h[y['container_port']] = [] unless h[y['container_port']] - h[y['container_port']] << { - 'HostIp' => y['host_ip'], - 'HostPort' => y['host_port'], - } - end - end - end - - # log_driver and log_opts really handle this - def log_config(value = Chef::NOT_PASSED) - if value != Chef::NOT_PASSED - @log_config = value - log_driver value['Type'] - log_opts value['Config'] - end - return @log_config if defined?(@log_config) - def_logcfg = {} - def_logcfg['Type'] = log_driver if property_is_set?(:log_driver) - def_logcfg['Config'] = log_opts if property_is_set?(:log_opts) - def_logcfg = nil if def_logcfg.empty? - def_logcfg - end - - # TODO: test image property in serverspec and kitchen, not only in rspec - # for full specs of image parsing, see spec/helpers_container_spec.rb - # - # If you say: `repo 'blah'` - # Image will be: `blah:latest` - # - # If you say: `repo 'blah'; tag '3.1'` - # Image will be: `blah:3.1` - # - # If you say: `image 'blah'` - # Repo will be: `blah` - # Tag will be: `latest` - # - # If you say: `image 'blah:3.1'` - # Repo will be: `blah` - # Tag will be: `3.1` - # - # If you say: `image 'repo/blah'` - # Repo will be: `repo/blah` - # Tag will be: `latest` - # - # If you say: `image 'repo/blah:3.1'` - # Repo will be: `repo/blah` - # Tag will be: `3.1` - # - # If you say: `image 'repo:1337/blah'` - # Repo will be: `repo:1337/blah` - # Tag will be: `latest' - # - # If you say: `image 'repo:1337/blah:3.1'` - # Repo will be: `repo:1337/blah` - # Tag will be: `3.1` - # - def image(image = nil) - if image - if image.include?('/') - # pathological case, a ':' may be present which starts the 'port' - # part of the image name and not a tag. example: 'host:1337/blah' - # fortunately, tags are only found in the 'basename' part of image - # so we can split on '/' and rebuild once the tag has been parsed. - dirname, _, basename = image.rpartition('/') - r, t = basename.split(':', 2) - r = [dirname, r].join('/') - else - # normal case, the ':' starts the tag part - r, t = image.split(':', 2) - end - repo r - tag t if t - end - "#{repo}:#{tag}" - end - - def to_shellwords(command) - return nil if command.nil? - Shellwords.shellwords(command) - end - - def ulimits_to_hash - return nil if ulimits.nil? - ulimits.map do |u| - name = u.split('=')[0] - soft = u.split('=')[1].split(':')[0] - hard = u.split('=')[1].split(':')[1] - { 'Name' => name, 'Soft' => soft.to_i, 'Hard' => hard.to_i } - end - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_image.rb b/chef/cookbooks/docker/libraries/helpers_image.rb deleted file mode 100644 index f08614c..0000000 --- a/chef/cookbooks/docker/libraries/helpers_image.rb +++ /dev/null @@ -1,104 +0,0 @@ -module DockerCookbook - module DockerHelpers - module Image - ################ - # Helper methods - ################ - - def build_from_directory - i = Docker::Image.build_from_dir( - source, - { - 'nocache' => nocache, - 'rm' => rm, - }, - connection - ) - i.tag('repo' => repo, 'tag' => tag, 'force' => force) - end - - def build_from_dockerfile - i = Docker::Image.build( - IO.read(source), - { - 'nocache' => nocache, - 'rm' => rm, - }, - connection - ) - i.tag('repo' => repo, 'tag' => tag, 'force' => force) - end - - def build_from_tar - i = Docker::Image.build_from_tar( - ::File.open(source, 'r'), - { - 'nocache' => nocache, - 'rm' => rm, - }, - connection - ) - i.tag('repo' => repo, 'tag' => tag, 'force' => force) - end - - def build_image - if ::File.directory?(source) - build_from_directory - elsif ::File.extname(source) == '.tar' - build_from_tar - else - build_from_dockerfile - end - end - - def image_identifier - "#{repo}:#{tag}" - end - - def import_image - with_retries do - i = Docker::Image.import(source, {}, connection) - i.tag('repo' => repo, 'tag' => tag, 'force' => force) - end - end - - def pull_image - with_retries do - registry_host = parse_registry_host(repo) - creds = node.run_state['docker_auth'] && node.run_state['docker_auth'][registry_host] || (node.run_state['docker_auth'] ||= {})['index.docker.io'] - - original_image = Docker::Image.get(image_identifier, {}, connection) if Docker::Image.exist?(image_identifier, {}, connection) - new_image = Docker::Image.create({ 'fromImage' => image_identifier }, creds, connection) - - !(original_image && original_image.id.start_with?(new_image.id)) - end - end - - def push_image - with_retries do - i = Docker::Image.get(image_identifier, {}, connection) - i.push - end - end - - def remove_image - with_retries do - i = Docker::Image.get(image_identifier, {}, connection) - i.remove(force: force, noprune: noprune) - end - end - - def save_image - with_retries do - Docker::Image.save(repo, destination, connection) - end - end - - def load_image - with_retries do - Docker::Image.load(source, {}, connection) - end - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_installation_binary.rb b/chef/cookbooks/docker/libraries/helpers_installation_binary.rb deleted file mode 100644 index 625c8dc..0000000 --- a/chef/cookbooks/docker/libraries/helpers_installation_binary.rb +++ /dev/null @@ -1,66 +0,0 @@ -module DockerCookbook - module DockerHelpers - module InstallationBinary - def docker_bin - '/usr/bin/docker' - end - - def docker_kernel - node['kernel']['name'] - end - - def docker_arch - node['kernel']['machine'] - end - - def default_source - "https://get.docker.com/builds/#{docker_kernel}/#{docker_arch}/docker-#{version}" - end - - def default_checksum - case docker_kernel - when 'Darwin' - case version - when '1.6.0' then '9e960e925561b4ec2b81f52b6151cd129739c1f4fba91ce94bdc0333d7d98c38' - when '1.6.2' then 'f29b8b2185c291bd276f7cdac45a674f904e964426d5b969fda7b8ef6b8ab557' - when '1.7.0' then '1c8ee59249fdde401afebc9a079cb75d7674f03d2491789fb45c88020a8c5783' - when '1.7.1' then 'b8209b4382d0b4292c756dd055c12e5efacec2055d5900ac91efc8e81d317cf9' - when '1.8.1' then '0f5db35127cf14b57614ad7513296be600ddaa79182d8d118d095cb90c721e3a' - when '1.8.2' then 'cef593612752e5a50bd075931956075a534b293b7002892072397c3093fe11a6' - when '1.8.3' then 'b5a63a0e6fb393de8c3543c83433224796c7545901963ff3e3e9a41b1430c9cd' - when '1.9.0' then '91a8701e41a479def5371a333657c58c36478602e1f5eb1835457a3880232a2e' - when '1.9.1' then '8750ccc2098ec94ef7db110e0016ab02cfa47a1a76f0deb3faa50335b5ec0df9' - when '1.10.0' then 'f8dc0c7ef2a7efbe0e062017822066e55a40c752b9e92a636359f59ef562d79f' - when '1.10.1' then 'de4057057acd259ec38b5244a40d806993e2ca219e9869ace133fad0e09cedf2' - when '1.10.2' then '29249598587ad8f8597235bbeb11a11888fffb977b8089ea80b5ac5267ba9f2e' - end - when 'Linux' - case version - when '1.6.0' then '526fbd15dc6bcf2f24f99959d998d080136e290bbb017624a5a3821b63916ae8' - when '1.6.2' then 'e131b2d78d9f9e51b0e5ca8df632ac0a1d48bcba92036d0c839e371d6cf960ec' - when '1.7.1' then '4d535a62882f2123fb9545a5d140a6a2ccc7bfc7a3c0ec5361d33e498e4876d5' - when '1.8.1' then '843f90f5001e87d639df82441342e6d4c53886c65f72a5cc4765a7ba3ad4fc57' - when '1.8.2' then '97a3f5924b0b831a310efa8bf0a4c91956cd6387c4a8667d27e2b2dd3da67e4d' - when '1.8.3' then 'f024bc65c45a3778cf07213d26016075e8172de8f6e4b5702bedde06c241650f' - when '1.9.0' then '5d46455aac507e231fd2a558459779f1994f7151d6cb027efabfa36f568cf017' - when '1.9.1' then '52286a92999f003e1129422e78be3e1049f963be1888afc3c9a99d5a9af04666' - when '1.10.0' then 'a66b20423b7d849aa8ef448b98b41d18c45a30bf3fe952cc2ba4760600b18087' - when '1.10.1' then 'de4057057acd259ec38b5244a40d806993e2ca219e9869ace133fad0e09cedf2' - when '1.10.2' then '3fcac4f30e1c1a346c52ba33104175ae4ccbd9b9dbb947f56a0a32c9e401b768' - end - end - end - - def default_version - if node['platform'] == 'amazon' || - node['platform'] == 'ubuntu' && node['platform_version'].to_f < 15.04 || - node['platform_family'] == 'rhel' && node['platform_version'].to_i < 7 || - node['platform_family'] == 'debian' && node['platform_version'].to_i <= 7 - '1.6.2' - else - '1.10.2' - end - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_installation_package.rb b/chef/cookbooks/docker/libraries/helpers_installation_package.rb deleted file mode 100644 index 6d738fa..0000000 --- a/chef/cookbooks/docker/libraries/helpers_installation_package.rb +++ /dev/null @@ -1,105 +0,0 @@ -module DockerCookbook - module DockerHelpers - module InstallationPackage - def el6? - return true if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 6 - false - end - - def el7? - return true if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 7 - false - end - - def fedora? - return true if node['platform'] == 'fedora' - false - end - - def wheezy? - return true if node['platform'] == 'debian' && node['platform_version'].to_i == 7 - false - end - - def jesse? - return true if node['platform'] == 'debian' && node['platform_version'].to_i == 8 - false - end - - def precise? - return true if node['platform'] == 'ubuntu' && node['platform_version'] == '12.04' - false - end - - def trusty? - return true if node['platform'] == 'ubuntu' && node['platform_version'] == '14.04' - return true if node['platform'] == 'linuxmint' && node['platform_version'] =~ /^17\.[0-9]$/ - false - end - - def vivid? - return true if node['platform'] == 'ubuntu' && node['platform_version'] == '15.04' - false - end - - def wily? - return true if node['platform'] == 'ubuntu' && node['platform_version'] == '15.10' - false - end - - def xenial? - return true if node['platform'] == 'ubuntu' && node['platform_version'] == '16.04' - false - end - - def amazon? - return true if node['platform'] == 'amazon' - false - end - - # https://github.com/chef/chef/issues/4103 - def version_string(v) - ubuntu_prefix = if Gem::Version.new(v) > Gem::Version.new('1.12.3') - 'ubuntu-' - else - '' - end - - debian_prefix = if Gem::Version.new(v) > Gem::Version.new('1.12.3') - 'debian-' - else - '' - end - - return "#{v}-1.el6" if el6? - return "#{v}-1.el7.centos" if el7? - return "#{v}-1.17.amzn1" if amazon? - return "#{v}-1.fc#{node['platform_version'].to_i}" if fedora? - return "#{v}-0~#{debian_prefix}wheezy" if wheezy? - return "#{v}-0~#{debian_prefix}jessie" if jesse? - return "#{v}-0~#{ubuntu_prefix}precise" if precise? - return "#{v}-0~#{ubuntu_prefix}trusty" if trusty? - return "#{v}-0~#{ubuntu_prefix}vivid" if vivid? - return "#{v}-0~#{ubuntu_prefix}wily" if wily? - return "#{v}-0~#{ubuntu_prefix}xenial" if xenial? - v - end - - def default_docker_version - return '1.7.1' if el6? - return '1.9.1' if vivid? - return '1.12.6' if amazon? - '1.13.1' - end - - def default_package_name - return 'docker' if amazon? - 'docker-engine' - end - - def docker_bin - '/usr/bin/docker' - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_installation_tarball.rb b/chef/cookbooks/docker/libraries/helpers_installation_tarball.rb deleted file mode 100644 index dd3c27c..0000000 --- a/chef/cookbooks/docker/libraries/helpers_installation_tarball.rb +++ /dev/null @@ -1,50 +0,0 @@ -module DockerCookbook - module DockerHelpers - module InstallationTarball - def docker_bin_prefix - '/usr/bin' - end - - def docker_bin - "#{docker_bin_prefix}/docker" - end - - def docker_tarball - "#{Chef::Config[:file_cache_path]}/docker-#{version}.tgz" - end - - def docker_kernel - node['kernel']['name'] - end - - def docker_arch - node['kernel']['machine'] - end - - def default_source - "https://get.docker.com/builds/#{docker_kernel}/#{docker_arch}/docker-#{version}.tgz" - end - - def default_checksum - case docker_kernel - when 'Darwin' - case version - when '1.11.0' then '25e4f5f37e2e17beb20e5a468674750350824059bdeeca09d6a941bca8fc4f73' - when '1.11.1' then '6d35487fbcc7e3f722f3d5f3e5c070a41d87c88e3770f52ae28460a689c40efd' - when '1.11.2' then 'f44da1025c355c51ae6e150fcc0672b87a738b9c8ad98e5fa6091502211da19a' - end - when 'Linux' - case version - when '1.11.0' then '87331b3b75d32d3de5d507db9a19a24dd30ff9b2eb6a5a9bdfaba954da15e16b' - when '1.11.1' then '893e3c6e89c0cd2c5f1e51ea41bc2dd97f5e791fcfa3cee28445df277836339d' - when '1.11.2' then '8c2e0c35e3cda11706f54b2d46c2521a6e9026a7b13c7d4b8ae1f3a706fc55e1' - end - end - end - - def default_version - '1.11.2' - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_network.rb b/chef/cookbooks/docker/libraries/helpers_network.rb deleted file mode 100644 index b42ee24..0000000 --- a/chef/cookbooks/docker/libraries/helpers_network.rb +++ /dev/null @@ -1,118 +0,0 @@ -module DockerCookbook - module DockerHelpers - module Network - require 'ipaddr' - - ################### - # property coersion - ################### - - def coerce_auxiliary_addresses(v) - ray = [] - Array(v).each do |e| - case e - when String, Array, nil - ray += Array(e) - when Hash - e.each { |key, val| ray << "#{key}=#{val}" } - end - end - ray.length == 1 ? ray[0] : ray - end - - def coerce_gateway(v) - case v - when String - v.split('/')[0] - when Array - ray = Array(v).map { |a| a.split('/')[0] } - ray.length == 1 ? ray[0] : ray - end - end - - def coerce_subnet(v) - Array(v).length == 1 ? Array(v)[0] : v - end - - def coerce_ip_range(v) - Array(v).length == 1 ? Array(v)[0] : v - end - - ###### - # IPAM - ###### - - def consolidate_ipam(subnets, ranges, gateways, auxaddrs) - subnets = Array(subnets) - ranges = Array(ranges) - gateways = Array(gateways) - auxaddrs = Array(auxaddrs) - subnets = [] if subnets.empty? - ranges = [] if ranges.empty? - gateways = [] if gateways.empty? - auxaddrs = [] if auxaddrs.empty? - if subnets.size < ranges.size || subnets.size < gateways.size - raise 'every ip-range or gateway myust have a corresponding subnet' - end - - data = {} - - # Check overlapping subnets - subnets.each do |s| - data.each do |k, _| - if subnet_matches(s, k) || subnet_matches(k, s) - raise 'multiple overlapping subnet configuration is not supported' - end - end - data[s] = { 'Subnet' => s, 'AuxiliaryAddresses' => {} } - end - - ranges.each do |r| - match = false - subnets.each do |s| - ok = subnet_matches(s, r) - next unless ok - if data[s].fetch('IPRange', '') != '' - raise 'cannot configure multiple ranges on the same subnet' - end - data[s]['IPRange'] = r - match = true - end - raise "no matching subnet for range #{r}" unless match - end - - gateways.each do |g| - match = false - subnets.each do |s| - ok = subnet_matches(s, g) - next unless ok - unless data[s].fetch('Gateway', '').empty? - raise "cannot configure multiple gateways (#{g}, #{data[s]['Gateway']}) for the same subnet (#{s})" - end - data[s]['Gateway'] = g - match = true - end - raise "no matching subnet for gateway #{s}" unless match - end - - auxaddrs.each do |aa| - key, a = aa.split('=') - match = false - subnets.each do |s| - # require 'pry' ; binding.pry - ok = subnet_matches(s, a) - next unless ok - data[s]['AuxiliaryAddresses'][key] = a - match = true - end - raise "no matching subnet for aux-address #{a}" unless match - end - data.values - end - - def subnet_matches(subnet, data) - IPAddr.new(subnet).include?(IPAddr.new(data)) - end - end - end -end diff --git a/chef/cookbooks/docker/libraries/helpers_service.rb b/chef/cookbooks/docker/libraries/helpers_service.rb index 320ab63..3cf20c3 100644 --- a/chef/cookbooks/docker/libraries/helpers_service.rb +++ b/chef/cookbooks/docker/libraries/helpers_service.rb @@ -16,13 +16,13 @@ fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}| ([0-9a-fA-F]{1,4}:){1,4}: ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3} (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]) -)/ +)/.freeze -IPV4_ADDR ||= /((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])/ +IPV4_ADDR ||= /((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])/.freeze -IPV6_CIDR ||= /s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*/ +IPV6_CIDR ||= /s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*/.freeze -IPV4_CIDR ||= %r{(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))} +IPV4_CIDR ||= %r{(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))}.freeze module DockerCookbook module DockerHelpers @@ -58,13 +58,13 @@ module DockerCookbook c_a = 3 if a =~ %r{^tcp://127.0.0.1:} c_a = 4 if a =~ %r{^tcp://(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.).*:} c_a = 5 if a =~ %r{^tcp://0.0.0.0:} - c_a = 6 unless c_a + c_a ||= 6 c_b = 1 if b =~ /^unix:/ c_b = 2 if b =~ /^fd:/ c_b = 3 if b =~ %r{^tcp://127.0.0.1:} c_b = 4 if b =~ %r{^tcp://(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.).*:} c_b = 5 if b =~ %r{^tcp://0.0.0.0:} - c_b = 6 unless c_b + c_b ||= 6 c_a <=> c_b end if sorted.first =~ %r{^tcp://0.0.0.0:} @@ -76,16 +76,17 @@ module DockerCookbook def connect_socket return "/var/run/#{docker_name}.sock" unless host + return nil if host.grep(%r{unix://|fd://}).empty? sorted = coerce_host(host).sort do |a, b| c_a = 1 if a =~ /^unix:/ c_a = 2 if a =~ /^fd:/ - c_a = 3 unless c_a + c_a ||= 3 c_b = 1 if b =~ /^unix:/ c_b = 2 if b =~ /^fd:/ - c_b = 3 unless c_b + c_b ||= 3 c_a <=> c_b end - sorted.first + sorted.first.sub(%r{unix://|fd://}, '') end def coerce_host(v) @@ -138,6 +139,14 @@ module DockerCookbook end end + def docker_raw_logs_arg + if Gem::Version.new(docker_major_version) < Gem::Version.new('1.11') + '' + else + '--raw-logs' + end + end + def docker_daemon_cmd [dockerd_bin, docker_daemon_arg, docker_daemon_opts].join(' ') end @@ -165,6 +174,12 @@ module DockerCookbook opts end + def systemd_socket_args + opts = '' + systemd_socket_opts.each { |systemd_socket_opt| opts << "#{systemd_socket_opt}\n" } if systemd_socket_opts + opts + end + def docker_daemon_opts opts = [] opts << "--api-cors-header=#{api_cors_header}" if api_cors_header @@ -182,8 +197,9 @@ module DockerCookbook opts << "--fixed-cidr=#{fixed_cidr}" if fixed_cidr opts << "--fixed-cidr-v6=#{fixed_cidr_v6}" if fixed_cidr_v6 opts << "--group=#{group}" if group - opts << "--graph=#{graph}" if graph - host.each { |h| opts << "-H #{h}" } if host + opts << "--data-root=#{data_root}" if data_root + opts << "--default-address-pool=#{default_ip_address_pool}" unless default_ip_address_pool.nil? + host.each { |h| opts << "--host #{h}" } if host opts << "--icc=#{icc}" unless icc.nil? insecure_registry.each { |i| opts << "--insecure-registry=#{i}" } if insecure_registry opts << "--ip=#{ip}" if ip @@ -194,7 +210,7 @@ module DockerCookbook opts << "--log-level=#{log_level}" if log_level labels.each { |l| opts << "--label=#{l}" } if labels opts << "--log-driver=#{log_driver}" if log_driver - log_opts.each { |log_opt| opts << "--log-opt #{log_opt}" } if log_opts + log_opts.each { |log_opt| opts << "--log-opt '#{log_opt}'" } if log_opts opts << "--mtu=#{mtu}" if mtu opts << "--pidfile=#{pidfile}" if pidfile opts << "--registry-mirror=#{registry_mirror}" if registry_mirror @@ -218,6 +234,6 @@ module DockerCookbook return true if o.stdout =~ /CONTAINER/ false end - end + end unless defined?(DockerCookbook::DockerHelpers::Service) end end diff --git a/chef/cookbooks/docker/libraries/matchers.rb b/chef/cookbooks/docker/libraries/matchers.rb deleted file mode 100644 index 87cb23d..0000000 --- a/chef/cookbooks/docker/libraries/matchers.rb +++ /dev/null @@ -1,339 +0,0 @@ -if defined?(ChefSpec) - ##################### - # docker_installation - ##################### - ChefSpec.define_matcher :docker_installation - - def create_docker_installation(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation, :create, resource_name) - end - - def delete_docker_installation(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation, :delete, resource_name) - end - - def create_docker_installation_binary(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_binary, :create, resource_name) - end - - def delete_docker_installation_binary(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_binary, :delete, resource_name) - end - - def create_docker_installation_script(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_script, :create, resource_name) - end - - def delete_docker_installation_script(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_script, :delete, resource_name) - end - - def create_docker_installation_package(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_package, :create, resource_name) - end - - def delete_docker_installation_package(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_package, :delete, resource_name) - end - - def create_docker_installation_tarball(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_tarball, :create, resource_name) - end - - def delete_docker_installation_tarball(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_installation_tarball, :delete, resource_name) - end - - ################ - # docker_service - ################ - ChefSpec.define_matcher :docker_service - - def create_docker_service(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service, :create, resource_name) - end - - def delete_docker_service(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service, :delete, resource_name) - end - - def start_docker_service(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service, :start, resource_name) - end - - def stop_docker_service(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service, :stop, resource_name) - end - - def restart_docker_service(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service, :restart, resource_name) - end - - ######################## - # docker_service_manager - ######################## - ChefSpec.define_matcher :docker_service_manager - - def create_docker_service_manager(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager, :create, resource_name) - end - - def delete_docker_service_manager(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager, :delete, resource_name) - end - - def start_docker_service_manager(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager, :start, resource_name) - end - - def stop_docker_service_manager(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager, :stop, resource_name) - end - - def restart_docker_service_manager(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager, :restart, resource_name) - end - - def create_docker_service_manager_execute(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_execute, :create, resource_name) - end - - def delete_docker_service_manager_execute(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_execute, :delete, resource_name) - end - - def start_docker_service_manager_execute(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_execute, :start, resource_name) - end - - def stop_docker_service_manager_execute(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_execute, :stop, resource_name) - end - - def restart_docker_service_manager_execute(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_execute, :restart, resource_name) - end - - def create_docker_service_manager_sysvinit(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_sysvinit, :create, resource_name) - end - - def delete_docker_service_manager_sysvinit(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_sysvinit, :delete, resource_name) - end - - def start_docker_service_manager_sysvinit(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_sysvinit, :start, resource_name) - end - - def stop_docker_service_manager_sysvinit(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_sysvinit, :stop, resource_name) - end - - def restart_docker_service_manager_sysvinit(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_sysvinit, :restart, resource_name) - end - - def create_docker_service_manager_upstart(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_upstart, :create, resource_name) - end - - def delete_docker_service_manager_upstart(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_upstart, :delete, resource_name) - end - - def start_docker_service_manager_upstart(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_upstart, :start, resource_name) - end - - def stop_docker_service_manager_upstart(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_upstart, :stop, resource_name) - end - - def restart_docker_service_manager_upstart(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_upstart, :restart, resource_name) - end - - def create_docker_service_manager_systemd(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_systemd, :create, resource_name) - end - - def delete_docker_service_manager_systemd(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_systemd, :delete, resource_name) - end - - def start_docker_service_manager_systemd(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_systemd, :start, resource_name) - end - - def stop_docker_service_manager_systemd(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_systemd, :stop, resource_name) - end - - def restart_docker_service_manager_systemd(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_service_manager_systemd, :restart, resource_name) - end - - ############## - # docker_image - ############## - ChefSpec.define_matcher :docker_image - - def build_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :build, resource_name) - end - - def build_if_missing_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :build_if_missing, resource_name) - end - - def pull_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :pull, resource_name) - end - - def pull_if_missing_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :pull_if_missing, resource_name) - end - - def import_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :import, resource_name) - end - - def push_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :push, resource_name) - end - - def remove_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :remove, resource_name) - end - - def save_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :save, resource_name) - end - - def load_docker_image(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_image, :load, resource_name) - end - - ################## - # docker_container - ################## - ChefSpec.define_matcher :docker_container - - def create_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :create, resource_name) - end - - def start_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :start, resource_name) - end - - def stop_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :stop, resource_name) - end - - def kill_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :kill, resource_name) - end - - def run_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :run, resource_name) - end - - def run_if_missing_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :run_if_missing, resource_name) - end - - def pause_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :pause, resource_name) - end - - def unpause_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :unpause, resource_name) - end - - def restart_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :restart, resource_name) - end - - def redeploy_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :redeploy, resource_name) - end - - def delete_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :delete, resource_name) - end - - def remove_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :remove, resource_name) - end - - def commit_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :commit, resource_name) - end - - def export_docker_container(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_container, :export, resource_name) - end - - ############## - # docker_tag - ############## - ChefSpec.define_matcher :docker_tag - - def tag_docker_tag(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_tag, :tag, resource_name) - end - - ################# - # docker_registry - ################# - ChefSpec.define_matcher :docker_registry - - def login_docker_registry(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_registry, :login, resource_name) - end - - ################ - # docker_network - ################ - ChefSpec.define_matcher :docker_network - - def create_docker_network(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_network, :create, resource_name) - end - - def delete_docker_network(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_network, :delete, resource_name) - end - - def connect_docker_network(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_network, :connect, resource_name) - end - - def disconnect_docker_network(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_network, :disconnect, resource_name) - end - - ############### - # docker_volume - ############### - ChefSpec.define_matcher :docker_volume - - def create_docker_volume(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_volume, :create, resource_name) - end - - def remove_docker_volume(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_volume, :remove, resource_name) - end - - ############### - # docker_exec - ############### - ChefSpec.define_matcher :docker_exec - - def run_docker_exec(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:docker_exec, :run, resource_name) - end -end diff --git a/chef/cookbooks/docker/metadata.json b/chef/cookbooks/docker/metadata.json deleted file mode 100644 index d40d638..0000000 --- a/chef/cookbooks/docker/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"docker","version":"2.15.2","description":"Provides docker_service, docker_image, and docker_container resources","long_description":"","maintainer":"Cookbook Engineering Team","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","redhat":">= 0.0.0","ubuntu":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file diff --git a/chef/cookbooks/docker/metadata.rb b/chef/cookbooks/docker/metadata.rb new file mode 100644 index 0000000..efafcdb --- /dev/null +++ b/chef/cookbooks/docker/metadata.rb @@ -0,0 +1,21 @@ +name 'docker' +maintainer 'Chef Software, Inc.' +maintainer_email 'cookbooks@chef.io' +license 'Apache-2.0' +description 'Provides docker_service, docker_image, and docker_container resources' +version '4.9.2' + +source_url 'https://github.com/chef-cookbooks/docker' +issues_url 'https://github.com/chef-cookbooks/docker/issues' + +supports 'amazon' +supports 'centos' +supports 'scientific' +supports 'oracle' +supports 'debian' +supports 'fedora' +supports 'redhat' +supports 'ubuntu' + +chef_version '>= 12.15' +gem 'docker-api', '~> 1.34.0' diff --git a/chef/cookbooks/docker/spec/docker_test/container_spec.rb b/chef/cookbooks/docker/spec/docker_test/container_spec.rb new file mode 100644 index 0000000..873f5a1 --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/container_spec.rb @@ -0,0 +1,925 @@ +require 'spec_helper' + +describe 'docker_test::container' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + before do + stub_command("[ ! -z `docker ps -qaf 'name=busybox_ls$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=bill$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=hammer_time$'` ]").and_return(false) + stub_command('docker ps -a | grep red_light | grep Exited').and_return(true) + stub_command("[ ! -z `docker ps -qaf 'name=red_light$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=green_light$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=quitter$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=restarter$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=uber_options$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=kill_after$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=change_network_mode$'` ]").and_return(false) + stub_command('docker images | grep cmd_change').and_return(false) + stub_command('docker ps -a | grep cmd_change$').and_return(false) + end + + context 'testing create action' do + it 'create docker_container[hello-world]' do + expect(chef_run).to create_docker_container('hello-world').with( + api_retries: 3, + read_timeout: 60, + container_name: 'hello-world', + repo: 'hello-world', + tag: 'latest', + command: ['/hello'], + cgroup_parent: '', + cpu_shares: 0, + cpuset_cpus: '', + detach: true, + domain_name: '', + log_driver: 'json-file', + memory: 0, + memory_swap: 0, + network_disabled: false, + outfile: nil, + restart_maximum_retry_count: 0, + restart_policy: nil, + security_opt: nil, + signal: 'SIGTERM', + user: '' + ) + end + end + + context 'testing run action' do + it 'run docker_container[hello-world]' do + expect(chef_run).to run_docker_container('busybox_ls').with( + repo: 'busybox', + command: ['ls', '-la', '/'] + ) + end + + it 'run_if_missing docker_container[alpine_ls]' do + expect(chef_run).to run_if_missing_docker_container('alpine_ls').with( + repo: 'alpine', + tag: '3.1', + command: ['ls', '-la', '/'] + ) + end + end + + context 'testing ports property' do + it 'run docker_container[an_echo_server]' do + expect(chef_run).to run_docker_container('an_echo_server').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '7', '-e', '/bin/cat'], + port: '7:7' + ) + end + + it 'run docker_container[another_echo_server]' do + expect(chef_run).to run_docker_container('another_echo_server').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '7', '-e', '/bin/cat'], + port: '7' + ) + end + + it 'run docker_container[an_udp_echo_server]' do + expect(chef_run).to run_docker_container('an_udp_echo_server').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ul', '-p', '7', '-e', '/bin/cat'], + port: '5007:7/udp' + ) + end + + it 'run docker_container[multi_ip_port]' do + expect(chef_run).to run_docker_container('multi_ip_port').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ul', '-p', '7', '-e', '/bin/cat'], + port: ['8301', '8301:8301/udp', '127.0.0.1:8500:8500', '127.0.1.1:8500:8500'] + ) + end + + it 'run docker_container[port_range]' do + expect(chef_run).to run_docker_container('port_range').with( + repo: 'alpine', + tag: '3.1', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: ['2000-2001', '2000-2001/udp', '3000-3001/tcp', '7000-7002:8000-8002'] + ) + end + end + + context 'testing action :kill' do + it 'run execute[bill]' do + expect(chef_run).to run_execute('bill').with( + command: 'docker run --name bill -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'kill docker_container[bill]' do + expect(chef_run).to kill_docker_container('bill') + end + end + + context 'testing action :stop' do + it 'run execute[hammer_time]' do + expect(chef_run).to run_execute('hammer_time').with( + command: 'docker run --name hammer_time -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'stop docker_container[hammer_time]' do + expect(chef_run).to stop_docker_container('hammer_time') + end + end + + context 'testing action :pause' do + it 'run execute[rm stale red_light]' do + expect(chef_run).to run_execute('rm stale red_light').with( + command: 'docker rm -f red_light' + ) + end + + it 'run execute[red_light]' do + expect(chef_run).to run_execute('red_light').with( + command: 'docker run --name red_light -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'pause docker_container[red_light]' do + expect(chef_run).to pause_docker_container('red_light') + end + end + + context 'testing action :unpause' do + it 'run bash[green_light]' do + expect(chef_run).to run_bash('green_light') + end + + it 'unpause docker_container[green_light]' do + expect(chef_run).to unpause_docker_container('green_light') + end + end + + context 'testing action :restart' do + it 'run bash[quitter]' do + expect(chef_run).to run_bash('quitter') + end + + it 'restart docker_container[quitter]' do + expect(chef_run).to restart_docker_container('quitter') + end + + it 'create file[/marker_container_quitter_restarter]' do + expect(chef_run).to create_file('/marker_container_quitter_restarter') + end + + it 'run execute[restarter]' do + expect(chef_run).to run_execute('restarter').with( + command: 'docker run --name restarter -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'restart docker_container[restarter]' do + expect(chef_run).to restart_docker_container('restarter') + end + + it 'create file[/marker_container_restarter]' do + expect(chef_run).to create_file('/marker_container_restarter') + end + end + + context 'testing action :delete' do + it 'run execute[deleteme]' do + expect(chef_run).to run_execute('deleteme').with( + command: 'docker run --name deleteme -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'create file[/marker_container_deleteme' do + expect(chef_run).to create_file('/marker_container_deleteme') + end + + it 'delete docker_container[deleteme]' do + expect(chef_run).to delete_docker_container('deleteme') + end + end + + context 'testing action :redeploy' do + it 'runs docker_container[redeployer]' do + expect(chef_run).to run_docker_container('redeployer').with( + repo: 'alpine', + tag: '3.1', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: '7' + ) + end + + it 'creates docker_container[unstarted_redeployer]' do + expect(chef_run).to create_docker_container('unstarted_redeployer').with( + repo: 'alpine', + tag: '3.1', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: '7' + ) + end + + it 'runs execute[redeploy redeployers]' do + expect(chef_run).to run_execute('redeploy redeployers') + end + end + + context 'testing bind_mounter' do + it 'creates directory[/hostbits]' do + expect(chef_run).to create_directory('/hostbits').with( + owner: 'root', + group: 'root', + mode: '0755' + ) + end + + it 'creates file[/hostbits/hello.txt]' do + expect(chef_run).to create_file('/hostbits/hello.txt').with( + content: 'hello there\n', + owner: 'root', + group: 'root', + mode: '0644' + ) + end + + it 'creates directory[/more-hostbits]' do + expect(chef_run).to create_directory('/more-hostbits').with( + owner: 'root', + group: 'root', + mode: '0755' + ) + end + + it 'creates file[/more-hostbits/hello.txt]' do + expect(chef_run).to create_file('/more-hostbits/hello.txt').with( + content: 'hello there\n', + owner: 'root', + group: 'root', + mode: '0644' + ) + end + + it 'run_if_missing docker_container[bind_mounter]' do + expect(chef_run).to run_if_missing_docker_container('bind_mounter').with( + repo: 'busybox', + command: ['ls', '-la', '/bits', '/more-bits'], + volumes_binds: ['/hostbits:/bits', '/more-hostbits:/more-bits', '/winter:/spring:ro'], + volumes: { '/snow' => {}, '/summer' => {} } + ) + end + end + + context 'testing binds_alias' do + it 'run_if_missing docker_container[binds_alias]' do + expect(chef_run).to run_if_missing_docker_container('binds_alias').with( + repo: 'busybox', + command: ['ls', '-la', '/bits', '/more-bits'], + volumes_binds: ['/fall:/sun', '/winter:/spring:ro'], + volumes: { '/snow' => {}, '/summer' => {} } + ) + end + end + + context 'testing volumes_from' do + it 'creates directory[/chefbuilder]' do + expect(chef_run).to create_directory('/chefbuilder').with( + owner: 'root', + group: 'root' + ) + end + + it 'runs execute[copy chef to chefbuilder]' do + expect(chef_run).to run_execute('copy chef to chefbuilder').with( + command: 'tar cf - /opt/chef | tar xf - -C /chefbuilder', + creates: '/chefbuilder/opt' + ) + end + + it 'creates file[/chefbuilder/Dockerfile]' do + expect(chef_run).to create_file('/chefbuilder/Dockerfile') + end + + it 'build_if_missing docker_image[chef_container]' do + expect(chef_run).to build_if_missing_docker_image('chef_container').with( + tag: 'latest', + source: '/chefbuilder' + ) + end + + it 'create docker_container[chef_container]' do + expect(chef_run).to create_docker_container('chef_container').with( + command: ['true'], + volumes: { '/opt/chef' => {} } + ) + end + + it 'run_if_missing docker_container[ohai_debian]' do + expect(chef_run).to run_if_missing_docker_container('ohai_debian').with( + command: ['/opt/chef/embedded/bin/ohai', 'platform'], + repo: 'debian', + volumes_from: ['chef_container'] + ) + end + end + + context 'testing env' do + it 'run_if_missing docker_container[env]' do + expect(chef_run).to run_if_missing_docker_container('env').with( + repo: 'debian', + env: ['PATH=/usr/bin', 'FOO=bar'], + command: ['env'] + ) + end + end + + context 'testing entrypoint' do + it 'run_if_missing docker_container[ohai_again]' do + expect(chef_run).to run_if_missing_docker_container('ohai_again').with( + repo: 'debian', + volumes_from: ['chef_container'], + entrypoint: ['/opt/chef/embedded/bin/ohai'] + ) + end + + it 'run_if_missing docker_container[ohai_again_debian]' do + expect(chef_run).to run_if_missing_docker_container('ohai_again_debian').with( + repo: 'debian', + volumes_from: ['chef_container'], + entrypoint: ['/opt/chef/embedded/bin/ohai'], + command: ['platform'] + ) + end + end + + context 'testing Dockefile CMD directive' do + it 'creates directory[/cmd_test]' do + expect(chef_run).to create_directory('/cmd_test') + end + + it 'creates file[/cmd_test/Dockerfile]' do + expect(chef_run).to create_file('/cmd_test/Dockerfile') + end + + it 'build_if_missing docker_image[cmd_test]' do + expect(chef_run).to build_if_missing_docker_image('cmd_test').with( + tag: 'latest', + source: '/cmd_test' + ) + end + + it 'run_if_missing docker_container[cmd_test]' do + expect(chef_run).to run_if_missing_docker_container('cmd_test') + end + end + + context 'testing autoremove' do + it 'runs docker_container[sean_was_here]' do + expect(chef_run).to run_docker_container('sean_was_here').with( + repo: 'debian', + volumes_from: ['chef_container'], + autoremove: true + ) + end + + it 'creates file[/marker_container_sean_was_here]' do + expect(chef_run).to create_file('/marker_container_sean_was_here') + end + end + + context 'testing detach' do + it 'runs docker_container[attached]' do + expect(chef_run).to run_docker_container('attached').with( + repo: 'debian', + volumes_from: ['chef_container'], + detach: false + ) + end + + it 'creates file[/marker_container_attached]' do + expect(chef_run).to create_file('/marker_container_attached') + end + + context 'with timeout' do + it 'runs docker_container[attached_with_timeout]' do + expect(chef_run).to run_docker_container('attached_with_timeout').with( + repo: 'debian', + volumes_from: ['chef_container'], + detach: false, + timeout: 10 + ) + end + + it 'creates file[/marker_container_attached_with_timeout]' do + expect(chef_run).to create_file('/marker_container_attached_with_timeout') + end + end + end + + context 'testing cap_add' do + it 'run_if_missing docker_container[cap_add_net_admin]' do + expect(chef_run).to run_if_missing_docker_container('cap_add_net_admin').with( + repo: 'debian', + command: ['bash', '-c', 'ip addr add 10.9.8.7/24 brd + dev eth0 label eth0:0 ; ip addr list'], + cap_add: ['NET_ADMIN'] + ) + end + + it 'run_if_missing docker_container[cap_add_net_admin_error]' do + expect(chef_run).to run_if_missing_docker_container('cap_add_net_admin_error').with( + repo: 'debian', + command: ['bash', '-c', 'ip addr add 10.9.8.7/24 brd + dev eth0 label eth0:0 ; ip addr list'] + ) + end + end + + context 'testing cap_drop' do + it 'run_if_missing docker_container[cap_drop_mknod]' do + expect(chef_run).to run_if_missing_docker_container('cap_drop_mknod').with( + repo: 'debian', + command: ['bash', '-c', 'mknod -m 444 /dev/urandom2 c 1 9 ; ls -la /dev/urandom2'], + cap_drop: ['MKNOD'] + ) + end + + it 'run_if_missing docker_container[cap_drop_mknod_error]' do + expect(chef_run).to run_if_missing_docker_container('cap_drop_mknod_error').with( + repo: 'debian', + command: ['bash', '-c', 'mknod -m 444 /dev/urandom2 c 1 9 ; ls -la /dev/urandom2'] + ) + end + end + + context 'testing hostname and domain_name' do + it 'run_if_missing docker_container[fqdn]' do + expect(chef_run).to run_if_missing_docker_container('fqdn').with( + repo: 'debian', + command: ['hostname', '-f'], + hostname: 'computers', + domain_name: 'biz' + ) + end + end + + context 'testing dns' do + it 'run_if_missing docker_container[dns]' do + expect(chef_run).to run_if_missing_docker_container('dns').with( + repo: 'debian', + command: ['cat', '/etc/resolv.conf'], + hostname: 'computers', + dns: ['4.3.2.1', '1.2.3.4'], + dns_search: ['computers.biz', 'chef.io'] + ) + end + end + + context 'testing extra_hosts' do + it 'run_if_missing docker_container[extra_hosts]' do + expect(chef_run).to run_if_missing_docker_container('extra_hosts').with( + repo: 'debian', + command: ['cat', '/etc/hosts'], + extra_hosts: ['east:4.3.2.1', 'west:1.2.3.4'] + ) + end + end + + context 'testing cpu_shares' do + it 'run_if_missing docker_container[cpu_shares]' do + expect(chef_run).to run_if_missing_docker_container('cpu_shares').with( + repo: 'alpine', + tag: '3.1', + command: ['ls', '-la'], + cpu_shares: 512 + ) + end + end + + context 'testing cpuset_cpus' do + it 'run_if_missing docker_container[cpuset_cpus]' do + expect(chef_run).to run_if_missing_docker_container('cpuset_cpus').with( + repo: 'alpine', + tag: '3.1', + command: ['ls', '-la'], + cpuset_cpus: '0,1' + ) + end + end + + context 'testing restart_policy' do + it 'run_if_missing docker_container[try_try_again]' do + expect(chef_run).to run_if_missing_docker_container('try_try_again').with( + repo: 'alpine', + tag: '3.1', + command: ['grep', 'asdasdasd', '/etc/passwd'], + restart_policy: 'on-failure', + restart_maximum_retry_count: 2 + ) + end + + it 'run_if_missing docker_container[reboot_survivor]' do + expect(chef_run).to run_if_missing_docker_container('reboot_survivor').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '123', '-e', '/bin/cat'], + port: '123', + restart_policy: 'always' + ) + end + + it 'run_if_missing docker_container[reboot_survivor_retry]' do + expect(chef_run).to run_if_missing_docker_container('reboot_survivor_retry').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '123', '-e', '/bin/cat'], + port: '123', + restart_policy: nil, + restart_maximum_retry_count: 2 + ) + end + end + + context 'testing links' do + it 'runs docker_container[link_source]' do + expect(chef_run).to run_docker_container('link_source').with( + repo: 'alpine', + tag: '3.1', + env: ['FOO=bar', 'BIZ=baz'], + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: '321' + ) + end + + it 'runs docker_container[link_source_2]' do + expect(chef_run).to run_docker_container('link_source_2').with( + repo: 'alpine', + tag: '3.1', + env: ['FOO=few', 'BIZ=buzz'], + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: '322' + ) + end + + it 'run_if_missing docker_container[link_target_1]' do + expect(chef_run).to run_if_missing_docker_container('link_target_1').with( + repo: 'alpine', + tag: '3.1', + env: ['ASD=asd'], + command: ['ping', '-c', '1', 'hello'], + links: ['link_source:hello'] + ) + end + + it 'run_if_missing docker_container[link_target_2]' do + expect(chef_run).to run_if_missing_docker_container('link_target_2').with( + repo: 'alpine', + tag: '3.1', + command: ['env'], + links: ['link_source:hello'] + ) + end + + it 'run_if_missing docker_container[link_target_3]' do + expect(chef_run).to run_if_missing_docker_container('link_target_3').with( + repo: 'alpine', + tag: '3.1', + env: ['ASD=asd'], + command: ['ping', '-c', '1', 'hello_again'], + links: ['link_source:hello', 'link_source_2:hello_again'] + ) + end + + it 'run_if_missing docker_container[link_target_4]' do + expect(chef_run).to run_if_missing_docker_container('link_target_4').with( + repo: 'alpine', + tag: '3.1', + command: ['env'], + links: ['link_source:hello', 'link_source_2:hello_again'] + ) + end + + it 'runs execute[redeploy_link_source]' do + expect(chef_run).to run_execute('redeploy_link_source') + end + end + + context 'testing link removal' do + it 'run_if_missing docker_container[another_link_source]' do + expect(chef_run).to run_if_missing_docker_container('another_link_source').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '456', '-e', '/bin/cat'], + port: '456' + ) + end + + it 'run_if_missing docker_container[another_link_target]' do + expect(chef_run).to run_if_missing_docker_container('another_link_target').with( + repo: 'alpine', + tag: '3.1', + command: ['ping', '-c', '1', 'hello'], + links: ['another_link_source:derp'] + ) + end + end + + context 'testing volume removal' do + it 'creates directory[/dangler]' do + expect(chef_run).to create_directory('/dangler').with( + owner: 'root', + group: 'root', + mode: '0755' + ) + end + + it 'creates file[/dangler/Dockerfile]' do + expect(chef_run).to create_file('/dangler/Dockerfile') + end + + it 'build_if_missing docker_image[dangler]' do + expect(chef_run).to build_if_missing_docker_image('dangler').with( + tag: 'latest', + source: '/dangler' + ) + end + + it 'creates docker_container[dangler]' do + expect(chef_run).to create_docker_container('dangler').with( + command: ['true'] + ) + end + + it 'creates file[/marker_container_dangler]' do + expect(chef_run).to create_file('/marker_container_dangler') + end + + it 'deletes docker_container[dangler_volume_remover]' do + expect(chef_run).to delete_docker_container('dangler_volume_remover').with( + container_name: 'dangler', + remove_volumes: true + ) + end + end + + context 'testing mutator' do + it 'tags docker_tag[mutator_from_busybox]' do + expect(chef_run).to tag_docker_tag('mutator_from_busybox').with( + target_repo: 'busybox', + target_tag: 'latest', + to_repo: 'someara/mutator', + to_tag: 'latest' + ) + end + + it 'run_if_missing docker_container[mutator]' do + expect(chef_run).to run_if_missing_docker_container('mutator').with( + repo: 'someara/mutator', + tag: 'latest', + command: ['sh', '-c', 'touch /mutator-`date +"%Y-%m-%d_%H-%M-%S"`'], + outfile: '/mutator.tar', + force: true + ) + end + + it 'runs execute[commit mutator]' do + expect(chef_run).to run_execute('commit mutator') + end + end + + context 'testing network_mode' do + it 'runs docker_container[network_mode]' do + expect(chef_run).to run_docker_container('network_mode').with( + repo: 'alpine', + tag: '3.1', + command: ['nc', '-ll', '-p', '776', '-e', '/bin/cat'], + port: '776:776', + network_mode: 'host' + ) + end + end + + it 'runs execute[change_network_mode]' do + expect(chef_run).to run_execute('change_network_mode') + end + + it 'runs docker_container[change_network_mode]' do + expect(chef_run).to run_docker_container('change_network_mode') + end + + context 'testing ulimits' do + it 'runs docker_container[ulimits]' do + expect(chef_run).to run_docker_container('ulimits').with( + repo: 'alpine', + tag: '3.1', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + port: '778:778', + cap_add: ['SYS_RESOURCE'], + ulimits: [ + 'nofile=40960:40960', + 'core=100000000:100000000', + 'memlock=100000000:100000000', + ] + ) + end + end + + context 'testing api_timeouts' do + it 'run_if_missing docker_container[api_timeouts]' do + expect(chef_run).to run_if_missing_docker_container('api_timeouts').with( + command: ['nc', '-ll', '-p', '779', '-e', '/bin/cat'], + repo: 'alpine', + tag: '3.1', + read_timeout: 60, + write_timeout: 60 + ) + end + end + + context 'testing uber_options' do + it 'runs execute[uber_options]' do + expect(chef_run).to run_execute('uber_options').with( + command: 'docker run --name uber_options -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + ) + end + + it 'runs docker_container[uber_options]' do + expect(chef_run).to run_docker_container('uber_options').with( + repo: 'alpine', + tag: '3.1', + hostname: 'www', + domainname: 'computers.biz', + env: ['FOO=foo', 'BAR=bar'], + mac_address: '00:00:DE:AD:BE:EF', + network_disabled: false, + tty: true, + volumes_binds: ['/hostbits:/bits', '/more-hostbits:/more-bits'], + volumes: { '/root' => {} }, + working_dir: '/', + cap_add: %w(NET_ADMIN SYS_RESOURCE), + cap_drop: ['MKNOD'], + cpu_shares: 512, + cpuset_cpus: '0,1', + dns: ['8.8.8.8', '8.8.4.4'], + dns_search: ['computers.biz'], + extra_hosts: ['east:4.3.2.1', 'west:1.2.3.4'], + links: ['link_source:hello'], + port: '1234:1234', + volumes_from: ['chef_container'], + user: 'operator', + entrypoint: ['/bin/sh', '-c'], + command: ['trap exit 0 SIGTERM; while :; do sleep 5; done'], + ulimits: [ + 'nofile=40960:40960', + 'core=100000000:100000000', + 'memlock=100000000:100000000', + ], + labels: { 'foo' => 'bar', 'hello' => 'world' } + ) + end + end + + context 'testing overrides' do + it 'creates directory[/overrides]' do + expect(chef_run).to create_directory('/overrides').with( + owner: 'root', + group: 'root' + ) + end + + it 'creates file[/overrides/Dockerfile]' do + expect(chef_run).to create_file('/overrides/Dockerfile') + end + + it 'build_if_missing docker_image[overrides]' do + expect(chef_run).to build_if_missing_docker_image('overrides').with( + tag: 'latest', + source: '/overrides', + force: true + ) + end + + it 'run_if_missing docker_container[overrides-1]' do + expect(chef_run).to run_docker_container('overrides-1').with( + repo: 'overrides' + ) + end + + it 'run_if_missing docker_container[overrides-2]' do + expect(chef_run).to run_docker_container('overrides-2').with( + repo: 'overrides', + user: 'operator', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'], + env: ['FOO=biz'], + volume: { '/var/log' => {} }, + workdir: '/tmp' + ) + end + end + + context 'testing host overrides' do + it 'creates docker_container[host_override]' do + expect(chef_run).to create_docker_container('host_override').with( + repo: 'alpine', + host: 'tcp://127.0.0.1:2376', + command: ['ls', '-la', '/'] + ) + end + end + + context 'testing logging drivers' do + it 'run_if_missing docker_container[syslogger]' do + expect(chef_run).to run_if_missing_docker_container('syslogger').with( + command: ['nc', '-ll', '-p', '780', '-e', '/bin/cat'], + repo: 'alpine', + tag: '3.1', + log_driver: 'syslog', + log_opts: { 'tag' => 'container-syslogger' } + ) + end + end + + context 'testing kill_after' do + it 'creates directory[/kill_after]' do + expect(chef_run).to create_directory('/kill_after').with( + owner: 'root', + group: 'root' + ) + end + + it 'creates file[/kill_after/loop.sh]' do + expect(chef_run).to create_file('/kill_after/loop.sh') + end + + it 'creates file[/kill_after/Dockerfile]' do + expect(chef_run).to create_file('/kill_after/Dockerfile') + end + + it 'build_if_missing docker_image[kill_after]' do + expect(chef_run).to build_if_missing_docker_image('kill_after').with( + tag: 'latest', + source: '/kill_after', + force: true + ) + end + + it 'run execute[kill_after]' do + expect(chef_run).to run_execute('kill_after').with( + command: 'docker run --name kill_after -d kill_after' + ) + end + + it 'stop docker_container[kill_after]' do + expect(chef_run).to stop_docker_container('kill_after') + end + + it 'run_if_missing docker_container[pid_mode]' do + expect(chef_run).to run_if_missing_docker_container('pid_mode').with( + pid_mode: 'host' + ) + end + + it 'run_if_missing docker_container[ipc_mode]' do + expect(chef_run).to run_if_missing_docker_container('ipc_mode').with( + ipc_mode: 'host' + ) + end + + it 'run_if_missing docker_container[uts_mode]' do + expect(chef_run).to run_if_missing_docker_container('uts_mode').with( + uts_mode: 'host' + ) + end + end + + context 'testing ro_rootfs' do + it 'creates read-only rootfs' do + expect(chef_run).to run_if_missing_docker_container('ro_rootfs').with( + ro_rootfs: true + ) + end + end + + context 'testing health_check options' do + it 'sets health_check options' do + expect(chef_run).to run_docker_container('health_check').with( + repo: 'alpine', + tag: '3.1', + health_check: { + 'Test' => + [ + 'string', + ], + 'Interval' => 0, + 'Timeout' => 0, + 'Retries' => 0, + 'StartPeriod' => 0, + } + ) + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/exec_spec.rb b/chef/cookbooks/docker/spec/docker_test/exec_spec.rb new file mode 100644 index 0000000..b4ae401 --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/exec_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'docker_test::exec' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + it 'pull_if_missing docker_image[busybox]' do + expect(chef_run).to pull_if_missing_docker_image('busybox') + end + + it 'run docker_container[busybox_exec]' do + expect(chef_run).to run_docker_container('busybox_exec').with( + repo: 'busybox', + command: ['sh', '-c', 'trap exit 0 SIGTERM; while :; do sleep 1; done'] + ) + end + + context 'testing run action' do + it 'run docker_exec[touch_it]' do + expect(chef_run).to run_docker_exec('touch_it').with( + container: 'busybox_exec', + command: ['touch', '/tmp/onefile'], + timeout: 120 + ) + end + + it 'creates file[/marker_busybox_exec_onefile]' do + expect(chef_run).to create_file('/marker_busybox_exec_onefile') + end + + it 'run docker_exec[another]' do + expect(chef_run).to run_docker_exec('poke_it').with( + container: 'busybox_exec', + command: ['touch', '/tmp/twofile'] + ) + end + + it 'creates file[/marker_busybox_exec_twofile]' do + expect(chef_run).to create_file('/marker_busybox_exec_twofile') + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/image_prune_spec.rb b/chef/cookbooks/docker/spec/docker_test/image_prune_spec.rb new file mode 100644 index 0000000..e33bdb2 --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/image_prune_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe 'docker_test::image_prune' do + context 'it steps over the provider' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '18.04').converge(described_recipe) } + + context 'testing default action, default properties' do + it 'prunes docker_image[hello-world]' do + expect(chef_run).to prune_docker_image_prune('hello-world').with( + dangling: true + ) + end + + it 'prunes docker_image[hello-world]' do + expect(chef_run).to prune_docker_image_prune('prune-old-images').with( + dangling: true, + prune_until: '1h30m', + with_label: 'com.example.vendor=ACME', + without_label: 'no_prune' + ) + end + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/image_spec.rb b/chef/cookbooks/docker/spec/docker_test/image_spec.rb new file mode 100644 index 0000000..c998d4c --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/image_spec.rb @@ -0,0 +1,271 @@ +require 'spec_helper' + +describe 'docker_test::image' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + before do + stub_command('/usr/bin/test -f /tmp/registry/tls/ca-key.pem').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/server-key.pem').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/server.csr').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/server.pem').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/key.pem').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/client.csr').and_return(true) + stub_command('/usr/bin/test -f /tmp/registry/tls/cert.pem').and_return(true) + stub_command("[ ! -z `docker ps -qaf 'name=registry_service$'` ]").and_return(true) + stub_command("[ ! -z `docker ps -qaf 'name=registry_proxy$'` ]").and_return(true) + stub_command('netstat -plnt | grep ":5000" && netstat -plnt | grep ":5043"').and_return(false) + end + + context 'testing default action, default properties' do + it 'pulls docker_image[hello-world]' do + expect(chef_run).to pull_docker_image('hello-world').with( + api_retries: 3, + destination: nil, + force: false, + nocache: false, + noprune: false, + read_timeout: 120, + repo: 'hello-world', + rm: true, + source: nil, + tag: 'latest', + write_timeout: nil + ) + end + end + + context 'testing non-default name attribute containing a single quote' do + it "pulls docker_image[Tom's container]" do + expect(chef_run).to pull_docker_image("Tom's container").with( + repo: 'tduffield/testcontainerd' + ) + end + end + + context 'testing the :pull action' do + it 'pulls docker_image[busybox]' do + expect(chef_run).to pull_docker_image('busybox') + end + end + + context 'testing using pull_if_missing' do + it 'pull_if_missing docker_image[debian]' do + expect(chef_run).to pull_if_missing_docker_image('debian') + end + end + + context 'testing specifying a tag and read/write timeouts' do + it 'pulls docker_image[alpine]' do + expect(chef_run).to pull_docker_image('alpine').with( + tag: '3.1', + read_timeout: 60, + write_timeout: 60 + ) + end + end + + context 'testing the host property' do + it 'pulls docker_image[alpine-localhost]' do + expect(chef_run).to pull_docker_image('alpine-localhost').with( + repo: 'alpine', + tag: '2.7', + host: 'tcp://127.0.0.1:2376' + ) + end + end + + context 'testing :remove action' do + it 'runs execute[pull vbatts/slackware]' do + expect(chef_run).to run_execute('pull vbatts/slackware').with( + command: 'docker pull vbatts/slackware ; touch /marker_image_slackware', + creates: '/marker_image_slackware' + ) + end + + it 'removes docker_image[vbatts/slackware]' do + expect(chef_run).to remove_docker_image('vbatts/slackware') + end + end + + context 'testing :save action' do + it 'saves docker_image[save hello-world]' do + expect(chef_run).to save_docker_image('save hello-world').with( + repo: 'hello-world', + destination: '/hello-world.tar' + ) + end + end + + context 'testing :load action' do + it 'pulls docker_image[cirros]' do + expect(chef_run).to pull_docker_image('cirros') + end + + it 'saves docker_image[save cirros]' do + expect(chef_run).to save_docker_image('save cirros').with( + destination: '/cirros.tar' + ) + end + + it 'removes docker_image[remove cirros]' do + expect(chef_run).to remove_docker_image('remove cirros').with( + repo: 'cirros' + ) + end + + it 'loads docker_image[load cirros]' do + expect(chef_run).to load_docker_image('load cirros').with( + source: '/cirros.tar' + ) + end + + it 'creates file[/marker_image_image-1]' do + expect(chef_run).to create_file('/marker_load_cirros-1') + end + end + + context 'testing the :build action from Dockerfile' do + it 'creates directory[/usr/local/src/container1]' do + expect(chef_run).to create_directory('/usr/local/src/container1') + end + + it 'creates cookbook_file[/usr/local/src/container1/Dockerfile]' do + expect(chef_run).to create_cookbook_file('/usr/local/src/container1/Dockerfile').with( + source: 'Dockerfile_1' + ) + end + + it 'build docker_image[someara/image-1]' do + expect(chef_run).to build_docker_image('someara/image-1').with( + tag: 'v0.1.0', + source: '/usr/local/src/container1/Dockerfile', + force: true + ) + end + + it 'creates file[/marker_image_image-1]' do + expect(chef_run).to create_file('/marker_image_image-1') + end + end + + context 'testing the :build action from directory' do + it 'creates directory[/usr/local/src/container2]' do + expect(chef_run).to create_directory('/usr/local/src/container2') + end + + it 'creates file[/usr/local/src/container2/foo.txt]' do + expect(chef_run).to create_file('/usr/local/src/container2/foo.txt').with( + content: 'Dockerfile_2 contains ADD for this file' + ) + end + + it 'creates cookbook_file[/usr/local/src/container2/Dockerfile]' do + expect(chef_run).to create_cookbook_file('/usr/local/src/container2/Dockerfile').with( + source: 'Dockerfile_2' + ) + end + + it 'build_if_missing docker_image[someara/image.2]' do + expect(chef_run).to build_if_missing_docker_image('someara/image.2').with( + tag: 'v0.1.0', + source: '/usr/local/src/container2' + ) + end + end + + context 'testing the :build action from a tarball' do + it 'creates cookbook_file[/usr/local/src/image_3.tar]' do + expect(chef_run).to create_cookbook_file('/usr/local/src/image_3.tar').with( + source: 'image_3.tar' + ) + end + + it 'build_if_missing docker_image[image_3]' do + expect(chef_run).to build_if_missing_docker_image('image_3').with( + tag: 'v0.1.0', + source: '/usr/local/src/image_3.tar' + ) + end + end + + context 'testing the :import action' do + it 'imports docker_image[hello-again]' do + expect(chef_run).to import_docker_image('hello-again').with( + tag: 'v0.1.0', + source: '/hello-world.tar' + ) + end + end + + context 'testing images with dots and dashes in the name' do + it 'pulls docker_image[someara/name-w-dashes]' do + expect(chef_run).to pull_docker_image('someara/name-w-dashes') + end + + it 'pulls docker_image[someara/name.w.dots]' do + expect(chef_run).to pull_docker_image('someara/name.w.dots') + end + end + + context 'when setting up a local registry' do + it 'includes the "docker_test::registry" recipe' do + expect(chef_run).to include_recipe('docker_test::registry') + end + end + + context 'testing pushing to a private registry' do + it 'tags docker_tag[private repo tag for name-w-dashes:v1.0.1]' do + expect(chef_run).to tag_docker_tag('private repo tag for name-w-dashes:v1.0.1').with( + target_repo: 'hello-again', + target_tag: 'v0.1.0', + to_repo: 'localhost:5043/someara/name-w-dashes', + to_tag: 'latest' + ) + end + + it 'tags docker_tag[private repo tag for name.w.dots]' do + expect(chef_run).to tag_docker_tag('private repo tag for name.w.dots').with( + target_repo: 'busybox', + target_tag: 'latest', + to_repo: 'localhost:5043/someara/name.w.dots', + to_tag: 'latest' + ) + end + + it 'pushes docker_image[localhost:5043/someara/name-w-dashes]' do + expect(chef_run).to push_docker_image('localhost:5043/someara/name-w-dashes') + end + + it 'creates file[/marker_image_private_name-w-dashes]' do + expect(chef_run).to create_file('/marker_image_private_name-w-dashes') + end + + it 'pushes docker_image[localhost:5043/someara/name.w.dots]' do + expect(chef_run).to push_docker_image('localhost:5043/someara/name.w.dots') + end + + it 'pushes docker_image[localhost:5043/someara/name.w.dots] with tag v0.1.0' do + expect(chef_run).to push_docker_image('localhost:5043/someara/name.w.dots').with( + tag: 'v0.1.0' + ) + end + + it 'login docker_registry[localhost:5043]' do + expect(chef_run).to login_docker_registry('localhost:5043').with( + username: 'testuser', + password: 'testpassword', + email: 'alice@computers.biz' + ) + end + + it 'creates file[/marker_image_private_name.w.dots]' do + expect(chef_run).to create_file('/marker_image_private_name.w.dots') + end + end + + context 'testing pulling from public Dockerhub after being authenticated to a private one' do + it 'pulls docker_image[fedora]' do + expect(chef_run).to pull_docker_image('fedora') + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/installation_package_spec.rb b/chef/cookbooks/docker/spec/docker_test/installation_package_spec.rb new file mode 100644 index 0000000..1d4117e --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/installation_package_spec.rb @@ -0,0 +1,140 @@ +require 'spec_helper' + +describe 'docker_test::installation_package' do + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'ubuntu', + version: '18.04', + step_into: ['docker_installation_package']).converge(described_recipe) + end + + context 'testing default action, default properties' do + it 'installs docker' do + expect(chef_run).to create_docker_installation_package('default').with(version: '18.06.0') + end + end + + # Coverage of all recent docker versions + # To ensure test coverage and backwards compatibility + # With the frequent changes in package naming convention + # List generated from + # https://download.docker.com/linux/ubuntu/dists/#{distro}/stable/binary-amd64/Packages + + context 'version strings for Ubuntu 18.04' do + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'ubuntu', + version: '18.04', + step_into: ['docker_installation_package']).converge(described_recipe) + end + + [ + # Bionic + { docker_version: '18.03.1', expected: '18.03.1~ce~3-0~ubuntu' }, + { docker_version: '18.06.0', expected: '18.06.0~ce~3-0~ubuntu' }, + { docker_version: '18.06.1', expected: '18.06.1~ce~3-0~ubuntu' }, + { docker_version: '18.09.0', expected: '5:18.09.0~3-0~ubuntu-bionic' }, + ].each do |suite| + it 'generates the correct version string ubuntu bionic' do + custom_resource = chef_run.docker_installation_package('default') + actual = custom_resource.version_string(suite[:docker_version]) + expect(actual).to eq(suite[:expected]) + end + end + end + + context 'version strings for Ubuntu 16.04' do + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'ubuntu', + version: '16.04', + step_into: ['docker_installation_package']).converge(described_recipe) + end + + [ + { docker_version: '17.03.0', expected: '17.03.0~ce-0~ubuntu-xenial' }, + { docker_version: '17.03.1', expected: '17.03.1~ce-0~ubuntu-xenial' }, + { docker_version: '17.03.2', expected: '17.03.2~ce-0~ubuntu-xenial' }, + { docker_version: '17.03.3', expected: '17.03.3~ce-0~ubuntu-xenial' }, + { docker_version: '17.06.0', expected: '17.06.0~ce-0~ubuntu' }, + { docker_version: '17.06.1', expected: '17.06.1~ce-0~ubuntu' }, + { docker_version: '17.09.0', expected: '17.09.0~ce-0~ubuntu' }, + { docker_version: '17.09.1', expected: '17.09.1~ce-0~ubuntu' }, + { docker_version: '17.12.0', expected: '17.12.0~ce-0~ubuntu' }, + { docker_version: '17.12.1', expected: '17.12.1~ce-0~ubuntu' }, + { docker_version: '18.03.0', expected: '18.03.0~ce-0~ubuntu' }, + { docker_version: '18.03.1', expected: '18.03.1~ce-0~ubuntu' }, + { docker_version: '18.06.0', expected: '18.06.0~ce~3-0~ubuntu' }, + { docker_version: '18.06.1', expected: '18.06.1~ce~3-0~ubuntu' }, + { docker_version: '18.09.0', expected: '5:18.09.0~3-0~ubuntu-xenial' }, + ].each do |suite| + it 'generates the correct version string ubuntu xenial' do + custom_resource = chef_run.docker_installation_package('default') + actual = custom_resource.version_string(suite[:docker_version]) + expect(actual).to eq(suite[:expected]) + end + end + end + + context 'version strings for Debian 9.5' do + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'debian', + version: '9.5', + step_into: ['docker_installation_package']).converge(described_recipe) + end + [ + { docker_version: '17.03.0', expected: '17.03.0~ce-0~debian-stretch' }, + { docker_version: '17.03.1', expected: '17.03.1~ce-0~debian-stretch' }, + { docker_version: '17.03.2', expected: '17.03.2~ce-0~debian-stretch' }, + { docker_version: '17.03.3', expected: '17.03.3~ce-0~debian-stretch' }, + { docker_version: '17.06.0', expected: '17.06.0~ce-0~debian' }, + { docker_version: '17.06.1', expected: '17.06.1~ce-0~debian' }, + { docker_version: '17.09.0', expected: '17.09.0~ce-0~debian' }, + { docker_version: '17.09.1', expected: '17.09.1~ce-0~debian' }, + { docker_version: '17.12.0', expected: '17.12.0~ce-0~debian' }, + { docker_version: '17.12.1', expected: '17.12.1~ce-0~debian' }, + { docker_version: '18.03.0', expected: '18.03.0~ce-0~debian' }, + { docker_version: '18.03.1', expected: '18.03.1~ce-0~debian' }, + { docker_version: '18.06.0', expected: '18.06.0~ce~3-0~debian' }, + { docker_version: '18.06.1', expected: '18.06.1~ce~3-0~debian' }, + { docker_version: '18.09.0', expected: '5:18.09.0~3-0~debian-stretch' }, + ].each do |suite| + + it 'generates the correct version string debian stretch' do + custom_resource = chef_run.docker_installation_package('default') + actual = custom_resource.version_string(suite[:docker_version]) + expect(actual).to eq(suite[:expected]) + end + end + end + + context 'version strings for Centos 7' do + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'centos', + version: '7', + step_into: ['docker_installation_package']).converge(described_recipe) + end + # https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ + [ + { docker_version: '17.03.0', expected: '17.03.0.ce-1.el7.centos' }, + { docker_version: '17.03.1', expected: '17.03.1.ce-1.el7.centos' }, + { docker_version: '17.03.2', expected: '17.03.2.ce-1.el7.centos' }, + { docker_version: '17.03.3', expected: '17.03.3.ce-1.el7' }, + { docker_version: '17.06.0', expected: '17.06.0.ce-1.el7.centos' }, + { docker_version: '17.06.1', expected: '17.06.1.ce-1.el7.centos' }, + { docker_version: '17.09.0', expected: '17.09.0.ce-1.el7.centos' }, + { docker_version: '17.09.1', expected: '17.09.1.ce-1.el7.centos' }, + { docker_version: '17.12.0', expected: '17.12.0.ce-1.el7.centos' }, + { docker_version: '17.12.1', expected: '17.12.1.ce-1.el7.centos' }, + { docker_version: '18.03.0', expected: '18.03.0.ce-1.el7.centos' }, + { docker_version: '18.03.1', expected: '18.03.1.ce-1.el7.centos' }, + { docker_version: '18.06.0', expected: '18.06.0.ce-3.el7' }, + { docker_version: '18.06.1', expected: '18.06.1.ce-3.el7' }, + { docker_version: '18.09.0', expected: '18.09.0-3.el7' }, + ].each do |suite| + + it 'generates the correct version string centos 7' do + custom_resource = chef_run.docker_installation_package('default') + actual = custom_resource.version_string(suite[:docker_version]) + expect(actual).to eq(suite[:expected]) + end + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/network_spec.rb b/chef/cookbooks/docker/spec/docker_test/network_spec.rb new file mode 100644 index 0000000..f8f11cf --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/network_spec.rb @@ -0,0 +1,174 @@ +require 'spec_helper' + +describe 'docker_test::network' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + context 'creates a network with unicode name' do + it 'creates docker_network_seseme_straße' do + expect(chef_run).to create_docker_network('seseme_straße') + end + end + + context 'creates a network with defaults' do + it 'creates docker_network_a' do + expect(chef_run).to create_docker_network('network_a') + end + + it 'creates echo-base-network_a' do + expect(chef_run).to run_docker_container('echo-base-network_a') + end + + it 'creates echo-station-network_a' do + expect(chef_run).to run_docker_container('echo-station-network_a') + end + end + + context 'when testing network deletion' do + it 'creates network_b with the CLI' do + expect(chef_run).to run_execute('create network_b').with( + command: 'docker network create network_b' + ) + end + + it 'creates /marker_delete_network_b' do + expect(chef_run).to create_file('/marker_delete_network_b') + end + + it 'deletes docker_network[network_b]' do + expect(chef_run).to delete_docker_network('network_b') + end + end + + context 'creates a network with subnet and gateway' do + it 'creates docker_network_c' do + expect(chef_run).to create_docker_network('network_c').with( + subnet: '192.168.88.0/24', + gateway: '192.168.88.1' + ) + end + + it 'creates echo-base-network_c' do + expect(chef_run).to run_docker_container('echo-base-network_c') + end + + it 'creates echo-station-network_c' do + expect(chef_run).to run_docker_container('echo-station-network_c') + end + end + + context 'creates a network with aux_address' do + it 'creates docker_network_d' do + expect(chef_run).to create_docker_network('network_d').with( + subnet: '192.168.89.0/24', + gateway: '192.168.89.1', + aux_address: ['a=192.168.89.2', 'b=192.168.89.3'] + ) + end + + it 'creates echo-base-network_d' do + expect(chef_run).to run_docker_container('echo-base-network_d') + end + + it 'creates echo-station-network_d' do + expect(chef_run).to run_docker_container('echo-station-network_d') + end + end + + context 'creates a network with overlay driver' do + it 'creates network_e' do + expect(chef_run).to create_docker_network('network_e').with( + driver: 'overlay' + ) + end + end + + context 'creates a network with an ip-range' do + it 'creates docker_network_f' do + expect(chef_run).to create_docker_network('network_f').with( + driver: 'bridge', + subnet: '172.28.0.0/16', + gateway: '172.28.5.254', + ip_range: '172.28.5.0/24' + ) + end + + it 'creates echo-base-network_f' do + expect(chef_run).to run_docker_container('echo-base-network_f') + end + + it 'creates echo-station-network_f' do + expect(chef_run).to run_docker_container('echo-station-network_f') + end + end + + context 'create an overlay network with multiple subnets' do + it 'creates docker_network_g' do + expect(chef_run).to create_docker_network('network_g').with( + driver: 'overlay', + subnet: ['192.168.0.0/16', '192.170.0.0/16'], + gateway: ['192.168.0.100', '192.170.0.100'], + ip_range: '192.168.1.0/24', + aux_address: ['a=192.168.1.5', 'b=192.168.1.6', 'a=192.170.1.5', 'b=192.170.1.6'] + ) + end + + it 'creates echo-base-network_g' do + expect(chef_run).to run_docker_container('echo-base-network_g') + end + + it 'creates echo-station-network_g' do + expect(chef_run).to run_docker_container('echo-station-network_g') + end + end + + context 'connect and disconnect a container' do + it 'creates docker_network_h1' do + expect(chef_run).to create_docker_network('network_h1') + end + + it 'creates docker_network_h2' do + expect(chef_run).to create_docker_network('network_h2') + end + + it 'creates container1-network_h' do + expect(chef_run).to run_docker_container('container1-network_h') + end + + it 'creates /marker/network_h' do + expect(chef_run).to create_file('/marker_network_h') + end + + it 'connects container1-network_h with network_h2' do + expect(chef_run).to connect_docker_network('network_h2 connector').with( + container: 'container1-network_h' + ) + end + + it 'disconnects container1-network_h from network_h1' do + expect(chef_run).to disconnect_docker_network('network_h1 disconnector').with( + container: 'container1-network_h' + ) + end + end + + context 'ipv6 network' do + it 'creates docker_network_ipv6' do + expect(chef_run).to create_docker_network('network_ipv6').with( + enable_ipv6: true, + subnet: 'fd00:dead:beef::/48' + ) + end + + it 'creates docker_network_ipv4' do + expect(chef_run).to create_docker_network('network_ipv4') + end + end + + context 'internal network' do + it 'creates docker_network_internal' do + expect(chef_run).to create_docker_network('network_internal').with( + internal: true + ) + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/plugin_spec.rb b/chef/cookbooks/docker/spec/docker_test/plugin_spec.rb new file mode 100644 index 0000000..4194706 --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/plugin_spec.rb @@ -0,0 +1,118 @@ +require 'spec_helper' + +describe 'docker_test::plugin' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + let(:sshfs_caps) do + [ + { + 'Name' => 'network', + 'Value' => ['host'], + }, + { + 'Name' => 'mount', + 'Value' => ['/var/lib/docker/plugins/'], + }, + { + 'Name' => 'mount', + 'Value' => [''], + }, + { + 'Name' => 'device', + 'Value' => ['/dev/fuse'], + }, + { + 'Name' => 'capabilities', + 'Value' => ['CAP_SYS_ADMIN'], + }, + ] + end + + context 'testing default action, default properties, but with privilege grant' do + it 'installs vieux/sshfs' do + expect(chef_run).to install_docker_plugin('vieux/sshfs').with( + api_retries: 3, + grant_privileges: sshfs_caps, + options: {}, + remote_tag: 'latest' + ) + end + end + + context 'reconfigure existing plugin' do + it 'enables debug on vieux/sshfs' do + expect(chef_run).to update_docker_plugin('configure vieux/sshfs').with( + api_retries: 3, + grant_privileges: [], + options: { + 'DEBUG' => '1', + }, + local_alias: 'vieux/sshfs', + remote_tag: 'latest' + ) + end + end + + context 'testing the remove action' do + it 'removes vieux/sshfs' do + expect(chef_run).to remove_docker_plugin('remove vieux/sshfs').with( + api_retries: 3, + grant_privileges: [], + options: {}, + local_alias: 'vieux/sshfs', + remote_tag: 'latest' + ) + end + end + + context 'testing configure and install at the same time' do + it 'installs wetopi/rbd' do + expect(chef_run).to install_docker_plugin('rbd').with( + remote: 'wetopi/rbd', + remote_tag: '1.0.1', + grant_privileges: true, + options: { + 'LOG_LEVEL' => '4', + } + ) + end + + it 'removes wetopi/rbd again' do + expect(chef_run).to remove_docker_plugin('remove rbd').with( + local_alias: 'rbd' + ) + end + end + + context 'install is idempotent' do + it 'installs vieux/sshfs two times' do + expect(chef_run).to install_docker_plugin('sshfs 2.1').with( + remote: 'vieux/sshfs', + remote_tag: 'latest', + local_alias: 'sshfs', + grant_privileges: true + ) + + expect(chef_run).to install_docker_plugin('sshfs 2.2').with( + remote: 'vieux/sshfs', + remote_tag: 'latest', + local_alias: 'sshfs', + grant_privileges: true + ) + end + end + + context 'test :enable / :disable action' do + it 'enables sshfs' do + expect(chef_run).to enable_docker_plugin('enable sshfs').with( + local_alias: 'sshfs' + ) + end + + it 'disables sshfs' do + expect(chef_run).to disable_docker_plugin('disable sshfs').with( + local_alias: 'sshfs' + ) + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/registry_spec.rb b/chef/cookbooks/docker/spec/docker_test/registry_spec.rb new file mode 100644 index 0000000..a78f22c --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/registry_spec.rb @@ -0,0 +1,125 @@ +require 'spec_helper' + +describe 'docker_test::registry' do + cached(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe) } + + before do + stub_command('/usr/bin/test -f /tmp/registry/tls/ca.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/ca-key.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/key.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/cert.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/server-key.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/server.pem').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/client.csr').and_return(false) + stub_command('/usr/bin/test -f /tmp/registry/tls/server.csr').and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=registry_service$'` ]").and_return(false) + stub_command("[ ! -z `docker ps -qaf 'name=registry_proxy$'` ]").and_return(false) + stub_command('netstat -plnt | grep ":5000" && netstat -plnt | grep ":5043"').and_return(false) + end + + context 'when compiling the recipe' do + it 'creates directory[/tmp/registry/tls]' do + expect(chef_run).to create_directory('/tmp/registry/tls').with( + recursive: true + ) + end + + it 'runs bash[creating private key for docker server]' do + expect(chef_run).to run_bash('creating private key for docker server') + end + + it 'runs bash[generating CA private and public key]' do + expect(chef_run).to run_bash('generating CA private and public key') + end + + it 'runs bash[generating certificate request for server]' do + expect(chef_run).to run_bash('generating certificate request for server') + end + + it 'creates file[/tmp/registry/tls/server-extfile.cnf]' do + expect(chef_run).to create_file('/tmp/registry/tls/server-extfile.cnf') + end + + it 'runs bash[signing request for server]' do + expect(chef_run).to run_bash('signing request for server') + end + + it 'runs bash[creating private key for docker client]' do + expect(chef_run).to run_bash('creating private key for docker client') + end + + it 'runs bash[generating certificate request for client]' do + expect(chef_run).to run_bash('generating certificate request for client') + end + + it 'creates file[/tmp/registry/tls/client-extfile.cnf]' do + expect(chef_run).to create_file('/tmp/registry/tls/client-extfile.cnf') + end + + it 'runs bash[signing request for client]' do + expect(chef_run).to run_bash('signing request for client') + end + + it 'pulls docker_image[nginx]' do + expect(chef_run).to pull_docker_image('nginx').with( + tag: '1.9' + ) + end + + it 'pulls docker_image[registry]' do + expect(chef_run).to pull_docker_image('registry').with( + tag: '2.6.1' + ) + end + + it 'creates directory[/tmp/registry/auth]' do + expect(chef_run).to create_directory('/tmp/registry/auth').with( + recursive: true, + owner: 'root', + mode: '0755' + ) + end + + it 'creates template[/tmp/registry/auth/registry.conf]' do + expect(chef_run).to create_template('/tmp/registry/auth/registry.conf').with( + source: 'registry/auth/registry.conf.erb', + owner: 'root', + mode: '0755' + ) + end + + it 'runs execute[copy server cert for registry]' do + expect(chef_run).to run_execute('copy server cert for registry').with( + command: 'cp /tmp/registry/tls/server.pem /tmp/registry/auth/server.crt', + creates: '/tmp/registry/auth/server.crt' + ) + end + + it 'runs execute[copy server key for registry]' do + expect(chef_run).to run_execute('copy server key for registry').with( + command: 'cp /tmp/registry/tls/server-key.pem /tmp/registry/auth/server.key', + creates: '/tmp/registry/auth/server.key' + ) + end + + it 'creates template[/tmp/registry/auth/registry.password]' do + expect(chef_run).to create_template('/tmp/registry/auth/registry.password').with( + source: 'registry/auth/registry.password.erb', + owner: 'root', + mode: '0755' + ) + end + + it 'runs bash[start docker registry]' do + expect(chef_run).to run_bash('start docker registry') + end + + it 'runs bash[start docker registry proxy]' do + expect(chef_run).to run_bash('start docker registry proxy') + end + + it 'runs bash[wait for docker registry and proxy]' do + expect(chef_run).to run_bash('wait for docker registry and proxy') + end + end +end diff --git a/chef/cookbooks/docker/spec/docker_test/service_spec.rb b/chef/cookbooks/docker/spec/docker_test/service_spec.rb new file mode 100644 index 0000000..28a9abb --- /dev/null +++ b/chef/cookbooks/docker/spec/docker_test/service_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' +require_relative '../../libraries/helpers_service' + +describe 'docker_test::service' do + before do + allow_any_instance_of(DockerCookbook::DockerHelpers::Service).to receive(:installed_docker_version).and_return('18.06.0') + end + + cached(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'ubuntu', + version: '16.04', + step_into: %w(helpers_service docker_service docker_service_base docker_service_manager docker_service_manager_systemd)).converge(described_recipe) + end + + # If you have to change this file you most likely updated a default service option + # Please note that it will require a docker service restart + # Which is consumer impacting + expected = < '192.168.0.0/24')) +# end +# +# it 'should have aux address' do +# expect(subject).to include(include('AuxiliaryAddresses' => { 'foo' => '192.168.0.34', 'bar' => '192.168.0.124' })) +# end +# +# it 'should have gateways' do +# expect(subject).to include(include('Gateway' => '192.168.0.34')) +# end +# +# it 'should have ip range' do +# expect(subject).to include(include('IPRange' => '192.168.0.31/28')) +# end +# end +# end diff --git a/chef/cookbooks/docker/spec/libraries/container_networks_spec.rb b/chef/cookbooks/docker/spec/libraries/container_networks_spec.rb new file mode 100644 index 0000000..c08d39d --- /dev/null +++ b/chef/cookbooks/docker/spec/libraries/container_networks_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' +require 'docker' +require_relative '../../libraries/docker_base' +require_relative '../../libraries/docker_container' + +describe DockerCookbook::DockerContainer do + let(:resource) { DockerCookbook::DockerContainer.new('hello_world') } + + it 'has a default action of [:run]' do + expect(resource.action).to eql([:run]) + end + + describe 'gets ip_address_from_container_networks' do + let(:options) { { 'id' => rand(10_000).to_s } } + subject do + Docker::Container.send(:new, Docker.connection, options) + end + # https://docs.docker.com/engine/api/version-history/#v121-api-changes + context 'when docker API < 1.21' do + let(:ip_address) { '10.0.0.1' } + let(:options) do + { + 'id' => rand(10_000).to_s, + 'IPAddress' => ip_address, + } + end + it 'gets ip_address as nil' do + actual = resource.ip_address_from_container_networks(subject) + expect { resource.ip_address_from_container_networks(subject) }.not_to raise_error + expect(actual).to eq(nil) + end + end + context 'when docker API > 1.21' do + let(:ip_address) { '10.0.0.1' } + let(:options) do + { + 'id' => rand(10_000).to_s, + 'NetworkSettings' => { + 'Networks' => { + 'bridge' => { + 'IPAMConfig' => { + 'IPv4Address' => ip_address, + }, + }, + }, + }, + } + end + it 'gets ip_address' do + actual = resource.ip_address_from_container_networks(subject) + expect(actual).to eq(ip_address) + end + end + end +end diff --git a/chef/cookbooks/docker/spec/libraries/container_spec.rb b/chef/cookbooks/docker/spec/libraries/container_spec.rb new file mode 100644 index 0000000..5dfe010 --- /dev/null +++ b/chef/cookbooks/docker/spec/libraries/container_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' +require 'chef' +require 'excon' + +require_relative '../../libraries/docker_base' +require_relative '../../libraries/docker_container' + +describe 'docker_container' do + step_into :docker_container + platform 'ubuntu' + + # Info returned by docker api + # https://docs.docker.com/engine/api/v1.39/#tag/Container + let(:container) do + { + 'Id' => '123456789', + 'IPAddress' => '10.0.0.1', + 'Image' => 'ubuntu:bionic', + 'Names' => ['/hello_world'], + 'Config' => { 'Labels' => {} }, + 'HostConfig' => { 'RestartPolicy' => { 'Name' => 'unless-stopped', + 'MaximumRetryCount' => 1 }, + 'Binds' => [], + 'ReadonlyRootfs' => false }, + 'State' => 'not running', + 'Warnings' => [], + }.to_json + end + # https://docs.docker.com/engine/api/v1.39/#tag/Image + let(:image) do + { 'Id' => 'bf119e2', + 'Repository' => 'ubuntu', 'Tag' => 'bionic', + 'Created' => 1_364_102_658, 'Size' => 24_653, + 'VirtualSize' => 180_116_135, + 'Config' => { 'Labels' => {} } }.to_json + end + # https://docs.docker.com/engine/api/v1.39/#operation/SystemInfo + let(:info) do + { 'Labels' => {} }.to_json + end + # https://docs.docker.com/engine/api/v1.39/#operation/ContainerCreate + let(:create) do + { + 'Id' => 'e90e34656806', + 'Warnings' => [], + }.to_json + end + + before do + # Ensure docker api calls are mocked + # It is low level much easier to do in Excon + # Plus, the low level mock allows testing this cookbook + # for multiple docker apis and docker-api gems + # https://github.com/excon/excon#stubs + Excon.defaults[:mock] = true + Excon.stub({ method: :get, path: '/v1.16/containers/hello_world/json' }, body: container, status: 200) + Excon.stub({ method: :get, path: '/v1.16/images/ubuntu:bionic/json' }, body: image, status: 200) + Excon.stub({ method: :get, path: '/v1.16/info' }, body: info, status: 200) + Excon.stub({ method: :delete, path: '/v1.16/containers/123456789' }, body: '', status: 200) + Excon.stub({ method: :post, path: '/v1.16/containers/create' }, body: create, status: 200) + Excon.stub({ method: :get, path: '/v1.16/containers/123456789/start' }, body: '', status: 200) + end + + context 'creates a docker container with default options' do + recipe do + docker_container 'hello_world' do + tag 'ubuntu:latest' + action :create + end + end + + it { + expect { chef_run }.to_not raise_error + expect(chef_run).to create_docker_container('hello_world').with( + tag: 'ubuntu:latest', + create_options: { 'name' => 'hello_world', 'Image' => 'hello_world:ubuntu:latest', 'Labels' => {}, 'Cmd' => nil, 'AttachStderr' => false, 'AttachStdin' => false, 'AttachStdout' => false, 'Domainname' => '', 'Entrypoint' => nil, 'Env' => [], 'ExposedPorts' => {}, 'Hostname' => nil, 'MacAddress' => nil, 'NetworkDisabled' => false, 'OpenStdin' => false, 'StdinOnce' => false, 'Tty' => false, 'User' => '', 'Volumes' => {}, 'WorkingDir' => '', 'HostConfig' => { 'Binds' => nil, 'CapAdd' => nil, 'CapDrop' => nil, 'CgroupParent' => '', 'CpuShares' => 0, 'CpusetCpus' => '', 'Devices' => [], 'Dns' => [], 'DnsSearch' => [], 'ExtraHosts' => nil, 'IpcMode' => '', 'Init' => nil, 'KernelMemory' => 0, 'Links' => nil, 'LogConfig' => nil, 'Memory' => 0, 'MemorySwap' => 0, 'MemorySwappiness' => 0, 'MemoryReservation' => 0, 'NetworkMode' => 'bridge', 'OomKillDisable' => false, 'OomScoreAdj' => -500, 'Privileged' => false, 'PidMode' => '', 'PortBindings' => {}, 'PublishAllPorts' => false, 'RestartPolicy' => { 'Name' => nil, 'MaximumRetryCount' => 0 }, 'ReadonlyRootfs' => false, 'Runtime' => 'runc', 'SecurityOpt' => nil, 'Sysctls' => {}, 'Ulimits' => nil, 'UsernsMode' => '', 'UTSMode' => '', 'VolumesFrom' => nil, 'VolumeDriver' => nil }, 'NetworkingConfig' => { 'EndpointsConfig' => { 'bridge' => { 'IPAMConfig' => { 'IPv4Address' => nil }, 'Aliases' => [] } } } } + ) + } + end + + context 'creates a docker container with healthcheck options' do + recipe do + docker_container 'hello_world' do + tag 'ubuntu:latest' + health_check( + 'Test' => + [ + 'string', + ], + 'Interval' => 0, + 'Timeout' => 0, + 'Retries' => 0, + 'StartPeriod' => 0 + ) + action :create + end + end + + it { + expect { chef_run }.to_not raise_error + expect(chef_run).to create_docker_container('hello_world').with( + tag: 'ubuntu:latest', + create_options: { 'name' => 'hello_world', 'Image' => 'hello_world:ubuntu:latest', 'Labels' => {}, 'Cmd' => nil, 'AttachStderr' => false, 'AttachStdin' => false, 'AttachStdout' => false, 'Domainname' => '', 'Entrypoint' => nil, 'Env' => [], 'ExposedPorts' => {}, 'Hostname' => nil, 'MacAddress' => nil, 'NetworkDisabled' => false, 'OpenStdin' => false, 'StdinOnce' => false, 'Tty' => false, 'User' => '', 'Volumes' => {}, 'WorkingDir' => '', 'HostConfig' => { 'Binds' => nil, 'CapAdd' => nil, 'CapDrop' => nil, 'CgroupParent' => '', 'CpuShares' => 0, 'CpusetCpus' => '', 'Devices' => [], 'Dns' => [], 'DnsSearch' => [], 'ExtraHosts' => nil, 'IpcMode' => '', 'Init' => nil, 'KernelMemory' => 0, 'Links' => nil, 'LogConfig' => nil, 'Memory' => 0, 'MemorySwap' => 0, 'MemorySwappiness' => 0, 'MemoryReservation' => 0, 'NetworkMode' => 'bridge', 'OomKillDisable' => false, 'OomScoreAdj' => -500, 'Privileged' => false, 'PidMode' => '', 'PortBindings' => {}, 'PublishAllPorts' => false, 'RestartPolicy' => { 'Name' => nil, 'MaximumRetryCount' => 0 }, 'ReadonlyRootfs' => false, 'Runtime' => 'runc', 'SecurityOpt' => nil, 'Sysctls' => {}, 'Ulimits' => nil, 'UsernsMode' => '', 'UTSMode' => '', 'VolumesFrom' => nil, 'VolumeDriver' => nil }, 'NetworkingConfig' => { 'EndpointsConfig' => { 'bridge' => { 'IPAMConfig' => { 'IPv4Address' => nil }, 'Aliases' => [] } } }, 'Healthcheck' => { 'Test' => ['string'], 'Interval' => 0, 'Timeout' => 0, 'Retries' => 0, 'StartPeriod' => 0 } } + ) + } + end + + context 'creates a docker container with default options for windows' do + platform 'windows' + recipe do + docker_container 'hello_world' do + tag 'ubuntu:latest' + action :create + end + end + + it { + expect { chef_run }.to_not raise_error + expect(chef_run).to create_docker_container('hello_world').with( + tag: 'ubuntu:latest', + # Should be missing 'MemorySwappiness' + create_options: { 'name' => 'hello_world', 'Image' => 'hello_world:ubuntu:latest', 'Labels' => {}, 'Cmd' => nil, 'AttachStderr' => false, 'AttachStdin' => false, 'AttachStdout' => false, 'Domainname' => '', 'Entrypoint' => nil, 'Env' => [], 'ExposedPorts' => {}, 'Hostname' => nil, 'MacAddress' => nil, 'NetworkDisabled' => false, 'OpenStdin' => false, 'StdinOnce' => false, 'Tty' => false, 'User' => '', 'Volumes' => {}, 'WorkingDir' => '', 'HostConfig' => { 'Binds' => nil, 'CapAdd' => nil, 'CapDrop' => nil, 'CgroupParent' => '', 'CpuShares' => 0, 'CpusetCpus' => '', 'Devices' => [], 'Dns' => [], 'DnsSearch' => [], 'ExtraHosts' => nil, 'IpcMode' => '', 'Init' => nil, 'KernelMemory' => 0, 'Links' => nil, 'LogConfig' => nil, 'Memory' => 0, 'MemorySwap' => 0, 'MemoryReservation' => 0, 'NetworkMode' => 'bridge', 'OomKillDisable' => false, 'OomScoreAdj' => -500, 'Privileged' => false, 'PidMode' => '', 'PortBindings' => {}, 'PublishAllPorts' => false, 'RestartPolicy' => { 'Name' => nil, 'MaximumRetryCount' => 0 }, 'ReadonlyRootfs' => false, 'Runtime' => 'runc', 'SecurityOpt' => nil, 'Sysctls' => {}, 'Ulimits' => nil, 'UsernsMode' => '', 'UTSMode' => '', 'VolumesFrom' => nil, 'VolumeDriver' => nil }, 'NetworkingConfig' => { 'EndpointsConfig' => { 'bridge' => { 'IPAMConfig' => { 'IPv4Address' => nil }, 'Aliases' => [] } } } } + ) + } + end +end diff --git a/chef/cookbooks/docker/spec/libraries/image_prune_spec.rb b/chef/cookbooks/docker/spec/libraries/image_prune_spec.rb new file mode 100644 index 0000000..f012689 --- /dev/null +++ b/chef/cookbooks/docker/spec/libraries/image_prune_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' +require_relative '../../libraries/docker_base' +require_relative '../../libraries/docker_image_prune' + +describe DockerCookbook::DockerImagePrune do + let(:resource) { DockerCookbook::DockerImagePrune.new('rspec') } + + it 'has a default action of [:prune]' do + expect(resource.action).to eql([:prune]) + end + + it 'generates filter json' do + # Arrange + expected = '{"filters":["dangling=true","until=1h30m","label=com.example.vendor=ACME","label!=no_prune"]}' + resource.dangling = true + resource.prune_until = '1h30m' + resource.with_label = 'com.example.vendor=ACME' + resource.without_label = 'no_prune' + resource.action :prune + + # Act + actual = resource.generate_json(resource) + + # Assert + expect(actual).to eq(expected) + end +end diff --git a/chef/cookbooks/docker/spec/libraries/registry_spec.rb b/chef/cookbooks/docker/spec/libraries/registry_spec.rb new file mode 100644 index 0000000..bc292ad --- /dev/null +++ b/chef/cookbooks/docker/spec/libraries/registry_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +require_relative '../../libraries/docker_base' +require_relative '../../libraries/docker_registry' + +describe 'docker_registry' do + step_into :docker_registry + platform 'ubuntu' + + # Info returned by docker api + # https://docs.docker.com/engine/api/v1.39/#section/Authentication + let(:auth) do + { + 'identitytoken' => '9cbafc023786cd7...', + }.to_json + end + + before do + # Ensure docker api calls are mocked + # It is low level much easier to do in Excon + # Plus, the low level mock allows testing this cookbook + # for multiple docker apis and docker-api gems + # https://github.com/excon/excon#stubs + Excon.defaults[:mock] = true + Excon.stub({ method: :post, path: '/v1.16/auth' }, body: auth, status: 200) + end + + context 'logs into a docker registry with default options' do + recipe do + docker_registry 'chefspec_custom_registry' do + email 'chefspec_email' + password 'chefspec_password' + username 'chefspec_username' + end + end + it { + expect { chef_run }.to_not raise_error + expect(chef_run).to login_docker_registry('chefspec_custom_registry').with( + email: 'chefspec_email', + password: 'chefspec_password', + username: 'chefspec_username', + host: nil + ) + } + end + + context 'logs into a docker registry with host' do + recipe do + docker_registry 'chefspec_custom_registry' do + email 'chefspec_email' + password 'chefspec_password' + username 'chefspec_username' + host 'chefspec_host' + end + end + it { + expect { chef_run }.to_not raise_error + expect(chef_run).to login_docker_registry('chefspec_custom_registry').with( + email: 'chefspec_email', + password: 'chefspec_password', + username: 'chefspec_username', + host: 'chefspec_host' + ) + } + end + + context 'logs into a docker registry with host environment variable' do + recipe do + docker_registry 'chefspec_custom_registry' do + email 'chefspec_email' + password 'chefspec_password' + username 'chefspec_username' + end + end + it { + # Set the environment variable + stub_const 'ENV', ENV.to_h.merge('DOCKER_HOST' => 'chefspec_host_environment_variable') + + expect { chef_run }.to_not raise_error + expect(chef_run).to login_docker_registry('chefspec_custom_registry').with( + email: 'chefspec_email', + password: 'chefspec_password', + username: 'chefspec_username', + host: 'chefspec_host_environment_variable' + ) + } + end +end diff --git a/chef/cookbooks/docker/spec/spec_helper.rb b/chef/cookbooks/docker/spec/spec_helper.rb new file mode 100644 index 0000000..cd26510 --- /dev/null +++ b/chef/cookbooks/docker/spec/spec_helper.rb @@ -0,0 +1,21 @@ +require 'chefspec' +require 'chefspec/berkshelf' + +class RSpecHelper + class< export http_proxy="<%= @config.http_proxy %>" diff --git a/chef/cookbooks/docker/templates/default/sysconfig/docker.erb b/chef/cookbooks/docker/templates/default/sysconfig/docker.erb index b132240..c178495 100755 --- a/chef/cookbooks/docker/templates/default/sysconfig/docker.erb +++ b/chef/cookbooks/docker/templates/default/sysconfig/docker.erb @@ -1,10 +1,4 @@ # /etc/sysconfig/docker -# -# Other arguments to pass to the docker daemon process -# These will be parsed by the sysv initscript and appended -# to the arguments list passed to docker - -other_args="<%= @docker_daemon_opts %>" # If you need Docker to use an HTTP proxy, it can also be specified here. <% if @config.http_proxy %> diff --git a/chef/cookbooks/docker/templates/default/systemd/docker.service-override.erb b/chef/cookbooks/docker/templates/default/systemd/docker.service-override.erb index 8c0f83e..6a3f8e1 100644 --- a/chef/cookbooks/docker/templates/default/systemd/docker.service-override.erb +++ b/chef/cookbooks/docker/templates/default/systemd/docker.service-override.erb @@ -1,7 +1,13 @@ [Unit] Description=Docker Application Container Engine -Documentation=http://docs.docker.com -After=network.target +Documentation=https://docs.docker.com +<% if @docker_socket.nil? %> +After=network-online.target firewalld.service +<% else %> +After=network-online.target <%= @docker_name %>.socket firewalld.service +Requires=<%= @docker_name %>.socket +<% end %> +Wants=network-online.target [Service] Type=notify @@ -17,6 +23,9 @@ Environment="NO_PROXY=<%= @config.no_proxy %>" <% if @config.tmpdir %> Environment="TMPDIR=<%= @config.tmpdir %>" <% end %> +<% @env_vars.each do |key, val| %> +Environment="<%= key %>=<%= val %>" +<% end unless @env_vars.nil? %> <% if @config.ipv4_forward %> ExecStartPre=/sbin/sysctl -w net.ipv4.ip_forward=1 <% end %> @@ -25,11 +34,20 @@ ExecStartPre=/sbin/sysctl -w net.ipv6.conf.all.forwarding=1 <% end %> ExecStart=<%= @docker_daemon_cmd %> ExecStartPost=<%= @docker_wait_ready %> -Restart=always -MountFlags=<%= @docker_mount_flags %> +ExecReload=/bin/kill -s HUP $MAINPID +<% if @config.mount_flags %> +MountFlags=<%= @config.mount_flags %> +<% end %> LimitNOFILE=1048576 -LimitNPROC=1048576 +LimitNPROC=infinity LimitCORE=infinity +TasksMax=infinity +TimeoutStartSec=0 +Delegate=yes +KillMode=process +Restart=always +StartLimitBurst=3 +StartLimitInterval=60s <%= @systemd_args %> [Install] diff --git a/chef/cookbooks/docker/templates/default/systemd/docker.service.erb b/chef/cookbooks/docker/templates/default/systemd/docker.service.erb index 5c924d8..d3e5180 100644 --- a/chef/cookbooks/docker/templates/default/systemd/docker.service.erb +++ b/chef/cookbooks/docker/templates/default/systemd/docker.service.erb @@ -1,18 +1,38 @@ [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com -After=network.target <%= @docker_name %>.socket +<% if @docker_socket.nil? %> +After=network-online.target firewalld.service +<% else %> +After=network-online.target <%= @docker_name %>.socket firewalld.service Requires=<%= @docker_name %>.socket +<% end %> +Wants=network-online.target [Service] Type=notify -ExecStart=/usr/bin/docker daemon -H fd:// -MountFlags=<%= @docker_mount_flags %> +# the default is not to use systemd for cgroups because the delegate issues still +# exists and systemd currently does not support the cgroup feature set required +# for containers run by docker +ExecStart=/usr/bin/dockerd -H fd:// +ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=1048576 -LimitNPROC=1048576 +# Having non-zero Limit*s causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +LimitNPROC=infinity LimitCORE=infinity -TasksMax=1048576 +# Uncomment TasksMax if your systemd version supports it. +# Only systemd 226 and above support this version. +TasksMax=infinity TimeoutStartSec=0 +# set delegate yes so that systemd does not reset the cgroups of docker containers +Delegate=yes +# kill only the docker process, not all processes in the cgroup +KillMode=process +# restart the docker process if it exits prematurely +Restart=on-failure +StartLimitBurst=3 +StartLimitInterval=60s [Install] WantedBy=multi-user.target diff --git a/chef/cookbooks/docker/templates/default/systemd/docker.socket-override.erb b/chef/cookbooks/docker/templates/default/systemd/docker.socket-override.erb index 7e6b705..2fb6217 100644 --- a/chef/cookbooks/docker/templates/default/systemd/docker.socket-override.erb +++ b/chef/cookbooks/docker/templates/default/systemd/docker.socket-override.erb @@ -4,9 +4,8 @@ PartOf=<%= @docker_name %>.service [Socket] ListenStream=<%= @docker_socket %> -SocketMode=0660 -SocketUser=root SocketGroup=<%= @config.group %> +<%= @systemd_socket_args %> [Install] WantedBy=sockets.target diff --git a/chef/cookbooks/docker/templates/default/systemd/docker.socket.erb b/chef/cookbooks/docker/templates/default/systemd/docker.socket.erb index 22b452d..7e6b705 100644 --- a/chef/cookbooks/docker/templates/default/systemd/docker.socket.erb +++ b/chef/cookbooks/docker/templates/default/systemd/docker.socket.erb @@ -6,7 +6,7 @@ PartOf=<%= @docker_name %>.service ListenStream=<%= @docker_socket %> SocketMode=0660 SocketUser=root -SocketGroup=docker +SocketGroup=<%= @config.group %> [Install] WantedBy=sockets.target diff --git a/chef/cookbooks/docker/templates/default/sysvinit/docker-debian.erb b/chef/cookbooks/docker/templates/default/sysvinit/docker-debian.erb index bd1ffbf..932798b 100644 --- a/chef/cookbooks/docker/templates/default/sysvinit/docker-debian.erb +++ b/chef/cookbooks/docker/templates/default/sysvinit/docker-debian.erb @@ -23,6 +23,7 @@ BASE=<%= @docker_name %> # modify these in /etc/default/$BASE (/etc/default/docker) DOCKER=<%= @dockerd_bin_link %> +DOCKER_OPTS="<%= @docker_daemon_arg %> <%= @docker_daemon_opts %>" # This is the pid file managed by docker itself DOCKER_PIDFILE=/var/run/$BASE.pid # This is the pid file created/managed by start-stop-daemon @@ -106,10 +107,15 @@ case "$1" in --pidfile "$DOCKER_SSD_PIDFILE" \ --make-pidfile \ -- \ - <%= @docker_daemon_arg %> -p "$DOCKER_PID_FILE" \ $DOCKER_OPTS \ + -p "$DOCKER_PIDFILE" \ >> "$DOCKER_LOGFILE" 2>&1 - <%= @docker_wait_ready %> + + <%= @docker_wait_ready %> > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log_failure_msg "<%= @docker_socket %> failed to start" + exit 1 + fi log_end_msg $? ;; diff --git a/chef/cookbooks/docker/templates/default/upstart/docker.conf.erb b/chef/cookbooks/docker/templates/default/upstart/docker.conf.erb index 4189fe6..1055632 100644 --- a/chef/cookbooks/docker/templates/default/upstart/docker.conf.erb +++ b/chef/cookbooks/docker/templates/default/upstart/docker.conf.erb @@ -34,24 +34,18 @@ end script script # modify these in /etc/default/$UPSTART_JOB (/etc/default/docker) - DOCKER=<%= @dockerd_bin_link %> - DOCKER_OPTS= if [ -f /etc/default/$UPSTART_JOB ]; then . /etc/default/$UPSTART_JOB fi - exec "$DOCKER" <%= @docker_daemon_arg %> $DOCKER_OPTS --raw-logs + exec <%= @docker_daemon_cmd %> <%= @docker_raw_logs_arg %> end script post-start script - DOCKER_OPTS= - if [ -f /etc/default/$UPSTART_JOB ]; then - . /etc/default/$UPSTART_JOB - fi <%= @docker_wait_ready %> if [ $? -eq 0 ]; then echo "<%= @docker_socket %> is up" else - echo "<%= @docker_socket %> failed to come start" + echo "<%= @docker_socket %> failed to start" exit 1 fi end script diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/CHANGELOG.md b/chef/cookbooks/docker/test/cookbooks/docker_test/CHANGELOG.md new file mode 100644 index 0000000..a08038c --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/CHANGELOG.md @@ -0,0 +1,35 @@ +# CHANGELOG for docker_test + +This file is used to list changes made in each version of docker_test. + +## 0.5.1: + +* Bugfix: Test docker_image :build for both file and directory source + +## 0.5.0: + +* Bugfix: Switch docker@0.25.0 deprecated dockerfile container LWRP attribute to source + +## 0.4.0: + +* Bugfix: Remove deprecated public_port in container_lwrp +* Bugfix: Add `init_type false` for busybox test containers +* Enhancement: Add tduffield/testcontainerd image, container, and tests + +## 0.3.0: + +* Enhancement: Change Dockerfile FROM to already downloaded busybox image instead of ubuntu + +## 0.2.0: + +* Added container_lwrp recipe +* Removed default recipe from image_lwrp recipe + +## 0.1.0: + +* Initial release of docker_test + +- - - +Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown. + +The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown. diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_1 b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_1 new file mode 100644 index 0000000..3346eee --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_1 @@ -0,0 +1,2 @@ +FROM busybox +RUN /bin/echo 'hello from image_1' diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_2 b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_2 new file mode 100644 index 0000000..31fa5ce --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_2 @@ -0,0 +1,4 @@ +FROM busybox +ADD foo.txt /tmp/foo.txt +RUN /bin/echo 'hello from image_2' +VOLUME /home diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_4 b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_4 new file mode 100644 index 0000000..6b0530c --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/files/Dockerfile_4 @@ -0,0 +1,32 @@ +# Create a docker image that takes a long time to build + +# Centos as a base image. Any should work for the for loop test, but +# CentOS is needed for the yum test. +# Note that pulling the base image will not trigger a +# timeout, regardless of how long it +# takes +FROM centos + +# Simply wait for wait for 30 minutes, output a status update every 10 seconds +# This does not appear to trigger the timeout problem +# RUN [ "bash", "-c", "for minute in {1..30} ; do for second in {0..59..10} ; do echo -n \" $minute:$second \" ; sleep 10 ; done ; done" ] + +# This triggers the timeout. +# Sleep for 5 minutes, 3 times. +# RUN [ "bash", "-c", "for minute in {0..10..5} ; do echo -n \" $minute \" ; sleep 300 ; done" ] + +# Let's try this next. +# Sleep for 1 minutes, 15 time +RUN [ "bash", "-c", "for minute in {0..15} ; do echo -n \" $minute \" ; sleep 60 ; done" ] + +# This should trigger the timeout unless you have a very fast Internet connection. +# RUN \ + # curl -SL https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm -o epel.rpm \ + # && yum install -y epel.rpm \ + # && rm epel.rpm \ + # && yum install -y \ + # zarafa \ + # supervisor \ + # && yum clean all \ + # && rm -rf /usr/share/man /etc/httpd/conf.d/ssl.conf + diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3.tar b/chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3.tar new file mode 100644 index 0000000000000000000000000000000000000000..7437741ac3519be34a620eba91624be922b58c1f GIT binary patch literal 2560 zcmeH^F%N<;5QRJQD{f<>SK312Y~0j@#Mx9*lvt<%{r?t;hC$q#Xl$3)^e(-3-%BX* zeh@L263C!g{!mQCsP1hzz)~qCXDLGg$WlZ}KzeuP2Hg6q>YTOSHd=LRcBE^os@W4(;DDkXGj%d_sP+GtP8*)p2yLYUbqJWfj}S-2>d94J4TT_oB#j- literal 0 HcmV?d00001 diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3/Dockerfile b/chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3/Dockerfile new file mode 100644 index 0000000..8b17be5 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/files/image_3/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:3.1 +RUN /bin/echo 'hello from image_3' diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/metadata.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/metadata.rb new file mode 100644 index 0000000..e88533e --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/metadata.rb @@ -0,0 +1,9 @@ +name 'docker_test' +maintainer 'Sean OMeara' +maintainer_email 'sean@sean.io' +license 'Apache-2.0' +description 'installs a buncha junk' +version '0.6.0' + +depends 'docker' +depends 'etcd' diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/auto.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/auto.rb new file mode 100644 index 0000000..b8a91de --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/auto.rb @@ -0,0 +1,21 @@ +################ +# Docker service +################ + +docker_service 'default' do + host 'unix:///var/run/docker.sock' + install_method 'auto' + service_manager 'auto' + action [:create, :start] +end + +docker_image 'alpine' do + action :pull +end + +docker_container 'an_echo_server' do + repo 'alpine' + command 'nc -ll -p 7 -e /bin/cat' + port '7:7' + action :run +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/container.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/container.rb new file mode 100644 index 0000000..1110ef0 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/container.rb @@ -0,0 +1,1238 @@ +# Two variables, one recipe. +caname = 'docker_service_default' +caroot = "/ca/#{caname}" + +################ +# action :create +################ + +# create a container without starting it +docker_container 'hello-world' do + command '/hello' + action :create +end + +############# +# action :run +############# + +# This command will exit succesfully. This will happen on every +# chef-client run. +docker_container 'busybox_ls' do + repo 'busybox' + command 'ls -la /' + not_if "[ ! -z `docker ps -qaf 'name=busybox_ls$'` ]" + action :run +end + +# The :run_if_missing action will only run once. It is the default +# action. +docker_container 'alpine_ls' do + repo 'alpine' + tag '3.1' + command 'ls -la /' + action :run_if_missing +end + +############### +# port property +############### + +# This process remains running between chef-client runs, :run will do +# nothing on subsequent converges. +docker_container 'an_echo_server' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 7 -e /bin/cat' + port '7:7' + action :run +end + +# let docker pick the host port +docker_container 'another_echo_server' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 7 -e /bin/cat' + port '7' + action :run +end + +# specify the udp protocol +docker_container 'an_udp_echo_server' do + repo 'alpine' + tag '3.1' + command 'nc -ul -p 7 -e /bin/cat' + port '5007:7/udp' + action :run +end + +# multiple ips +docker_container 'multi_ip_port' do + repo 'alpine' + tag '3.1' + command 'nc -ul -p 7 -e /bin/cat' + port ['8301', '8301:8301/udp', '127.0.0.1:8500:8500', '127.0.1.1:8500:8500'] + action :run +end + +# port range +docker_container 'port_range' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port ['2000-2001', '2000-2001/udp', '3000-3001/tcp', '7000-7002:8000-8002'] + action :run +end + +############## +# action :kill +############## + +# start a container to be killed +execute 'bill' do + command 'docker run --name bill -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=bill$'` ]" + action :run +end + +docker_container 'bill' do + action :kill +end + +############## +# action :stop +############## + +# start a container to be stopped +execute 'hammer_time' do + command 'docker run --name hammer_time -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=hammer_time$'` ]" + action :run +end + +docker_container 'hammer_time' do + action :stop +end + +############### +# action :pause +############### + +# clean up existed container after a service restart +execute 'rm stale red_light' do + command 'docker rm -f red_light' + only_if 'docker ps -a | grep red_light | grep Exited' + action :run +end + +# start a container to be paused +execute 'red_light' do + command 'docker run --name red_light -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=red_light$'` ]" + action :run +end + +docker_container 'red_light' do + action :pause +end + +################# +# action :unpause +################# + +# start and pause a container to be unpaused +bash 'green_light' do + code <<-EOF + docker run --name green_light -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done" + docker pause green_light + EOF + not_if "[ ! -z `docker ps -qaf 'name=green_light$'` ]" + action :run +end + +docker_container 'green_light' do + action :unpause +end + +################# +# action :restart +################# + +# create and stop a container to be restarted +bash 'quitter' do + code <<-EOF + docker run --name quitter -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done" + docker kill quitter + EOF + not_if "[ ! -z `docker ps -qaf 'name=quitter$'` ]" + action :run +end + +docker_container 'quitter' do + not_if { ::File.exist?('/marker_container_quitter_restarter') } + action :restart +end + +file '/marker_container_quitter_restarter' do + action :create +end + +# start a container to be restarted +execute 'restarter' do + command 'docker run --name restarter -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=restarter$'` ]" + action :run +end + +docker_container 'restarter' do + not_if { ::File.exist?('/marker_container_restarter') } + action :restart +end + +file '/marker_container_restarter' do + action :create +end + +################ +# action :delete +################ + +# create a container to be deleted +execute 'deleteme' do + command 'docker run --name deleteme -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if { ::File.exist?('/marker_container_deleteme') } + action :run +end + +file '/marker_container_deleteme' do + action :create +end + +docker_container 'deleteme' do + action :delete +end + +################## +# action :redeploy +################## + +docker_container 'redeployer' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '7' + action :run +end + +docker_container 'unstarted_redeployer' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '7' + action :create +end + +execute 'redeploy redeployers' do + command 'touch /marker_container_redeployer' + creates '/marker_container_redeployer' + notifies :redeploy, 'docker_container[redeployer]', :immediately + notifies :redeploy, 'docker_container[unstarted_redeployer]', :immediately + action :run +end + +############# +# bind mounts +############# + +directory '/hostbits' do + owner 'root' + group 'root' + mode '0755' + action :create +end + +file '/hostbits/hello.txt' do + content 'hello there\n' + owner 'root' + group 'root' + mode '0644' + action :create +end + +directory '/more-hostbits' do + owner 'root' + group 'root' + mode '0755' + action :create +end + +file '/more-hostbits/hello.txt' do + content 'hello there\n' + owner 'root' + group 'root' + mode '0644' + action :create +end + +# docker inspect -f "{{ .HostConfig.Binds }}" +docker_container 'bind_mounter' do + repo 'busybox' + command 'ls -la /bits /more-bits' + volumes ['/hostbits:/bits', '/more-hostbits:/more-bits', '/snow', '/winter:/spring:ro', '/summer'] + action :run_if_missing +end + +docker_container 'binds_alias' do + repo 'busybox' + command 'ls -la /bits /more-bits' + binds ['/fall:/sun', '/snow', '/winter:/spring:ro', '/summer'] + action :run_if_missing +end + +############## +# volumes_from +############## + +# build a chef container +directory '/chefbuilder' do + owner 'root' + group 'root' + action :create +end + +execute 'copy chef to chefbuilder' do + command 'tar cf - /opt/chef | tar xf - -C /chefbuilder' + creates '/chefbuilder/opt' + action :run +end + +file '/chefbuilder/Dockerfile' do + content <<-EOF + FROM scratch + ADD opt /opt + EOF + action :create +end + +docker_image 'chef_container' do + tag 'latest' + source '/chefbuilder' + action :build_if_missing +end + +# create a volume container +docker_container 'chef_container' do + command 'true' + volumes '/opt/chef' + action :create +end + +# Inspect the docker logs with test-kitchen bussers +docker_container 'ohai_debian' do + command '/opt/chef/embedded/bin/ohai platform' + repo 'debian' + volumes_from 'chef_container' + action :run_if_missing +end + +##### +# env +##### + +file '/env_file1' do + content <<-EOF + GOODBYE=TOMPETTY + 1950=2017 + EOF + action :create +end + +file '/env_file2' do + content <<-EOF + HELLO=WORLD + EOF + action :create +end + +docker_container 'env' do + repo 'debian' + env ['PATH=/usr/bin', 'FOO=bar'] + env_file lazy { '/env_file1' } + command 'env' + action :run_if_missing +end + +docker_container 'env_files' do + repo 'debian' + env_file lazy { ['/env_file1', '/env_file2'] } + command 'env' + action :run_if_missing +end + +############ +# entrypoint +############ + +# Inspect container logs with test-kitchen bussers +docker_container 'ohai_again' do + repo 'debian' + volumes_from 'chef_container' + entrypoint '/opt/chef/embedded/bin/ohai' + action :run_if_missing +end + +docker_container 'ohai_again_debian' do + repo 'debian' + volumes_from 'chef_container' + entrypoint '/opt/chef/embedded/bin/ohai' + command 'platform' + action :run_if_missing +end + +########## +# cmd_test +########## +directory '/cmd_test' do + action :create +end + +file '/cmd_test/Dockerfile' do + content <<-EOF + FROM alpine + CMD [ "/bin/ls", "-la", "/" ] + EOF + action :create +end + +docker_image 'cmd_test' do + tag 'latest' + source '/cmd_test' + action :build_if_missing +end + +docker_container 'cmd_test' do + action :run_if_missing +end + +############# +# :autoremove +############# + +# Inspect volume container with test-kitchen bussers +docker_container 'sean_was_here' do + command "touch /opt/chef/sean_was_here-#{Time.new.strftime('%Y%m%d%H%M')}" + repo 'debian' + volumes_from 'chef_container' + autoremove true + not_if { ::File.exist?('/marker_container_sean_was_here') } + action :run +end + +# marker to prevent :run on subsequent converges. +file '/marker_container_sean_was_here' do + action :create +end + +######### +# :detach +######### + +# Inspect volume container with test-kitchen bussers +docker_container 'attached' do + command "touch /opt/chef/attached-#{Time.new.strftime('%Y%m%d%H%M')}" + repo 'debian' + volumes_from 'chef_container' + detach false + not_if { ::File.exist?('/marker_container_attached') } + action :run +end + +# marker to prevent :run on subsequent converges. +file '/marker_container_attached' do + action :create +end + +###################### +# :detach with timeout +###################### + +# Inspect volume container with test-kitchen bussers +docker_container 'attached_with_timeout' do + command "sleep 15 && touch /opt/chef/attached_with_timeout-#{Time.new.strftime('%Y%m%d%H%M')}" + repo 'debian' + volumes_from 'chef_container' + detach false + timeout 10 + not_if { ::File.exist?('/marker_container_attached_with_timeout') } + action :run +end + +# marker to prevent :run on subsequent converges. +file '/marker_container_attached_with_timeout' do + action :create +end + +######### +# cap_add +######### + +# Inspect system with test-kitchen bussers +docker_container 'cap_add_net_admin' do + repo 'debian' + command 'bash -c "ip addr add 10.9.8.7/24 brd + dev eth0 label eth0:0 ; ip addr list"' + cap_add 'NET_ADMIN' + action :run_if_missing +end + +docker_container 'cap_add_net_admin_error' do + repo 'debian' + command 'bash -c "ip addr add 10.9.8.7/24 brd + dev eth0 label eth0:0 ; ip addr list"' + action :run_if_missing +end + +########## +# cap_drop +########## + +# Inspect container logs with test-kitchen bussers +docker_container 'cap_drop_mknod' do + repo 'debian' + command 'bash -c "mknod -m 444 /dev/urandom2 c 1 9 ; ls -la /dev/urandom2"' + cap_drop 'MKNOD' + action :run_if_missing +end + +docker_container 'cap_drop_mknod_error' do + repo 'debian' + command 'bash -c "mknod -m 444 /dev/urandom2 c 1 9 ; ls -la /dev/urandom2"' + action :run_if_missing +end + +########################### +# hostname and domain_name +########################### + +# Inspect container logs with test-kitchen bussers +docker_container 'fqdn' do + repo 'debian' + command 'hostname -f' + hostname 'computers' + domain_name 'biz' + action :run_if_missing +end + +##### +# dns +##### + +# Inspect container logs with test-kitchen bussers +docker_container 'dns' do + repo 'debian' + command 'cat /etc/resolv.conf' + hostname 'computers' + dns ['4.3.2.1', '1.2.3.4'] + dns_search ['computers.biz', 'chef.io'] + action :run_if_missing +end + +############# +# extra_hosts +############# + +# Inspect container logs with test-kitchen bussers +docker_container 'extra_hosts' do + repo 'debian' + command 'cat /etc/hosts' + extra_hosts ['east:4.3.2.1', 'west:1.2.3.4'] + action :run_if_missing +end + +############ +# cpu_shares +############ + +# docker inspect -f '{{ .HostConfig.CpuShares }}' cpu_shares +docker_container 'cpu_shares' do + repo 'alpine' + tag '3.1' + command 'ls -la' + cpu_shares 512 + action :run_if_missing +end + +############# +# cpuset_cpus +############# + +# docker inspect cpu_shares | grep '"CpusetCpus": "0,1"' +docker_container 'cpuset_cpus' do + repo 'alpine' + tag '3.1' + command 'ls -la' + cpuset_cpus '0,1' + action :run_if_missing +end + +################ +# restart_policy +################ + +# docker inspect restart_policy | grep 'RestartPolicy' +docker_container 'try_try_again' do + repo 'alpine' + tag '3.1' + command 'grep asdasdasd /etc/passwd' + restart_policy 'on-failure' + restart_maximum_retry_count 2 + action :run_if_missing +end + +docker_container 'reboot_survivor' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 123 -e /bin/cat' + port '123' + restart_policy 'always' + action :run_if_missing +end + +docker_container 'reboot_survivor_retry' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 123 -e /bin/cat' + port '123' + restart_maximum_retry_count 2 + action :run_if_missing +end + +####### +# links +####### + +# docker inspect -f "{{ .Config.Env }}" link_source +# docker inspect -f "{{ .NetworkSettings.IPAddress }}" link_source +docker_container 'link_source' do + repo 'alpine' + tag '3.1' + env ['FOO=bar', 'BIZ=baz'] + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '321' + action :run +end + +docker_container 'link_source_2' do + repo 'alpine' + tag '3.1' + env ['FOO=few', 'BIZ=buzz'] + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '322' + kill_after 1 + action :run +end + +# docker inspect -f "{{ .HostConfig.Links }}" link_target_1 +# docker inspect -f "{{ .Config.Env }}" link_target_1 +docker_container 'link_target_1' do + repo 'alpine' + tag '3.1' + env ['ASD=asd'] + command 'ping -c 1 hello' + links 'link_source:hello' + subscribes :run, 'docker_container[link_source]' + action :run_if_missing +end + +# docker logs linker_target_2 +docker_container 'link_target_2' do + repo 'alpine' + tag '3.1' + command 'env' + links ['link_source:hello'] + subscribes :run, 'docker_container[link_source]' + action :run_if_missing +end + +# docker logs linker_target_3 +docker_container 'link_target_3' do + repo 'alpine' + tag '3.1' + env ['ASD=asd'] + command 'ping -c 1 hello_again' + links ['link_source:hello', 'link_source_2:hello_again'] + subscribes :run, 'docker_container[link_source]' + subscribes :run, 'docker_container[link_source_2]' + action :run_if_missing +end + +# docker logs linker_target_4 +docker_container 'link_target_4' do + repo 'alpine' + tag '3.1' + command 'env' + links ['link_source:hello', 'link_source_2:hello_again'] + subscribes :run, 'docker_container[link_source]' + subscribes :run, 'docker_container[link_source_2]' + action :run_if_missing +end + +# When we deploy the link_source container links are broken and we +# have to redeploy the linked containers to fix them. +execute 'redeploy_link_source' do + command 'touch /marker_container_redeploy_link_source' + creates '/marker_container_redeploy_link_source' + notifies :redeploy, 'docker_container[link_source_2]' + notifies :redeploy, 'docker_container[link_target_1]' + notifies :redeploy, 'docker_container[link_target_2]' + notifies :redeploy, 'docker_container[link_target_3]' + notifies :redeploy, 'docker_container[link_target_4]' + action :run +end + +############## +# link removal +############## + +# docker inspect -f "{{ .Volumes }}" another_link_source +# docker inspect -f "{{ .HostConfig.Links }}" another_link_source +docker_container 'another_link_source' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 456 -e /bin/cat' + port '456' + action :run_if_missing +end + +# docker inspect -f "{{ .HostConfig.Links }}" another_link_target +docker_container 'another_link_target' do + repo 'alpine' + tag '3.1' + command 'ping -c 1 hello' + links ['another_link_source:derp'] + action :run_if_missing +end + +################ +# volume removal +################ + +directory '/dangler' do + owner 'root' + group 'root' + mode '0755' + action :create +end + +file '/dangler/Dockerfile' do + content <<-EOF + FROM busybox + RUN mkdir /stuff + VOLUME /stuff + EOF + action :create +end + +docker_image 'dangler' do + tag 'latest' + source '/dangler' + action :build_if_missing +end + +# create a volume container +docker_container 'dangler' do + command 'true' + not_if { ::File.exist?('/marker_container_dangler') } + action :create +end + +file '/marker_container_dangler' do + action :create +end + +docker_container 'dangler_volume_remover' do + container_name 'dangler' + remove_volumes true + action :delete +end + +######### +# mutator +######### + +docker_tag 'mutator_from_busybox' do + target_repo 'busybox' + target_tag 'latest' + to_repo 'someara/mutator' + to_tag 'latest' +end + +docker_container 'mutator' do + repo 'someara/mutator' + tag 'latest' + command "sh -c 'touch /mutator-`date +\"%Y-%m-%d_%H-%M-%S\"`'" + outfile '/mutator.tar' + force true + action :run_if_missing +end + +execute 'commit mutator' do + command 'touch /marker_container_mutator' + creates '/marker_container_mutator' + notifies :commit, 'docker_container[mutator]', :immediately + notifies :export, 'docker_container[mutator]', :immediately + notifies :redeploy, 'docker_container[mutator]', :immediately + action :run +end + +############## +# network_mode +############## + +docker_container 'network_mode' do + repo 'alpine' + tag '3.1' + command 'nc -ll -p 776 -e /bin/cat' + port '776:776' + network_mode 'host' + action :run +end + +##################### +# change_network_mode +##################### + +execute 'change_network_mode' do + command 'docker run --name change_network_mode -d alpine:3.1 sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=change_network_mode$'` ]" + action :run +end + +docker_container 'change_network_mode' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + network_mode 'host' + action :run +end + +######### +# ulimits +######### + +docker_container 'ulimits' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '778:778' + cap_add 'SYS_RESOURCE' + ulimits [ + { 'Name' => 'nofile', 'Soft' => 40_960, 'Hard' => 40_960 }, + { 'Name' => 'core', 'Soft' => 100_000_000, 'Hard' => 100_000_000 }, + { 'Name' => 'memlock', 'Soft' => 100_000_000, 'Hard' => 100_000_000 }, + ] + action :run +end + +############## +# api_timeouts +############## + +docker_container 'api_timeouts' do + command 'nc -ll -p 779 -e /bin/cat' + repo 'alpine' + tag '3.1' + read_timeout 60 + write_timeout 60 + action :run_if_missing +end + +############## +# uber_options +############## + +# start a container to be modified +execute 'uber_options' do + command 'docker run --name uber_options -d busybox sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if "[ ! -z `docker ps -qaf 'name=uber_options$'` ]" + action :run +end + +docker_container 'uber_options' do + repo 'alpine' + tag '3.1' + hostname 'www' + domainname 'computers.biz' + env ['FOO=foo', 'BAR=bar'] + mac_address '00:00:DE:AD:BE:EF' + network_disabled false + tty true + volumes ['/root', '/hostbits:/bits', '/more-hostbits:/more-bits'] + working_dir '/' + cap_add %w(NET_ADMIN SYS_RESOURCE) + cap_drop 'MKNOD' + cpu_shares 512 + cpuset_cpus '0,1' + dns ['8.8.8.8', '8.8.4.4'] + dns_search ['computers.biz'] + extra_hosts ['east:4.3.2.1', 'west:1.2.3.4'] + links ['link_source:hello'] + port '1234:1234' + volumes_from 'chef_container' + user 'operator' + command '"trap exit 0 SIGTERM; while :; do sleep 5; done"' + entrypoint '/bin/sh -c' + ulimits [ + 'nofile=40960:40960', + 'core=100000000:100000000', + 'memlock=100000000:100000000', + ] + labels ['foo:bar', 'hello:world'] + action :run +end + +########### +# overrides +########### + +# build a chef container +directory '/overrides' do + owner 'root' + group 'root' + action :create +end + +file '/overrides/Dockerfile' do + content <<-EOF + FROM busybox + RUN adduser -D bob + CMD trap exit 0 SIGTERM; while :; do sleep 1; done + USER bob + ENV FOO foo + ENV BAR bar + ENV BIZ=biz BAZ=baz + ENV BUZZ buzz + VOLUME /home + WORKDIR /var + EXPOSE 4321 + EOF + notifies :build, 'docker_image[overrides]' + action :create +end + +docker_image 'overrides' do + tag 'latest' + source '/overrides' + force true + action :build_if_missing + notifies :redeploy, 'docker_container[overrides-1]' + notifies :redeploy, 'docker_container[overrides-2]' +end + +docker_container 'overrides-1' do + repo 'overrides' + action :run +end + +docker_container 'overrides-2' do + repo 'overrides' + user 'operator' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + env ['FOO=biz'] + volumes '/var/log' + workdir '/tmp' + port ['9988:9988', '8877:8877'] + action :run +end + +################# +# host override +################# + +docker_container 'host_override' do + repo 'alpine' + host 'tcp://127.0.0.1:2376' + command 'ls -la /' + tls_verify true + tls_ca_cert "#{caroot}/ca.pem" + tls_client_cert "#{caroot}/cert.pem" + tls_client_key "#{caroot}/key.pem" + action :create +end + +################# +# logging drivers +################# + +docker_container 'syslogger' do + command 'nc -ll -p 780 -e /bin/cat' + repo 'alpine' + tag '3.1' + log_driver 'syslog' + log_opts 'tag=container-syslogger' + action :run_if_missing +end + +############ +# kill_after +############ + +# start a container that can't be stopped and relies on kill_after + +directory '/kill_after' do + owner 'root' + group 'root' + action :create +end + +file '/kill_after/loop.sh' do + content <<-EOF + #!/bin/sh + trap 'exit 0' SIGTERM + while true; do :; done + EOF + notifies :build, 'docker_image[kill_after]' + action :create +end + +file '/kill_after/Dockerfile' do + content <<-EOF + FROM busybox + ADD loop.sh / + RUN chmod +x /loop.sh + CMD "/loop.sh" + EOF + notifies :build, 'docker_image[kill_after]' + action :create +end + +docker_image 'kill_after' do + tag 'latest' + source '/kill_after' + force true + action :build_if_missing +end + +execute 'kill_after' do + command 'docker run --name kill_after -d kill_after' + not_if "[ ! -z `docker ps -qaf 'name=kill_after$'` ]" + action :run +end + +docker_container 'kill_after' do + repo 'kill_after' + kill_after 1 + action :stop +end + +###### +# oom_kill_disable +###### + +docker_container 'oom_kill_disable' do + repo 'alpine' + tag '3.1' + command 'ls -la' + oom_kill_disable true + timeout 40 + action :run_if_missing +end + +###### +# oom_score_adj +###### + +docker_container 'oom_score_adj' do + repo 'alpine' + tag '3.1' + command 'ls -la' + oom_score_adj 600 + timeout 40 + action :run_if_missing +end + +########## +# pid_mode +########## + +docker_container 'pid_mode' do + repo 'alpine' + tag '3.1' + command 'ps -ef' + pid_mode 'host' + timeout 40 + action :run_if_missing +end + +###### +# init +###### + +# docker inspect init | grep '"Init": true' +docker_container 'init' do + repo 'alpine' + tag '3.1' + command 'ls -la' + init true + timeout 40 + action :run_if_missing +end + +########## +# ipc_mode +########## + +docker_container 'ipc_mode' do + repo 'alpine' + tag '3.1' + command 'ps -ef' + ipc_mode 'host' + timeout 40 + action :run_if_missing +end + +########## +# uts_mode +########## + +docker_container 'uts_mode' do + repo 'alpine' + tag '3.1' + command 'ps -ef' + uts_mode 'host' + timeout 40 + action :run_if_missing +end + +################## +# read-only rootfs +################## + +docker_container 'ro_rootfs' do + repo 'alpine' + tag '3.1' + command 'ps -ef' + ro_rootfs true + timeout 40 + action :run_if_missing +end + +################## +# sysctl settings +################## + +docker_container 'sysctls' do + repo 'alpine' + tag '3.1' + command '/sbin/sysctl -a' + sysctls 'net.core.somaxconn' => '65535', + 'net.core.xfrm_acq_expires' => '42' + timeout 40 + action :run_if_missing +end + +######################## +# Dockerfile CMD changes +######################## + +directory '/usr/local/src/cmd_change_one' do + action :create +end + +file '/usr/local/src/cmd_change_one/Dockerfile' do + content < + [ + 'string', + ], + 'Interval' => 0, + 'Timeout' => 0, + 'Retries' => 0, + 'StartPeriod' => 0 + ) + action :run +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/default.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/default.rb new file mode 100644 index 0000000..d7f2c79 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/default.rb @@ -0,0 +1,145 @@ +################ +# Setting up TLS +################ + +caname = 'docker_service_default' +caroot = "/ca/#{caname}" + +directory caroot.to_s do + recursive true + action :create +end + +# Self signed CA +bash "#{caname} - generating CA private and public key" do + cmd = 'openssl req' + cmd += ' -x509' + cmd += ' -nodes' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -subj '/CN=kitchen2docker/'" + cmd += ' -newkey rsa:4096' + cmd += " -keyout #{caroot}/ca-key.pem" + cmd += " -out #{caroot}/ca.pem" + cmd += ' 2>&1>/dev/null' + code cmd + not_if "/usr/bin/test -f #{caroot}/ca-key.pem" + not_if "/usr/bin/test -f #{caroot}/ca.pem" + action :run +end + +# server certs +bash "#{caname} - creating private key for docker server" do + code "openssl genrsa -out #{caroot}/server-key.pem 4096" + not_if "/usr/bin/test -f #{caroot}/server-key.pem" + action :run +end + +bash "#{caname} - generating certificate request for server" do + cmd = 'openssl req' + cmd += ' -new' + cmd += ' -sha256' + cmd += " -subj '/CN=#{node['hostname']}/'" + cmd += " -key #{caroot}/server-key.pem" + cmd += " -out #{caroot}/server.csr" + code cmd + only_if "/usr/bin/test -f #{caroot}/server-key.pem" + not_if "/usr/bin/test -f #{caroot}/server.csr" + action :run +end + +file "#{caroot}/server-extfile.cnf" do + content "subjectAltName = IP:#{node['ipaddress']},IP:127.0.0.1\n" + action :create +end + +bash "#{caname} - signing request for server" do + cmd = 'openssl x509' + cmd += ' -req' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -CA #{caroot}/ca.pem" + cmd += " -CAkey #{caroot}/ca-key.pem" + cmd += ' -CAcreateserial' + cmd += " -in #{caroot}/server.csr" + cmd += " -out #{caroot}/server.pem" + cmd += " -extfile #{caroot}/server-extfile.cnf" + not_if "/usr/bin/test -f #{caroot}/server.pem" + code cmd + action :run +end + +# client certs +bash "#{caname} - creating private key for docker client" do + code "openssl genrsa -out #{caroot}/key.pem 4096" + not_if "/usr/bin/test -f #{caroot}/key.pem" + action :run +end + +bash "#{caname} - generating certificate request for client" do + cmd = 'openssl req' + cmd += ' -new' + cmd += " -subj '/CN=client/'" + cmd += " -key #{caroot}/key.pem" + cmd += " -out #{caroot}/client.csr" + code cmd + only_if "/usr/bin/test -f #{caroot}/key.pem" + not_if "/usr/bin/test -f #{caroot}/client.csr" + action :run +end + +file "#{caroot}/client-extfile.cnf" do + content "extendedKeyUsage = clientAuth\n" + action :create +end + +bash "#{caname} - signing request for client" do + cmd = 'openssl x509' + cmd += ' -req' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -CA #{caroot}/ca.pem" + cmd += " -CAkey #{caroot}/ca-key.pem" + cmd += ' -CAcreateserial' + cmd += " -in #{caroot}/client.csr" + cmd += " -out #{caroot}/cert.pem" + cmd += " -extfile #{caroot}/client-extfile.cnf" + code cmd + not_if "/usr/bin/test -f #{caroot}/cert.pem" + action :run +end + +################ +# Etcd service +################ + +etcd_service 'etcd0' do + advertise_client_urls "http://#{node['ipaddress']}:2379,http://0.0.0.0:4001" + listen_client_urls 'http://0.0.0.0:2379,http://0.0.0.0:4001' + initial_advertise_peer_urls "http://#{node['ipaddress']}:2380" + listen_peer_urls 'http://0.0.0.0:2380' + initial_cluster_token 'etcd0' + initial_cluster "etcd0=http://#{node['ipaddress']}:2380" + initial_cluster_state 'new' + action [:create, :start] +end + +################ +# Docker service +################ + +docker_service 'default' do + host ['unix:///var/run/docker.sock', 'tcp://127.0.0.1:2376'] + version node['docker']['version'] + labels ['environment:test', 'foo:bar'] + tls_verify true + tls_ca_cert "#{caroot}/ca.pem" + tls_server_cert "#{caroot}/server.pem" + tls_server_key "#{caroot}/server-key.pem" + tls_client_cert "#{caroot}/cert.pem" + tls_client_key "#{caroot}/key.pem" + cluster_store "etcd://#{node['ipaddress']}:4001" + cluster_advertise "#{node['ipaddress']}:4001" + install_method 'package' + action [:create, :start] +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/exec.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/exec.rb new file mode 100644 index 0000000..34e4bd4 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/exec.rb @@ -0,0 +1,25 @@ +docker_image 'busybox' do + action :pull_if_missing +end + +docker_container 'busybox_exec' do + repo 'busybox' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' +end + +docker_exec 'touch_it' do + container 'busybox_exec' + command ['touch', '/tmp/onefile'] + timeout 120 + not_if { ::File.exist?('/marker_busybox_exec_onefile') } +end + +file '/marker_busybox_exec_onefile' + +docker_exec 'poke_it' do + container 'busybox_exec' + cmd ['touch', '/tmp/twofile'] + not_if { ::File.exist?('/marker_busybox_exec_twofile') } +end + +file '/marker_busybox_exec_twofile' diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image.rb new file mode 100644 index 0000000..36a2f0f --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image.rb @@ -0,0 +1,317 @@ +# Two variables, one recipe. +caname = 'docker_service_default' +caroot = "/ca/#{caname}" + +######################### +# :pull_if_missing, :pull +######################### + +# default action, default properties +docker_image 'hello-world' + +# non-default name attribute, containing a single quote +docker_image "Tom's container" do + repo 'tduffield/testcontainerd' +end + +# :pull action specified +docker_image 'busybox' do + action :pull +end + +# :pull_if_missing +docker_image 'debian' do + action :pull_if_missing +end + +# specify a tag and read/write timeouts +docker_image 'alpine' do + tag '3.1' + read_timeout 60 + write_timeout 60 +end + +# host override +docker_image 'alpine-localhost' do + repo 'alpine' + tag '2.7' + host 'tcp://127.0.0.1:2376' + tls_verify true + tls_ca_cert "#{caroot}/ca.pem" + tls_client_cert "#{caroot}/cert.pem" + tls_client_key "#{caroot}/key.pem" +end + +######### +# :remove +######### + +# install something so it can be used to test the :remove action +execute 'pull vbatts/slackware' do + command 'docker pull vbatts/slackware ; touch /marker_image_slackware' + creates '/marker_image_slackware' + action :run +end + +docker_image 'vbatts/slackware' do + action :remove +end + +######## +# :save +######## + +docker_image 'save hello-world' do + repo 'hello-world' + destination '/hello-world.tar' + not_if { ::File.exist?('/hello-world.tar') } + action :save +end + +######## +# :load +######## + +docker_image 'cirros' do + action :pull + not_if { ::File.exist?('/marker_load_cirros-1') } +end + +docker_image 'save cirros' do + repo 'cirros' + destination '/cirros.tar' + not_if { ::File.exist?('/cirros.tar') } + action :save +end + +docker_image 'remove cirros' do + repo 'cirros' + not_if { ::File.exist?('/marker_load_cirros-1') } + action :remove +end + +docker_image 'load cirros' do + source '/cirros.tar' + not_if { ::File.exist?('/marker_load_cirros-1') } + action :load +end + +file '/marker_load_cirros-1' do + action :create +end + +########################### +# :build +########################### + +# Build from a Dockerfile +directory '/usr/local/src/container1' do + action :create +end + +cookbook_file '/usr/local/src/container1/Dockerfile' do + source 'Dockerfile_1' + action :create +end + +docker_image 'someara/image-1' do + tag 'v0.1.0' + source '/usr/local/src/container1/Dockerfile' + force true + not_if { ::File.exist?('/marker_image_image-1') } + action :build +end + +file '/marker_image_image-1' do + action :create +end + +# Build from a directory +directory '/usr/local/src/container2' do + action :create +end + +file '/usr/local/src/container2/foo.txt' do + content 'Dockerfile_2 contains ADD for this file' + action :create +end + +cookbook_file '/usr/local/src/container2/Dockerfile' do + source 'Dockerfile_2' + action :create +end + +docker_image 'someara/image.2' do + tag 'v0.1.0' + source '/usr/local/src/container2' + action :build_if_missing +end + +# Build from a tarball +cookbook_file '/usr/local/src/image_3.tar' do + source 'image_3.tar' + action :create +end + +docker_image 'image_3' do + tag 'v0.1.0' + source '/usr/local/src/image_3.tar' + action :build_if_missing +end + +######### +# :import +######### + +docker_image 'hello-again' do + tag 'v0.1.0' + source '/hello-world.tar' + action :import +end + +################ +# :tag and :push +################ + +###################### +# This commented out section was manually tested by replacing the +# authentication creds with real live Dockerhub creds. +##################### + +# docker_registry 'https://index.docker.io/v1/' do +# username 'youthere' +# password 'p4sswh1rr3d' +# email 'youthere@computers.biz' +# end + +# # name-w-dashes +# docker_tag 'public dockerhub someara/name-w-dashes:v1.0.1' do +# target_repo 'hello-again' +# target_tag 'v0.1.0' +# to_repo 'someara/name-w-dashes' +# to_tag 'latest' +# action :tag +# end + +# docker_image 'push someara/name-w-dashes' do +# repo 'someara/name-w-dashes' +# not_if { ::File.exist?('/marker_image_public_name-w-dashes') } +# action :push +# end + +# file '/marker_image_public_name-w-dashes' do +# action :create +# end + +# # name.w.dots +# docker_tag 'public dockerhub someara/name.w.dots:latest' do +# target_repo 'busybox' +# target_tag 'latest' +# to_repo 'someara/name.w.dots' +# to_tag 'latest' +# action :tag +# end + +# docker_image 'push someara/name.w.dots' do +# repo 'someara/name.w.dots' +# not_if { ::File.exist?('/marker_image_public_name.w.dots') } +# action :push +# end + +# file '/marker_image_public_name.w.dots' do +# action :create +# end + +# # private-repo-test +# docker_tag 'public dockerhub someara/private-repo-test:v1.0.1' do +# target_repo 'hello-world' +# target_tag 'latest' +# to_repo 'someara/private-repo-test' +# to_tag 'latest' +# action :tag +# end + +# docker_image 'push someara/private-repo-test' do +# repo 'someara/private-repo-test' +# not_if { ::File.exist?('/marker_image_public_private-repo-test') } +# action :push +# end + +# file '/marker_image_public_private-repo-test' do +# action :create +# end + +# docker_image 'someara/private-repo-test' + +# public images +docker_image 'someara/name-w-dashes' +docker_image 'someara/name.w.dots' + +################## +# Private registry +################## + +include_recipe 'docker_test::registry' + +# for pushing to private repo +docker_tag 'private repo tag for name-w-dashes:v1.0.1' do + target_repo 'hello-again' + target_tag 'v0.1.0' + to_repo 'localhost:5043/someara/name-w-dashes' + to_tag 'latest' + action :tag +end + +# for pushing to private repo +docker_tag 'private repo tag for name.w.dots' do + target_repo 'busybox' + target_tag 'latest' + to_repo 'localhost:5043/someara/name.w.dots' + to_tag 'latest' + action :tag +end + +docker_tag 'private repo tag for name.w.dots v0.1.0' do + target_repo 'busybox' + target_tag 'latest' + to_repo 'localhost:5043/someara/name.w.dots' + to_tag 'v0.1.0' + action :tag +end + +docker_registry 'localhost:5043' do + username 'testuser' + password 'testpassword' + email 'alice@computers.biz' +end + +docker_image 'localhost:5043/someara/name-w-dashes' do + not_if { ::File.exist?('/marker_image_private_name-w-dashes') } + action :push +end + +file '/marker_image_private_name-w-dashes' do + action :create +end + +docker_image 'localhost:5043/someara/name.w.dots' do + not_if { ::File.exist?('/marker_image_private_name.w.dots') } + action :push +end + +docker_image 'localhost:5043/someara/name.w.dots' do + not_if { ::File.exist?('/marker_image_private_name.w.dots') } + tag 'v0.1.0' + action :push +end + +file '/marker_image_private_name.w.dots' do + action :create +end + +# Pull from the public Dockerhub after being authenticated to a +# private one + +docker_image 'fedora' do + action :pull +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image_prune.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image_prune.rb new file mode 100644 index 0000000..cb306b0 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/image_prune.rb @@ -0,0 +1,15 @@ +######################### +# :prune +######################### + +docker_image_prune 'hello-world' do + dangling true +end + +docker_image_prune 'prune-old-images' do + dangling true + prune_until '1h30m' + with_label 'com.example.vendor=ACME' + without_label 'no_prune' + action :prune +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_package.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_package.rb new file mode 100644 index 0000000..3bc3e43 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_package.rb @@ -0,0 +1,4 @@ +docker_installation_package 'default' do + version '18.06.0' + action :create +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_script.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_script.rb new file mode 100644 index 0000000..809ad02 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_script.rb @@ -0,0 +1,4 @@ +docker_installation_script 'default' do + repo node['docker']['repo'] + action :create +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_tarball.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_tarball.rb new file mode 100644 index 0000000..46f193a --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/installation_tarball.rb @@ -0,0 +1,4 @@ +docker_installation_tarball 'default' do + version node['docker']['version'] + action :create +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/network.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/network.rb new file mode 100644 index 0000000..3899cba --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/network.rb @@ -0,0 +1,251 @@ +# pull alpine image +docker_image 'alpine' do + tag '3.1' + action :pull_if_missing +end + +# unicode characters +docker_network 'seseme_straße' do + action :create +end + +########### +# network_a +########### + +# defaults +docker_network 'network_a' do + action :create +end + +# docker run --net= +docker_container 'echo-base-network_a' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '1337' + network_mode 'network_a' + action :run +end + +docker_container 'echo-station-network_a' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '31337' + network_mode 'network_a' + action :run +end + +############ +# network_b +############ + +execute 'create network_b' do + command 'docker network create network_b' + not_if { ::File.exist?('/marker_delete_network_b') } +end + +file '/marker_delete_network_b' do + action :create +end + +# Delete a network +docker_network 'network_b' do + action :delete +end + +########### +# network_c +########### + +# specify subnet and gateway +docker_network 'network_c' do + subnet '192.168.88.0/24' + gateway '192.168.88.1' + action :create +end + +# docker run --net= +docker_container 'echo-base-network_c' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '1337' + network_mode 'network_c' + action :run +end + +docker_container 'echo-station-network_c' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '31337' + network_mode 'network_c' + action :run +end + +########### +# network_d +########### + +# create a network with aux_address +docker_network 'network_d' do + subnet '192.168.89.0/24' + gateway '192.168.89.1' + aux_address ['a=192.168.89.2', 'b=192.168.89.3'] +end + +docker_container 'echo-base-network_d' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '1337' + network_mode 'network_d' + action :run +end + +docker_container 'echo-station-network_d' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '31337' + network_mode 'network_d' + action :run +end + +########### +# network_e +########### + +# specify overlay driver +docker_network 'network_e' do + driver 'overlay' + action :create +end + +########### +# network_f +########### + +# create a network with an ip-range +docker_network 'network_f' do + driver 'bridge' + subnet '172.28.0.0/16' + gateway '172.28.5.254' + ip_range '172.28.5.0/24' +end + +docker_container 'echo-base-network_f' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '1337' + network_mode 'network_f' + ip_address '172.28.5.5' + action :run +end + +docker_container 'echo-station-network_f' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '31337' + network_mode 'network_f' + action :run +end + +########### +# network_g +########### + +# create an overlay network with multiple subnets +docker_network 'network_g' do + driver 'overlay' + subnet ['192.168.0.0/16', '192.170.0.0/16'] + gateway ['192.168.0.100', '192.170.0.100'] + ip_range '192.168.1.0/24' + aux_address ['a=192.168.1.5', 'b=192.168.1.6', 'a=192.170.1.5', 'b=192.170.1.6'] +end + +docker_container 'echo-base-network_g' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '1337' + network_mode 'network_g' + action :run +end + +docker_container 'echo-station-network_g' do + repo 'alpine' + tag '3.1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + port '31337' + network_mode 'network_g' + action :run +end + +########### +# network_h +########### + +# connect same container to multiple networks +docker_network 'network_h1' do + action :create +end + +docker_network 'network_h2' do + action :create +end + +docker_container 'container1-network_h' do + repo 'alpine' + tag '3.1' + network_mode 'network_h1' + command 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"' + not_if { ::File.exist?('/marker_network_h') } + action :run +end + +file '/marker_network_h' do + action :create +end + +docker_network 'network_h2 connector' do + container 'container1-network_h' + network_name 'network_h2' + action :connect +end + +# disconnet from a network +docker_network 'network_h1 disconnector' do + container 'container1-network_h' + network_name 'network_h1' + action :disconnect +end + +############## +# network_ipv6 +############## +# IPv6 enabled network +docker_network 'network_ipv6' do + enable_ipv6 true + subnet 'fd00:dead:beef::/48' + action :create +end + +############## +# network_ipv4 +############## +docker_network 'network_ipv4' do + action :create +end + +################## +# network_internal +################## +docker_network 'network_internal' do + internal true + action :create +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/plugin.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/plugin.rb new file mode 100644 index 0000000..281af9b --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/plugin.rb @@ -0,0 +1,94 @@ +###################### +# :install and :update +###################### + +sshfs_caps = [ + { + 'Name' => 'network', + 'Value' => ['host'], + }, + { + 'Name' => 'mount', + 'Value' => ['/var/lib/docker/plugins/'], + }, + { + 'Name' => 'mount', + 'Value' => [''], + }, + { + 'Name' => 'device', + 'Value' => ['/dev/fuse'], + }, + { + 'Name' => 'capabilities', + 'Value' => ['CAP_SYS_ADMIN'], + }, +] + +docker_plugin 'vieux/sshfs' do + grant_privileges sshfs_caps +end + +docker_plugin 'configure vieux/sshfs' do + action :update + local_alias 'vieux/sshfs' + options( + 'DEBUG' => '1' + ) +end + +docker_plugin 'remove vieux/sshfs' do + local_alias 'vieux/sshfs' + action :remove +end + +####################### +# :install with options +####################### + +docker_plugin 'rbd' do + remote 'wetopi/rbd' + remote_tag '1.0.1' + grant_privileges true + options( + 'LOG_LEVEL' => '4' + ) +end + +docker_plugin 'remove rbd' do + local_alias 'rbd' + action :remove +end + +####################################### +# :install twice (should be idempotent) +####################################### + +docker_plugin 'sshfs 2.1' do + local_alias 'sshfs' + remote 'vieux/sshfs' + remote_tag 'latest' + grant_privileges true +end + +docker_plugin 'sshfs 2.2' do + local_alias 'sshfs' + remote 'vieux/sshfs' + remote_tag 'latest' + grant_privileges true +end + +docker_plugin 'enable sshfs' do + local_alias 'sshfs' + action :enable +end + +docker_plugin 'disable sshfs' do + local_alias 'sshfs' + action :disable +end + +docker_plugin 'remove sshfs again' do + local_alias 'sshfs' + action :remove +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/registry.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/registry.rb new file mode 100644 index 0000000..52ca592 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/registry.rb @@ -0,0 +1,192 @@ +# We're going to need some SSL certificates for testing. + +caroot = '/tmp/registry/tls' + +directory caroot.to_s do + recursive true + action :create +end + +# Self signed CA +bash 'generating CA private and public key' do + cmd = 'openssl req' + cmd += ' -x509' + cmd += ' -nodes' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -subj '/CN=kitchen2docker/'" + cmd += ' -newkey rsa:4096' + cmd += " -keyout #{caroot}/ca-key.pem" + cmd += " -out #{caroot}/ca.pem" + cmd += ' 2>&1>/dev/null' + code cmd + not_if "/usr/bin/test -f #{caroot}/ca-key.pem" + not_if "/usr/bin/test -f #{caroot}/ca.pem" + action :run +end + +# server certs +bash 'creating private key for docker server' do + code "openssl genrsa -out #{caroot}/server-key.pem 4096" + not_if "/usr/bin/test -f #{caroot}/server-key.pem" + action :run +end + +bash 'generating certificate request for server' do + cmd = 'openssl req' + cmd += ' -new' + cmd += ' -sha256' + cmd += " -subj '/CN=#{node['hostname']}/'" + cmd += " -key #{caroot}/server-key.pem" + cmd += " -out #{caroot}/server.csr" + code cmd + not_if "/usr/bin/test -f #{caroot}/server.csr" + action :run +end + +file "#{caroot}/server-extfile.cnf" do + content "subjectAltName = IP:#{node['ipaddress']},IP:127.0.0.1\n" + action :create +end + +bash 'signing request for server' do + cmd = 'openssl x509' + cmd += ' -req' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -CA #{caroot}/ca.pem" + cmd += " -CAkey #{caroot}/ca-key.pem" + cmd += ' -CAcreateserial' + cmd += " -in #{caroot}/server.csr" + cmd += " -out #{caroot}/server.pem" + cmd += " -extfile #{caroot}/server-extfile.cnf" + not_if "/usr/bin/test -f #{caroot}/server.pem" + code cmd + action :run +end + +# client certs +bash 'creating private key for docker client' do + code "openssl genrsa -out #{caroot}/key.pem 4096" + not_if "/usr/bin/test -f #{caroot}/key.pem" + action :run +end + +bash 'generating certificate request for client' do + cmd = 'openssl req' + cmd += ' -new' + cmd += " -subj '/CN=client/'" + cmd += " -key #{caroot}/key.pem" + cmd += " -out #{caroot}/client.csr" + code cmd + not_if "/usr/bin/test -f #{caroot}/client.csr" + action :run +end + +file "#{caroot}/client-extfile.cnf" do + content "extendedKeyUsage = clientAuth\n" + action :create +end + +bash 'signing request for client' do + cmd = 'openssl x509' + cmd += ' -req' + cmd += ' -days 365' + cmd += ' -sha256' + cmd += " -CA #{caroot}/ca.pem" + cmd += " -CAkey #{caroot}/ca-key.pem" + cmd += ' -CAcreateserial' + cmd += " -in #{caroot}/client.csr" + cmd += " -out #{caroot}/cert.pem" + cmd += " -extfile #{caroot}/client-extfile.cnf" + code cmd + not_if "/usr/bin/test -f #{caroot}/cert.pem" + action :run +end + +# Set up a test registry to test :push +# https://github.com/docker/distribution/blob/master/docs/authentication.md +# + +docker_image 'nginx' do + tag '1.9' +end + +docker_image 'registry' do + tag '2.6.1' +end + +directory '/tmp/registry/auth' do + recursive true + owner 'root' + mode '0755' + action :create +end + +template '/tmp/registry/auth/registry.conf' do + source 'registry/auth/registry.conf.erb' + owner 'root' + mode '0755' + action :create +end + +# install certificates +execute 'copy server cert for registry' do + command "cp #{caroot}/server.pem /tmp/registry/auth/server.crt" + creates '/tmp/registry/auth/server.crt' + action :run +end + +execute 'copy server key for registry' do + command "cp #{caroot}/server-key.pem /tmp/registry/auth/server.key" + creates '/tmp/registry/auth/server.key' + action :run +end + +# testuser / testpassword +template '/tmp/registry/auth/registry.password' do + source 'registry/auth/registry.password.erb' + owner 'root' + mode '0755' + action :create +end + +bash 'start docker registry' do + code <<-EOF + docker run \ + -d \ + -p 5000:5000 \ + --name registry_service \ + --restart=always \ + registry:2 + EOF + not_if "[ ! -z `docker ps -qaf 'name=registry_service$'` ]" +end + +bash 'start docker registry proxy' do + code <<-EOF + docker run \ + -d \ + -p 5043:443 \ + --name registry_proxy \ + --restart=always \ + -v /tmp/registry/auth/:/etc/nginx/conf.d \ + nginx:1.9 + EOF + not_if "[ ! -z `docker ps -qaf 'name=registry_proxy$'` ]" +end + +bash 'wait for docker registry and proxy' do + code <<-EOF + i=0 + tries=20 + while true; do + ((i++)) + netstat -plnt | grep ":5000" && netstat -plnt | grep ":5043" + [ $? -eq 0 ] && break + [ $i -eq $tries ] && break + sleep 1 + done + EOF + not_if 'netstat -plnt | grep ":5000" && netstat -plnt | grep ":5043"' +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/service.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/service.rb new file mode 100644 index 0000000..91fe52a --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/service.rb @@ -0,0 +1,7 @@ +docker_service 'default' do + storage_driver 'overlay2' + bip '10.10.10.0/24' + default_ip_address_pool 'base=10.10.10.0/16,size=24' + service_manager 'systemd' + action [:create, :start] +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/smoke.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/smoke.rb new file mode 100644 index 0000000..46b167d --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/smoke.rb @@ -0,0 +1,84 @@ +######################### +# service named 'default' +######################### + +docker_service 'default' do + install_method 'package' + graph '/var/lib/docker' + action [:create, :start] +end + +################ +# simple process +################ + +docker_image 'busybox' do + host 'unix:///var/run/docker.sock' +end + +docker_container 'service default echo server' do + container_name 'an_echo_server' + repo 'busybox' + command 'nc -ll -p 7 -e /bin/cat' + port '7' + action :run +end + +##################### +# squid forward proxy +##################### + +directory '/etc/squid_forward_proxy' do + recursive true + owner 'root' + mode '0755' + action :create +end + +template '/etc/squid_forward_proxy/squid.conf' do + source 'squid_forward_proxy/squid.conf.erb' + owner 'root' + mode '0755' + notifies :redeploy, 'docker_container[squid_forward_proxy]' + action :create +end + +docker_image 'cbolt/squid' do + tag 'latest' + action :pull +end + +docker_container 'squid_forward_proxy' do + repo 'cbolt/squid' + tag 'latest' + restart_policy 'on-failure' + kill_after 5 + port '3128:3128' + command '/usr/sbin/squid -NCd1' + volumes '/etc/squid_forward_proxy/squid.conf:/etc/squid/squid.conf' + subscribes :redeploy, 'docker_image[cbolt/squid]' + action :run +end + +############# +# service one +############# + +docker_service 'one' do + graph '/var/lib/docker-one' + host 'unix:///var/run/docker-one.sock' + http_proxy 'http://127.0.0.1:3128' + https_proxy 'http://127.0.0.1:3128' + action :start +end + +docker_image 'hello-world' do + host 'unix:///var/run/docker-one.sock' + tag 'latest' +end + +docker_container 'hello-world' do + host 'unix:///var/run/docker-one.sock' + command '/hello' + action :create +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/timeout.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/timeout.rb new file mode 100644 index 0000000..87ea968 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/timeout.rb @@ -0,0 +1,35 @@ +# service +include_recipe 'docker_test::default' + +# Build an image that takes longer than two minutes +# (the default read_timeout) to build +# + +docker_image 'centos' + +# Make sure that the image does not exist, to avoid a cache hit +# while building the docker image. This can legitimately fail +# if the image does not exist. +execute 'rmi kkeane/image.4' do + command 'docker rmi kkeane/image.4:chef' + ignore_failure true + action :run +end + +directory '/usr/local/src/container4' do + action :create +end + +cookbook_file '/usr/local/src/container4/Dockerfile' do + source 'Dockerfile_4' + action :create +end + +docker_image 'timeout test image' do + repo 'kkeane/image.4' + read_timeout 3600 # 1 hour + write_timeout 3600 # 1 hour + tag 'chef' + source '/usr/local/src/container4' + action :build_if_missing +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/volume.rb b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/volume.rb new file mode 100644 index 0000000..18eedd8 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/recipes/volume.rb @@ -0,0 +1,54 @@ +########### +# remove_me +########### + +execute 'docker volume create --name remove_me' do + not_if { ::File.exist?('/marker_remove_me') } + action :run +end + +file '/marker_remove_me' do + action :create +end + +docker_volume 'remove_me' do + action :remove +end + +####### +# hello +####### + +docker_volume 'hello' do + action :create +end + +docker_volume 'hello again' do + volume_name 'hello_again' + action :create +end + +################## +# hello containers +################## + +docker_image 'alpine' do + tag '3.1' + action :pull_if_missing +end + +docker_container 'file_writer' do + repo 'alpine' + tag '3.1' + volumes ['hello:/hello'] + command 'touch /hello/sean_was_here' + action :run_if_missing +end + +docker_container 'file_reader' do + repo 'alpine' + tag '3.1' + volumes ['hello:/hello'] + command 'ls /hello/sean_was_here' + action :run_if_missing +end diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/templates/nginx_forward_proxy/proxy.conf.erb b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/nginx_forward_proxy/proxy.conf.erb new file mode 100644 index 0000000..4871e6e --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/nginx_forward_proxy/proxy.conf.erb @@ -0,0 +1,7 @@ +server { + resolver 8.8.8.8; + listen 8080; + location / { + proxy_pass http://$http_host$request_uri; + } +} diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.conf.erb b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.conf.erb new file mode 100644 index 0000000..f9b8d22 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.conf.erb @@ -0,0 +1,38 @@ +upstream docker-registry { + server <%= node['ipaddress'] %>:5000; +} + +server { + listen 443 ssl; + server_name <%= node['ipaddress'] %>; + + # Disable SSL for testing registry + ssl_certificate /etc/nginx/conf.d/server.crt; + ssl_certificate_key /etc/nginx/conf.d/server.key; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + location /v2/ { + # Do not allow connections from docker 1.5 and earlier + # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents + if ($http_user_agent ~* "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*\$" ) { + return 404; + } + + # To add basic authentication to v2 use auth_basic setting plus add_header + auth_basic "registry.localhost"; + auth_basic_user_file /etc/nginx/conf.d/registry.password; + add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always; + + proxy_pass http://docker-registry; + proxy_set_header Host $http_host; # required for docker client's sake + proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 900; + } +} diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.password.erb b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.password.erb new file mode 100644 index 0000000..5f75306 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/registry/auth/registry.password.erb @@ -0,0 +1 @@ +testuser:$apr1$TPsqBp55$icazbv6goXik2yJVSlp7l1 diff --git a/chef/cookbooks/docker/test/cookbooks/docker_test/templates/squid_forward_proxy/squid.conf.erb b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/squid_forward_proxy/squid.conf.erb new file mode 100644 index 0000000..12f4f82 --- /dev/null +++ b/chef/cookbooks/docker/test/cookbooks/docker_test/templates/squid_forward_proxy/squid.conf.erb @@ -0,0 +1,44 @@ +http_port 3128 + +acl localnet src 10.0.0.0/8 # RFC1918 possible internal network +acl localnet src 172.16.0.0/12 # RFC1918 possible internal network +acl localnet src 192.168.0.0/16 # RFC1918 possible internal network +acl localnet src fc00::/7 # RFC 4193 local private network range +acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines + +acl SSL_ports port 443 + +acl Safe_ports port 80 # http +acl Safe_ports port 21 # ftp +acl Safe_ports port 443 # https +acl Safe_ports port 70 # gopher +acl Safe_ports port 210 # wais +acl Safe_ports port 280 # http-mgmt +acl Safe_ports port 488 # gss-http +acl Safe_ports port 591 # filemaker +acl Safe_ports port 777 # multiling http +acl Safe_ports port 1025-65535 # unregistered ports + +acl CONNECT method CONNECT + +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access allow localhost manager +http_access deny manager + +# +# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS +# + +http_access allow localnet +http_access allow localhost +http_access deny all + +coredump_dir /squid/var/cache/squid + +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 +refresh_pattern . 0 20% 4320 + +# access_log /dev/stdout diff --git a/chef/cookbooks/docker/test/integration/installation_package/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/installation_package/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..7e3e6cd --- /dev/null +++ b/chef/cookbooks/docker/test/integration/installation_package/inspec/assert_functioning_spec.rb @@ -0,0 +1,10 @@ +if os[:name] == 'amazon' + describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } + end +else + describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/18.06.0/) } + end +end diff --git a/chef/cookbooks/docker/test/integration/installation_script_experimental/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/installation_script_experimental/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..69e763c --- /dev/null +++ b/chef/cookbooks/docker/test/integration/installation_script_experimental/inspec/assert_functioning_spec.rb @@ -0,0 +1,3 @@ +describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } +end diff --git a/chef/cookbooks/docker/test/integration/installation_script_main/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/installation_script_main/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..69e763c --- /dev/null +++ b/chef/cookbooks/docker/test/integration/installation_script_main/inspec/assert_functioning_spec.rb @@ -0,0 +1,3 @@ +describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } +end diff --git a/chef/cookbooks/docker/test/integration/installation_script_test/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/installation_script_test/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..69e763c --- /dev/null +++ b/chef/cookbooks/docker/test/integration/installation_script_test/inspec/assert_functioning_spec.rb @@ -0,0 +1,3 @@ +describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } +end diff --git a/chef/cookbooks/docker/test/integration/installation_tarball/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/installation_tarball/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..3b39f8a --- /dev/null +++ b/chef/cookbooks/docker/test/integration/installation_tarball/inspec/assert_functioning_spec.rb @@ -0,0 +1,4 @@ +describe command('/usr/bin/docker --version') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/18.06.0/) } +end diff --git a/chef/cookbooks/docker/test/integration/network/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/network/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..6675e4d --- /dev/null +++ b/chef/cookbooks/docker/test/integration/network/inspec/assert_functioning_spec.rb @@ -0,0 +1,277 @@ +########### +# reference +########### + +# https://docs.docker.com/engine/reference/commandline/network_create/ + +########### +# network_a +########### + +describe command("docker network ls -qf 'name=network_a$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_a') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "bridge\n" } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_a') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-station-network_a' } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_a') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-base-network_a' } +end + +########### +# network_b +########### + +describe command("docker network ls -qf 'name=network_b$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should be_empty } +end + +########### +# network_c +########### + +describe command("docker network ls -qf 'name=network_c$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_c') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "bridge\n" } +end + +describe command('docker network inspect network_c') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{192\.168\.88\.0/24}) } + its(:stdout) { should match(/192\.168\.88\.1/) } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_c') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-station-network_c' } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_c') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-base-network_c' } +end + +########### +# network_d +########### + +describe command("docker network ls -qf 'name=network_d$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_d') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "bridge\n" } +end + +describe command('docker network inspect network_d') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/a.*192\.168\.89\.2/) } + its(:stdout) { should match(/b.*192\.168\.89\.3/) } +end + +########### +# network_e +########### + +describe command("docker network ls -qf 'name=network_e$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_e') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "overlay\n" } +end + +########### +# network_f +########### + +describe command("docker network ls -qf 'name=network_f$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_f') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "bridge\n" } +end + +describe command('docker network inspect network_f') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{Subnet.*172\.28\.0\.0/16}) } + its(:stdout) { should match(%r{IPRange.*172\.28\.5\.0/24}) } + its(:stdout) { should match(/Gateway.*172\.28\.5\.254/) } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_f') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-station-network_f' } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_f') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-base-network_f' } +end + +describe command('docker inspect -f "{{ .NetworkSettings.Networks.network_f.IPAddress }}" echo-base-network_f') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match '172.28.5.5' } +end + +########### +# network_g +########### + +describe command("docker network ls -qf 'name=network_g$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker network inspect -f "{{ .Driver }}" network_g') do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "overlay\n" } +end + +describe command('docker network inspect network_g') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{Subnet.*192\.168\.0\.0/16}) } + its(:stdout) { should match(%r{IPRange.*192\.168\.1\.0/24}) } + its(:stdout) { should match(/Gateway.*192\.168\.0\.100/) } + its(:stdout) { should match(/a.*192\.168\.1\.5/) } + its(:stdout) { should match(/a.*192\.168\.1\.5/) } + its(:stdout) { should match(%r{Subnet.*192\.170\.0\.0/16}) } + its(:stdout) { should match(/Gateway.*192\.170\.0\.100/) } + its(:stdout) { should match(/a.*192\.170\.1\.5/) } + its(:stdout) { should match(/a.*192\.170\.1\.5/) } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_g') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-station-network_g' } +end + +describe command('docker network inspect -f "{{ .Containers }}" network_g') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'echo-base-network_g' } +end + +########### +# network_h +########### + +describe command("docker network ls -qf 'name=network_h1$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command("docker network inspect -f '{{ range $c:=.Containers }}{{ $c.Name }}{{ end }}' network_h1") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match 'container1-network_h' } +end + +describe command("docker network inspect -f '{{ range $c:=.Containers }}{{ $c.Name }}{{ end }}' network_h2") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'container1-network_h' } +end + +############## +# network_ipv4 +############## + +describe command("docker network ls -qf 'name=network_ipv4$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command("docker network inspect -f '{{ .EnableIPv6 }}' network_ipv4") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'false' } +end + +describe command("docker network inspect -f '{{ .Internal }}' network_ipv4") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'false' } +end + +############## +# network_ipv6 +############## + +describe command("docker network ls -qf 'name=network_ipv6$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command("docker network inspect -f '{{ .EnableIPv6 }}' network_ipv6") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'true' } +end + +describe command("docker network inspect -f '{{ range $i:=.IPAM.Config }}{{ .Subnet | printf \"%s\\n\" }}{{ end }}' network_ipv6") do + its(:exit_status) { should eq 0 } + its(:stdout) { should include 'fd00:dead:beef::/48' } +end + +################## +# network_internal +################## + +describe command("docker network ls -qf 'name=network_internal'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command("docker network inspect -f '{{ .Internal }}' network_internal") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match 'true' } +end + +# describe command('docker network inspect test-network') do +# its(:exit_status) { should eq 0 } +# end + +# describe command('docker network inspect test-network-overlay') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(/Driver.*overlay/) } +# end + +# describe command('docker network inspect test-network-ip') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(%r{Subnet.*192\.168\.88\.0/24}) } +# its(:stdout) { should match(/Gateway.*192\.168\.88\.3/) } +# end + +# describe command('docker network inspect test-network-aux') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(/a.*192\.168\.89\.4/) } +# its(:stdout) { should match(/b.*192\.168\.89\.5/) } +# end + +# describe command('docker network inspect test-network-ip-range') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match('asdf') } +# end + +# describe command('docker network inspect test-network-connect') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should include(network_container['Id']) } +# end diff --git a/chef/cookbooks/docker/test/integration/resources/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/resources/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..2d76f58 --- /dev/null +++ b/chef/cookbooks/docker/test/integration/resources/inspec/assert_functioning_spec.rb @@ -0,0 +1,962 @@ +volumes_filter = '{{ .Config.Volumes }}' +mounts_filter = '{{ .Mounts }}' +uber_options_network_mode = 'bridge' + +################################################## +# test/cookbooks/docker_test/recipes/default.rb +################################################## + +# docker_service[default] + +describe docker.version do + its('Server.Version') { should eq '18.06.0-ce' } +end + +describe command('docker info') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/environment=/) } + its(:stdout) { should match(/foo=/) } +end + +############################################## +# test/cookbooks/docker_test/recipes/image.rb +############################################## + +# test/cookbooks/docker_test/recipes/image.rb + +# docker_image[hello-world] + +describe docker_image('hello-world:latest') do + it { should exist } + its('repo') { should eq 'hello-world' } + its('tag') { should eq 'latest' } +end + +# docker_image[Tom's container] + +describe docker_image('tduffield/testcontainerd:latest') do + it { should exist } + its('repo') { should eq 'tduffield/testcontainerd' } + its('tag') { should eq 'latest' } +end + +# docker_image[busybox] + +describe docker_image('busybox:latest') do + it { should exist } + its('repo') { should eq 'busybox' } + its('tag') { should eq 'latest' } +end + +# docker_image[alpine] + +describe docker_image('alpine:3.1') do + it { should exist } + its('repo') { should eq 'alpine' } + its('tag') { should eq '3.1' } +end + +describe docker_image('alpine:2.7') do + it { should exist } + its('repo') { should eq 'alpine' } + its('tag') { should eq '2.7' } +end + +# docker_image[vbatts/slackware] + +describe docker_image('vbatts/slackware:latest') do + it { should_not exist } + its('repo') { should_not eq 'vbatts/slackware' } + its('tag') { should_not eq 'latest' } +end +# docker_image[save cirros] + +describe file('/cirros.tar') do + it { should be_file } + its('mode') { should cmp '0644' } +end + +# docker_image[load cirros] + +describe docker_image('cirros:latest') do + it { should exist } + its('repo') { should eq 'cirros' } + its('tag') { should eq 'latest' } +end + +# docker_image[someara/image-1] + +describe docker_image('someara/image-1:v0.1.0') do + it { should exist } + its('repo') { should eq 'someara/image-1' } + its('tag') { should eq 'v0.1.0' } +end + +# docker_image[someara/image.2] + +describe docker_image('someara/image.2:v0.1.0') do + it { should exist } + its('repo') { should eq 'someara/image.2' } + its('tag') { should eq 'v0.1.0' } +end + +# docker_image[image_3] + +describe docker_image('image_3:v0.1.0') do + it { should exist } + its('repo') { should eq 'image_3' } + its('tag') { should eq 'v0.1.0' } +end + +# docker_image[name-w-dashes] + +describe docker_image('localhost:5043/someara/name-w-dashes:latest') do + it { should exist } + its('repo') { should eq 'localhost:5043/someara/name-w-dashes' } + its('tag') { should eq 'latest' } +end + +# docker_tag[private repo tag for name.w.dots:latest / v0.1.0 / / v0.1.1 /] + +describe docker_image('localhost:5043/someara/name.w.dots:latest') do + it { should exist } + its('repo') { should eq 'localhost:5043/someara/name.w.dots' } + its('tag') { should eq 'latest' } +end + +describe docker_image('localhost:5043/someara/name.w.dots:v0.1.0') do + it { should exist } + its('repo') { should eq 'localhost:5043/someara/name.w.dots' } + its('tag') { should eq 'v0.1.0' } +end + +# FIXME: We need to test the "docker_registry" stuff... +# I can't figure out how to search the local registry to see if the +# authentication and :push actions in the test recipe actually worked. +# +# Skipping for now. + +################################################## +# test/cookbooks/docker_test/recipes/container.rb +################################################## + +# docker_container[hello-world] + +describe docker_container('hello-world') do + it { should exist } + it { should_not be_running } +end + +# docker_container[busybox_ls] + +describe docker_container('busybox_ls') do + it { should exist } + it { should_not be_running } +end + +# docker_container[alpine_ls] + +describe docker_container('alpine_ls') do + it { should exist } + it { should_not be_running } +end + +# docker_container[an_echo_server] + +describe docker_container('an_echo_server') do + it { should exist } + it { should be_running } + its('ports') { should eq '0.0.0.0:7->7/tcp' } +end + +# docker_container[another_echo_server] + +describe docker_container('another_echo_server') do + it { should exist } + it { should be_running } + its('ports') { should eq '0.0.0.0:32768->7/tcp' } +end + +# docker_container[an_udp_echo_server] + +describe docker_container('an_udp_echo_server') do + it { should exist } + it { should be_running } + its('ports') { should eq '0.0.0.0:5007->7/udp' } +end + +# docker_container[multi_ip_port] + +describe docker_container('multi_ip_port') do + it { should exist } + it { should be_running } + its('ports') { should eq '0.0.0.0:8301->8301/udp, 127.0.0.1:8500->8500/tcp, 127.0.1.1:8500->8500/tcp, 0.0.0.0:32769->8301/tcp' } +end + +# docker_container[port_range] + +describe command("docker inspect -f '{{ .HostConfig.PortBindings }}' port_range") do + its(:exit_status) { should eq 0 } + its(:stdout) { should include('2000/tcp:[{ }]') } + its(:stdout) { should include('2001/tcp:[{ }]') } + its(:stdout) { should include('2000/udp:[{ }]') } + its(:stdout) { should include('2001/udp:[{ }]') } + its(:stdout) { should include('3000/tcp:[{ }]') } + its(:stdout) { should include('3001/tcp:[{ }]') } + its(:stdout) { should include('8000/tcp:[{0.0.0.0 7000}]') } + its(:stdout) { should include('8001/tcp:[{0.0.0.0 7001}]') } + its(:stdout) { should include('8002/tcp:[{0.0.0.0 7002}]') } +end + +# docker_container[bill] + +describe docker_container('bill') do + it { should exist } + it { should_not be_running } +end + +# docker_container[hammer_time] + +describe docker_container('hammer_time') do + it { should exist } + it { should_not be_running } +end + +describe command("docker ps -af 'name=hammer_time$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited/) } +end + +# docker_container[red_light] + +describe docker_container('red_light') do + it { should exist } + it { should be_running } +end + +describe command("docker ps -af 'name=red_light$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Paused/) } +end + +# docker_container[green_light] + +describe docker_container('green_light') do + it { should exist } + it { should be_running } +end + +# docker_container[quitter] + +describe docker_container('quitter') do + it { should exist } + it { should be_running } +end + +# docker_container[restarter] + +describe docker_container('restarter') do + it { should exist } + it { should be_running } +end + +# docker_container[deleteme] + +describe docker_container('deleteme') do + it { should_not exist } + it { should_not be_running } +end + +# docker_container[redeployer] + +describe docker_container('redeployer') do + it { should exist } + it { should be_running } +end + +# docker_container[unstarted_redeployer] + +describe docker_container('unstarted_redeployer') do + it { should exist } + it { should_not be_running } +end + +# docker_container[bind_mounter] + +describe docker_container('bind_mounter') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .HostConfig.Binds }}" bind_mounter') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\/hostbits\:\/bits}) } + its(:stdout) { should match(%r{\/more-hostbits\:\/more-bits}) } + its(:stdout) { should match(%r{\/winter\:\/spring\:ro}) } +end + +# docker_container[binds_alias] + +describe docker_container('binds_alias') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .HostConfig.Binds }}" binds_alias') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\/fall\:\/sun}) } + its(:stdout) { should match(%r{\/winter\:\/spring\:ro}) } +end + +describe command('docker inspect -f "{{ .Config.Volumes }}" binds_alias') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\/snow\:\{\}}) } + its(:stdout) { should match(%r{\/summer\:\{\}}) } +end + +# docker_container[chef_container] + +describe docker_container('chef_container') do + it { should exist } + it { should_not be_running } +end + +describe command("docker inspect -f \"#{volumes_filter}\" chef_container") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\/opt\/chef\:}) } +end + +# docker_container[ohai_debian] +describe docker_container('ohai_debian') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs ohai_debian') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/debian/) } +end + +describe command("docker inspect -f \"#{mounts_filter}\" ohai_debian") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\/opt\/chef}) } +end + +# docker_container[env] + +describe docker_container('env') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .Config.Env }}" env') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{\[PATH=\/usr\/bin FOO=bar GOODBYE=TOMPETTY 1950=2017\]}) } +end + +# docker_container[env_files] + +describe docker_container('env_files') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .Config.Env }}" env_files') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/\[GOODBYE=TOMPETTY 1950=2017 HELLO=WORLD /) } +end + +# docker_container[ohai_again] +describe docker_container('ohai_again') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs ohai_again') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/ohai_time/) } +end + +# docker_container[cmd_test] + +describe docker_container('cmd_test') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs cmd_test') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/.dockerenv/) } +end + +# docker_container[sean_was_here] +describe docker_container('sean_was_here') do + it { should_not exist } + it { should_not be_running } +end + +describe command('docker run --rm --volumes-from chef_container debian ls -la /opt/chef/') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/sean_was_here-/) } +end + +# docker_container[attached] +describe docker_container('attached') do + it { should exist } + it { should_not be_running } +end + +describe command('docker run --rm --volumes-from chef_container debian ls -la /opt/chef/') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/attached-\d{12}/) } +end + +# docker_container[attached_with_timeout] +describe docker_container('attached_with_timeout') do + it { should exist } + it { should_not be_running } +end + +describe command('docker run --rm --volumes-from chef_container debian ls -la /opt/chef/') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match(/attached_with_timeout-\d{12}/) } +end + +# docker_container[cap_add_net_admin] + +describe docker_container('cap_add_net_admin') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs cap_add_net_admin') do + its(:exit_status) { should eq 0 } + its(:stderr) { should_not match(/RTNETLINK answers: Operation not permitted/) } +end + +# docker_container[cap_add_net_admin_error] + +describe docker_container('cap_add_net_admin_error') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs cap_add_net_admin_error') do + its(:exit_status) { should eq 0 } + its(:stderr) { should match(/RTNETLINK answers: Operation not permitted/) } +end + +# docker_container[cap_drop_mknod] + +describe docker_container('cap_drop_mknod') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs cap_drop_mknod') do + its(:exit_status) { should eq 0 } + its(:stderr) { should match(%r{mknod: /dev/urandom2: Operation not permitted}) } + its(:stderr) { should match(%r{ls: cannot access '/dev/urandom2': No such file or directory}) } +end + +# docker_container[cap_drop_mknod_error] + +describe docker_container('cap_drop_mknod_error') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs cap_drop_mknod_error') do + its(:exit_status) { should eq 0 } + its(:stderr) { should_not match(%r{mknod: '/dev/urandom2': Operation not permitted}) } +end + +# docker_container[fqdn] + +describe docker_container('fqdn') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs fqdn') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/computers.biz/) } +end + +# docker_container[dns] + +describe docker_container('dns') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .HostConfig.Dns }}" dns') do + its(:stdout) { should match(/\[4.3.2.1 1.2.3.4\]/) } +end + +# docker_container[extra_hosts] + +describe docker_container('extra_hosts') do + it { should exist } + it { should_not be_running } +end + +describe command('docker inspect -f "{{ .HostConfig.ExtraHosts }}" extra_hosts') do + its(:stdout) { should match(/\[east:4.3.2.1 west:1.2.3.4\]/) } +end + +# docker_container[devices_sans_cap_sys_admin] + +# describe command("docker ps -af 'name=devices_sans_cap_sys_admin$'") do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(/Exited/) } +# end + +# FIXME: find a method to test this that works across all platforms in test-kitchen +# Is this test invalid? +# describe command("md5sum /root/disk1") do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(/0f343b0931126a20f133d67c2b018a3b/) } +# end + +# docker_container[devices_with_cap_sys_admin] + +# describe command("docker ps -af 'name=devices_with_cap_sys_admin$'") do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should match(/Exited/) } +# end + +# describe command('md5sum /root/disk1') do +# its(:exit_status) { should eq 0 } +# its(:stdout) { should_not match(/0f343b0931126a20f133d67c2b018a3b/) } +# end + +# docker_container[cpu_shares] + +describe docker_container('cpu_shares') do + it { should exist } + it { should_not be_running } +end + +describe command("docker inspect -f '{{ .HostConfig.CpuShares }}' cpu_shares") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/512/) } +end + +# docker_container[cpuset_cpus] + +describe docker_container('cpuset_cpus') do + it { should exist } + it { should_not be_running } +end + +describe command("docker inspect -f '{{ .HostConfig.CpusetCpus }}' cpuset_cpus") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/0,1/) } +end + +# docker_container[try_try_again] + +# FIXME: Find better tests +describe docker_container('try_try_again') do + it { should exist } + it { should_not be_running } +end + +# docker_container[reboot_survivor] + +describe command("docker ps -af 'name=reboot_survivor$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match(/Exited/) } +end + +# docker_container[reboot_survivor_retry] + +describe docker_container('reboot_survivor_retry') do + it { should exist } + it { should be_running } +end + +# docker_container[link_source] + +describe docker_container('link_source') do + it { should exist } + it { should be_running } +end + +# docker_container[link_source_2] + +describe docker_container('link_source_2') do + it { should exist } + it { should be_running } +end + +# docker_container[link_target_1] + +describe docker_container('link_target_1') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs link_target_1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match(/ping: bad address 'hello'/) } +end + +# docker_container[link_target_2] + +describe docker_container('link_target_2') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs link_target_2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{HELLO_NAME=/link_target_2/hello}) } +end + +# docker_container[link_target_3] + +describe docker_container('link_target_3') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs link_target_3') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match(/ping: bad address 'hello_again'/) } +end + +describe command("docker inspect -f '{{ .HostConfig.Links }}' link_target_3") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[/link_source:/link_target_3/hello /link_source_2:/link_target_3/hello_again]}) } +end + +# docker_container[link_target_4] + +describe docker_container('link_target_4') do + it { should exist } + it { should_not be_running } +end + +describe command('docker logs link_target_4') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{HELLO_NAME=/link_target_4/hello}) } + its(:stdout) { should match(%r{HELLO_AGAIN_NAME=/link_target_4/hello_again}) } +end + +describe command("docker inspect -f '{{ .HostConfig.Links }}' link_target_4") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[/link_source:/link_target_4/hello /link_source_2:/link_target_4/hello_again]}) } +end + +# docker_container[dangler] + +# describe command('ls -la `cat /dangler_volpath`') do +# its(:exit_status) { should_not eq 0 } +# end + +# FIXME: this changed with 1.8.x. Find a way to sanely test across various platforms + +# docker_container[mutator] + +describe docker_container('mutator') do + it { should exist } + it { should_not be_running } +end + +describe file('/mutator.tar') do + it { should be_file } + its('mode') { should cmp '0644' } +end + +# docker_container[network_mode] + +describe docker_container('network_mode') do + it { should exist } + it { should be_running } +end + +describe command("docker inspect -f '{{ .HostConfig.NetworkMode }}' network_mode") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/host/) } +end + +# docker_container[oom_kill_disable] + +describe command("docker ps -af 'name=oom_kill_disable$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.OomKillDisable }}' oom_kill_disable") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'true' } +end + +# docker_container[oom_score_adj] + +describe command("docker ps -af 'name=oom_score_adj$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.OomScoreAdj }}' oom_score_adj") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/600/) } +end + +# docker_container[ulimits] +describe docker_container('ulimits') do + it { should exist } + it { should be_running } +end + +describe command("docker inspect -f '{{ .HostConfig.Ulimits }}' ulimits") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/nofile=40960:40960 core=100000000:100000000 memlock=100000000:100000000/) } +end + +# docker_container[uber_options] +describe docker_container('uber_options') do + it { should exist } + it { should be_running } +end + +describe command("docker inspect -f '{{ .Config.Domainname }}' uber_options") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/computers.biz/) } +end + +describe command("docker inspect -f '{{ .Config.MacAddress }}' uber_options") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/00:00:DE:AD:BE:EF/) } +end + +describe command("docker inspect -f '{{ .HostConfig.Ulimits }}' uber_options") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/nofile=40960:40960 core=100000000:100000000 memlock=100000000:100000000/) } +end + +describe command("docker inspect -f '{{ .HostConfig.NetworkMode }}' uber_options") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/#{uber_options_network_mode}/) } +end + +# docker inspect returns the labels unsorted +describe command("docker inspect -f '{{ .Config.Labels }}' uber_options") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/foo:bar/) } + its(:stdout) { should match(/hello:world/) } +end + +# docker_container[overrides-1] + +describe docker_container('overrides-1') do + it { should exist } + it { should be_running } +end + +describe command('docker inspect -f "{{ .Config.User }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/bob/) } +end + +describe command('docker inspect -f "{{ .Config.Env }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin FOO=foo BAR=bar BIZ=biz BAZ=baz]}) } +end + +describe command('docker inspect -f "{{ .Config.Entrypoint }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/\[\]/) } +end + +describe command('docker inspect -f "{{ .Config.Cmd }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[ls -la /]}) } +end + +describe command('docker inspect -f "{{ .Config.WorkingDir }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{/var}) } +end + +describe command('docker inspect -f "{{ .Config.Volumes }}" overrides-1') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{map\[/home:{}\]}) } +end + +# docker_container[overrides-2] + +describe docker_container('overrides-2') do + it { should exist } + it { should be_running } +end + +describe command('docker inspect -f "{{ .Config.User }}" overrides-2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/operator/) } +end + +describe command('docker inspect -f "{{ .Config.Env }}" overrides-2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[FOO=biz PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin BAR=bar BIZ=biz BAZ=baz]}) } +end + +describe command('docker inspect -f "{{ .Config.Entrypoint }}" overrides-2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[/bin/sh -c]}) } +end + +describe command('docker inspect -f "{{ .Config.Cmd }}" overrides-2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{[ls -laR /]}) } +end + +describe command('docker inspect -f "{{ .Config.WorkingDir }}" overrides-2') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{/tmp}) } +end + +# docker_container[syslogger] + +describe docker_container('syslogger') do + it { should exist } + it { should be_running } +end + +describe command("docker inspect -f '{{ .HostConfig.LogConfig.Type }}' syslogger") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/syslog/) } +end + +describe command("docker inspect -f '{{ .HostConfig.LogConfig.Config }}' syslogger") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/tag:container-syslogger/) } +end + +# docker_container[host_override] + +describe docker_container('host_override') do + it { should exist } + it { should_not be_running } +end + +# docker_container[kill_after] + +describe docker_container('kill_after') do + it { should exist } + it { should_not be_running } +end + +kill_after_start = command("docker inspect -f '{{.State.StartedAt}}' kill_after").stdout +kill_after_start = DateTime.parse(kill_after_start).to_time.to_i + +kill_after_finish = command("docker inspect -f '{{.State.FinishedAt}}' kill_after").stdout +kill_after_finish = DateTime.parse(kill_after_finish).to_time.to_i + +kill_after_run_time = kill_after_finish - kill_after_start + +describe kill_after_run_time do + it { should be_within(5).of(1) } +end + +# docker_container[pid_mode] + +describe command("docker ps -af 'name=pid_mode$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.PidMode }}' pid_mode") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'host' } +end + +# docker_container[init] + +describe command("docker ps -af 'name=init$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.Init }}' init") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'true' } +end + +# docker_container[ipc_mode] + +describe command("docker ps -af 'name=ipc_mode$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.IpcMode }}' ipc_mode") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'host' } +end + +# docker_container[uts_mode] + +describe command("docker ps -af 'name=uts_mode$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/Exited \(0\)/) } +end + +describe command("docker inspect --format '{{ .HostConfig.UTSMode }}' uts_mode") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'host' } +end + +describe command("docker inspect --format '{{ .HostConfig.ReadonlyRootfs }}' ro_rootfs") do + its(:exit_status) { should eq 0 } + its(:stdout) { eq 'true' } +end + +# sysctls +describe command("docker inspect --format '{{ .HostConfig.Sysctls }}' sysctls") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/net.core.somaxconn:65535/) } + its(:stdout) { should match(/net.core.xfrm_acq_expires:42/) } +end + +# cmd_change + +describe command("docker inspect -f '{{ .Config.Cmd }}' cmd_change") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/nc -ll -p 9/) } +end + +# docker_container[memory] + +describe command("docker inspect -f '{{ .HostConfig.KernelMemory }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/10485760/) } +end + +describe command("docker inspect -f '{{ .HostConfig.Memory }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/5242880/) } +end + +describe command("docker inspect -f '{{ .HostConfig.MemorySwap }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/5242880/) } +end + +describe command("docker inspect -f '{{ .HostConfig.MemorySwappiness }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/50/) } +end + +describe command("docker inspect -f '{{ .HostConfig.MemoryReservation }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/5242880/) } +end + +describe command("docker inspect -f '{{ .HostConfig.ShmSize }}' memory") do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/67108864/) } +end diff --git a/chef/cookbooks/docker/test/integration/smoke/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/smoke/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..f640999 --- /dev/null +++ b/chef/cookbooks/docker/test/integration/smoke/inspec/assert_functioning_spec.rb @@ -0,0 +1,23 @@ +# service named 'default' +describe command('docker images') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/busybox/) } +end + +describe command('docker ps -a') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/an_echo_server/) } +end + +# service one +describe command('docker --host=unix:///var/run/docker-one.sock images') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/^hello-world/) } + its(:stdout) { should_not match(/^alpine/) } +end + +describe command('docker --host=unix:///var/run/docker-one.sock ps -a') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/hello-world/) } + its(:stdout) { should_not match(/an_echo_server/) } +end diff --git a/chef/cookbooks/docker/test/integration/volume/inspec/assert_functioning_spec.rb b/chef/cookbooks/docker/test/integration/volume/inspec/assert_functioning_spec.rb new file mode 100644 index 0000000..6182ef8 --- /dev/null +++ b/chef/cookbooks/docker/test/integration/volume/inspec/assert_functioning_spec.rb @@ -0,0 +1,43 @@ +########### +# reference +########### + +# https://docs.docker.com/engine/reference/commandline/volume_create/ + +########### +# remove_me +########### + +describe command('docker volume ls -q') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match(/^remove_me$/) } +end + +####### +# hello +####### + +describe command('docker volume ls -q') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(/^hello$/) } + its(:stdout) { should match(/^hello_again$/) } +end + +################## +# hello containers +################## + +describe command("docker ps -qaf 'name=file_writer$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command("docker ps -qaf 'name=file_reader$'") do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not be_empty } +end + +describe command('docker logs file_reader') do + its(:exit_status) { should eq 0 } + its(:stdout) { should match(%r{/hello/sean_was_here}) } +end