Class: Chef::Provisioning::DockerDriver::DockerTransport
- Inherits:
-
Transport
- Object
- Transport
- Chef::Provisioning::DockerDriver::DockerTransport
- Includes:
- Mixin::ShellOut
- Defined in:
- lib/chef/provisioning/docker_driver/docker_transport.rb
Defined Under Namespace
Classes: DockerResult
Instance Attribute Summary collapse
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
-
#container_name ⇒ Object
readonly
Returns the value of attribute container_name.
-
#credentials ⇒ Object
readonly
Returns the value of attribute credentials.
-
#image ⇒ Object
readonly
Returns the value of attribute image.
-
#repository_name ⇒ Object
readonly
Returns the value of attribute repository_name.
-
#tunnel_transport ⇒ Object
readonly
Returns the value of attribute tunnel_transport.
Instance Method Summary collapse
- #available? ⇒ Boolean
- #disconnect ⇒ Object
- #download_file(path, local_path) ⇒ Object
-
#execute(command, options = {}) ⇒ Object
Execute the specified command inside the container, returns a Mixlib::Shellout object Options contains the optional keys: :env => env vars :read_only => Do not commit this execute operation, just execute it :ports => ports to listen on (-p command-line options) :detached => true/false, execute this command in detached mode (for final program to run).
-
#initialize(container_name, base_image_name, credentials, connection, tunnel_transport = nil) ⇒ DockerTransport
constructor
A new instance of DockerTransport.
- #make_url_available_to_remote(url) ⇒ Object
- #read_file(path) ⇒ Object
- #upload_file(local_path, path) ⇒ Object
- #write_file(path, content) ⇒ Object
Constructor Details
#initialize(container_name, base_image_name, credentials, connection, tunnel_transport = nil) ⇒ DockerTransport
Returns a new instance of DockerTransport.
15 16 17 18 19 20 21 22 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 15 def initialize(container_name, base_image_name, credentials, connection, tunnel_transport = nil) @repository_name = 'chef' @container_name = container_name @image = Docker::Image.get(base_image_name, connection) @credentials = credentials @connection = connection @tunnel_transport = tunnel_transport end |
Instance Attribute Details
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
30 31 32 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 30 def connection @connection end |
#container_name ⇒ Object (readonly)
Returns the value of attribute container_name.
26 27 28 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 26 def container_name @container_name end |
#credentials ⇒ Object (readonly)
Returns the value of attribute credentials.
29 30 31 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 29 def credentials @credentials end |
#image ⇒ Object (readonly)
Returns the value of attribute image.
28 29 30 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 28 def image @image end |
#repository_name ⇒ Object (readonly)
Returns the value of attribute repository_name.
27 28 29 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 27 def repository_name @repository_name end |
#tunnel_transport ⇒ Object (readonly)
Returns the value of attribute tunnel_transport.
31 32 33 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 31 def tunnel_transport @tunnel_transport end |
Instance Method Details
#available? ⇒ Boolean
214 215 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 214 def available? end |
#disconnect ⇒ Object
210 211 212 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 210 def disconnect @proxy_thread.kill if @proxy_thread end |
#download_file(path, local_path) ⇒ Object
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 157 def download_file(path, local_path) # TODO stream file = File.open(local_path, 'w') begin file.write(read_file(path)) file.close rescue File.delete(file) end end |
#execute(command, options = {}) ⇒ Object
Execute the specified command inside the container, returns a Mixlib::Shellout object Options contains the optional keys:
:env => env vars
:read_only => Do not commit this execute operation, just execute it
:ports => ports to listen on (-p command-line options)
:detached => true/false, execute this command in detached mode (for final program to run)
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 39 def execute(command, ={}) Chef::Log.debug("execute '#{command}' with options #{}") begin connection.post("/containers/#{container_name}/stop?t=0", '') Chef::Log.debug("stopped /containers/#{container_name}") rescue Excon::Errors::NotModified Chef::Log.debug("Already stopped #{container_name}") rescue Docker::Error::NotFoundError end begin # Delete the container if it exists and is dormant connection.delete("/containers/#{container_name}?v=true&force=true") Chef::Log.debug("deleted /containers/#{container_name}") rescue Docker::Error::NotFoundError end command = Shellwords.split(command) if command.is_a?(String) # TODO shell_out has no way to live stream stderr??? live_stream = nil live_stream = STDOUT if [:stream] live_stream = [:stream_stdout] if [:stream_stdout] args = ['docker', 'run', '--name', container_name] if [:env] [:env].each do |key, value| args << '-e' args << "#{key}=#{value}" end end if [:detached] args << '--detach' end if [:ports] [:ports].each do |portnum| args << '-p' args << "#{portnum}" end end if [:keep_stdin_open] args << '-i' end args << @image.id args += command cmdstr = Shellwords.join(args) Chef::Log.debug("Executing #{cmdstr}") # Remove this when https://github.com/opscode/chef/pull/2100 gets merged and released # nullify live_stream because at the moment EventsOutputStream doesn't understand <<, which # ShellOut uses live_stream = nil unless live_stream.respond_to? :<< cmd = Mixlib::ShellOut.new(cmdstr, :live_stream => live_stream, :timeout => execute_timeout()) cmd.run_command unless [:read_only] Chef::Log.debug("Committing #{container_name} as #{repository_name}:#{container_name}") container = Docker::Container.get(container_name) @image = container.commit('repo' => repository_name, 'tag' => container_name) end Chef::Log.debug("Execute complete: status #{cmd.exitstatus}") cmd end |
#make_url_available_to_remote(url) ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 172 def make_url_available_to_remote(url) # The host is already open to the container. Just find out its address and return it! uri = URI(url) host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3] Chef::Log.debug("Making URL available: #{host}") if host == '127.0.0.1' || host == '[::1]' result = execute('ip route ls', :read_only => true) Chef::Log.debug("IP route: #{result.stdout}") if result.stdout =~ /default via (\S+)/ uri.host = if using_boot2docker? # Intermediate VM does NAT, so local address should be fine here Chef::Log.debug("Using boot2docker!") IPSocket.getaddress(Socket.gethostname) else $1 end if !@proxy_thread # Listen to docker instances only, and forward to localhost @proxy_thread = Thread.new do Chef::Log.debug("Starting proxy thread: #{uri.host}:#{uri.port} <--> #{host}:#{uri.port}") ChefZeroHttpProxy.new(uri.host, uri.port, host, uri.port).run end end Chef::Log.debug("Using Chef server URL: #{uri.to_s}") return uri.to_s else raise "Cannot forward port: ip route ls did not show default in expected format.\nSTDOUT: #{result.stdout}" end end url end |
#read_file(path) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 114 def read_file(path) container = Docker::Container.create({ 'Image' => @image.id, 'Cmd' => %w(echo true) }, connection) begin tarfile = '' # NOTE: this would be more efficient if we made it a stream and passed that to Minitar container.copy(path) do |block| tarfile << block end rescue Docker::Error::ServerError if $!. =~ /500/ || $!. =~ /Could not find the file/ return nil else raise end ensure container.delete end output = '' Archive::Tar::Minitar::Input.open(StringIO.new(tarfile)) do |inp| inp.each do |entry| while next_output = entry.read output << next_output end entry.close end end output end |
#upload_file(local_path, path) ⇒ Object
168 169 170 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 168 def upload_file(local_path, path) @image = @image.insert_local('localPath' => local_path, 'outputPath' => path, 't' => "#{repository_name}:#{container_name}") end |
#write_file(path, content) ⇒ Object
148 149 150 151 152 153 154 155 |
# File 'lib/chef/provisioning/docker_driver/docker_transport.rb', line 148 def write_file(path, content) # TODO hate tempfiles. Find an in memory way. Tempfile.open('metal_docker_write_file') do |file| file.write(content) file.close @image = @image.insert_local('localPath' => file.path, 'outputPath' => path, 't' => "#{repository_name}:#{container_name}") end end |