diff --git a/README.md b/README.md index d990e3e1..2c8320f0 100755 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ * [Networks](#networks) * [Volumes](#volumes) * [Compose](#compose) + * [Machine](#machine) * [Swarm mode](#swarm-mode) * [Tasks](#tasks) * [Docker services](#docker-services) @@ -684,6 +685,25 @@ docker_stack { 'test': To remove the stack, set `ensure => absent`. +### Machine + +Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands. You can use Machine to create Docker hosts on your local Mac or Windows box, on your company network, in your data center, or on cloud providers like Azure, AWS, or Digital Ocean. + +For more information on machines see the [Docker Machines](https://docs.docker.com/machine/) documentation. + +This module only takes responsability for installing the Docker Machine utility. + +To install Docker Machine, add the following code to the manifest file: + +```puppet +class {'docker::machine': + ensure => present, + version => '1.16.1', +} +``` + +Set the `version` parameter to any version you need to install. + ### Swarm mode To natively manage a cluster of Docker Engines known as a swarm, Docker Engine 1.12 includes a swarm mode. @@ -969,6 +989,7 @@ docker::plugin {'foo/fooplugin:latest' * docker * docker::compose * docker::images +* docker::machine * docker::networks * docker::params * docker::plugins diff --git a/manifests/machine.pp b/manifests/machine.pp new file mode 100644 index 00000000..795e874c --- /dev/null +++ b/manifests/machine.pp @@ -0,0 +1,100 @@ +# == Class: docker::machine +# +# Class to install Docker Machine using the recommended curl command. +# +# === Parameters +# +# [*ensure*] +# Whether to install or remove Docker Machine +# Valid values are absent present +# Defaults to present +# +# [*version*] +# The version of Docker Machine to install. +# Defaults to the value set in $docker::params::machine_version +# +# [*install_path*] +# The path where to install Docker Machine. +# Defaults to the value set in $docker::params::machine_install_path +# +# [*proxy*] +# Proxy to use for downloading Docker Machine. +# +class docker::machine( + Optional[Pattern[/^present$|^absent$/]] $ensure = 'present', + Optional[String] $version = $docker::params::machine_version, + Optional[String] $install_path = $docker::params::machine_install_path, + Optional[String] $proxy = undef +) inherits docker::params { + + if $proxy != undef { + validate_re($proxy, '^((http[s]?)?:\/\/)?([^:^@]+:[^:^@]+@|)([\da-z\.-]+)\.([\da-z\.]{2,6})(:[\d])?([\/\w \.-]*)*\/?$') + } + + if $::osfamily == 'windows' { + $file_extension = '.exe' + $file_owner = 'Administrator' + } else { + $file_extension = '' + $file_owner = 'root' + } + + $docker_machine_location = "${install_path}/docker-machine${file_extension}" + $docker_machine_location_versioned = "${install_path}/docker-machine-${version}${file_extension}" + + if $ensure == 'present' { + $docker_machine_url = "https://github.com/docker/machine/releases/download/v${version}/docker-machine-${::kernel}-x86_64${file_extension}" + + if $proxy != undef { + $proxy_opt = "--proxy ${proxy}" + } else { + $proxy_opt = '' + } + + if $::osfamily == 'windows' { +# lint:ignore:140chars + $docker_download_command = "if (Invoke-WebRequest ${docker_machine_url} ${proxy_opt} -UseBasicParsing -OutFile \"${docker_machine_location_versioned}\") { exit 0 } else { exit 1}" +# lint:endignore + + exec { "Install Docker Machine ${version}": + command => template('docker/windows/download_docker_machine.ps1.erb'), + provider => powershell, + creates => $docker_machine_location_versioned, + } + + file { $docker_machine_location: + ensure => 'link', + target => $docker_machine_location_versioned, + require => Exec["Install Docker Machine ${version}"] + } + } else { + ensure_packages(['curl']) + exec { "Install Docker Machine ${version}": + path => '/usr/bin/', + cwd => '/tmp', + command => "curl -s -S -L ${proxy_opt} ${docker_machine_url} -o ${docker_machine_location_versioned}", + creates => $docker_machine_location_versioned, + require => Package['curl'], + } + + file { $docker_machine_location_versioned: + owner => $file_owner, + mode => '0755', + require => Exec["Install Docker Machine ${version}"] + } + + file { $docker_machine_location: + ensure => 'link', + target => $docker_machine_location_versioned, + require => File[$docker_machine_location_versioned] + } + } + } else { + file { [ + $docker_machine_location_versioned, + $docker_machine_location + ]: + ensure => absent, + } + } +} diff --git a/manifests/params.pp b/manifests/params.pp index 75453c91..b8df7279 100755 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -30,13 +30,16 @@ $tls_key = "${::docker_program_data_path}/docker/certs.d/server-key.pem" $compose_version = '1.21.2' $compose_install_path = "${::docker_program_files_path}/Docker" + $machine_install_path = "${::docker_program_files_path}/Docker" } else { $tls_cacert = '/etc/docker/tls/ca.pem' $tls_cert = '/etc/docker/tls/cert.pem' $tls_key = '/etc/docker/tls/key.pem' $compose_version = '1.9.0' $compose_install_path = '/usr/local/bin' + $machine_install_path = '/usr/local/bin' } + $machine_version = '0.16.1' $ip_forward = true $iptables = true $ipv6 = false diff --git a/spec/classes/compose_spec.rb b/spec/classes/compose_spec.rb index d241d2fe..100359ad 100644 --- a/spec/classes/compose_spec.rb +++ b/spec/classes/compose_spec.rb @@ -69,8 +69,8 @@ end context 'when proxy contains username and password' do - let(:params) { {:proxy => 'http://user:password@proxy.example.org:3128/', - :version => '1.7.0'} } + let(:params) { {:proxy => 'http://user:password@proxy.example.org:3128/', + :version => '1.7.0'} } it { is_expected.to compile } it { is_expected.to contain_exec('Install Docker Compose 1.7.0').with_command( 'curl -s -S -L --proxy http://user:password@proxy.example.org:3128/ https://github.com/docker/compose/releases/download/1.7.0/docker-compose-Linux-x86_64 -o /usr/local/bin/docker-compose-1.7.0') diff --git a/spec/classes/machine_spec.rb b/spec/classes/machine_spec.rb new file mode 100644 index 00000000..6c4a35d4 --- /dev/null +++ b/spec/classes/machine_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +describe 'docker::machine', :type => :class do + let(:facts) do + { + :kernel => 'Linux', + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :lsbdistid => 'Ubuntu', + :lsbdistcodename => 'maverick', + :kernelrelease => '3.8.0-29-generic', + :operatingsystemrelease => '10.04', + :operatingsystemmajrelease => '10', + } + end + + it { is_expected.to compile } + + context 'with defaults for all parameters' do + it { should compile.with_all_deps } + it { should contain_exec('Install Docker Machine 0.16.1').with( + 'path' => '/usr/bin/', + 'cwd' => '/tmp', + 'command' => 'curl -s -S -L https://github.com/docker/machine/releases/download/v0.16.1/docker-machine-Linux-x86_64 -o /usr/local/bin/docker-machine-0.16.1', + 'creates' => '/usr/local/bin/docker-machine-0.16.1', + 'require' => 'Package[curl]' + )} + it { should contain_file('/usr/local/bin/docker-machine-0.16.1').with( + 'owner' => 'root', + 'mode' => '0755', + 'require' => 'Exec[Install Docker Machine 0.16.1]' + )} + it { should contain_file('/usr/local/bin/docker-machine').with( + 'ensure' => 'link', + 'target' => '/usr/local/bin/docker-machine-0.16.1', + 'require' => 'File[/usr/local/bin/docker-machine-0.16.1]' + )} + end + + context 'with ensure => absent' do + let (:params) { { :ensure => 'absent' } } + it { should contain_file('/usr/local/bin/docker-machine-0.16.1').with_ensure('absent') } + it { should contain_file('/usr/local/bin/docker-machine').with_ensure('absent') } + end + + context 'when no proxy is provided' do + let(:params) { {:version => '0.16.0'} } + it { is_expected.to contain_exec('Install Docker Machine 0.16.0').with_command( + 'curl -s -S -L https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-Linux-x86_64 -o /usr/local/bin/docker-machine-0.16.0') + } + end + + context 'when proxy is provided' do + let(:params) { {:proxy => 'http://proxy.example.org:3128/', + :version => '0.16.0'} } + it { is_expected.to compile } + it { is_expected.to contain_exec('Install Docker Machine 0.16.0').with_command( + 'curl -s -S -L --proxy http://proxy.example.org:3128/ https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-Linux-x86_64 -o /usr/local/bin/docker-machine-0.16.0') + } + end + + context 'when proxy is not a http proxy' do + let(:params) { {:proxy => 'this is not a URL'} } + it do + expect { + is_expected.to compile + }.to raise_error(/does not match/) + end + end + + context 'when proxy contains username and password' do + let(:params) { {:proxy => 'http://user:password@proxy.example.org:3128/', + :version => '0.16.0'} } + it { is_expected.to compile } + it { is_expected.to contain_exec('Install Docker Machine 0.16.0').with_command( + 'curl -s -S -L --proxy http://user:password@proxy.example.org:3128/ https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-Linux-x86_64 -o /usr/local/bin/docker-machine-0.16.0') + } + end + + context 'when proxy IP is provided' do + let(:params) { {:proxy => 'http://10.10.10.10:3128/', + :version => '0.16.0'} } + it { is_expected.to compile } + it { is_expected.to contain_exec('Install Docker Machine 0.16.0').with_command( + 'curl -s -S -L --proxy http://10.10.10.10:3128/ https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-Linux-x86_64 -o /usr/local/bin/docker-machine-0.16.0') + } + end +end diff --git a/templates/windows/download_docker_machine.ps1.erb b/templates/windows/download_docker_machine.ps1.erb new file mode 100644 index 00000000..229dd6b9 --- /dev/null +++ b/templates/windows/download_docker_machine.ps1.erb @@ -0,0 +1,23 @@ +try { +$WebClient = New-Object System.Net.WebClient +<%if @proxy %> +$uri = New-Object Uri("<%= @proxy %>") +if ($uri.UserInfo -eq $null) { + $WebProxy = New-Object System.Net.WebProxy("<%= @proxy %>",$true) + $WebClient.Proxy = $WebProxy +} +else { + $user,$password = $uri.UserInfo -split (':') + $proxyAddress = $uri.Scheme + "://" + $uri.Host + ":" + $uri.Port + $uri.PathAndQuery + $WebProxy = New-Object System.Net.WebProxy($uri,$true) + $WebClient.Proxy = $WebProxy + $WebClient.Proxy.Credentials = New-Object System.Net.NetworkCredential($user, $password) +} +<% end %> + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + $WebClient.DownloadFile("<%= @docker_machine_url %>","<%= @docker_machine_location_versioned %>") +} +catch { + exit 1 +} +exit 0 \ No newline at end of file