docker-cli 0.3.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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