lib/kitchen/docker/helpers/container_helper.rb in kitchen-docker-2.15.0 vs lib/kitchen/docker/helpers/container_helper.rb in kitchen-docker-3.0.0

- old
+ new

@@ -1,172 +1,176 @@ -# -# 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 +# +# 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 + # rubocop:disable Metrics/ModuleLength, Style/Documentation + 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 + + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + 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 + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + + 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 + # rubocop:enable Metrics/ModuleLength, Style/Documentation + end + end +end