diff --git a/manifests/init.pp b/manifests/init.pp index eb48a62..1ccbbc0 100755 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,671 +1,680 @@ # == Class: docker # # Module to install an up-to-date version of Docker from package. # # === Parameters # # [*version*] # The package version to install, used to set the package name. # Defaults to undefined # # [*ensure*] # Passed to the docker package. # Defaults to present # # [*prerequired_packages*] # An array of additional packages that need to be installed to support # docker. Defaults change depending on the operating system. # # [*dependent_packages*] # An array of packages installed by the docker-ce package v 18.09 and later. # Used when uninstalling to ensure containers cannot be run on the system. # Defaults change depending on the operating system. # # [*tcp_bind*] # The tcp socket to bind to in the format # tcp://127.0.0.1:4243 # Defaults to undefined # # [*tls_enable*] # Enable TLS. # Defaults to false # # [*tls_verify*] # Use TLS and verify the remote # Defaults to true # # [*tls_cacert*] # Path to TLS CA certificate # Defaults to '/etc/docker/tls/ca.pem on linux and C:/ProgramData/docker/certs.d/ca.pem on Windows' # # [*tls_cert*] # Path to TLS certificate file # Defaults to '/etc/docker/tls/cert.pem on linux and C:/ProgramData/docker/certs.d/server-cert.pem on Windows' # # [*tls_key*] # Path to TLS key file # Defaults to '/etc/docker/tls/key.pem' on linux and C:/ProgramData/docker/certs.d/server-key.pem on Windows # # [*ip_forward*] # Enables IP forwarding on the Docker host. # The default is true. # # [*iptables*] # Enable Docker's addition of iptables rules. # Default is true. # # [*ip_masq*] # Enable IP masquerading for bridge's IP range. # The default is true. # # [*icc*] # Enable or disable Docker's unrestricted inter-container and Docker daemon host communication. # (Requires iptables=true to disable) # Default is undef. (Docker daemon's default is true) # # [*bip*] # Specify docker's network bridge IP, in CIDR notation. # Defaults to undefined. # # [*mtu*] # Docker network MTU. # Defaults to undefined. # # [*bridge*] # Attach containers to a pre-existing network bridge # use 'none' to disable container networking # Defaults to undefined. # # [*fixed_cidr*] # IPv4 subnet for fixed IPs # 10.20.0.0/16 # Defaults to undefined # # [*default_gateway*] # IPv4 address of the container default gateway; # this address must be part of the bridge subnet # (which is defined by bridge) # Defaults to undefined # # [*ipv6*] # Enables ipv6 support for the docker daemon # Defaults to false # # [*ipv6_cidr*] # IPv6 subnet for fixed IPs # # [*default_gateway_ipv6*] # IPv6 address of the container default gateway: # Defaults to undefined # # [*socket_bind*] # The unix socket to bind to. Defaults to # unix:///var/run/docker.sock. # # [*log_level*] # Set the logging level # Defaults to undef: docker defaults to info if no value specified # Valid values: debug, info, warn, error, fatal # # [*log_driver*] # Set the log driver. # Defaults to undef. # Docker default is json-file. # Valid values: none, json-file, syslog, journald, gelf, fluentd # Valid values description: # none : Disables any logging for the container. # docker logs won't be available with this driver. # json-file: Default logging driver for Docker. # Writes JSON messages to file. # syslog : Syslog logging driver for Docker. # Writes log messages to syslog. # journald : Journald logging driver for Docker. # Writes log messages to journald. # gelf : Graylog Extended Log Format (GELF) logging driver for Docker. # Writes log messages to a GELF endpoint: Graylog or Logstash. # fluentd : Fluentd logging driver for Docker. # Writes log messages to fluentd (forward input). # splunk : Splunk logging driver for Docker. # Writes log messages to Splunk (HTTP Event Collector). # awslogs : AWS Cloudwatch Logs logging driver for Docker. # Write log messages to Cloudwatch API # # [*log_opt*] # Set the log driver specific options # Defaults to undef # Valid values per log driver: # none : undef # json-file: # max-size=[0-9+][k|m|g] # max-file=[0-9+] # syslog : # syslog-address=[tcp|udp]://host:port # syslog-address=unix://path # syslog-facility=daemon|kern|user|mail|auth| # syslog|lpr|news|uucp|cron| # authpriv|ftp| # local0|local1|local2|local3| # local4|local5|local6|local7 # syslog-tag="some_tag" # journald : undef # gelf : # gelf-address=udp://host:port # gelf-tag="some_tag" # fluentd : # fluentd-address=host:port # fluentd-tag={{.ID}} - short container id (12 characters)| # {{.FullID}} - full container id # {{.Name}} - container name # splunk : # splunk-token= # splunk-url=https://your_splunk_instance:8088 # awslogs : # awslogs-group= # awslogs-stream= # awslogs-create-group=true|false # awslogs-datetime-format= - strftime expression # awslogs-multiline-pattern=multiline start pattern using a regular expression # tag={{.ID}} - short container id (12 characters)| # {{.FullID}} - full container id # {{.Name}} - container name # # [*selinux_enabled*] # Enable selinux support. Default is false. SELinux does not presently # support the BTRFS storage driver. # Valid values: true, false # # [*use_upstream_package_source*] # Whether or not to use the upstream package source. # If you run your own package mirror, you may set this # to false. # # [*pin_upstream_package_source*] # Pin upstream package source; this option currently only has any effect on # apt-based distributions. Set to false to remove pinning on the upstream # package repository. See also "apt_source_pin_level". # Defaults to true # # [*apt_source_pin_level*] # What level to pin our source package repository to; this only is relevent # if you're on an apt-based system (Debian, Ubuntu, etc) and # $use_upstream_package_source is set to true. Set this to false to disable # pinning, and undef to ensure the apt preferences file apt::source uses to # define pins is removed. # Defaults to 10 # # [*package_source_location*] # If you're using an upstream package source, what is it's # location. Defaults to http://get.docker.com/ubuntu on Debian # # [*service_state*] # Whether you want to docker daemon to start up # Defaults to running # # [*service_enable*] # Whether you want to docker daemon to start up at boot # Defaults to true # # [*manage_service*] # Specify whether the service should be managed. # Valid values are 'true', 'false'. # Defaults to 'true'. # # [*root_dir*] # Custom root directory for containers # Defaults to undefined # # [*dns*] # Custom dns server address # Defaults to undefined # # [*dns_search*] # Custom dns search domains # Defaults to undefined # # [*socket_group*] # Group ownership of the unix control socket. # Default is based on OS (docker, dockerroot, undef) # # [*extra_parameters*] # Any extra parameters that should be passed to the docker daemon. # Defaults to undefined # # [*shell_values*] # Array of shell values to pass into init script config files # # [*proxy*] # Will set the http_proxy and https_proxy env variables in /etc/sysconfig/docker (redhat/centos) or /etc/default/docker (debian) # # [*no_proxy*] # Will set the no_proxy variable in /etc/sysconfig/docker (redhat/centos) or /etc/default/docker (debian) # # [*storage_driver*] # Specify a storage driver to use # Default is undef: let docker choose the correct one # Valid values: aufs, devicemapper, btrfs, overlay, overlay2, vfs, zfs # # [*dm_basesize*] # The size to use when creating the base device, which limits the size of images and containers. # Default value is 10G # # [*dm_fs*] # The filesystem to use for the base image (xfs or ext4) # Defaults to ext4 # # [*dm_mkfsarg*] # Specifies extra mkfs arguments to be used when creating the base device. # # [*dm_mountopt*] # Specifies extra mount options used when mounting the thin devices. # # [*dm_blocksize*] # A custom blocksize to use for the thin pool. # Default blocksize is 64K. # Warning: _DO NOT_ change this parameter after the lvm devices have been initialized. # # [*dm_loopdatasize*] # Specifies the size to use when creating the loopback file for the "data" device which is used for the thin pool # Default size is 100G # # [*dm_loopmetadatasize*] # Specifies the size to use when creating the loopback file for the "metadata" device which is used for the thin pool # Default size is 2G # # [*dm_datadev*] # (deprecated - dm_thinpooldev should be used going forward) # A custom blockdevice to use for data for the thin pool. # # [*dm_metadatadev*] # (deprecated - dm_thinpooldev should be used going forward) # A custom blockdevice to use for metadata for the thin pool. # # [*dm_thinpooldev*] # Specifies a custom block storage device to use for the thin pool. # # [*dm_use_deferred_removal*] # Enables use of deferred device removal if libdm and the kernel driver support the mechanism. # # [*dm_use_deferred_deletion*] # Enables use of deferred device deletion if libdm and the kernel driver support the mechanism. # # [*dm_blkdiscard*] # Enables or disables the use of blkdiscard when removing devicemapper devices. # Defaults to false # # [*dm_override_udev_sync_check*] # By default, the devicemapper backend attempts to synchronize with the udev # device manager for the Linux kernel. This option allows disabling that # synchronization, to continue even though the configuration may be buggy. # Defaults to true # # [*overlay2_override_kernel_check*] # Overrides the Linux kernel version check allowing using overlay2 with kernel < 4.0. # Default value is false # # [*manage_package*] # Won't install or define the docker package, useful if you want to use your own package # Defaults to true # # [*package_name*] # Specify custom package name # Default is set on a per system basis in docker::params # # [*service_name*] # Specify custom service name # Default is set on a per system basis in docker::params # # [*docker_command*] # Specify a custom docker command name # Default is set on a per system basis in docker::params # # [*daemon_subcommand*] # Specify a subcommand/flag for running docker as daemon # Default is set on a per system basis in docker::params # # [*docker_users*] # Specify an array of users to add to the docker group # Default is empty # # [*docker_group*] # Specify a string for the docker group # Default is OS and package specific # # [*daemon_environment_files*] # Specify additional environment files to add to the # service-overrides.conf # # [*repo_opt*] # Specify a string to pass as repository options (RedHat only) # # [*storage_devs*] # A quoted, space-separated list of devices to be used. # # [*storage_vg*] # The volume group to use for docker storage. # # [*storage_root_size*] # The size to which the root filesystem should be grown. # # [*storage_data_size*] # The desired size for the docker data LV # # [*storage_min_data_size*] # The minimum size of data volume otherwise pool creation fails # # [*storage_chunk_size*] # Controls the chunk size/block size of thin pool. # # [*storage_growpart*] # Enable resizing partition table backing root volume group. # # [*storage_auto_extend_pool*] # Enable/disable automatic pool extension using lvm # # [*storage_pool_autoextend_threshold*] # Auto pool extension threshold (in % of pool size) # # [*storage_pool_autoextend_percent*] # Extend the pool by specified percentage when threshold is hit. # # [*tmp_dir_config*] # Whether to set the TMPDIR value in the systemd config file # Default: true (set the value); false will comment out the line. # Note: false is backwards compatible prior to PR #58 # # [*tmp_dir*] # Sets the tmp dir for Docker (path) # # [*registry_mirror*] # Sets the prefered container registry mirror. # Default: undef # # [*nuget_package_provider_version*] # The version of the NuGet Package provider # Default: undef # # [*docker_msft_provider_version*] # The version of the Microsoft Docker Provider Module # Default: undef class docker( Optional[String] $version = $docker::params::version, String $ensure = $docker::params::ensure, Variant[Array[String], Hash] $prerequired_packages = $docker::params::prerequired_packages, Array $dependent_packages = $docker::params::dependent_packages, String $docker_ce_start_command = $docker::params::docker_ce_start_command, Optional[String] $docker_ce_package_name = $docker::params::docker_ce_package_name, Optional[String] $docker_ce_source_location = $docker::params::package_ce_source_location, Optional[String] $docker_ce_key_source = $docker::params::package_ce_key_source, Optional[String] $docker_ce_key_id = $docker::params::package_ce_key_id, Optional[String] $docker_ce_release = $docker::params::package_ce_release, Optional[String] $docker_package_location = $docker::params::package_source_location, Optional[String] $docker_package_key_source = $docker::params::package_key_source, Optional[Boolean] $docker_package_key_check_source = $docker::params::package_key_check_source, Optional[String] $docker_package_key_id = $docker::params::package_key_id, Optional[String] $docker_package_release = $docker::params::package_release, String $docker_engine_start_command = $docker::params::docker_engine_start_command, String $docker_engine_package_name = $docker::params::docker_engine_package_name, String $docker_ce_channel = $docker::params::docker_ce_channel, Optional[Boolean] $docker_ee = $docker::params::docker_ee, Optional[String] $docker_ee_package_name = $docker::params::package_ee_package_name, Optional[String] $docker_ee_source_location = $docker::params::package_ee_source_location, Optional[String] $docker_ee_key_source = $docker::params::package_ee_key_source, Optional[String] $docker_ee_key_id = $docker::params::package_ee_key_id, Optional[String] $docker_ee_repos = $docker::params::package_ee_repos, Optional[String] $docker_ee_release = $docker::params::package_ee_release, Variant[String,Array[String],Undef] $tcp_bind = $docker::params::tcp_bind, Boolean $tls_enable = $docker::params::tls_enable, Boolean $tls_verify = $docker::params::tls_verify, Optional[String] $tls_cacert = $docker::params::tls_cacert, Optional[String] $tls_cert = $docker::params::tls_cert, Optional[String] $tls_key = $docker::params::tls_key, Boolean $ip_forward = $docker::params::ip_forward, Boolean $ip_masq = $docker::params::ip_masq, Optional[Boolean]$ipv6 = $docker::params::ipv6, Optional[String]$ipv6_cidr = $docker::params::ipv6_cidr, Optional[String]$default_gateway_ipv6 = $docker::params::default_gateway_ipv6, Optional[String] $bip = $docker::params::bip, Optional[String] $mtu = $docker::params::mtu, Boolean $iptables = $docker::params::iptables, Optional[Boolean] $icc = $docker::params::icc, String $socket_bind = $docker::params::socket_bind, Optional[String] $fixed_cidr = $docker::params::fixed_cidr, Optional[String] $bridge = $docker::params::bridge, Optional[String] $default_gateway = $docker::params::default_gateway, Optional[String] $log_level = $docker::params::log_level, Optional[String] $log_driver = $docker::params::log_driver, Array $log_opt = $docker::params::log_opt, Optional[Boolean] $selinux_enabled = $docker::params::selinux_enabled, Optional[Boolean] $use_upstream_package_source = $docker::params::use_upstream_package_source, Optional[Boolean] $pin_upstream_package_source = $docker::params::pin_upstream_package_source, Optional[Integer] $apt_source_pin_level = $docker::params::apt_source_pin_level, Optional[String] $package_release = $docker::params::package_release, String $service_state = $docker::params::service_state, Boolean $service_enable = $docker::params::service_enable, Boolean $manage_service = $docker::params::manage_service, Optional[String] $root_dir = $docker::params::root_dir, Optional[Boolean] $tmp_dir_config = $docker::params::tmp_dir_config, Optional[String] $tmp_dir = $docker::params::tmp_dir, Variant[String,Array,Undef] $dns = $docker::params::dns, Variant[String,Array,Undef] $dns_search = $docker::params::dns_search, Variant[String,Boolean,Undef] $socket_group = $docker::params::socket_group, Array $labels = $docker::params::labels, Variant[String,Array,Undef] $extra_parameters = undef, Variant[String,Array,Undef] $shell_values = undef, Optional[String] $proxy = $docker::params::proxy, Optional[String] $no_proxy = $docker::params::no_proxy, Optional[String] $storage_driver = $docker::params::storage_driver, Optional[String] $dm_basesize = $docker::params::dm_basesize, Optional[String] $dm_fs = $docker::params::dm_fs, Optional[String] $dm_mkfsarg = $docker::params::dm_mkfsarg, Optional[String] $dm_mountopt = $docker::params::dm_mountopt, Optional[String] $dm_blocksize = $docker::params::dm_blocksize, Optional[String] $dm_loopdatasize = $docker::params::dm_loopdatasize, Optional[String] $dm_loopmetadatasize = $docker::params::dm_loopmetadatasize, Optional[String] $dm_datadev = $docker::params::dm_datadev, Optional[String] $dm_metadatadev = $docker::params::dm_metadatadev, Optional[String] $dm_thinpooldev = $docker::params::dm_thinpooldev, Optional[Boolean] $dm_use_deferred_removal = $docker::params::dm_use_deferred_removal, Optional[Boolean] $dm_use_deferred_deletion = $docker::params::dm_use_deferred_deletion, Optional[Boolean] $dm_blkdiscard = $docker::params::dm_blkdiscard, Optional[Boolean] $dm_override_udev_sync_check = $docker::params::dm_override_udev_sync_check, Boolean $overlay2_override_kernel_check = $docker::params::overlay2_override_kernel_check, Optional[String] $execdriver = $docker::params::execdriver, Boolean $manage_package = $docker::params::manage_package, Optional[String] $package_source = $docker::params::package_source, Optional[String] $service_name = $docker::params::service_name, Array $docker_users = [], String $docker_group = $docker::params::docker_group, Array $daemon_environment_files = [], Variant[String,Hash,Undef] $repo_opt = $docker::params::repo_opt, Optional[String] $os_lc = $docker::params::os_lc, Optional[String] $storage_devs = $docker::params::storage_devs, Optional[String] $storage_vg = $docker::params::storage_vg, Optional[String] $storage_root_size = $docker::params::storage_root_size, Optional[String] $storage_data_size = $docker::params::storage_data_size, Optional[String] $storage_min_data_size = $docker::params::storage_min_data_size, Optional[String] $storage_chunk_size = $docker::params::storage_chunk_size, Optional[Boolean] $storage_growpart = $docker::params::storage_growpart, Optional[String] $storage_auto_extend_pool = $docker::params::storage_auto_extend_pool, Optional[String] $storage_pool_autoextend_threshold = $docker::params::storage_pool_autoextend_threshold, Optional[String] $storage_pool_autoextend_percent = $docker::params::storage_pool_autoextend_percent, Variant[String,Boolean,Undef] $storage_config = $docker::params::storage_config, Optional[String] $storage_config_template = $docker::params::storage_config_template, Optional[String] $storage_setup_file = $docker::params::storage_setup_file, Optional[String] $service_provider = $docker::params::service_provider, Variant[String,Boolean,Undef] $service_config = $docker::params::service_config, Optional[String] $service_config_template = $docker::params::service_config_template, Variant[String,Boolean,Undef] $service_overrides_template = $docker::params::service_overrides_template, Variant[String,Boolean,Undef] $socket_overrides_template = $docker::params::socket_overrides_template, Optional[Boolean] $socket_override = $docker::params::socket_override, Variant[String,Boolean,Undef] $service_after_override = $docker::params::service_after_override, Optional[Boolean] $service_hasstatus = $docker::params::service_hasstatus, Optional[Boolean] $service_hasrestart = $docker::params::service_hasrestart, Optional[String] $registry_mirror = $docker::params::registry_mirror, + Boolean $acknowledge_unsupported_os = false, # Windows specific parameters Optional[String] $docker_msft_provider_version = $docker::params::docker_msft_provider_version, Optional[String] $nuget_package_provider_version = $docker::params::nuget_package_provider_version, ) inherits docker::params { - if $::osfamily { + if $::osfamily and !$acknowledge_unsupported_os { assert_type(Pattern[/^(Debian|RedHat|windows)$/], $::osfamily) |$a, $b| { fail(translate('This module only works on Debian, Red Hat or Windows based systems.')) } } if ($::operatingsystem == 'CentOS') and (versioncmp($::operatingsystemmajrelease, '7') < 0) { fail(translate('This module only works on CentOS version 7 and higher based systems.')) } if ($default_gateway) and (!$bridge) { fail(translate('You must provide the $bridge parameter.')) } if $log_level { assert_type(Pattern[/^(debug|info|warn|error|fatal)$/], $log_level) |$a, $b| { fail(translate('log_level must be one of debug, info, warn, error or fatal')) } } if $log_driver { if $::osfamily == 'windows' { assert_type(Pattern[/^(none|json-file|syslog|gelf|fluentd|splunk|awslogs|etwlogs)$/], $log_driver) |$a, $b| { fail(translate('log_driver must be one of none, json-file, syslog, gelf, fluentd, splunk, awslogs or etwlogs')) } } else { assert_type(Pattern[/^(none|json-file|syslog|journald|gelf|fluentd|splunk|awslogs)$/], $log_driver) |$a, $b| { fail(translate('log_driver must be one of none, json-file, syslog, journald, gelf, fluentd, splunk or awslogs')) } } } if $storage_driver { if $::osfamily == 'windows' { assert_type(Pattern[/^(windowsfilter)$/], $storage_driver) |$a, $b| { fail(translate('Valid values for storage_driver on windows are windowsfilter')) } } else { assert_type(Pattern[/^(aufs|devicemapper|btrfs|overlay|overlay2|vfs|zfs)$/], $storage_driver) |$a, $b| { fail(translate('Valid values for storage_driver are aufs, devicemapper, btrfs, overlay, overlay2, vfs, zfs.')) } } } if ($bridge) and ($::osfamily == 'windows') { assert_type(Pattern[/^(none|nat|transparent|overlay|l2bridge|l2tunnel)$/], $bridge) |$a, $b| { fail(translate('bridge must be one of none, nat, transparent, overlay, l2bridge or l2tunnel on Windows.')) } } if $dm_fs { assert_type(Pattern[/^(ext4|xfs)$/], $dm_fs) |$a, $b| { fail(translate('Only ext4 and xfs are supported currently for dm_fs.')) } } if ($dm_loopdatasize or $dm_loopmetadatasize) and ($dm_datadev or $dm_metadatadev) { fail(translate('You should provide parameters only for loop lvm or direct lvm, not both.')) } # lint:ignore:140chars if ($dm_datadev or $dm_metadatadev) and $dm_thinpooldev { fail(translate('You can use the $dm_thinpooldev parameter, or the $dm_datadev and $dm_metadatadev parameter pair, but you cannot use both.')) } # lint:endignore if ($dm_datadev or $dm_metadatadev) { notice('The $dm_datadev and $dm_metadatadev parameter pair are deprecated. The $dm_thinpooldev parameter should be used instead.') } if ($dm_datadev and !$dm_metadatadev) or (!$dm_datadev and $dm_metadatadev) { fail(translate('You need to provide both $dm_datadev and $dm_metadatadev parameters for direct lvm.')) } if ($dm_basesize or $dm_fs or $dm_mkfsarg or $dm_mountopt or $dm_blocksize or $dm_loopdatasize or $dm_loopmetadatasize or $dm_datadev or $dm_metadatadev) and ($storage_driver != 'devicemapper') { fail(translate('Values for dm_ variables will be ignored unless storage_driver is set to devicemapper.')) } if($tls_enable) { if(!$tcp_bind) { fail(translate('You need to provide tcp bind parameter for TLS.')) } } if ( $version == undef ) or ( $version !~ /^(17[.]0[0-5][.][0-1](~|-|\.)ce|1.\d+)/ ) { if ( $docker_ee) { $package_location = $docker::docker_ee_source_location $package_key_source = $docker::docker_ee_key_source $package_key_check_source = true $package_key = $docker::docker_ee_key_id $package_repos = $docker::docker_ee_repos $release = $docker::docker_ee_release $docker_start_command = $docker::docker_ee_start_command $docker_package_name = $docker::docker_ee_package_name } else { case $::osfamily { 'Debian' : { $package_location = $docker_ce_source_location $package_key_source = $docker_ce_key_source $package_key = $docker_ce_key_id $package_repos = $docker_ce_channel $release = $docker_ce_release } 'Redhat' : { $package_location = $docker_ce_source_location $package_key_source = $docker_ce_key_source $package_key_check_source = true } 'windows': { fail(translate('This module only work for Docker Enterprise Edition on Windows.')) } - default: {} + default: { + $package_location = $docker_package_location + $package_key_source = $docker_package_key_source + $package_key_check_source = $docker_package_key_check_source + } } $docker_start_command = $docker_ce_start_command $docker_package_name = $docker_ce_package_name } } else { case $::osfamily { 'Debian' : { $package_location = $docker_package_location $package_key_source = $docker_package_key_source $package_key_check_source = $docker_package_key_check_source $package_key = $docker_package_key_id $package_repos = 'main' $release = $docker_package_release } 'Redhat' : { $package_location = $docker_package_location $package_key_source = $docker_package_key_source $package_key_check_source = $docker_package_key_check_source } - default : {} + default : { + $package_location = $docker_package_location + $package_key_source = $docker_package_key_source + $package_key_check_source = $docker_package_key_check_source + } } $docker_start_command = $docker_engine_start_command $docker_package_name = $docker_engine_package_name } if ( $version != undef ) and ( $version =~ /^(17[.]0[0-4]|1.\d+)/ ) { $root_dir_flag = '-g' } else { $root_dir_flag = '--data-root' } if $ensure != 'absent' { contain 'docker::repos' contain 'docker::install' contain 'docker::config' contain 'docker::service' Class['docker::repos'] -> Class['docker::install'] -> Class['docker::config'] -> Class['docker::service'] Class['docker'] -> Docker::Registry <||> -> Docker::Image <||> Class['docker'] -> Docker::Image <||> Class['docker'] -> Docker::Run <||> } else { contain 'docker::repos' contain 'docker::install' Class['docker::repos'] -> Class['docker::install'] } } diff --git a/manifests/install.pp b/manifests/install.pp index 542320e..eb26b86 100755 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -1,134 +1,134 @@ # == Class: docker # # Module to install an up-to-date version of Docker from a package repository. # This module works only on Debian Red Hat and Windows based distributions. # # === Parameters # [*version*] # The package version to install, used to set the package name. # # [*nuget_package_provider_version*] # The version of the NuGet Package provider # Default: undef # # [*docker_msft_provider_version*] # The version of the Microsoft Docker Provider Module # Default: undef # # [*docker_ee_package_name*] # The name of the Docker Enterprise Edition package # Default: Docker class docker::install ( $version = $docker::version, $nuget_package_provider_version = $docker::nuget_package_provider_version, $docker_msft_provider_version = $docker::docker_msft_provider_version, $docker_ee_package_name = $docker::docker_ee_package_name, $docker_download_url = $docker::package_location, $dependent_packages = $docker::dependent_packages, ) { $docker_start_command = $docker::docker_start_command - if $::osfamily { + if $::osfamily and !::docker::acknowledge_unsupported_os { assert_type(Pattern[/^(Debian|RedHat|windows)$/], $::osfamily) |$a, $b| { fail(translate('This module only works on Debian, RedHat or Windows.')) } } if $docker::version and $docker::ensure != 'absent' { $ensure = $docker::version } else { $ensure = $docker::ensure } if $docker::manage_package { if empty($docker::repo_opt) { $docker_hash = {} } else { $docker_hash = { 'install_options' => $docker::repo_opt } } if $docker::package_source { case $::osfamily { 'Debian' : { $pk_provider = 'dpkg' } 'RedHat' : { $pk_provider = 'yum' } 'windows' : { fail(translate('Custom package source is currently not implemented on windows.')) } default : { $pk_provider = undef } } case $docker::package_source { /docker-engine/ : { ensure_resource('package', 'docker', merge($docker_hash, { ensure => $ensure, provider => $pk_provider, source => $docker::package_source, name => $docker::docker_engine_package_name, })) } /docker-ce/ : { ensure_resource('package', 'docker', merge($docker_hash, { ensure => $ensure, provider => $pk_provider, source => $docker::package_source, name => $docker::docker_ce_package_name, })) } default : {} } } else { if $::osfamily != 'windows' { ensure_resource('package', 'docker', merge($docker_hash, { ensure => $ensure, name => $docker::docker_package_name, })) if $ensure == 'absent' { ensure_resource('package', $dependent_packages, { ensure => $ensure, }) } } else { if $ensure == 'absent' { exec { 'remove-docker-package': command => template('docker/windows/remove_docker.ps1.erb'), provider => powershell, unless => template('docker/windows/check_docker.ps1.erb'), logoutput => true, } } else { if $docker::package_location { exec { 'install-docker-package': command => template('docker/windows/download_docker.ps1.erb'), provider => powershell, unless => template('docker/windows/check_docker_url.ps1.erb'), logoutput => true, notify => Exec['service-restart-on-failure'], } } else { exec { 'install-docker-package': command => template('docker/windows/install_powershell_provider.ps1.erb'), provider => powershell, unless => template('docker/windows/check_powershell_provider.ps1.erb'), logoutput => true, notify => Exec['service-restart-on-failure'], } } exec { 'service-restart-on-failure': command => 'SC.exe failure Docker reset= 432000 actions= restart/30000/restart/60000/restart/60000', refreshonly => true, logoutput => true, provider => powershell, } } } } } } diff --git a/manifests/run.pp b/manifests/run.pp index 1f01f65..d5f339f 100755 --- a/manifests/run.pp +++ b/manifests/run.pp @@ -1,534 +1,548 @@ # == Define: docker:run # # A define which manages a running docker container. # # == Parameters # # [*restart*] # Sets a restart policy on the docker run. # Note: If set, puppet will NOT setup an init script to manage, instead # it will do a raw docker run command using a CID file to track the container # ID. # # If you want a normal named container with an init script and a restart policy # you must use the extra_parameters feature and pass it in like this: # # extra_parameters => ['--restart=always'] # # However, if your system is using sytemd this restart policy will be # ineffective because the ExecStop commands will run which will cause # docker to stop restarting it. In this case you should use the # systemd_restart option to specify the policy you want. # # This will allow the docker container to be restarted if it dies, without # puppet help. # # [*service_prefix*] # (optional) The name to prefix the startup script with and the Puppet # service resource title with. Default: 'docker-' # # [*restart_service*] # (optional) Whether or not to restart the service if the the generated init # script changes. Default: true # # [*restart_service_on_docker_refresh*] # Whether or not to restart the service if the docker service is restarted. # Only has effect if the docker_service parameter is set. # Default: true # # [*manage_service*] # (optional) Whether or not to create a puppet Service resource for the init # script. Disabling this may be useful if integrating with existing modules. # Default: true # # [*docker_service*] # (optional) If (and how) the Docker service itself is managed by Puppet # true -> Service['docker'] # false -> no Service dependency # anything else -> Service[docker_service] # Default: false # # [*health_check_cmd*] # (optional) Specifies the command to execute to check that the container is healthy using the docker health check functionality. # Default: undef # # [*health_check_interval*] # (optional) Specifies the interval that the health check command will execute in seconds. # Default: undef # # [*restart_on_unhealthy*] # (optional) Checks the health status of Docker container and if it is unhealthy the service will be restarted. # The health_check_cmd parameter must be set to true to use this functionality. # Default: undef # # [*net*] # # The docker network to attach to a container. # Can be a String or Array (if using multiple networks) # Default: bridge # # [*extra_parameters*] # An array of additional command line arguments to pass to the `docker run` # command. Useful for adding additional new or experimental options that the # module does not yet support. # # [*systemd_restart*] # (optional) If the container is to be managed by a systemd unit file set the # Restart option on the unit file. Can be any valid value for this systemd # configuration. Most commonly used are on-failure or always. # Default: on-failure # # [*custom_unless*] # (optional) Specify an additional unless for the Docker run command when using restart. # Default: undef # # [*after_create*] # (optional) Specifies the command to execute after container is created but before it is started. # Default: undef # define docker::run( Optional[Pattern[/^[\S]*$/]] $image, Optional[Pattern[/^present$|^absent$/]] $ensure = 'present', Optional[String] $command = undef, Optional[Pattern[/^[\d]*(b|k|m|g)$/]] $memory_limit = '0b', Variant[String,Array,Undef] $cpuset = [], Variant[String,Array,Undef] $ports = [], Variant[String,Array,Undef] $labels = [], Variant[String,Array,Undef] $expose = [], Variant[String,Array,Undef] $volumes = [], Variant[String,Array,Undef] $links = [], Optional[Boolean] $use_name = false, Optional[Boolean] $running = true, Variant[String,Array,Undef] $volumes_from = [], Variant[String,Array] $net = 'bridge', Variant[String,Boolean] $username = false, Variant[String,Boolean] $hostname = false, Variant[String,Array,Undef] $env = [], Variant[String,Array,Undef] $env_file = [], Variant[String,Array,Undef] $dns = [], Variant[String,Array,Undef] $dns_search = [], Variant[String,Array,Undef] $lxc_conf = [], Optional[String] $service_prefix = 'docker-', + Optional[String] $service_provider = undef, Optional[Boolean] $restart_service = true, Optional[Boolean] $restart_service_on_docker_refresh = true, Optional[Boolean] $manage_service = true, Variant[String,Boolean] $docker_service = false, Optional[Boolean] $disable_network = false, Optional[Boolean] $privileged = false, Optional[Boolean] $detach = undef, Variant[String,Array[String],Undef] $extra_parameters = undef, Optional[String] $systemd_restart = 'on-failure', Variant[String,Hash,Undef] $extra_systemd_parameters = {}, Optional[Boolean] $pull_on_start = false, Variant[String,Array,Undef] $after = [], Variant[String,Array,Undef] $after_service = [], Variant[String,Array,Undef] $depends = [], Variant[String,Array,Undef] $depend_services = [], Optional[Boolean] $tty = false, Variant[String,Array,Undef] $socket_connect = [], Variant[String,Array,Undef] $hostentries = [], Optional[String] $restart = undef, Variant[String,Boolean] $before_start = false, Variant[String,Boolean] $before_stop = false, Optional[String] $after_create = undef, Optional[Boolean] $remove_container_on_start = true, Optional[Boolean] $remove_container_on_stop = true, Optional[Boolean] $remove_volume_on_start = false, Optional[Boolean] $remove_volume_on_stop = false, Optional[Integer] $stop_wait_time = 0, Optional[String] $syslog_identifier = undef, Optional[Boolean] $read_only = false, Optional[String] $health_check_cmd = undef, Optional[Boolean] $restart_on_unhealthy = false, Optional[Integer] $health_check_interval = undef, Variant[String,Array,Undef] $custom_unless = [], ) { include docker::params if ($socket_connect != []) { $sockopts = join(any2array($socket_connect), ',') $docker_command = "${docker::params::docker_command} -H ${sockopts}" }else { $docker_command = $docker::params::docker_command } $service_name = $docker::service_name $docker_group = $docker::docker_group if $restart { assert_type(Pattern[/^(no|always|unless-stopped|on-failure)|^on-failure:[\d]+$/], $restart) } if ($remove_volume_on_start and !$remove_container_on_start) { fail(translate("In order to remove the volume on start for ${title} you need to also remove the container")) } if ($remove_volume_on_stop and !$remove_container_on_stop) { fail(translate("In order to remove the volume on stop for ${title} you need to also remove the container")) } if $use_name { notify { "docker use_name warning: ${title}": message => 'The use_name parameter is no-longer required and will be removed in a future release', withpath => true, } } if $systemd_restart { assert_type(Pattern[/^(no|always|on-success|on-failure|on-abnormal|on-abort|on-watchdog)$/], $systemd_restart) } + $service_provider_real = $service_provider ? { + undef => $docker::params::service_provider, + default => $service_provider, + } + if $detach == undef { - $valid_detach = $docker::params::detach_service_in_init + $valid_detach = $service_provider_real ? { + 'systemd' => false, + default => $docker::params::detach_service_in_init, + } } else { $valid_detach = $detach } $extra_parameters_array = any2array($extra_parameters) $after_array = any2array($after) $depends_array = any2array($depends) $depend_services_array = any2array($depend_services) $docker_run_flags = docker_run_flags({ cpuset => any2array($cpuset), disable_network => $disable_network, dns => any2array($dns), dns_search => any2array($dns_search), env => any2array($env), env_file => any2array($env_file), expose => any2array($expose), extra_params => any2array($extra_parameters), hostentries => any2array($hostentries), hostname => $hostname, links => any2array($links), lxc_conf => any2array($lxc_conf), memory_limit => $memory_limit, net => $net, ports => any2array($ports), labels => any2array($labels), privileged => $privileged, socket_connect => any2array($socket_connect), tty => $tty, username => $username, volumes => any2array($volumes), volumes_from => any2array($volumes_from), read_only => $read_only, health_check_cmd => $health_check_cmd, restart_on_unhealthy => $restart_on_unhealthy, health_check_interval => $health_check_interval, osfamily => $::osfamily, }) $sanitised_title = docker::sanitised_name($title) if empty($depends_array) { $sanitised_depends_array = [] } else { $sanitised_depends_array = docker::sanitised_name($depends_array) } if empty($after_array) { $sanitised_after_array = [] } else { $sanitised_after_array = docker::sanitised_name($after_array) } if $::osfamily == 'windows' { $exec_environment = "PATH=${::docker_program_files_path}/Docker/;${::docker_systemroot}/System32/" $exec_timeout = 3000 $exec_path = ["${::docker_program_files_path}/Docker/"] $exec_provider = 'powershell' $cidfile = "${::docker_user_temp_path}/${service_prefix}${sanitised_title}.cid" # lint:ignore:140chars $restart_check = "${docker_command} inspect ${sanitised_title} -f '{{ if eq \\\"unhealthy\\\" .State.Health.Status }} {{ .Name }}{{ end }}' | findstr ${sanitised_title}" $container_running_check = "\$state = ${docker_command} inspect ${sanitised_title} -f \"{{ .State.Running }}\"; if (\$state -ieq \"true\") { Exit 0 } else { Exit 1 }" # lint:endignore } else { $exec_environment = 'HOME=/root' $exec_path = ['/bin', '/usr/bin'] $exec_timeout = 0 $exec_provider = undef $cidfile = "/var/run/${service_prefix}${sanitised_title}.cid" # lint:ignore:140chars $restart_check = "${docker_command} inspect ${sanitised_title} -f '{{ if eq \"unhealthy\" .State.Health.Status }} {{ .Name }}{{ end }}' | grep ${sanitised_title}" $container_running_check = "${docker_command} inspect ${sanitised_title} -f \"{{ .State.Running }}\" | grep true" # lint:endignore } if $restart_on_unhealthy { exec { "Restart unhealthy container ${title} with docker": command => "${docker_command} restart ${sanitised_title}", onlyif => $restart_check, environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } } if $restart { if $ensure == 'absent' { exec { "stop ${title} with docker": command => "${docker_command} stop --time=${stop_wait_time} ${sanitised_title}", onlyif => "${docker_command} inspect ${sanitised_title}", environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } exec { "remove ${title} with docker": command => "${docker_command} rm -v ${sanitised_title}", onlyif => "${docker_command} inspect ${sanitised_title}", environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } file { $cidfile: ensure => absent, } } else { $run_with_docker_command = [ "${docker_command} run -d ${docker_run_flags}", "--name ${sanitised_title} --cidfile=${cidfile}", "--restart=\"${restart}\" ${image} ${command}", ] $inspect = ["${docker_command} inspect ${sanitised_title}"] if $custom_unless { $exec_unless = concat($custom_unless, $inspect) } else { $exec_unless = $inspect } exec { "run ${title} with docker": command => join($run_with_docker_command, ' '), unless => $exec_unless, environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } if $running == false { exec { "stop ${title} with docker": command => "${docker_command} stop --time=${stop_wait_time} ${sanitised_title}", onlyif => $container_running_check, environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } } else { exec { "start ${title} with docker": command => "${docker_command} start ${sanitised_title}", unless => $container_running_check, environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout } } } } else { $docker_run_inline_start = template('docker/docker-run-start.erb') $docker_run_inline_stop = template('docker/docker-run-stop.erb') - case $docker::params::service_provider { + case $service_provider_real { 'systemd': { $initscript = "/etc/systemd/system/${service_prefix}${sanitised_title}.service" $startscript = "/usr/local/bin/docker-run-${sanitised_title}-start.sh" $stopscript = "/usr/local/bin/docker-run-${sanitised_title}-stop.sh" $startstop_template = 'docker/usr/local/bin/docker-run.sh.epp' $init_template = 'docker/etc/systemd/system/docker-run.erb' $mode = '0644' + $hasstatus = true } 'upstart': { $initscript = "/etc/init.d/${service_prefix}${sanitised_title}" $init_template = 'docker/etc/init.d/docker-run.erb' $mode = '0750' $startscript = undef $stopscript = undef - $starstop_template = undef + $startstop_template = undef + $hasstatus = true } default: { if $::osfamily != 'windows' { fail(translate('Docker needs a Debian or RedHat based system.')) } elsif $ensure == 'present' { fail(translate('Restart parameter is required for Windows')) } + + $hasstatus = $::docker::params::service_hasstatus } } if $syslog_identifier { $_syslog_identifier = $syslog_identifier } else { $_syslog_identifier = "${service_prefix}${sanitised_title}" } if $ensure == 'absent' { if $::osfamily == 'windows'{ exec { "stop container ${service_prefix}${sanitised_title}": command => "${docker_command} stop --time=${stop_wait_time} ${sanitised_title}", onlyif => "${docker_command} inspect ${sanitised_title}", environment => $exec_environment, path => $exec_path, provider => $exec_provider, timeout => $exec_timeout, notify => Exec["remove container ${service_prefix}${sanitised_title}"] } } else { service { "${service_prefix}${sanitised_title}": ensure => false, enable => false, - hasstatus => $docker::params::service_hasstatus, + hasstatus => $hasstatus, + provider => $service_provider_real, } } exec { "remove container ${service_prefix}${sanitised_title}": command => "${docker_command} rm -v ${sanitised_title}", onlyif => "${docker_command} inspect ${sanitised_title}", environment => $exec_environment, path => $exec_path, refreshonly => true, provider => $exec_provider, timeout => $exec_timeout } if $::osfamily != 'windows' { file { "/etc/systemd/system/${service_prefix}${sanitised_title}.service": ensure => absent, path => "/etc/systemd/system/${service_prefix}${sanitised_title}.service", } if ($startscript) { file { $startscript: ensure => absent } } if ($stopscript) { file { $stopscript: ensure => absent } } } else { file { $cidfile: ensure => absent, } } } else { if ($startscript) { file { $startscript: ensure => present, content => epp($startstop_template, {'script' => $docker_run_inline_start}), owner => 'root', group => $docker_group, mode => '0770' } } if ($stopscript) { file { $stopscript: ensure => present, content => epp($startstop_template, {'script' => $docker_run_inline_stop}), owner => 'root', group => $docker_group, mode => '0770' } } file { $initscript: ensure => present, content => template($init_template), owner => 'root', group => $docker_group, mode => $mode, } if $manage_service { if $running == false { service { "${service_prefix}${sanitised_title}": ensure => $running, enable => false, - hasstatus => $docker::params::service_hasstatus, + hasstatus => $hasstatus, require => File[$initscript], } } else { # Transition help from moving from CID based container detection to # Name-based container detection. See #222 for context. # This code should be considered temporary until most people have # transitioned. - 2015-04-15 if $initscript == "/etc/init.d/${service_prefix}${sanitised_title}" { # This exec sequence will ensure the old-style CID container is stopped # before we replace the init script with the new-style. $transition_onlyif = [ "/usr/bin/test -f /var/run/docker-${sanitised_title}.cid &&", "/usr/bin/test -f /etc/init.d/${service_prefix}${sanitised_title}", ] exec { "/bin/sh /etc/init.d/${service_prefix}${sanitised_title} stop": onlyif => join($transition_onlyif, ' '), require => [], } -> file { "/var/run/${service_prefix}${sanitised_title}.cid": ensure => absent, } -> File[$initscript] } service { "${service_prefix}${sanitised_title}": ensure => $running, enable => true, - provider => $docker::params::service_provider, - hasstatus => $docker::params::service_hasstatus, + provider => $service_provider_real, + hasstatus => $hasstatus, require => File[$initscript], } } if $docker_service { if $docker_service == true { Service['docker'] -> Service["${service_prefix}${sanitised_title}"] if $restart_service_on_docker_refresh == true { Service['docker'] ~> Service["${service_prefix}${sanitised_title}"] } } else { Service[$docker_service] -> Service["${service_prefix}${sanitised_title}"] if $restart_service_on_docker_refresh == true { Service[$docker_service] ~> Service["${service_prefix}${sanitised_title}"] } } } } - if $docker::params::service_provider == 'systemd' { + if $service_provider_real == 'systemd' { exec { "docker-${sanitised_title}-systemd-reload": path => ['/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/'], command => 'systemctl daemon-reload', refreshonly => true, require => [File[$initscript],File[$startscript],File[$stopscript]], subscribe => [File[$initscript],File[$startscript],File[$stopscript]] } Exec["docker-${sanitised_title}-systemd-reload"] -> Service<| title == "${service_prefix}${sanitised_title}" |> } if $restart_service { if $startscript or $stopscript { [File[$initscript],File[$startscript],File[$stopscript]] ~> Service<| title == "${service_prefix}${sanitised_title}" |> } else { [File[$initscript]] ~> Service<| title == "${service_prefix}${sanitised_title}" |> } } else { if $startscript or $stopscript { [File[$initscript],File[$startscript],File[$stopscript]] -> Service<| title == "${service_prefix}${sanitised_title}" |> } else { [File[$initscript]] -> Service<| title == "${service_prefix}${sanitised_title}" |> } } } } } diff --git a/manifests/service.pp b/manifests/service.pp index f2d7502..0e2f446 100755 --- a/manifests/service.pp +++ b/manifests/service.pp @@ -1,247 +1,249 @@ # == Class: docker::service # # Class to manage the docker service daemon # # === Parameters # [*tcp_bind*] # Which tcp port, if any, to bind the docker service to. # # [*ip_forward*] # This flag interacts with the IP forwarding setting on # your host system's kernel # # [*iptables*] # Enable Docker's addition of iptables rules # # [*ip_masq*] # Enable IP masquerading for bridge's IP range. # # [*socket_bind*] # Which local unix socket to bind the docker service to. # # [*socket_group*] # Which local unix socket to bind the docker service to. # # [*root_dir*] # Specify a non-standard root directory for docker. # # [*extra_parameters*] # Plain additional parameters to pass to the docker daemon # # [*shell_values*] # Array of shell values to pass into init script config files # # [*manage_service*] # Specify whether the service should be managed. # Valid values are 'true', 'false'. # Defaults to 'true'. # class docker::service ( $docker_command = $docker::docker_command, $docker_start_command = $docker::docker_start_command, $service_name = $docker::service_name, $tcp_bind = $docker::tcp_bind, $ip_forward = $docker::ip_forward, $iptables = $docker::iptables, $ip_masq = $docker::ip_masq, $icc = $docker::icc, $bridge = $docker::bridge, $fixed_cidr = $docker::fixed_cidr, $default_gateway = $docker::default_gateway, $ipv6 = $docker::ipv6, $ipv6_cidr = $docker::ipv6_cidr, $default_gateway_ipv6 = $docker::default_gateway_ipv6, $socket_bind = $docker::socket_bind, $log_level = $docker::log_level, $log_driver = $docker::log_driver, $log_opt = $docker::log_opt, $selinux_enabled = $docker::selinux_enabled, $socket_group = $docker::socket_group, $labels = $docker::labels, $dns = $docker::dns, $dns_search = $docker::dns_search, $service_state = $docker::service_state, $service_enable = $docker::service_enable, $manage_service = $docker::manage_service, $root_dir = $docker::root_dir, $extra_parameters = $docker::extra_parameters, $shell_values = $docker::shell_values, $proxy = $docker::proxy, $no_proxy = $docker::no_proxy, $execdriver = $docker::execdriver, $bip = $docker::bip, $mtu = $docker::mtu, $storage_driver = $docker::storage_driver, $dm_basesize = $docker::dm_basesize, $dm_fs = $docker::dm_fs, $dm_mkfsarg = $docker::dm_mkfsarg, $dm_mountopt = $docker::dm_mountopt, $dm_blocksize = $docker::dm_blocksize, $dm_loopdatasize = $docker::dm_loopdatasize, $dm_loopmetadatasize = $docker::dm_loopmetadatasize, $dm_datadev = $docker::dm_datadev, $dm_metadatadev = $docker::dm_metadatadev, $tmp_dir_config = $docker::tmp_dir_config, $tmp_dir = $docker::tmp_dir, $dm_thinpooldev = $docker::dm_thinpooldev, $dm_use_deferred_removal = $docker::dm_use_deferred_removal, $dm_use_deferred_deletion = $docker::dm_use_deferred_deletion, $dm_blkdiscard = $docker::dm_blkdiscard, $dm_override_udev_sync_check = $docker::dm_override_udev_sync_check, $overlay2_override_kernel_check = $docker::overlay2_override_kernel_check, $storage_devs = $docker::storage_devs, $storage_vg = $docker::storage_vg, $storage_root_size = $docker::storage_root_size, $storage_data_size = $docker::storage_data_size, $storage_min_data_size = $docker::storage_min_data_size, $storage_chunk_size = $docker::storage_chunk_size, $storage_growpart = $docker::storage_growpart, $storage_auto_extend_pool = $docker::storage_auto_extend_pool, $storage_pool_autoextend_threshold = $docker::storage_pool_autoextend_threshold, $storage_pool_autoextend_percent = $docker::storage_pool_autoextend_percent, $storage_config = $docker::storage_config, $storage_config_template = $docker::storage_config_template, $storage_setup_file = $docker::storage_setup_file, $service_provider = $docker::service_provider, $service_config = $docker::service_config, $service_config_template = $docker::service_config_template, $service_overrides_template = $docker::service_overrides_template, $socket_overrides_template = $docker::socket_overrides_template, $socket_override = $docker::socket_override, $service_after_override = $docker::service_after_override, $service_hasstatus = $docker::service_hasstatus, $service_hasrestart = $docker::service_hasrestart, $daemon_environment_files = $docker::daemon_environment_files, $tls_enable = $docker::tls_enable, $tls_verify = $docker::tls_verify, $tls_cacert = $docker::tls_cacert, $tls_cert = $docker::tls_cert, $tls_key = $docker::tls_key, $registry_mirror = $docker::registry_mirror, $root_dir_flag = $docker::root_dir_flag, ) { - unless $::osfamily =~ /(Debian|RedHat|windows)/ { + unless $::osfamily =~ /(Debian|RedHat|windows)/ or $::docker::acknowledge_unsupported_os { fail(translate('The docker::service class needs a Debian, Redhat or Windows based system.')) } $dns_array = any2array($dns) $dns_search_array = any2array($dns_search) $labels_array = any2array($labels) $extra_parameters_array = any2array($extra_parameters) $shell_values_array = any2array($shell_values) $tcp_bind_array = any2array($tcp_bind) if $service_config != undef { $_service_config = $service_config } else { if $::osfamily == 'Debian' { $_service_config = "/etc/default/${service_name}" + } else { + $_service_config = undef } } $_manage_service = $manage_service ? { true => Service['docker'], default => [], } if $::osfamily == 'RedHat' { file { $storage_setup_file: ensure => present, force => true, content => template('docker/etc/sysconfig/docker-storage-setup.erb'), before => $_manage_service, notify => $_manage_service, } } if $::osfamily == 'windows' { file { ["${::docker_program_data_path}/docker/", "${::docker_program_data_path}/docker/config/"]: ensure => directory, } } case $service_provider { 'systemd': { file { '/etc/systemd/system/docker.service.d': ensure => 'directory', } if $service_overrides_template { file { '/etc/systemd/system/docker.service.d/service-overrides.conf': ensure => 'present', content => template($service_overrides_template), notify => Exec['docker-systemd-reload-before-service'], before => $_manage_service, } } if $socket_override { file { '/etc/systemd/system/docker.socket.d': ensure => 'directory', } file { '/etc/systemd/system/docker.socket.d/socket-overrides.conf': ensure => 'present', content => template($socket_overrides_template), notify => Exec['docker-systemd-reload-before-service'], before => $_manage_service, } } exec { 'docker-systemd-reload-before-service': path => ['/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/'], command => 'systemctl daemon-reload > /dev/null', notify => $_manage_service, refreshonly => true, } } 'upstart': { file { '/etc/init.d/docker': ensure => 'link', target => '/lib/init/upstart-job', force => true, notify => $_manage_service, } } default: {} } if $storage_config { file { $storage_config: ensure => present, force => true, content => template($storage_config_template), notify => $_manage_service, } } if $_service_config { file { $_service_config: ensure => present, force => true, content => template($service_config_template), notify => $_manage_service, } } if $manage_service { if $::osfamily == 'windows' { reboot { 'pending_reboot': when => 'pending', onlyif => 'component_based_servicing', timeout => 1, } } if ! defined(Service['docker']) { service { 'docker': ensure => $service_state, name => $service_name, enable => $service_enable, hasstatus => $service_hasstatus, hasrestart => $service_hasrestart, provider => $service_provider, } } } } diff --git a/spec/defines/run_spec.rb b/spec/defines/run_spec.rb index 06119a3..e2398bf 100755 --- a/spec/defines/run_spec.rb +++ b/spec/defines/run_spec.rb @@ -1,686 +1,685 @@ require 'spec_helper' -['Debian', 'RedHat'].each do |osfamily| +['Debian', 'RedHat', 'generic systemd'].each do |osfamily| describe 'docker::run', :type => :define do let(:title) { 'sample' } - let(:pre_condition) { "class { 'docker': docker_group => 'docker', service_name => 'docker' }" } + + params = {'command' => 'command', 'image' => 'base'} + context "on #{osfamily}" do initscript = '/etc/systemd/system/docker-sample.service' startscript = "/usr/local/bin/docker-run-sample-start.sh" stopscript = "/usr/local/bin/docker-run-sample-stop.sh" if osfamily == 'Debian' + pre_condition = "class { 'docker': docker_group => 'docker', service_name => 'docker' }" + let(:pre_condition) { pre_condition } let(:facts) { { :architecture => 'amd64', :osfamily => 'Debian', :operatingsystem => 'Ubuntu', :lsbdistid => 'Ubuntu', :lsbdistcodename => 'xenial', :kernelrelease => '4.4.0-21-generic', :operatingsystemrelease => '16.04', :operatingsystemmajrelease => '16.04', - :os => { :distro => { :codename => 'wheezy' }, :family => 'Debian', :name => 'Debian', :release => { :major => '7', :full => '7.0' } } + :os => { :distro => { :codename => 'wheezy' }, :family => 'Debian', :name => 'Debian', :release => { :major => '7', :full => '7.0' } } } } systemd = true elsif osfamily == 'RedHat' + pre_condition = "class { 'docker': docker_group => 'docker', service_name => 'docker' }" + let(:pre_condition) { pre_condition } let(:facts) { { :architecture => 'x86_64', :osfamily => osfamily, :operatingsystem => 'RedHat', :lsbdistcodename => 'xenial', :operatingsystemrelease => '7.2', :operatingsystemmajrelease => '7', :kernelversion => '3.10.0', :os => { :distro => { :codename => 'wheezy' }, :family => osfamily, :name => osfamily, :release => { :major => '7', :full => '7.0' } } } } systemd = true + elsif osfamily == 'generic systemd' + pre_condition = "class { 'docker': docker_group => 'docker', service_name => 'docker', service_provider => systemd, acknowledge_unsupported_os => true }" + let(:pre_condition) { pre_condition } + let(:facts) { { + :osfamily => 'Gentoo', + :operatingsystem => 'Generic', + } } + params.merge!({'service_provider' => 'systemd'}) + systemd = true end - + startscript_or_init = systemd ? startscript : initscript stopscript_or_init = systemd ? stopscript : initscript context 'passing the required params' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } it { should compile.with_all_deps } it { should contain_service('docker-sample') } it { should contain_file(initscript).with_content(/#{Regexp.escape(startscript)}/).with_mode('0644') } it { should contain_file(initscript).with_content(/#{Regexp.escape(stopscript)}/) } it { should contain_file(startscript_or_init).with_content(/docker start/).with_content(/command/).with_content(/base/)} if systemd it { should contain_file(initscript).with_content(/^SyslogIdentifier=docker-sample$/) } end end context 'when passing `after` containers' do - let(:params) { {'command' => 'command', 'image' => 'base', 'after' => ['foo', 'bar', 'foo_bar/baz']} } + let(:params) { params.merge({'after' => ['foo', 'bar', 'foo_bar/baz']}) } if (systemd) it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-foo.service/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-bar.service/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-foo_bar-baz.service/) } it { should contain_file(initscript).with_content(/Wants=(.*\s+)?docker-foo.service/) } it { should contain_file(initscript).with_content(/Wants=(.*\s+)?docker-bar.service/) } it { should contain_file(initscript).with_content(/Wants=(.*\s+)?docker-foo_bar-baz.service/) } else it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-foo/) } it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-bar/) } it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-foo_bar-baz/) } end end context 'when passing `depends` containers' do - let(:params) { {'command' => 'command', 'image' => 'base', 'depends' => ['foo', 'bar', 'foo_bar/baz']} } + let(:params) { params.merge({'depends' => ['foo', 'bar', 'foo_bar/baz']}) } if (systemd) it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-foo.service/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-bar.service/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?docker-foo_bar-baz.service/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?docker-foo.service/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?docker-bar.service/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?docker-foo_bar-baz.service/) } else it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-foo/) } it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-bar/) } it { should contain_file(initscript).with_content(/Required-Start:.*\s+docker-foo_bar-baz/) } it { should contain_file(initscript).with_content(/Required-Stop:.*\s+docker-foo/) } it { should contain_file(initscript).with_content(/Required-Stop:.*\s+docker-bar/) } it { should contain_file(initscript).with_content(/Required-Stop:.*\s+docker-foo_bar-baz/) } end end context 'when passing `depend_services`' do - let(:params) { {'command' => 'command', 'image' => 'base', 'depend_services' => ['foo', 'bar']} } + let(:params) { params.merge({'depend_services' => ['foo', 'bar']}) } if (systemd) it { should contain_file(initscript).with_content(/After=(.*\s+)?foo.service/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?bar.service/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?foo.service/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?bar.service/) } context 'with full systemd unit names' do - let(:params) { {'command' => 'command', 'image' => 'base', 'depend_services' => ['foo', 'bar.service', 'baz.target']} } + let(:params) { params.merge({'depend_services' => ['foo', 'bar.service', 'baz.target']}) } it { should contain_file(initscript).with_content(/After=(.*\s+)?foo.service(\s+|$)/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?bar.service(\s+|$)/) } it { should contain_file(initscript).with_content(/After=(.*\s+)?baz.target(\s+|$)/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?foo.service(\s+|$)/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?bar.service(\s+|$)/) } it { should contain_file(initscript).with_content(/Requires=(.*\s+)?baz.target(\s+|$)/) } end else it { should contain_file(initscript).with_content(/Required-Start:.*\s+foo/) } it { should contain_file(initscript).with_content(/Required-Start:.*\s+bar/) } it { should contain_file(initscript).with_content(/Required-Stop:.*\s+foo/) } it { should contain_file(initscript).with_content(/Required-Stop:.*\s+bar/) } end end context 'removing containers and volumes' do context 'when trying to remove the volume and not the container on stop' do - let(:params) {{ - 'command' => 'command', - 'image' => 'base', + let(:params) { params.merge({ 'remove_container_on_stop' => false, 'remove_volume_on_stop' => true, - }} + }) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'when trying to remove the volume and not the container on start' do - let(:params) {{ - 'command' => 'command', - 'image' => 'base', + let(:params) { params.merge({ 'remove_container_on_start' => false, 'remove_volume_on_start' => true, - }} + }) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'When restarting an unhealthy container' do - let(:params) {{ - 'command' => 'command', - 'image' => 'base', + let(:params) { params.merge({ 'health_check_cmd' => 'pwd', 'restart_on_unhealthy' => true, 'health_check_interval' => 60, - }} + }) } if (systemd) - it { should contain_file(stopscript).with_content(/\/usr\/bin\/docker stop --time=0 /).with_content(/\/usr\/bin\/docker rm/) } + it { should contain_file(stopscript).with_content(/\/usr\/bin\/docker stop --time=0 /).with_content(/\/usr\/bin\/docker rm/) } it { should contain_file(startscript).with_content(/--health-cmd/) } end end context 'when not removing containers on container start and stop' do - let(:params) {{ - 'command' => 'command', - 'image' => 'base', + let(:params) { params.merge({ 'remove_container_on_start' => false, 'remove_container_on_stop' => false, - }} + }) } it { should_not contain_file(startscript_or_init).with_content(/\/usr\/bin\/docker rm sample/) } end context 'when removing containers on container start' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_container_on_start' => true} } + let(:params) { params.merge({'remove_container_on_start' => true}) } it { should contain_file(startscript_or_init).with_content(/\/usr\/bin\/docker rm sample/) } end context 'when removing containers on container stop' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_container_on_stop' => true} } + let(:params) { params.merge({'remove_container_on_stop' => true}) } it { should contain_file(stopscript_or_init).with_content(/\/usr\/bin\/docker rm sample/) } end context 'when not removing volumes on container start' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_volume_on_start' => false} } + let(:params) { params.merge({'remove_volume_on_start' => false}) } it { should_not contain_file(startscript_or_init).with_content(/\/usr\/bin\/docker rm -v sample/) } end context 'when removing volumes on container start' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_volume_on_start' => true} } + let(:params) { params.merge({'remove_volume_on_start' => true}) } it { should contain_file(startscript_or_init).with_content(/\/usr\/bin\/docker rm -v/) } end context 'when not removing volumes on container stop' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_volume_on_stop' => false} } + let(:params) { params.merge({'remove_volume_on_stop' => false}) } it { should_not contain_file(stopscript_or_init).with_content(/\/usr\/bin\/docker rm -v sample/) } end context 'when removing volumes on container stop' do - let(:params) { {'command' => 'command', 'image' => 'base', 'remove_volume_on_stop' => true} } + let(:params) { params.merge({'remove_volume_on_stop' => true}) } it { should contain_file(stopscript_or_init).with_content(/\/usr\/bin\/docker rm -v/) } end end context 'with autorestart functionality' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } if (systemd) it { should contain_file(initscript).with_content(/Restart=on-failure/) } end end context 'when lxc_conf disables swap' do - let(:params) { {'command' => 'command', 'image' => 'base', 'lxc_conf' => 'lxc.cgroup.memory.memsw.limit_in_bytes=536870912'} } + let(:params) { params.merge({'lxc_conf' => 'lxc.cgroup.memory.memsw.limit_in_bytes=536870912'}) } it { should contain_file(startscript_or_init).with_content(/-lxc-conf=\"lxc.cgroup.memory.memsw.limit_in_bytes=536870912\"/) } end context 'when `use_name` is true' do - let(:params) { {'command' => 'command', 'image' => 'base', 'use_name' => true } } + let(:params) { params.merge({'use_name' => true }) } it { should contain_file(startscript_or_init).with_content(/--name sample /) } end context 'when stopping the service' do - let(:params) { {'command' => 'command', 'image' => 'base', 'running' => false} } + let(:params) { params.merge({'running' => false}) } it { should contain_service('docker-sample').with_ensure(false) } end context 'when passing a memory limit in bytes' do - let(:params) { {'command' => 'command', 'image' => 'base', 'memory_limit' => '1000b'} } + let(:params) { params.merge({'memory_limit' => '1000b'}) } it { should contain_file(startscript_or_init).with_content(/-m 1000b/) } end context 'when passing a cpuset' do - let(:params) { {'command' => 'command', 'image' => 'base', 'cpuset' => '3'} } + let(:params) { params.merge({'cpuset' => '3'}) } it { should contain_file(startscript_or_init).with_content(/--cpuset-cpus=3/) } end context 'when passing a multiple cpu cpuset' do - let(:params) { {'command' => 'command', 'image' => 'base', 'cpuset' => ['0', '3']} } + let(:params) { params.merge({'cpuset' => ['0', '3']}) } it { should contain_file(startscript_or_init).with_content(/--cpuset-cpus=0,3/) } end context 'when not passing a cpuset' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } it { should contain_file(startscript_or_init).without_content(/--cpuset-cpus=/) } end context 'when passing a links option' do - let(:params) { {'command' => 'command', 'image' => 'base', 'links' => ['example:one', 'example:two']} } + let(:params) { params.merge({'links' => ['example:one', 'example:two']}) } it { should contain_file(startscript_or_init).with_content(/--link example:one/).with_content(/--link example:two/) } end context 'when passing a hostname' do - let(:params) { {'command' => 'command', 'image' => 'base', 'hostname' => 'example.com'} } + let(:params) { params.merge({'hostname' => 'example.com'}) } it { should contain_file(startscript_or_init).with_content(/-h 'example.com'/) } end context 'when not passing a hostname' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } it { should contain_file(startscript_or_init).without_content(/-h ''/) } end context 'when passing a username' do - let(:params) { {'command' => 'command', 'image' => 'base', 'username' => 'bob'} } + let(:params) { params.merge({'username' => 'bob'}) } it { should contain_file(startscript_or_init).with_content(/-u 'bob'/) } end context 'when not passing a username' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } it { should contain_file(startscript_or_init).without_content(/-u ''/) } end context 'when passing a port number' do - let(:params) { {'command' => 'command', 'image' => 'base', 'ports' => '4444'} } + let(:params) { params.merge({'ports' => '4444'}) } it { should contain_file(startscript_or_init).with_content(/-p 4444/) } end context 'when passing a port to expose' do - let(:params) { {'command' => 'command', 'image' => 'base', 'expose' => '4666'} } + let(:params) { params.merge({'expose' => '4666'}) } it { should contain_file(startscript_or_init).with_content(/--expose=4666/) } end context 'when passing a label' do - let(:params) { {'command' => 'command', 'image' => 'base', 'labels' => 'key=value'} } + let(:params) { params.merge({'labels' => 'key=value'}) } it { should contain_file(startscript_or_init).with_content(/-l key=value/) } end context 'when passing a hostentry' do - let(:params) { {'command' => 'command', 'image' => 'base', 'hostentries' => 'dummyhost:127.0.0.2'} } + let(:params) { params.merge({'hostentries' => 'dummyhost:127.0.0.2'}) } it { should contain_file(startscript_or_init).with_content(/--add-host dummyhost:127.0.0.2/) } end context 'when connecting to shared data volumes' do - let(:params) { {'command' => 'command', 'image' => 'base', 'volumes_from' => '6446ea52fbc9'} } + let(:params) { params.merge({'volumes_from' => '6446ea52fbc9'}) } it { should contain_file(startscript_or_init).with_content(/--volumes-from 6446ea52fbc9/) } end context 'when connecting to several shared data volumes' do - let(:params) { {'command' => 'command', 'image' => 'base', 'volumes_from' => ['sample-linked-container-1', 'sample-linked-container-2']} } + let(:params) { params.merge({'volumes_from' => ['sample-linked-container-1', 'sample-linked-container-2']}) } it { should contain_file(startscript_or_init).with_content(/--volumes-from sample-linked-container-1/) } it { should contain_file(startscript_or_init).with_content(/--volumes-from sample-linked-container-2/) } end context 'when passing several port numbers' do - let(:params) { {'command' => 'command', 'image' => 'base', 'ports' => ['4444', '4555']} } + let(:params) { params.merge({'ports' => ['4444', '4555']}) } it { should contain_file(startscript_or_init).with_content(/-p 4444/).with_content(/-p 4555/) } end context 'when passing several labels' do - let(:params) { {'command' => 'command', 'image' => 'base', 'labels' => ['key1=value1', 'key2=value2']} } + let(:params) { params.merge({'labels' => ['key1=value1', 'key2=value2']}) } it { should contain_file(startscript_or_init).with_content(/-l key1=value1/).with_content(/-l key2=value2/) } end context 'when passing several ports to expose' do - let(:params) { {'command' => 'command', 'image' => 'base', 'expose' => ['4666', '4777']} } + let(:params) { params.merge({'expose' => ['4666', '4777']}) } it { should contain_file(startscript_or_init).with_content(/--expose=4666/).with_content(/--expose=4777/) } end context 'when passing serveral environment variables' do - let(:params) { {'command' => 'command', 'image' => 'base', 'env' => ['FOO=BAR', 'FOO2=BAR2']} } + let(:params) { params.merge({'env' => ['FOO=BAR', 'FOO2=BAR2']}) } it { should contain_file(startscript_or_init).with_content(/-e "FOO=BAR"/).with_content(/-e "FOO2=BAR2"/) } end context 'when passing an environment variable' do - let(:params) { {'command' => 'command', 'image' => 'base', 'env' => 'FOO=BAR'} } + let(:params) { params.merge({'env' => 'FOO=BAR'}) } it { should contain_file(startscript_or_init).with_content(/-e "FOO=BAR"/) } end context 'when passing serveral environment files' do - let(:params) { {'command' => 'command', 'image' => 'base', 'env_file' => ['/etc/foo.env', '/etc/bar.env']} } + let(:params) { params.merge({'env_file' => ['/etc/foo.env', '/etc/bar.env']}) } it { should contain_file(startscript_or_init).with_content(/--env-file \/etc\/foo.env/).with_content(/--env-file \/etc\/bar.env/) } end context 'when passing an environment file' do - let(:params) { {'command' => 'command', 'image' => 'base', 'env_file' => '/etc/foo.env'} } + let(:params) { params.merge({'env_file' => '/etc/foo.env'}) } it { should contain_file(startscript_or_init).with_content(/--env-file \/etc\/foo.env/) } end context 'when passing serveral dns addresses' do - let(:params) { {'command' => 'command', 'image' => 'base', 'dns' => ['8.8.8.8', '8.8.4.4']} } + let(:params) { params.merge({'dns' => ['8.8.8.8', '8.8.4.4']}) } it { should contain_file(startscript_or_init).with_content(/--dns 8.8.8.8/).with_content(/--dns 8.8.4.4/) } end context 'when passing a dns address' do - let(:params) { {'command' => 'command', 'image' => 'base', 'dns' => '8.8.8.8'} } + let(:params) { params.merge({'dns' => '8.8.8.8'}) } it { should contain_file(startscript_or_init).with_content(/--dns 8.8.8.8/) } end context 'when passing serveral sockets to connect to' do - let(:params) { {'command' => 'command', 'image' => 'base', 'socket_connect' => ['tcp://127.0.0.1:4567', 'tcp://127.0.0.2:4567']} } + let(:params) { params.merge({'socket_connect' => ['tcp://127.0.0.1:4567', 'tcp://127.0.0.2:4567']}) } it { should contain_file(startscript_or_init).with_content(/-H tcp:\/\/127.0.0.1:4567/) } end context 'when passing a socket to connect to' do - let(:params) { {'command' => 'command', 'image' => 'base', 'socket_connect' => 'tcp://127.0.0.1:4567'} } + let(:params) { params.merge({'socket_connect' => 'tcp://127.0.0.1:4567'}) } it { should contain_file(startscript_or_init).with_content(/-H tcp:\/\/127.0.0.1:4567/) } end context 'when passing serveral dns search domains' do - let(:params) { {'command' => 'command', 'image' => 'base', 'dns_search' => ['my.domain.local', 'other-domain.de']} } + let(:params) { params.merge({'dns_search' => ['my.domain.local', 'other-domain.de']}) } it { should contain_file(startscript_or_init).with_content(/--dns-search my.domain.local/).with_content(/--dns-search other-domain.de/) } end context 'when passing a dns search domain' do - let(:params) { {'command' => 'command', 'image' => 'base', 'dns_search' => 'my.domain.local'} } + let(:params) { params.merge({'dns_search' => 'my.domain.local'}) } it { should contain_file(startscript_or_init).with_content(/--dns-search my.domain.local/) } end context 'when disabling network' do - let(:params) { {'command' => 'command', 'image' => 'base', 'disable_network' => true} } + let(:params) { params.merge({'disable_network' => true}) } it { should contain_file(startscript_or_init).with_content(/-n false/) } end context 'when running privileged' do - let(:params) { {'command' => 'command', 'image' => 'base', 'privileged' => true} } + let(:params) { params.merge({'privileged' => true}) } it { should contain_file(startscript_or_init).with_content(/--privileged/) } end context 'should run with correct detached value' do - let(:params) { {'command' => 'command', 'image' => 'base'} } + let(:params) { params } if (systemd) it { should_not contain_file(startscript).with_content(/--detach=true/) } else it { should contain_file(initscript).with_content(/--detach=true/) } end end context 'should be able to override detached' do - let(:params) { {'command' => 'command', 'image' => 'base', 'detach' => false} } + let(:params) { params.merge({'detach' => false}) } it { should contain_file(startscript_or_init).without_content(/--detach=true/) } end context 'when running with a tty' do - let(:params) { {'command' => 'command', 'image' => 'base', 'tty' => true} } + let(:params) { params.merge({'tty' => true}) } it { should contain_file(startscript_or_init).with_content(/-t/) } end context 'when running with read-only image' do - let(:params) { {'command' => 'command', 'image' => 'base', 'read_only' => true} } + let(:params) { params.merge({'read_only' => true}) } it { should contain_file(startscript_or_init).with_content(/--read-only=true/) } end context 'when passing serveral extra parameters' do - let(:params) { {'command' => 'command', 'image' => 'base', 'extra_parameters' => ['--rm', '-w /tmp']} } + let(:params) { params.merge({'extra_parameters' => ['--rm', '-w /tmp']}) } it { should contain_file(startscript_or_init).with_content(/--rm/).with_content(/-w \/tmp/) } end context 'when passing an extra parameter' do - let(:params) { {'command' => 'command', 'image' => 'base', 'extra_parameters' => '-c 4'} } + let(:params) { params.merge({'extra_parameters' => '-c 4'}) } it { should contain_file(startscript_or_init).with_content(/-c 4/) } end context 'when passing a data volume' do - let(:params) { {'command' => 'command', 'image' => 'base', 'volumes' => '/var/log'} } + let(:params) { params.merge({'volumes' => '/var/log'}) } it { should contain_file(startscript_or_init).with_content(/-v \/var\/log/) } end context 'when passing serveral data volume' do - let(:params) { {'command' => 'command', 'image' => 'base', 'volumes' => ['/var/lib/couchdb', '/var/log']} } + let(:params) { params.merge({'volumes' => ['/var/lib/couchdb', '/var/log']}) } it { should contain_file(startscript_or_init).with_content(/-v \/var\/lib\/couchdb/) } it { should contain_file(startscript_or_init).with_content(/-v \/var\/log/) } end context 'when using network mode with a single network' do - let(:params) { {'command' => 'command', 'image' => 'nginx', 'net' => 'host'} } + let(:params) { params.merge({'net' => 'host'}) } it { should contain_file(startscript_or_init).with_content(/--net host/) } end context 'when using network mode with multiple networks' do - let(:params) { {'command' => 'command', 'image' => 'nginx', 'net' => ['host','foo']} } + let(:params) { params.merge({'net' => ['host','foo']}) } it { should contain_file(startscript_or_init).with_content(/docker network connect host sample/) } it { should contain_file(startscript_or_init).with_content(/docker network connect foo sample/) } end context 'when `pull_on_start` is true' do - let(:params) { {'command' => 'command', 'image' => 'base', 'pull_on_start' => true } } + let(:params) { params.merge({'pull_on_start' => true}) } it { should contain_file(startscript_or_init).with_content(/docker pull base/) } end context 'when `pull_on_start` is false' do - let(:params) { {'command' => 'command', 'image' => 'base', 'pull_on_start' => false } } + let(:params) { params.merge({'pull_on_start' => false}) } it { should_not contain_file(startscript_or_init).with_content(/docker pull base/) } end context 'when `before_start` is set' do - let(:params) { {'command' => 'command', 'image' => 'base', 'before_start' => "echo before_start" } } + let(:params) { params.merge({'before_start' => "echo before_start"}) } it { should contain_file(startscript_or_init).with_content(/before_start/) } end context 'when `before_start` is not set' do - let(:params) { {'command' => 'command', 'image' => 'base', 'before_start' => false } } + let(:params) { params.merge({'before_start' => false}) } it { should_not contain_file(startscript_or_init).with_content(/before_start/) } end context 'when `before_stop` is set' do - let(:params) { {'command' => 'command', 'image' => 'base', 'before_stop' => "echo before_stop" } } + let(:params) { params.merge({'before_stop' => "echo before_stop"}) } it { should contain_file(stopscript_or_init).with_content(/before_stop/) } end context 'when `before_stop` is not set' do - let(:params) { {'command' => 'command', 'image' => 'base', 'before_stop' => false } } + let(:params) { params.merge({'before_stop' => false}) } it { should_not contain_file(stopscript_or_init).with_content(/before_stop/) } end context 'when `after_create` is set' do - let(:params) { {'command' => 'command', 'image' => 'base', 'after_create' => "echo after_create" } } + let(:params) { params.merge({'after_create' => "echo after_create"}) } it { should contain_file(startscript_or_init).with_content(/after_create/) } end context 'with an title that will not format into a path' do let(:title) { 'this/that' } - let(:params) { {'image' => 'base'} } + let(:params) { params } new_initscript = '/etc/systemd/system/docker-this-that.service' new_startscript = '/usr/local/bin/docker-run-this-that-start.sh' new_stopscript = '/usr/local/bin/docker-run-this-that-stop.sh' it { should contain_service('docker-this-that') } it { should contain_file(new_initscript) } it { should contain_file(new_startscript) } it { should contain_file(new_stopscript) } end context 'with manage_service turned off' do let(:title) { 'this/that' } - let(:params) { {'image' => 'base', 'manage_service' => false} } + let(:params) { params.merge({'manage_service' => false}) } new_initscript = '/etc/systemd/system/docker-this-that.service' new_startscript = '/usr/local/bin/docker-run-this-that-start.sh' new_stopscript = '/usr/local/bin/docker-run-this-that-stop.sh' it { should_not contain_service('docker-this-that') } it { should contain_file(new_initscript) } it { should contain_file(new_startscript) } it { should contain_file(new_stopscript) } end context 'with service_prefix set to empty string' do let(:title) { 'this/that' } - let(:params) { {'image' => 'base', 'service_prefix' => ''} } + let(:params) { params.merge({'service_prefix' => ''}) } new_initscript = '/etc/systemd/system/this-that.service' new_startscript = '/usr/local/bin/docker-run-this-that-start.sh' new_stopscript = '/usr/local/bin/docker-run-this-that-stop.sh' it { should contain_service('this-that') } it { should contain_file(new_initscript) } it { should contain_file(new_startscript) } it { should contain_file(new_stopscript) } end context 'with an invalid title' do let(:title) { 'with spaces' } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'with title that need sanitisation' do let(:title) { 'this/that_other' } - let(:params) { {'image' => 'base' } } + let(:params) { params } new_initscript = '/etc/systemd/system/docker-this-that_other.service' new_startscript = '/usr/local/bin/docker-run-this-that_other-start.sh' new_stopscript = '/usr/local/bin/docker-run-this-that_other-stop.sh' it { should contain_service('docker-this-that_other') } it { should contain_file(new_initscript) } it { should contain_file(new_startscript) } it { should contain_file(new_stopscript) } end context 'with an invalid image name' do - let(:params) { {'command' => 'command', 'image' => 'with spaces', 'running' => 'not a boolean'} } + let(:params) { params.merge({'image' => 'with spaces', 'running' => 'not a boolean'}) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'with an invalid running value' do let(:title) { 'with spaces' } - let(:params) { {'command' => 'command', 'image' => 'base', 'running' => 'not a boolean'} } + let(:params) { params.merge({'running' => 'not a boolean'}) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'with an invalid memory value' do let(:title) { 'with spaces' } - let(:params) { {'command' => 'command', 'image' => 'base', 'memory' => 'not a number'} } + let(:params) { params.merge({'memory' => 'not a number'}) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'with a missing memory unit' do let(:title) { 'with spaces' } - let(:params) { {'command' => 'command', 'image' => 'base', 'memory' => '10240'} } + let(:params) { params.merge({'memory' => '10240'}) } it do expect { should contain_service('docker-sample') }.to raise_error(Puppet::Error) end end context 'with restart policy set to no' do - let(:params) { {'restart' => 'no', 'command' => 'command', 'image' => 'base', 'extra_parameters' => '-c 4'} } + let(:params) { params.merge({'restart' => 'no', 'extra_parameters' => '-c 4'}) } it { should contain_exec('run sample with docker') } it { should contain_exec('run sample with docker').with_unless(/sample/) } it { should contain_exec('run sample with docker').with_unless(/inspect/) } it { should contain_exec('run sample with docker').with_command(/--cidfile=\/var\/run\/docker-sample.cid/) } it { should contain_exec('run sample with docker').with_command(/-c 4/) } it { should contain_exec('run sample with docker').with_command(/--restart="no"/) } it { should contain_exec('run sample with docker').with_command(/base command/) } it { should contain_exec('run sample with docker').with_timeout(0) } end context 'with restart policy set to always' do - let(:params) { {'restart' => 'always', 'command' => 'command', 'image' => 'base', 'extra_parameters' => '-c 4'} } + let(:params) { params.merge({'restart' => 'always', 'extra_parameters' => '-c 4'}) } it { should contain_exec('run sample with docker') } it { should contain_exec('run sample with docker').with_unless(/sample/) } it { should contain_exec('run sample with docker').with_unless(/inspect/) } it { should contain_exec('run sample with docker').with_command(/--cidfile=\/var\/run\/docker-sample.cid/) } it { should contain_exec('run sample with docker').with_command(/-c 4/) } it { should contain_exec('run sample with docker').with_command(/--restart="always"/) } it { should contain_exec('run sample with docker').with_command(/base command/) } it { should contain_exec('run sample with docker').with_timeout(0) } end context 'with restart policy set to on-failure' do - let(:params) { {'restart' => 'on-failure', 'command' => 'command', 'image' => 'base', 'extra_parameters' => '-c 4'} } + let(:params) { params.merge({'restart' => 'on-failure', 'extra_parameters' => '-c 4'}) } it { should contain_exec('run sample with docker') } it { should contain_exec('run sample with docker').with_unless(/sample/) } it { should contain_exec('run sample with docker').with_unless(/inspect/) } it { should contain_exec('run sample with docker').with_command(/--cidfile=\/var\/run\/docker-sample.cid/) } it { should contain_exec('run sample with docker').with_command(/-c 4/) } it { should contain_exec('run sample with docker').with_command(/--restart="on-failure"/) } it { should contain_exec('run sample with docker').with_command(/base command/) } it { should contain_exec('run sample with docker').with_timeout(0) } end context 'with restart policy set to on-failure:3' do - let(:params) { {'restart' => 'on-failure:3', 'command' => 'command', 'image' => 'base', 'extra_parameters' => '-c 4'} } + let(:params) { params.merge({'restart' => 'on-failure:3', 'extra_parameters' => '-c 4'}) } it { should contain_exec('run sample with docker') } it { should contain_exec('run sample with docker').with_unless(/sample/) } it { should contain_exec('run sample with docker').with_unless(/inspect/) } it { should contain_exec('run sample with docker').with_command(/--cidfile=\/var\/run\/docker-sample.cid/) } it { should contain_exec('run sample with docker').with_command(/-c 4/) } it { should contain_exec('run sample with docker').with_command(/--restart="on-failure:3"/) } it { should contain_exec('run sample with docker').with_command(/base command/) } it { should contain_exec('run sample with docker').with_timeout(0) } end context 'when `docker_service` is false' do - let(:params) { {'command' => 'command', 'image' => 'base', 'docker_service' => false} } + let(:params) { params.merge({'docker_service' => false}) } it { should compile.with_all_deps } it { should contain_service('docker-sample') } end context 'when `docker_service` is true' do - let(:params) { {'command' => 'command', 'image' => 'base', 'docker_service' => true} } - let(:pre_condition) { - [ "service { 'docker': }", - "class { 'docker': docker_group => 'docker', service_name => 'docker' }" ] } + let(:params) { params.merge({'docker_service' => true}) } + let(:pre_condition) { ["service { 'docker': provider => systemd }", pre_condition] } it { should compile.with_all_deps } it { should contain_service('docker').that_comes_before('Service[docker-sample]') } it { should contain_service('docker').that_notifies('Service[docker-sample]') } end context 'when `docker_service` is true and `restart_service_on_docker_refresh` is false' do - let(:params) { {'command' => 'command', 'image' => 'base', 'docker_service' => true, 'restart_service_on_docker_refresh' => false} } - let(:pre_condition) { - [ "service { 'docker': }", - "class { 'docker': docker_group => 'docker', service_name => 'docker' }" ] } + let(:params) { params.merge({'docker_service' => true, 'restart_service_on_docker_refresh' => false}) } + let(:pre_condition) { ["service { 'docker': provider => systemd }", pre_condition] } it { should compile.with_all_deps } it { should contain_service('docker').that_comes_before('Service[docker-sample]') } end context 'when `docker_service` is `my-docker`' do - let(:params) { {'command' => 'command', 'image' => 'base', 'docker_service' => 'my-docker'} } - let(:pre_condition) { - [ "service { 'my-docker': }", - "class { 'docker': docker_group => 'docker', service_name => 'docker' }" ] } + let(:params) { params.merge({'docker_service' => 'my-docker'}) } + let(:pre_condition) { ["service { 'my-docker': provider => systemd }", pre_condition] } it { should compile.with_all_deps } it { should contain_service('my-docker').that_comes_before('Service[docker-sample]') } it { should contain_service('my-docker').that_notifies('Service[docker-sample]') } end context 'when `docker_service` is `my-docker` and `restart_service_on_docker_refresh` is false' do - let(:params) { {'command' => 'command', 'image' => 'base', 'docker_service' => 'my-docker', 'restart_service_on_docker_refresh' => false} } - let(:pre_condition) { - [ "service { 'my-docker': }", - "class { 'docker': docker_group => 'docker', service_name => 'docker' }" ] } + let(:params) { params.merge({'docker_service' => 'my-docker', 'restart_service_on_docker_refresh' => false}) } + let(:pre_condition) { ["service { 'my-docker': provider => systemd }", pre_condition] } it { should compile.with_all_deps } it { should contain_service('my-docker').that_comes_before('Service[docker-sample]') } end context 'with syslog_identifier' do - let(:params) { {'command' => 'command', 'image' => 'base', 'syslog_identifier' => 'docker-universe' } } + let(:params) { params.merge({'syslog_identifier' => 'docker-universe' }) } if systemd it { should contain_file(initscript).with_content(/^SyslogIdentifier=docker-universe$/) } end end context 'with extra_systemd_parameters' do - let(:params) { {'command' => 'command', 'image' => 'base', 'extra_systemd_parameters' => {'RestartSec' => 5}} } + let(:params) { params.merge({'extra_systemd_parameters' => {'RestartSec' => 5}}) } if (systemd) it { should contain_file(initscript).with_content(/^RestartSec=5$/) } end end context 'with ensure absent' do - let(:params) { {'ensure' => 'absent', 'command' => 'command', 'image' => 'base'} } + let(:params) { params.merge({'ensure' => 'absent'}) } it { should compile.with_all_deps } it { should contain_service('docker-sample').with_ensure(false) } it { should contain_exec("remove container docker-sample").with_command('docker rm -v sample') } it { should_not contain_file('docker-sample.service')} end end end end