Class: Vanagon::Engine::Docker
- Defined in:
- lib/vanagon/engine/docker.rb
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#build_host_name ⇒ Object
Return the docker image name to build on.
- #dispatch(command, return_output = false) ⇒ Object
-
#docker_cp(source, target) ⇒ Object
Copy files between a container and the host.
-
#docker_cp_globs_from(globs, host_path) ⇒ Object
Copy files matching a glob pattern from the container to the host.
-
#docker_cp_globs_to(globs, container_path) ⇒ Object
Copy files matching a glob pattern from the host to the container.
-
#docker_exec(command, return_output = false) ⇒ Object
Execute a command on a container via docker exec.
-
#initialize(platform, target = nil, **opts) ⇒ Docker
constructor
Both the docker_image and the docker command itself are required for the docker engine to work.
-
#name ⇒ Object
Get the engine name.
- #retrieve_built_artifact(artifacts_to_fetch, no_packaging) ⇒ Object
-
#select_target ⇒ Object
This method is used to obtain a vm to build upon using a docker container.
- #ship_workdir(workdir) ⇒ Object
-
#teardown ⇒ Object
This method is used to tell the vmpooler to delete the instance of the vm that was being used so the pool can be replenished.
-
#wait_for_ssh ⇒ void
Wait for ssh to come up in the container.
Methods inherited from Base
#get_remote_workdir, #parse_target_defaults, #setup, #startup, #validate_platform
Constructor Details
#initialize(platform, target = nil, **opts) ⇒ Docker
Both the docker_image and the docker command itself are required for the docker engine to work
9 10 11 12 13 14 15 |
# File 'lib/vanagon/engine/docker.rb', line 9 def initialize(platform, target = nil, **opts) super @docker_cmd = Vanagon::Utilities.find_program_on_path('docker') @required_attributes << "docker_image" @required_attributes.delete('ssh_port') if @platform.use_docker_exec end |
Instance Method Details
#build_host_name ⇒ Object
Return the docker image name to build on
23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/vanagon/engine/docker.rb', line 23 def build_host_name if @build_host_name.nil? validate_platform # Docker requires container names to match: [a-zA-Z0-9][a-zA-Z0-9_.-] # So, transform slashes and colons commonly used as separators in # image names. @build_host_name = @platform.docker_image.gsub(%r{[/:]}, '_') end @build_host_name end |
#dispatch(command, return_output = false) ⇒ Object
59 60 61 62 63 64 65 |
# File 'lib/vanagon/engine/docker.rb', line 59 def dispatch(command, return_output = false) if @platform.use_docker_exec docker_exec(command, return_output) else super end end |
#docker_cp(source, target) ⇒ Object
Copy files between a container and the host
97 98 99 |
# File 'lib/vanagon/engine/docker.rb', line 97 def docker_cp(source, target) Vanagon::Utilities.ex("#{@docker_cmd} cp '#{source}' '#{target}'") end |
#docker_cp_globs_from(globs, host_path) ⇒ Object
Globs are expanded by running ‘/bin/sh` in the container, which may not support the same variety of expressions as Ruby’s ‘Dir.glob`. For example, `**` may not work.
Copy files matching a glob pattern from the container to the host
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/vanagon/engine/docker.rb', line 115 def docker_cp_globs_from(globs, host_path) Array(globs).each do |glob| # Match the behavior of `rsync -r` when both paths are directories # by copying the contents of the directory instead of the directory. glob += '*' if glob.end_with?('/') && host_path.end_with?('/') # TODO: This doesn't handle "interesting" paths. E.g. paths with # spaces or other special non-glob characters. This could be # fixed with a variant of `Shellwords.shellescape` that allows # glob characters to pass through. paths = docker_exec(%(for file in #{glob};do [ -e "$file" ] && printf '%s\\0' "${file}";done), true).split("\0") paths.each do |path| docker_cp("#{build_host_name}-builder:#{path}", host_path) end end end |
#docker_cp_globs_to(globs, container_path) ⇒ Object
Copy files matching a glob pattern from the host to the container
102 103 104 105 106 107 108 |
# File 'lib/vanagon/engine/docker.rb', line 102 def docker_cp_globs_to(globs, container_path) Array(globs).each do |glob| Dir.glob(glob).each do |path| docker_cp(path, "#{build_host_name}-builder:#{container_path}") end end end |
#docker_exec(command, return_output = false) ⇒ Object
Execute a command on a container via docker exec
90 91 92 93 94 |
# File 'lib/vanagon/engine/docker.rb', line 90 def docker_exec(command, return_output = false) command = command.gsub("'", "'\\\\''") Vanagon::Utilities.local_command("#{@docker_cmd} exec #{build_host_name}-builder /bin/sh -c '#{command}'", return_command_output: return_output) end |
#name ⇒ Object
Get the engine name
18 19 20 |
# File 'lib/vanagon/engine/docker.rb', line 18 def name 'docker' end |
#retrieve_built_artifact(artifacts_to_fetch, no_packaging) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/vanagon/engine/docker.rb', line 75 def retrieve_built_artifact(artifacts_to_fetch, no_packaging) if @platform.use_docker_exec output_path = 'output/' FileUtils.mkdir_p(output_path) unless no_packaging artifacts_to_fetch << "#{@remote_workdir}/output/*" end docker_cp_globs_from(artifacts_to_fetch, 'output/') else super end end |
#select_target ⇒ Object
This method is used to obtain a vm to build upon using a docker container.
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/vanagon/engine/docker.rb', line 38 def select_target ssh_args = @platform.use_docker_exec ? '' : "-p #{@target_port}:22" extra_args = @platform.docker_run_args.nil? ? [] : @platform.docker_run_args Vanagon::Utilities.ex("#{@docker_cmd} run -d --name #{build_host_name}-builder #{ssh_args} #{extra_args.join(' ')} #{@platform.docker_image}") @target = URI.new('localhost') wait_for_ssh unless @platform.use_docker_exec rescue StandardError => e raise Vanagon::Error.wrap(e, "Something went wrong getting a target vm to build on using Docker.") end |
#ship_workdir(workdir) ⇒ Object
67 68 69 70 71 72 73 |
# File 'lib/vanagon/engine/docker.rb', line 67 def ship_workdir(workdir) if @platform.use_docker_exec docker_cp_globs_to("#{workdir}/*", @remote_workdir) else super end end |
#teardown ⇒ Object
This method is used to tell the vmpooler to delete the instance of the vm that was being used so the pool can be replenished.
52 53 54 55 56 57 |
# File 'lib/vanagon/engine/docker.rb', line 52 def teardown Vanagon::Utilities.ex("#{@docker_cmd} stop #{build_host_name}-builder") Vanagon::Utilities.ex("#{@docker_cmd} rm #{build_host_name}-builder") rescue Vanagon::Error => e VanagonLogger.error "There was a problem tearing down the docker container #{build_host_name}-builder (#{e.})." end |
#wait_for_ssh ⇒ void
This method returns an undefined value.
Wait for ssh to come up in the container
Retry 5 times with a 1 second sleep between errors to account for network resets while SSHD is starting. Allow a maximum of 5 seconds for SSHD to start.
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/vanagon/engine/docker.rb', line 141 def wait_for_ssh Vanagon::Utilities.retry_with_timeout(5, 5) do begin Vanagon::Utilities.remote_ssh_command("#{@target_user}@#{@target}", 'exit', @target_port) rescue StandardError => e sleep(1) # Give SSHD some time to start. raise e end end rescue StandardError => e raise Vanagon::Error.wrap(e, "SSH was not up in the container after 5 seconds.") end |