lib/jarl/docker.rb in jarl-0.7.0 vs lib/jarl/docker.rb in jarl-0.8.1

- old
+ new

@@ -62,13 +62,21 @@ Container.new id end @docker_containers_running end + # Returns `docker ps` info inspector instance + # + def self.ps + @docker_ps ||= Ps.new + end + + # Reloads lists of images and containers # def self.reload! + @docker_ps = nil @docker_images = nil @docker_images_used = nil @docker_containers_running = nil end @@ -132,10 +140,56 @@ " --name #{container_name} #{params[:image]} #{params[:command]}" # puts docker_cmd sh docker_cmd end + # `docker ps` info inspector + # + class Ps + FIELDS = [ + 'CONTAINER ID', 'IMAGE', 'COMMAND', 'CREATED', 'STATUS', 'PORTS', 'NAMES' + ] + + attr_reader :entries + + def initialize + lines = `docker ps`.split("\n") + @headers = lines.shift + @data = lines + @entries = lines.map do |line| + FIELDS.map { |name| [name, field(line, name)] }.to_h + end + end + + def field_i_start(name) + i_start = @headers.index(name) + fail "Failed to find the field #{name} in docker ps" unless i_start + i_start + end + + # @return [nil,Integer] right index for field or -1 if the field is rightmost + # + def field_i_end(name) + i_start = field_i_start(name) + r_headers = @headers[i_start..-1].sub(/^#{name}/, '') + m = r_headers.match(/^(\s+)/) + m ? i_start + name.size + m[1].size - 1 : -1 + end + + def field_i_range(name) + field_i_start(name)..field_i_end(name) + end + + def field(line, name) + line[field_i_range(name)].strip + end + + def [](id) + entries.find { |e| id == e['CONTAINER ID'] } + end + end + # Image # class Image attr_accessor :name, :path @@ -203,28 +257,58 @@ end # class Image # Container # class Container - attr_accessor :id, :long_id, :name, :image, :image_id, :ip, :ps, :ports, :params + attr_accessor :id def initialize(id) @id = id - @ps = `docker ps | grep #{id}` - container_inspect = `docker inspect #{id}` - @params = JSON.parse(container_inspect).first - @long_id = params['Id'] - @name = params['Name'].gsub('/', '') - @image = params['Config']['Image'] - @image_id = params['Image'] - @ip = params['NetworkSettings']['IPAddress'] - port_maps = params['NetworkSettings']['Ports'] - @ports = port_maps.keys.map do |port| + end + + def ps + Docker.ps[id] or fail "Failed to find ps info for #{id}" + end + + def container_inspect + return @container_inspect if @container_inspect + # puts "Loading inspect for: #{ps}" + @container_inspect ||= JSON.parse(`docker inspect #{id}`).first + end + + def long_id + container_inspect['Id'] + end + + def name + ps['NAMES'] + # container_inspect['Name'].gsub('/', '') + end + + def image + container_inspect['Config']['Image'] + end + + def image_id + container_inspect['Image'] + end + + def ip + container_inspect['NetworkSettings']['IPAddress'] + end + + def ports + port_maps = container_inspect['NetworkSettings']['Ports'] + port_maps.keys.map do |port| { from: port, to: port_maps[port] } end end + def volumes + container_inspect['Volumes'] + end + def open_ssh_session!(params = {}, command = nil) ssh_flags = ['-oStrictHostKeyChecking=no'] if params['ssh_identity'] ssh_flags << "-i #{params['ssh_identity']}" if params['ssh_identity'].is_a?(String) if params['ssh_identity'].is_a?(Array) @@ -244,11 +328,11 @@ def clean! self.class.clean_containers(name) end def uptime - params['State'] && params['State']['StartedAt'] && - Time.now.utc - DateTime.parse(params['State']['StartedAt']).to_time.utc + container_inspect['State'] && container_inspect['State']['StartedAt'] && + Time.now.utc - DateTime.parse(container_inspect['State']['StartedAt']).to_time.utc end def self.clean_containers(*names) names.each do |name| begin