jarl 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5236af50f9ae03530ad885c513aa7f2cab5ec001
4
- data.tar.gz: c054de648fe8d3d61af434f4c7eae774ed9513b9
3
+ metadata.gz: 83b74b296a0d7b717781e0e95afc0229fccf6806
4
+ data.tar.gz: ad1000a7b31104b2f4c89850acec71e59cd52a12
5
5
  SHA512:
6
- metadata.gz: 96e8031a848011187b457d2e2eb0399df81ae93395f418014c243937073f380b7eeb497f7e94a80fc9426fbfb724e7607ef4a34f7dfe288c50dbf12fcb6a41bf
7
- data.tar.gz: 1a125e6dab7a71f8300e63f37ac496421949e0f97dab6df46c381680cf3c9fcb086c359addff5cd8d89a80d7366d00ee7b7410ecaf62304d13eda999885cfbbf
6
+ metadata.gz: 40284867d9621630fa84494ede01af179a92474c61ac1fe723358a55c0115848a056cbba18bc41fc5aa1a3ceb308f48e3219add98ba5695798fe9fc9e80816b1
7
+ data.tar.gz: f4d2e5ae060dbcfff10601956dac755c706972d3099009017aa78acd762ffb6d28493225a32812d0d05480dc7cb6c240198a526b1a2d29d410dd466289d33b0b
@@ -1,7 +1,7 @@
1
1
  module Jarl
2
2
  class Application
3
3
  attr_reader :group, :name, :hostname, :base_path
4
- attr_reader :image, :volumes, :ports, :environment, :entrypoint, :command
4
+ attr_reader :image, :scale, :volumes, :ports, :environment, :entrypoint, :command
5
5
  attr_reader :serial
6
6
 
7
7
  # Create Application object from application definition:
@@ -22,6 +22,10 @@ module Jarl
22
22
  unless @image.is_a?(String)
23
23
  fail "Application '#{self}' has invalid 'image' definition, String is expected"
24
24
  end
25
+ @scale = params['scale'] || 1
26
+ unless @scale.is_a?(Integer) && @scale > 0
27
+ fail "Application '#{self}' has invalid 'scale' definition, Integer > 0 is expected"
28
+ end
25
29
  @volumes = params['volumes'] || []
26
30
  unless @volumes.is_a?(Array)
27
31
  fail "Application '#{self}' has invalid 'volumes' definition, Array is expected"
@@ -59,18 +63,42 @@ module Jarl
59
63
  end
60
64
 
61
65
  def running?
62
- instances.size > 0
66
+ instances.any?(&:running?)
63
67
  end
64
68
 
65
69
  def instances
66
- Docker.containers_running.select { |c| c.name =~ /^#{full_name}(\.\d+)?$/ }.map do |c|
67
- Instance.new(self, c)
70
+ running_instances + stopped_instances
71
+ end
72
+
73
+ def running_containers
74
+ @running_containers ||= Docker.containers_running.select do |c|
75
+ c.name =~ /^#{full_name}(\.\d+)?$/
68
76
  end
69
77
  end
70
78
 
71
- # Start +scale+ instances of the application
79
+ def running_instances
80
+ @running_instances ||= running_containers.map do |c|
81
+ n = c.name.sub(/^#{full_name}\.?/, '')
82
+ n = n.empty? ? nil : n.to_i
83
+ Instance.new(self, n, c)
84
+ end
85
+ end
86
+
87
+ def stopped_instances
88
+ return @stopped_instances if @stopped_instances
89
+ n_range = scale == 1 ? [nil] : (1..scale).to_a
90
+ @stopped_instances = n_range.reject do |n|
91
+ running_instances.map(&:n).include?(n)
92
+ end
93
+ @stopped_instances = @stopped_instances.map do |n|
94
+ Instance.new(self, n, nil)
95
+ end
96
+ @stopped_instances
97
+ end
98
+
99
+ # Start instances of the application
72
100
  #
73
- def start(scale = 1)
101
+ def start
74
102
  instances.map(&:stop!) if running?
75
103
  if scale > 1
76
104
  scale.times { |n| Instance.start(self, n + 1) }
@@ -129,35 +157,60 @@ module Jarl
129
157
  # Application::Instance represents a single running instance of the application
130
158
  #
131
159
  class Instance
132
- attr_reader :application, :container
133
- def initialize(application, container)
160
+ attr_reader :application, :n, :container
161
+
162
+ # @param application [Application]
163
+ # @param n [nil,Integer] Instance number, nil if an instance is the primary instance
164
+ # @param container [nil,Docker::Container] Running container, if present
165
+ #
166
+ def initialize(application, n, container)
134
167
  @application = application
168
+ @n = n
135
169
  @container = container
136
170
  end
137
171
 
172
+ def running?
173
+ !@container.nil?
174
+ end
175
+
176
+ def full_name
177
+ n ? "#{application.full_name}.#{n}" : application.full_name
178
+ end
179
+
180
+ def hostname
181
+ n ? "#{application.hostname}-#{n}" : application.hostname
182
+ end
183
+
138
184
  def stop!
185
+ return unless running?
139
186
  @container.stop!
140
187
  end
141
188
 
142
- def name
143
- @container.name
144
- end
189
+ def start!
190
+ return if running?
191
+ # puts esc_yellow("Starting #{application.name}.#{n}") if n
145
192
 
146
- def n
147
- suffix = @container.name.split('.').last
148
- suffix =~ /^\d+$/ ? suffix : nil
193
+ Docker.start(
194
+ name: full_name,
195
+ hostname: hostname,
196
+ image: application.image_name,
197
+ volumes: application.volumes,
198
+ ports: application.ports,
199
+ environment: application.environment,
200
+ command: application.command
201
+ )
149
202
  end
150
203
 
151
204
  def tail_log(*_args)
205
+ return unless running?
152
206
  color_code = Console::Colors::SEQUENCE[application.serial % Console::Colors::SEQUENCE.size]
153
207
  begin
154
- instance_no = n ? ".#{n}" : ''
155
208
  IO.popen "docker logs -f #{container.id}", 'r' do |p|
156
209
  str = '<<< STARTED >>>'
157
210
  while str
158
211
  str = p.gets
159
212
  str.split("\n").each do |s|
160
- puts "#{esc_color color_code, application.full_name}#{instance_no}: #{s}"
213
+ puts "#{esc_color color_code, full_name}: #{s}"
161
214
  end
162
215
  end
163
216
  end
@@ -167,20 +220,9 @@ module Jarl
167
220
  end
168
221
 
169
222
  def ssh(command = nil)
223
+ fail "Failed to open SSH, no running container for '#{full_name}'" unless running?
170
224
  container.open_ssh_session!(Jarl.config.params, command)
171
225
  end
172
-
173
- def self.start(application, n = nil)
174
- Docker.start(
175
- name: (n ? "#{application.full_name}.#{n}" : application.full_name),
176
- hostname: (n ? "#{application.hostname}-#{n}" : application.hostname),
177
- image: application.image_name,
178
- volumes: application.volumes,
179
- ports: application.ports,
180
- environment: application.environment,
181
- command: application.command
182
- )
183
- end
184
226
  end # class Instance
185
227
  end # class Application
186
228
  end # module Jarl
data/lib/jarl/base.rb CHANGED
@@ -42,10 +42,49 @@ module Jarl
42
42
  end.flatten
43
43
  end
44
44
 
45
+ # Returns list of running application instances
46
+ #
47
+ def self.application_instances
48
+ @application_instances ||= applications.map(&:instances).flatten
49
+ end
50
+
45
51
  # Returns list of applications matching the pattern
46
52
  #
47
- def self.find_applications_by(pattern)
48
- applications.select { |a| a.full_name.index(pattern) }
53
+ # @param patterns [nil] Match all application instances
54
+ # @param patterns [String] Match application instances by single pattern
55
+ # @param patterns [Arary<String>] Match application instances by all patterns
56
+ #
57
+ def self.find_applications_by(patterns)
58
+ find_application_instances_by(patterns).map(&:application).uniq
59
+ end
60
+
61
+ # Returns list of running application instances matching the pattern(s)
62
+ #
63
+ # @param patterns [nil] Match all application instances
64
+ # @param patterns [String] Match application instances by single pattern
65
+ # @param patterns [Arary<String>] Match application instances by all patterns
66
+ #
67
+ def self.find_application_instances_by(patterns)
68
+ patterns = nil if patterns && patterns.empty?
69
+ case patterns
70
+ when nil
71
+ application_instances
72
+ when String
73
+ application_instances.select { |i| i.full_name.index(patterns) }
74
+ when Array
75
+ application_instances.select { |i| patterns.any? { |p| i.full_name.index(p) } }
76
+ else
77
+ fail "Unexpected #{patterns.class} passed as argument to .find_application_instances_by"
78
+ end
79
+ end
80
+
81
+ #
82
+ #
83
+ def self.reload!
84
+ @jarl_files = nil
85
+ @applications = nil
86
+ @application_instances = nil
87
+ Docker.reload!
49
88
  end
50
89
 
51
90
  private
data/lib/jarl/cli.rb CHANGED
@@ -25,52 +25,58 @@ module Jarl
25
25
  puts " #{app.name}"
26
26
  end
27
27
  end
28
- # show_jarl_applications_status(apps)
29
28
  end
30
29
 
31
30
  #
32
- desc 'status [NAME]', '(default) Show applications statuses'
33
- def status(name = nil)
31
+ desc 'status [NAME ...]', '(default) Show applications statuses'
32
+ def status(*names)
34
33
  Jarl.load(options)
35
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
36
- show_jarl_applications_status(apps)
34
+ ais = Jarl.find_application_instances_by(names)
35
+ show_jarl_application_instances_status(ais)
37
36
  end
38
37
  default_task :status
39
38
 
40
- #
41
- option :scale,
42
- type: :numeric,
43
- default: 1,
44
- desc: 'Start several instances'
45
- desc 'up [NAME]', 'Start or restart applications'
46
- def up(name = nil)
39
+ desc 'up [NAME ...]', 'Start or restart applications'
40
+ def up(*names)
47
41
  Jarl.load(options)
48
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
49
- apps.each do |app|
50
- puts esc_green(app.running? ? "Restarting '#{app}'..." : "Starting '#{app}'...")
51
- app.start(options[:scale])
42
+ if Jarl.find_application_instances_by(names).any?(&:running?)
43
+ down(*names)
44
+ Jarl.reload!
45
+ end
46
+ ais = Jarl.find_application_instances_by(names)
47
+ ais.each do |i|
48
+ puts esc_green "Starting '#{i.full_name}'..."
49
+ i.start!
52
50
  end
51
+ # apps = name ? Jarl.find_applications_by(name) : Jarl.applications
52
+ # apps.each do |app|
53
+ # puts esc_green(app.running? ? "Restarting '#{app}'..." : "Starting '#{app}'...")
54
+ # app.start
55
+ # end
53
56
  # show_jarl_applications_status(apps)
54
57
  end
55
58
 
56
59
  #
57
- desc 'down [NAME]', 'Stop applications'
58
- def down(name = nil)
60
+ desc 'down [NAME ...]', 'Stop applications'
61
+ def down(*names)
59
62
  Jarl.load(options)
60
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
61
- apps.each do |app|
62
- next unless app.running?
63
- app.instances.each do |i|
64
- puts esc_yellow "Stopping '#{i.name}'..."
65
- i.stop!
66
- end
63
+ ais = Jarl.find_application_instances_by(names).select(&:running?)
64
+ puts esc_yellow 'No running applications found' unless ais.size > 0
65
+ ais.each do |i|
66
+ puts esc_yellow "Stopping '#{i.full_name}'..."
67
+ i.stop!
67
68
  end
68
69
  end
69
70
 
70
71
  desc 'execute NAME [COMMAND ...]', 'Run a single command against application image'
71
72
  def execute(name, command = nil, *args)
72
73
  Jarl.load(options)
73
- app = Jarl.find_applications_by(name).first
74
+ apps = Jarl.find_applications_by(name)
75
+ if apps.size > 1
76
+ puts esc_yellow 'More than one application matches the pattern, using the first one:'
77
+ puts esc_yellow " #{apps.map(&:full_name).join(', ')}"
78
+ end
79
+ app = apps.first
74
80
  abort "Failed to find application by name: '#{name}'" unless app
75
81
  app.execute(command, args)
76
82
  end
@@ -79,7 +85,13 @@ module Jarl
79
85
  desc 'ssh NAME [COMMAND ...]', 'Open an interactive SSH session to a running application or execute a command and exit'
80
86
  def ssh(name, command = nil, *args)
81
87
  Jarl.load(options)
82
- app = Jarl.find_applications_by(name).first
88
+ ais = Jarl.find_application_instances_by(name).select(&:running?)
89
+ abort 'No running applications found' unless ais.size > 0
90
+ if ais.size > 1
91
+ puts esc_yellow 'More than one running application instance matches the pattern, using the first one:'
92
+ puts esc_yellow " #{ais.map(&:full_name).join(', ')}"
93
+ end
94
+ app = ais.first
83
95
  abort "Failed to find application by name: '#{name}'" unless app
84
96
  abort "Application is not running: '#{app.full_name}'" unless app.running?
85
97
  app.ssh([command] + args)
@@ -87,45 +99,46 @@ module Jarl
87
99
 
88
100
  #
89
101
  option :ip, type: :boolean, desc: 'Show only IPs'
90
- desc 'inspect [NAME]', 'Inspect applications'
91
- def inspect(name = nil)
102
+ desc 'inspect [NAME ...]', 'Inspect running application instances'
103
+ def inspect(*names)
92
104
  Jarl.load(options)
93
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
94
- apps.each do |app|
105
+ ais = Jarl.find_application_instances_by(names).select(&:running?)
106
+ abort 'No running applications found' unless ais.size > 0
107
+ ais.each do |ai|
95
108
  if options[:ip]
96
- puts app.instances.map(&:container).map(&:ip) if app.running?
109
+ puts ai.container.ip
97
110
  else
98
- show_jarl_application_inspect(app)
111
+ show_jarl_application_instance_inspect(ai)
99
112
  end
100
113
  end
101
114
  end
102
115
 
103
- desc 'build [NAME]', 'Rebuild docker images for Dockerfile based applications'
104
- def build(name = nil)
116
+ desc 'build [NAME ...]', 'Rebuild docker images for Dockerfile based applications'
117
+ def build(*names)
105
118
  Jarl.load(options)
106
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
119
+ apps = Jarl.find_applications_by(names)
107
120
  apps.select(&:image_is_a_path?).each do |app|
108
121
  puts esc_yellow "Building image for '#{app}'..."
109
122
  app.build
110
123
  end
111
124
  end
112
125
 
113
- desc 'pull [NAME]', 'Pull docker images for regestry based applications'
114
- def pull(name = nil)
126
+ desc 'pull [NAME ...]', 'Pull docker images for regestry based applications'
127
+ def pull(*names)
115
128
  Jarl.load(options)
116
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
129
+ apps = Jarl.find_applications_by(names)
117
130
  apps.select(&:image_is_a_registry_path?).each do |app|
118
131
  puts esc_yellow "Pulling image '#{app}'..."
119
132
  app.pull
120
133
  end
121
134
  end
122
135
 
123
- desc 'logs [NAME]', 'Show log output for applications'
124
- def logs(name = nil)
136
+ desc 'logs [NAME ...]', 'Show log output for applications'
137
+ def logs(*names)
125
138
  Jarl.load(options)
126
- apps = name ? Jarl.find_applications_by(name) : Jarl.applications
139
+ ais = Jarl.find_application_instances_by(names)
127
140
  threads = []
128
- apps.select(&:running?).map(&:instances).flatten.each do |instance|
141
+ ais.select(&:running?).flatten.each do |instance|
129
142
  threads << Thread.new { instance.tail_log }
130
143
  end
131
144
 
@@ -148,14 +161,12 @@ module Jarl
148
161
  "Jarl v#{Jarl::VERSION}"
149
162
  end
150
163
 
151
- def show_jarl_applications_status(apps)
152
- if apps.size == 0
164
+ def show_jarl_application_instances_status(ais)
165
+ if ais.size == 0
153
166
  puts esc_yellow 'No applications found'
154
167
  return
155
168
  end
156
- full_names = apps.map do |app|
157
- app.running? ? app.instances.map { |i| i.container.name } : app.full_name
158
- end.flatten
169
+ full_names = ais.map(&:full_name)
159
170
  max_full_name_len = [full_names.map(&:size).max, 12].max
160
171
  puts esc_format(
161
172
  ['APPLICATION', max_full_name_len],
@@ -164,20 +175,18 @@ module Jarl
164
175
  ['IP', 12],
165
176
  ['PORTS']
166
177
  )
167
- apps.each do |app|
168
- if app.running?
169
- app.instances.each do |i|
170
- puts esc_format(
171
- [i.container.name, max_full_name_len, :yellow],
172
- [i.container.id, 12, :green],
173
- [seconds_to_human(i.container.uptime), 12, :yellow],
174
- [i.container.ip, 12, :yellow],
175
- [i.container.ports.map { |p| "#{p[:from]}" }.join(', ')]
176
- )
177
- end
178
+ ais.each do |i|
179
+ if i.running?
180
+ puts esc_format(
181
+ [i.container.name, max_full_name_len, :yellow],
182
+ [i.container.id, 12, :green],
183
+ [seconds_to_human(i.container.uptime), 12, :yellow],
184
+ [i.container.ip, 12, :yellow],
185
+ [i.container.ports.map { |p| "#{p[:from]}" }.join(', ')]
186
+ )
178
187
  else
179
188
  puts esc_format(
180
- [app.full_name, max_full_name_len, :yellow],
189
+ [i.full_name, max_full_name_len, :yellow],
181
190
  ['no', 12],
182
191
  ['', 12],
183
192
  ['', 12],
@@ -187,21 +196,21 @@ module Jarl
187
196
  end
188
197
  end
189
198
 
190
- def show_jarl_application_inspect(app)
191
- unless app.running?
192
- puts esc_yellow("#{app.full_name}: ") + 'down'
199
+ def show_jarl_application_instance_inspect(ai)
200
+ unless ai.running?
201
+ puts esc_yellow("#{ai.full_name}: ") + 'off'
193
202
  return
194
203
  end
195
- app.instances.map(&:container).each do |container|
196
- puts esc_yellow "#{container.name}: " + esc_green(container.id)
197
- puts " app: #{esc_yellow app.full_name}"
198
- puts " image: #{esc_yellow container.image}"
199
- puts " full ID: #{esc_yellow container.long_id}"
200
- puts " uptime: #{esc_yellow seconds_to_human container.uptime}"
201
- puts " IP: #{esc_yellow container.ip}"
202
- puts " ports: #{esc_yellow container.ports.map { |p| "#{p[:from]}->#{p[:to]}"}.join(', ')}"
203
- puts " volumes: #{esc_yellow container.params['Volumes']}"
204
- end
204
+ app = ai.application
205
+ container = ai.container
206
+ puts esc_yellow "#{container.name}: " + esc_green(container.id)
207
+ puts " app: #{esc_yellow app.full_name}"
208
+ puts " image: #{esc_yellow container.image}"
209
+ puts " full ID: #{esc_yellow container.long_id}"
210
+ puts " uptime: #{esc_yellow seconds_to_human container.uptime}"
211
+ puts " IP: #{esc_yellow container.ip}"
212
+ puts " ports: #{esc_yellow container.ports.map { |p| "#{p[:from]}->#{p[:to]}"}.join(', ')}"
213
+ puts " volumes: #{esc_yellow container.volumes}"
205
214
  end
206
215
  end # class CLI
207
216
  end # module Jarl
data/lib/jarl/docker.rb CHANGED
@@ -64,9 +64,17 @@ module Docker
64
64
  @docker_containers_running
65
65
  end
66
66
 
67
+ # Returns `docker ps` info inspector instance
68
+ #
69
+ def self.ps
70
+ @docker_ps ||= Ps.new
71
+ end
72
+
73
+
67
74
  # Reloads lists of images and containers
68
75
  #
69
76
  def self.reload!
77
+ @docker_ps = nil
70
78
  @docker_images = nil
71
79
  @docker_images_used = nil
72
80
  @docker_containers_running = nil
@@ -134,6 +142,52 @@ module Docker
134
142
  sh docker_cmd
135
143
  end
136
144
 
145
+ # `docker ps` info inspector
146
+ #
147
+ class Ps
148
+ FIELDS = [
149
+ 'CONTAINER ID', 'IMAGE', 'COMMAND', 'CREATED', 'STATUS', 'PORTS', 'NAMES'
150
+ ]
151
+
152
+ attr_reader :entries
153
+
154
+ def initialize
155
+ lines = `docker ps`.split("\n")
156
+ @headers = lines.shift
157
+ @data = lines
158
+ @entries = lines.map do |line|
159
+ FIELDS.map { |name| [name, field(line, name)] }.to_h
160
+ end
161
+ end
162
+
163
+ def field_i_start(name)
164
+ i_start = @headers.index(name)
165
+ fail "Failed to find the field #{name} in docker ps" unless i_start
166
+ i_start
167
+ end
168
+
169
+ # @return [nil,Integer] right index for field or -1 if the field is rightmost
170
+ #
171
+ def field_i_end(name)
172
+ i_start = field_i_start(name)
173
+ r_headers = @headers[i_start..-1].sub(/^#{name}/, '')
174
+ m = r_headers.match(/^(\s+)/)
175
+ m ? i_start + name.size + m[1].size - 1 : -1
176
+ end
177
+
178
+ def field_i_range(name)
179
+ field_i_start(name)..field_i_end(name)
180
+ end
181
+
182
+ def field(line, name)
183
+ line[field_i_range(name)].strip
184
+ end
185
+
186
+ def [](id)
187
+ entries.find { |e| id == e['CONTAINER ID'] }
188
+ end
189
+ end
190
+
137
191
  # Image
138
192
  #
139
193
  class Image
@@ -205,24 +259,54 @@ module Docker
205
259
  # Container
206
260
  #
207
261
  class Container
208
- attr_accessor :id, :long_id, :name, :image, :image_id, :ip, :ps, :ports, :params
262
+ attr_accessor :id
209
263
 
210
264
  def initialize(id)
211
265
  @id = id
212
- @ps = `docker ps | grep #{id}`
213
- container_inspect = `docker inspect #{id}`
214
- @params = JSON.parse(container_inspect).first
215
- @long_id = params['Id']
216
- @name = params['Name'].gsub('/', '')
217
- @image = params['Config']['Image']
218
- @image_id = params['Image']
219
- @ip = params['NetworkSettings']['IPAddress']
220
- port_maps = params['NetworkSettings']['Ports']
221
- @ports = port_maps.keys.map do |port|
266
+ end
267
+
268
+ def ps
269
+ Docker.ps[id] or fail "Failed to find ps info for #{id}"
270
+ end
271
+
272
+ def container_inspect
273
+ return @container_inspect if @container_inspect
274
+ # puts "Loading inspect for: #{ps}"
275
+ @container_inspect ||= JSON.parse(`docker inspect #{id}`).first
276
+ end
277
+
278
+ def long_id
279
+ container_inspect['Id']
280
+ end
281
+
282
+ def name
283
+ ps['NAMES']
284
+ # container_inspect['Name'].gsub('/', '')
285
+ end
286
+
287
+ def image
288
+ container_inspect['Config']['Image']
289
+ end
290
+
291
+ def image_id
292
+ container_inspect['Image']
293
+ end
294
+
295
+ def ip
296
+ container_inspect['NetworkSettings']['IPAddress']
297
+ end
298
+
299
+ def ports
300
+ port_maps = container_inspect['NetworkSettings']['Ports']
301
+ port_maps.keys.map do |port|
222
302
  { from: port, to: port_maps[port] }
223
303
  end
224
304
  end
225
305
 
306
+ def volumes
307
+ container_inspect['Volumes']
308
+ end
309
+
226
310
  def open_ssh_session!(params = {}, command = nil)
227
311
  ssh_flags = ['-oStrictHostKeyChecking=no']
228
312
  if params['ssh_identity']
@@ -246,8 +330,8 @@ module Docker
246
330
  end
247
331
 
248
332
  def uptime
249
- params['State'] && params['State']['StartedAt'] &&
250
- Time.now.utc - DateTime.parse(params['State']['StartedAt']).to_time.utc
333
+ container_inspect['State'] && container_inspect['State']['StartedAt'] &&
334
+ Time.now.utc - DateTime.parse(container_inspect['State']['StartedAt']).to_time.utc
251
335
  end
252
336
 
253
337
  def self.clean_containers(*names)
data/lib/jarl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jarl
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jarl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-15 00:00:00.000000000 Z
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
111
  version: '0'
112
112
  requirements: []
113
113
  rubyforge_project:
114
- rubygems_version: 2.2.2
114
+ rubygems_version: 2.4.5
115
115
  signing_key:
116
116
  specification_version: 4
117
117
  summary: Jarl, docker container management tool