kuber_kit 0.5.8 → 0.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43a9f6570da4774b94202c3bc69218d3ed09f6884f94a0298e08b33c31f0ece4
4
- data.tar.gz: 1f6ab288380f5de3e202de937bd46b6cdc810bfbf4454b2a3109797f7a9ba8e1
3
+ metadata.gz: 03c60b8fd02854d59ccad27ac3e512b726049d55f87f41d9c0ac0256344705ba
4
+ data.tar.gz: e60f2f47da61e2b5c3942878c19c863c2537bd5a6513476bb4a26aea81259674
5
5
  SHA512:
6
- metadata.gz: 4af8a912626d5f37811d2abfa042334654cb950a5e640e6e46d9abb1094d3e54c16341b5e42a1af8d0db68ef433ba5b3147af86fe5cf23b501e93c6fe6f6de4a
7
- data.tar.gz: f357c787ab98eb2173cb7048191eec24fad97489f51a1ec57f38fcbdf695609aee2a96d496bd57f47216188cfcd073d9bcc11391be7ddfb4d77816466a00b0bf
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kuber_kit (0.5.8)
4
+ kuber_kit (0.6.1)
5
5
  cli-ui
6
6
  contracts-lite
7
7
  dry-auto_inject (~> 0.7.0)
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?
@@ -3,7 +3,8 @@ apiVersion: apps/v1
3
3
  kind: Deployment
4
4
  metadata:
5
5
  labels:
6
- app: <%= service_uri %>
6
+ app: <%= service_uri %>
7
+ user: <%= KuberKit.user %>
7
8
  name: <%= service_uri %>
8
9
  spec:
9
10
  replicas: 1
@@ -0,0 +1,5 @@
1
+ FROM <%= image_url(:ruby) %>
2
+
3
+ RUN not_existing_command
4
+
5
+ CMD ["tail", "-f", "/dev/null"]
@@ -0,0 +1,4 @@
1
+ KuberKit
2
+ .define_image(:failing_app)
3
+ .registry(:default)
4
+ .depends_on(:ruby, :app_sources)
@@ -0,0 +1,6 @@
1
+ KuberKit
2
+ .define_service(:failing_app)
3
+ .depends_on(:env_file)
4
+ .template(:service)
5
+ .images(:failing_app)
6
+ .tags("app", "minimal")
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 :ArtifactsUpdater, 'artifacts_sync/artifacts_updater'
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.artifacts_updater",
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
- ui.create_task("Updating artifacts") do |task|
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
- result = compile_simultaneously(dep_image_names, build_id, build_server_pool)
21
- compiled_images += dep_image_names
22
- compilation_result = compilation_result.merge(result)
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
- { images: compiled_images, compilation: compilation_result }
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
- shell = build_server_pool.get_shell
43
-
44
- compiler_result[image_name] = image_compiler.call(shell, image_name, build_id)
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
- compiler_result
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 = show_tags_selection
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
- services_list = all_service_names.map(&:to_s).map(&:yellow).join(", ")
48
- ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
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
- images_names = services.map(&:images).flatten.uniq
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
- compile_result = compile_images(images_names)
63
- return false unless compile_result
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
- result = deploy_simultaneously(dep_service_names)
71
- deployed_services += dep_service_names
72
- deployment_result = deployment_result.merge(result)
65
+
66
+ if deployment_result.succeeded?
67
+ deploy_simultaneously(dep_service_names, deployment_result)
68
+ end
73
69
  end
74
70
 
75
- { services: all_service_names, deployment: deployment_result }
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
- deployer_result[service_name] = service_deployer.call(local_shell, service_name.to_sym)
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 true if images_names.empty?
105
+ return KuberKit::Actions::ActionResult.new if images_names.empty?
108
106
  image_compiler.call(images_names, {})
109
107
  end
110
108
 
111
- def show_tags_selection()
112
- specific_service_option = "deploy specific service"
113
- all_services_option = "deploy all services"
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 show_service_selection()
138
- services = service_store
139
- .all_definitions
140
- .values
141
- .map(&:service_name)
142
- .uniq
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
- selected_service = ui.prompt("Please select which service to deploy", services)
151
- [[selected_service], []]
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::ArtifactsUpdater
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, artifacts)
21
+ def update(shell, artifact)
22
22
  add_default_resolvers
23
23
 
24
- artifacts.each do |artifact|
25
- resolver = @@resolvers[artifact.class]
24
+ resolver = @@resolvers[artifact.class]
26
25
 
27
- ui.print_debug "ArtifactUpdater", "Updating artifact #{artifact.name.to_s.green}"
28
-
29
- raise ResolverNotFoundError, "Can't find resolver for artifact #{artifact}" if resolver.nil?
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
- resolver.resolve(shell, artifact)
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
- result = KuberKit::Container['actions.image_compiler'].call(image_names, options)
23
+ action_result = KuberKit::Container['actions.image_compiler'].call(image_names, options)
23
24
  end
24
25
 
25
- if result
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: 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.deployer_require_confirimation ||
48
+ KuberKit.current_configuration.deployer_require_confirmation ||
45
49
  false
46
50
  started_at = Time.now.to_i
47
- result = KuberKit::Container['actions.service_deployer'].call(
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 result
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: 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
@@ -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.artifacts_updater" do
217
- KuberKit::ArtifactsSync::ArtifactsUpdater.new
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, :build_servers, :global_build_vars,
4
- :deployer_strategy, :deployer_namespace, :deployer_require_confirimation
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
- deployer_require_confirimation: Bool,
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:, build_servers:, global_build_vars:,
24
- deployer_strategy:, deployer_namespace:, deployer_require_confirimation:)
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
- @deployer_require_confirimation = deployer_require_confirimation
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
- deployer_require_confirimation: @deployer_require_confirimation || false,
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 deployer_require_confirimation
101
- @deployer_require_confirimation = true
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
- deployer_require_confirimation: configuration_attrs.deployer_require_confirimation,
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(stdout = nil, level = nil)
18
- if !stdout
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(stdout || configs.log_file_path)
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
 
@@ -1,3 +1,3 @@
1
1
  module KuberKit
2
- VERSION = "0.5.8"
2
+ VERSION = "0.6.1"
3
3
  end
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.5.8
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-06-17 00:00:00.000000000 Z
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/artifacts_updater.rb
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