diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000..e908d0b --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,147 @@ +name: "nightly" + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +env: + HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 + HONEYCOMB_DATASET: litmus tests + SERVICE_URL: https://facade-main-6f3kfepqcq-ew.a.run.app/v1/provision + +jobs: + setup_matrix: + name: "Setup Test Matrix" + runs-on: ubuntu-20.04 + outputs: + matrix: ${{ steps.get-matrix.outputs.matrix }} + steps: + - name: Checkout Source + uses: actions/checkout@v2 + + - name: Activate Ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/gems + key: ${{ runner.os }}-nightly-${{ hashFiles('**/Gemfile') }} + restore-keys: | + ${{ runner.os }}-nightly- + ${{ runner.os }}- + + - name: Install gems + run: | + bundle config path vendor/gems + bundle config jobs 8 + bundle config retry 3 + bundle install + bundle clean + + - name: Setup Acceptance Test Matrix + id: get-matrix + run: "bundle exec matrix_from_metadata" + + Acceptance: + needs: + - setup_matrix + + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: ${{fromJson(needs.setup_matrix.outputs.matrix)}} + + steps: + - name: Checkout Source + uses: actions/checkout@v2 + + - name: Activate Ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/gems + key: ${{ runner.os }}-nightly-${{ hashFiles('**/Gemfile') }} + restore-keys: | + ${{ runner.os }}-nightly- + ${{ runner.os }}- + + - name: Install gems + run: | + bundle config path vendor/gems + bundle config jobs 8 + bundle config retry 3 + bundle install + bundle clean + + - name: bundler environment + run: | + bundle env + + - name: Provision test environment + run: | + bundle exec rake 'litmus:provision[provision::provision_service,${{ matrix.platform }}]' + echo ::group::=== REQUEST === + cat request.json || true + echo + echo ::endgroup:: + echo ::group::=== INVENTORY === + sed -e 's/password: .*/password: "[redacted]"/' < inventory.yaml || true + echo ::endgroup:: + + # The provision service hands out machines as soon as they're provisioned. + # The GCP VMs might still take a while to spool up and configure themselves fully. + # This retry loop spins until all agents have been installed successfully. + - name: Install agent + uses: nick-invision/retry@v1 + with: + timeout_minutes: 30 + max_attempts: 5 + retry_wait_seconds: 60 + command: bundle exec rake 'litmus:install_agent[${{ matrix.collection }}]' + + # The agent installer on windows does not finish in time for this to work. To + # work around this for now, retry after a minute if installing the module failed. + - name: Install module + uses: nick-invision/retry@v1 + with: + timeout_minutes: 30 + max_attempts: 2 + retry_wait_seconds: 60 + command: bundle exec rake 'litmus:install_module' + + - name: Run acceptance tests + run: bundle exec rake 'litmus:acceptance:parallel' + + - name: Remove test environment + if: ${{ always() }} + run: | + bundle exec rake 'litmus:tear_down' + echo ::group::=== REQUEST === + cat request.json || true + echo + echo ::endgroup:: + + slack-workflow-status: + if: always() + name: Post Workflow Status To Slack + needs: + - Acceptance + runs-on: ubuntu-20.04 + steps: + - name: Slack Workflow Notification + uses: Gamesight/slack-workflow-status@master + with: + # Required Input + repo_token: ${{secrets.GITHUB_TOKEN}} + slack_webhook_url: ${{secrets.SLACK_WEBHOOK}} + # Optional Input + channel: '#team-ia-bots' + name: 'GABot' diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml new file mode 100644 index 0000000..622c298 --- /dev/null +++ b/.github/workflows/pr_test.yml @@ -0,0 +1,127 @@ +name: "PR Testing" + +on: [pull_request] + +env: + HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 + HONEYCOMB_DATASET: litmus tests + SERVICE_URL: https://facade-main-6f3kfepqcq-ew.a.run.app/v1/provision + +jobs: + setup_matrix: + name: "Setup Test Matrix" + runs-on: ubuntu-20.04 + outputs: + matrix: ${{ steps.get-matrix.outputs.matrix }} + steps: + - name: Checkout Source + uses: actions/checkout@v2 + + - name: Activate Ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/gems + key: ${{ runner.os }}-pr-${{ hashFiles('**/Gemfile') }} + restore-keys: | + ${{ runner.os }}-pr- + ${{ runner.os }}- + + - name: Install gems + run: | + bundle config path vendor/gems + bundle config jobs 8 + bundle config retry 3 + bundle install + bundle clean + + - name: Setup Acceptance Test Matrix + id: get-matrix + run: "bundle exec matrix_from_metadata" + + Acceptance: + needs: + - setup_matrix + + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: ${{fromJson(needs.setup_matrix.outputs.matrix)}} + + steps: + - name: Checkout Source + uses: actions/checkout@v2 + + - name: Activate Ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/gems + key: ${{ runner.os }}-pr-${{ hashFiles('**/Gemfile') }} + restore-keys: | + ${{ runner.os }}-pr- + ${{ runner.os }}- + + - name: Install gems + run: | + bundle config path vendor/gems + bundle config jobs 8 + bundle config retry 3 + bundle install + bundle clean + + - name: bundler environment + run: | + bundle env + + - name: Provision test environment + run: | + bundle exec rake 'litmus:provision[provision::provision_service,${{ matrix.platform }}]' + echo ::group::=== REQUEST === + cat request.json || true + echo + echo ::endgroup:: + echo ::group::=== INVENTORY === + sed -e 's/password: .*/password: "[redacted]"/' < inventory.yaml || true + echo ::endgroup:: + + # The provision service hands out machines as soon as they're provisioned. + # The GCP VMs might still take a while to spool up and configure themselves fully. + # This retry loop spins until all agents have been installed successfully. + - name: Install agent + uses: nick-invision/retry@v1 + with: + timeout_minutes: 30 + max_attempts: 5 + retry_wait_seconds: 60 + command: bundle exec rake 'litmus:install_agent[${{ matrix.collection }}]' + + # The agent installer on windows does not finish in time for this to work. To + # work around this for now, retry after a minute if installing the module failed. + - name: Install module + uses: nick-invision/retry@v1 + with: + timeout_minutes: 30 + max_attempts: 2 + retry_wait_seconds: 60 + command: bundle exec rake 'litmus:install_module' + + - name: Run acceptance tests + run: bundle exec rake 'litmus:acceptance:parallel' + + - name: Remove test environment + if: ${{ always() }} + run: | + bundle exec rake 'litmus:tear_down' + echo ::group::=== REQUEST === + cat request.json || true + echo + echo ::endgroup:: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 23a45c2..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: "release" - -on: - push: - branches: - - 'release' - -jobs: - LitmusAcceptancePuppet5: - env: - HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 - HONEYCOMB_DATASET: litmus tests - runs-on: self-hosted - strategy: - matrix: - ruby_version: [2.5.x] - puppet_gem_version: [~> 6.0] - platform: [release_checks_5] - agent_family: ['puppet5'] - - steps: - - uses: actions/checkout@v1 - - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@main - with: - platform: ${{ matrix.platform }} - agent_family: ${{ matrix.agent_family }} - bundler_args: "--with=system_tests" - LitmusAcceptancePuppet6: - env: - HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 - HONEYCOMB_DATASET: litmus tests - runs-on: self-hosted - strategy: - matrix: - ruby_version: [2.5.x] - puppet_gem_version: [~> 6.0] - platform: [release_checks_6] - agent_family: ['puppet6'] - - steps: - - uses: actions/checkout@v1 - - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@main - with: - platform: ${{ matrix.platform }} - agent_family: ${{ matrix.agent_family }} - bundler_args: "--with=system_tests" - Spec: - runs-on: self-hosted - strategy: - matrix: - check: [spec, 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop'] - ruby_version: [2.5.x] - puppet_gem_version: [~> 5.0, ~> 6.0] - exclude: - - puppet_gem_version: ~> 5.0 - check: 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop' - - ruby_version: 2.5.x - puppet_gem_version: ~> 5.0 - steps: - - uses: actions/checkout@v1 - - name: Spec Tests - uses: puppetlabs/action-litmus_spec@main - with: - puppet_gem_version: ${{ matrix.puppet_gem_version }} - check: ${{ matrix.check }} diff --git a/.github/workflows/ubuntu16_pr.yaml b/.github/workflows/ubuntu16_pr.yaml deleted file mode 100644 index 3afc00e..0000000 --- a/.github/workflows/ubuntu16_pr.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: "ubuntu1604" - -on: [push, pull_request] - -jobs: - LitmusAcceptance: - runs-on: ubuntu-16.04 - steps: - - uses: actions/checkout@v1 - - name: Set up Ruby 2.6 - uses: actions/setup-ruby@v1 - with: - ruby-version: 2.6 - - name: Prepare inventory file - run: | - cat <> inventory.yaml - --- - version: 2 - groups: - - name: local - targets: - - uri: litmus_localhost - config: - transport: local - - name: ssh_nodes - targets: [] - - name: winrm_nodes - targets: [] - EOF - - name: Install gems and puppet agent - run: | - bundle install - sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:install_agent' - - name: Install module - run: bundle exec rake 'litmus:install_module' - - name: Run acceptance tests - run: sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:acceptance:localhost' diff --git a/.github/workflows/ubuntu18_pr.yaml b/.github/workflows/ubuntu18_pr.yaml index c10ebdf..8b5489c 100644 --- a/.github/workflows/ubuntu18_pr.yaml +++ b/.github/workflows/ubuntu18_pr.yaml @@ -1,37 +1,69 @@ -name: "ubuntu1804" +name: "Test on Ubuntu Github Runners" on: [push, pull_request] jobs: - LitmusAcceptance: - runs-on: ubuntu-18.04 + Acceptance: + strategy: + fail-fast: false + matrix: + platform: + - ubuntu-16.04 + - ubuntu-18.04 + - ubuntu-20.04 + collection: + - puppet5 + - puppet6 + - puppet7-nightly + exclude: + # newer OS not supported on older agent + - platform: ubuntu-20.04 + collection: puppet5 + + runs-on: ${{ matrix.platform }} + steps: - - uses: actions/checkout@v1 - - name: Set up Ruby 2.6 - uses: actions/setup-ruby@v1 - with: - ruby-version: 2.6 - - name: Prepare inventory file - run: | - cat <> inventory.yaml - --- - version: 2 - groups: - - name: local - targets: - - uri: litmus_localhost - config: - transport: local - - name: ssh_nodes - targets: [] - - name: winrm_nodes - targets: [] - EOF - - name: Install gems and puppet agent - run: | - bundle install - sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:install_agent' - - name: Install module - run: bundle exec rake 'litmus:install_module' - - name: Run acceptance tests - run: sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:acceptance:localhost' + - name: Checkout Source + uses: actions/checkout@v2 + + - name: Activate Ruby 2.7 + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/gems + key: ${{ runner.os }}-pr-${{ hashFiles('**/Gemfile') }} + restore-keys: | + ${{ runner.os }}-pr- + ${{ runner.os }}- + + - name: Prepare inventory file + run: | + cat <> inventory.yaml + --- + version: 2 + groups: + - name: local + targets: + - uri: litmus_localhost + config: + transport: local + - name: ssh_nodes + targets: [] + - name: winrm_nodes + targets: [] + EOF + + - name: Install gems and puppet agent + run: | + bundle install + sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:install_agent[${{ matrix.collection }}]' + + - name: Install module + run: bundle exec rake 'litmus:install_module' + + - name: Run acceptance tests + run: sudo -u root env "PATH=$PATH" bundle exec rake 'litmus:acceptance:localhost' diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml deleted file mode 100644 index a8097b9..0000000 --- a/.github/workflows/weekly.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: "weekly" - -on: - schedule: - - cron: '0 0 * * 6' - -jobs: - LitmusAcceptancePuppet5: - env: - HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 - HONEYCOMB_DATASET: litmus tests - runs-on: self-hosted - strategy: - matrix: - ruby_version: [2.5.x] - puppet_gem_version: [~> 6.0] - platform: [release_checks_5] - agent_family: ['puppet5'] - - steps: - - uses: actions/checkout@v1 - - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@main - with: - platform: ${{ matrix.platform }} - agent_family: ${{ matrix.agent_family }} - bundler_args: "--with=system_tests" - LitmusAcceptancePuppet6: - env: - HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 - HONEYCOMB_DATASET: litmus tests - runs-on: self-hosted - strategy: - matrix: - ruby_version: [2.5.x] - puppet_gem_version: [~> 6.0] - platform: [release_checks_6] - agent_family: ['puppet6'] - - steps: - - uses: actions/checkout@v1 - - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@main - with: - platform: ${{ matrix.platform }} - agent_family: ${{ matrix.agent_family }} - bundler_args: "--with=system_tests" - Spec: - runs-on: self-hosted - strategy: - matrix: - check: [spec, 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop'] - ruby_version: [2.5.x] - puppet_gem_version: [~> 5.0, ~> 6.0] - exclude: - - puppet_gem_version: ~> 5.0 - check: 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop' - - ruby_version: 2.5.x - puppet_gem_version: ~> 5.0 - steps: - - uses: actions/checkout@v1 - - name: Spec Tests - uses: puppetlabs/action-litmus_spec@main - with: - puppet_gem_version: ${{ matrix.puppet_gem_version }} - check: ${{ matrix.check }} diff --git a/Gemfile b/Gemfile index 510c7a0..5ac0873 100644 --- a/Gemfile +++ b/Gemfile @@ -1,79 +1,81 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org' def location_for(place_or_version, fake_version = nil) git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} file_url_regex = %r{\Afile:\/\/(?.*)} if place_or_version && (git_url = place_or_version.match(git_url_regex)) [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] else [place_or_version, { require: false }] end end ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments minor_version = ruby_version_segments[0..1].join('.') group :development do gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-module-posix-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] gem "puppet-module-posix-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] gem "puppet-module-win-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-module-win-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "ruby-pwsh", require: false gem "github_changelog_generator", require: false, git: 'https://github.com/skywinder/github-changelog-generator', ref: '20ee04ba1234e9e83eb2ffb5056e23d641c7a018' if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.2.2') + gem "puppet_litmus", require: false, git: 'https://github.com/puppetlabs/puppet_litmus', branch: 'main' if Gem::Version.new(RUBY_VERSION.dup) > Gem::Version.new('2.5.0') + gem "bolt", '= 2.23.0', require: false if Gem::Version.new(RUBY_VERSION.dup) > Gem::Version.new('2.5.0') end group :system_tests do gem "puppet-module-posix-system-r#{minor_version}", require: false, platforms: [:ruby] gem "puppet-module-win-system-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "rspec-retry", require: false end puppet_version = ENV['PUPPET_GEM_VERSION'] facter_version = ENV['FACTER_GEM_VERSION'] hiera_version = ENV['HIERA_GEM_VERSION'] gems = {} gems['puppet'] = location_for(puppet_version) # If facter or hiera versions have been specified via the environment # variables gems['facter'] = location_for(facter_version) if facter_version gems['hiera'] = location_for(hiera_version) if hiera_version if Gem.win_platform? && puppet_version =~ %r{^(file:///|git://)} # If we're using a Puppet gem on Windows which handles its own win32-xxx gem # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). gems['win32-dir'] = ['<= 0.4.9', require: false] gems['win32-eventlog'] = ['<= 0.6.5', require: false] gems['win32-process'] = ['<= 0.7.5', require: false] gems['win32-security'] = ['<= 0.2.5', require: false] gems['win32-service'] = ['0.8.8', require: false] end gems.each do |gem_name, gem_params| gem gem_name, *gem_params end # Evaluate Gemfile.local and ~/.gemfile if they exist extra_gemfiles = [ "#{__FILE__}.local", File.join(Dir.home, '.gemfile'), ] extra_gemfiles.each do |gemfile| if File.file?(gemfile) && File.readable?(gemfile) eval(File.read(gemfile), binding) end end # vim: syntax=ruby diff --git a/manifests/params.pp b/manifests/params.pp index feda744..2436107 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,382 +1,376 @@ # @summary Default parameter values for the docker module # class docker::params { $version = undef $ensure = present $docker_ce_start_command = 'dockerd' $docker_ce_package_name = 'docker-ce' $docker_engine_start_command = 'docker daemon' $docker_engine_package_name = 'docker-engine' $docker_ce_channel = stable $docker_ee = false $docker_ee_start_command = 'dockerd' $docker_ee_source_location = undef $docker_ee_key_source = undef $docker_ee_key_id = undef $docker_ee_repos = stable $tcp_bind = undef $tls_enable = false $tls_verify = true $machine_version = '0.16.1' $ip_forward = true $iptables = true $ipv6 = false $ipv6_cidr = undef $default_gateway_ipv6 = undef $icc = undef $ip_masq = true $bip = undef $mtu = undef $fixed_cidr = undef $bridge = undef $default_gateway = undef $socket_bind = 'unix:///var/run/docker.sock' $log_level = undef $log_driver = undef $log_opt = [] $selinux_enabled = undef $socket_group_default = 'docker' $labels = [] $service_state = running $service_enable = true $manage_service = true $root_dir = undef $tmp_dir_config = true $tmp_dir = '/tmp/' $dns = undef $dns_search = undef $proxy = undef $compose_base_url = 'https://github.com/docker/compose/releases/download' $compose_symlink_name = 'docker-compose' $no_proxy = undef $execdriver = undef $storage_driver = undef $dm_basesize = undef $dm_fs = undef $dm_mkfsarg = undef $dm_mountopt = undef $dm_blocksize = undef $dm_loopdatasize = undef $dm_loopmetadatasize = undef $dm_datadev = undef $dm_metadatadev = undef $dm_thinpooldev = undef $dm_use_deferred_removal = undef $dm_use_deferred_deletion = undef $dm_blkdiscard = undef $dm_override_udev_sync_check = undef $overlay2_override_kernel_check = false $manage_package = true $package_source = undef $service_name_default = 'docker' $docker_group_default = 'docker' $storage_devs = undef $storage_vg = undef $storage_root_size = undef $storage_data_size = undef $storage_min_data_size = undef $storage_chunk_size = undef $storage_growpart = undef $storage_auto_extend_pool = undef $storage_pool_autoextend_threshold = undef $storage_pool_autoextend_percent = undef $storage_config_template = 'docker/etc/sysconfig/docker-storage.erb' $registry_mirror = undef $curl_ensure = true $os_lc = downcase($facts['os']['name']) $docker_msft_provider_version = undef $nuget_package_provider_version = undef $docker_command = 'docker' if ($facts['os']['family'] == 'windows') { $compose_install_path = "${::docker_program_files_path}/Docker" $compose_version = '1.21.2' $docker_ee_package_name = 'Docker' $machine_install_path = "${::docker_program_files_path}/Docker" $tls_cacert = "${::docker_program_data_path}/docker/certs.d/ca.pem" $tls_cert = "${::docker_program_data_path}/docker/certs.d/server-cert.pem" $tls_key = "${::docker_program_data_path}/docker/certs.d/server-key.pem" } else { $compose_install_path = '/usr/local/bin' $compose_version = '1.21.2' $docker_ee_package_name = 'docker-ee' $machine_install_path = '/usr/local/bin' $tls_cacert = '/etc/docker/tls/ca.pem' $tls_cert = '/etc/docker/tls/cert.pem' $tls_key = '/etc/docker/tls/key.pem' } case $facts['os']['family'] { 'Debian' : { case $facts['os']['name'] { 'Ubuntu' : { $package_release = "ubuntu-${facts['os']['distro']['codename']}" if (versioncmp($facts['os']['release']['full'], '15.04') >= 0) { $service_after_override = undef $service_config_template = 'docker/etc/sysconfig/docker.systemd.erb' $service_hasrestart = true $service_hasstatus = true $service_overrides_template = 'docker/etc/systemd/system/docker.service.d/service-overrides-debian.conf.erb' $service_provider = 'systemd' $socket_override = false $socket_overrides_template = 'docker/etc/systemd/system/docker.socket.d/socket-overrides.conf.erb' $storage_config = '/etc/default/docker-storage' include docker::systemd_reload } else { $service_config_template = 'docker/etc/default/docker.erb' $service_overrides_template = undef $socket_overrides_template = undef $socket_override = false $service_after_override = undef $service_provider = 'upstart' $service_hasstatus = true $service_hasrestart = false $storage_config = undef } } default: { if (versioncmp($facts['facterversion'], '2.4.6') <= 0) { $package_release = "debian-${facts['os']['lsb']['distcodename']}" } else { $package_release = "debian-${facts['os']['distro']['codename']}" } $service_provider = 'systemd' $storage_config = '/etc/default/docker-storage' $service_config_template = 'docker/etc/sysconfig/docker.systemd.erb' $service_overrides_template = 'docker/etc/systemd/system/docker.service.d/service-overrides-debian.conf.erb' $socket_overrides_template = 'docker/etc/systemd/system/docker.socket.d/socket-overrides.conf.erb' $socket_override = false $service_after_override = undef $service_hasstatus = true $service_hasrestart = true include docker::systemd_reload } } $apt_source_pin_level = 500 $docker_group = $docker_group_default $pin_upstream_package_source = true $repo_opt = undef $service_config = undef $service_name = $service_name_default $socket_group = $socket_group_default $storage_setup_file = undef $use_upstream_package_source = true $package_ce_source_location = "https://download.docker.com/linux/${os_lc}" $package_ce_key_source = "https://download.docker.com/linux/${os_lc}/gpg" $package_ce_key_id = '9DC858229FC7DD38854AE2D88D81803C0EBFCD88' if (versioncmp($facts['facterversion'], '2.4.6') <= 0) { $package_ce_release = $facts['os']['lsb']['distcodename'] } else { $package_ce_release = $facts['os']['distro']['codename'] } $package_source_location = 'http://apt.dockerproject.org/repo' $package_key_source = 'https://apt.dockerproject.org/gpg' $package_key_check_source = undef $package_key_id = '58118E89F3A912897C070ADBF76221572C52609D' $package_ee_source_location = $docker_ee_source_location $package_ee_key_source = $docker_ee_key_source $package_ee_key_id = $docker_ee_key_id if (versioncmp($facts['facterversion'], '2.4.6') <= 0) { $package_ee_release = $facts['os']['lsb']['distcodename'] } else { $package_ee_release = $facts['os']['distro']['codename'] } $package_ee_repos = $docker_ee_repos $package_ee_package_name = $docker_ee_package_name if ($service_provider == 'systemd') { $detach_service_in_init = false } else { $detach_service_in_init = true } } 'RedHat' : { $service_after_override = undef $service_config = '/etc/sysconfig/docker' $service_config_template = 'docker/etc/sysconfig/docker.systemd.erb' $service_hasrestart = true $service_hasstatus = true $service_overrides_template = 'docker/etc/systemd/system/docker.service.d/service-overrides-rhel.conf.erb' $service_provider = 'systemd' $socket_override = false $socket_overrides_template = 'docker/etc/systemd/system/docker.socket.d/socket-overrides.conf.erb' $storage_config = '/etc/sysconfig/docker-storage' $storage_setup_file = '/etc/sysconfig/docker-storage-setup' $use_upstream_package_source = true $apt_source_pin_level = undef $detach_service_in_init = false $package_ce_key_id = undef $package_ce_key_source = 'https://download.docker.com/linux/centos/gpg' $package_ce_release = undef $package_ce_source_location = "https://download.docker.com/linux/centos/${facts['os']['release']['major']}/${facts['os']['architecture']}/${docker_ce_channel}" $package_ee_key_id = $docker_ee_key_id $package_ee_key_source = $docker_ee_key_source $package_ee_package_name = $docker_ee_package_name $package_ee_release = undef $package_ee_repos = $docker_ee_repos $package_ee_source_location = $docker_ee_source_location $package_key_check_source = true $package_key_id = undef $package_key_source = 'https://yum.dockerproject.org/gpg' $package_release = undef $package_source_location = "https://yum.dockerproject.org/repo/main/centos/${facts['os']['release']['major']}" $pin_upstream_package_source = undef $service_name = $service_name_default if $use_upstream_package_source { $docker_group = $docker_group_default $socket_group = $socket_group_default } else { $docker_group = 'dockerroot' $socket_group = 'dockerroot' } - - # repo_opt to specify install_options for docker package - if $facts['os']['name'] == 'RedHat' { - $repo_opt = '--enablerepo=rhel-7-server-extras-rpms' - } else { - $repo_opt = undef - } + $repo_opt = undef } 'windows' : { $msft_nuget_package_provider_version = $nuget_package_provider_version $msft_provider_version = $docker_msft_provider_version $msft_package_version = $version $service_config_template = 'docker/windows/config/daemon.json.erb' $service_config = "${::docker_program_data_path}/docker/config/daemon.json" $docker_group = 'docker' $package_ce_source_location = undef $package_ce_key_source = undef $package_ce_key_id = undef $package_ce_repos = undef $package_ce_release = undef $package_key_id = undef $package_release = undef $package_source_location = undef $package_key_source = undef $package_key_check_source = undef $package_ee_source_location = undef $package_ee_package_name = $docker_ee_package_name $package_ee_key_source = undef $package_ee_key_id = undef $package_ee_repos = undef $package_ee_release = undef $use_upstream_package_source = undef $pin_upstream_package_source = undef $apt_source_pin_level = undef $socket_group = undef $service_name = $service_name_default $repo_opt = undef $storage_config = undef $storage_setup_file = undef $service_provider = undef $service_overrides_template = undef $socket_overrides_template = undef $socket_override = false $service_after_override = undef $service_hasstatus = undef $service_hasrestart = undef $detach_service_in_init = true } 'Suse': { $docker_group = $docker_group_default $socket_group = $socket_group_default $package_key_source = undef $package_key_check_source = undef $package_source_location = undef $package_key_id = undef $package_repos = undef $package_release = undef $package_ce_key_source = undef $package_ce_source_location = undef $package_ce_key_id = undef $package_ce_repos = undef $package_ce_release = undef $package_ee_source_location = undef $package_ee_key_source = undef $package_ee_key_id = undef $package_ee_release = undef $package_ee_repos = undef $package_ee_package_name = undef $use_upstream_package_source = true $service_overrides_template = undef $socket_overrides_template = undef $socket_override = false $service_after_override = undef $service_hasstatus = undef $service_hasrestart = undef $service_provider = 'systemd' $package_name = $docker_ce_package_name $service_name = $service_name_default $detach_service_in_init = true $repo_opt = undef $nowarn_kernel = false $service_config = undef $storage_config = undef $storage_setup_file = undef $service_config_template = undef $pin_upstream_package_source = undef $apt_source_pin_level = undef } default: { $docker_group = $docker_group_default $socket_group = $socket_group_default $package_key_source = undef $package_key_check_source = undef $package_source_location = undef $package_key_id = undef $package_repos = undef $package_release = undef $package_ce_key_source = undef $package_ce_source_location = undef $package_ce_key_id = undef $package_ce_repos = undef $package_ce_release = undef $package_ee_source_location = undef $package_ee_key_source = undef $package_ee_key_id = undef $package_ee_release = undef $package_ee_repos = undef $package_ee_package_name = undef $use_upstream_package_source = true $service_overrides_template = undef $socket_overrides_template = undef $socket_override = false $service_after_override = undef $service_hasstatus = undef $service_hasrestart = undef $service_provider = undef $package_name = $docker_ce_package_name $service_name = $service_name_default $detach_service_in_init = true $repo_opt = undef $nowarn_kernel = false $service_config = undef $storage_config = undef $storage_setup_file = undef $service_config_template = undef $pin_upstream_package_source = undef $apt_source_pin_level = undef } } # Special extra packages are required on some OSes. # Specifically apparmor is needed for Ubuntu: # https://github.com/docker/docker/issues/4734 $prerequired_packages = $facts['os']['family'] ? { 'Debian' => $facts['os']['name'] ? { 'Debian' => [ 'cgroupfs-mount', ], 'Ubuntu' => [ 'cgroup-lite', 'apparmor', ], default => [], }, 'RedHat' => ['device-mapper'], default => [], } $dependent_packages = [ 'docker-ce-cli', 'containerd.io', ] } diff --git a/metadata.json b/metadata.json index e82f8f1..5c313fd 100644 --- a/metadata.json +++ b/metadata.json @@ -1,79 +1,73 @@ { "name": "puppetlabs-docker", "version": "3.12.1", "author": "puppetlabs", "summary": "Module for installing and managing docker", "license": "Apache-2.0", "source": "git://github.com/puppetlabs/puppetlabs-docker", "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 < 7.0.0" }, { "name": "puppetlabs/apt", "version_requirement": ">= 4.4.1 < 8.0.0" }, { "name": "puppetlabs/translate", "version_requirement": ">= 0.0.1 < 3.0.0" }, { "name": "puppetlabs/powershell", "version_requirement": ">= 2.1.4 < 4.0.0" }, { "name": "puppetlabs/reboot", "version_requirement": ">=2.0.0 < 3.0.0" } ], "operatingsystem_support": [ - { - "operatingsystem": "RedHat", - "operatingsystemrelease": [ - "7" - ] - }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "7" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04", "18.04", "20.04" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "8.0", "9.0", "10" ] }, { "operatingsystem": "Windows", "operatingsystemrelease": [ "2016", "2019" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 5.5.10 < 7.0.0" } ], "pdk-version": "1.18.1", "template-url": "https://github.com/puppetlabs/pdk-templates#main", "template-ref": "remotes/origin/main-0-g8f10887" } diff --git a/spec/acceptance/compose_v3_spec.rb b/spec/acceptance/compose_v3_spec.rb index 6930ef8..29c8d88 100644 --- a/spec/acceptance/compose_v3_spec.rb +++ b/spec/acceptance/compose_v3_spec.rb @@ -1,159 +1,157 @@ require 'spec_helper_acceptance' if os[:family] == 'windows' install_dir = '/cygdrive/c/Program Files/Docker' file_extension = '.exe' docker_args = 'docker_ee => true' tmp_path = 'C:/cygwin64/tmp' test_container = if os[:release] =~ %r{2019} 'nanoserver' else 'nanoserver-sac2016' end else - docker_args = if os[:family] == 'redhat' - "repo_opt => '--enablerepo=localmirror-extras'" - elsif os[:name] == 'ubuntu' && os[:release][:full] == '14.04' + docker_args = if os[:name] == 'ubuntu' && os[:release][:full] == '14.04' "version => '18.06.1~ce~3-0~ubuntu'" else '' 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, %r{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', win_broken: true do let(:install_pp) do <<-MANIFEST docker_compose { 'web': compose_files => ['#{tmp_path}/docker-compose-v3.yml'], ensure => present, } MANIFEST end it 'is idempotent' do idempotent_apply(install_pp) end it 'has docker compose installed' do run_shell('docker-compose --help', expect_failures: false) end it 'finds a docker container' do run_shell('docker inspect web_compose_test_1', expect_failures: false) end end context 'creating compose projects with multi compose files', win_broken: true do before(:all) do install_pp = <<-MANIFEST docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => present, } MANIFEST apply_manifest(install_pp, catch_failures: true) end it "should find container with #{test_container} tag" do run_shell("docker inspect web1_compose_test_1 | grep #{test_container}", acceptable_exit_codes: [0]) end end context 'Destroying project with multiple compose files', win_broken: true do let(:destroy_pp) do <<-MANIFEST docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => absent, } MANIFEST end before(:all) do install_pp = <<-MANIFEST docker_compose { 'web1': compose_files => ['#{tmp_path}/docker-compose-v3.yml', '#{tmp_path}/docker-compose-override-v3.yml'], ensure => present, } MANIFEST apply_manifest(install_pp, catch_failures: true) end it 'is idempotent' do idempotent_apply(destroy_pp) end it 'does not find a docker container' do run_shell('docker inspect web1_compose_test_1', expect_failures: true) end end context 'Requesting a specific version of compose' do let(:version) do '1.21.2' end it 'is idempotent' do pp = <<-MANIFEST class { 'docker::compose': version => '#{version}', } MANIFEST idempotent_apply(pp) end it 'has installed the requested version' do run_shell('docker-compose --version', expect_failures: false) do |r| expect(r.stdout).to match(%r{#{version}}) end end end context 'Removing docker compose' do let(:version) do '1.21.2' end it 'is idempotent' do pp = <<-MANIFEST class { 'docker::compose': ensure => absent, version => '#{version}', } MANIFEST idempotent_apply(pp) end it 'has removed the relevant files' do run_shell("test -e \"#{install_dir}/docker-compose#{file_extension}\"", expect_failures: true) run_shell("test -e \"#{install_dir}/docker-compose-#{version}#{file_extension}\"", expect_failures: true) end after(:all) do install_pp = <<-MANIFEST class { 'docker': #{docker_args}} class { 'docker::compose': } MANIFEST apply_manifest(install_pp, catch_failures: true) end end end diff --git a/spec/acceptance/docker_custom_source_spec.rb b/spec/acceptance/docker_custom_source_spec.rb index c24f5da..fd1c0cf 100644 --- a/spec/acceptance/docker_custom_source_spec.rb +++ b/spec/acceptance/docker_custom_source_spec.rb @@ -1,107 +1,105 @@ require 'spec_helper_acceptance' if os[:family] == 'windows' docker_args = 'docker_ee => true, docker_ee_source_location => "https://download.docker.com/components/engine/windows-server/17.06/docker-17.06.2-ee-14.zip"' default_image = 'winamd64/hello-seattle' # 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"' skip = false elsif os[:name] == 'Ubuntu' && os[:release][:full] == '14.04' docker_args = "version => '18.06.1~ce~3-0~ubuntu'" default_image = 'busybox' skip = true else docker_args = '' default_image = 'busybox' skip = false end describe 'the Puppet Docker module' do context 'with download location', skip: skip do let(:pp) do - " - class { 'docker': #{docker_args} } - " + "class { 'docker': #{docker_args} }" end it 'runs successfully' do apply_manifest(pp, catch_failures: true) end it 'runs idempotently' do apply_manifest(pp, catch_changes: true) unless selinux == 'true' end it 'is start a docker process' do if os[:family] == 'windows' run_shell('powershell Get-Process -Name dockerd') do |r| expect(r.stdout).to match(%r{ProcessName}) end else run_shell('ps aux | grep docker') do |r| expect(r.stdout).to match %r{dockerd -H unix:\/\/\/var\/run\/docker.sock} end end end it 'installs a working docker client' do run_shell("#{docker_command} ps", expect_failures: false) end it 'stops 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) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} ps", expect_failures: false) apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: true) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} inspect container-3-6", expect_failures: true) if os[:family] == 'windows' run_shell('test -f /cygdrive/c/Users/Administrator/AppData/Local/Temp/container-3-6.service', expect_failures: true) else run_shell('test -f /etc/systemd/system/container-3-6.service', expect_failures: true) end end end end diff --git a/spec/acceptance/docker_full_spec.rb b/spec/acceptance/docker_full_spec.rb index 0021cb0..3019325 100644 --- a/spec/acceptance/docker_full_spec.rb +++ b/spec/acceptance/docker_full_spec.rb @@ -1,998 +1,996 @@ require 'spec_helper_acceptance' if os[:kernel] == 'windows' docker_args = 'docker_ee => true' default_image = 'winamd64/hello-seattle' default_image_tag = if os[:release][:major] == '2019' 'nanoserver' else 'nanoserver-sac2016' end default_digest = 'sha256:dcba85354678b50608b8c40ec6d17cce063a224aa0e12b6a55dc47b67f039e75' default_local_digest = 'sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10' second_image = 'winamd64/hola-mundo' 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:\Users\Public\test_file.txt"' default_docker_exec_command = 'cmd /c "echo test > C:\Users\Public\test_file.txt"' docker_mount_path = 'C:/Users/Public/DockerVolume' storage_driver = 'windowsfilter' else - docker_args = if os[:family] == 'redhat' - "repo_opt => '--enablerepo=localmirror-extras'" - elsif os[:name] == 'Ubuntu' && os[:release][:full] == '14.04' + docker_args = if os[:name] == 'ubuntu' && os[:release][:full] == '14.04' "version => '18.06.1~ce~3-0~ubuntu'" else '' end default_image = 'alpine' second_image = 'busybox' default_image_tag = '3.7' default_digest = 'sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a' default_local_digest = 'sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10' 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' storage_driver = if os[:family] == 'Debian' && os[:release][:major] =~ %r{14.04|^8$} 'aufs' elsif os[:family] == 'RedHat' 'devicemapper' else 'overlay2' end end describe 'the Puppet Docker module' do context 'clean up before each test', win_broken: true do before(:each) do retry_on_error_matching(60, 5, %r{connection failure running}) do # Stop all container using systemd run_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 run_shell("#{docker_command} rm -f $(#{docker_command} ps -a -q) || true") # Delete all existing images run_shell("#{docker_command} rmi -f $(#{docker_command} images -q) || true") # Check to make sure no images are present run_shell("#{docker_command} images | wc -l") do |r| expect(r.stdout).to match(%r{^0|1$}) # rubocop:disable RSpec/ExpectInHook: end # Check to make sure no running containers are present run_shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(%r{^0|1$}) # rubocop:disable RSpec/ExpectInHook: end end end describe 'docker class' do context 'without any parameters', win_broken: true do let(:pp) { "class { 'docker': #{docker_args} }" } it 'runs successfully' do apply_manifest(pp, catch_failures: true) end it 'runs idempotently' do apply_manifest(pp, catch_changes: true) unless selinux == 'true' end it 'is start a docker process' do if os[:family] == 'windows' run_shell('powershell Get-Process -Name dockerd') do |r| expect(r.stdout).to match(%r{ProcessName}) end else run_shell('ps aux | grep docker') do |r| expect(r.stdout).to match(%r{dockerd -H unix:\/\/\/var\/run\/docker.sock}) end end end it 'installs a working docker client' do run_shell("#{docker_command} ps", expect_failures: false) end it 'stops 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} ps", expect_failures: false) apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: true) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} inspect container-3-6", expect_failures: true) if os[:family] == 'windows' run_shell('test -f /cygdrive/c/Users/Administrator/AppData/Local/Temp/container-3-6.service', expect_failures: true) else run_shell('test -f /etc/systemd/system/container-3-6.service', expect_failures: true) end end end context 'passing a storage driver' do let(:pp) do <<-MANIFEST class {'docker': #{docker_args}, storage_driver => "#{storage_driver}", } MANIFEST end it 'applies manifest' do apply_manifest(pp, catch_failures: true) sleep 15 end it 'results in the docker daemon being configured with the specified storage driver' do run_shell("#{docker_command} info -f \"{{ .Driver}}\"") do |r| expect(r.stdout).to match %r{#{storage_driver}} end end end context 'passing a TCP address to bind to' do let(:pp) do <<-MANIFEST class { 'docker': tcp_bind => 'tcp://127.0.0.1:4444', #{docker_args} } MANIFEST end it 'runs idempotently' do idempotent_apply(pp) unless selinux == 'true' sleep 4 end it 'results in docker listening on the specified address' do if os[:family] == 'windows' run_shell('netstat -a -b') do |r| expect(r.stdout).to match(%r{127.0.0.1:4444}) end else run_shell('netstat -tulpn | grep docker') do |r| expect(r.stdout).to match(%r{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 let(:pp) do <<-MANIFEST class { 'docker': socket_bind => 'unix:///var/run/docker.sock', #{docker_args} } MANIFEST end it 'runs idempotently' do idempotent_apply(pp) unless selinux == 'true' sleep 4 end it 'shows docker listening on the specified unix socket' do if os[:family] != 'windows' run_shell('ps aux | grep docker') do |r| expect(r.stdout).to match(%r{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 os[:family] == 'windows' end it 'uninstalls successfully' do pp = <<-EOS class {'docker': #{docker_args}, ensure => 'absent' } EOS apply_manifest(pp, catch_failures: true) sleep 4 run_shell('docker ps', expect_failures: true) end end end describe 'docker::image' do it 'successfullies 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} images") do |r| expect(r.stdout).to match(%r{#{default_image}}) end end it 'successfullies 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} images") do |r| expect(r.stdout).to match(%r{#{default_image}\s+#{default_image_tag}}) end end it 'successfullies 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} images --digests") do |r| expect(r.stdout).to match(%r{#{default_image}.*#{default_digest}}) end end it 'creates a new image based on a Dockerfile' do run_cmd = if os[:family] == 'windows' 'RUN echo test > C:\\Users\\Public\\Dockerfile_test.txt' else "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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 if os[:family] == 'windows' run_shell("#{docker_command} run alpine_with_file cmd /c dir Users\\\\Public") do |r| expect(r.stdout).to match(%r{_test.txt}) end else run_shell("#{docker_command} run alpine_with_file ls #{dockerfile_test}") do |r| expect(r.stdout).to match(%r{#{dockerfile_test}}) end end end it 'creates 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 # Commit currently running container as an image container_id = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") run_shell("#{docker_command} commit #{container_id.stdout.strip} alpine_from_commit") # Stop all container using systemd run_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 run_shell("#{docker_command} rm -f $(docker ps -a -q) || true") # Make sure no other containers are running run_shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(%r{^1$}) end # Export new to a tar file run_shell("#{docker_command} save alpine_from_commit > /root/rootfs.tar") # Remove all images run_shell("#{docker_command} rmi $(docker images -q) || true") # Make sure no other images are present run_shell("#{docker_command} images | wc -l") do |r| expect(r.stdout).to match(%r{^1$}) end apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: true) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} run alpine_from_commit ls /root") do |r| expect(r.stdout).to match(%r{test_file_for_tar_test.txt}) end end it 'successfullies 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} images") do |r| expect(r.stdout).not_to match(%r{#{default_image}}) end end end describe 'docker::run' do it 'starts 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if os[:family] == 'windows' run_shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Users\\\\Public") do |r| expect(r.stdout).to match(%r{test_file.txt}) end else run_shell("#{docker_command} exec #{container_id.stdout.strip} ls /root") do |r| expect(r.stdout).to match(%r{test_file.txt}) end end container_name = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") expect(container_name.stdout.strip.to_s).to match(%r{(container-3-1|container_3_1)}) end it 'starts 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} ps") do |r| expect(r.stdout).to match(%r{#{default_run_command}.+5555\/tcp\, 0\.0\.0.0\:\d+\-\>4444\/tcp}) end end it 'starts 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") run_shell("#{docker_command} exec #{container_id.stdout.strip} hostname") do |r| expect(r.stdout).to match(%r{testdomain.com}) end end it 'starts 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}': ensure => directory, before => File['#{docker_mount_path}/test_mount.txt'], } 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 container_id = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if os[:family] == 'windows' run_shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Users\\\\Public\\\\DockerVolume\\\\mnt") do |r| expect(r.stdout).to match(%r{test_mount.txt}) end else run_shell("#{docker_command} exec #{container_id.stdout.strip} ls /root/mnt") do |r| expect(r.stdout).to match(%r{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 'starts 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell('#{docker_command} inspect container_3_5_5') do |r| expect(r.stdout).to match(%r{"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 'starts 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 container1 = run_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 => ['#{container1.stdout.strip}'], links => "#{container1.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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 container2 = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") container_id = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") run_shell("#{docker_command} inspect -f \"{{ .HostConfig.Links }}\" #{container_id.stdout.strip}") do |r| expect(r.stdout).to match("/#{container1.stdout.strip}:/#{container2.stdout.strip}/the_link") end end it 'stops a running container', win_broken: true 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(%r{^2$}) end apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: true) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 4 run_shell("#{docker_command} ps | wc -l") do |r| expect(r.stdout).to match(%r{^1$}) end end it 'stops 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} inspect container_3_6_1", expect_failures: false) apply_manifest(pp2, catch_failures: true) apply_manifest(pp2, catch_changes: true) unless selinux == 'true' # A sleep to give docker time to execute properly sleep 15 run_shell("#{docker_command} inspect container_3_6_1", expect_failures: true) end it 'allows 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 selinux == 'true' end it 'restarts a unhealthy container' do pp5 = <<-EOS class { 'docker': #{docker_args} } 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 class { 'docker': #{docker_args} } docker::run { 'container_3_7_3': image => '#{default_image}', ensure => absent, } EOS if os[:family] == 'windows' apply_manifest(pp5, catch_failures: true) elsif os[:release] =~ %r{14.04|^8$} apply_manifest(pp5, catch_failures: true) do |r| expect(r.stdout).to match(%r{container_3_7_3}) end else apply_manifest(pp5, catch_failures: true) do |r| expect(r.stdout).to match(%r{docker-container_3_7_3-systemd-reload}) end end apply_manifest(pp_delete, catch_failures: true) end end it 'run with verify_digest' do pp = <<-EOS class { 'docker': #{docker_args} } docker::image { '#{default_image}:#{default_image_tag}': require => Class['docker'], } docker::run { '#{default_image}': image => '#{default_image}:#{default_image_tag}', verify_digest => '#{default_local_digest}', } EOS pp_invalid = <<-EOS docker::run { '#{default_image}': image => '#{default_image}:#{default_image_tag}', verify_digest => 'sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc000', } EOS apply_manifest(pp, catch_failures: true) run_shell('/usr/local/bin/docker-run-alpine-start.sh', expect_failures: false) do |r| expect(r.stdout.include?('Digest verify failed!')).to be false end apply_manifest(pp_invalid, catch_failures: true) run_shell('/usr/local/bin/docker-run-alpine-start.sh', expect_failures: true) do |r| expect(r.stdout.include?('Digest verify failed!')).to be true end end end describe 'docker::exec', win_broken: true do it 'runs 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 15 container1 = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $NF}'") pp2 = <<-EOS class { 'docker': #{docker_args} } docker::exec { 'test_command': container => '#{container1.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 = run_shell("#{docker_command} ps | awk 'FNR == 2 {print $1}'") if os[:family] == 'windows' run_shell("#{docker_command} exec #{container_id.stdout.strip} cmd /c dir Users\\\\Public") do |r| expect(r.stdout).to match(%r{test_file.txt}) end else run_shell("#{docker_command} exec #{container_id.stdout.strip} ls /root") do |r| expect(r.stdout).to match(%r{test_file.txt}) end end apply_manifest(pp_delete, catch_failures: true) end it 'onlies run if notified when refreshonly is true', win_broken: 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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 if os[:family] == 'windows' run_shell("#{docker_command} exec #{container_name} cmd /c dir Users\\\\Public") do |r| expect(r.stdout).not_to match(%r{test_file.txt}) end else run_shell("#{docker_command} exec #{container_name} ls /root") do |r| expect(r.stdout).not_to match(%r{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 selinux == 'true' # A sleep to give docker time to execute properly sleep 4 if os[:family] == 'windows' run_shell("#{docker_command} exec #{container_name} cmd /c dir Users\\\\Public") do |r| expect(r.stdout).to match(%r{home}) end else run_shell("#{docker_command} exec #{container_name} ls /") do |r| expect(r.stdout).to match(%r{home}) end end apply_manifest(pp_delete, catch_failures: true) end end end diff --git a/spec/acceptance/docker_params_changed_spec.rb b/spec/acceptance/docker_params_changed_spec.rb index 041bf4a..e464fed 100644 --- a/spec/acceptance/docker_params_changed_spec.rb +++ b/spec/acceptance/docker_params_changed_spec.rb @@ -1,145 +1,141 @@ require 'spec_helper_acceptance' if os[:family] == 'windows' os_name = run_shell('systeminfo | findstr /R /C:"OS Name"') raise 'Could not retrieve systeminfo for Windows box' if os_name.exit_code != 0 os_name = os_name.stdout.split(%r{\s}).include?('2016') ? 'win-2016' : 'win-2019' docker_args = 'docker_ee => true' docker_network = 'nat' volume_location = 'C:\\' docker_image = if os_name == 'win-2016' 'stefanscherer/nanoserver:sac2016' else 'stefanscherer/nanoserver:10.0.17763.1040' end else - docker_args = if os[:family] == 'redhat' - "repo_opt => '--enablerepo=localmirror-extras'" - else - '' - end + docker_args = '' docker_network = 'bridge' volume_location = '/opt' docker_image = 'hello-world:linux' end describe 'docker trigger parammeters change' do before(:all) do if os[:family] != 'windows' install_pp = "class { 'docker': #{docker_args}}" apply_manifest(install_pp) end run_shell("mkdir #{volume_location}/volume_1") run_shell("mkdir #{volume_location}/volume_2") end context 'when image is changed' do image_changed = if os[:family] == 'windows' if os_name == 'win-2016' 'stefanscherer/nanoserver:10.0.14393.2551' else 'stefanscherer/nanoserver:1809' end else 'hello-world:latest' end let(:pp1) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{docker_image}', restart => 'always', net => '#{docker_network}' } " end let(:pp2) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{image_changed}', restart => 'always', net => '#{docker_network}' } " end it 'creates servercore with first image' do idempotent_apply(pp1) end it 'detect image change and apply the change' do apply_manifest(pp2, catch_failures: true) run_shell('docker inspect --format="{{ .Config.Image }}" servercore') do |r| expect(r.stdout).to match(%r{#{image_changed}}) end end end context 'when volumes parameter is changed' do if os[:family] == 'windows' volumes1 = "volumes => ['volume-1:C:\\volume_1']" volumes2 = "volumes => ['volume-1:C:\\volume_1', 'volume-2:C:\\volume_2']" else volumes1 = "volumes => ['volume-1:#{volume_location}/volume_1']" volumes2 = "volumes => ['volume-1:#{volume_location}/volume_1', 'volume-2:#{volume_location}/volume_2']" end let(:pp1) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{docker_image}', restart => 'always', net => '#{docker_network}', #{volumes1}} " end let(:pp2) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{docker_image}', restart => 'always', net => '#{docker_network}', #{volumes2}} " end it "creates servercore with #{volumes1}" do idempotent_apply(pp1) end it "creates servercore with #{volumes2}" do apply_manifest(pp2, catch_failures: true) run_shell('docker inspect servercore --format="{{ json .Mounts }}"') do |r| inspect_result = JSON.parse(r.stdout) inspect_result = inspect_result.map { |item| item['Name'] }.sort expect(inspect_result).to eq(['volume-1', 'volume-2']) end end end context 'when ports parameter is changed' do ports1 = "ports => ['4444']" ports2 = "ports => ['4444', '4445']" let(:pp1) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{docker_image}', restart => 'always', net => '#{docker_network}', #{ports1}} " end let(:pp2) do " class {'docker': #{docker_args}} docker::run {'servercore': image => '#{docker_image}', restart => 'always', net => '#{docker_network}', #{ports2}} " end it 'creates servercore with ports => ["4444"]' do idempotent_apply(pp1) end it 'creates servercore with ports => ["4444", "4445"]' do apply_manifest(pp2, catch_failures: true) run_shell('docker inspect servercore --format="{{ json .HostConfig.PortBindings }}"') do |r| inspect_result = JSON.parse(r.stdout) inspect_result = inspect_result.keys.map { |item| item.split('/')[0] }.sort expect(inspect_result).to eq(['4444', '4445']) end end end after(:all) do run_shell("rm -r #{volume_location}/volume_1") run_shell("rm -r #{volume_location}/volume_2") end end diff --git a/spec/acceptance/docker_spec.rb b/spec/acceptance/docker_spec.rb index 143cd3e..8d99917 100644 --- a/spec/acceptance/docker_spec.rb +++ b/spec/acceptance/docker_spec.rb @@ -1,320 +1,318 @@ require 'spec_helper_acceptance' broken = false registry_port = 5000 if os[:family] == 'windows' result = run_shell("ipconfig | findstr /i 'ipv4'") raise 'Could not retrieve ip address for Windows box' if result.exit_code != 0 ip = result.stdout.split("\n")[0].split(':')[1].strip @windows_ip = ip docker_args = "docker_ee => true, extra_parameters => '\"insecure-registries\": [ \"#{@windows_ip}:5000\" ]'" root_dir = 'C:/Users/Administrator/AppData/Local/Temp' docker_registry_image = 'stefanscherer/registry-windows' docker_network = 'nat' registry_host = @windows_ip config_file = '/cygdrive/c/Users/Administrator/.docker/config.json' server_strip = "#{registry_host}_#{registry_port}" bad_server_strip = "#{registry_host}_5001" broken = true else - docker_args = if os[:family] == 'redhat' - "repo_opt => '--enablerepo=localmirror-extras'" - elsif os[:name] == 'ubuntu' && os[:release][:full] == '14.04' + docker_args = if os[:name] == 'ubuntu' && os[:release][:full] == '14.04' "version => '18.06.1~ce~3-0~ubuntu'" else '' end docker_registry_image = 'registry' docker_network = 'bridge' registry_host = '127.0.0.1' server_strip = "#{registry_host}:#{registry_port}" bad_server_strip = "#{registry_host}:5001" config_file = '/root/.docker/config.json' root_dir = '/root' end describe 'docker' do package_name = 'docker-ce' service_name = 'docker' command = 'docker' context 'When adding system user', win_broken: broken do let(:pp) do " class { 'docker': #{docker_args}, docker_users => ['user1'] } " end it 'the docker daemon' do apply_manifest(pp, catch_failures: true) do |r| expect(r.stdout).not_to match(%r{docker-systemd-reload-before-service}) end end end context 'When prepare_service_only param is set(prepare_service_only => true)', win_broken: broken do let(:pp) do " class { 'docker': #{docker_args} } docker::run { 'servercore': image => 'hello-world:latest', prepare_service_only => true, } " end it 'creates the service without starting it' do apply_manifest(pp, catch_failures: true) end it 'not start the service' do run_shell('systemctl status docker-servercore', expect_failures: true) do |r| expect(r.stdout.include?('Main PID')).to be false end end end context 'When prepare_service_only param is not set(prepare_service_only => false)', win_broken: broken do let(:pp) do " class { 'docker': #{docker_args} } docker::run { 'servercore': image => 'hello-world:latest', } " end it 'creates the service and start it' do apply_manifest(pp, catch_failures: true) end it 'start the service' do run_shell('systemctl status docker-servercore', expect_failures: true) do |r| expect(r.stdout.include?('Main PID')).to be true end end end context 'When root_dir is set' do let(:pp) do "class { 'docker': #{docker_args}, root_dir => \"#{root_dir}\"}" end let(:shell_command) do if os[:family] == 'windows' 'cat C:/ProgramData/docker/config/daemon.json' else 'systemctl status docker' end end it 'works' do apply_manifest(pp, catch_failures: true) run_shell(shell_command) do |r| if os[:family] == 'windows' expect(r.stdout).to match(%r{\"data-root\": \"#{root_dir}\"}) else expect(r.stdout).to match(%r{--data-root #{root_dir}}) end end end end context 'with default parameters', win_broken: broken do let(:pp) do " class { 'docker': docker_users => [ 'testuser' ], #{docker_args} } docker::image { 'nginx': } docker::run { 'nginx': image => 'nginx', net => 'host', require => Docker::Image['nginx'], } docker::run { 'nginx2': image => 'nginx', restart => 'always', require => Docker::Image['nginx'], } " end it 'applies with no errors' do apply_manifest(pp, catch_failures: true) end it 'is idempotent' do apply_manifest(pp, catch_changes: true) end describe package(package_name) do it { is_expected.to be_installed } end describe service(service_name) do it { is_expected.to be_enabled } it { is_expected.to be_running } end it "#{command} version" do run_shell("#{command} version", expect_failures: false) end it "#{command} images" do result = run_shell("sudo #{command} images", expect_failures: false) expect(result[:exit_code]).to eq 0 expect(result[:stdout]).to match %r{nginx} end it "#{command} inspect nginx" do run_shell("sudo #{command} inspect nginx", expect_failures: false) end it "#{command} inspect nginx2" do run_shell("sudo #{command} inspect nginx2", expect_failures: false) end it "#{command} ps --no-trunc | grep `cat /var/run/docker-nginx2.cid`" do result = run_shell("sudo #{command} ps --no-trunc | grep `cat /var/run/docker-nginx2.cid`", expect_failures: false) expect(result[:exit_code]).to eq 0 expect(result[:stdout]).to match %r{nginx -g 'daemon off;'} end it 'netstat -tlndp' do result = run_shell('netstat -tlndp') expect(result[:exit_code]).to eq 0 expect(result[:stdout]).to match %r{0\.0\.0\.0\:80} end it 'id testuser | grep docker' do result = run_shell('id testuser | grep docker') expect(result[:exit_code]).to eq 0 expect(result[:stdout]).to match %r{docker} end end context 'When asked to have the latest image of something', win_broken: broken do let(:pp) do " class { 'docker': docker_users => [ 'testuser' ] } docker::image { 'busybox': ensure => latest } " end it 'applies with no errors' do apply_manifest(pp, catch_failures: true) end end context 'When registry_mirror is set', win_broken: broken do let(:pp) do " class { 'docker': registry_mirror => 'http://testmirror.io' } " end it 'applies with no errors' do apply_manifest(pp, catch_failures: true) end it 'has a registry mirror set' do run_shell('ps -aux | grep docker') do |r| expect(r.stdout).to match(%r{--registry-mirror=http:\/\/testmirror.io}) end end end context 'When registry_mirror is array', win_broken: broken do let(:pp) do " class { 'docker': registry_mirror => ['http://testmirror1.io', 'http://testmirror2.io'] } " end it 'applies with no errors' do apply_manifest(pp, catch_failures: true) end it 'has all registry mirrors set' do run_shell('ps -aux | grep docker') do |r| expect(r.stdout).to match(%r{--registry-mirror=http:\/\/testmirror1.io}) expect(r.stdout).to match(%r{--registry-mirror=http:\/\/testmirror2.io}) end end end context 'registry' do let(:registry_address) do "#{registry_host}:#{registry_port}" end let(:registry_bad_address) do "#{registry_host}:5001" end it 'is able to run registry' do pp = <<-MANIFEST class { 'docker': #{docker_args}} docker::run { 'registry': image => '#{docker_registry_image}', pull_on_start => true, restart => 'always', net => '#{docker_network}', ports => '#{registry_port}:#{registry_port}', } MANIFEST retry_on_error_matching(60, 5, %r{connection failure running}) do apply_manifest(pp, catch_failures: true) end # avoid a race condition with the registry taking time to start # on some operating systems sleep 10 end it 'is able to login to the registry', retry: 3, retry_wait: 10, win_broken: true do pp = <<-MANIFEST docker::registry { '#{registry_address}': username => 'username', password => 'password', } MANIFEST apply_manifest(pp, catch_failures: true) run_shell("grep #{registry_address} #{config_file}", expect_failures: false) run_shell("test -e \"#{root_dir}/registry-auth-puppet_receipt_#{server_strip}_root\"", expect_failures: false) end it 'is able to logout from the registry', win_broken: true do pp = <<-MANIFEST docker::registry { '#{registry_address}': ensure=> absent, } MANIFEST apply_manifest(pp, catch_failures: true) run_shell("grep #{registry_address} #{config_file}", expect_failures: true) end it 'does not create receipt if registry login fails', win_broken: true do pp = <<-MANIFEST docker::registry { '#{registry_bad_address}': username => 'username', password => 'password', } MANIFEST apply_manifest(pp, catch_failures: false) run_shell("grep #{registry_bad_address} #{config_file}", expect_failures: true) run_shell("test -e \"#{root_dir}/registry-auth-puppet_receipt_#{bad_server_strip}_root\"", expect_failures: true) end end end diff --git a/spec/acceptance/network_spec.rb b/spec/acceptance/network_spec.rb index 276d162..174e5d1 100644 --- a/spec/acceptance/network_spec.rb +++ b/spec/acceptance/network_spec.rb @@ -1,46 +1,44 @@ require 'spec_helper_acceptance' broken = false command = 'docker' network_name = 'test-network' if os[:family] == 'windows' puts 'Not implemented on Windows' broken = true -elsif os[:family] == 'RedHat' - docker_args = "repo_opt => '--enablerepo=localmirror-extras'" -elsif os[:name] == 'Ubuntu' && os[:release][:full] == '14.04' +elsif os[:name] == 'ubuntu' && os[:release][:full] == '14.04' docker_args = "version => '18.06.1~ce~3-0~ubuntu'" else docker_args = '' end describe 'docker network', win_broken: broken do before(:all) do install_pp = "class { 'docker': #{docker_args}}" apply_manifest(install_pp, catch_failures: true) end it "#{command} network --help" do run_shell("#{command} network --help", expect_failures: false) end context 'with a local bridge network described in Puppet' do after(:all) do run_shell("#{command} network rm #{network_name}") end it 'is idempotent' do pp = <<-MANIFEST docker_network { '#{network_name}': ensure => present, } MANIFEST idempotent_apply(pp) end it 'has created a network' do run_shell("#{command} network inspect #{network_name}", expect_failures: false) end end end diff --git a/spec/acceptance/plugin_spec.rb b/spec/acceptance/plugin_spec.rb index db96d2e..b9f2c74 100644 --- a/spec/acceptance/plugin_spec.rb +++ b/spec/acceptance/plugin_spec.rb @@ -1,44 +1,42 @@ require 'spec_helper_acceptance' broken = false command = 'docker' plugin_name = 'vieux/sshfs' if os[:family] == 'windows' puts 'Not implemented on Windows' broken = true -elsif os[:family] == 'RedHat' - docker_args = "repo_opt => '--enablerepo=localmirror-extras'" -elsif os[:name] == 'Ubuntu' && os[:release][:full] == '14.04' +elsif os[:name] == 'ubuntu' && os[:release][:full] == '14.04' docker_args = "version => '18.06.1~ce~3-0~ubuntu'" else docker_args = '' end describe 'docker plugin', win_broken: broken do before(:all) do install_code = "class { 'docker': #{docker_args}}" apply_manifest(install_code, catch_failures: true) end it "#{command} plugin --help" do run_shell("#{command} plugin --help", expect_failures: false) end context 'manage a plugin' do after(:all) do run_shell("#{command} plugin rm -f #{plugin_name}") end it 'is idempotent' do pp = <<-MANIFEST docker::plugin { '#{plugin_name}':} MANIFEST idempotent_apply(pp) end it 'has installed a plugin' do run_shell("#{command} plugin inspect #{plugin_name}", expect_failures: false) end end end diff --git a/spec/acceptance/volume_spec.rb b/spec/acceptance/volume_spec.rb index c0b71cc..b9974ce 100644 --- a/spec/acceptance/volume_spec.rb +++ b/spec/acceptance/volume_spec.rb @@ -1,50 +1,47 @@ require 'spec_helper_acceptance' volume_name = 'test-volume' if os[:family] == 'windows' docker_args = 'docker_ee => true' command = '"/cygdrive/c/Program Files/Docker/docker"' -elsif 'osfamily' == 'RedHat' - docker_args = "repo_opt => '--enablerepo=localmirror-extras'" - command = 'docker' -elsif os[:name] == 'Ubuntu' && os[:release][:full] == '14.04' +elsif os[:name] == 'ubuntu' && os[:release][:full] == '14.04' docker_args = "version => '18.06.1~ce~3-0~ubuntu'" command = 'docker' else docker_args = '' command = 'docker' end describe 'docker volume' do before(:all) do retry_on_error_matching(60, 5, %r{connection failure running}) do install_pp = "class { 'docker': #{docker_args} }" apply_manifest(install_pp, catch_failures: true) end end it 'exposes volume subcommand' do run_shell("#{command} volume --help", expect_failures: false) end context 'with a local volume described in Puppet' do it 'applies idempotently' do pp = <<-MANIFEST docker_volume { '#{volume_name}': ensure => present, } MANIFEST idempotent_apply(pp) end it 'has created a volume' do run_shell("#{command} volume inspect #{volume_name}", expect_failures: false) end after(:all) do run_shell("#{command} volume rm #{volume_name}") end end end diff --git a/spec/spec_helper_acceptance_local.rb b/spec/spec_helper_acceptance_local.rb index e65dd94..0a8ea62 100644 --- a/spec/spec_helper_acceptance_local.rb +++ b/spec/spec_helper_acceptance_local.rb @@ -1,190 +1,193 @@ require 'puppet_litmus' require 'rspec/retry' require 'tempfile' include PuppetLitmus # This method allows a block to be passed in and if an exception is raised # that matches the 'error_matcher' matcher, the block will wait a set number # of seconds before retrying. # Params: # - max_retry_count - Max number of retries # - retry_wait_interval_secs - Number of seconds to wait before retry # - error_matcher - Matcher which the exception raised must match to allow retry # Example Usage: # retry_on_error_matching(3, 5, /OpenGPG Error/) do # apply_manifest(pp, :catch_failures => true) # end def retry_on_error_matching(max_retry_count = 3, retry_wait_interval_secs = 5, error_matcher = nil) try = 0 begin try += 1 yield rescue StandardError => e raise unless try < max_retry_count && (error_matcher.nil? || e.message =~ error_matcher) sleep retry_wait_interval_secs retry end end def create_remote_file(name, full_name, file_content) Tempfile.open name do |tempfile| File.open(tempfile.path, 'w') { |file| file.puts file_content } bolt_upload_file(tempfile.path, full_name) end end RSpec.configure do |c| # Add exclusive filter for Windows untill all the windows functionality is implemented c.filter_run_excluding win_broken: true # Readable test descriptions c.formatter = :documentation # show retry status in spec process c.verbose_retry = true # show exception that triggers a retry if verbose_retry is set to true c.display_try_failure_messages = true # Configure all nodes in nodeset c.before :suite do # Install module and dependencies # Due to RE-6764, running yum update renders the machine unable to install # other software. Thus this workaround. if os[:family] == 'redhat' run_shell('mv /etc/yum.repos.d/redhat.repo /etc/yum.repos.d/internal-mirror.repo', expect_failures: true) run_shell('rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm', expect_failures: true) run_shell('yum update -y -q') # run_shell('yum upgrade -y') end if os[:family] == 'debian' || os[:family] == 'ubuntu' run_shell('apt-get update -y') # run_shell('apt-get upgrade -y') run_shell('apt-get install -y lsb-release') run_shell('apt-get install -y net-tools') end run_shell('puppet module install puppetlabs-stdlib --version 4.24.0', expect_failures: true) run_shell('puppet module install puppetlabs-apt --version 4.4.1', expect_failures: true) run_shell('puppet module install puppetlabs-translate --version 1.0.0', expect_failures: true) run_shell('puppet module install puppetlabs-powershell --version 2.1.5', expect_failures: true) run_shell('puppet module install puppetlabs-reboot --version 2.0.0', expect_failures: true) # net-tools required for netstat utility being used by some tests if os[:family] == 'redhat' && os[:release].to_i == 7 - run_shell('yum install -y net-tools device-mapper') + run_shell('yum -y install lvm2 device-mapper device-mapper-persistent-data device-mapper-event device-mapper-libs device-mapper-event-libs') + run_shell('yum install -y yum-utils net-tools') + run_shell('yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo') + run_shell('yum-config-manager --enable docker\*') end docker_compose_content_v3 = <<-EOS version: "3.4" x-images: &default-image alpine:3.8 services: compose_test: image: *default-image command: /bin/sh -c "while true; do echo hello world; sleep 1; done" EOS docker_compose_override_v3 = <<-EOS version: "3.4" x-images: &default-image debian:stable-slim services: compose_test: image: *default-image command: /bin/sh -c "while true; do echo hello world; sleep 1; done" EOS docker_stack_override_v3 = <<-EOS version: "3.4" x-images: &default-image debian:stable-slim services: compose_test: image: *default-image command: /bin/sh -c "while true; do echo hello world; sleep 1; done" EOS docker_compose_content_v3_windows = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle command: cmd.exe /C "ping 8.8.8.8 -t" networks: default: external: name: nat EOS docker_compose_override_v3_windows = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle:nanoserver command: cmd.exe /C "ping 8.8.8.8 -t" networks: default: external: name: nat EOS docker_compose_override_v3_windows2016 = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle:nanoserver-sac2016 command: cmd.exe /C "ping 8.8.8.8 -t" networks: default: external: name: nat EOS docker_stack_content_windows = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle command: cmd.exe /C "ping 8.8.8.8 -t" EOS docker_stack_override_windows = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle:nanoserver EOS docker_stack_override_windows2016 = <<-EOS version: "3" services: compose_test: image: winamd64/hello-seattle:nanoserver-sac2016 EOS if os[:family] == 'windows' create_remote_file(host, '/tmp/docker-compose-v3.yml', docker_compose_content_v3_windows) create_remote_file(host, '/tmp/docker-stack.yml', docker_stack_content_windows) if os[:release] =~ %r{2019} create_remote_file(host, '/tmp/docker-compose-override-v3.yml', docker_compose_override_v3_windows) create_remote_file(host, '/tmp/docker-stack-override.yml', docker_stack_override_windows) else create_remote_file(host, '/tmp/docker-compose-override-v3.yml', docker_compose_override_v3_windows2016) create_remote_file(host, '/tmp/docker-stack-override.yml', docker_stack_override_windows2016) end else create_remote_file(host, '/tmp/docker-compose-v3.yml', docker_compose_content_v3) create_remote_file(host, '/tmp/docker-stack.yml', docker_compose_content_v3) create_remote_file(host, '/tmp/docker-compose-override-v3.yml', docker_compose_override_v3) create_remote_file(host, '/tmp/docker-stack-override.yml', docker_stack_override_v3) end next unless os[:family] == 'windows' result = run_shell("ipconfig | findstr /i 'ipv4'") raise 'Could not retrieve ip address for Windows box' if result.exit_code != 0 ip = result.stdout.split("\n")[0].split(':')[1].strip retry_on_error_matching(60, 5, %r{connection failure running}) do @windows_ip = ip end apply_manifest("class { 'docker': docker_ee => true, extra_parameters => '\"insecure-registries\": [ \"#{@windows_ip}:5000\" ]' }", catch_failures: true) docker_path = 'C:\\Program Files\\Docker' run_shell("set PATH \"%PATH%;C:\\Users\\Administrator\\AppData\\Local\\Temp;#{docker_path}\"") puts 'Waiting for box to come online' sleep 300 end end