diff --git a/lib/puppet/provider/docker_compose/ruby.rb b/lib/puppet/provider/docker_compose/ruby.rb index e9bb360..bfcca81 100644 --- a/lib/puppet/provider/docker_compose/ruby.rb +++ b/lib/puppet/provider/docker_compose/ruby.rb @@ -1,106 +1,106 @@ # frozen_string_literal: true require 'deep_merge' Puppet::Type.type(:docker_compose).provide(:ruby) do desc 'Support for Puppet running Docker Compose' mk_resource_methods commands dockercompose: 'docker-compose' commands dockercmd: 'docker' has_command(:docker, command(:dockercmd)) do - environment(HOME: '/var/tmp') + environment(HOME: '/root') end def exists? Puppet.info("Checking for compose project #{name}") compose_services = {} compose_containers = [] # get merged config using docker-compose config args = [compose_files, '-p', name, 'config'].insert(3, resource[:options]).compact compose_output = YAML.safe_load(execute([command(:dockercompose)] + args, combine: false)) # rubocop:disable Style/StringLiterals containers = docker([ 'ps', '--format', "{{.Label \"com.docker.compose.service\"}}-{{.Image}}", '--filter', "label=com.docker.compose.project=#{name}", ]).split("\n") compose_containers.push(*containers) compose_containers.uniq! compose_services = compose_output['services'] if compose_services.count != compose_containers.count return false end counts = Hash[*compose_services.each.map { |key, array| image = (array['image']) ? array['image'] : get_image(key, compose_services) Puppet.info("Checking for compose service #{key} #{image}") ["#{key}-#{image}", compose_containers.count("#{key}-#{image}")] }.flatten] # No containers found for the project if counts.empty? || # Containers described in the compose file are not running counts.any? { |_k, v| v.zero? } || # The scaling factors in the resource do not match the number of running containers resource[:scale] && counts.merge(resource[:scale]) != counts false else true end end def get_image(service_name, compose_services) image = compose_services[service_name]['image'] unless image if compose_services[service_name]['extends'] image = get_image(compose_services[service_name]['extends'], compose_services) elsif compose_services[service_name]['build'] image = "#{name}_#{service_name}" end end image end def create Puppet.info("Running compose project #{name}") args = [compose_files, '-p', name, 'up', '-d', '--remove-orphans'].insert(3, resource[:options]).insert(5, resource[:up_args]).compact dockercompose(args) return unless resource[:scale] instructions = resource[:scale].map { |k, v| "#{k}=#{v}" } Puppet.info("Scaling compose project #{name}: #{instructions.join(' ')}") args = [compose_files, '-p', name, 'scale'].insert(3, resource[:options]).compact + instructions dockercompose(args) end def destroy Puppet.info("Removing all containers for compose project #{name}") kill_args = [compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact dockercompose(kill_args) rm_args = [compose_files, '-p', name, 'rm', '--force', '-v'].insert(3, resource[:options]).compact dockercompose(rm_args) end def restart return unless exists? Puppet.info("Rebuilding and Restarting all containers for compose project #{name}") kill_args = [compose_files, '-p', name, 'kill'].insert(3, resource[:options]).compact dockercompose(kill_args) build_args = [compose_files, '-p', name, 'build'].insert(3, resource[:options]).compact dockercompose(build_args) create end def compose_files resource[:compose_files].map { |x| ['-f', x] }.flatten end private end diff --git a/lib/puppet/provider/docker_network/ruby.rb b/lib/puppet/provider/docker_network/ruby.rb index 7b4d8d5..4a8cbd7 100644 --- a/lib/puppet/provider/docker_network/ruby.rb +++ b/lib/puppet/provider/docker_network/ruby.rb @@ -1,104 +1,104 @@ # frozen_string_literal: true require 'json' Puppet::Type.type(:docker_network).provide(:ruby) do desc 'Support for Docker Networking' mk_resource_methods commands dockercmd: 'docker' has_command(:docker, command(:dockercmd)) do - environment(HOME: '/var/tmp') + environment(HOME: '/root') end def network_conf flags = ['network', 'create'] multi_flags = ->(values, format) { filtered = [values].flatten.compact filtered.map { |val| format % val } } [ ['--driver=%s', :driver], ['--subnet=%s', :subnet], ['--gateway=%s', :gateway], ['--ip-range=%s', :ip_range], ['--ipam-driver=%s', :ipam_driver], ['--aux-address=%s', :aux_address], ['--opt=%s', :options], ].each do |(format, key)| values = resource[key] new_flags = multi_flags.call(values, format) flags.concat(new_flags) end if defined?(resource[:additional_flags]) additional_flags = [] if resource[:additional_flags].is_a?(String) additional_flags = resource[:additional_flags].split elsif resource[:additional_flags].is_a?(Array) additional_flags = resource[:additional_flags] end additional_flags.each do |additional_flag| flags << additional_flag end end flags << resource[:name] end def self.instances output = docker(['network', 'ls']) lines = output.split("\n") lines.shift # remove header row lines.map do |line| _, name, driver = line.split(' ') inspect = docker(['network', 'inspect', name]) obj = JSON.parse(inspect).first ipam_driver = unless obj['IPAM']['Driver'].nil? obj['IPAM']['Driver'] end subnet = unless obj['IPAM']['Config'].nil? || obj['IPAM']['Config'].empty? if obj['IPAM']['Config'].first.key? 'Subnet' obj['IPAM']['Config'].first['Subnet'] end end new( name: name, id: obj['Id'], ipam_driver: ipam_driver, subnet: subnet, ensure: :present, driver: driver, ) end end def self.prefetch(resources) instances.each do |prov| if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition resource.provider = prov end end end def flush raise Puppet::Error, _('Docker network does not support mutating existing networks') if !@property_hash.empty? && @property_hash[:ensure] != :absent end def exists? Puppet.info("Checking if docker network #{name} exists") @property_hash[:ensure] == :present end def create Puppet.info("Creating docker network #{name}") docker(network_conf) end def destroy Puppet.info("Removing docker network #{name}") docker(['network', 'rm', name]) end end diff --git a/lib/puppet/provider/docker_stack/ruby.rb b/lib/puppet/provider/docker_stack/ruby.rb index 7678947..b1fc55d 100644 --- a/lib/puppet/provider/docker_stack/ruby.rb +++ b/lib/puppet/provider/docker_stack/ruby.rb @@ -1,94 +1,94 @@ # frozen_string_literal: true require 'deep_merge' Puppet::Type.type(:docker_stack).provide(:ruby) do desc 'Support for Puppet running Docker Stacks' mk_resource_methods commands dockercmd: 'docker' has_command(:docker, command(:dockercmd)) do - environment(HOME: '/var/tmp') + environment(HOME: '/root') end def exists? Puppet.info("Checking for stack #{name}") stack_services = {} stack_containers = [] resource[:compose_files].each do |file| compose_file = YAML.safe_load(File.read(file), [], [], true) # rubocop:disable Style/StringLiterals containers = docker([ 'ps', '--format', "{{.Label \"com.docker.swarm.service.name\"}}-{{.Image}}", '--filter', "label=com.docker.stack.namespace=#{name}", ]).split("\n").each do |c| c.slice!("#{name}_") end stack_containers.push(*containers) stack_containers.uniq! # rubocop:enable Style/StringLiterals case compose_file['version'] when %r{^3(\.[0-7])?$} stack_services.merge!(compose_file['services']) else raise(Puppet::Error, "Unsupported docker compose file syntax version \"#{compose_file['version']}\"!") end end if stack_services.count != stack_containers.count return false end counts = Hash[*stack_services.each.map { |key, array| image = (array['image']) ? array['image'] : get_image(key, stack_services) image = "#{image}:latest" unless image.include?(':') Puppet.info("Checking for compose service #{key} #{image}") ["#{key}-#{image}", stack_containers.count("#{key}-#{image}")] }.flatten] # No containers found for the project if counts.empty? || # Containers described in the compose file are not running counts.any? { |_k, v| v.zero? } false else true end end def get_image(service_name, stack_services) image = stack_services[service_name]['image'] unless image if stack_services[service_name]['extends'] image = get_image(stack_services[service_name]['extends'], stack_services) elsif stack_services[service_name]['build'] image = "#{name}_#{service_name}" end end image end def create Puppet.info("Running stack #{name}") args = ['stack', 'deploy', compose_files, name].insert(1, bundle_file).insert(4, resource[:up_args]).compact docker(args) end def destroy Puppet.info("Removing docker stack #{name}") rm_args = ['stack', 'rm', name] docker(rm_args) end def bundle_file return resource[:bundle_file].map { |x| ['-c', x] }.flatten unless resource[:bundle_file].nil? end def compose_files resource[:compose_files].map { |x| ['-c', x] }.flatten end private end diff --git a/lib/puppet/provider/docker_volume/ruby.rb b/lib/puppet/provider/docker_volume/ruby.rb index 25028d8..6c04dc9 100644 --- a/lib/puppet/provider/docker_volume/ruby.rb +++ b/lib/puppet/provider/docker_volume/ruby.rb @@ -1,73 +1,73 @@ # frozen_string_literal: true require 'json' Puppet::Type.type(:docker_volume).provide(:ruby) do desc 'Support for Docker Volumes' mk_resource_methods commands dockercmd: 'docker' has_command(:docker, command(:dockercmd)) do - environment(HOME: '/var/tmp') + environment(HOME: '/root') end def volume_conf flags = ['volume', 'create'] multi_flags = ->(values, format) { filtered = [values].flatten.compact filtered.map { |val| format % val } } [ ['--driver=%s', :driver], ['--opt=%s', :options], ].each do |(format, key)| values = resource[key] new_flags = multi_flags.call(values, format) flags.concat(new_flags) end flags << resource[:name] end def self.instances output = docker(['volume', 'ls']) lines = output.split("\n") lines.shift # remove header row lines.map do |line| driver, name = line.split(' ') inspect = docker(['volume', 'inspect', name]) obj = JSON.parse(inspect).first new( name: name, mountpoint: obj['Mountpoint'], options: obj['Options'], ensure: :present, driver: driver, ) end end def self.prefetch(resources) instances.each do |prov| if (resource = resources[prov.name]) resource.provider = prov end end end def exists? Puppet.info("Checking if docker volume #{name} exists") @property_hash[:ensure] == :present end def create Puppet.info("Creating docker volume #{name}") docker(volume_conf) end def destroy Puppet.info("Removing docker volume #{name}") docker(['volume', 'rm', name]) end end