kamaze-docker_image 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +6 -0
  3. data/.yardopts +16 -0
  4. data/lib/kamaze-docker_image.rb +24 -0
  5. data/lib/kamaze/docker_image.rb +223 -0
  6. data/lib/kamaze/docker_image/command.rb +79 -0
  7. data/lib/kamaze/docker_image/concern.rb +22 -0
  8. data/lib/kamaze/docker_image/concern/containers.rb +75 -0
  9. data/lib/kamaze/docker_image/concern/docker.rb +36 -0
  10. data/lib/kamaze/docker_image/concern/executable.rb +24 -0
  11. data/lib/kamaze/docker_image/concern/readable_attrs.rb +48 -0
  12. data/lib/kamaze/docker_image/concern/setup.rb +98 -0
  13. data/lib/kamaze/docker_image/concern/setup/config.rb +35 -0
  14. data/lib/kamaze/docker_image/loader.rb +61 -0
  15. data/lib/kamaze/docker_image/loader/context.rb +57 -0
  16. data/lib/kamaze/docker_image/loader/helper.rb +99 -0
  17. data/lib/kamaze/docker_image/loader/tasks.rb +22 -0
  18. data/lib/kamaze/docker_image/loader/tasks/build.rb +23 -0
  19. data/lib/kamaze/docker_image/loader/tasks/exec.rb +19 -0
  20. data/lib/kamaze/docker_image/loader/tasks/push.rb +19 -0
  21. data/lib/kamaze/docker_image/loader/tasks/restart.rb +21 -0
  22. data/lib/kamaze/docker_image/loader/tasks/run.rb +19 -0
  23. data/lib/kamaze/docker_image/loader/tasks/ssh.rb +19 -0
  24. data/lib/kamaze/docker_image/loader/tasks/start.rb +19 -0
  25. data/lib/kamaze/docker_image/loader/tasks/stop.rb +19 -0
  26. data/lib/kamaze/docker_image/runner.rb +126 -0
  27. data/lib/kamaze/docker_image/runner/storage.rb +78 -0
  28. data/lib/kamaze/docker_image/ssh.rb +143 -0
  29. data/lib/kamaze/docker_image/version.rb +13 -0
  30. data/lib/kamaze/docker_image/version.yml +17 -0
  31. metadata +99 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fad5772cb626cf0f9a7be4b64b3c5f32dd14daff83f8eccc6345e22d5120b8aa
4
+ data.tar.gz: ae5b2cfd9b17dba7827f5e7d88763c6bee9e24dc55b6f567661fb147b0e1f89d
5
+ SHA512:
6
+ metadata.gz: 073c70b2161a1d37569e3fe44ff94447a8219f31bae85518d97e59a9c098569c9d75739c3d3c427c6cf506d51a1125cb5e3230669071e874a565955be0e87893
7
+ data.tar.gz: 7f2c5d696672fdb98f8d696ebb5185ed1b0df1bd695b99277bfc27922635b3da522ec29aeefdde1d7798f0c49828220f63cf70bd73e2af7166f9ab668a1232b4
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ inherit_gem:
3
+ kamaze-project:
4
+ - .rubocop.yml
5
+ AllCops:
6
+ NewCops: disable
data/.yardopts ADDED
@@ -0,0 +1,16 @@
1
+ # vim: ft=sh
2
+
3
+ lib/**/*.rb \
4
+ --no-progress \
5
+ --markup-provider 'redcarpet' \
6
+ --markup 'markdown' \
7
+ --charset 'utf-8' \
8
+ --protected --private --embed-mixins \
9
+ --tag type:'type' --hide-tag 'type' \
10
+ --readme README.md \
11
+ --exclude '_flymake\\.rb$' \
12
+ --exclude '/\\.#'
13
+
14
+ # Local Variables:
15
+ # mode: sh
16
+ # End:
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ $LOAD_PATH.unshift(__dir__)
10
+
11
+ lock = Dir.chdir("#{__dir__}/..") do
12
+ [['gems.rb', 'gems.locked'], ['Gemfile', 'Gemfile.lock']]
13
+ .map { |m| Dir.glob(m).size >= 2 }
14
+ .include?(true)
15
+ end
16
+
17
+ if lock
18
+ require 'rubygems'
19
+ require 'bundler/setup'
20
+
21
+ if Gem::Specification.find_all_by_name('kamaze-project').any?
22
+ require 'kamaze/project/core_ext/pp'
23
+ end
24
+ end
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ # rubocop:disable Style/Documentation
10
+
11
+ module Kamaze
12
+ end
13
+
14
+ # rubocop:enable Style/Documentation
15
+
16
+ # Describe a docker image
17
+ class Kamaze::DockerImage
18
+ # Get commands
19
+ #
20
+ # Commands as run by runner
21
+ #
22
+ # @see Kamaze::DockerImage::Runner#command
23
+ # @see Kamaze::DockerImage::Concern::Setup#default_commands
24
+ #
25
+ # @return [Hash]
26
+ attr_reader :commands
27
+
28
+ # Get image name
29
+ #
30
+ # @return [String]
31
+ attr_reader :name
32
+
33
+ # Get version
34
+ #
35
+ # @return [String]
36
+ attr_reader :version
37
+
38
+ # Get namespace used for tasks
39
+ #
40
+ # @return [String|Symbol|nil]
41
+ attr_reader :tasks_ns
42
+
43
+ # Get name used to run container
44
+ #
45
+ # @return [String]
46
+ attr_reader :run_as
47
+
48
+ # Config related to ssh.
49
+ #
50
+ # @return [Hash|nil]
51
+ attr_reader :ssh
52
+
53
+ # Executable path or name for ``docker``
54
+ #
55
+ # @return [String]
56
+ attr_reader :docker_bin
57
+
58
+ attr_reader :tasks_load
59
+
60
+ # Get default command for ``exec``
61
+ #
62
+ # @see Runner#exec
63
+ #
64
+ # @return [String]
65
+ attr_reader :exec_command
66
+
67
+ autoload(:Pathname, 'pathname')
68
+ autoload(:Open3, 'open3')
69
+ autoload(:JSON, 'json')
70
+
71
+ {
72
+ Concern: 'concern',
73
+ Command: 'command',
74
+ Runner: 'runner',
75
+ SSH: 'ssh',
76
+ Loader: 'loader',
77
+ VERSION: 'version',
78
+ }.each { |k, v| autoload(k, "#{__dir__}/docker_image/#{v}") }
79
+
80
+ include Concern::Executable
81
+ include Concern::Setup
82
+ include Concern::ReadableAttrs
83
+
84
+ def initialize(&block)
85
+ setup(caller_locations, &block)
86
+
87
+ @runner = Runner.new(self)
88
+ @ssh = SSH.new(self).freeze
89
+ tasks_load! if tasks_load?
90
+ end
91
+
92
+ # Get image id (through docker command).
93
+ #
94
+ # @return [String, nil]
95
+ def id
96
+ # docker image list --format "{{json .ID}}" image_name:image_version
97
+ [
98
+ self.to_h[:docker_bin] || executable
99
+ ].concat(['image', 'list', '--format', '{{json .ID}}', self.to_s]).yield_self do |command|
100
+ Open3.capture3(*command).tap do |stdout, _, status|
101
+ return nil unless status.success?
102
+
103
+ return stdout.lines.empty? ? nil : JSON.parse(stdout.lines.first)
104
+ end
105
+ end
106
+ end
107
+
108
+ # Denote image is started.
109
+ #
110
+ # @return [Boolean]
111
+ def started?
112
+ runner.started?
113
+ end
114
+
115
+ # Denote image is running?.
116
+ #
117
+ # @return [Boolean]
118
+ def running?
119
+ runner.running?
120
+ end
121
+
122
+ # Get name of available commands.
123
+ #
124
+ # @return [Array<Symbol>]
125
+ def available_commands
126
+ commands.clone.reject { |_k, args| args.nil? }.to_h.keys.sort
127
+ end
128
+
129
+ # Get tag
130
+ #
131
+ # tag has the following format: ``#{name}:#{version}``
132
+ #
133
+ # @return [String]
134
+ def tag
135
+ "#{name}:#{version}"
136
+ end
137
+
138
+ alias to_s tag
139
+
140
+ # @return [Hash]
141
+ def to_h
142
+ readable_attrs_values
143
+ .to_h.tap { |h| h.merge!(tag: tag) }
144
+ .sort.to_h
145
+ end
146
+
147
+ # @return [Boolean]
148
+ def verbose?
149
+ !!@verbose
150
+ end
151
+
152
+ # @return [Boolean]
153
+ def tasks_load?
154
+ !!self.tasks_load
155
+ end
156
+
157
+ # @return [Pathname]
158
+ def path
159
+ Pathname.new(@path)
160
+ end
161
+
162
+ # @see Runner#actions
163
+ def method_missing(method, *args, &block)
164
+ respond_to_missing?(method) ? runner.public_send(method, *args, &block) : super
165
+ end
166
+
167
+ def respond_to_missing?(method, include_private = false)
168
+ # rubocop:disable Style/RedundantParentheses
169
+ (runner&.actions).to_a.include?(method.to_sym) || super(method, include_private)
170
+ # rubocop:enable Style/RedundantParentheses
171
+ end
172
+
173
+ protected
174
+
175
+ # @type [String]
176
+ attr_writer :name
177
+
178
+ # @see Concern::Setup#setup_defaults
179
+ # @type [String]
180
+ attr_writer :path
181
+
182
+ # @see Concern::Setup#setup_defaults
183
+ # @type [Boolean]
184
+ attr_writer :verbose
185
+
186
+ # @see Concern::Setup#setup_defaults
187
+ # @type [String]
188
+ attr_writer :version
189
+
190
+ # @type [String|nil]
191
+ attr_writer :tasks_ns
192
+
193
+ # @see Concern::Setup#setup_defaults
194
+ # @type [String]
195
+ attr_writer :tasks_load
196
+
197
+ # @see Concern::Setup#setup_defaults
198
+ # @type [String]
199
+ attr_writer :run_as
200
+
201
+ # @see Concern::Setup#setup_defaults
202
+ # @type [String]
203
+ attr_writer :exec_command
204
+
205
+ # @type [Hash]
206
+ attr_writer :ssh
207
+
208
+ # @see Concern::Setup#setup_defaults
209
+ # @type [Hash]
210
+ attr_writer :commands
211
+
212
+ # @see Concern::Setup#setup_defaults
213
+ # @type [String|Symbol]
214
+ attr_writer :docker_bin
215
+
216
+ # @return [Runner]
217
+ attr_reader :runner
218
+
219
+ # Load tasks
220
+ def tasks_load!
221
+ self.tap { Loader.new(self).call }
222
+ end
223
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../docker_image'
10
+
11
+ # Describe a command
12
+ #
13
+ # Command is able to run itself.
14
+ class Kamaze::DockerImage::Command
15
+ autoload :Shellwords, 'shellwords'
16
+
17
+ # @return [Hash]
18
+ attr_reader :config
19
+
20
+ # @param [Array<String>] command
21
+ # @param [Hash] config
22
+ # @param [String|nil] extra
23
+ def initialize(command, config = {}, extra = nil)
24
+ command.clone.to_a.tap do |c|
25
+ extras = Shellwords.split(extra.to_s).compact
26
+ @parts = c.push(*extras).freeze
27
+ end
28
+
29
+ config.clone.to_h.tap do |c|
30
+ @config = c.freeze
31
+ end
32
+ end
33
+
34
+ # @return [Array<String>]
35
+ def to_a
36
+ parts.clone
37
+ end
38
+
39
+ # @return [String]
40
+ def to_s
41
+ Shellwords.join(self.to_a)
42
+ end
43
+
44
+ def run(&block)
45
+ sh(*self.to_a, &block)
46
+ end
47
+
48
+ alias call run
49
+
50
+ # @return [Boolean]
51
+ def execute
52
+ system(*self.to_a)
53
+ end
54
+
55
+ protected
56
+
57
+ # @return [Array<String>]
58
+ attr_reader :parts
59
+
60
+ # Get utils.
61
+ #
62
+ # return [Class]
63
+ def utils
64
+ if Gem::Specification.find_all_by_name('rake')
65
+ require 'rake'
66
+ require 'rake/file_utils'
67
+ end
68
+
69
+ Class.new { include FileUtils }.new
70
+ end
71
+
72
+ # @see https://github.com/ruby/rake/blob/124a03bf4c0db41cd80a41394a9e7c6426e44784/lib/rake/file_utils.rb#L43
73
+ def sh(*cmd, &block)
74
+ options = cmd.last.is_a?(Hash) ? cmd.pop : {}
75
+ options[:verbose] = config[:verbose] unless options.key?(:verbose)
76
+
77
+ utils.sh(*cmd.map(&:to_s).push(options), &block)
78
+ end
79
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../docker_image'
10
+
11
+ # rubocop:disable Style/Documentation
12
+
13
+ module Kamaze::DockerImage::Concern
14
+ {
15
+ Containers: 'containers',
16
+ Setup: 'setup',
17
+ Executable: 'executable',
18
+ ReadableAttrs: 'readable_attrs',
19
+ }.each { |k, v| autoload(k, "#{__dir__}/concern/#{v}") }
20
+ end
21
+
22
+ # rubocop:enable Style/Documentation
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../concern'
10
+
11
+ # Provide containers method.
12
+ module Kamaze::DockerImage::Concern::Containers
13
+ include Kamaze::DockerImage::Concern::Executable
14
+
15
+ autoload(:Open3, 'open3')
16
+ autoload(:JSON, 'json')
17
+
18
+ protected
19
+
20
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
21
+
22
+ # List containers.
23
+ #
24
+ # Containers are indexed by name.
25
+ #
26
+ # @return [Hash{String => Hash}]
27
+ def containers(all: true)
28
+ [(config[:docker_bin] || executable).to_s].map(&:freeze).freeze.yield_self do |cmd|
29
+ cmd.dup.concat(['ps', (all ? '-a' : nil), '--format', '{{json .}}']).yield_self do |command|
30
+ [].tap do |items|
31
+ Open3.capture3(*command.compact).yield_self do |stdout, _, status|
32
+ stdout.lines.each { |line| items.push(JSON.parse(line)) } if status.success?
33
+ end
34
+ end
35
+ end.map { |h| containers_maker.call(h) }.map { |h| [h.info['Name'].gsub(%r{^/*}, '').to_s, h] }.to_h
36
+ end
37
+ end
38
+
39
+ # Add some methods on retrieved info.
40
+ #
41
+ # @api private
42
+ #
43
+ # @return [Proc}
44
+ def containers_maker
45
+ # @type [Hash{String => Object}] given_data
46
+ lambda do |given_data|
47
+ command = [(config[:docker_bin] || executable).to_s]
48
+ .map(&:freeze)
49
+ .concat(['inspect', '--format', '{{json .}}', given_data.fetch('ID')])
50
+
51
+ given_data.dup.tap do |result|
52
+ result.singleton_class.tap do |klass|
53
+ :inspection.tap do |method_name|
54
+ klass.__send__(:define_method, method_name) do
55
+ -> { Struct.new(:stdout, :stderr, :status).new(*Open3.capture3(*command.compact)) }
56
+ end
57
+ klass.__send__(:protected, method_name)
58
+ end
59
+
60
+ klass.__send__(:define_method, :info) do
61
+ inspection.call.yield_self do |v|
62
+ (v.status.success? ? JSON.parse(v.stdout) : nil).to_h
63
+ end
64
+ end
65
+
66
+ klass.__send__(:define_method, :running?) do
67
+ self.info['State'].to_h['Status'] == 'running'
68
+ end
69
+ end
70
+ end.freeze
71
+ end
72
+ end
73
+
74
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
75
+ end