# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'erb' require 'json' require 'shellwords' require 'tempfile' require 'uri' require 'kitchen' require 'kitchen/configurable' require_relative '../erb_context' require_relative 'cli_helper' module Kitchen module Docker module Helpers module ContainerHelper include Configurable include Kitchen::Docker::Helpers::CliHelper def parse_container_id(output) container_id = output.chomp unless [12, 64].include?(container_id.size) raise ActionFailed, 'Could not parse Docker run output for container ID' end container_id end def dockerfile_template template = IO.read(File.expand_path(config[:dockerfile])) context = Kitchen::Docker::ERBContext.new(config.to_hash) ERB.new(template).result(context.get_binding) end def remote_socket? config[:socket] ? socket_uri.scheme == 'tcp' : false end def socket_uri URI.parse(config[:socket]) end def dockerfile_path(file) config[:build_context] ? Pathname.new(file.path).relative_path_from(Pathname.pwd).to_s : file.path end def container_exists?(state) state[:container_id] && !!docker_command("top #{state[:container_id]}") rescue false end def container_exec(state, command) cmd = build_exec_command(state, command) docker_command(cmd) rescue => e raise "Failed to execute command on Docker container. #{e}" end def create_dir_on_container(state, path) path = replace_env_variables(state, path) cmd = "mkdir -p #{path}" if state[:platform].include?('windows') psh = "-Command if(-not (Test-Path \'#{path}\')) { New-Item -Path \'#{path}\' -Force }" cmd = build_powershell_command(psh) end cmd = build_exec_command(state, cmd) docker_command(cmd) rescue => e raise "Failed to create directory #{path} on container. #{e}" end def copy_file_to_container(state, local_file, remote_file) debug("Copying local file #{local_file} to #{remote_file} on container") remote_file = replace_env_variables(state, remote_file) remote_file = "#{state[:container_id]}:#{remote_file}" cmd = build_copy_command(local_file, remote_file) docker_command(cmd) rescue => e raise "Failed to copy file #{local_file} to container. #{e}" end def container_env_variables(state) # Retrieves all environment variables from inside container vars = {} if state[:platform].include?('windows') cmd = build_powershell_command('-Command [System.Environment]::GetEnvironmentVariables() ^| ConvertTo-Json') cmd = build_exec_command(state, cmd) stdout = docker_command(cmd, suppress_output: !logger.debug?).strip vars = ::JSON.parse(stdout) else cmd = build_exec_command(state, 'printenv') stdout = docker_command(cmd, suppress_output: !logger.debug?).strip stdout.split("\n").each { |line| vars[line.split('=')[0]] = line.split('=')[1] } end vars end def replace_env_variables(state, str) if str.include?('$env:') key = str[/\$env:(.*?)(\\|$)/, 1] value = container_env_variables(state)[key].to_s.strip str = str.gsub("$env:#{key}", value) elsif str.include?('$') key = str[/\$(.*?)(\/|$)/, 1] value = container_env_variables(state)[key].to_s.strip str = str.gsub("$#{key}", value) end str end def run_container(state, transport_port = nil) cmd = build_run_command(state[:image_id], transport_port) output = docker_command(cmd) parse_container_id(output) end def container_ip_address(state) cmd = "inspect --format '{{ .NetworkSettings.IPAddress }}'" cmd << " #{state[:container_id]}" docker_command(cmd).strip rescue raise ActionFailed, 'Error getting internal IP of Docker container' end def remove_container(state) container_id = state[:container_id] docker_command("stop -t 0 #{container_id}") docker_command("rm #{container_id}") end def dockerfile_proxy_config env_variables = '' if config[:http_proxy] env_variables << "ENV http_proxy #{config[:http_proxy]}\n" env_variables << "ENV HTTP_PROXY #{config[:http_proxy]}\n" end if config[:https_proxy] env_variables << "ENV https_proxy #{config[:https_proxy]}\n" env_variables << "ENV HTTPS_PROXY #{config[:https_proxy]}\n" end if config[:no_proxy] env_variables << "ENV no_proxy #{config[:no_proxy]}\n" env_variables << "ENV NO_PROXY #{config[:no_proxy]}\n" end env_variables end end end end end