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