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,36 @@
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
+ # Provides setup (used during initialization) and related methods.
12
+ #
13
+ # @todo remove this file, it SHOULD be useless
14
+ module Kamaze::DockerImage::Concern::Docker
15
+ autoload(:Docker, 'docker')
16
+
17
+ protected
18
+
19
+ # Fetch containers
20
+ #
21
+ # @param [String] run_as
22
+ # @param [Array|nil] states
23
+ # @return [Array<Docker::Container>]
24
+ def fetch_containers(run_as, states = nil)
25
+ unless states.nil?
26
+ states = (states.is_a?(Array) ? states : [states]).map(&:to_s)
27
+ states = nil if states.empty?
28
+ end
29
+
30
+ Docker::Container.all(all: true).keep_if do |c|
31
+ states.to_a.empty? ? true : states.include?(c.info.fetch('State'))
32
+ end.keep_if do |c|
33
+ c.info.fetch('Names').include?("/#{run_as}")
34
+ end
35
+ end
36
+ 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
+ require_relative '../concern'
10
+
11
+ # PProvide method to retrieve path to docker executable.
12
+ module Kamaze::DockerImage::Concern::Executable
13
+ autoload(:Cliver, 'cliver')
14
+
15
+ protected
16
+
17
+ # Get executable
18
+ #
19
+ # @raise [Cliver::Dependency::NotFound]
20
+ # @return [String]
21
+ def executable
22
+ Cliver.detect!(:docker).freeze
23
+ end
24
+ end
@@ -0,0 +1,48 @@
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
+ # Provides ``readable_attrs`` method
12
+ #
13
+ # Readable attributes have an instance variable and an accessor,
14
+ # boolean accessors are also supported.
15
+ #
16
+ # As a result, class including this module obtains a Hash representation.
17
+ module Kamaze::DockerImage::Concern::ReadableAttrs
18
+ # Get readable attributes
19
+ #
20
+ # @return [Array<Symbol>]
21
+ def readable_attrs
22
+ instance_variables.clone.map do |attr|
23
+ k = attr.to_s.gsub(/^@/, '').to_sym
24
+
25
+ methods = ([k, "#{k}?".to_sym] & public_methods)
26
+
27
+ methods.empty? ? nil : k
28
+ end.compact.sort
29
+ end
30
+
31
+ def to_h
32
+ readable_attrs_values.to_h
33
+ end
34
+
35
+ protected
36
+
37
+ # Get readable attributes with values
38
+ #
39
+ # @return [Array<Array>]
40
+ def readable_attrs_values
41
+ readable_attrs.map do |k|
42
+ # booleanaccessor will override "real" accessor
43
+ ([k, "#{k}?".to_sym] & public_methods)
44
+ .map { |m| [k, self.public_send(m)] }
45
+ .first
46
+ end.compact
47
+ end
48
+ end
@@ -0,0 +1,98 @@
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
+ # Provides setup (used during initialization) and related methods.
12
+ module Kamaze::DockerImage::Concern::Setup
13
+ autoload :OpenStruct, 'ostruct'
14
+ autoload :Pathname, 'pathname'
15
+ autoload :YAML, 'yaml'
16
+ autoload :Config, "#{__dir__}/setup/config"
17
+
18
+ protected
19
+
20
+ # Setup
21
+ #
22
+ # @param [Array<Thread::Backtrace::Location>] locations
23
+ # @return [self]
24
+ def setup(locations, &block)
25
+ setup_defaults(locations).tap do
26
+ setup_block(&block)
27
+
28
+ @name = @name.to_s
29
+ @commands = Hash[@commands.map { |k, v| [k.to_sym, v] }]
30
+
31
+ to_h.each { |k, v| instance_variable_set("@#{k}", v) }
32
+ end
33
+ end
34
+
35
+ # rubocop:disable Metrics/MethodLength
36
+
37
+ # Setup atttributes with default values
38
+ #
39
+ # @param [Array<Thread::Backtrace::Location>] locations
40
+ # @return [self]
41
+ def setup_defaults(locations)
42
+ self.tap do
43
+ @name = nil
44
+ @version = 'latest'
45
+
46
+ @path = Pathname.new('.')
47
+ @verbose = $stdout.tty? && $stderr.tty?
48
+ @tasks_load = true
49
+ @tasks_ns = nil
50
+ @run_as = called_from(locations).dirname.basename.to_s
51
+ @docker_bin = 'docker'
52
+ @exec_command = 'bash -il'
53
+ @commands = default_commands
54
+ @ssh = {}
55
+ end
56
+ end
57
+
58
+ # rubocop:enable Metrics/MethodLength
59
+
60
+ # @yield [Config] config used to setup instance
61
+ # @return [Config]
62
+ def setup_block
63
+ Config.new(self.respond_to?(:to_h) ? to_h : {}).tap do |s|
64
+ yield(s) if block_given?
65
+
66
+ s.freeze
67
+ s.to_h.each { |k, v| setup_attr(k, v) }
68
+ end
69
+ end
70
+
71
+ # Get default commands
72
+ #
73
+ # @return [Hash]
74
+ def default_commands
75
+ content = Pathname.new(__dir__).join('..', 'commands.yml').read
76
+
77
+ YAML.safe_load(content, [Symbol])
78
+ end
79
+
80
+ private
81
+
82
+ # Set given attr with given value
83
+ #
84
+ # @param [String|Symbol] attr
85
+ # @param [Object] val
86
+ def setup_attr(attr, val)
87
+ __send__("#{attr}=", val)
88
+ rescue NoMethodError
89
+ nil
90
+ end
91
+
92
+ # @return [Pathname]
93
+ def called_from(locations = caller_locations)
94
+ location = locations.first.path
95
+
96
+ Pathname.new(location).realpath
97
+ end
98
+ end
@@ -0,0 +1,35 @@
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 '../setup'
10
+ require 'ostruct'
11
+
12
+ # Config data structure
13
+ #
14
+ # @see https://ruby-doc.org/stdlib-2.0.0/libdoc/ostruct/rdoc/OpenStruct.html
15
+ class Kamaze::DockerImage::Concern::Setup::Config < OpenStruct
16
+ def respond_to_missing?(method, include_private = false)
17
+ super
18
+ end
19
+
20
+ # Introduces some strictness on ``OpenStruct#method_missing``
21
+ #
22
+ # @see https://apidock.com/ruby/OpenStruct/method_missing
23
+ # @return [Object]
24
+ def method_missing(method, *args)
25
+ if method[-1] != '='
26
+ unless self.to_h.include?(method.to_sym)
27
+ message = "undefined method `#{method}' for #{self}"
28
+
29
+ raise NoMethodError, message, caller(1)
30
+ end
31
+ end
32
+
33
+ super
34
+ end
35
+ end
@@ -0,0 +1,61 @@
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
+ # Loader for tasks (using eval binding)
12
+ class Kamaze::DockerImage::Loader
13
+ autoload :Pathname, 'pathname'
14
+ autoload :Context, "#{__dir__}/loader/context"
15
+
16
+ # @param [Kamaze::DockerImage] image
17
+ def initialize(image)
18
+ @image = image.clone.freeze
19
+ end
20
+
21
+ # Load tasks.
22
+ #
23
+ # @return [self]
24
+ def call
25
+ self.tap do
26
+ if loadable?
27
+ context.call do |b|
28
+ b.local_variable_set(:image, image)
29
+ b.eval(content)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # @return [Boolean]
36
+ def loadable?
37
+ context.dsl?
38
+ end
39
+
40
+ protected
41
+
42
+ # @return [Kamaze::DockerImage]
43
+ attr_reader :image
44
+
45
+ # @return [Pathname]
46
+ def file
47
+ Pathname.new(__dir__).join('loader', 'tasks.rb')
48
+ end
49
+
50
+ # Tasks file content (to eval)
51
+ #
52
+ # @return [String]
53
+ def content
54
+ file.read
55
+ end
56
+
57
+ # @return [Module<Context>]
58
+ def context
59
+ Context
60
+ end
61
+ end
@@ -0,0 +1,57 @@
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 '../loader'
10
+
11
+ # Provides empty binding.
12
+ #
13
+ # Sample of use:
14
+ #
15
+ # ```ruby
16
+ # Context.call do |b|
17
+ # b.local_variable_set(:answer, 42)
18
+ # b.local_variable_set(:home, '127.0.0.1')
19
+ #
20
+ # b.eval(content)
21
+ # end
22
+ # ```
23
+ module Kamaze::DockerImage::Loader::Context
24
+ class << self
25
+ def call
26
+ yield(binding)
27
+ end
28
+
29
+ # Denote ``DSL`` is defined.
30
+ #
31
+ # @return [Boolean]
32
+ def dsl?
33
+ !!dsl
34
+ end
35
+
36
+ protected
37
+
38
+ # @return [Binding]
39
+ def binding
40
+ -> { super }.tap { load_dsl }.call
41
+ end
42
+
43
+ # @return [Rake::DSL, nil]
44
+ def dsl
45
+ Object.const_get('Rake::DSL')
46
+ rescue NameError
47
+ nil
48
+ end
49
+
50
+ # Apply ``Rake::DSL``
51
+ #
52
+ # @return [self]
53
+ def load_dsl
54
+ self.tap { self.extend(dsl) if dsl? }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,99 @@
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 '../loader'
10
+
11
+ # Helper for tasks.
12
+ #
13
+ # Sample of use:
14
+ #
15
+ # ```ruby
16
+ # helper = Kamaze::DockerImage::Loader::Helper.new(image)
17
+ #
18
+ # desc 'Run a command in a new container'
19
+ #
20
+ # task helper.appoint(:run), [:command] do |task, args|
21
+ # helper.call(task, args) { image.run(args[:command]) }
22
+ # end
23
+ # ````
24
+ class Kamaze::DockerImage::Loader::Helper
25
+ # @param [Kamaze::DockerImage] image
26
+ def initialize(image)
27
+ @image = image
28
+ end
29
+
30
+ # Make task name using namespace (from image)
31
+ #
32
+ # @return [String]
33
+ def appoint(name)
34
+ namer.call(name)
35
+ end
36
+
37
+ # Execute related ``pre_`` and ``post_`` tasks
38
+ #
39
+ # @param [Rake::Task] task
40
+ # @param [Hash{Symbol => Object}] args
41
+ #
42
+ # Sample of use:
43
+ #
44
+ # ```ruby
45
+ # task 'docker:pre_start' do |task, args|
46
+ # pp(task, args)
47
+ # end
48
+ #
49
+ # task 'docker:post_start' do |task, args|
50
+ # pp(task, args)
51
+ # end
52
+ # ```
53
+ def wrap(task, args = [], &block)
54
+ on_pre(task, args)
55
+ block.call
56
+ on_post(task, args)
57
+ end
58
+
59
+ alias call wrap
60
+
61
+ protected
62
+
63
+ # @return [Kamaze::DockerImage]
64
+ attr_accessor :image
65
+
66
+ # @return [Proc]
67
+ def namer
68
+ lambda do |name|
69
+ "#{image.tasks_ns}:#{name}".gsub(/^:/, '')
70
+ end
71
+ end
72
+
73
+ # @param [Rake::Task] task
74
+ def on_pre(task, args)
75
+ task_call(on: :pre, from: task, args: args)
76
+ end
77
+
78
+ # @param [Rake::Task] task
79
+ def on_post(task, args)
80
+ task_call(on: :post, from: task, args: args)
81
+ end
82
+
83
+ # Call pre/post tasks.
84
+ #
85
+ # on: pre/post
86
+ # from: task as ``Rake::Task``
87
+ # args: Hash
88
+ def task_call(on:, from:, args:)
89
+ cname = from.name.gsub(/^#{image.tasks_ns}:/, '')
90
+ # @formatter:off
91
+ {
92
+ pre: namer.call("pre_#{cname}"),
93
+ post: namer.call("post_#{cname}"),
94
+ }.fetch(on).tap do |name|
95
+ Rake::Task[name].execute(**args.to_h) if Rake::Task.task_defined?(name)
96
+ end
97
+ # @formatter:on
98
+ end
99
+ end