docker-cli 0.3.1 → 0.5.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.
@@ -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(" ")}"
@@ -79,7 +82,12 @@ module Docker
79
82
  cmd << "ps"
80
83
  cmd << "-q"
81
84
  cmd << "-f"
82
- cmd << "name=\"#{name}\""
85
+
86
+ if opts[:exact_name] == true
87
+ cmd << "name=\"^/#{name}$\""
88
+ else
89
+ cmd << "name=\"#{name}\""
90
+ end
83
91
 
84
92
  logger.debug "Find container: #{cmd.join(" ")}"
85
93
 
@@ -100,12 +108,22 @@ module Docker
100
108
  # From little testing seems the command by default already support regex formatting
101
109
  # So can use the regex marker to get exact match
102
110
  # e.g. if want exact match, pass in ^#{name}\z
103
- cmd << "name=\"#{name}\""
111
+ #cmd << "name=\"#{name}\""
112
+
113
+ if opts[:exact_name] == true
114
+ cmd << "name=\"^/#{name}$\""
115
+ else
116
+ cmd << "name=\"#{name}\""
117
+ end
104
118
 
105
119
  logger.debug "Find from all container: #{cmd.join(" ")}"
106
120
  Command.new(cmd)
107
121
  end
108
122
 
123
+ #
124
+ # Create container from image directly
125
+ # e.g. > docker run -it <image> "/bin/bash"
126
+ #
109
127
  def create_container_from_image(image, opts = { })
110
128
  opts = {} if opts.nil?
111
129
  cmd = []
@@ -113,13 +131,21 @@ module Docker
113
131
  cmd << "run"
114
132
  cmd << "-i" if opts[:interactive] == true
115
133
  cmd << "-t" if opts[:tty] == true
134
+ cmd << "-d" if opts[:detached] == true
135
+ cmd << "--rm" if opts[:del] == true
116
136
  if not (opts[:container_name].nil? or opts[:container_name].empty?)
117
- cmd << "--name #{opts[:container_name]}"
137
+ cmd << "--name \"#{opts[:container_name]}\""
118
138
  end
119
139
 
120
140
  cmd << process_mount(opts)
121
141
  cmd << process_port(opts)
122
142
 
143
+ if opts[:match_user] == true
144
+ ui = UserInfo.user_info
145
+ gi = UserInfo.group_info
146
+ cmd << "-u #{ui[:uid]}:#{gi[:gid]}"
147
+ end
148
+
123
149
  cmd << image
124
150
 
125
151
  if not_empty?(opts[:command])
@@ -128,7 +154,7 @@ module Docker
128
154
 
129
155
  interactive = false
130
156
  interactive = true if opts[:interactive] or opts[:tty]
131
-
157
+
132
158
  logger.debug "Run Container from Image : #{cmd.join(" ")}"
133
159
  Command.new(cmd, (interactive ? true : false))
134
160
  end # run_container_from_image
@@ -220,17 +246,17 @@ module Docker
220
246
 
221
247
 
222
248
  private
223
- # expecting :mounts => [{ "/dir/local" => "/dir/inside/docker" }]
249
+ # expecting :mounts => { "/dir/local" => "/dir/inside/docker" }
224
250
  def process_mount(opts)
225
- if not (opts[:mount].nil? or opts[:mount].empty?)
226
- m = opts[:mount]
227
- m = [m] if not m.is_a?(Array)
228
- res = []
229
- m.each do |mm|
230
- host = mm.keys.first
231
- res << "-v #{host}:#{mm[host]}"
251
+ if not_empty?(opts[:mounts]) #not (opts[:mounts].nil? or opts[:mounts].empty?)
252
+ m = opts[:mounts]
253
+ if m.is_a?(Hash)
254
+ res = []
255
+ m.each do |local, docker|
256
+ res << "-v #{local}:#{docker}"
257
+ end
258
+ res.join(" ")
232
259
  end
233
- res.join(" ")
234
260
  else
235
261
  ""
236
262
  end
@@ -238,13 +264,20 @@ module Docker
238
264
  end # process_mount
239
265
 
240
266
  def process_port(opts)
241
- if not (opts[:ports].nil? or opts[:ports].empty?)
267
+ if not_empty?(opts[:ports]) #not (opts[:ports].nil? or opts[:ports].empty?)
242
268
  po = opts[:ports]
243
- po = [po] if not po.is_a?(Array)
244
269
  res = []
245
- po.each do |host,docker|
246
- res << "-p #{host}:#{docker}"
270
+ if po.is_a?(Hash)
271
+ po.each do |host, docker|
272
+ res << "-p #{host}:#{docker}"
273
+ end
247
274
  end
275
+ #po = [po] if not po.is_a?(Array)
276
+ #po.each do |e|
277
+ # # 1st is port on host
278
+ # # 2nd is port inside container
279
+ # res << "-p #{e.keys.first}:#{e.values.first}"
280
+ #end
248
281
  res.join(" ")
249
282
  else
250
283
  ""
@@ -253,15 +286,17 @@ module Docker
253
286
  end
254
287
 
255
288
  def logger
256
- if @logger.nil?
257
- @logger = TeLogger::Tlogger.new
258
- @logger.tag = :docker_cmd
259
- end
260
- @logger
289
+ Cli.logger(:cmdFact)
261
290
  end
262
291
 
263
- def parse_container_list(out, &block)
264
-
292
+ def build_add_user_script
293
+ path = File.join(File.dirname(__FILE__),"..","..","..","scripts","create_user.sh.erb")
294
+ if File.exist?(path)
295
+ ui = UserInfo.user_info
296
+ gi = UserInfo.group_info
297
+
298
+ 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] })
299
+ end
265
300
  end
266
301
 
267
302
  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