lib/kitchen/driver/docker.rb in kitchen-docker-2.4.0 vs lib/kitchen/driver/docker.rb in kitchen-docker-2.5.0

- old
+ new

@@ -17,10 +17,12 @@ require 'kitchen' require 'json' require 'securerandom' require 'uri' require 'net/ssh' +require 'tempfile' +require 'shellwords' require File.join(File.dirname(__FILE__), 'docker', 'erb') module Kitchen module Driver @@ -49,10 +51,12 @@ default_config :tls_key, nil default_config :publish_all, false default_config :wait_for_sshd, true default_config :private_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa') default_config :public_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa.pub') + default_config :build_options, nil + default_config :run_options, nil default_config :use_sudo do |driver| !driver.remote_socket? end @@ -194,15 +198,19 @@ RUN yum install -y sudo openssh-server openssh-clients which curl RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' eos when 'arch' + # See https://bugs.archlinux.org/task/47052 for why we + # blank out limits.conf. <<-eos - RUN pacman -Syu --noconfirm - RUN pacman -S --noconfirm openssh sudo curl + RUN pacman --noconfirm -Sy archlinux-keyring + RUN pacman-db-upgrade + RUN pacman --noconfirm -Sy openssl openssh sudo curl RUN ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key RUN ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key + RUN echo >/etc/security/limits.conf eos when 'gentoo' <<-eos RUN emerge sync RUN emerge net-misc/openssh app-admin/sudo @@ -229,14 +237,12 @@ base = <<-eos RUN if ! getent passwd #{username}; then \ useradd -d #{homedir} -m -s /bin/bash #{username}; \ fi RUN echo #{username}:#{password} | chpasswd - RUN echo '#{username} ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers - RUN mkdir -p /etc/sudoers.d - RUN echo '#{username} ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/#{username} - RUN chmod 0440 /etc/sudoers.d/#{username} + RUN echo "#{username} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + RUN echo "Defaults !requiretty" >> /etc/sudoers RUN mkdir -p #{homedir}/.ssh RUN chown -R #{username} #{homedir}/.ssh RUN chmod 0700 #{homedir}/.ssh RUN touch #{homedir}/.ssh/authorized_keys RUN chown #{username} #{homedir}/.ssh/authorized_keys @@ -244,11 +250,11 @@ eos custom = '' Array(config[:provision_command]).each do |cmd| custom << "RUN #{cmd}\n" end - ssh_key = "RUN echo '#{public_key}' >> #{homedir}/.ssh/authorized_keys" + ssh_key = "RUN echo #{Shellwords.escape(public_key)} >> #{homedir}/.ssh/authorized_keys" # Empty string to ensure the file ends with a newline. [from, env_variables, platform, base, custom, ssh_key, ''].join("\n") end def dockerfile @@ -266,23 +272,25 @@ if line =~ /image id|build successful|successfully built/i return line.split(/\s+/).last end end raise ActionFailed, - 'Could not parse Docker build output for image ID' + 'Could not parse Docker build output for image ID' end def build_image(state) cmd = "build" cmd << " --no-cache" unless config[:use_cache] + extra_build_options = config_to_options(config[:build_options]) + cmd << " #{extra_build_options}" unless extra_build_options.empty? dockerfile_contents = dockerfile build_context = config[:build_context] ? '.' : '-' file = Tempfile.new('Dockerfile-kitchen', Dir.pwd) output = begin file.write(dockerfile) file.close - docker_command("#{cmd} -f #{file.path} #{build_context}", :input => dockerfile_contents) + docker_command("#{cmd} -f #{Shellwords.escape(file.path)} #{build_context}", :input => dockerfile_contents) ensure file.close unless file.closed? file.unlink end parse_image_id(output) @@ -315,10 +323,12 @@ cmd << " -e https_proxy=#{config[:https_proxy]}" if config[:https_proxy] cmd << " --privileged" if config[:privileged] Array(config[:cap_add]).each {|cap| cmd << " --cap-add=#{cap}"} if config[:cap_add] Array(config[:cap_drop]).each {|cap| cmd << " --cap-drop=#{cap}"} if config[:cap_drop] Array(config[:security_opt]).each {|opt| cmd << " --security-opt=#{opt}"} if config[:security_opt] + extra_run_options = config_to_options(config[:run_options]) + cmd << " #{extra_run_options}" unless extra_run_options.empty? cmd << " #{image_id} #{config[:run_command]}" cmd end def run_container(state) @@ -331,15 +341,15 @@ state[:container_id] && !!docker_command("top #{state[:container_id]}") rescue false end def parse_container_ssh_port(output) begin - host, port = output.split(':') + _host, port = output.split(':') port.to_i rescue raise ActionFailed, - 'Could not parse Docker port output for container SSH port' + 'Could not parse Docker port output for container SSH port' end end def container_ssh_port(state) begin @@ -359,8 +369,28 @@ def rm_image(state) image_id = state[:image_id] docker_command("rmi #{image_id}") end + + # Convert the config input for `:build_options` or `:run_options` in to a + # command line string for use with Docker. + # + # @since 2.5.0 + # @param config [nil, String, Array, Hash] Config data to convert. + # @return [String] + def config_to_options(config) + case config + when nil + '' + when String + config + when Array + config.map {|c| config_to_options(c) }.join(' ') + when Hash + config.map {|k, v| Array(v).map {|c| "--#{k}=#{Shellwords.escape(c)}" }.join(' ') }.join(' ') + end + end + end end end