diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a05e3..4b2e5dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,160 +1,168 @@ +# Version 3.2.0 + +Adds in support for Puppet 6 + +Containers will be restared due to script changes in [PR #367](https://github.com/puppetlabs/puppetlabs-docker/pull/367) + +A full list of issues and PRs associated with this release can be found [here](https://github.com/puppetlabs/puppetlabs-docker/milestone/4?closed=1) + # Version 3.1.0 Adding in the following faetures/functionality - Docker Stack support on Windows. # Version 3.0.0 Various fixes for github issues - 206 - 226 - 241 - 280 - 281 - 287 - 289 - 294 - 303 - 312 - 314 Adding in the following features/functionality -Support for multiple compose files. A full list of issues and PRs associated with this release can be found [here](https://github.com/puppetlabs/puppetlabs-docker/issues?q=is%3Aissue+milestone%3AV3.0.0+is%3Aclosed) # Version 2.0.0 Various fixes for github issues - 193 - 197 - 198 - 203 - 207 - 208 - 209 - 211 - 212 - 213 - 215 - 216 - 217 - 218 - 223 - 224 - 225 - 228 - 229 - 230 - 232 - 234 - 237 - 243 - 245 - 255 - 256 - 259 Adding in the following features/functionality - Ability to define swarm clusters in Hiera. - Support docker compose file V2.3. - Support refresh only flag. - Support for Docker healthcheck and unhealthy container restart. - Support for Docker on Windows: - Add docker ee support for windows server 2016. - Docker image on Windows. - Docker run on Windows. - Docker compose on Windows. - Docker swarm on Windows. - Add docker exec functionality for docker on windows. - Add storage driver for Windows. A full list of issues and PRs associated with this release can be found [here](https://github.com/puppetlabs/puppetlabs-docker/milestone/2?closed=1) # Version 1.1.0 Various fixes for Github issues - 183 - 173 - 173 - 167 - 163 - 161 Adding in the following features/functionality - IPv6 support - Define type for docker plugins A full list of issues and PRs associated with this release can be found [here](https://github.com/puppetlabs/puppetlabs-docker/milestone/1?closed=1) # Version 1.0.5 Various fixes for Github issues - 98 - 104 - 115 - 122 - 124 Adding in the following features/functionality - Removed all unsupported OS related code from module - Removed EPEL dependency - Added http support in compose proxy - Added in rubocop support and i18 gem support - Type and provider for docker volumes - Update apt module to latest - Added in support for a registry mirror - Facts for docker version and docker info - Fixes for $pass_hash undef - Fixed typo in param.pp - Replaced deprecated stblib functions with data types # Version 1.0.4 Correcting changelog # Version 1.0.3 Various fixes for Github issues - 33 - 68 - 74 - 77 - 84 Adding in the following features/functionality: - Add tasks to update existing service - Backwards compatible TMPDIR - Optional GPG check on repos - Force pull on image tag 'latest' - Add support for overlay2.override_kernel_check setting - Add docker network fact - Add pw hash for registry login idompodency - Additional flags for creating a network - Fixing incorrect repo url for redhat # Version 1.0.2 Various fixes for Github issues - 9 - 11 - 15 - 21 Add tasks support for Docker Swarm # Version 1.0.1 Updated metadata and CHANGELOG # Version 1.0.0 Forked for garethr/docker v5.3.0 Added support for: - Docker services within a swarm cluster - Swarm mode - Docker secrets diff --git a/metadata.json b/metadata.json index ba707d6..4d86664 100755 --- a/metadata.json +++ b/metadata.json @@ -1,76 +1,76 @@ { "name": "puppetlabs-docker", - "version": "3.1.0", + "version": "3.2.0", "author": "Puppet Labs", "summary": "Module for installing and managing docker", "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-docker.git", "project_page": "https://github.com/puppetlabs/puppetlabs-docker", "issues_url": "https://github.com/puppetlabs/puppetlabs-docker/issues", "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.24.0 <= 5.1.0" }, { "name": "puppetlabs/apt", "version_requirement": ">= 4.4.1 <= 6.2.1" }, { "name": "puppetlabs/translate", "version_requirement": ">= 0.0.1 <=1.1.0" }, { "name": "puppetlabs/powershell", "version_requirement": ">= 2.1.4 <= 2.2.0" }, { "name": "puppetlabs/reboot", "version_requirement": "2.0.0" } ], "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "7" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "7" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04", "18.04" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "8.0", "9.0" ] }, { "operatingsystem": "Windows", "operatingsystemrelease": [ "Server 2016" ] } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 4.0.0 <=5.5.6" + "version_requirement": ">= 4.2.1 < 7.0.0" } ], "pdk-version": "1.8.0", "template-url": "file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git", "template-ref": "1.8.0-0-g0d9da00" } \ No newline at end of file diff --git a/spec/acceptance/compose_v3_spec.rb b/spec/acceptance/compose_v3_spec.rb index b9b93f3..5ed8971 100644 --- a/spec/acceptance/compose_v3_spec.rb +++ b/spec/acceptance/compose_v3_spec.rb @@ -1,153 +1,153 @@ require 'spec_helper_acceptance' if fact('osfamily') == 'windows' install_dir = '/cygdrive/c/Program Files/Docker' file_extension = '.exe' docker_args = 'docker_ee => true' tmp_path = 'C:/cygwin64/tmp' test_container = 'nanoserver-sac2016' else if fact('osfamily') == 'RedHat' - docker_args = "repo_opt => '--enablerepo=localmirror-extras'" + docker_args = "repo_opt => '--enablerepo=localmirror-everything'" else docker_args = '' end install_dir = '/usr/local/bin' file_extension = '' tmp_path = '/tmp' test_container = 'debian' end describe 'docker compose' do before(:all) do retry_on_error_matching(60, 5, /connection failure running/) do install_code = <<-code class { 'docker': #{docker_args} } class { 'docker::compose': version => '1.23.2', } code apply_manifest(install_code, :catch_failures=>true) end end context 'Creating compose v3 projects' do it 'should have docker compose installed' do shell('docker-compose --help', :acceptable_exit_codes => [0]) end before(:all) do @install = <<-code docker_compose { 'web': compose_files => ['#{tmp_path}/docker-compose-v3.yml'], ensure => present, } code apply_manifest(@install, :catch_failures=>true) end it 'should be idempotent' do apply_manifest(@install, :catch_changes=>true) end it 'should find a docker container' do shell('docker inspect web_compose_test_1', :acceptable_exit_codes => [0]) end end context 'creating compose projects with multi compose files' do before(:all) do @install = <<-pp1 docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => present, } pp1 apply_manifest(@install, :catch_failures=>true) end it "should find container with #{test_container} tag" do shell("docker inspect web1_compose_test_1 | grep #{test_container}", :acceptable_exit_codes => [0]) end end context 'Destroying project with multiple compose files' do before(:all) do @install = <<-pp1 docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => present, } pp1 @destroy = <<-pp2 docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => absent, } pp2 apply_manifest(@install, :catch_failures=>true) apply_manifest(@destroy, :catch_failures=>true) end it 'should be idempotent' do apply_manifest(@destroy, :catch_changes=>true) end it 'should not find a docker container' do shell('docker inspect web1_compose_test_1', :acceptable_exit_codes => [1]) end end context 'Requesting a specific version of compose' do before(:all) do @version = '1.21.2' @pp = <<-code class { 'docker::compose': version => '#{@version}', } code apply_manifest(@pp, :catch_failures=>true) end it 'should be idempotent' do apply_manifest(@pp, :catch_changes=>true) end it 'should have installed the requested version' do shell('docker-compose --version', :acceptable_exit_codes => [0]) do |r| expect(r.stdout).to match(/#{@version}/) end end end context 'Removing docker compose' do before(:all) do @version = '1.21.2' @pp = <<-code class { 'docker::compose': ensure => absent, version => '#{@version}', } code apply_manifest(@pp, :catch_failures=>true) end it 'should be idempotent' do apply_manifest(@pp, :catch_changes=>true) end it 'should have removed the relevant files' do shell("test -e \"#{install_dir}/docker-compose#{file_extension}\"", :acceptable_exit_codes => [1]) shell("test -e \"#{install_dir}/docker-compose-#{@version}#{file_extension}\"", :acceptable_exit_codes => [1]) end after(:all) do install_code = <<-code class { 'docker': #{docker_args}} class { 'docker::compose': } code apply_manifest(install_code, :catch_failures=>true) end end end diff --git a/spec/acceptance/docker_full_spec.rb b/spec/acceptance/docker_full_spec.rb index cb3c6e0..db5ca30 100644 --- a/spec/acceptance/docker_full_spec.rb +++ b/spec/acceptance/docker_full_spec.rb @@ -1,970 +1,970 @@ require 'spec_helper_acceptance' if fact('operatingsystem') == 'windows' docker_args = 'docker_ee => true' default_image = 'microsoft/nanoserver' default_image_tag = '10.0.14393.2189' second_image = 'hello-world' default_digest = 'sha256:204c41542c0927ac0296802e44c56b886b47e99cf8220fb49d46951bd5fc1742' default_dockerfile = 'C:/Users/Administrator/AppData/Local/Temp/Dockerfile' dockerfile_test = 'C:/Windows/Dockerfile_test.txt' #The default args are set because: #restart => 'always' - there is no service created to manage containers #net => 'nat' - docker uses bridged by default when running a container. When installing docker on windows the default network is NAT. default_docker_run_arg = "restart => 'always', net => 'nat'," default_run_command = "ping 127.0.0.1 -t" docker_command = "\"/cygdrive/c/Program Files/Docker/docker\"" default_docker_exec_lr_command = 'cmd /c "ping 127.0.0.1 -t > c:\windows\temp\test_file.txt"' default_docker_exec_command = 'cmd /c "echo test > c:\windows\temp\test_file.txt"' docker_mount_path = 'C:/Users/Administrator/AppData/Local/Temp' storage_driver = "windowsfilter" elsif fact('operatingsystem') =~ (/RedHat|CentOS/) - docker_args = "repo_opt => '--enablerepo=localmirror-extras'" + docker_args = "repo_opt => '--enablerepo=localmirror-everything'" default_image = 'alpine' second_image = 'busybox' default_image_tag = '3.7' default_digest = 'sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a' default_dockerfile = '/root/Dockerfile' dockerfile_test = "#{default_dockerfile}_test.txt" docker_command = "docker" default_docker_run_arg = '' default_run_command = "init" default_docker_exec_lr_command = '/bin/sh -c "touch /root/test_file.txt; while true; do echo hello world; sleep 1; done"' default_docker_exec_command = 'touch /root/test_file.txt' docker_mount_path = "/root" storage_driver = "devicemapper" else docker_args = '' default_image = 'alpine' second_image = 'busybox' default_image_tag = '3.7' default_digest = 'sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a' default_dockerfile = '/root/Dockerfile' dockerfile_test = "#{default_dockerfile}_test.txt" docker_command = "docker" default_docker_run_arg = '' default_run_command = "init" default_docker_exec_lr_command = '/bin/sh -c "touch /root/test_file.txt; while true; do echo hello world; sleep 1; done"' default_docker_exec_command = 'touch /root/test_file.txt' docker_mount_path = "/root" if fact('os.release.major') =~ (/14.04|^8$/) storage_driver = "aufs" else storage_driver = "overlay2" end end describe 'the Puppet Docker module' do context 'clean up before each test' do before(:each) do retry_on_error_matching(60, 5, /connection failure running/) do # Stop all container using systemd shell('ls -D -1 /etc/systemd/system/docker-container* | sed \'s/\/etc\/systemd\/system\///g\' | sed \'s/\.service//g\' | while read container; do service $container stop; done') # Delete all running containers shell("#{docker_command} rm -f $(#{docker_command} ps -a -q) || true") # Delete all existing images shell("#{docker_command} rmi -f $(#{docker_command} images -q) || true") # Check to make sure no images are present shell("#{docker_command} images | wc -l") do |r| expect(r.stdout).to match(/^0|1$/) end # Check to make sure no running containers are present shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(/^0|1$/) end end end describe 'docker class' do context 'without any parameters' do let(:pp) {" class { 'docker': #{docker_args} } "} it 'should run successfully' do apply_manifest(pp, :catch_failures => true) end it 'should run idempotently' do apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' end it 'should be start a docker process' do if fact('osfamily') == 'windows' shell('powershell Get-Process -Name dockerd') do |r| expect(r.stdout).to match(/ProcessName/) end else shell('ps aux | grep docker') do |r| expect(r.stdout).to match(/dockerd -H unix:\/\/\/var\/run\/docker.sock/) end end end it 'should install a working docker client' do shell("#{docker_command} ps", :acceptable_exit_codes => [0] ) end it 'should stop a running container and remove container' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6': image => '#{default_image}', command => '#{default_run_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6': ensure => 'absent', image => '#{default_image}', require => Docker::Image['#{default_image}'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 15 shell("#{docker_command} ps", :acceptable_exit_codes => [0]) apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 15 shell("#{docker_command} inspect container-3-6", :acceptable_exit_codes => [1]) if fact('osfamily') == 'windows' shell('test -f /cygdrive/c/Users/Administrator/AppData/Local/Temp/container-3-6.service', :acceptable_exit_codes => [1]) else shell('test -f /etc/systemd/system/container-3-6.service', :acceptable_exit_codes => [1]) end end end context 'passing a storage driver' do before(:all) do @pp=<<-EOS class {'docker': #{docker_args}, storage_driver => "#{storage_driver}", } EOS apply_manifest(@pp, :catch_failures => true) sleep 15 end it 'should result in the docker daemon being configured with the specified storage driver' do shell("#{docker_command} info -f \"{{ .Driver}}\"") do |r| expect(r.stdout).to match (/#{storage_driver}/) end end end context 'passing a TCP address to bind to' do before(:all) do @pp =<<-EOS class { 'docker': tcp_bind => 'tcp://127.0.0.1:4444', #{docker_args} } EOS apply_manifest(@pp, :catch_failures => true) # A sleep to give docker time to execute properly sleep 4 end it 'should run idempotently' do apply_manifest(@pp, :catch_changes => true) unless fact('selinux') == 'true' end it 'should result in docker listening on the specified address' do if fact('osfamily') == 'windows' shell('netstat -a -b') do |r| expect(r.stdout).to match(/127.0.0.1:4444/) end else shell('netstat -tulpn | grep docker') do |r| expect(r.stdout).to match(/tcp\s+0\s+0\s+127.0.0.1:4444\s+0.0.0.0\:\*\s+LISTEN\s+\d+\/docker/) end end end end context 'bound to a particular unix socket' do before(:each) do @pp =<<-EOS class { 'docker': socket_bind => 'unix:///var/run/docker.sock', #{docker_args} } EOS apply_manifest(@pp, :catch_failures => true) # A sleep to give docker time to execute properly sleep 4 end it 'should run idempotently' do apply_manifest(@pp, :catch_changes => true) unless fact('selinux') == 'true' end it 'should show docker listening on the specified unix socket' do if fact('osfamily') != 'windows' shell('ps aux | grep docker') do |r| expect(r.stdout).to match(/unix:\/\/\/var\/run\/docker.sock/) end end end end context 'uninstall docker' do after(:all) do @pp =<<-EOS class {'docker': #{docker_args}, ensure => 'present' } EOS apply_manifest(@pp, :catch_failures => true) # Wait for reboot if windows sleep 300 if fact('osfamily') == 'windows' end it 'should uninstall successfully' do @pp =<<-EOS class {'docker': #{docker_args}, ensure => 'absent' } EOS apply_manifest(@pp, :catch_failures => true) sleep 4 shell('docker ps', :acceptable_exit_codes => [1, 127]) end end end describe 'docker::image' do it 'should successfully download an image from the Docker Hub' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': ensure => present, require => Class['docker'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} images") do |r| expect(r.stdout).to match(/#{default_image}/) end end it 'should successfully download an image based on a tag from the Docker Hub' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': ensure => present, image_tag => '#{default_image_tag}', require => Class['docker'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} images") do |r| expect(r.stdout).to match(/#{default_image}\s+#{default_image_tag}/) end end it 'should successfully download an image based on a digest from the Docker Hub' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': ensure => present, image_digest => '#{default_digest}', require => Class['docker'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} images --digests") do |r| expect(r.stdout).to match(/#{default_image}.*#{default_digest}/) end end it 'should create a new image based on a Dockerfile' do if fact('osfamily') == 'windows' run_cmd = 'RUN echo test > C:\\Windows\\Temp\\Dockerfile_test.txt' else run_cmd = "RUN echo test > #{dockerfile_test}" end pp=<<-EOS class { 'docker': #{docker_args} } docker::image { 'alpine_with_file': docker_file => "#{default_dockerfile}", require => Class['docker'], } file { '#{default_dockerfile}': ensure => present, content => "FROM #{default_image}\n#{run_cmd}", before => Docker::Image['alpine_with_file'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 if fact('osfamily') == 'windows' shell("#{docker_command} run alpine_with_file cmd /c dir Windows\\\\Temp") do |r| expect(r.stdout).to match(/_test.txt/) end else shell("#{docker_command} run alpine_with_file ls #{dockerfile_test}") do |r| expect(r.stdout).to match(/#{dockerfile_test}/) end end end it 'should create a new image based on a tar', :win_broken => true do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], ensure => present, } docker::run { 'container_2_4': image => '#{default_image}', command => '/bin/sh -c "touch /root/test_file_for_tar_test.txt; while true; do echo hello world; sleep 1; done"', require => Docker::Image['alpine'], } EOS pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { 'alpine_from_commit': docker_tar => "/root/rootfs.tar" } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 # Commit currently running container as an image container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") shell("#{docker_command} commit #{container_id.stdout.strip} alpine_from_commit") # Stop all container using systemd shell('ls -D -1 /etc/systemd/system/docker-container* | sed \'s/\/etc\/systemd\/system\///g\' | sed \'s/\.service//g\' | while read container; do service $container stop; done') # Stop all running containers shell("#{docker_command} rm -f $(docker ps -a -q) || true") # Make sure no other containers are running shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(/^1$/) end # Export new to a tar file shell("#{docker_command} save alpine_from_commit > /root/rootfs.tar") # Remove all images shell("#{docker_command} rmi $(docker images -q) || true") # Make sure no other images are present shell("#{docker_command} images | wc -l") do |r| expect(r.stdout).to match(/^1$/) end apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} run alpine_from_commit ls /root") do |r| expect(r.stdout).to match(/test_file_for_tar_test.txt/) end end it 'should successfully delete the image' do pp1=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': ensure => present, require => Class['docker'], } EOS apply_manifest(pp1, :catch_failures => true) pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': ensure => absent, } EOS apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} images") do |r| expect(r.stdout).to_not match(/#{default_image}/) end end end describe "docker::run" do it 'should start a container with a configurable command' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_1': image => '#{default_image}', command => '#{default_docker_exec_lr_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if fact('osfamily') == 'windows' shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Windows\\\\Temp") do |r| expect(r.stdout).to match(/test_file.txt/) end else shell("#{docker_command} exec #{container_id.stdout.strip} ls /root") do |r| expect(r.stdout).to match(/test_file.txt/) end end container_name = shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") expect("#{container_name.stdout.strip}").to match(/(container-3-1|container_3_1)/) end it 'should start a container with port configuration' do pp=<<-EOS class { 'docker': #{docker_args}} docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_2': image => '#{default_image}', command => '#{default_run_command}', ports => ['4444'], expose => ['5555'], require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} ps") do |r| expect(r.stdout).to match(/"#{default_run_command}".+5555\/tcp\, 0\.0\.0.0\:\d+\-\>4444\/tcp/) end end it 'should start a container with the hostname set' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_3': image => '#{default_image}', command => '#{default_run_command}', hostname => 'testdomain.com', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") shell("#{docker_command} exec #{container_id.stdout.strip} hostname") do |r| expect(r.stdout).to match(/testdomain.com/) end end it 'should start a container while mounting local volumes' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_4': image => '#{default_image}', command => '#{default_run_command}', volumes => ["#{docker_mount_path}:#{docker_mount_path}/mnt:rw"], require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } file { '#{docker_mount_path}/test_mount.txt': ensure => present, before => Docker::Run['container_3_4'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if fact('osfamily') == 'windows' shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Users\\\\Administrator\\\\AppData\\\\Local\\\\Temp\\\\mnt") do |r| expect(r.stdout).to match(/test_mount.txt/) end else shell("#{docker_command} exec #{container_id.stdout.strip} ls /root/mnt") do |r| expect(r.stdout).to match(/test_mount.txt/) end end end #cpuset is not supported on Docker Windows #STDERR: C:/Program Files/Docker/docker.exe: Error response from daemon: invalid option: Windows does not support CpusetCpus. it 'should start a container with cpuset paramater set', :win_broken => true do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_5_5': image => '#{default_image}', command => '#{default_run_command}', cpuset => ['0'], require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell('#{docker_command} inspect container_3_5_5') do |r| expect(r.stdout).to match(/"CpusetCpus"\: "0"/) end end #leagacy container linking was not implemented on Windows. --link is a legacy Docker feature: https://docs.docker.com/network/links/ it 'should start multiple linked containers', :win_broken => true do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_5_1': image => '#{default_image}', command => '#{default_run_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 container_1 = shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_5_2': image => '#{default_image}', command => '#{default_run_command}', depends => ['#{container_1.stdout.strip}'], links => "#{container_1.stdout.strip}:the_link", require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 container_2 = shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") shell("#{docker_command} inspect -f \"{{ .HostConfig.Links }}\" #{container_id.stdout.strip}") do |r| expect(r.stdout).to match("/#{container_1.stdout.strip}:/#{container_2.stdout.strip}/the_link") end end it 'should stop a running container' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6': image => '#{default_image}', command => '#{default_run_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6': image => '#{default_image}', running => false, require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(/^2$/) end apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(/^1$/) end end it 'should stop a running container and remove container' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6_1': image => '#{default_image}', command => '#{default_run_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS pp2=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_3_6_1': ensure => 'absent', image => '#{default_image}', require => Docker::Image['#{default_image}'], } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 15 shell("#{docker_command} inspect container_3_6_1", :acceptable_exit_codes => [0]) apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 15 shell("#{docker_command} inspect container_3_6_1", :acceptable_exit_codes => [1]) end it 'should allow dependency for ordering of independent run and image' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': } docker::run { 'container_3_7_1': image => '#{default_image}', command => '#{default_run_command}', #{default_docker_run_arg} } docker::image { '#{second_image}': require => Docker::Run['container_3_7_1'], } docker::run { 'container_3_7_2': image => '#{second_image}', command => '#{default_run_command}', #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' end it 'should restart a unhealthy container' do pp5=<<-EOS docker::run { 'container_3_7_3': image => '#{default_image}', command => '#{default_run_command}', health_check_cmd => 'echo', restart_on_unhealthy => true, #{default_docker_run_arg} } EOS pp_delete=<<-EOS docker::run { 'container_3_7_3': image => '#{default_image}', ensure => absent, } EOS if fact('osfamily') == 'windows' apply_manifest(pp5, :catch_failures => true) elsif fact('os.release.major') =~ (/14.04|8/) apply_manifest(pp5, :catch_failures => true) do |r| expect(r.stdout).to match(/container_3_7_3/) end else apply_manifest(pp5, :catch_failures => true) do |r| expect(r.stdout).to match(/docker-container_3_7_3-systemd-reload/) end end apply_manifest(pp_delete, :catch_failures => true) end end end describe "docker::exec" do it 'should run a command inside an already running container' do pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': require => Class['docker'], } docker::run { 'container_4_1': image => '#{default_image}', command => '#{default_run_command}', require => Docker::Image['#{default_image}'], #{default_docker_run_arg} } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 15 container_1 = shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") pp2=<<-EOS class { 'docker': #{docker_args} } docker::exec { 'test_command': container => '#{container_1.stdout.strip}', command => '#{default_docker_exec_command}', tty => true, } EOS pp_delete=<<-EOS docker::run { 'container_4_1': image => '#{default_image}', ensure => absent, } EOS apply_manifest(pp2, :catch_failures => true) # A sleep to give docker time to execute properly sleep 4 container_id = shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if fact('osfamily') == 'windows' shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Windows\\\\Temp") do |r| expect(r.stdout).to match(/test_file.txt/) end else shell("#{docker_command} exec #{container_id.stdout.strip} ls /root") do |r| expect(r.stdout).to match(/test_file.txt/) end end apply_manifest(pp_delete, :catch_failures => true) end it 'should only run if notified when refreshonly is true' do container_name = 'container_4_2' pp=<<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}': } docker::run { '#{container_name}': image => '#{default_image}', command => '#{default_run_command}', #{default_docker_run_arg} } docker::exec { 'test_command': container => '#{container_name}', command => '#{default_docker_exec_command}', refreshonly => true, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 if fact('osfamily') == 'windows' shell("#{docker_command} exec #{container_name} cmd /c dir Windows\\\\Temp") do |r| expect(r.stdout).to_not match(/test_file.txt/) end else shell("#{docker_command} exec #{container_name} ls /root") do |r| expect(r.stdout).to_not match(/test_file.txt/) end end pp_extra=<<-EOS file { '#{default_dockerfile}_dummy_file': ensure => 'present', notify => Docker::Exec['test_command'], } EOS pp_delete=<<-EOS docker::run { '#{container_name}': image => '#{default_image}', ensure => absent, } EOS pp2 = pp + pp_extra apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) unless fact('selinux') == 'true' # A sleep to give docker time to execute properly sleep 4 if fact('osfamily') == 'windows' shell("#{docker_command} exec #{container_name} cmd /c dir Windows\\\\Temp") do |r| expect(r.stdout).to match(/test_file.txt/) end else shell("#{docker_command} exec #{container_name} ls /root") do |r| expect(r.stdout).to match(/test_file.txt/) end end apply_manifest(pp_delete, :catch_failures => true) end end end