kamaze-docker_image 0.0.5
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.
- checksums.yaml +7 -0
- data/.rubocop.yml +6 -0
- data/.yardopts +16 -0
- data/lib/kamaze-docker_image.rb +24 -0
- data/lib/kamaze/docker_image.rb +223 -0
- data/lib/kamaze/docker_image/command.rb +79 -0
- data/lib/kamaze/docker_image/concern.rb +22 -0
- data/lib/kamaze/docker_image/concern/containers.rb +75 -0
- data/lib/kamaze/docker_image/concern/docker.rb +36 -0
- data/lib/kamaze/docker_image/concern/executable.rb +24 -0
- data/lib/kamaze/docker_image/concern/readable_attrs.rb +48 -0
- data/lib/kamaze/docker_image/concern/setup.rb +98 -0
- data/lib/kamaze/docker_image/concern/setup/config.rb +35 -0
- data/lib/kamaze/docker_image/loader.rb +61 -0
- data/lib/kamaze/docker_image/loader/context.rb +57 -0
- data/lib/kamaze/docker_image/loader/helper.rb +99 -0
- data/lib/kamaze/docker_image/loader/tasks.rb +22 -0
- data/lib/kamaze/docker_image/loader/tasks/build.rb +23 -0
- data/lib/kamaze/docker_image/loader/tasks/exec.rb +19 -0
- data/lib/kamaze/docker_image/loader/tasks/push.rb +19 -0
- data/lib/kamaze/docker_image/loader/tasks/restart.rb +21 -0
- data/lib/kamaze/docker_image/loader/tasks/run.rb +19 -0
- data/lib/kamaze/docker_image/loader/tasks/ssh.rb +19 -0
- data/lib/kamaze/docker_image/loader/tasks/start.rb +19 -0
- data/lib/kamaze/docker_image/loader/tasks/stop.rb +19 -0
- data/lib/kamaze/docker_image/runner.rb +126 -0
- data/lib/kamaze/docker_image/runner/storage.rb +78 -0
- data/lib/kamaze/docker_image/ssh.rb +143 -0
- data/lib/kamaze/docker_image/version.rb +13 -0
- data/lib/kamaze/docker_image/version.yml +17 -0
- 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
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
|