docker-cli 0.3.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.release_history.yml +2 -0
- data/.rubocop.yml +2 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +24 -27
- data/Rakefile +2 -1
- data/docker-cli.gemspec +5 -2
- data/exe/_gemdocker +225 -0
- data/exe/dc-update +24 -0
- data/exe/gemdocker +52 -0
- data/exe/gemdocker_test +40 -0
- data/lib/docker/cli/command.rb +37 -31
- data/lib/docker/cli/command_factory.rb +49 -25
- data/lib/docker/cli/command_result.rb +16 -0
- data/lib/docker/cli/docker_composer.rb +113 -0
- data/lib/docker/cli/docker_container.rb +216 -0
- data/lib/docker/cli/docker_image.rb +205 -0
- data/lib/docker/cli/docker_run_log.rb +169 -0
- data/lib/docker/cli/dockerfile.rb +62 -0
- data/lib/docker/cli/dockerfile_template/dup_gem_bundler_env.rb +73 -0
- data/lib/docker/cli/dockerfile_template/match_user.rb +38 -0
- data/lib/docker/cli/dockerfile_template.rb +69 -0
- data/lib/docker/cli/gem/bundler_helper.rb +25 -0
- data/lib/docker/cli/image_helper.rb +43 -0
- data/lib/docker/cli/operations/args_parser.rb +53 -0
- data/lib/docker/cli/operations/run.rb +203 -0
- data/lib/docker/cli/operations/run_del.rb +67 -0
- data/lib/docker/cli/operations/run_keep.rb +118 -0
- data/lib/docker/cli/user_info.rb +39 -0
- data/lib/docker/cli/version.rb +1 -1
- data/lib/docker/cli.rb +64 -0
- data/scripts/create_user.sh.erb +10 -0
- metadata +51 -12
@@ -1,12 +1,15 @@
|
|
1
1
|
|
2
|
+
require 'erb'
|
3
|
+
|
2
4
|
require_relative 'command'
|
5
|
+
require_relative 'user_info'
|
3
6
|
|
4
7
|
module Docker
|
5
8
|
module Cli
|
6
9
|
class CommandFactory
|
7
10
|
include TR::CondUtils
|
8
11
|
|
9
|
-
def build_image(name = "", opts = { })
|
12
|
+
def build_image(name = "", opts = { }, &block)
|
10
13
|
|
11
14
|
opts = { } if opts.nil?
|
12
15
|
cmd = []
|
@@ -37,9 +40,9 @@ module Docker
|
|
37
40
|
cmd << "images"
|
38
41
|
cmd << "-q"
|
39
42
|
if not_empty?(tag)
|
40
|
-
cmd << "#{name}:#{tag}"
|
43
|
+
cmd << "\"#{name}:#{tag}\""
|
41
44
|
else
|
42
|
-
cmd << name
|
45
|
+
cmd << "\"#{name}\""
|
43
46
|
end
|
44
47
|
|
45
48
|
logger.debug "Find image: #{cmd.join(" ")}"
|
@@ -106,6 +109,10 @@ module Docker
|
|
106
109
|
Command.new(cmd)
|
107
110
|
end
|
108
111
|
|
112
|
+
#
|
113
|
+
# Create container from image directly
|
114
|
+
# e.g. > docker run -it <image> "/bin/bash"
|
115
|
+
#
|
109
116
|
def create_container_from_image(image, opts = { })
|
110
117
|
opts = {} if opts.nil?
|
111
118
|
cmd = []
|
@@ -113,13 +120,21 @@ module Docker
|
|
113
120
|
cmd << "run"
|
114
121
|
cmd << "-i" if opts[:interactive] == true
|
115
122
|
cmd << "-t" if opts[:tty] == true
|
123
|
+
cmd << "-d" if opts[:detached] == true
|
124
|
+
cmd << "--rm" if opts[:del] == true
|
116
125
|
if not (opts[:container_name].nil? or opts[:container_name].empty?)
|
117
|
-
cmd << "--name #{opts[:container_name]}"
|
126
|
+
cmd << "--name \"#{opts[:container_name]}\""
|
118
127
|
end
|
119
128
|
|
120
129
|
cmd << process_mount(opts)
|
121
130
|
cmd << process_port(opts)
|
122
131
|
|
132
|
+
if opts[:match_user] == true
|
133
|
+
ui = UserInfo.user_info
|
134
|
+
gi = UserInfo.group_info
|
135
|
+
cmd << "-u #{ui[:uid]}:#{gi[:gid]}"
|
136
|
+
end
|
137
|
+
|
123
138
|
cmd << image
|
124
139
|
|
125
140
|
if not_empty?(opts[:command])
|
@@ -128,7 +143,7 @@ module Docker
|
|
128
143
|
|
129
144
|
interactive = false
|
130
145
|
interactive = true if opts[:interactive] or opts[:tty]
|
131
|
-
|
146
|
+
|
132
147
|
logger.debug "Run Container from Image : #{cmd.join(" ")}"
|
133
148
|
Command.new(cmd, (interactive ? true : false))
|
134
149
|
end # run_container_from_image
|
@@ -220,17 +235,17 @@ module Docker
|
|
220
235
|
|
221
236
|
|
222
237
|
private
|
223
|
-
# expecting :mounts =>
|
238
|
+
# expecting :mounts => { "/dir/local" => "/dir/inside/docker" }
|
224
239
|
def process_mount(opts)
|
225
|
-
if not (opts[:
|
226
|
-
m = opts[:
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
240
|
+
if not_empty?(opts[:mounts]) #not (opts[:mounts].nil? or opts[:mounts].empty?)
|
241
|
+
m = opts[:mounts]
|
242
|
+
if m.is_a?(Hash)
|
243
|
+
res = []
|
244
|
+
m.each do |local, docker|
|
245
|
+
res << "-v #{local}:#{docker}"
|
246
|
+
end
|
247
|
+
res.join(" ")
|
232
248
|
end
|
233
|
-
res.join(" ")
|
234
249
|
else
|
235
250
|
""
|
236
251
|
end
|
@@ -238,13 +253,20 @@ module Docker
|
|
238
253
|
end # process_mount
|
239
254
|
|
240
255
|
def process_port(opts)
|
241
|
-
if not (opts[:ports].nil? or opts[:ports].empty?)
|
256
|
+
if not_empty?(opts[:ports]) #not (opts[:ports].nil? or opts[:ports].empty?)
|
242
257
|
po = opts[:ports]
|
243
|
-
po = [po] if not po.is_a?(Array)
|
244
258
|
res = []
|
245
|
-
po.
|
246
|
-
|
259
|
+
if po.is_a?(Hash)
|
260
|
+
po.each do |host, docker|
|
261
|
+
res << "-p #{host}:#{docker}"
|
262
|
+
end
|
247
263
|
end
|
264
|
+
#po = [po] if not po.is_a?(Array)
|
265
|
+
#po.each do |e|
|
266
|
+
# # 1st is port on host
|
267
|
+
# # 2nd is port inside container
|
268
|
+
# res << "-p #{e.keys.first}:#{e.values.first}"
|
269
|
+
#end
|
248
270
|
res.join(" ")
|
249
271
|
else
|
250
272
|
""
|
@@ -253,15 +275,17 @@ module Docker
|
|
253
275
|
end
|
254
276
|
|
255
277
|
def logger
|
256
|
-
|
257
|
-
@logger = TeLogger::Tlogger.new
|
258
|
-
@logger.tag = :docker_cmd
|
259
|
-
end
|
260
|
-
@logger
|
278
|
+
Cli.logger(:cmdFact)
|
261
279
|
end
|
262
280
|
|
263
|
-
def
|
264
|
-
|
281
|
+
def build_add_user_script
|
282
|
+
path = File.join(File.dirname(__FILE__),"..","..","..","scripts","create_user.sh.erb")
|
283
|
+
if File.exist?(path)
|
284
|
+
ui = UserInfo.user_info
|
285
|
+
gi = UserInfo.group_info
|
286
|
+
|
287
|
+
ERB.new(File.read(path)).result_with_hash({ user_group_id: gi[:gid], user_group_name: gi[:group_name], user_id: ui[:uid], user_login: ui[:login] })
|
288
|
+
end
|
265
289
|
end
|
266
290
|
|
267
291
|
end
|
@@ -19,6 +19,10 @@ module Docker
|
|
19
19
|
is_empty?(@out)
|
20
20
|
end
|
21
21
|
|
22
|
+
def is_err_stream_empty?
|
23
|
+
is_empty?(@err)
|
24
|
+
end
|
25
|
+
|
22
26
|
def out_stream
|
23
27
|
@out.join("\n")
|
24
28
|
end
|
@@ -35,6 +39,18 @@ module Docker
|
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
42
|
+
def success?
|
43
|
+
not failed?
|
44
|
+
end
|
45
|
+
alias_method :successful?, :success?
|
46
|
+
|
47
|
+
def each_line(&block)
|
48
|
+
out_stream.each_line(&block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def lines
|
52
|
+
out_stream.lines
|
53
|
+
end
|
38
54
|
end
|
39
55
|
|
40
56
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
require_relative 'user_info'
|
5
|
+
|
6
|
+
module Docker
|
7
|
+
module Cli
|
8
|
+
class DockerComposer
|
9
|
+
include TR::CondUtils
|
10
|
+
include TR::ArgUtils
|
11
|
+
|
12
|
+
arg_spec do
|
13
|
+
|
14
|
+
callback :pre_processing do |a|
|
15
|
+
parse_input(a)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_input(argv, &block)
|
21
|
+
@dcPath = argv.first
|
22
|
+
@dcPath = "./docker-compose.yml" if is_empty?(@dcPath)
|
23
|
+
@dcPath = "./docker-compose.yaml" if not File.exist?(@dcPath)
|
24
|
+
raise RuntimeException, "docker-compose.[yml,yaml] not found. Please provide the docker-compose.yml file to load" if not File.exist?(@dcPath)
|
25
|
+
|
26
|
+
@outPath = argv[1]
|
27
|
+
@outPath = "#{@dcPath}-gen.yml" if is_empty?(@outPath)
|
28
|
+
|
29
|
+
process_dc
|
30
|
+
|
31
|
+
[true, []]
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_dc
|
35
|
+
if File.exist?(@dcPath)
|
36
|
+
|
37
|
+
cont = YAML.safe_load(File.read(@dcPath))
|
38
|
+
|
39
|
+
if not_empty?(cont["services"])
|
40
|
+
|
41
|
+
cont["services"].each do |servName, conf|
|
42
|
+
|
43
|
+
# if user key is empty, match with current uid and gid
|
44
|
+
if conf.keys.include?("user") and is_empty?(conf["user"])
|
45
|
+
conf["user"] = "#{user_info[:uid]}:#{user_group_info[:gid]}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# add to volumes if there is development gems found
|
49
|
+
if not_empty?(conf["volumes"])
|
50
|
+
vol = conf["volumes"]
|
51
|
+
|
52
|
+
if vol.include?("devgems")
|
53
|
+
|
54
|
+
vol.delete("devgems")
|
55
|
+
logger.debug "Volume after delete : #{vol.inspect}"
|
56
|
+
|
57
|
+
devGems = Cli.find_dev_gems
|
58
|
+
logger.debug " Found #{devGems.length} devgems"
|
59
|
+
if devGems.length > 0
|
60
|
+
if @parse_argv_block
|
61
|
+
@mount_root = @parse_argv_block.call(:prompt_docker_mount_root)
|
62
|
+
else
|
63
|
+
raise RuntimeException, "Please provide a block to prompt for missing parameters"
|
64
|
+
end
|
65
|
+
|
66
|
+
devGems.each do |name,path|
|
67
|
+
vol << "#{path}:#{File.join(@mount_root, name)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
reCont = cont.to_yaml
|
79
|
+
reCont = reCont.gsub("---","")
|
80
|
+
File.open(@outPath, "w") do |f|
|
81
|
+
f.write reCont
|
82
|
+
end
|
83
|
+
|
84
|
+
else
|
85
|
+
raise RuntimeException, "Given docker compose file '#{@dcPath}' does not exist"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def user_info
|
91
|
+
if @_user_info.nil?
|
92
|
+
@_user_info = UserInfo.user_info
|
93
|
+
end
|
94
|
+
@_user_info
|
95
|
+
end
|
96
|
+
|
97
|
+
def user_group_info
|
98
|
+
if @_userg_info.nil?
|
99
|
+
@_userg_info = UserInfo.group_info
|
100
|
+
end
|
101
|
+
@_userg_info
|
102
|
+
end
|
103
|
+
|
104
|
+
def logger
|
105
|
+
if @_logger.nil?
|
106
|
+
@_logger = Cli.logger(:docomp)
|
107
|
+
end
|
108
|
+
@_logger
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
|
2
|
+
require_relative 'command_factory'
|
3
|
+
|
4
|
+
module Docker
|
5
|
+
module Cli
|
6
|
+
|
7
|
+
# only use during creation of new container
|
8
|
+
class ContainerProfile
|
9
|
+
include TR::CondUtils
|
10
|
+
|
11
|
+
attr_accessor :run_command, :image_name
|
12
|
+
def initialize
|
13
|
+
@interactive = true
|
14
|
+
@run_detached = false
|
15
|
+
@remove_after_run = false
|
16
|
+
@match_user = false
|
17
|
+
@run_command = "/bin/bash"
|
18
|
+
@mounts = {}
|
19
|
+
@ports = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def mount_points
|
23
|
+
@mounts.freeze
|
24
|
+
end
|
25
|
+
def add_mount_point(host, inside_docker)
|
26
|
+
if not_empty?(host) and not_empty?(inside_docker)
|
27
|
+
@mounts[host] = inside_docker
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ports
|
32
|
+
@ports.freeze
|
33
|
+
end
|
34
|
+
def add_port_mapping(host, docker)
|
35
|
+
if not_empty?(host) and not_empty?(docker)
|
36
|
+
@ports[host] = docker
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def is_interactive?
|
41
|
+
@interactive
|
42
|
+
end
|
43
|
+
def interactive=(val)
|
44
|
+
@interactive = val
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_run_detached?
|
48
|
+
@run_detached
|
49
|
+
end
|
50
|
+
def run_detached=(val)
|
51
|
+
@run_detached = val
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_after_run?
|
55
|
+
@remove_after_run
|
56
|
+
end
|
57
|
+
def remove_after_run=(val)
|
58
|
+
@remove_after_run = val
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_match_user?
|
62
|
+
@match_user
|
63
|
+
end
|
64
|
+
def match_user=(val)
|
65
|
+
@match_user = val
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_hash
|
69
|
+
# this returns a hash that match expectation of input in CommandFactory.create_container_from_image
|
70
|
+
{ interactive: @interactive, tty: @interactive, detached: @run_detached, del: @remove_after_run, mounts: @mounts, ports: @ports, match_user: @match_user, command: @run_command }
|
71
|
+
end
|
72
|
+
|
73
|
+
end # class NewContainerProfile
|
74
|
+
|
75
|
+
class DockerContainer
|
76
|
+
include TR::CondUtils
|
77
|
+
|
78
|
+
#def self.is_exists?(name)
|
79
|
+
# res = command.find_from_all_container(name, opts).run
|
80
|
+
# raise CommandFailed, "Command to check if container exist failed. Error was : #{res.err_stream}" if not res.successful?
|
81
|
+
# not res.is_out_stream_empty?
|
82
|
+
#end
|
83
|
+
|
84
|
+
#def self.create(image, opts = {}, &block)
|
85
|
+
# command.create_container_from_image(image, opts).run
|
86
|
+
#end
|
87
|
+
|
88
|
+
#def self.prep_container(image, opts = {})
|
89
|
+
# # render the create_user script
|
90
|
+
# res = build_add_user_script
|
91
|
+
# # system always mount current dir inside docker
|
92
|
+
# dest = File.join(opts[:mount_local],"create_user.sh")
|
93
|
+
# File.open(dest,"w") do |f|
|
94
|
+
# f.write res
|
95
|
+
# end
|
96
|
+
# `chmod +x #{dest}`
|
97
|
+
|
98
|
+
# # create non interactive session to create the user & group first
|
99
|
+
# opts[:command] = "#{File.join(opts[:mount_docker],"create_user.sh")}"
|
100
|
+
# opts[:detached] = true
|
101
|
+
# command.create_container_from_image(image, opts).run
|
102
|
+
#end
|
103
|
+
|
104
|
+
def self.containers_of_image_from_history(img, opts = { })
|
105
|
+
cont = DockerRunLog.instance.containers(img)
|
106
|
+
res = {}
|
107
|
+
if cont.length == 1
|
108
|
+
c = cont.first
|
109
|
+
res[c[:container]] = c
|
110
|
+
else
|
111
|
+
cont.each do |c|
|
112
|
+
res[c[:container]] = "#{c[:container]} [Last Access : #{Time.at(c[:last_run])}] - Config : #{c[:argv]}"
|
113
|
+
end
|
114
|
+
res
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#def self.containers(image = nil)
|
119
|
+
#
|
120
|
+
#end
|
121
|
+
|
122
|
+
#def self.container(name)
|
123
|
+
#
|
124
|
+
#end
|
125
|
+
|
126
|
+
attr_reader :name
|
127
|
+
|
128
|
+
def initialize(name, history = nil)
|
129
|
+
@name = name
|
130
|
+
@history = history
|
131
|
+
end
|
132
|
+
|
133
|
+
def is_exist?
|
134
|
+
res = command.find_from_all_container(@name).run
|
135
|
+
raise CommandFailed, "Command to check if container exist failed. Error was : #{res.err_stream}" if not res.successful?
|
136
|
+
not res.is_out_stream_empty?
|
137
|
+
end
|
138
|
+
|
139
|
+
def create(container_profile)
|
140
|
+
raise CommandFailed, " Image name is not given to create the container '#{@name}'" if is_empty?(container_profile.image_name)
|
141
|
+
opts = container_profile.to_hash
|
142
|
+
opts[:container_name] = @name
|
143
|
+
command.create_container_from_image(container_profile.image_name, opts).run
|
144
|
+
end
|
145
|
+
|
146
|
+
def name_for_display
|
147
|
+
if @history.nil?
|
148
|
+
@name
|
149
|
+
else
|
150
|
+
"#{@history[:container]} [Last Access : #{Time.at(@history[:last_run])}] - Config : #{@history[:argv]}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def run_before?
|
155
|
+
not @history.nil?
|
156
|
+
end
|
157
|
+
|
158
|
+
def history
|
159
|
+
if not @history.nil?
|
160
|
+
@history.freeze
|
161
|
+
else
|
162
|
+
@history = {}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def is_running?
|
167
|
+
res = command.find_running_container(@name).run
|
168
|
+
raise CommandFailed, "Command to find running container failed. Error was : #{res.err_stream}" if not res.successful?
|
169
|
+
not res.is_out_stream_empty?
|
170
|
+
end
|
171
|
+
|
172
|
+
def start(&block)
|
173
|
+
command.start_container(@name).run
|
174
|
+
end
|
175
|
+
|
176
|
+
def stop(&block)
|
177
|
+
command.stop_container(@name).run
|
178
|
+
end
|
179
|
+
|
180
|
+
def attach(&block)
|
181
|
+
command.attach_container(@name).run
|
182
|
+
end
|
183
|
+
|
184
|
+
def delete!(&block)
|
185
|
+
command.delete_container(@name).run
|
186
|
+
end
|
187
|
+
|
188
|
+
def run(cmd, opts = {}, &block)
|
189
|
+
command.run_command_in_running_container(@name, cmd, opts).run
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def self.command
|
194
|
+
if @_cmd.nil?
|
195
|
+
@_cmd = CommandFactory.new
|
196
|
+
end
|
197
|
+
@_cmd
|
198
|
+
end
|
199
|
+
|
200
|
+
def command
|
201
|
+
self.class.command
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.build_add_user_script
|
205
|
+
path = File.join(File.dirname(__FILE__),"..","..","..","scripts","create_user.sh.erb")
|
206
|
+
if File.exist?(path)
|
207
|
+
ui = UserInfo.user_info
|
208
|
+
gi = UserInfo.group_info
|
209
|
+
|
210
|
+
ERB.new(File.read(path)).result_with_hash({ user_group_id: gi[:gid], user_group_name: gi[:group_name], user_id: ui[:uid], user_login: ui[:login] })
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
|
2
|
+
require_relative 'command_factory'
|
3
|
+
|
4
|
+
module Docker
|
5
|
+
module Cli
|
6
|
+
class DockerImage
|
7
|
+
include TR::CondUtils
|
8
|
+
|
9
|
+
def self.set_master_format(format)
|
10
|
+
@_doc_mformat = format
|
11
|
+
end
|
12
|
+
def self.master_format
|
13
|
+
if @_doc_mformat.nil?
|
14
|
+
@_doc_mformat = "{{.Repository}}#{self.separator}{{.ID}}#{self.separator}{{.Tag}}"
|
15
|
+
end
|
16
|
+
@_doc_mformat.freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.set_inspect_format(format)
|
20
|
+
@_dec_iformat = format
|
21
|
+
end
|
22
|
+
def self.inspect_format
|
23
|
+
if @_doc_iformat.nil?
|
24
|
+
@_doc_iformat = "{{.Created}}#{self.separator}{{.Size}}"
|
25
|
+
end
|
26
|
+
@_doc_iformat.freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.set_separator(sep)
|
30
|
+
@_doc_sep = sep
|
31
|
+
end
|
32
|
+
def self.separator
|
33
|
+
if @_doc_sep.nil?
|
34
|
+
@_doc_sep = ";"
|
35
|
+
end
|
36
|
+
@_doc_sep.freeze
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.images
|
40
|
+
logger.warn "loading images from system is an expensive operation. Please implement some cache at aplication level to increase its efficiency"
|
41
|
+
cmd = []
|
42
|
+
cmd << Cli.docker_exe
|
43
|
+
cmd << "images"
|
44
|
+
cmd << "--format"
|
45
|
+
cmd << "\"#{self.master_format}\""
|
46
|
+
|
47
|
+
rres = []
|
48
|
+
res = Command.new(cmd).run
|
49
|
+
if res.successful?
|
50
|
+
res.each_line do |l|
|
51
|
+
sp = l.strip.split(self.separator)
|
52
|
+
rres << { name: sp[0], id: sp[1], tag: sp[2] }
|
53
|
+
end
|
54
|
+
else
|
55
|
+
logger.warn "Command '#{cmd.join(" ")}' failed.\n Error was : #{res.err_stream}"
|
56
|
+
end
|
57
|
+
|
58
|
+
fres = []
|
59
|
+
rres.each do |r|
|
60
|
+
ccmd = []
|
61
|
+
ccmd << cmd[0]
|
62
|
+
ccmd << "inspect"
|
63
|
+
ccmd << "-f"
|
64
|
+
ccmd << "'{{.ID}}#{self.separator}{{.Created}}#{self.separator}{{.Size}}'"
|
65
|
+
ccmd << r[:name]
|
66
|
+
|
67
|
+
rres = Command.new(ccmd).run
|
68
|
+
if rres.successful?
|
69
|
+
rres.each_line do |l|
|
70
|
+
sp = l.strip.split(self.separator)
|
71
|
+
rid = sp[0]
|
72
|
+
r[:image_id] = rid.split(":")[1]
|
73
|
+
r[:created] = sp[1]
|
74
|
+
r[:size] = sp[2]
|
75
|
+
r[:runtime] = true
|
76
|
+
fres << DockerImage.new(r[:name], r)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
logger.warn "Command '#{ccmd.join(" ")}' failed.\n Error was : #{rres.err_stream}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
fres
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.image(image)
|
87
|
+
cmd = []
|
88
|
+
cmd << Cli.docker_exe
|
89
|
+
cmd << "images"
|
90
|
+
cmd << "--format"
|
91
|
+
cmd << "\"#{self.master_format}\""
|
92
|
+
# image and tag is in single unit
|
93
|
+
# e.g.:
|
94
|
+
# jruby:9.2-jdk11
|
95
|
+
# jruby:9
|
96
|
+
# jruby:9.3.0.0-jdk11
|
97
|
+
cmd << image
|
98
|
+
|
99
|
+
rres = []
|
100
|
+
res = Command.new(cmd).run
|
101
|
+
if res.successful?
|
102
|
+
# single image could have many lines because they have
|
103
|
+
# different tags!
|
104
|
+
res.each_line do |l|
|
105
|
+
sp = l.strip.split(self.separator)
|
106
|
+
rres << { name: sp[0], id: sp[1], tag: sp[2] }
|
107
|
+
end
|
108
|
+
else
|
109
|
+
logger.warn "Command '#{cmd.join(" ")}' failed.\n Error was : #{res.err_stream}"
|
110
|
+
end
|
111
|
+
|
112
|
+
fres = []
|
113
|
+
rres.each do |r|
|
114
|
+
ccmd = []
|
115
|
+
ccmd << cmd[0]
|
116
|
+
ccmd << "inspect"
|
117
|
+
ccmd << "-f"
|
118
|
+
ccmd << "'{{.ID}}#{self.separator}{{.Created}}#{self.separator}{{.Size}}'"
|
119
|
+
ccmd << r[:name]
|
120
|
+
|
121
|
+
rres = Command.new(ccmd).run
|
122
|
+
if rres.successful?
|
123
|
+
rres.each_line do |l|
|
124
|
+
sp = l.strip.split(self.separator)
|
125
|
+
rid = sp[0]
|
126
|
+
r[:image_id] = rid.split(":")[1]
|
127
|
+
r[:created] = sp[1]
|
128
|
+
r[:size] = sp[2]
|
129
|
+
r[:runtime] = true
|
130
|
+
fres << DockerImage.new(r[:name], r)
|
131
|
+
end
|
132
|
+
else
|
133
|
+
logger.warn "Command '#{ccmd.join(" ")}' failed.\n Error was : #{rres.err_stream}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
fres
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.build(imageName, dockerfile, context = ".")
|
141
|
+
command.build_image(imageName, dockerfile: dockerfile, context_root: context).run
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
attr_reader :name, :tag, :size, :created, :image_id, :sid
|
146
|
+
|
147
|
+
def initialize(name, opts = {})
|
148
|
+
@name = name
|
149
|
+
if not_empty?(opts)
|
150
|
+
@sid = opts[:sid]
|
151
|
+
@image_id = opts[:image_id]
|
152
|
+
@tag = opts[:tag]
|
153
|
+
@size = opts[:size]
|
154
|
+
@created = opts[:created]
|
155
|
+
@runtime = opts[:runtime]
|
156
|
+
end
|
157
|
+
|
158
|
+
@runtime = false if is_empty?(@runtime) or not_bool?(@runtime)
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
def is_runtime_image?
|
163
|
+
@runtime
|
164
|
+
end
|
165
|
+
|
166
|
+
def has_containers?
|
167
|
+
DockerRunLog.instance.image_has_containers?(@name)
|
168
|
+
end
|
169
|
+
|
170
|
+
def containers
|
171
|
+
if @_cont.nil?
|
172
|
+
# here assuming every run from system will be logged
|
173
|
+
# but what about the one not using the system?
|
174
|
+
@_cont = DockerRunLog.instance.image_containers(@name).collect { |e| DockerContainer.new(e[:container], e) }
|
175
|
+
end
|
176
|
+
@_cont
|
177
|
+
end
|
178
|
+
|
179
|
+
def delete!
|
180
|
+
if not_empty?(@tag)
|
181
|
+
command.delete_image(@name, @tag, opts)
|
182
|
+
else
|
183
|
+
raise IndefiniteOption, "Delete image cannot proceed because there might be more than single instance of the image. Please provide a tag for definite selection for deletion."
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
def self.command
|
189
|
+
if @_cmd.nil?
|
190
|
+
@_cmd = CommandFactory.new
|
191
|
+
end
|
192
|
+
@_cmd
|
193
|
+
end
|
194
|
+
|
195
|
+
def command
|
196
|
+
self.class.command
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.logger
|
200
|
+
Cli.logger(:docker_image)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|