docker-cli 0.3.0 → 0.5.0

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.
@@ -0,0 +1,53 @@
1
+
2
+ require 'toolrack'
3
+ require_relative 'run_keep'
4
+ require_relative 'run_del'
5
+ require_relative 'run'
6
+
7
+ module Docker
8
+ module Cli
9
+ class ArgsParser
10
+ include TR::ArgUtils
11
+
12
+ class ArgsParserException < StandardError; end
13
+
14
+ OpsOption = [
15
+ "run-keep", "rk",
16
+ "run-del","rd",
17
+ "run","r"
18
+ ]
19
+
20
+ arg_spec do
21
+
22
+ callback :pre_processing do |argv|
23
+ select_runner(argv)
24
+ end
25
+
26
+ end
27
+
28
+ def select_runner(argv)
29
+ ops = argv.first
30
+ if is_empty?(ops)
31
+ raise ArgsParserException, "\n Operation is empty. First parameter is operation. Supported operations including : #{OpsOption.join(", ")}\n\n"
32
+ else
33
+ case ops
34
+ when "run-keep", "rk"
35
+ Docker::Cli::Operations::RunKeep.new.parse_argv(argv[1..-1])
36
+
37
+ when "run-del", "rd"
38
+ Docker::Cli::Operations::RunDel.new.parse_argv(argv[1..-1])
39
+
40
+ when "run", "r"
41
+ Docker::Cli::Operations::Run.new.run
42
+
43
+ else
44
+ raise ArgsParserException, " Unknown operation '#{ops}'. First parameter is operation. Supported operations including : #{OpsOption.join(", ")}\n"
45
+ end
46
+ end
47
+
48
+ [true, argv[1..-1]]
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,203 @@
1
+
2
+ require 'securerandom'
3
+ require 'tty/prompt'
4
+ require_relative '../dockerfile'
5
+
6
+ module Docker
7
+ module Cli
8
+ module Operations
9
+
10
+ # Normal run by finding Dockerfile
11
+ # By default is interactive
12
+ class Run
13
+
14
+ def initialize
15
+ @pmt = TTY::Prompt.new
16
+ end
17
+
18
+ def run
19
+
20
+ # find dockerfile to build an image
21
+ df = Dockerfile.find_available
22
+ raise NoDockerfileFound, "No Dockerfile found. Please create one and re-run this operation" if df.length == 0
23
+
24
+ if df.length > 1
25
+ @selDf = @pmt.select(" Please select one of the Dockerfile to execute : ") do |m|
26
+ df.each do |f|
27
+ m.choice f, f
28
+ end
29
+ end
30
+ else
31
+ @selDf = df.first
32
+ end
33
+
34
+ @mount_root = @pmt.ask(" Please provide a root for folder mount into Docker env : ", default: "/opt", required: true)
35
+
36
+ df = Dockerfile.new(@selDf)
37
+ # parameter pass in is to build the template
38
+ # e.g. docker_root is to build the dup_gem_bundler_env directive
39
+ ndf = df.render_dockerfile(docker_root: @mount_root)
40
+
41
+ @dev_gems = {}
42
+ devGems = Cli.find_dev_gems
43
+ if devGems.length > 0
44
+ devGems.each do |k,v|
45
+ @dev_gems[v] = File.join(@mount_root, File.basename(v))
46
+ end
47
+ end
48
+
49
+ dfName = @pmt.ask(" Please provide the new name for the generated Dockerfile : ", required: true, default: "Dockerfile.docli")
50
+ dfPath = File.join(Dir.getwd, dfName)
51
+ File.open(dfPath,"w") do |f|
52
+ f.write ndf
53
+ end
54
+
55
+ if Dockerfile.run_before?(dfPath)
56
+ proceed = @pmt.yes?(" Given dockerfile '#{@selDf}' seems already run before. Do you want to use existing image instead? ")
57
+ if proceed
58
+ img = Dockerfile.images(dfPath)
59
+ if img.length > 1
60
+ @selImg = @pmt.select(" There are multiple images being run from the same Dockerfile. Please select one of them : ") do |m|
61
+ img.each do |i|
62
+ m.choice i, i
63
+ end
64
+ end
65
+ elsif img.length > 0
66
+ @selImg = img.first
67
+ end
68
+
69
+ else
70
+ # not using existing image.. built one
71
+ #@df, @selImg = build_image_from_dockerfile_bin(ndf)
72
+ @selImg = build_image_from_dockerfile(dfPath, dfName)
73
+ end
74
+
75
+ else
76
+ #logger.debug "Dockerfile not being run before"
77
+ #@df, @selImg = build_image_from_dockerfile_bin(ndf) # =>
78
+ @selImg = build_image_from_dockerfile(dfPath, dfName)
79
+ end
80
+
81
+ logger.debug "selected image : #{@selImg}"
82
+
83
+ di = DockerImage.new(@selImg)
84
+ if di.has_containers?
85
+ if di.containers.length > 1
86
+ @selCont = @pmt.select(" Please select one of the container to run : ") do |m|
87
+
88
+ di.containers.each do |c|
89
+ m.choice c.name_for_display, c
90
+ end
91
+
92
+ m.choice "New container", :new
93
+
94
+ end
95
+
96
+ else
97
+ @selCont = di.containers.first
98
+ end
99
+
100
+ end # has_containers?
101
+
102
+
103
+ case @selCont
104
+ when :new, nil
105
+ @selCont = @pmt.ask(" Please provide a new container name : ", required: true, default: "#{File.basename(Dir.getwd)}_#{SecureRandom.hex(4)}")
106
+
107
+ cp = ContainerProfile.new
108
+ if devGems.length > 0
109
+ devGems.each do |name, path|
110
+ cp.add_mount_point(path, File.join(@mount_root, name))
111
+ end
112
+ end
113
+
114
+ # add current dir as mount point
115
+ cp.add_mount_point(Dir.getwd, File.join(@mount_root, File.basename(Dir.getwd)))
116
+
117
+ while true
118
+ STDOUT.puts "\n\n Mount points : \n"
119
+ ctn = 1
120
+ cp.mount_points.each do |local, docker|
121
+ STDOUT.puts " #{ctn}. #{local} ==> #{docker}"
122
+ end
123
+ apath = @pmt.ask("\n Please provide full path to mount in the docker (just enter if done) : ")
124
+ break if is_empty?(apath)
125
+
126
+ if File.exist?(apath)
127
+ mpath = @pmt.ask(" Please provide mount point inside the docker : ", default: File.dirname(apath))
128
+ cp.add_mount_point(mpath, File.join(@mount_root, File.basename(mpath)))
129
+ else
130
+ STDERR.puts "Given path '#{apath}' doesn't exist. Please try again."
131
+ end
132
+ end
133
+
134
+ cmd = @pmt.ask(" What command should be inside the docker? : ", required: true, default: "/bin/bash" )
135
+ cp.run_command = cmd
136
+ cp.image_name = @selImg
137
+
138
+ dc = DockerContainer.new(@selCont)
139
+ dc.create(cp)
140
+ DockerRunLog.instance.log(@selImg, @selCont)
141
+
142
+ else
143
+
144
+ #cmd = @pmt.ask(" What command should be inside the docker? : ", required: true, default: "/bin/bash" )
145
+ dc = DockerContainer.new(@selCont.name)
146
+ dc.start
147
+ dc.attach
148
+ #dc.run(cmd)
149
+
150
+ end
151
+
152
+
153
+ end
154
+
155
+ def build_image_from_dockerfile(df, dfName)
156
+
157
+ iName = File.basename(Dir.getwd)
158
+ name = @pmt.ask(" Please provide an image name for Dockerfile '#{dfName}' : ", required: true, default: "#{iName}_image")
159
+ ctx = @pmt.ask(" Context to run to the dockerfile? ", required: true, default: ".")
160
+
161
+ DockerImage.build(name, dfName ,ctx)
162
+ DockerRunLog.instance.log_dockerfile_image(df, name)
163
+
164
+ name
165
+
166
+ end
167
+
168
+ #def build_image_from_dockerfile_bin(df)
169
+ # #raise NoDockerfileFound, "Given Dockerfile to build image '#{df}' does not exist" if not File.exist?(df)
170
+
171
+ # dfName = @pmt.ask(" Please provide the new name for the generated Dockerfile : ", required: true, default: "Dockerfile.docli")
172
+ # path = File.join(Dir.getwd, dfName)
173
+ # dfName = File.basename(path)
174
+ # if not_empty?(df)
175
+ # File.open(path,"w") do |f|
176
+ # f.write df
177
+ # end
178
+ # end
179
+ #
180
+ # iName = File.basename(Dir.getwd)
181
+ # name = @pmt.ask(" Please provide an image name for Dockerfile '#{dfName}' : ", required: true, default: "#{iName}_image")
182
+ # ctx = @pmt.ask(" Context to run to the dockerfile? ", required: true, default: ".")
183
+
184
+ # DockerImage.build(name, dfName ,ctx)
185
+ # DockerRunLog.instance.log_dockerfile_image(df, name)
186
+
187
+ # [dfName, name]
188
+ #end
189
+
190
+
191
+ private
192
+ def logger
193
+ if @_logger.nil?
194
+ @_logger = Cli.logger(:run_ops)
195
+ end
196
+ @_logger
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,67 @@
1
+
2
+ module Docker
3
+ module Cli
4
+ module Operations
5
+ class RunDel
6
+ include TR::ArgUtils
7
+
8
+ arg_spec do
9
+
10
+ callback :pre_processing do |a|
11
+ capture_image(a)
12
+ end
13
+
14
+ opt "-c", "Command to be executed inside the Docker" do |a|
15
+ capture_command(a)
16
+ end
17
+
18
+ opt "-u", "Run as current user for Docker" do
19
+ set_use_same_user(true)
20
+ end
21
+
22
+ callback :post_processing do |a|
23
+ run
24
+ end
25
+
26
+ end
27
+
28
+ def initialize
29
+ @match_user = false
30
+ # leave this blank as the image may have already
31
+ # set an entry program
32
+ @cmd = ""
33
+ end
34
+
35
+ def capture_image(a)
36
+ @dimage = a.first
37
+ [true, a[1..-1]]
38
+ end
39
+
40
+ def capture_command(a)
41
+ @cmd = a
42
+ end
43
+
44
+ def set_use_same_user(bol)
45
+ @match_user = bol
46
+ end
47
+
48
+ # Just run with image name on command line
49
+ def run
50
+
51
+ mountLocal = Dir.getwd
52
+ mountDocker = "/opt/#{File.basename(Dir.getwd)}"
53
+ if TR::RTUtils.on_linux? and @match_user
54
+ # This approach has user match with local user but no name on the docker
55
+ # workable not nice only
56
+ Docker::Cli::DockerContainer.create_container(@dimage, interactive: true, tty: true, command: @cmd, mount: { mountLocal => mountDocker }, match_user: @match_user, del: true)
57
+ else
58
+ # Apparently on Mac and Windows, the user issue is not an issue
59
+ Docker::Cli::DockerContainer.create_container(@dimage, interactive: true, tty: true, command: @cmd, mount: { mountLocal => mountDocker }, del: true)
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,118 @@
1
+
2
+ require 'tty/prompt'
3
+ require_relative '../docker_run_log'
4
+
5
+ module Docker
6
+ module Cli
7
+ module Operations
8
+ class RunKeep
9
+ include TR::ArgUtils
10
+
11
+ arg_spec do
12
+
13
+ callback :pre_processing do |a|
14
+ capture_image(a)
15
+ end
16
+
17
+ opt "-c", "Command to be executed inside the Docker" do |a|
18
+ capture_command(a)
19
+ end
20
+
21
+ opt "-u", "Run as current user for Docker" do
22
+ set_use_same_user(true)
23
+ end
24
+
25
+ opt "-n", "Name of the container" do |a|
26
+ capture_container_name(a)
27
+ end
28
+
29
+ callback :post_processing do |a|
30
+ run
31
+ end
32
+
33
+ end
34
+
35
+ def initialize
36
+ @match_user = false #TR::RTUtils.on_linux?
37
+ # leave this blank as the image may have already
38
+ # set an entry program
39
+ @cmd = ""
40
+ end
41
+
42
+ def capture_image(a)
43
+ @fullArgv = a
44
+ @dimage = a.first
45
+ [true, a[1..-1]]
46
+ end
47
+
48
+ def capture_command(a)
49
+ logger.debug "Capturing command : #{a}"
50
+ @cmd = a
51
+ end
52
+
53
+ def capture_container_name(a)
54
+ @contName = a
55
+ end
56
+
57
+ def set_use_same_user(bol)
58
+ @match_user = bol
59
+ end
60
+
61
+ # Just run with image name on command line
62
+ def run
63
+
64
+ if Docker::Cli::DockerRunLog.instance.has_existing_container?(@dimage)
65
+ pmt = TTY::Prompt.new
66
+ begin
67
+ eCont = pmt.select(" System found there were some container already exist on this image.\n Do you want to reuse the existing container? ") do |m|
68
+ DockerContainer.containers_of_image_from_history(@dimage).each do |c, name|
69
+ m.choice name, c
70
+ end
71
+ m.choice "Run new container", :new_cont
72
+ m.choice "Quit", :quit
73
+ end
74
+
75
+ case eCont
76
+ when :new_cont
77
+ run_new
78
+ when :quit
79
+ STDOUT.puts " Have a nice day "
80
+ else
81
+ cont = DockerContainer.new(eCont)
82
+ cont.start if not cont.is_running?
83
+ cont.attach
84
+ end
85
+ rescue TTY::Reader::InputInterrupt
86
+ end
87
+ else
88
+ run_new
89
+ end
90
+
91
+ end
92
+
93
+ private
94
+ def run_new
95
+ mountLocal = Dir.getwd
96
+ mountDocker = "/opt/#{File.basename(Dir.getwd)}"
97
+ contName = @contName || SecureRandom.hex(18)
98
+ if TR::RTUtils.on_linux? and @match_user
99
+ # This approach has user match with local user but no name on the docker
100
+ # workable not nice only
101
+ Docker::Cli::DockerContainer.create_container(@dimage, interactive: true, tty: true, command: @cmd, mount: { mountLocal => mountDocker }, match_user: @match_user, container_name: contName)
102
+ else
103
+ # Apparently on Mac and Windows, the user issue is not an issue
104
+ Docker::Cli::DockerContainer.create_container(@dimage, interactive: true, tty: true, command: @cmd, mount: { mountLocal => mountDocker }, container_name: contName)
105
+ end
106
+
107
+ Docker::Cli::DockerRunLog.instance.log(@dimage, contName, argv: @fullArgv)
108
+
109
+ end
110
+
111
+ def logger
112
+ Cli.logger(:rk)
113
+ end
114
+
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require 'etc'
3
+
4
+ module Docker
5
+ module Cli
6
+
7
+ module UserInfo
8
+ include TR::CondUtils
9
+
10
+ def self.user_info(login = nil)
11
+ login = Etc.getlogin if is_empty?(login)
12
+ res = { login: login }
13
+ begin
14
+ res[:uid] = Etc.getpwnam(login).uid
15
+ rescue Exception => ex
16
+ res[:uid] = nil
17
+ end
18
+ res
19
+ end
20
+
21
+ def self.group_info(login = nil)
22
+ login = Etc.getlogin if is_empty?(login)
23
+ res = { }
24
+ begin
25
+ gnm = Etc.getgrnam(login)
26
+ res[:group_name] = gnm.name
27
+ res[:gid] = gnm.gid
28
+ rescue Exception => ex
29
+ p ex
30
+ res[:group_name] = ""
31
+ res[:gid] = nil
32
+ end
33
+ res
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Docker
4
4
  module Cli
5
- VERSION = "0.3.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
data/lib/docker/cli.rb CHANGED
@@ -9,9 +9,21 @@ require_relative "cli/version"
9
9
  require_relative 'cli/command'
10
10
  require_relative 'cli/command_factory'
11
11
 
12
+ require_relative 'cli/docker_image'
13
+ require_relative 'cli/docker_container'
14
+ require_relative 'cli/docker_composer'
15
+
16
+ require_relative 'cli/dockerfile_template'
17
+
12
18
  module Docker
13
19
  module Cli
20
+ include TR::CondUtils
21
+
14
22
  class Error < StandardError; end
23
+ class RuntimeException < StandardError; end
24
+ class CommandFailed < StandardError; end
25
+ class IndefiniteOption < StandardError; end
26
+ class NoDockerfileFound < StandardError; end
15
27
  # Your code goes here...
16
28
 
17
29
  def Cli.docker_exe
@@ -25,5 +37,57 @@ module Docker
25
37
 
26
38
  end
27
39
 
40
+ def self.find_dev_gems
41
+ if @_devGems.nil?
42
+ @_devGems = {}
43
+ Bundler.load.dependencies.each do |d|
44
+ if not d.source.nil?
45
+ src = d.source
46
+ if src.path.to_s != "."
47
+ @_devGems[d.name] = src.path.expand_path.to_s
48
+ end
49
+ end
50
+ end
51
+ end
52
+ @_devGems
53
+ end
54
+
55
+ def self.digest_bin(bin)
56
+ OpenSSL::Digest.new("SHA3-256").hexdigest(bin)
57
+ end
58
+
59
+ def self.command_output(out)
60
+ if out.is_a?(Array)
61
+ out.each do |e|
62
+ STDOUT.puts " ## #{e}"
63
+ end
64
+ else
65
+ STDOUT.puts " ## #{out}"
66
+ end
67
+ end
68
+
69
+ def self.logger(tag = nil, &block)
70
+ if @_logger.nil?
71
+ @_logger = TeLogger::Tlogger.new(STDOUT)
72
+ end
73
+
74
+ if block
75
+ if not_empty?(tag)
76
+ @_logger.with_tag(tag, &block)
77
+ else
78
+ @_logger.with_tag(@_logger.tag, &block)
79
+ end
80
+ else
81
+ if is_empty?(tag)
82
+ @_logger.tag = :docker_cli
83
+ @_logger
84
+ else
85
+ # no block but tag is given? hmm
86
+ @_logger.tag = tag
87
+ @_logger
88
+ end
89
+ end
90
+ end
91
+
28
92
  end
29
93
  end
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ # This is mostly a test. May not work across different variant of linux
4
+
5
+ groupadd -f -g <%= user_group_id %> <%= user_group_name %> && useradd -u <%= user_id %> -g <%= user_group_id %> -m <%= user_login %> && usermod -aG sudo <%= user_login %> && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
6
+
7
+ tail -f /dev/null
8
+ #while true; do sleep 1000; done
9
+ #exec /bin/bash
10
+