devkitkat 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.gitlab-ci.yml +15 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +74 -0
- data/LICENSE.txt +21 -0
- data/README.md +250 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/devkitkat +6 -0
- data/bin/fast_rspec +3 -0
- data/bin/setup +8 -0
- data/devkitkat.gemspec +37 -0
- data/docs/READ.md +1 -0
- data/docs/config/READ.md +1 -0
- data/docs/machine/READ.md +1 -0
- data/docs/service/READ.md +1 -0
- data/lib/devkitkat.rb +14 -0
- data/lib/devkitkat/command.rb +65 -0
- data/lib/devkitkat/config.rb +87 -0
- data/lib/devkitkat/executor.rb +63 -0
- data/lib/devkitkat/executor/docker.rb +97 -0
- data/lib/devkitkat/executor/local.rb +25 -0
- data/lib/devkitkat/main.rb +46 -0
- data/lib/devkitkat/service.rb +243 -0
- data/lib/devkitkat/version.rb +3 -0
- metadata +225 -0
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "devkitkat"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
12
|
+
|
13
|
+
# require "irb"
|
14
|
+
# IRB.start(__FILE__)
|
data/bin/devkitkat
ADDED
data/bin/fast_rspec
ADDED
data/bin/setup
ADDED
data/devkitkat.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "devkitkat/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "devkitkat"
|
8
|
+
spec.version = Devkitkat::VERSION
|
9
|
+
spec.authors = ["Shinya Maeda"]
|
10
|
+
spec.email = ["shinya@gitlab.com"]
|
11
|
+
|
12
|
+
spec.summary = "Make micro services easy"
|
13
|
+
spec.description = "Make micro services easy"
|
14
|
+
spec.homepage = "https://gitlab.com/dosuken123/devkitkat"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
end
|
22
|
+
spec.bindir = "bin"
|
23
|
+
spec.executables = "devkitkat"
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
spec.add_development_dependency "rspec-temp_dir", "~> 1.1.0"
|
30
|
+
spec.add_development_dependency "pry", "~> 0.12.2"
|
31
|
+
spec.add_development_dependency "pry-nav"
|
32
|
+
spec.add_runtime_dependency "activesupport", "~> 6.0.0"
|
33
|
+
spec.add_runtime_dependency "parallel", "~> 1.17.0"
|
34
|
+
spec.add_runtime_dependency "ruby-progressbar", "~> 1.10.1"
|
35
|
+
spec.add_runtime_dependency "colorize", "~> 0.8.1"
|
36
|
+
spec.add_runtime_dependency "docker-api", "~> 1.34.2"
|
37
|
+
end
|
data/docs/READ.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Devkitkat
|
data/docs/config/READ.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Config
|
@@ -0,0 +1 @@
|
|
1
|
+
# Machine
|
@@ -0,0 +1 @@
|
|
1
|
+
# Service
|
data/lib/devkitkat.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "devkitkat/version"
|
2
|
+
require "devkitkat/main"
|
3
|
+
require "devkitkat/executor"
|
4
|
+
require "devkitkat/command"
|
5
|
+
require "devkitkat/config"
|
6
|
+
require "devkitkat/service"
|
7
|
+
require 'yaml'
|
8
|
+
require 'optparse'
|
9
|
+
require 'parallel'
|
10
|
+
require 'colorize'
|
11
|
+
require 'active_support/core_ext/array/conversions'
|
12
|
+
|
13
|
+
module Devkitkat
|
14
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Devkitkat
|
2
|
+
class Command
|
3
|
+
attr_reader :options, :script, :target, :args
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@options = {}
|
7
|
+
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: devkitkat <script> <target> [options]"
|
10
|
+
|
11
|
+
opts.on("-p", "--path PATH", "The root path of the .devkitkat.yml") do |v|
|
12
|
+
options[:root_path] = v
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on("-e", "--exclude SERVICE", "Exclude serviced from the specified target") do |v|
|
16
|
+
options[:exclude] ||= []
|
17
|
+
options[:exclude] << v
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-e", "--env-var VARIABLE", "additional environment variables") do |v|
|
21
|
+
options[:variables] ||= {}
|
22
|
+
options[:variables].merge!(Hash[*v.split('=')])
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("-d", "--depth DEPTH", "Git depth for pull/fetch") do |v|
|
26
|
+
options[:git_depth] = v
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("-r", "--remote REMOTE", "Git remote") do |v|
|
30
|
+
options[:git_remote] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("-b", "--branch BRANCH", "Git branch") do |v|
|
34
|
+
options[:git_branch] = v
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-t", "--tty", "TTY mode. In this mode, log won't be emitted.") do |v|
|
38
|
+
options[:tty] = v
|
39
|
+
end
|
40
|
+
end.parse!
|
41
|
+
|
42
|
+
@script, @target, *@args = ARGV
|
43
|
+
end
|
44
|
+
|
45
|
+
def tty?
|
46
|
+
options[:tty]
|
47
|
+
end
|
48
|
+
|
49
|
+
def variables
|
50
|
+
options[:variables]
|
51
|
+
end
|
52
|
+
|
53
|
+
def tmp_dir
|
54
|
+
File.join(kit_root, 'tmp')
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_tmp_dir
|
58
|
+
FileUtils.mkdir_p(tmp_dir)
|
59
|
+
end
|
60
|
+
|
61
|
+
def kit_root
|
62
|
+
Dir.pwd # TODO: root_path
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Devkitkat
|
2
|
+
class Config
|
3
|
+
DEVKITKAT_FILE_NAME = '.devkitkat.yml'
|
4
|
+
HIDDEN_SERVICES = %w[system]
|
5
|
+
|
6
|
+
attr_reader :devkitkat_yml, :kit_root
|
7
|
+
|
8
|
+
def initialize(kit_root)
|
9
|
+
@kit_root = kit_root
|
10
|
+
@devkitkat_yml = load_config
|
11
|
+
end
|
12
|
+
|
13
|
+
def all_services
|
14
|
+
services + HIDDEN_SERVICES
|
15
|
+
end
|
16
|
+
|
17
|
+
def resolve!(target, exclude: nil)
|
18
|
+
services = if target.nil? || target == 'system'
|
19
|
+
%w[system]
|
20
|
+
elsif target == 'all'
|
21
|
+
all_services
|
22
|
+
elsif group = find_group(target)
|
23
|
+
services_for_group(group)
|
24
|
+
elsif service = find_service(target)
|
25
|
+
[service]
|
26
|
+
else
|
27
|
+
raise ArgumentError, "The target name #{target} couldn't be resolved"
|
28
|
+
end
|
29
|
+
|
30
|
+
services = services - exclude if exclude
|
31
|
+
|
32
|
+
services
|
33
|
+
end
|
34
|
+
|
35
|
+
def environment_type
|
36
|
+
devkitkat_yml.dig('environment', 'type') || 'local'
|
37
|
+
end
|
38
|
+
|
39
|
+
def environment_image
|
40
|
+
devkitkat_yml.dig('environment', 'image')
|
41
|
+
end
|
42
|
+
|
43
|
+
def application
|
44
|
+
devkitkat_yml.fetch('application', '')
|
45
|
+
end
|
46
|
+
|
47
|
+
def variables
|
48
|
+
devkitkat_yml.fetch('variables', {})
|
49
|
+
end
|
50
|
+
|
51
|
+
def service_hash(name)
|
52
|
+
devkitkat_yml.dig('services', name) || {}
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def services
|
58
|
+
devkitkat_yml['services']&.keys || []
|
59
|
+
end
|
60
|
+
|
61
|
+
def groups
|
62
|
+
devkitkat_yml['groups']&.keys || []
|
63
|
+
end
|
64
|
+
|
65
|
+
def services_for_group(group)
|
66
|
+
devkitkat_yml.dig('groups', group) || []
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_group(target)
|
70
|
+
groups.find { |group| group == target }
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_service(target)
|
74
|
+
services.find { |service| service == target }
|
75
|
+
end
|
76
|
+
|
77
|
+
def load_config
|
78
|
+
File.read(config_path).yield_self do |content|
|
79
|
+
YAML.load(content)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def config_path
|
84
|
+
File.join(kit_root, DEVKITKAT_FILE_NAME)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "devkitkat/executor/docker"
|
2
|
+
require "devkitkat/executor/local"
|
3
|
+
|
4
|
+
module Devkitkat
|
5
|
+
class Executor
|
6
|
+
attr_reader :service, :scripts
|
7
|
+
|
8
|
+
delegate :config, :command, to: :service
|
9
|
+
delegate :prepare, :cleanup, to: :executor
|
10
|
+
|
11
|
+
SCRIPT_HEADER = <<-EOS
|
12
|
+
#!/bin/bash
|
13
|
+
set -e
|
14
|
+
EOS
|
15
|
+
|
16
|
+
def initialize(service)
|
17
|
+
@service = service
|
18
|
+
delete_script_file
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(cmd)
|
22
|
+
ensure_script_file
|
23
|
+
|
24
|
+
File.open(script_file, 'a') do |stream|
|
25
|
+
stream.write(cmd + "\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def commit
|
30
|
+
executor.commit(script_file)
|
31
|
+
ensure
|
32
|
+
delete_script_file
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def executor
|
38
|
+
@executor ||= klass.new(service)
|
39
|
+
end
|
40
|
+
|
41
|
+
def klass
|
42
|
+
Object.const_get("Devkitkat::Executor::#{config.environment_type.capitalize}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def script_file
|
46
|
+
File.join(command.tmp_dir, "script-#{service.name}-#{command.script}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def ensure_script_file
|
50
|
+
create_script_file unless File.exist?(script_file)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_script_file
|
54
|
+
command.create_tmp_dir
|
55
|
+
File.write(script_file, SCRIPT_HEADER)
|
56
|
+
File.chmod(0777, script_file)
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete_script_file
|
60
|
+
FileUtils.rm_f(script_file)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'docker'
|
3
|
+
|
4
|
+
module Devkitkat
|
5
|
+
class Executor
|
6
|
+
class Docker
|
7
|
+
attr_reader :service, :script_file
|
8
|
+
|
9
|
+
delegate :config, :command, to: :service
|
10
|
+
|
11
|
+
def initialize(service)
|
12
|
+
@service = service
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare
|
16
|
+
start_container
|
17
|
+
end
|
18
|
+
|
19
|
+
def cleanup
|
20
|
+
stop_container
|
21
|
+
end
|
22
|
+
|
23
|
+
def commit(script_file)
|
24
|
+
@script_file = script_file
|
25
|
+
|
26
|
+
rewrite_root_path!
|
27
|
+
new_path = script_path_in_container
|
28
|
+
|
29
|
+
container.exec([new_path])
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def rewrite_root_path!
|
35
|
+
content = File.read(script_file)
|
36
|
+
new_content = content.gsub(command.kit_root, root_in_container)
|
37
|
+
File.write(script_file, new_content)
|
38
|
+
end
|
39
|
+
|
40
|
+
def script_path_in_container
|
41
|
+
relative_path = script_file.delete_prefix(command.kit_root)
|
42
|
+
File.join(root_in_container, relative_path)
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_path_in_container
|
46
|
+
relative_path = service.log_path.delete_prefix(command.kit_root)
|
47
|
+
File.join(root_in_container, relative_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
def docker_image
|
51
|
+
config.environment_image
|
52
|
+
end
|
53
|
+
|
54
|
+
def container
|
55
|
+
@container ||= ::Docker::Container.create(container_parameter)
|
56
|
+
end
|
57
|
+
|
58
|
+
def container_parameter
|
59
|
+
# TODO: Speicfy users otherwise the created files are owned by root
|
60
|
+
params = {
|
61
|
+
'Cmd' => %w[tail -f],
|
62
|
+
'Image' => docker_image,
|
63
|
+
'name' => service.container_name,
|
64
|
+
'HostConfig' => {
|
65
|
+
'Binds' => ["#{command.kit_root}:#{root_in_container}"]
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
if service.port
|
70
|
+
params.deep_merge!(
|
71
|
+
'ExposedPorts' => { "#{service.port}/tcp" => {} },
|
72
|
+
'HostConfig' => {
|
73
|
+
'PortBindings' => {
|
74
|
+
"#{service.port}/tcp" => [{ 'HostPort' => service.port.to_s }]
|
75
|
+
}
|
76
|
+
}
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
params
|
81
|
+
end
|
82
|
+
|
83
|
+
def root_in_container
|
84
|
+
"/devkitkat"
|
85
|
+
end
|
86
|
+
|
87
|
+
def start_container
|
88
|
+
container.start
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop_container
|
92
|
+
container.stop
|
93
|
+
container.remove
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Devkitkat
|
2
|
+
class Executor
|
3
|
+
class Local
|
4
|
+
attr_reader :service
|
5
|
+
|
6
|
+
delegate :config, :command, to: :service
|
7
|
+
|
8
|
+
def initialize(service)
|
9
|
+
@service = service
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
# no-op
|
14
|
+
end
|
15
|
+
|
16
|
+
def cleanup
|
17
|
+
# no-op
|
18
|
+
end
|
19
|
+
|
20
|
+
def commit(script_file)
|
21
|
+
system(script_file)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|