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.
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
@@ -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 'helper'
10
+
11
+ # @type [Kamaze::DockerImage::Loader::Context] self
12
+ self.singleton_class.__send__(:define_method, :helper) do
13
+ Kamaze::DockerImage::Loader::Helper.new(image)
14
+ end
15
+
16
+ # tasks --------------------------------------------------------------
17
+
18
+ Pathname.new(__dir__).join('tasks').tap do |path|
19
+ Dir.glob(path.join('*.rb')).map { |fp| Pathname.new(fp) }.each do |file|
20
+ self.instance_eval(file.read, file.to_s, 1)
21
+ end
22
+ end
@@ -0,0 +1,23 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:build)
12
+ desc 'Build image'
13
+
14
+ task helper.appoint(:build), [:cached] do |task, args|
15
+ autoload(:YAML, 'yaml')
16
+
17
+ YAML.safe_load(args.key?(:cached) ? args[:cached] : 'true').tap do |cached|
18
+ helper.call(task, args) { cached ? image.build : image.rebuild }
19
+ end
20
+
21
+ task.reenable
22
+ end
23
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:exec)
12
+ desc 'Run a command in a running container'
13
+
14
+ task helper.appoint(:exec), [:command] do |task, args|
15
+ helper.call(task, args) { image.exec(args[:command]) }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:push)
12
+ desc 'Push image'
13
+
14
+ task helper.appoint(:push) do |task|
15
+ helper.call(task) { image.push }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,21 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ %i[start stop].map { |v| image.available_commands.include?(v) }.uniq.tap do |v|
12
+ if v == [true]
13
+ desc 'Restart container'
14
+
15
+ task helper.appoint(:restart) do |task|
16
+ helper.call(task) { image.restart }
17
+
18
+ task.reenable
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:run)
12
+ desc 'Run a command in a new container'
13
+
14
+ task helper.appoint(:run), [:command] do |task, args|
15
+ helper.call(task, args) { image.run(args[:command]) }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.ssh.enabled?
12
+ desc 'Connect to container using Secure Shell (SSH)'
13
+
14
+ task helper.appoint(:ssh), [:command] do |task, args|
15
+ helper.call(task) { image.ssh.call(args[:command]) }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:start)
12
+ desc 'Start container as %<run_as>s' % { run_as: image.run_as }
13
+
14
+ task helper.appoint(:start) do |task|
15
+ helper.call(task) { image.start }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,19 @@
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
+ # @type [Kamaze::DockerImage::Loader::Helper] helper
10
+
11
+ if image.available_commands.include?(:stop)
12
+ desc 'Stop container'
13
+
14
+ task helper.appoint(:stop) do |task|
15
+ helper.call(task) { image.stop }
16
+
17
+ task.reenable
18
+ end
19
+ end
@@ -0,0 +1,126 @@
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
+ # Runner provide methods to execute image related actions
12
+ #
13
+ # @see #actions
14
+ # @see Kamaze::DockerImage::Concern::Setup#default_commands
15
+ class Kamaze::DockerImage::Runner
16
+ include Kamaze::DockerImage::Concern::Containers
17
+
18
+ # noinspection RubyConstantNamingConvention
19
+ Command = Kamaze::DockerImage::Command
20
+
21
+ # Available actions
22
+ #
23
+ # Actions registrable on ``image``.
24
+ # @see Runner#actions
25
+ ACTIONS = %i[restart start stop exec run build push rm rebuild].sort
26
+
27
+ autoload :Storage, "#{__dir__}/runner/storage"
28
+
29
+ # @param [Kamaze::DockerImage] image
30
+ #
31
+ # @see Kamaze::DockerImage::Concern::Setup#default_commands
32
+ def initialize(image)
33
+ @config = image.to_h.reject! { |k| k == :commands }.freeze
34
+ @commands = Storage[image.commands].tap do |store|
35
+ store.config = @config
36
+ end
37
+
38
+ @commands.freeze
39
+ end
40
+
41
+ # Build image
42
+ def build(&block)
43
+ command(:build).run(&block)
44
+ end
45
+
46
+ # Push image
47
+ def push(&block)
48
+ command(:push).run(&block)
49
+ end
50
+
51
+ # Build image (do not use cache)
52
+ def rebuild(&block)
53
+ command(:rebuild).run(&block)
54
+ end
55
+
56
+ def run(extra = nil, &block)
57
+ command(:run, extra).run(&block)
58
+ end
59
+
60
+ def exec(extra = nil, &block)
61
+ default = config.fetch(:exec_command)
62
+ extra ||= default
63
+
64
+ command(:exec, extra).run(&block)
65
+ end
66
+
67
+ def start(&block)
68
+ command(:start).run(&block) unless running?
69
+ end
70
+
71
+ def stop(&block)
72
+ command(:stop).run(&block) if started?
73
+ end
74
+
75
+ def rm(&block)
76
+ command(:rm).run(&block) if started?
77
+ end
78
+
79
+ def restart(&block)
80
+ stop(&block)
81
+ rm(&block)
82
+ start(&block)
83
+ end
84
+
85
+ # @return [Array<Symbol>]
86
+ def actions
87
+ ACTIONS
88
+ end
89
+
90
+ # Denote container is started.
91
+ #
92
+ # @return [Boolean]
93
+ def started?
94
+ # !fetch_containers(config.fetch(:run_as)).empty?
95
+ config.fetch(:run_as).yield_self { |name| !containers[name].nil? }
96
+ end
97
+
98
+ # Denote container is running.
99
+ #
100
+ # @return [Boolean]
101
+ def running?
102
+ # !fetch_containers(config.fetch(:run_as), :running).empty?
103
+ config.fetch(:run_as).yield_self { |name| containers[name]&.running? }
104
+ end
105
+
106
+ protected
107
+
108
+ # @return [Hash]
109
+ attr_reader :config
110
+
111
+ # Get commands
112
+ #
113
+ # @return [Hash]
114
+ attr_reader :commands
115
+
116
+ # Generate command.
117
+ #
118
+ # @param [String|Symbol] name
119
+ # @param [String|nil] extra
120
+ # @return [Command]
121
+ def command(name, extra = nil)
122
+ command = commands.fetch(name.to_sym)
123
+
124
+ Command.new(command, config, extra)
125
+ end
126
+ end
@@ -0,0 +1,78 @@
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 '../runner'
10
+
11
+ # Store commands to be executed.
12
+ #
13
+ # Command is shaped (formatted) on retrieval, using ``config``.
14
+ #
15
+ # @see #shape
16
+ # @see #config=
17
+ class Kamaze::DockerImage::Runner::Storage < Hash
18
+ include(Kamaze::DockerImage::Concern::Executable)
19
+
20
+ # @param [Hash] config
21
+ def config=(config)
22
+ @config = config.clone.freeze
23
+ end
24
+
25
+ # @return [Hash]
26
+ def config
27
+ @config.to_h
28
+ end
29
+
30
+ # Retrieves the value object corresponding to the key object.
31
+ #
32
+ # @return [Array<String>]
33
+ def [](key)
34
+ self.fetch(key)
35
+ rescue KeyError
36
+ super
37
+ end
38
+
39
+ # Returns a value from the hash for the given key.
40
+ #
41
+ # @raise [KeyError]
42
+ # @return [Array<String>]
43
+ def fetch(key)
44
+ key = key.to_sym
45
+ val = super
46
+
47
+ val ? shape(val) : val
48
+ end
49
+
50
+ protected
51
+
52
+ # Get executable
53
+ #
54
+ # @raise [Cliver::Dependency::NotFound]
55
+ # @return [String]
56
+ def executable
57
+ config[:docker_bin] || super
58
+ end
59
+
60
+ # Format given command
61
+ #
62
+ # @param [Array] command
63
+ # @return [Array<String>]
64
+ def shape(command)
65
+ # rubocop:disable Style/TernaryParentheses
66
+ h = {
67
+ opt_it: ($stdout.tty? and $stderr.tty?) ? '-it' : nil,
68
+ }
69
+ # rubocop:enable Style/TernaryParentheses
70
+
71
+ [executable]
72
+ .push(*command)
73
+ .map(&:to_s)
74
+ .map { |w| w % config.merge(h) }
75
+ .map { |w| w.to_s.empty? ? nil : w }
76
+ .compact
77
+ end
78
+ end
@@ -0,0 +1,143 @@
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
+ autoload :YAML, 'yaml'
11
+ autoload :Pathname, 'pathname'
12
+ autoload :Shellwords, 'shellwords'
13
+ autoload :Timeout, 'timeout'
14
+ autoload :Cliver, 'cliver'
15
+
16
+ # Runner provide methods to connect into image using ssh.
17
+ #
18
+ # Sample of use:
19
+ #
20
+ # ```ruby
21
+ # require 'kamaze/docker_image'
22
+ #
23
+ # ssh = Kamaze::DockerImage::SSH.new(run_as: 'kamaze_sample_image')
24
+ # ```
25
+ class Kamaze::DockerImage::SSH < Hash
26
+ include Kamaze::DockerImage::Concern::Containers
27
+
28
+ # noinspection RubyConstantNamingConvention
29
+ Command = Kamaze::DockerImage::Command
30
+
31
+ # @return [Hash]
32
+ attr_reader :config
33
+
34
+ # @param [Kamaze::DockerImage] image
35
+ #
36
+ # @see Kamaze::DockerImage::Concern::Setup#default_commands
37
+ def initialize(image)
38
+ defaults.merge(image.to_h[:ssh].to_h).tap do |ssh|
39
+ @config = image.to_h.merge(ssh: ssh).freeze
40
+ end.each { |k, v| self[k] = v }
41
+ end
42
+
43
+ # Connect to ssh (executing optional command ``cmd``).
44
+ #
45
+ # @param [Array<String|Object>] cmd
46
+ # @raise [Errno::ENONET]
47
+ #
48
+ # @see #command
49
+ def call(cmd = nil, &block)
50
+ network? ? wait : (raise Errno::ENONET)
51
+ rescue Timeout::Error
52
+ nil
53
+ ensure
54
+ command(cmd).run(&block)
55
+ end
56
+
57
+ # Wait until ssh is available.
58
+ #
59
+ # @return [self]
60
+ def wait
61
+ Timeout.timeout(config.fetch(:ssh).fetch(:timeout)) do
62
+ loop do
63
+ command(config.fetch(:ssh).fetch(:test)).tap do |command|
64
+ if command.execute
65
+ return block_given? ? yield(self) : self
66
+ end
67
+
68
+ sleep(0.5)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ # Get defaults for config.
75
+ #
76
+ # @return [Hash{Symbol => Object}]
77
+ def defaults
78
+ YAML.safe_load(Pathname.new(__dir__).join('ssh.yml').read, [Symbol])
79
+ end
80
+
81
+ # @return [Command]
82
+ def command(cmd = nil)
83
+ cmd = Shellwords.split(cmd) if cmd.is_a?(String)
84
+
85
+ config.fetch(:ssh).fetch(:command)
86
+ .map { |w| w % params }
87
+ .push(*cmd.to_a)
88
+ .tap { |command| return Command.new(command, config) }
89
+ end
90
+
91
+ # Params used to shape command.
92
+ #
93
+ # @return [Hash{Symbol => Object}]
94
+ def params
95
+ # rubocop:disable Style/TernaryParentheses
96
+ {
97
+ executable: executable,
98
+ port: config.fetch(:ssh).fetch(:port),
99
+ user: config.fetch(:ssh).fetch(:user),
100
+ host: network.fetch(0),
101
+ opt_pty: ($stdout.tty? and $stderr.tty?) ? '-t' : '-T',
102
+ }
103
+ # rubocop:enable Style/TernaryParentheses
104
+ end
105
+
106
+ # Get absolute path for executable.
107
+ #
108
+ # @return [String|Object]
109
+ def executable
110
+ config.fetch(:ssh).fetch(:executable).tap do |executable|
111
+ Cliver.detect(executable).tap do |s|
112
+ return (s || executable).freeze
113
+ end
114
+ end
115
+ end
116
+
117
+ # Denote SSH is enabled.
118
+ #
119
+ # @return [Boolean]
120
+ def enabled?
121
+ config.fetch(:ssh)[:enabled]
122
+ end
123
+
124
+ # Get ip addresses.
125
+ #
126
+ # @return [Array<String>]
127
+ def network
128
+ # container = fetch_containers(config.fetch(:run_as), [:running])[0]
129
+ containers[config.fetch(:run_as)].yield_self do |container|
130
+ return [] if container.nil?
131
+ return [] unless container.running?
132
+
133
+ container.info
134
+ .fetch('NetworkSettings').fetch('Networks')
135
+ .values.keep_if { |v| v.to_h['IPAddress'] }.map { |v| v['IPAddress'] }.compact
136
+ end
137
+ end
138
+
139
+ # @return [Boolean]
140
+ def network?
141
+ !network.empty?
142
+ end
143
+ end