docker-cli 0.3.1 → 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,169 @@
1
+
2
+ require 'singleton'
3
+ require 'yaml'
4
+
5
+ module Docker
6
+ module Cli
7
+
8
+ class NonEmptyRecord < StandardError; end
9
+
10
+ class DockerRunLog
11
+ include TR::CondUtils
12
+ include Singleton
13
+
14
+ def log(image, container, opts = {})
15
+ if not_empty?(image) and not_empty?(container)
16
+ logfile[image] = [] if logfile[image].nil?
17
+ cont = { container: container, created_at: Time.now.to_i, last_run: Time.now.to_i }
18
+ cont = cont.merge(opts) if not_empty?(opts)
19
+ logfile[image] << cont
20
+ write
21
+ end
22
+ end
23
+
24
+ #def log_dockerfile(df)
25
+ # if not_empty?(df) and File.exist?(df)
26
+ # logfile[:dockerfile_signature] = [] if logfile[:dockerfile_signature].nil?
27
+ # d = digest_file(df)
28
+ # if not logfile[:dockerfile_signature].include?(d)
29
+ # logfile[:dockerfile_signature] << digest.hexdigest(File.read(df))
30
+ # end
31
+ # write
32
+ # end
33
+ #end
34
+
35
+ def log_dockerfile_image(df, image)
36
+ if not_empty?(df) and File.exist?(df) and not_empty?(image)
37
+ logfile[:dockerfile_images] = { } if logfile[:dockerfile_images].nil?
38
+ d = digest_file(df)
39
+ logfile[:dockerfile_images][d] = [] if logfile[:dockerfile_images][d].nil?
40
+ logfile[:dockerfile_images][d] << image
41
+ write
42
+ end
43
+ end
44
+
45
+ def has_dockerfile_built_to_image?(df)
46
+ if not_empty?(df)
47
+ if File.exist?(df)
48
+ d = digest_file(df)
49
+ else
50
+ d = df
51
+ end
52
+
53
+ not (logfile[:dockerfile_images].nil? or logfile[:dockerfile_images][d].nil?)
54
+ end
55
+ end
56
+
57
+ def dockerfile_images(df)
58
+ if File.exist?(df)
59
+ d = digest_file(df)
60
+ else
61
+ d = df
62
+ end
63
+
64
+ if (logfile[:dockerfile_images].nil? or logfile[:dockerfile_images][d].nil?)
65
+ []
66
+ else
67
+ logfile[:dockerfile_images][d]
68
+ end
69
+ end
70
+
71
+ def has_dockerfile_seen_before?(df)
72
+ logger.debug "dockerfile_seen_before? #{df}"
73
+ if not_empty?(df) and File.exist?(df)
74
+ d = Cli.digest_bin(File.read(df))
75
+ logger.debug "Digest : #{d}"
76
+ logger.debug "Record : #{logfile[:dockerfile_images]}"
77
+ if not logfile[:dockerfile_images].nil?
78
+ logfile[:dockerfile_images].include?(d)
79
+ else
80
+ false
81
+ end
82
+ else
83
+ false
84
+ end
85
+ end
86
+
87
+ def digest_file(path)
88
+ if not_empty?(path) and File.exist?(path)
89
+ Cli.digest_bin(File.read(path))
90
+ else
91
+ ""
92
+ end
93
+ end
94
+
95
+ def image_has_containers?(image)
96
+ not logfile[image].nil? and logfile[image].length > 0
97
+ end
98
+
99
+ def delete_image(image, opts = {})
100
+ if logfile[image].nil? or is_empty?(logfile[image])
101
+ logfile.delete(image)
102
+ elsif not_empty?(opts) and opts[:force] == true
103
+ logfile.delete(image)
104
+ else
105
+ raise NonEmptyRecord, "Image #{image} has #{logfile[image].length} container(s). Remove image failed."
106
+ end
107
+ end
108
+
109
+ def update_last_run(image, cont)
110
+ if not logfile[image].nil? and not logfile[image][cont].nil?
111
+ logfile[image][cont][:last_run] = Time.now.to_i
112
+ write
113
+ end
114
+ end
115
+
116
+ def image_containers(image)
117
+ if not logfile[image].nil?
118
+ logfile[image]
119
+ else
120
+ []
121
+ end
122
+ end
123
+
124
+ def all_logs
125
+ logfile.freeze
126
+ end
127
+
128
+ private
129
+ def logfile
130
+ if @_logfile.nil?
131
+ if File.exist?(log_path)
132
+ @_logfile = YAML.load(File.read(log_path))
133
+ else
134
+ @_logfile = {}
135
+ end
136
+ end
137
+ @_logfile
138
+ end
139
+
140
+ def write
141
+ File.open(log_path,"w") do |f|
142
+ f.write YAML.dump(logfile)
143
+ end
144
+ end
145
+
146
+ def log_path
147
+ if @_logPath.nil?
148
+ @_logPath = File.join(Dir.getwd, ".docker_run_log")
149
+ end
150
+ @_logPath
151
+ end
152
+
153
+ def digest
154
+ if @_digest.nil?
155
+ @_digest = Cli.digest
156
+ end
157
+ @_digest
158
+ end
159
+
160
+ def logger
161
+ if @_logger.nil?
162
+ @_logger = Cli.logger(:drLog)
163
+ end
164
+ @_logger
165
+ end
166
+
167
+ end # class DockerRunLog
168
+ end
169
+ end
@@ -0,0 +1,62 @@
1
+
2
+ require 'openssl'
3
+
4
+ module Docker
5
+ module Cli
6
+ class Dockerfile
7
+
8
+ class NoDockerfileFound < StandardError; end
9
+
10
+ def self.find_available(root = Dir.getwd)
11
+ Dir.glob("**/Dockerfile*")
12
+ end
13
+
14
+ def self.run_before?(dockerfile_path)
15
+ DockerRunLog.instance.has_dockerfile_seen_before?(dockerfile_path)
16
+ end
17
+
18
+ # expect dockerfile is CONTENT, not file path
19
+ def self.images(dockerfile)
20
+ DockerRunLog.instance.dockerfile_images(dockerfile)
21
+ end
22
+
23
+ def initialize(file)
24
+ @dfile = file
25
+ end
26
+
27
+ def render_dockerfile(vals = {}, &block)
28
+ if @_df.nil?
29
+ if @dfile.nil?
30
+ @_df = nil
31
+ else
32
+ if File.exist?(@dfile)
33
+ if is_erb_template?
34
+ @_df = process_dockerfile_template(@dfile, vals)
35
+ else
36
+ @_df = File.read(@dfile)
37
+ end
38
+ else
39
+ @_df = nil
40
+ end
41
+ end
42
+ end
43
+ @_df
44
+ end
45
+
46
+ def is_erb_template?
47
+ if File.exist?(@dfile)
48
+ cont = File.read(@dfile)
49
+ (cont =~ /<%=/ and cont =~ /%>/) != nil
50
+ else
51
+ false
52
+ end
53
+ end
54
+
55
+ def process_dockerfile_template(file, values = {})
56
+ raise Error, "Given dockerfile to process as template not found" if not File.exist?(file)
57
+ DockerfileTemplate::TemplateEngine.new.process(File.read(file), values)
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,73 @@
1
+
2
+ module Docker
3
+ module Cli
4
+ module DockerfileTemplate
5
+ module DupGemBundlerEnv
6
+
7
+ # DSL entry by including into DockerfileTemplate module
8
+ def dup_gem_bundler_env(&block)
9
+ if has_dev_gems?
10
+ logger.debug "Detected development gems"
11
+
12
+ #add_mandatory_key(:docker_root)
13
+ #if not has_mandatory_keys? and block
14
+ # @docker_root = block.call(:docker_root)
15
+ #else
16
+ raise TemplateKeyRequired, "docker_root is required for dup_gem_bundler_env to function" if is_empty?(@docker_root)
17
+ #end
18
+
19
+ # gen shell script
20
+ res = gen_script
21
+ block.call(:script_output, res) if block
22
+ localPath = File.join(Dir.getwd,"dup_gem_bundler_env.rb")
23
+ File.open(localPath,"w") do |f|
24
+ f.write res
25
+ end
26
+
27
+ inst = []
28
+ # copy inside docker
29
+ inst << "COPY #{File.basename(localPath)} /tmp/dup_gem_bundler_env.rb"
30
+ # run the script
31
+ inst << "RUN ruby /tmp/dup_gem_bundler_env.rb"
32
+ # for the docker just this two lines
33
+ # but the localPath must be there first before this two
34
+ # lines can come into effect
35
+ inst.join("\n")
36
+ else
37
+ ""
38
+ end
39
+ end
40
+
41
+ private
42
+ def has_dev_gems?
43
+ not Cli.find_dev_gems.empty?
44
+ end
45
+
46
+ def gen_script
47
+
48
+ res = %Q(
49
+ #!/usr/bin/env ruby
50
+
51
+ ## This file is auto-generated.
52
+
53
+ <% Docker::Cli.find_dev_gems.each do |name, pa| %>
54
+ `bundle config --global local.<%= name %> <%= File.join(@docker_root, File.basename(pa)) %>`
55
+ <% end %>
56
+ )
57
+
58
+ ERB.new(res).result(binding)
59
+
60
+ end
61
+
62
+ def logger
63
+ if @_logger
64
+ @_logger = Cli.logger(:temp_dup_gem_bundler_env)
65
+ end
66
+ @_logger
67
+ end
68
+
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,38 @@
1
+
2
+ require 'erb'
3
+ require_relative '../user_info'
4
+
5
+ module Docker
6
+ module Cli
7
+ module DockerfileTemplate
8
+ module MatchUser
9
+
10
+ # DSL entry
11
+ def match_user
12
+
13
+ logger.debug "match_user called"
14
+ ui = UserInfo.user_info
15
+ gi = UserInfo.group_info
16
+
17
+ ERB.new(user_template).result_with_hash({ user_group_id: gi[:gid], user_group_name: gi[:group_name], user_id: ui[:uid], user_login: ui[:login] })
18
+
19
+ end
20
+
21
+ private
22
+ def user_template
23
+ if @_ut.nil?
24
+ @_ut = []
25
+ @_ut << "RUN apt-get install -y sudo && 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"
26
+ @_ut << "USER <%= user_login %>"
27
+ end
28
+ @_ut.join("\n")
29
+ end
30
+
31
+ def logger
32
+ Cli.logger(:temp_match_user)
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,69 @@
1
+
2
+ Dir.glob(File.join(File.dirname(__FILE__),"dockerfile_template","*.rb")).each do |f|
3
+ require_relative f
4
+ end
5
+
6
+ module Docker
7
+ module Cli
8
+ module DockerfileTemplate
9
+ class TemplateKeyRequired < StandardError; end
10
+ class TemplateEngine
11
+ include MatchUser
12
+ include DupGemBundlerEnv
13
+
14
+ def process(cont, values = {}, &block)
15
+ logger.debug "Got values : #{values}"
16
+ values.each do |k,v|
17
+
18
+ logger.debug "Creating field #{k}"
19
+
20
+ self.class.class_eval <<-END
21
+ if not (Class.instance_methods.include?(:#{k}) and Class.instace_methods.include?(:#{k}=))
22
+ attr_accessor :#{k}
23
+ elsif not Class.instance_methods.include?(:#{k})
24
+ attr_reader :#{k}
25
+ elsif not Class.instance_methods.include?(:#{k}=)
26
+ attr_writer :#{k}
27
+ end
28
+ END
29
+
30
+ self.send("#{k}=", v)
31
+ end
32
+
33
+
34
+ ERB.new(cont).result(binding)
35
+ end
36
+
37
+ private
38
+ def logger
39
+ if @_logger.nil?
40
+ @_logger = Cli.logger(:df_template)
41
+ end
42
+ @_logger
43
+ end
44
+
45
+ def add_mandatory_key(key)
46
+ if @_man.nil?
47
+ @_man = []
48
+ end
49
+ @_man << key if not_empty?(key)
50
+ end
51
+
52
+ def mandatory_keys
53
+ @_man
54
+ end
55
+
56
+ def has_mandatory_keys?
57
+ given = true
58
+ mandatory_keys.each do |mk|
59
+ given = Class.instance_methods.include?(mk.to_sym) and Class.instance_methods.include?("#{mk}=".to_sym)
60
+ break if not given
61
+ end
62
+
63
+ given
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,25 @@
1
+
2
+ require 'bundler'
3
+
4
+ module Docker
5
+ module Cli
6
+ module BundlerHelper
7
+
8
+ def find_local_dev_gems
9
+
10
+ res = {}
11
+ Bundler.load.dependencies.each do |d|
12
+ if not d.source.nil?
13
+ src = d.source
14
+ if src.path.to_s != "."
15
+ res[d.name] = src.path.expand_path.to_s
16
+ end
17
+ end
18
+ end
19
+ res
20
+
21
+ end # find_local_dev_gem
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+
2
+
3
+ module Docker
4
+ module Cli
5
+ module ImageHelper
6
+
7
+ def build_image(pmt, cmdFact)
8
+
9
+ root = Dir.getwd
10
+ dockerfile = File.join(root, "Dockerfile")
11
+
12
+ again = true
13
+ while again
14
+ if not File.exist?(dockerfile)
15
+ dockerfile = pmt.ask(" #{dockerfile} does not exist. Please provide new location of Dockerfile: ", required: true)
16
+ else
17
+ again = false
18
+ end
19
+ end
20
+
21
+ again = true
22
+ while again
23
+ dname = pmt.ask(" Please provide name of image at local : ", required: true)
24
+ if cmdFact.is_image_exist?(dname)
25
+
26
+ reuse = pmt.yes?(" Given local image name '#{dname}' already taken. Use back the same image? 'No' to retry with new name : ")
27
+ if reuse
28
+ again = false
29
+ end
30
+ else
31
+ rv = cmdFact.build_image(dname, dockerfile: dockerfile)
32
+ raise CommandFailed, "Build image command failed. Error was : #{rv.err_stream}"
33
+ again = false
34
+ end
35
+ end
36
+
37
+ dname
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -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