diff --git a/lib/puppet/provider/docker_compose/ruby.rb b/lib/puppet/provider/docker_compose/ruby.rb index 0d196d54..b1c1b15f 100644 --- a/lib/puppet/provider/docker_compose/ruby.rb +++ b/lib/puppet/provider/docker_compose/ruby.rb @@ -9,8 +9,6 @@ has_command(:docker, 'docker') - has_command(:dockercompose, 'docker-compose') - def set_tmpdir return unless resource[:tmpdir] @@ -28,8 +26,8 @@ def exists? set_tmpdir # get merged config using docker-compose config - args = [compose_files, '-p', name, 'config'].insert(3, resource[:options]).compact - compose_output = Puppet::Util::Yaml.safe_load(execute([command(:dockercompose)] + args, combine: false), [Symbol]) + args = ['compose', compose_files, '-p', name, 'config'].insert(3, resource[:options]).compact + compose_output = Puppet::Util::Yaml.safe_load(execute([command(:docker)] + args, combine: false), [Symbol]) containers = docker([ 'ps', @@ -76,32 +74,32 @@ def get_image(service_name, compose_services) def create Puppet.info("Running compose project #{name}") - args = [compose_files, '-p', name, 'up', '-d', '--remove-orphans'].insert(3, resource[:options]).insert(5, resource[:up_args]).compact - dockercompose(args) + args = ['compose', compose_files, '-p', name, 'up', '-d', '--remove-orphans'].insert(3, resource[:options]).insert(5, resource[:up_args]).compact + docker(args) return unless resource[:scale] instructions = resource[:scale].map { |k, v| "#{k}=#{v}" } Puppet.info("Scaling compose project #{name}: #{instructions.join(' ')}") - args = [compose_files, '-p', name, 'scale'].insert(3, resource[:options]).compact + instructions - dockercompose(args) + args = ['compose', compose_files, '-p', name, 'scale'].insert(3, resource[:options]).compact + instructions + docker(args) end def destroy Puppet.info("Removing all containers for compose project #{name}") - kill_args = [compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact - dockercompose(kill_args) - rm_args = [compose_files, '-p', name, 'rm', '--force', '-v'].insert(3, resource[:options]).compact - dockercompose(rm_args) + kill_args = ['compose', compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact + docker(kill_args) + rm_args = ['compose', compose_files, '-p', name, 'rm', '--force', '-v'].insert(3, resource[:options]).compact + docker(rm_args) end def restart return unless exists? Puppet.info("Rebuilding and Restarting all containers for compose project #{name}") - kill_args = [compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact - dockercompose(kill_args) - build_args = [compose_files, '-p', name, 'build'].insert(3, resource[:options]).compact - dockercompose(build_args) + kill_args = ['compose', compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact + docker(kill_args) + build_args = ['compose', compose_files, '-p', name, 'build'].insert(3, resource[:options]).compact + docker(build_args) create end diff --git a/manifests/compose.pp b/manifests/compose.pp index fc485909..1a2e68cd 100644 --- a/manifests/compose.pp +++ b/manifests/compose.pp @@ -7,118 +7,48 @@ # @param version # The version of Docker Compose to install. # -# @param install_path -# The path where to install Docker Compose. -# -# @param symlink_name -# The name of the symlink created pointing to the actual docker-compose binary -# This allows use of own docker-compose wrapper scripts for the times it's -# necessary to set certain things before running the docker-compose binary -# -# @param proxy -# Proxy to use for downloading Docker Compose. -# -# @param base_url -# The base url for installation -# This allows use of a mirror that follows the same layout as the -# official repository -# -# @param raw_url -# Override the raw URL for installation -# The default is to build a URL from baseurl. If rawurl is set, the caller is -# responsible for ensuring the URL points to the correct version and -# architecture. -# -# @param curl_ensure -# Whether or not the curl package is ensured by this module. -# class docker::compose ( - Enum[present,absent] $ensure = present, - Optional[String] $version = $docker::params::compose_version, - Optional[String] $install_path = $docker::params::compose_install_path, - Optional[String] $symlink_name = $docker::params::compose_symlink_name, - Optional[Pattern['^((http[s]?)?:\/\/)?([^:^@]+:[^:^@]+@|)([\da-z\.-]+)\.([\da-z\.]{2,6})(:[\d])?([\/\w \.-]*)*\/?$']] $proxy = undef, - Optional[String] $base_url = $docker::params::compose_base_url, - Optional[String] $raw_url = undef, - Optional[Boolean] $curl_ensure = $docker::params::curl_ensure, -) inherits docker::params { - if $facts['os']['family'] == 'windows' { - $file_extension = '.exe' - $file_owner = 'Administrator' - } else { - $file_extension = '' - $file_owner = 'root' - } + Enum[present,absent] $ensure = present, + Optional[String] $version = undef, +) { + include docker - $docker_compose_location = "${install_path}/${symlink_name}${file_extension}" - $docker_compose_location_versioned = "${install_path}/docker-compose-${version}${file_extension}" + if $docker::manage_package { + include docker::params - if $ensure == 'present' { - if $raw_url != undef { - $docker_compose_url = $raw_url - } else { - $docker_compose_url = "${base_url}/${version}/docker-compose-${facts['kernel']}-${facts['os']['hardware']}${file_extension}" + $_version = $version ? { + undef => $docker::params::compose_version, + default => $version, } - - if $proxy != undef { - $proxy_opt = "--proxy ${proxy}" + if $_version and $ensure != 'absent' { + $package_ensure = $_version } else { - $proxy_opt = '' + $package_ensure = $ensure } - if $facts['os']['family'] == 'windows' { - $docker_download_command = "if (Invoke-WebRequest ${docker_compose_url} ${proxy_opt} -UseBasicParsing -OutFile \"${docker_compose_location_versioned}\") { exit 0 } else { exit 1}" # lint:ignore:140chars - - $parameters = { - 'proxy' => $proxy, - 'docker_compose_url' => $docker_compose_url, - 'docker_compose_location_versioned' => $docker_compose_location_versioned, + case $facts['os']['family'] { + 'Debian': { + $_require = $docker::use_upstream_package_source ? { + true => [Apt::Source['docker'], Class['apt::update']], + false => undef, + } } - - exec { "Install Docker Compose ${version}": - command => epp('docker/windows/download_docker_compose.ps1.epp', $parameters), - provider => powershell, - creates => $docker_compose_location_versioned, + 'RedHat': { + $_require = $docker::use_upstream_package_source ? { + true => Yumrepo['docker'], + false => undef, + } } - - file { $docker_compose_location: - ensure => 'link', - target => $docker_compose_location_versioned, - require => Exec["Install Docker Compose ${version}"], - } - } else { - if $curl_ensure { - stdlib::ensure_packages(['curl']) - } - - exec { "Install Docker Compose ${version}": - path => '/usr/bin/', - cwd => '/tmp', - command => "curl -s -S -L ${proxy_opt} ${docker_compose_url} -o ${docker_compose_location_versioned}", - creates => $docker_compose_location_versioned, - require => Package['curl'], + 'Windows': { + fail('The docker compose portion of this module is not supported on Windows') } - - file { $docker_compose_location_versioned: - owner => $file_owner, - mode => '0755', - seltype => 'container_runtime_exec_t', - require => Exec["Install Docker Compose ${version}"], - } - - file { $docker_compose_location: - ensure => 'link', - target => $docker_compose_location_versioned, - require => File[$docker_compose_location_versioned], + default: { + fail('The docker compose portion of this module only works on Debian or RedHat') } } - } else { - file { $docker_compose_location_versioned: - ensure => absent, - } - - file { $docker_compose_location: - ensure => absent, + package { 'docker-compose-plugin': + ensure => $package_ensure, + require => $_require, } } } diff --git a/manifests/params.pp b/manifests/params.pp index 540abee9..86984dd9 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -47,8 +47,7 @@ $dns = undef $dns_search = undef $proxy = undef - $compose_base_url = 'https://github.com/docker/compose/releases/download' - $compose_symlink_name = 'docker-compose' + $compose_version = undef $no_proxy = undef $execdriver = undef $storage_driver = undef @@ -90,16 +89,12 @@ $docker_command = 'docker' if ($facts['os']['family'] == 'windows') { - $compose_install_path = "${facts['docker_program_files_path']}/Docker" - $compose_version = '1.29.2' $docker_ee_package_name = 'Docker' $machine_install_path = "${facts['docker_program_files_path']}/Docker" $tls_cacert = "${facts['docker_program_data_path']}/docker/certs.d/ca.pem" $tls_cert = "${facts['docker_program_data_path']}/docker/certs.d/server-cert.pem" $tls_key = "${facts['docker_program_data_path']}/docker/certs.d/server-key.pem" } else { - $compose_install_path = '/usr/local/bin' - $compose_version = '1.29.2' $docker_ee_package_name = 'docker-ee' $machine_install_path = '/usr/local/bin' $tls_cacert = '/etc/docker/tls/ca.pem' diff --git a/spec/acceptance/compose_v3_spec.rb b/spec/acceptance/compose_v3_spec.rb index 75f3a309..729dcf84 100644 --- a/spec/acceptance/compose_v3_spec.rb +++ b/spec/acceptance/compose_v3_spec.rb @@ -2,38 +2,21 @@ 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 %r{2019|2022}.match?(os[:release]) - 'nanoserver' - else - 'nanoserver-sac2016' - end -else - docker_args = '' - install_dir = '/usr/local/bin' - file_extension = '' - tmp_path = '/tmp' - test_container = 'debian' -end +tmp_path = '/tmp' +test_container = 'debian' -describe 'docker compose' do +describe 'docker compose', :win_broken 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', - } + class { 'docker': } + class { 'docker::compose': } CODE apply_manifest(install_code, catch_failures: true) end end - context 'Creating compose v3 projects', :win_broken do + context 'Creating compose v3 projects' do let(:install_pp) do <<-MANIFEST docker_compose { 'web': @@ -51,15 +34,15 @@ class { 'docker::compose': end it 'has docker compose installed' do - run_shell('docker-compose --help', expect_failures: false) + 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) + run_shell('docker inspect web-compose_test_1', expect_failures: false) end end - context 'creating compose projects with multi compose files', :win_broken do + context 'creating compose projects with multi compose files' do before(:all) do install_pp = <<-MANIFEST docker_compose { 'web1': @@ -75,11 +58,11 @@ class { 'docker::compose': end it "finds container with #{test_container} tag" do - run_shell("docker inspect web1_compose_test_1 | grep #{test_container}", acceptable_exit_codes: [0]) + 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 do + context 'Destroying project with multiple compose files' do let(:destroy_pp) do <<-MANIFEST docker_compose { 'web1': @@ -105,31 +88,26 @@ class { 'docker::compose': end it 'does not find a docker container' do - run_shell('docker inspect web1_compose_test_1', expect_failures: true) + 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' + '2.25.0' end it 'is idempotent' do pp = <<-MANIFEST class { 'docker::compose': - version => '#{version}', + version => '#{version}-*', } MANIFEST idempotent_apply(pp) end it 'has installed the requested version' do - if os[:family] == 'redhat' && os[:release].to_i == 7 - run_shell('sudo mv /usr/local/bin/docker-compose /usr/bin/docker-compose') - run_shell('sudo chmod +x /usr/bin/docker-compose') - end - command = 'docker-compose --version' - command = "export PATH=/usr/local/bin:$PATH && #{command}" if os[:family] == 'redhat' + command = 'docker compose version' run_shell(command, expect_failures: false) do |r| expect(r.stdout).to match(%r{#{version}}) @@ -138,13 +116,9 @@ class { 'docker::compose': end context 'Removing docker compose' do - let(:version) do - '1.21.2' - end - after(:all) do install_pp = <<-MANIFEST - class { 'docker': #{docker_args}} + class { 'docker': } class { 'docker::compose': } MANIFEST apply_manifest(install_pp, catch_failures: true) @@ -154,15 +128,13 @@ class { 'docker::compose': } 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) + it 'has removed the compose plugin' do + run_shell('docker compose version', expect_failures: true) end end end diff --git a/spec/classes/compose_spec.rb b/spec/classes/compose_spec.rb index 84835fc2..3d473e31 100644 --- a/spec/classes/compose_spec.rb +++ b/spec/classes/compose_spec.rb @@ -9,29 +9,6 @@ }, 'with version => 1.7.0' => { 'version' => '1.7.0' - }, - 'when proxy is provided' => { - 'version' => '1.7.0', - 'proxy' => 'http://proxy.example.org:3128/' - }, - 'when proxy is not a http proxy' => { - 'proxy' => 'this is not a URL' - }, - 'when proxy contains username and password' => { - 'version' => '1.7.0', - 'proxy' => 'http://user:password@proxy.example.org:3128/' - }, - 'when proxy IP is provided' => { - 'version' => '1.7.0', - 'proxy' => 'http://10.10.10.10:3128/' - }, - 'when base_url is provided' => { - 'version' => '1.7.0', - 'base_url' => 'http://example.org' - }, - 'when raw_url is provided' => { - 'version' => '1.7.0', - 'raw_url' => 'http://example.org' } } @@ -56,13 +33,7 @@ context title do params = { 'ensure' => 'present', - 'version' => defaults['compose_version'], - 'install_path' => defaults['compose_install_path'], - 'symlink_name' => defaults['compose_symlink_name'], - 'proxy' => :undef, - 'base_url' => defaults['compose_base_url'], - 'raw_url' => :undef, - 'curl_ensure' => defaults['curl_ensure'] + 'version' => defaults['compose_version'] }.merge(local_params) let(:facts) do @@ -73,15 +44,7 @@ params end - if title == 'when proxy is not a http proxy' - it 'raises an error for invalid proxy URL' do - expect(subject).to compile.and_raise_error( - %r{parameter 'proxy' expects an undef value or a match for Pattern}, - ) - end - else - include_examples 'compose', params, facts - end + include_examples 'compose', params, facts end end end diff --git a/spec/helper/get_defaults.rb b/spec/helper/get_defaults.rb index c4ea9b08..aeffaaab 100644 --- a/spec/helper/get_defaults.rb +++ b/spec/helper/get_defaults.rb @@ -3,8 +3,6 @@ def get_defaults(_facts) bip = :undef bridge = :undef - compose_base_url = 'https://github.com/docker/compose/releases/download' - compose_symlink_name = 'docker-compose' curl_ensure = true default_gateway = :undef default_gateway_ipv6 = :undef @@ -88,18 +86,15 @@ def get_defaults(_facts) tmp_dir = '/tmp/' tmp_dir_config = true version = :undef + compose_version = :undef if _facts[:os]['family'] == 'windows' - compose_install_path = "#{_facts['docker_program_files_path']}/Docker" - compose_version = '1.21.2' docker_ee_package_name = 'Docker' machine_install_path = "#{_facts['docker_program_files_path']}/Docker" tls_cacert = "#{_facts['docker_program_data_path']}/docker/certs.d/ca.pem" tls_cert = "#{_facts['docker_program_data_path']}/docker/certs.d/server-cert.pem" tls_key = "#{_facts['docker_program_data_path']}/docker/certs.d/server-key.pem" else - compose_install_path = '/usr/local/bin' - compose_version = '1.9.0' docker_ee_package_name = 'docker-ee' machine_install_path = '/usr/local/bin' tls_cacert = '/etc/docker/tls/ca.pem' @@ -340,9 +335,6 @@ def get_defaults(_facts) 'apt_source_pin_level' => apt_source_pin_level, 'bip' => bip, 'bridge' => bridge, - 'compose_base_url' => compose_base_url, - 'compose_install_path' => compose_install_path, - 'compose_symlink_name' => compose_symlink_name, 'compose_version' => compose_version, 'curl_ensure' => curl_ensure, 'default_gateway' => default_gateway, diff --git a/spec/shared_examples/compose.rb b/spec/shared_examples/compose.rb index a34790c2..0f763387 100644 --- a/spec/shared_examples/compose.rb +++ b/spec/shared_examples/compose.rb @@ -3,95 +3,22 @@ shared_examples 'compose' do |_params, _facts| ensure_value = _params['ensure'] version = _params['version'] - install_path = _params['install_path'] - symlink_name = _params['symlink_name'] - proxy = _params['proxy'] - base_url = _params['base_url'] - raw_url = _params['raw_url'] - curl_ensure = _params['curl_ensure'] - if _facts[:os]['family'] == 'windows' - file_extension = '.exe' - file_owner = 'Administrator' - else - file_extension = '' - file_owner = 'root' - end - - docker_compose_location = "#{install_path}/#{symlink_name}#{file_extension}" - docker_compose_location_versioned = "#{install_path}/docker-compose-#{version}#{file_extension}" - - if ensure_value == 'present' - docker_compose_url = if raw_url == :undef - "#{base_url}/#{version}/docker-compose-#{_facts[:kernel]}-x86_64#{file_extension}" - else - raw_url - end - - proxy_opt = if proxy == :undef - '' - else - "--proxy #{proxy}" - end - - if _facts[:os]['family'] == 'windows' - docker_download_command = "if (Invoke-WebRequest #{docker_compose_url} #{proxy_opt} -UseBasicParsing -OutFile \"#{docker_compose_location_versioned}\") { exit 0 } else { exit 1 }" - - it { - expect(subject).to contain_exec("Install Docker Compose #{version}").with( - 'provider' => 'powershell', - 'creates' => docker_compose_location_versioned, - ) - - expect(subject).to contain_file(docker_compose_location).with( - 'ensure' => 'link', - 'target' => docker_compose_location_versioned, - ).that_requires( - "Exec[Install Docker Compose #{version}]", - ) - } - else - if curl_ensure - it { - expect(subject).to contain_package('curl') - } + if _params['manage_package'] + ensure_value = + if _params['version'] != :undef && _params['ensure'] != 'absent' + _params['version'] + else + _params['ensure'] end + case _facts['os']['family'] + when 'Debian', 'RedHat' it { - expect(subject).to contain_exec("Install Docker Compose #{version}").with( - 'path' => '/usr/bin/', - 'cwd' => '/tmp', - 'command' => "curl -s -S -L #{proxy_opt} #{docker_compose_url} -o #{docker_compose_location_versioned}", - 'creates' => docker_compose_location_versioned, - ).that_requires( - 'Package[curl]', - ) - - expect(subject).to contain_file(docker_compose_location_versioned).with( - 'owner' => file_owner, - 'mode' => '0755', - ).that_requires( - "Exec[Install Docker Compose #{version}]", - ) - - expect(subject).to contain_file(docker_compose_location).with( - 'ensure' => 'link', - 'target' => docker_compose_location_versioned, - ).that_requires( - "File[#{docker_compose_location_versioned}]", + expect(subject).to contain_package('docker-compose-plugin').with( + ensure: ensure_value, ) } end - else - - it { - expect(subject).to contain_file(docker_compose_location_versioned).with( - 'ensure' => 'absent', - ) - - expect(subject).to contain_file(docker_compose_location).with( - 'ensure' => 'absent', - ) - } end end diff --git a/spec/spec_helper_acceptance_local.rb b/spec/spec_helper_acceptance_local.rb index 17c7fd43..2d86750c 100644 --- a/spec/spec_helper_acceptance_local.rb +++ b/spec/spec_helper_acceptance_local.rb @@ -112,39 +112,6 @@ def fetch_puppet_version 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: @@ -165,13 +132,10 @@ def fetch_puppet_version 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 %r{2019|2022}.match?(os[:release]) - 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