kuber_kit 0.5.8 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +1 -6
- data/example/app_data/service.yml +2 -1
- data/example/images/failing_app/Dockerfile +5 -0
- data/example/images/failing_app/image.rb +4 -0
- data/example/services/failing_app.rb +6 -0
- data/lib/kuber_kit.rb +9 -1
- data/lib/kuber_kit/actions/action_result.rb +32 -0
- data/lib/kuber_kit/actions/configuration_loader.rb +15 -6
- data/lib/kuber_kit/actions/image_compiler.rb +18 -12
- data/lib/kuber_kit/actions/service_deployer.rb +41 -66
- data/lib/kuber_kit/artifacts_sync/{artifacts_updater.rb → artifact_updater.rb} +7 -9
- data/lib/kuber_kit/cli.rb +18 -24
- data/lib/kuber_kit/container.rb +10 -2
- data/lib/kuber_kit/core/configuration.rb +10 -6
- data/lib/kuber_kit/core/configuration_definition.rb +11 -3
- data/lib/kuber_kit/core/configuration_factory.rb +2 -1
- data/lib/kuber_kit/image_compiler/action_handler.rb +3 -0
- data/lib/kuber_kit/service_deployer/deployment_options_selector.rb +49 -0
- data/lib/kuber_kit/service_deployer/service_list_resolver.rb +7 -2
- data/lib/kuber_kit/service_deployer/strategies/docker.rb +6 -1
- data/lib/kuber_kit/shell/local_shell.rb +12 -0
- data/lib/kuber_kit/tools/build_dir_cleaner.rb +26 -0
- data/lib/kuber_kit/tools/logger_factory.rb +6 -5
- data/lib/kuber_kit/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03c60b8fd02854d59ccad27ac3e512b726049d55f87f41d9c0ac0256344705ba
|
4
|
+
data.tar.gz: e60f2f47da61e2b5c3942878c19c863c2537bd5a6513476bb4a26aea81259674
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85bfd81c3419a8a44960c89e9e31d06a4775aa143141fdc8da8f46ea207d60a2be53310213a5cc96cf1fe034097c13f09d10256a72d0535bb6ee363d0a12c987
|
7
|
+
data.tar.gz: 7182215530a9ee4908e4e483c578764c3bbc63f4d510c89b68bf8a2cb15a5e41bf714eb553b1497ad2236af4e585feb0e6aa810b00bb8e0f3b3ff1357e9717bf
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
**0.6.1**
|
2
|
+
- Improve performance of artifacts update by updating in threads.
|
3
|
+
- Added an ability to define default services
|
4
|
+
|
5
|
+
**0.6.0**
|
6
|
+
- Cleanup old image build dirs
|
7
|
+
- Add rotation to deployment log file
|
8
|
+
|
9
|
+
**0.5.10**
|
10
|
+
- Fix a regression when deployment result would not be properly returned as json.
|
11
|
+
|
12
|
+
**0.5.9**
|
13
|
+
- Added an ability to set custom user
|
14
|
+
- Allow setting environment variable in docker strategy
|
15
|
+
- Properly stop deployment if image compilation is failed
|
16
|
+
|
1
17
|
**0.5.8**
|
2
18
|
- Update gemspec to support ruby 2.5
|
3
19
|
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
- add kit get method for more interactive kubernetes
|
2
|
-
- env files should use a separate deployment method (with change detection)
|
3
1
|
- add automatical confirmation support for service deployer
|
4
2
|
- template should be able to set default attributes
|
5
|
-
- template should be able to depend on image?
|
6
|
-
- cleanup image builds older than some date
|
7
|
-
- add some rotation for deploy log
|
8
|
-
- kit status should show the list of services and their status, with ability to select & view logs
|
3
|
+
- template should be able to depend on image?
|
data/lib/kuber_kit.rb
CHANGED
@@ -79,6 +79,7 @@ module KuberKit
|
|
79
79
|
end
|
80
80
|
|
81
81
|
module Tools
|
82
|
+
autoload :BuildDirCleaner, 'tools/build_dir_cleaner'
|
82
83
|
autoload :FilePresenceChecker, 'tools/file_presence_checker'
|
83
84
|
autoload :LoggerFactory, 'tools/logger_factory'
|
84
85
|
autoload :ProcessCleaner, 'tools/process_cleaner'
|
@@ -121,7 +122,7 @@ module KuberKit
|
|
121
122
|
|
122
123
|
module ArtifactsSync
|
123
124
|
autoload :AbstractArtifactResolver, 'artifacts_sync/abstract_artifact_resolver'
|
124
|
-
autoload :
|
125
|
+
autoload :ArtifactUpdater, 'artifacts_sync/artifact_updater'
|
125
126
|
autoload :GitArtifactResolver, 'artifacts_sync/git_artifact_resolver'
|
126
127
|
autoload :NullArtifactResolver, 'artifacts_sync/null_artifact_resolver'
|
127
128
|
end
|
@@ -153,6 +154,7 @@ module KuberKit
|
|
153
154
|
autoload :ActionHandler, 'service_deployer/action_handler'
|
154
155
|
autoload :StrategyDetector, 'service_deployer/strategy_detector'
|
155
156
|
autoload :Deployer, 'service_deployer/deployer'
|
157
|
+
autoload :DeploymentOptionsSelector, 'service_deployer/deployment_options_selector'
|
156
158
|
autoload :ServiceListResolver, 'service_deployer/service_list_resolver'
|
157
159
|
autoload :ServiceDependencyResolver, 'service_deployer/service_dependency_resolver'
|
158
160
|
|
@@ -170,6 +172,7 @@ module KuberKit
|
|
170
172
|
end
|
171
173
|
|
172
174
|
module Actions
|
175
|
+
autoload :ActionResult, 'actions/action_result'
|
173
176
|
autoload :ImageCompiler, 'actions/image_compiler'
|
174
177
|
autoload :EnvFileReader, 'actions/env_file_reader'
|
175
178
|
autoload :TemplateReader, 'actions/template_reader'
|
@@ -275,6 +278,11 @@ module KuberKit
|
|
275
278
|
KuberKit::Core::ContextHelper::BaseHelper.class_exec(&proc)
|
276
279
|
end
|
277
280
|
|
281
|
+
def set_user(value)
|
282
|
+
@user = value
|
283
|
+
@user_id = nil
|
284
|
+
end
|
285
|
+
|
278
286
|
def user
|
279
287
|
@user ||= ENV["KUBER_KIT_USERNAME"] || `whoami`.chomp
|
280
288
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class KuberKit::Actions::ActionResult
|
2
|
+
attr_reader :finished_tasks, :all_results, :error
|
3
|
+
|
4
|
+
def initialize()
|
5
|
+
@all_results = {}
|
6
|
+
@started_tasks = []
|
7
|
+
@finished_tasks = []
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def start_task(task)
|
12
|
+
@mutex.synchronize do
|
13
|
+
@started_tasks.push(task)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def finish_task(task, result = nil)
|
18
|
+
@mutex.synchronize do
|
19
|
+
@started_tasks.delete(task)
|
20
|
+
@finished_tasks.push(task)
|
21
|
+
@all_results[task] = result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def failed!(error)
|
26
|
+
@error = error
|
27
|
+
end
|
28
|
+
|
29
|
+
def succeeded?
|
30
|
+
@error.nil? && @started_tasks.empty?
|
31
|
+
end
|
32
|
+
end
|
@@ -5,7 +5,7 @@ class KuberKit::Actions::ConfigurationLoader
|
|
5
5
|
"core.service_store",
|
6
6
|
"core.configuration_store",
|
7
7
|
"tools.workdir_detector",
|
8
|
-
"artifacts_sync.
|
8
|
+
"artifacts_sync.artifact_updater",
|
9
9
|
"shell.local_shell",
|
10
10
|
"ui",
|
11
11
|
"configs"
|
@@ -43,11 +43,7 @@ class KuberKit::Actions::ConfigurationLoader
|
|
43
43
|
load_infrastructure(infra_path)
|
44
44
|
|
45
45
|
if load_inventory
|
46
|
-
|
47
|
-
artifacts = KuberKit.current_configuration.artifacts.values
|
48
|
-
artifacts_updater.update(local_shell, artifacts)
|
49
|
-
task.update_title("Updated #{artifacts.count} artifacts")
|
50
|
-
end
|
46
|
+
update_artifacts(KuberKit.current_configuration.artifacts.values)
|
51
47
|
|
52
48
|
ui.create_task("Loading image definitions") do |task|
|
53
49
|
files = image_store.load_definitions(images_path)
|
@@ -101,4 +97,17 @@ class KuberKit::Actions::ConfigurationLoader
|
|
101
97
|
rescue KuberKit::Shell::AbstractShell::DirNotFoundError
|
102
98
|
ui.print_warning("ConfigurationLoader", "Directory with infrastructure not found: #{infra_path}")
|
103
99
|
end
|
100
|
+
|
101
|
+
def update_artifacts(artifacts)
|
102
|
+
return unless artifacts.any?
|
103
|
+
|
104
|
+
artifact_task_group = ui.create_task_group
|
105
|
+
artifacts.each do |artifact|
|
106
|
+
artifact_task_group.add("Updating #{artifact.name.to_s.yellow}") do |task|
|
107
|
+
artifact_updater.update(local_shell, artifact)
|
108
|
+
task.update_title("Updated #{artifact.name.to_s.green}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
artifact_task_group.wait
|
112
|
+
end
|
104
113
|
end
|
@@ -10,38 +10,40 @@ class KuberKit::Actions::ImageCompiler
|
|
10
10
|
|
11
11
|
Contract ArrayOf[Symbol], Hash => Any
|
12
12
|
def call(image_names, options)
|
13
|
+
compilation_result = KuberKit::Actions::ActionResult.new()
|
14
|
+
|
13
15
|
build_id = generate_build_id
|
14
16
|
build_server_pool = build_server_pool_factory.create()
|
15
17
|
|
16
|
-
compiled_images = []
|
17
|
-
compilation_result = {}
|
18
18
|
image_dependency_resolver.each_with_deps(image_names) do |dep_image_names|
|
19
19
|
ui.print_debug("ImageCompiler", "Scheduling to compile: #{dep_image_names.inspect}. Limit: #{configs.compile_simultaneous_limit}")
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
|
21
|
+
if compilation_result.succeeded?
|
22
|
+
compile_simultaneously(dep_image_names, build_id, build_server_pool, compilation_result)
|
23
|
+
end
|
23
24
|
end
|
24
25
|
|
25
26
|
build_server_pool.disconnect_all
|
26
27
|
|
27
|
-
|
28
|
+
compilation_result
|
28
29
|
rescue KuberKit::Error => e
|
29
30
|
ui.print_error("Error", e.message)
|
30
31
|
|
32
|
+
compilation_result.failed!(e.message)
|
33
|
+
|
31
34
|
false
|
32
35
|
end
|
33
36
|
|
34
37
|
private
|
35
|
-
def compile_simultaneously(image_names, build_id, build_server_pool)
|
38
|
+
def compile_simultaneously(image_names, build_id, build_server_pool, compilation_result)
|
36
39
|
task_group = ui.create_task_group
|
37
|
-
compiler_result = {}
|
38
40
|
image_names.map do |image_name|
|
39
41
|
|
40
42
|
ui.print_debug("ImageCompiler", "Started compiling: #{image_name.to_s.green}")
|
41
43
|
task_group.add("Compiling #{image_name.to_s.yellow}") do |task|
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
compilation_result.start_task(image_name)
|
45
|
+
image_result = compile_one(image_name, build_id, build_server_pool)
|
46
|
+
compilation_result.finish_task(image_name, image_result)
|
45
47
|
|
46
48
|
task.update_title("Compiled #{image_name.to_s.green}")
|
47
49
|
ui.print_debug("ImageCompiler", "Finished compiling: #{image_name}")
|
@@ -49,7 +51,11 @@ class KuberKit::Actions::ImageCompiler
|
|
49
51
|
|
50
52
|
end
|
51
53
|
task_group.wait
|
52
|
-
|
54
|
+
end
|
55
|
+
|
56
|
+
def compile_one(image_name, build_id, build_server_pool)
|
57
|
+
shell = build_server_pool.get_shell
|
58
|
+
image_compiler.call(shell, image_name, build_id)
|
53
59
|
end
|
54
60
|
|
55
61
|
def generate_build_id
|
@@ -3,6 +3,7 @@ class KuberKit::Actions::ServiceDeployer
|
|
3
3
|
"actions.image_compiler",
|
4
4
|
"service_deployer.service_list_resolver",
|
5
5
|
"service_deployer.service_dependency_resolver",
|
6
|
+
"service_deployer.deployment_options_selector",
|
6
7
|
"core.service_store",
|
7
8
|
"shell.local_shell",
|
8
9
|
"tools.process_cleaner",
|
@@ -19,21 +20,24 @@ class KuberKit::Actions::ServiceDeployer
|
|
19
20
|
require_confirmation: Maybe[Bool],
|
20
21
|
] => Any
|
21
22
|
def call(services:, tags:, skip_services: nil, skip_compile: false, require_confirmation: false)
|
23
|
+
deployment_result = KuberKit::Actions::ActionResult.new()
|
22
24
|
current_configuration = KuberKit.current_configuration
|
23
25
|
|
24
26
|
if services.empty? && tags.empty?
|
25
|
-
services, tags =
|
27
|
+
services, tags = deployment_options_selector.call()
|
26
28
|
end
|
27
29
|
|
28
|
-
|
30
|
+
default_services = current_configuration.default_services.map(&:to_s)
|
29
31
|
disabled_services = current_configuration.disabled_services.map(&:to_s)
|
30
32
|
disabled_services += skip_services if skip_services
|
33
|
+
|
31
34
|
|
32
35
|
service_names = service_list_resolver.resolve(
|
33
36
|
services: services || [],
|
34
37
|
tags: tags || [],
|
35
38
|
enabled_services: current_configuration.enabled_services.map(&:to_s),
|
36
|
-
disabled_services: disabled_services
|
39
|
+
disabled_services: disabled_services,
|
40
|
+
default_services: default_services
|
37
41
|
).map(&:to_sym)
|
38
42
|
|
39
43
|
# Return the list of services with all dependencies.
|
@@ -44,54 +48,50 @@ class KuberKit::Actions::ServiceDeployer
|
|
44
48
|
return false
|
45
49
|
end
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if require_confirmation
|
51
|
-
result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
|
52
|
-
return false unless ["confirm".green, "confirm", "yes"].include?(result)
|
53
|
-
end
|
54
|
-
|
55
|
-
services = all_service_names.map do |service_name|
|
56
|
-
service_store.get_service(service_name.to_sym)
|
51
|
+
unless allow_deployment?(require_confirmation: require_confirmation, service_names: all_service_names)
|
52
|
+
return false
|
57
53
|
end
|
58
54
|
|
59
|
-
|
60
|
-
|
55
|
+
# Compile images for all services and dependencies
|
56
|
+
images_names = get_image_names(service_names: all_service_names)
|
61
57
|
unless skip_compile
|
62
|
-
|
63
|
-
|
58
|
+
compilation_result = compile_images(images_names)
|
59
|
+
|
60
|
+
return false unless compilation_result && compilation_result.succeeded?
|
64
61
|
end
|
65
62
|
|
66
|
-
deployed_services = []
|
67
|
-
deployment_result = {}
|
68
63
|
service_dependency_resolver.each_with_deps(service_names) do |dep_service_names|
|
69
64
|
ui.print_debug("ServiceDeployer", "Scheduling to compile: #{dep_service_names.inspect}. Limit: #{configs.deploy_simultaneous_limit}")
|
70
|
-
|
71
|
-
|
72
|
-
|
65
|
+
|
66
|
+
if deployment_result.succeeded?
|
67
|
+
deploy_simultaneously(dep_service_names, deployment_result)
|
68
|
+
end
|
73
69
|
end
|
74
70
|
|
75
|
-
|
71
|
+
deployment_result
|
76
72
|
rescue KuberKit::Error => e
|
77
73
|
ui.print_error("Error", e.message)
|
78
74
|
|
75
|
+
deployment_result.failed!(e.message)
|
76
|
+
|
79
77
|
false
|
80
78
|
rescue Interrupt => e
|
81
79
|
process_cleaner.clean
|
80
|
+
|
81
|
+
false
|
82
82
|
end
|
83
83
|
|
84
84
|
private
|
85
|
-
def deploy_simultaneously(service_names)
|
85
|
+
def deploy_simultaneously(service_names, deployment_result)
|
86
86
|
task_group = ui.create_task_group
|
87
87
|
|
88
|
-
deployer_result = {}
|
89
|
-
|
90
88
|
service_names.each do |service_name|
|
91
89
|
|
92
90
|
ui.print_debug("ServiceDeployer", "Started deploying: #{service_name.to_s.green}")
|
93
91
|
task_group.add("Deploying #{service_name.to_s.yellow}") do |task|
|
94
|
-
|
92
|
+
deployment_result.start_task(service_name)
|
93
|
+
service_result = service_deployer.call(local_shell, service_name.to_sym)
|
94
|
+
deployment_result.finish_task(service_name, service_result)
|
95
95
|
|
96
96
|
task.update_title("Deployed #{service_name.to_s.green}")
|
97
97
|
ui.print_debug("ServiceDeployer", "Finished deploying: #{service_name.to_s.green}")
|
@@ -99,55 +99,30 @@ class KuberKit::Actions::ServiceDeployer
|
|
99
99
|
end
|
100
100
|
|
101
101
|
task_group.wait
|
102
|
-
|
103
|
-
deployer_result
|
104
102
|
end
|
105
103
|
|
106
104
|
def compile_images(images_names)
|
107
|
-
return
|
105
|
+
return KuberKit::Actions::ActionResult.new if images_names.empty?
|
108
106
|
image_compiler.call(images_names, {})
|
109
107
|
end
|
110
108
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
tags = [specific_service_option, all_services_option]
|
116
|
-
tags += service_store
|
117
|
-
.all_definitions
|
118
|
-
.values
|
119
|
-
.map(&:to_service_attrs)
|
120
|
-
.map(&:tags)
|
121
|
-
.flatten
|
122
|
-
.uniq
|
123
|
-
.sort
|
124
|
-
.map(&:to_s)
|
125
|
-
|
126
|
-
selected_tag = ui.prompt("Please select which tag to deploy", tags)
|
127
|
-
|
128
|
-
if selected_tag == specific_service_option
|
129
|
-
show_service_selection
|
130
|
-
elsif selected_tag == all_services_option
|
131
|
-
[["*"], []]
|
132
|
-
else
|
133
|
-
[[], [selected_tag]]
|
109
|
+
def get_image_names(service_names:)
|
110
|
+
services = service_names.map do |service_name|
|
111
|
+
service_store.get_service(service_name.to_sym)
|
134
112
|
end
|
113
|
+
|
114
|
+
services.map(&:images).flatten.uniq
|
135
115
|
end
|
136
116
|
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
.sort
|
144
|
-
.map(&:to_s)
|
145
|
-
|
146
|
-
if services.empty?
|
147
|
-
return [[], []]
|
117
|
+
def allow_deployment?(require_confirmation:, service_names:)
|
118
|
+
services_list = service_names.map(&:to_s).map(&:yellow).join(", ")
|
119
|
+
ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
|
120
|
+
|
121
|
+
unless require_confirmation
|
122
|
+
return true
|
148
123
|
end
|
149
124
|
|
150
|
-
|
151
|
-
[
|
125
|
+
result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
|
126
|
+
return ["confirm".green, "confirm", "yes"].include?(result)
|
152
127
|
end
|
153
128
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class KuberKit::ArtifactsSync::
|
1
|
+
class KuberKit::ArtifactsSync::ArtifactUpdater
|
2
2
|
ResolverNotFoundError = Class.new(KuberKit::NotFoundError)
|
3
3
|
|
4
4
|
include KuberKit::Import[
|
@@ -18,18 +18,16 @@ class KuberKit::ArtifactsSync::ArtifactsUpdater
|
|
18
18
|
@@resolvers[artifact_class] = artifact_resolver
|
19
19
|
end
|
20
20
|
|
21
|
-
def update(shell,
|
21
|
+
def update(shell, artifact)
|
22
22
|
add_default_resolvers
|
23
23
|
|
24
|
-
|
25
|
-
resolver = @@resolvers[artifact.class]
|
24
|
+
resolver = @@resolvers[artifact.class]
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
ui.print_debug "ArtifactUpdater", "Updating artifact #{artifact.name.to_s.green}"
|
27
|
+
|
28
|
+
raise ResolverNotFoundError, "Can't find resolver for artifact #{artifact}" if resolver.nil?
|
30
29
|
|
31
|
-
|
32
|
-
end
|
30
|
+
resolver.resolve(shell, artifact)
|
33
31
|
end
|
34
32
|
|
35
33
|
def add_default_resolvers
|
data/lib/kuber_kit/cli.rb
CHANGED
@@ -10,6 +10,7 @@ class KuberKit::CLI < Thor
|
|
10
10
|
class_option :ui, :type => :string, :desc => "UI mode (interactive|debug|simple)"
|
11
11
|
class_option :debug, :type => :boolean, aliases: ["-d"]
|
12
12
|
class_option :configuration, :type => :string, aliases: ["-C"]
|
13
|
+
class_option :user, :type => :string, aliases: ["-u"]
|
13
14
|
|
14
15
|
desc "compile IMAGE_NAMES", "Compile image with IMAGE_NAMES (comma-separated)"
|
15
16
|
def compile(image_names_str)
|
@@ -19,12 +20,15 @@ class KuberKit::CLI < Thor
|
|
19
20
|
image_names = image_names_str.split(",").map(&:strip).map(&:to_sym)
|
20
21
|
|
21
22
|
if KuberKit::Container['actions.configuration_loader'].call(options)
|
22
|
-
|
23
|
+
action_result = KuberKit::Container['actions.image_compiler'].call(image_names, options)
|
23
24
|
end
|
24
25
|
|
25
|
-
if
|
26
|
+
if action_result && action_result.succeeded?
|
26
27
|
time = (Time.now.to_i - started_at)
|
27
|
-
print_result("Image compilation finished! (#{time}s)", result:
|
28
|
+
print_result("Image compilation finished! (#{time}s)", result: {
|
29
|
+
images: action_result.finished_tasks,
|
30
|
+
compilation: action_result.all_results
|
31
|
+
})
|
28
32
|
else
|
29
33
|
exit 1
|
30
34
|
end
|
@@ -41,10 +45,10 @@ class KuberKit::CLI < Thor
|
|
41
45
|
|
42
46
|
if KuberKit::Container['actions.configuration_loader'].call(options)
|
43
47
|
require_confirmation = options[:require_confirmation] ||
|
44
|
-
KuberKit.current_configuration.
|
48
|
+
KuberKit.current_configuration.deployer_require_confirmation ||
|
45
49
|
false
|
46
50
|
started_at = Time.now.to_i
|
47
|
-
|
51
|
+
action_result = KuberKit::Container['actions.service_deployer'].call(
|
48
52
|
services: (options[:services] || []).flatten.uniq,
|
49
53
|
tags: (options[:tags] || []).flatten.uniq,
|
50
54
|
skip_services: (options[:skip_services] || []).flatten.uniq,
|
@@ -53,9 +57,12 @@ class KuberKit::CLI < Thor
|
|
53
57
|
)
|
54
58
|
end
|
55
59
|
|
56
|
-
if
|
60
|
+
if action_result && action_result.succeeded?
|
57
61
|
time = (Time.now.to_i - started_at)
|
58
|
-
print_result("Service deployment finished! (#{time}s)", result:
|
62
|
+
print_result("Service deployment finished! (#{time}s)", result: {
|
63
|
+
services: action_result.finished_tasks,
|
64
|
+
deployment: action_result.all_results
|
65
|
+
})
|
59
66
|
else
|
60
67
|
exit 1
|
61
68
|
end
|
@@ -178,6 +185,10 @@ class KuberKit::CLI < Thor
|
|
178
185
|
KuberKit.set_ui_mode(options[:ui].to_sym)
|
179
186
|
end
|
180
187
|
|
188
|
+
if options[:user]
|
189
|
+
KuberKit.set_user(options[:user])
|
190
|
+
end
|
191
|
+
|
181
192
|
# We should load config before loading any bean, to make sure that bean won't be built with default config
|
182
193
|
root_path = KuberKit::Container['tools.workdir_detector'].call(options)
|
183
194
|
config_file_path = File.join(root_path, APP_CONFIG_FILENAME)
|
@@ -189,21 +200,4 @@ class KuberKit::CLI < Thor
|
|
189
200
|
def print_result(message, data = {})
|
190
201
|
KuberKit::Container['ui'].print_result(message, data)
|
191
202
|
end
|
192
|
-
|
193
|
-
def cleanup_processes
|
194
|
-
# Stop all threads
|
195
|
-
Thread.list.each do |t|
|
196
|
-
t.abort_on_exception = false
|
197
|
-
t.report_on_exception = false
|
198
|
-
Thread.kill(t) if t != Thread.current
|
199
|
-
end
|
200
|
-
|
201
|
-
# Find all system calls
|
202
|
-
child_pids_raw = `ps auxww | grep '[K]IT=#{Process.pid}' | awk '{print $2}'`
|
203
|
-
child_pids = child_pids_raw.to_s.split("\n").reject(&:empty?)
|
204
|
-
child_pids.each do |pid|
|
205
|
-
puts "Killing child process: #{pid}"
|
206
|
-
Process.kill("SIGHUP", pid.to_i)
|
207
|
-
end
|
208
|
-
end
|
209
203
|
end
|
data/lib/kuber_kit/container.rb
CHANGED
@@ -121,6 +121,10 @@ class KuberKit::Container
|
|
121
121
|
KuberKit::Core::ContextHelper::ContextHelperFactory.new
|
122
122
|
end
|
123
123
|
|
124
|
+
register "tools.build_dir_cleaner" do
|
125
|
+
KuberKit::Tools::BuildDirCleaner.new
|
126
|
+
end
|
127
|
+
|
124
128
|
register "tools.file_presence_checker" do
|
125
129
|
KuberKit::Tools::FilePresenceChecker.new
|
126
130
|
end
|
@@ -213,8 +217,8 @@ class KuberKit::Container
|
|
213
217
|
KuberKit::ImageCompiler::VersionTagBuilder.new
|
214
218
|
end
|
215
219
|
|
216
|
-
register "artifacts_sync.
|
217
|
-
KuberKit::ArtifactsSync::
|
220
|
+
register "artifacts_sync.artifact_updater" do
|
221
|
+
KuberKit::ArtifactsSync::ArtifactUpdater.new
|
218
222
|
end
|
219
223
|
|
220
224
|
register "artifacts_sync.git_artifact_resolver" do
|
@@ -273,6 +277,10 @@ class KuberKit::Container
|
|
273
277
|
KuberKit::ServiceDeployer::Deployer.new
|
274
278
|
end
|
275
279
|
|
280
|
+
register "service_deployer.deployment_options_selector" do
|
281
|
+
KuberKit::ServiceDeployer::DeploymentOptionsSelector.new
|
282
|
+
end
|
283
|
+
|
276
284
|
register "service_deployer.service_list_resolver" do
|
277
285
|
KuberKit::ServiceDeployer::ServiceListResolver.new
|
278
286
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class KuberKit::Core::Configuration
|
2
2
|
attr_reader :name, :artifacts, :registries, :env_files, :templates, :kubeconfig_path,
|
3
|
-
:services_attributes, :enabled_services, :disabled_services, :
|
4
|
-
:
|
3
|
+
:services_attributes, :enabled_services, :disabled_services, :default_services,
|
4
|
+
:build_servers, :global_build_vars,
|
5
|
+
:deployer_strategy, :deployer_namespace, :deployer_require_confirmation
|
5
6
|
|
6
7
|
Contract KeywordArgs[
|
7
8
|
name: Symbol,
|
@@ -13,15 +14,17 @@ class KuberKit::Core::Configuration
|
|
13
14
|
services_attributes: HashOf[Symbol => Hash],
|
14
15
|
enabled_services: ArrayOf[Symbol],
|
15
16
|
disabled_services: ArrayOf[Symbol],
|
17
|
+
default_services: ArrayOf[Symbol],
|
16
18
|
build_servers: ArrayOf[KuberKit::Core::BuildServers::AbstractBuildServer],
|
17
19
|
global_build_vars: HashOf[Symbol => Any],
|
18
20
|
deployer_strategy: Symbol,
|
19
21
|
deployer_namespace: Maybe[Symbol],
|
20
|
-
|
22
|
+
deployer_require_confirmation: Bool,
|
21
23
|
] => Any
|
22
24
|
def initialize(name:, artifacts:, registries:, env_files:, templates:, kubeconfig_path:,
|
23
|
-
services_attributes:, enabled_services:, disabled_services:,
|
24
|
-
|
25
|
+
services_attributes:, enabled_services:, disabled_services:, default_services:,
|
26
|
+
build_servers:, global_build_vars:,
|
27
|
+
deployer_strategy:, deployer_namespace:, deployer_require_confirmation:)
|
25
28
|
@name = name
|
26
29
|
@artifacts = artifacts
|
27
30
|
@registries = registries
|
@@ -32,10 +35,11 @@ class KuberKit::Core::Configuration
|
|
32
35
|
@services_attributes = services_attributes
|
33
36
|
@enabled_services = enabled_services
|
34
37
|
@disabled_services = disabled_services
|
38
|
+
@default_services = default_services
|
35
39
|
@global_build_vars = global_build_vars
|
36
40
|
@deployer_strategy = deployer_strategy
|
37
41
|
@deployer_namespace = deployer_namespace
|
38
|
-
@
|
42
|
+
@deployer_require_confirmation = deployer_require_confirmation
|
39
43
|
end
|
40
44
|
|
41
45
|
def service_attributes(service_name)
|
@@ -13,6 +13,7 @@ class KuberKit::Core::ConfigurationDefinition
|
|
13
13
|
@build_servers = []
|
14
14
|
@enabled_services = []
|
15
15
|
@disabled_services = []
|
16
|
+
@default_services = []
|
16
17
|
@services_attributes = {}
|
17
18
|
end
|
18
19
|
|
@@ -26,12 +27,13 @@ class KuberKit::Core::ConfigurationDefinition
|
|
26
27
|
kubeconfig_path: @kubeconfig_path,
|
27
28
|
enabled_services: @enabled_services,
|
28
29
|
disabled_services: @disabled_services,
|
30
|
+
default_services: @default_services,
|
29
31
|
build_servers: @build_servers,
|
30
32
|
services_attributes: @services_attributes,
|
31
33
|
global_build_vars: @global_build_vars,
|
32
34
|
deployer_strategy: @deployer_strategy,
|
33
35
|
deployer_namespace: @deployer_namespace,
|
34
|
-
|
36
|
+
deployer_require_confirmation: @deployer_require_confirmation || false,
|
35
37
|
)
|
36
38
|
end
|
37
39
|
|
@@ -97,11 +99,12 @@ class KuberKit::Core::ConfigurationDefinition
|
|
97
99
|
self
|
98
100
|
end
|
99
101
|
|
100
|
-
def
|
101
|
-
@
|
102
|
+
def deployer_require_confirmation
|
103
|
+
@deployer_require_confirmation = true
|
102
104
|
|
103
105
|
self
|
104
106
|
end
|
107
|
+
alias_method :deployer_require_confirimation, :deployer_require_confirmation
|
105
108
|
|
106
109
|
def enabled_services(services)
|
107
110
|
if services.is_a?(Hash)
|
@@ -118,6 +121,11 @@ class KuberKit::Core::ConfigurationDefinition
|
|
118
121
|
raise KuberKit::Error, "#enabled_services method accepts only Array or Hash"
|
119
122
|
end
|
120
123
|
|
124
|
+
def default_services(services)
|
125
|
+
@default_services += services.map(&:to_sym)
|
126
|
+
return self
|
127
|
+
end
|
128
|
+
|
121
129
|
def disabled_services(services)
|
122
130
|
@disabled_services += services.map(&:to_sym)
|
123
131
|
return self
|
@@ -30,10 +30,11 @@ class KuberKit::Core::ConfigurationFactory
|
|
30
30
|
services_attributes: configuration_attrs.services_attributes,
|
31
31
|
enabled_services: configuration_attrs.enabled_services,
|
32
32
|
disabled_services: configuration_attrs.disabled_services,
|
33
|
+
default_services: configuration_attrs.default_services,
|
33
34
|
global_build_vars: configuration_attrs.global_build_vars || {},
|
34
35
|
deployer_strategy: configuration_attrs.deployer_strategy || configs.deployer_strategy,
|
35
36
|
deployer_namespace: configuration_attrs.deployer_namespace,
|
36
|
-
|
37
|
+
deployer_require_confirmation: configuration_attrs.deployer_require_confirmation,
|
37
38
|
)
|
38
39
|
end
|
39
40
|
|
@@ -2,12 +2,15 @@ class KuberKit::ImageCompiler::ActionHandler
|
|
2
2
|
include KuberKit::Import[
|
3
3
|
"image_compiler.compiler",
|
4
4
|
"core.image_store",
|
5
|
+
"tools.build_dir_cleaner",
|
5
6
|
"configs",
|
6
7
|
]
|
7
8
|
|
8
9
|
Contract KuberKit::Shell::AbstractShell, Symbol, String => Any
|
9
10
|
def call(shell, image_name, build_id)
|
10
11
|
image = image_store.get_image(image_name)
|
12
|
+
|
13
|
+
build_dir_cleaner.call(parent_dir: configs.image_compile_dir)
|
11
14
|
|
12
15
|
compile_dir = generate_compile_dir(build_id: build_id)
|
13
16
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class KuberKit::ServiceDeployer::DeploymentOptionsSelector
|
2
|
+
include KuberKit::Import[
|
3
|
+
"core.service_store",
|
4
|
+
"ui"
|
5
|
+
]
|
6
|
+
|
7
|
+
OPTION_SPECIFIC_SERVICE = "deploy specific service".freeze
|
8
|
+
OPTION_ALL_SERVICES = "deploy all services"
|
9
|
+
|
10
|
+
def call()
|
11
|
+
tags = [OPTION_SPECIFIC_SERVICE, OPTION_ALL_SERVICES]
|
12
|
+
tags += service_store
|
13
|
+
.all_definitions
|
14
|
+
.values
|
15
|
+
.map(&:to_service_attrs)
|
16
|
+
.map(&:tags)
|
17
|
+
.flatten
|
18
|
+
.uniq
|
19
|
+
.sort
|
20
|
+
.map(&:to_s)
|
21
|
+
|
22
|
+
selected_tag = ui.prompt("Please select which tag to deploy", tags)
|
23
|
+
|
24
|
+
if selected_tag == OPTION_SPECIFIC_SERVICE
|
25
|
+
show_service_selection
|
26
|
+
elsif selected_tag == OPTION_ALL_SERVICES
|
27
|
+
[["*"], []]
|
28
|
+
else
|
29
|
+
[[], [selected_tag]]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def show_service_selection()
|
34
|
+
services = service_store
|
35
|
+
.all_definitions
|
36
|
+
.values
|
37
|
+
.map(&:service_name)
|
38
|
+
.uniq
|
39
|
+
.sort
|
40
|
+
.map(&:to_s)
|
41
|
+
|
42
|
+
if services.empty?
|
43
|
+
return [[], []]
|
44
|
+
end
|
45
|
+
|
46
|
+
selected_service = ui.prompt("Please select which service to deploy", services)
|
47
|
+
[[selected_service], []]
|
48
|
+
end
|
49
|
+
end
|
@@ -7,9 +7,10 @@ class KuberKit::ServiceDeployer::ServiceListResolver
|
|
7
7
|
services: Optional[ArrayOf[String]],
|
8
8
|
tags: Optional[ArrayOf[String]],
|
9
9
|
enabled_services: Optional[ArrayOf[String]],
|
10
|
-
disabled_services: Optional[ArrayOf[String]]
|
10
|
+
disabled_services: Optional[ArrayOf[String]],
|
11
|
+
default_services: Optional[ArrayOf[String]]
|
11
12
|
] => ArrayOf[String]
|
12
|
-
def resolve(services: [], tags: [], enabled_services: [], disabled_services: [])
|
13
|
+
def resolve(services: [], tags: [], enabled_services: [], disabled_services: [], default_services: [])
|
13
14
|
all_definitions = service_store.all_definitions.values
|
14
15
|
|
15
16
|
included_services, excluded_services = split_by_inclusion(services)
|
@@ -41,6 +42,10 @@ class KuberKit::ServiceDeployer::ServiceListResolver
|
|
41
42
|
included_services = included_services.select{ |s| !disabled_services.include?(s) }
|
42
43
|
end
|
43
44
|
|
45
|
+
if included_services.any?
|
46
|
+
included_services += default_services
|
47
|
+
end
|
48
|
+
|
44
49
|
included_services
|
45
50
|
end
|
46
51
|
|
@@ -20,7 +20,8 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
|
|
20
20
|
:networks,
|
21
21
|
:expose,
|
22
22
|
:publish,
|
23
|
-
:env_file_names
|
23
|
+
:env_file_names,
|
24
|
+
:env_vars
|
24
25
|
]
|
25
26
|
|
26
27
|
Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
|
@@ -44,6 +45,7 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
|
|
44
45
|
|
45
46
|
env_file_names = strategy_options.fetch(:env_file_names, [])
|
46
47
|
env_files = prepare_env_files(shell, env_file_names)
|
48
|
+
env_vars = strategy_options.fetch(:env_vars, {})
|
47
49
|
|
48
50
|
image_name = strategy_options.fetch(:image_name, nil)
|
49
51
|
if image_name.nil?
|
@@ -84,6 +86,9 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
|
|
84
86
|
Array(env_files).each do |env_file|
|
85
87
|
custom_args << "--env-file #{env_file}"
|
86
88
|
end
|
89
|
+
env_vars.each do |key, value|
|
90
|
+
custom_args << "--env #{key}=#{value}"
|
91
|
+
end
|
87
92
|
|
88
93
|
docker_commands.run(
|
89
94
|
shell, image.remote_registry_url,
|
@@ -100,6 +100,18 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
def list_dirs(path)
|
104
|
+
command = %Q{find -L #{path} -type f}
|
105
|
+
command += " -name '#{name}'" if name
|
106
|
+
exec!(command).split(/[\r\n]+/)
|
107
|
+
rescue => e
|
108
|
+
if e.message.include?("No such file or directory")
|
109
|
+
raise DirNotFoundError.new("Dir not found: #{path}")
|
110
|
+
else
|
111
|
+
raise e
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
103
115
|
def wrap_command_with_pid(command)
|
104
116
|
"KIT=#{Process.pid} #{command}"
|
105
117
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class KuberKit::Tools::BuildDirCleaner
|
2
|
+
include KuberKit::Import[
|
3
|
+
"shell.bash_commands",
|
4
|
+
"shell.local_shell",
|
5
|
+
]
|
6
|
+
|
7
|
+
KEEP_DIRS_COUNT = 10
|
8
|
+
|
9
|
+
def call(parent_dir:)
|
10
|
+
dirs_to_delete = get_ancient_builds_dirs(parent_dir: parent_dir)
|
11
|
+
|
12
|
+
dirs_to_delete.each do |dir|
|
13
|
+
bash_commands.rm_rf(local_shell, dir)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def get_ancient_builds_dirs(parent_dir:)
|
19
|
+
all_dirs = Dir.glob("#{parent_dir}/*")
|
20
|
+
skip_dirs = all_dirs
|
21
|
+
.sort_by{ |f| File.ctime(f) }
|
22
|
+
.reverse[0...KEEP_DIRS_COUNT]
|
23
|
+
|
24
|
+
all_dirs - skip_dirs
|
25
|
+
end
|
26
|
+
end
|
@@ -10,16 +10,17 @@ class KuberKit::Tools::LoggerFactory
|
|
10
10
|
Logger::FATAL => String::Colors::PURPLE,
|
11
11
|
}
|
12
12
|
|
13
|
+
MAX_LOGS_TO_KEEP = 3
|
14
|
+
MAX_LOG_FILE_SIZE = 512000
|
15
|
+
|
13
16
|
include KuberKit::Import[
|
14
17
|
"configs",
|
15
18
|
]
|
16
19
|
|
17
|
-
def create(
|
18
|
-
|
19
|
-
prepare_log_file(configs.log_file_path)
|
20
|
-
end
|
20
|
+
def create(level: nil)
|
21
|
+
prepare_log_file(configs.log_file_path)
|
21
22
|
|
22
|
-
logger = Logger.new(
|
23
|
+
logger = Logger.new(configs.log_file_path, MAX_LOGS_TO_KEEP, MAX_LOG_FILE_SIZE)
|
23
24
|
|
24
25
|
logger.level = level || Logger::DEBUG
|
25
26
|
|
data/lib/kuber_kit/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kuber_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Iskander Khaziev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: contracts-lite
|
@@ -198,6 +198,8 @@ files:
|
|
198
198
|
- example/images/app_sources/Dockerfile
|
199
199
|
- example/images/app_sources/build_context/source.rb
|
200
200
|
- example/images/app_sources/image.rb
|
201
|
+
- example/images/failing_app/Dockerfile
|
202
|
+
- example/images/failing_app/image.rb
|
201
203
|
- example/images/ruby/Dockerfile
|
202
204
|
- example/images/ruby/image.rb
|
203
205
|
- example/images/ruby_app/Dockerfile
|
@@ -214,9 +216,11 @@ files:
|
|
214
216
|
- example/services/compose_app.rb
|
215
217
|
- example/services/docker_app.rb
|
216
218
|
- example/services/env_file.rb
|
219
|
+
- example/services/failing_app.rb
|
217
220
|
- example/services/ruby_app.rb
|
218
221
|
- kuber_kit.gemspec
|
219
222
|
- lib/kuber_kit.rb
|
223
|
+
- lib/kuber_kit/actions/action_result.rb
|
220
224
|
- lib/kuber_kit/actions/configuration_loader.rb
|
221
225
|
- lib/kuber_kit/actions/env_file_reader.rb
|
222
226
|
- lib/kuber_kit/actions/image_compiler.rb
|
@@ -232,7 +236,7 @@ files:
|
|
232
236
|
- lib/kuber_kit/actions/service_reader.rb
|
233
237
|
- lib/kuber_kit/actions/template_reader.rb
|
234
238
|
- lib/kuber_kit/artifacts_sync/abstract_artifact_resolver.rb
|
235
|
-
- lib/kuber_kit/artifacts_sync/
|
239
|
+
- lib/kuber_kit/artifacts_sync/artifact_updater.rb
|
236
240
|
- lib/kuber_kit/artifacts_sync/git_artifact_resolver.rb
|
237
241
|
- lib/kuber_kit/artifacts_sync/null_artifact_resolver.rb
|
238
242
|
- lib/kuber_kit/cli.rb
|
@@ -302,6 +306,7 @@ files:
|
|
302
306
|
- lib/kuber_kit/preprocessing/text_preprocessor.rb
|
303
307
|
- lib/kuber_kit/service_deployer/action_handler.rb
|
304
308
|
- lib/kuber_kit/service_deployer/deployer.rb
|
309
|
+
- lib/kuber_kit/service_deployer/deployment_options_selector.rb
|
305
310
|
- lib/kuber_kit/service_deployer/service_dependency_resolver.rb
|
306
311
|
- lib/kuber_kit/service_deployer/service_list_resolver.rb
|
307
312
|
- lib/kuber_kit/service_deployer/strategies/abstract.rb
|
@@ -327,6 +332,7 @@ files:
|
|
327
332
|
- lib/kuber_kit/template_reader/reader.rb
|
328
333
|
- lib/kuber_kit/template_reader/strategies/abstract.rb
|
329
334
|
- lib/kuber_kit/template_reader/strategies/artifact_file.rb
|
335
|
+
- lib/kuber_kit/tools/build_dir_cleaner.rb
|
330
336
|
- lib/kuber_kit/tools/file_presence_checker.rb
|
331
337
|
- lib/kuber_kit/tools/logger_factory.rb
|
332
338
|
- lib/kuber_kit/tools/process_cleaner.rb
|