diff --git a/manifests/image.pp b/manifests/image.pp index 282097f..72d9c63 100644 --- a/manifests/image.pp +++ b/manifests/image.pp @@ -1,157 +1,171 @@ # == Class: docker # # Module to install an up-to-date version of a Docker image # from the registry # # === Parameters # [*ensure*] # Whether you want the image present or absent. # # [*image*] # If you want the name of the image to be different from the # name of the puppet resource you can pass a value here. # # [*image_tag*] # If you want a specific tag of the image to be installed # # [*image_digest*] # If you want a specific content digest of the image to be installed # # [*docker_file*] # If you want to add a docker image from specific docker file # # [*docker_tar*] # If you want to load a docker image from specific docker tar # define docker::image( Optional[Pattern[/^(present|absent|latest)$/]] $ensure = 'present', Optional[Pattern[/^[\S]*$/]] $image = $title, Optional[String] $image_tag = undef, Optional[String] $image_digest = undef, Optional[Boolean] $force = false, Optional[String] $docker_file = undef, Optional[String] $docker_dir = undef, Optional[String] $docker_tar = undef, ) { include docker::params $docker_command = $docker::params::docker_command if $::osfamily == 'windows' { $update_docker_image_template = 'docker/windows/update_docker_image.ps1.erb' $update_docker_image_path = "${::docker_user_temp_path}/update_docker_image.ps1" $exec_environment = "PATH=${::docker_program_files_path}/Docker/" $exec_timeout = 3000 $update_docker_image_owner = undef $exec_path = ["${::docker_program_files_path}/Docker/"] $exec_provider = 'powershell' } else { $update_docker_image_template = 'docker/update_docker_image.sh.erb' $update_docker_image_path = '/usr/local/bin/update_docker_image.sh' $update_docker_image_owner = 'root' $exec_environment = 'HOME=/root' $exec_path = ['/bin', '/usr/bin'] $exec_timeout = 0 $exec_provider = undef } # Wrapper used to ensure images are up to date ensure_resource('file', $update_docker_image_path, { ensure => $docker::params::ensure, owner => $update_docker_image_owner, group => $update_docker_image_owner, mode => '0555', content => template($update_docker_image_template), } ) if ($docker_file) and ($docker_tar) { fail translate('docker::image must not have both $docker_file and $docker_tar set') } if ($docker_dir) and ($docker_tar) { fail translate('docker::image must not have both $docker_dir and $docker_tar set') } if ($image_digest) and ($docker_file) { fail translate('docker::image must not have both $image_digest and $docker_file set') } if ($image_digest) and ($docker_dir) { fail translate('docker::image must not have both $image_digest and $docker_dir set') } if ($image_digest) and ($docker_tar) { fail translate('docker::image must not have both $image_digest and $docker_tar set') } if $force { $image_force = '-f ' } else { $image_force = '' } if $image_tag { $image_arg = "${image}:${image_tag}" $image_remove = "${docker_command} rmi ${image_force}${image}:${image_tag}" $image_find = "${docker_command} images -q ${image}:${image_tag}" } elsif $image_digest { $image_arg = "${image}@${image_digest}" $image_remove = "${docker_command} rmi ${image_force}${image}:${image_digest}" $image_find = "${docker_command} images -q ${image}@${image_digest}" } else { $image_arg = $image $image_remove = "${docker_command} rmi ${image_force}${image}" $image_find = "${docker_command} images -q ${image}" } if $::osfamily == 'windows' { $_image_find = "If (-not (${image_find}) ) { Exit 1 }" } else { $_image_find = "${image_find} | grep ." } if ($docker_dir) and ($docker_file) { $image_install = "${docker_command} build -t ${image_arg} -f ${docker_file} ${docker_dir}" } elsif $docker_dir { $image_install = "${docker_command} build -t ${image_arg} ${docker_dir}" } elsif $docker_file { if $::osfamily == windows { $image_install = "Get-Content ${docker_file} -Raw | ${docker_command} build -t ${image_arg} -" } else { $image_install = "${docker_command} build -t ${image_arg} - < ${docker_file}" } } elsif $docker_tar { $image_install = "${docker_command} load -i ${docker_tar}" } else { if $::osfamily == 'windows' { $image_install = "& ${update_docker_image_path} -DockerImage ${image_arg}" } else { $image_install = "${update_docker_image_path} ${image_arg}" } } if $ensure == 'absent' { exec { $image_remove: path => $exec_path, environment => $exec_environment, onlyif => $_image_find, provider => $exec_provider, timeout => $exec_timeout, logoutput => true, } - } elsif $ensure == 'latest' or $image_tag == 'latest' or $ensure == 'present' { + } elsif $ensure == 'latest' or $image_tag == 'latest' { + notify { "Check if image ${image_arg} is in-sync": + noop => false, + } + ~> exec { "echo 'Update of ${image_arg} complete'": + environment => $exec_environment, + path => $exec_path, + timeout => $exec_timeout, + onlyif => $image_install, + require => File[$update_docker_image_path], + provider => $exec_provider, + logoutput => true, + refreshonly => true, + } + } elsif $ensure == 'present' { exec { $image_install: unless => $_image_find, environment => $exec_environment, path => $exec_path, timeout => $exec_timeout, returns => ['0', '2'], require => File[$update_docker_image_path], provider => $exec_provider, logoutput => true, } } Docker::Image <| title == $title |> } diff --git a/spec/defines/image_spec.rb b/spec/defines/image_spec.rb index 6bc22bf..0d02981 100644 --- a/spec/defines/image_spec.rb +++ b/spec/defines/image_spec.rb @@ -1,167 +1,167 @@ require 'spec_helper' describe 'docker::image', :type => :define do let(:title) { 'base' } let(:facts) { { :osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'jessie', :kernelrelease => '3.2.0-4-amd64', :operatingsystemmajrelease => '8', } } context 'with ensure => absent' do let(:params) { { 'ensure' => 'absent' } } it { should contain_exec('docker rmi base') } end context 'with ensure => absent and force => true' do let(:params) { { 'ensure' => 'absent', 'force' => true } } it { should contain_exec('docker rmi -f base') } end context 'with ensure => absent and image_tag => precise' do let(:params) { { 'ensure' => 'absent', 'image_tag' => 'precise' } } it { should contain_exec('docker rmi base:precise') } end context 'with ensure => present' do let(:params) { { 'ensure' => 'present' } } it { should contain_file('/usr/local/bin/update_docker_image.sh') } it { should contain_exec('/usr/local/bin/update_docker_image.sh base') } end context 'with docker_file => Dockerfile' do let(:params) { { 'docker_file' => 'Dockerfile' }} it { should contain_exec('docker build -t base - < Dockerfile') } end context 'with ensure => present and docker_file => Dockerfile' do let(:params) { { 'ensure' => 'present', 'docker_file' => 'Dockerfile' } } it { should contain_exec('docker build -t base - < Dockerfile') } end context 'with docker_dir => /tmp/docker_images/test1 and docker_file => /tmp/docker_images/test1/Dockerfile_altbuild' do let(:params) { { 'docker_dir' => '/tmp/docker_images/test1', 'docker_file' => '/tmp/docker_images/test1/Dockerfile_altbuild' }} it { should contain_exec('docker build -t base -f /tmp/docker_images/test1/Dockerfile_altbuild /tmp/docker_images/test1') } end context 'with docker_dir => /tmp/docker_images/test1' do let(:params) { { 'docker_dir' => '/tmp/docker_images/test1' }} it { should contain_exec('docker build -t base /tmp/docker_images/test1') } end context 'with ensure => present and docker_dir => /tmp/docker_images/test1' do let(:params) { { 'ensure' => 'present', 'docker_dir' => '/tmp/docker_images/test1' } } it { should contain_exec('docker build -t base /tmp/docker_images/test1') } end context 'with ensure => present and image_tag => precise' do let(:params) { { 'ensure' => 'present', 'image_tag' => 'precise' } } it { should contain_exec('/usr/local/bin/update_docker_image.sh base:precise') } end context 'with ensure => present and image_digest => sha256:deadbeef' do let(:params) { { 'ensure' => 'present', 'image_digest' => 'sha256:deadbeef' } } it { should contain_exec('/usr/local/bin/update_docker_image.sh base@sha256:deadbeef') } end context 'with ensure => present and image_tag => precise and docker_file => Dockerfile' do let(:params) { { 'ensure' => 'present', 'image_tag' => 'precise', 'docker_file' => 'Dockerfile' } } it { should contain_exec('docker build -t base:precise - < Dockerfile') } end context 'with ensure => present and image_tag => precise and docker_dir => /tmp/docker_images/test1' do let(:params) { { 'ensure' => 'present', 'image_tag' => 'precise', 'docker_dir' => '/tmp/docker_images/test1' } } it { should contain_exec('docker build -t base:precise /tmp/docker_images/test1') } end context 'with docker_tar => /tmp/docker_tars/test1.tar' do let(:params) { { 'docker_tar' => '/tmp/docker_tars/test1.tar' } } it { should contain_exec('docker load -i /tmp/docker_tars/test1.tar') } end context 'with ensure => present and docker_tar => /tmp/docker_tars/test1.tar' do let(:params) { { 'ensure' => 'present', 'docker_tar' => '/tmp/docker_tars/test1.tar' } } it { should contain_exec('docker load -i /tmp/docker_tars/test1.tar') } end context 'with docker_file => Dockerfile and docker_tar => /tmp/docker_tars/test1.tar' do let(:params) { { 'docker_file' => 'Dockerfile', 'docker_tar' => '/tmp/docker_tars/test1.tar' }} it do expect { should have_exec_resource_count(1) }.to raise_error(Puppet::Error) end end context 'with docker_tar => /tmp/docker_tars/test1.tar and docker_dir => /tmp/docker_images/test1' do let(:params) { { 'docker_tar' => '/tmp/docker_tars/test1.tar', 'docker_dir' => '/tmp/docker_images/test1' }} it do expect { should have_exec_resource_count(1) }.to raise_error(Puppet::Error) end end context 'with image_digest => sha256:deadbeef and docker_file => Dockerfile' do let(:params) { { 'image_digest' => 'sha256:deadbeef', 'docker_file' => 'Dockerfile' }} it do expect { should have_exec_resource_count(1) }.to raise_error(Puppet::Error) end end context 'with image_digest => sha256:deadbeef and docker_dir => /tmp/docker_images/test1' do let(:params) { { 'image_digest' => 'sha256:deadbeef', 'docker_dir' => '/tmp/docker_images/test1' }} it do expect { should have_exec_resource_count(1) }.to raise_error(Puppet::Error) end end context 'with image_digest => sha256:deadbeef and docker_tar => /tmp/docker_tars/test1.tar' do let(:params) { { 'image_digest' => 'sha256:deadbeef', 'docker_tar' => '/tmp/docker_tars/test1.tar' }} it do expect { should have_exec_resource_count(1) }.to raise_error(Puppet::Error) end end context 'with ensure => latest' do let(:params) { { 'ensure' => 'latest' } } - it { should contain_exec("/usr/local/bin/update_docker_image.sh base") } + it { should contain_exec("echo 'Update of base complete'").with_onlyif('/usr/local/bin/update_docker_image.sh base') } end context 'with ensure => latest and image_tag => precise' do let(:params) { { 'ensure' => 'latest', 'image_tag' => 'precise' } } - it { should contain_exec("/usr/local/bin/update_docker_image.sh base:precise") } + it { should contain_exec("echo 'Update of base:precise complete'") } end context 'with ensure => latest and image_digest => sha256:deadbeef' do let(:params) { { 'ensure' => 'latest', 'image_digest' => 'sha256:deadbeef' } } - it { should contain_exec("/usr/local/bin/update_docker_image.sh base@sha256:deadbeef") } + it { should contain_exec("echo 'Update of base@sha256:deadbeef complete'") } end context 'with an invalid image name' do let(:title) { 'with spaces' } it do expect { should contain_exec('/usr/local/bin/update_docker_image.sh with spaces') }.to raise_error(Puppet::Error) end end context 'with an invalid ensure value' do let(:params) { { 'ensure' => 'not present or absent' } } it do expect { should contain_exec('docker rmi base') }.to raise_error(Puppet::Error) end end end diff --git a/spec/defines/image_windows_spec.rb b/spec/defines/image_windows_spec.rb index c3f5566..7bd3376 100644 --- a/spec/defines/image_windows_spec.rb +++ b/spec/defines/image_windows_spec.rb @@ -1,54 +1,54 @@ require 'spec_helper' describe 'docker::image', :type => :define do let(:title) { 'base' } let(:facts) { { :architecture => 'amd64', :osfamily => 'windows', :operatingsystem => 'windows', :kernelrelease => '10.0.14393', :operatingsystemrelease => '2016', :operatingsystemmajrelease => '2016', :docker_program_data_path => 'C:/ProgramData', :docker_program_files_path => 'C:/Program Files', :docker_systemroot => 'C:/Windows', :docker_user_temp_path => 'C:/Users/Administrator/AppData/Local/Temp', :os => { :family => 'windows', :name => 'windows', :release => { :major => '2016', :full => '2016' } } } } context 'with ensure => present' do let(:params) { { 'ensure' => 'present' } } it { should contain_file('C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1') } it { should contain_exec('& C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1 -DockerImage base') } end context 'with docker_file => Dockerfile' do let(:params) { { 'docker_file' => 'Dockerfile' }} it { should contain_exec('Get-Content Dockerfile -Raw | docker build -t base -') } end context 'with ensure => present and docker_file => Dockerfile' do let(:params) { { 'ensure' => 'present', 'docker_file' => 'Dockerfile' } } it { should contain_exec('Get-Content Dockerfile -Raw | docker build -t base -') } end context 'with ensure => present and image_tag => nanoserver' do let(:params) { { 'ensure' => 'present', 'image_tag' => 'nanoserver' } } it { should contain_exec('& C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1 -DockerImage base:nanoserver') } end context 'with ensure => present and image_digest => sha256:deadbeef' do let(:params) { { 'ensure' => 'present', 'image_digest' => 'sha256:deadbeef' } } it { should contain_exec('& C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1 -DockerImage base@sha256:deadbeef') } end context 'with ensure => present and image_tag => nanoserver and docker_file => Dockerfile' do let(:params) { { 'ensure' => 'present', 'image_tag' => 'nanoserver', 'docker_file' => 'Dockerfile' } } it { should contain_exec('Get-Content Dockerfile -Raw | docker build -t base:nanoserver -') } end context 'with ensure => latest' do let(:params) { { 'ensure' => 'latest' } } - it { should contain_exec("& C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1 -DockerImage base") } + it { should contain_exec("echo 'Update of base complete'").with_onlyif('& C:/Users/Administrator/AppData/Local/Temp/update_docker_image.ps1 -DockerImage base') } end end \ No newline at end of file