kuber_kit 0.4.7 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile.lock +2 -2
  4. data/TODO.md +7 -5
  5. data/example/images/ruby_app/Dockerfile +3 -1
  6. data/example/services/docker_app.rb +1 -1
  7. data/example/services/ruby_app.rb +1 -0
  8. data/lib/kuber_kit.rb +10 -0
  9. data/lib/kuber_kit/actions/kubectl_attacher.rb +2 -2
  10. data/lib/kuber_kit/actions/kubectl_console.rb +2 -2
  11. data/lib/kuber_kit/actions/kubectl_describe.rb +2 -2
  12. data/lib/kuber_kit/actions/kubectl_env.rb +19 -0
  13. data/lib/kuber_kit/actions/kubectl_logs.rb +2 -2
  14. data/lib/kuber_kit/actions/service_checker.rb +32 -0
  15. data/lib/kuber_kit/actions/service_deployer.rb +78 -59
  16. data/lib/kuber_kit/cli.rb +35 -0
  17. data/lib/kuber_kit/configs.rb +2 -1
  18. data/lib/kuber_kit/container.rb +24 -0
  19. data/lib/kuber_kit/core/dependencies/abstract_dependency_resolver.rb +75 -0
  20. data/lib/kuber_kit/core/image.rb +2 -1
  21. data/lib/kuber_kit/core/service.rb +4 -2
  22. data/lib/kuber_kit/core/service_definition.rb +13 -6
  23. data/lib/kuber_kit/core/service_factory.rb +1 -0
  24. data/lib/kuber_kit/image_compiler/image_dependency_resolver.rb +5 -53
  25. data/lib/kuber_kit/kubernetes/resource_selector.rb +33 -0
  26. data/lib/kuber_kit/kubernetes/resources_fetcher.rb +7 -30
  27. data/lib/kuber_kit/service_deployer/service_dependency_resolver.rb +14 -0
  28. data/lib/kuber_kit/service_deployer/strategies/docker.rb +18 -1
  29. data/lib/kuber_kit/service_deployer/strategies/kubernetes.rb +9 -2
  30. data/lib/kuber_kit/shell/commands/kubectl_commands.rb +12 -4
  31. data/lib/kuber_kit/shell/commands/system_commands.rb +32 -0
  32. data/lib/kuber_kit/shell/local_shell.rb +6 -2
  33. data/lib/kuber_kit/shell/ssh_shell.rb +1 -1
  34. data/lib/kuber_kit/tools/process_cleaner.rb +38 -0
  35. data/lib/kuber_kit/version.rb +1 -1
  36. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 197d241ca2d0f76b0d8d749db348c3f033d63f619e4d1af223fc2b7886131b24
4
- data.tar.gz: 984d1db7f60e0bd1669aacc88f8b8901ff0be18a3a7d286b41c998aa661ac6f9
3
+ metadata.gz: 485e80726d7350ce239a165860ba4096b3549178d10e5ff8abdc918df983ab4c
4
+ data.tar.gz: 480a475c88bf4a6626a182ade7909e0a08143a978d96471faf0c2495021abf6a
5
5
  SHA512:
6
- metadata.gz: 2b0fd0641482e5d1510d3a4ab04715ebe417a026bb2face987f923d4cba65e30532b2e2bb7cf3d10a6088a1e729e4fdefaa323a686c28bd917c1e2952b2eac5b
7
- data.tar.gz: f7d083f24f6194f0815fd01a7b953c93db75e33c3db50d3c7e1677798be45f2a3f479500643cf4b83174f9aca65848f8313f873a07bb339881b76fbb6ff04ec8
6
+ metadata.gz: d285c169ea188e3c8d4679db94ea74a7c3b5cabc993fbd41e675d590505d1f714836de4b052cd1b1793d810069b1d61f2520d78bcc8c538a6efaa95730f0dc2d
7
+ data.tar.gz: b645418d23a5e68f5bebf571dcd2853d460cadd42247ccc749b5c938825b08671059fedd3cbb83fd960cc3deb8a6eb0a121c11468e4dc7e365dc89b803046383
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ **0.5.2**
2
+ - Added dependencies support to services
3
+ - Added an option to deploy all services in `kit deloy`
4
+ - Wait for rollout to finish during service deploy
5
+ - Deploy services in batches, not all of the simultaneously
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kuber_kit (0.4.7)
4
+ kuber_kit (0.5.2)
5
5
  cli-ui
6
6
  contracts-lite
7
7
  dry-auto_inject
@@ -20,7 +20,7 @@ GEM
20
20
  docile (1.3.2)
21
21
  dry-auto_inject (0.7.0)
22
22
  dry-container (>= 0.3.4)
23
- dry-configurable (0.12.0)
23
+ dry-configurable (0.12.1)
24
24
  concurrent-ruby (~> 1.0)
25
25
  dry-core (~> 0.5, >= 0.5.0)
26
26
  dry-container (0.7.2)
data/TODO.md CHANGED
@@ -1,7 +1,9 @@
1
- - add kit get method for interactive kubernetes
2
- - do not show result for images list, if list is too large
3
- - kit status should show the list of services and their status, with ability to select & view logs
4
- - find a way to always deploy some service, e.g. for migrations and env_files
1
+ - do not show result for images list, if list is too large (Mikhail)
2
+ - add kit get method for more interactive kubernetes
3
+ - env files should use a separate deployment method (with change detection)
4
+ - add automatical confirmation support for service deployer
5
5
  - template should be able to set default attributes
6
6
  - template should be able to depend on image?
7
- - cleanup image builds older than some date
7
+ - cleanup image builds older than some date
8
+ - add some rotation for deploy log
9
+ - kit status should show the list of services and their status, with ability to select & view logs
@@ -8,4 +8,6 @@ COPY README.md README.md
8
8
 
9
9
  RUN ruby /app/source.rb
10
10
 
11
- COPY example_file.txt <%= build_vars.example_file_name %>
11
+ COPY example_file.txt <%= build_vars.example_file_name %>
12
+
13
+ CMD ["tail", "-f", "/dev/null"]
@@ -4,7 +4,7 @@ KuberKit
4
4
  .deployer_strategy(:docker)
5
5
  .attributes(
6
6
  deployer: {
7
- detached: true,
7
+ detached: false,
8
8
  image_name: :ruby_app,
9
9
  container_name: "test_docker_app",
10
10
  delete_if_exists: true
@@ -1,5 +1,6 @@
1
1
  KuberKit
2
2
  .define_service(:ruby_app)
3
+ .depends_on(:env_file)
3
4
  .template(:service)
4
5
  .images(:ruby_app)
5
6
  .tags("app")
data/lib/kuber_kit.rb CHANGED
@@ -46,6 +46,10 @@ module KuberKit
46
46
  autoload :BuildServer, 'core/build_servers/build_server'
47
47
  end
48
48
 
49
+ module Dependencies
50
+ autoload :AbstractDependencyResolver, 'core/dependencies/abstract_dependency_resolver'
51
+ end
52
+
49
53
  module EnvFiles
50
54
  autoload :EnvFileStore, 'core/env_files/env_file_store'
51
55
  autoload :AbstractEnvFile, 'core/env_files/abstract_env_file'
@@ -76,6 +80,7 @@ module KuberKit
76
80
  module Tools
77
81
  autoload :FilePresenceChecker, 'tools/file_presence_checker'
78
82
  autoload :LoggerFactory, 'tools/logger_factory'
83
+ autoload :ProcessCleaner, 'tools/process_cleaner'
79
84
  end
80
85
 
81
86
  module Shell
@@ -92,6 +97,7 @@ module KuberKit
92
97
  autoload :GitCommands, 'shell/commands/git_commands'
93
98
  autoload :RsyncCommands, 'shell/commands/rsync_commands'
94
99
  autoload :KubectlCommands, 'shell/commands/kubectl_commands'
100
+ autoload :SystemCommands, 'shell/commands/system_commands'
95
101
  end
96
102
  end
97
103
 
@@ -143,6 +149,7 @@ module KuberKit
143
149
  autoload :StrategyDetector, 'service_deployer/strategy_detector'
144
150
  autoload :Deployer, 'service_deployer/deployer'
145
151
  autoload :ServiceListResolver, 'service_deployer/service_list_resolver'
152
+ autoload :ServiceDependencyResolver, 'service_deployer/service_dependency_resolver'
146
153
 
147
154
  module Strategies
148
155
  autoload :Abstract, 'service_deployer/strategies/abstract'
@@ -163,12 +170,14 @@ module KuberKit
163
170
  autoload :TemplateReader, 'actions/template_reader'
164
171
  autoload :ServiceReader, 'actions/service_reader'
165
172
  autoload :ServiceDeployer, 'actions/service_deployer'
173
+ autoload :ServiceChecker, 'actions/service_checker'
166
174
  autoload :ConfigurationLoader, 'actions/configuration_loader'
167
175
  autoload :KubectlApplier, 'actions/kubectl_applier'
168
176
  autoload :KubectlAttacher, 'actions/kubectl_attacher'
169
177
  autoload :KubectlConsole, 'actions/kubectl_console'
170
178
  autoload :KubectlDescribe, 'actions/kubectl_describe'
171
179
  autoload :KubectlLogs, 'actions/kubectl_logs'
180
+ autoload :KubectlEnv, 'actions/kubectl_env'
172
181
  end
173
182
 
174
183
  module Extensions
@@ -176,6 +185,7 @@ module KuberKit
176
185
  end
177
186
 
178
187
  module Kubernetes
188
+ autoload :ResourceSelector, 'kubernetes/resource_selector'
179
189
  autoload :ResourcesFetcher, 'kubernetes/resources_fetcher'
180
190
  end
181
191
 
@@ -2,7 +2,7 @@ class KuberKit::Actions::KubectlAttacher
2
2
  include KuberKit::Import[
3
3
  "shell.kubectl_commands",
4
4
  "shell.local_shell",
5
- "kubernetes.resources_fetcher",
5
+ "kubernetes.resource_selector",
6
6
  "ui"
7
7
  ]
8
8
 
@@ -12,7 +12,7 @@ class KuberKit::Actions::KubectlAttacher
12
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
13
13
 
14
14
  if !pod_name
15
- pod_name = resources_fetcher.call("attach")
15
+ pod_name = resource_selector.call("attach")
16
16
  end
17
17
 
18
18
  kubectl_commands.exec(
@@ -2,7 +2,7 @@ class KuberKit::Actions::KubectlConsole
2
2
  include KuberKit::Import[
3
3
  "shell.kubectl_commands",
4
4
  "shell.local_shell",
5
- "kubernetes.resources_fetcher",
5
+ "kubernetes.resource_selector",
6
6
  "ui"
7
7
  ]
8
8
 
@@ -12,7 +12,7 @@ class KuberKit::Actions::KubectlConsole
12
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
13
13
 
14
14
  if !pod_name
15
- pod_name = resources_fetcher.call("attach")
15
+ pod_name = resource_selector.call("attach")
16
16
  end
17
17
 
18
18
  kubectl_commands.exec(
@@ -2,7 +2,7 @@ class KuberKit::Actions::KubectlDescribe
2
2
  include KuberKit::Import[
3
3
  "shell.kubectl_commands",
4
4
  "shell.local_shell",
5
- "kubernetes.resources_fetcher",
5
+ "kubernetes.resource_selector",
6
6
  "ui"
7
7
  ]
8
8
 
@@ -12,7 +12,7 @@ class KuberKit::Actions::KubectlDescribe
12
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
13
13
 
14
14
  if !resource_name
15
- resource_name = resources_fetcher.call("describe", include_ingresses: true, include_pods: true)
15
+ resource_name = resource_selector.call("describe", include_ingresses: true, include_pods: true)
16
16
  end
17
17
 
18
18
  args = nil
@@ -0,0 +1,19 @@
1
+ class KuberKit::Actions::KubectlEnv
2
+ include KuberKit::Import[
3
+ "shell.local_shell",
4
+ "ui"
5
+ ]
6
+
7
+ Contract Hash => Any
8
+ def call(options)
9
+ configuration = KuberKit.current_configuration
10
+ kubeconfig_path = configuration.kubeconfig_path
11
+ ui.print_info("ENV", "export KUBECONFIG=#{kubeconfig_path}")
12
+
13
+ true
14
+ rescue KuberKit::Error => e
15
+ ui.print_error("Error", e.message)
16
+
17
+ false
18
+ end
19
+ end
@@ -2,7 +2,7 @@ class KuberKit::Actions::KubectlLogs
2
2
  include KuberKit::Import[
3
3
  "shell.kubectl_commands",
4
4
  "shell.local_shell",
5
- "kubernetes.resources_fetcher",
5
+ "kubernetes.resource_selector",
6
6
  "ui"
7
7
  ]
8
8
 
@@ -12,7 +12,7 @@ class KuberKit::Actions::KubectlLogs
12
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
13
13
 
14
14
  if !pod_name
15
- pod_name = resources_fetcher.call("attach")
15
+ pod_name = resource_selector.call("attach")
16
16
  end
17
17
 
18
18
  args = nil
@@ -0,0 +1,32 @@
1
+ class KuberKit::Actions::ServiceChecker
2
+ include KuberKit::Import[
3
+ "kubernetes.resources_fetcher",
4
+ "shell.local_shell",
5
+ "core.service_store",
6
+ "ui",
7
+ ]
8
+
9
+ Contract Hash => Any
10
+ def call(options)
11
+ services = service_store.all_definitions.values.map(&:service_name).map(&:to_s)
12
+
13
+ enabled_services = KuberKit.current_configuration.enabled_services.map(&:to_s)
14
+ if enabled_services.any?
15
+ services = services.select{ |s| enabled_services.include?(s) }
16
+ end
17
+
18
+ resources = resources_fetcher.call("deployments") + resources_fetcher.call("cronjobs")
19
+
20
+ missing_services = services.select{ |s| !resources.include?(s.gsub("_", "-")) }
21
+
22
+ ui.print_warning("Warning", "This command will only check services deployed using k8s")
23
+
24
+ ui.print_info("Missing", missing_services.inspect)
25
+
26
+ {}
27
+ rescue KuberKit::Error => e
28
+ ui.print_error("Error", e.message)
29
+
30
+ false
31
+ end
32
+ end
@@ -2,8 +2,11 @@ class KuberKit::Actions::ServiceDeployer
2
2
  include KuberKit::Import[
3
3
  "actions.image_compiler",
4
4
  "service_deployer.service_list_resolver",
5
+ "service_deployer.service_dependency_resolver",
5
6
  "core.service_store",
6
7
  "shell.local_shell",
8
+ "tools.process_cleaner",
9
+ "configs",
7
10
  "ui",
8
11
  service_deployer: "service_deployer.action_handler",
9
12
  ]
@@ -23,14 +26,17 @@ class KuberKit::Actions::ServiceDeployer
23
26
  services: services || [],
24
27
  tags: tags || [],
25
28
  enabled_services: KuberKit.current_configuration.enabled_services.map(&:to_s)
26
- )
29
+ ).map(&:to_sym)
27
30
 
28
- unless service_names.any?
31
+ # Return the list of services with all dependencies.
32
+ all_service_names = service_dependency_resolver.get_all(service_names)
33
+
34
+ unless all_service_names.any?
29
35
  ui.print_warning "ServiceDeployer", "No service found with given options, nothing will be deployed."
30
36
  return false
31
37
  end
32
38
 
33
- services_list = service_names.map(&:to_s).map(&:yellow).join(", ")
39
+ services_list = all_service_names.map(&:to_s).map(&:yellow).join(", ")
34
40
  ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
35
41
 
36
42
  if require_confirmation
@@ -38,7 +44,7 @@ class KuberKit::Actions::ServiceDeployer
38
44
  return false unless ["confirm".green, "confirm", "yes"].include?(result)
39
45
  end
40
46
 
41
- services = service_names.map do |service_name|
47
+ services = all_service_names.map do |service_name|
42
48
  service_store.get_service(service_name.to_sym)
43
49
  end
44
50
 
@@ -49,78 +55,91 @@ class KuberKit::Actions::ServiceDeployer
49
55
  return false unless compile_result
50
56
  end
51
57
 
52
- deployment_result = deploy_services(service_names)
58
+ deployed_services = []
59
+ deployment_result = {}
60
+ service_dependency_resolver.each_with_deps(service_names) do |dep_service_names|
61
+ ui.print_debug("ServiceDeployer", "Scheduling to compile: #{dep_service_names.inspect}. Limit: #{configs.deploy_simultaneous_limit}")
62
+ result = deploy_simultaneously(dep_service_names)
63
+ deployed_services += dep_service_names
64
+ deployment_result = deployment_result.merge(result)
65
+ end
53
66
 
54
- { services: service_names, deployment: deployment_result }
67
+ { services: all_service_names, deployment: deployment_result }
55
68
  rescue KuberKit::Error => e
56
69
  ui.print_error("Error", e.message)
57
70
 
58
71
  false
72
+ rescue Interrupt => e
73
+ process_cleaner.clean
59
74
  end
60
75
 
61
- def deploy_services(service_names)
62
- task_group = ui.create_task_group
76
+ private
77
+ def deploy_simultaneously(service_names)
78
+ task_group = ui.create_task_group
63
79
 
64
- deployer_result = {}
80
+ deployer_result = {}
65
81
 
66
- service_names.each do |service_name|
82
+ service_names.each do |service_name|
67
83
 
68
- ui.print_debug("ServiceDeployer", "Started deploying: #{service_name.to_s.green}")
69
- task_group.add("Deploying #{service_name.to_s.yellow}") do |task|
70
- deployer_result[service_name] = service_deployer.call(local_shell, service_name.to_sym)
84
+ ui.print_debug("ServiceDeployer", "Started deploying: #{service_name.to_s.green}")
85
+ task_group.add("Deploying #{service_name.to_s.yellow}") do |task|
86
+ deployer_result[service_name] = service_deployer.call(local_shell, service_name.to_sym)
71
87
 
72
- task.update_title("Deployed #{service_name.to_s.green}")
73
- ui.print_debug("ServiceDeployer", "Finished deploying: #{service_name.to_s.green}")
88
+ task.update_title("Deployed #{service_name.to_s.green}")
89
+ ui.print_debug("ServiceDeployer", "Finished deploying: #{service_name.to_s.green}")
90
+ end
74
91
  end
75
- end
76
92
 
77
- task_group.wait
93
+ task_group.wait
78
94
 
79
- deployer_result
80
- end
81
-
82
- def compile_images(images_names)
83
- return true if images_names.empty?
84
- image_compiler.call(images_names, {})
85
- end
95
+ deployer_result
96
+ end
86
97
 
87
- def show_tags_selection()
88
- specific_service_option = "deploy specific service"
89
-
90
- tags = [specific_service_option]
91
- tags += service_store
92
- .all_definitions
93
- .values
94
- .map(&:to_service_attrs)
95
- .map(&:tags)
96
- .flatten
97
- .uniq
98
- .sort
99
- .map(&:to_s)
100
-
101
- selected_tag = ui.prompt("Please select which tag to deploy", tags)
102
-
103
- if selected_tag == specific_service_option
104
- show_service_selection
105
- else
106
- [[], [selected_tag]]
98
+ def compile_images(images_names)
99
+ return true if images_names.empty?
100
+ image_compiler.call(images_names, {})
107
101
  end
108
- end
109
102
 
110
- def show_service_selection()
111
- services = service_store
112
- .all_definitions
113
- .values
114
- .map(&:service_name)
115
- .uniq
116
- .sort
117
- .map(&:to_s)
118
-
119
- if services.empty?
120
- return [[], []]
103
+ def show_tags_selection()
104
+ specific_service_option = "deploy specific service"
105
+ all_services_option = "deploy all services"
106
+
107
+ tags = [specific_service_option, all_services_option]
108
+ tags += service_store
109
+ .all_definitions
110
+ .values
111
+ .map(&:to_service_attrs)
112
+ .map(&:tags)
113
+ .flatten
114
+ .uniq
115
+ .sort
116
+ .map(&:to_s)
117
+
118
+ selected_tag = ui.prompt("Please select which tag to deploy", tags)
119
+
120
+ if selected_tag == specific_service_option
121
+ show_service_selection
122
+ elsif selected_tag == all_services_option
123
+ [["*"], []]
124
+ else
125
+ [[], [selected_tag]]
126
+ end
121
127
  end
122
128
 
123
- selected_service = ui.prompt("Please select which service to deploy", services)
124
- [[selected_service], []]
125
- end
129
+ def show_service_selection()
130
+ services = service_store
131
+ .all_definitions
132
+ .values
133
+ .map(&:service_name)
134
+ .uniq
135
+ .sort
136
+ .map(&:to_s)
137
+
138
+ if services.empty?
139
+ return [[], []]
140
+ end
141
+
142
+ selected_service = ui.prompt("Please select which service to deploy", services)
143
+ [[selected_service], []]
144
+ end
126
145
  end
data/lib/kuber_kit/cli.rb CHANGED
@@ -86,6 +86,15 @@ class KuberKit::CLI < Thor
86
86
  end
87
87
  end
88
88
 
89
+ desc "check", "Check to make sure that all services are deployed"
90
+ def check()
91
+ setup(options)
92
+
93
+ if KuberKit::Container['actions.configuration_loader'].call(options)
94
+ KuberKit::Container['actions.service_checker'].call(options)
95
+ end
96
+ end
97
+
89
98
  desc "apply FILE_PATH", "Apply FILE_PATH with kubectl"
90
99
  def apply(file_path)
91
100
  setup(options)
@@ -132,6 +141,15 @@ class KuberKit::CLI < Thor
132
141
  end
133
142
  end
134
143
 
144
+ desc "env", "Show environment variables for given configuration"
145
+ def env()
146
+ setup(options)
147
+
148
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
149
+ KuberKit::Container['actions.kubectl_env'].call(options)
150
+ end
151
+ end
152
+
135
153
  desc "version", "Print current version"
136
154
  def version
137
155
  puts KuberKit::VERSION
@@ -160,4 +178,21 @@ class KuberKit::CLI < Thor
160
178
  def print_result(message, data = {})
161
179
  KuberKit::Container['ui'].print_result(message, data)
162
180
  end
181
+
182
+ def cleanup_processes
183
+ # Stop all threads
184
+ Thread.list.each do |t|
185
+ t.abort_on_exception = false
186
+ t.report_on_exception = false
187
+ Thread.kill(t) if t != Thread.current
188
+ end
189
+
190
+ # Find all system calls
191
+ child_pids_raw = `ps auxww | grep '[K]IT=#{Process.pid}' | awk '{print $2}'`
192
+ child_pids = child_pids_raw.to_s.split("\n").reject(&:empty?)
193
+ child_pids.each do |pid|
194
+ puts "Killing child process: #{pid}"
195
+ Process.kill("SIGHUP", pid.to_i)
196
+ end
197
+ end
163
198
  end
@@ -4,7 +4,7 @@ class KuberKit::Configs
4
4
  AVAILABLE_CONFIGS = [
5
5
  :image_dockerfile_name, :image_build_context_dir, :image_tag, :docker_ignore_list, :image_compile_dir,
6
6
  :kuber_kit_dirname, :kuber_kit_min_version, :images_dirname, :services_dirname, :infra_dirname, :configurations_dirname,
7
- :artifact_clone_dir, :service_config_dir, :deployer_strategy, :compile_simultaneous_limit,
7
+ :artifact_clone_dir, :service_config_dir, :deployer_strategy, :compile_simultaneous_limit, :deploy_simultaneous_limit,
8
8
  :additional_images_paths, :deprecation_warnings_disabled, :log_file_path
9
9
  ]
10
10
  DOCKER_IGNORE_LIST = [
@@ -49,6 +49,7 @@ class KuberKit::Configs
49
49
  set :service_config_dir, "/tmp/kuber_kit/services"
50
50
  set :deployer_strategy, :kubernetes
51
51
  set :compile_simultaneous_limit, 5
52
+ set :deploy_simultaneous_limit, 5
52
53
  set :additional_images_paths, []
53
54
  set :deprecation_warnings_disabled, false
54
55
  set :log_file_path, "/tmp/kuber_kit.log"
@@ -21,6 +21,10 @@ class KuberKit::Container
21
21
  KuberKit::Actions::ServiceDeployer.new
22
22
  end
23
23
 
24
+ register "actions.service_checker" do
25
+ KuberKit::Actions::ServiceChecker.new
26
+ end
27
+
24
28
  register "actions.configuration_loader" do
25
29
  KuberKit::Actions::ConfigurationLoader.new
26
30
  end
@@ -45,6 +49,10 @@ class KuberKit::Container
45
49
  KuberKit::Actions::KubectlLogs.new
46
50
  end
47
51
 
52
+ register "actions.kubectl_env" do
53
+ KuberKit::Actions::KubectlEnv.new
54
+ end
55
+
48
56
  register "configs" do
49
57
  KuberKit::Configs.new
50
58
  end
@@ -121,6 +129,10 @@ class KuberKit::Container
121
129
  KuberKit::Container["tools.logger_factory"].create()
122
130
  end
123
131
 
132
+ register "tools.process_cleaner" do
133
+ KuberKit::Tools::ProcessCleaner.new
134
+ end
135
+
124
136
  register "shell.bash_commands" do
125
137
  KuberKit::Shell::Commands::BashCommands.new
126
138
  end
@@ -145,6 +157,10 @@ class KuberKit::Container
145
157
  KuberKit::Shell::Commands::KubectlCommands.new
146
158
  end
147
159
 
160
+ register "shell.system_commands" do
161
+ KuberKit::Shell::Commands::SystemCommands.new
162
+ end
163
+
148
164
  register "shell.local_shell" do
149
165
  KuberKit::Shell::LocalShell.new
150
166
  end
@@ -241,6 +257,10 @@ class KuberKit::Container
241
257
  KuberKit::ServiceDeployer::ServiceListResolver.new
242
258
  end
243
259
 
260
+ register "service_deployer.service_dependency_resolver" do
261
+ KuberKit::ServiceDeployer::ServiceDependencyResolver.new
262
+ end
263
+
244
264
  register "service_deployer.strategies.kubernetes" do
245
265
  KuberKit::ServiceDeployer::Strategies::Kubernetes.new
246
266
  end
@@ -261,6 +281,10 @@ class KuberKit::Container
261
281
  KuberKit::ServiceReader::Reader.new
262
282
  end
263
283
 
284
+ register "kubernetes.resource_selector" do
285
+ KuberKit::Kubernetes::ResourceSelector.new
286
+ end
287
+
264
288
  register "kubernetes.resources_fetcher" do
265
289
  KuberKit::Kubernetes::ResourcesFetcher.new
266
290
  end
@@ -0,0 +1,75 @@
1
+ class KuberKit::Core::Dependencies::AbstractDependencyResolver
2
+ CircularDependencyError = Class.new(KuberKit::Error)
3
+ DependencyNotFoundError = Class.new(KuberKit::NotFoundError)
4
+
5
+ # Iterate over list of dependencies for items (including the items themself).
6
+ # Iteration will send the list to the callback block function
7
+ Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
8
+ def each_with_deps(item_names, &block)
9
+ resolved_dependencies = []
10
+ # Get first list of dependencies ready to resolve
11
+ next_dependencies = get_next(item_names, limit: dependency_batch_size)
12
+
13
+ # Call the block for each list of dependencies ready to resolve, then calculate the next list
14
+ while (next_dependencies - resolved_dependencies).any?
15
+ block.call(next_dependencies)
16
+ resolved_dependencies += next_dependencies
17
+ next_dependencies = get_next(item_names, resolved: resolved_dependencies, limit: dependency_batch_size)
18
+ end
19
+
20
+ (item_names - resolved_dependencies).each_slice(dependency_batch_size) do |group|
21
+ block.call(group)
22
+ end
23
+ end
24
+
25
+ # Returns next list of dependencies ready to resolve.
26
+ # Item is not ready to resolve if it has personal dependency.
27
+ # E.g. if "A" depends on "B" and "C", "C" depends on "D", then only "B" and "D" will be returned.
28
+ Contract Or[Symbol, ArrayOf[Symbol]], KeywordArgs[
29
+ resolved: Optional[ArrayOf[Symbol]],
30
+ limit: Optional[Maybe[Num]]
31
+ ] => Any
32
+ def get_next(item_names, resolved: [], limit: nil)
33
+ deps = Array(item_names).map { |i| get_recursive_deps(i) }.flatten.uniq
34
+
35
+ # Find out which dependencies are ready to resolve,
36
+ # they should not have unresolved personal dependencies
37
+ ready_to_resolve = deps.select do |dep_name|
38
+ unresolved_deps = get_deps(dep_name) - resolved
39
+ unresolved_deps.empty?
40
+ end
41
+ unresolved_deps = ready_to_resolve - resolved
42
+ unresolved_deps = unresolved_deps.take(limit) if limit
43
+ unresolved_deps
44
+ end
45
+
46
+ # Get all dependencies for items (including the items themself), without any limitations
47
+ Contract Or[Symbol, ArrayOf[Symbol]] => Any
48
+ def get_all(item_names)
49
+ deps = Array(item_names).map { |i| get_recursive_deps(i) }.flatten
50
+ (deps + item_names).uniq
51
+ end
52
+
53
+ def get_recursive_deps(item_name, dependency_tree: [])
54
+ deps = get_deps(item_name)
55
+
56
+ if dependency_tree.include?(item_name)
57
+ raise CircularDependencyError, "Circular dependency found for #{item_name}. Dependency tree: #{dependency_tree.inspect}"
58
+ end
59
+
60
+ child_deps = []
61
+ deps.each do |i|
62
+ child_deps += get_recursive_deps(i, dependency_tree: dependency_tree + [item_name])
63
+ end
64
+
65
+ (deps + child_deps).uniq
66
+ end
67
+
68
+ def get_deps(item_name)
69
+ raise "This method should be overriden"
70
+ end
71
+
72
+ def dependency_batch_size
73
+ raise "This method should be overriden"
74
+ end
75
+ end
@@ -1,5 +1,6 @@
1
1
  class KuberKit::Core::Image
2
- attr_reader :name, :dependencies, :registry, :dockerfile_path, :build_vars, :build_context_dir, :tag, :before_build_callback, :after_build_callback
2
+ attr_reader :name, :dependencies, :registry, :dockerfile_path, :build_vars, :build_context_dir, :tag,
3
+ :before_build_callback, :after_build_callback
3
4
 
4
5
  Contract KeywordArgs[
5
6
  name: Symbol,
@@ -1,18 +1,20 @@
1
1
  class KuberKit::Core::Service
2
2
  AttributeNotSet = Class.new(Indocker::Error)
3
3
 
4
- attr_reader :name, :template_name, :tags, :images, :attributes, :deployer_strategy
4
+ attr_reader :name, :dependencies, :template_name, :tags, :images, :attributes, :deployer_strategy
5
5
 
6
6
  Contract KeywordArgs[
7
7
  name: Symbol,
8
+ dependencies: ArrayOf[Symbol],
8
9
  template_name: Maybe[Symbol],
9
10
  tags: ArrayOf[Symbol],
10
11
  images: ArrayOf[Symbol],
11
12
  attributes: HashOf[Symbol => Any],
12
13
  deployer_strategy: Maybe[Symbol]
13
14
  ] => Any
14
- def initialize(name:, template_name:, tags:, images:, attributes:, deployer_strategy:)
15
+ def initialize(name:, dependencies:, template_name:, tags:, images:, attributes:, deployer_strategy:)
15
16
  @name = name
17
+ @dependencies = dependencies
16
18
  @template_name = template_name
17
19
  @tags = tags
18
20
  @images = images
@@ -1,22 +1,29 @@
1
1
  class KuberKit::Core::ServiceDefinition
2
- attr_reader :service_name, :template_name
2
+ attr_reader :service_name, :template_name, :dependencies
3
3
 
4
4
  Contract Or[Symbol, String] => Any
5
5
  def initialize(service_name)
6
6
  @service_name = service_name.to_sym
7
+ @dependencies = []
7
8
  end
8
9
 
9
10
  def to_service_attrs
10
11
  OpenStruct.new(
11
- name: @service_name,
12
- template_name: get_value(@template_name),
13
- tags: Array(get_value(@tags)).map(&:to_sym),
14
- images: Array(get_value(@images)).map(&:to_sym),
15
- attributes: get_value(@attributes),
12
+ name: @service_name,
13
+ dependencies: @dependencies,
14
+ template_name: get_value(@template_name),
15
+ tags: Array(get_value(@tags)).map(&:to_sym),
16
+ images: Array(get_value(@images)).map(&:to_sym),
17
+ attributes: get_value(@attributes),
16
18
  deployer_strategy: get_value(@deployer_strategy),
17
19
  )
18
20
  end
19
21
 
22
+ def depends_on(*value, &block)
23
+ @dependencies = Array(value).flatten
24
+ self
25
+ end
26
+
20
27
  def template(value = nil, &block)
21
28
  @template_name = block_given? ? block : value
22
29
 
@@ -7,6 +7,7 @@ class KuberKit::Core::ServiceFactory
7
7
 
8
8
  KuberKit::Core::Service.new(
9
9
  name: service_attrs.name,
10
+ dependencies: service_attrs.dependencies,
10
11
  template_name: service_attrs.template_name,
11
12
  tags: service_attrs.tags,
12
13
  images: service_attrs.images,
@@ -1,62 +1,14 @@
1
- class KuberKit::ImageCompiler::ImageDependencyResolver
2
- CircularDependencyError = Class.new(KuberKit::Error)
3
- DependencyNotFoundError = Class.new(KuberKit::NotFoundError)
4
-
1
+ class KuberKit::ImageCompiler::ImageDependencyResolver < KuberKit::Core::Dependencies::AbstractDependencyResolver
5
2
  include KuberKit::Import[
6
3
  "core.image_store",
7
4
  "configs"
8
5
  ]
9
-
10
- Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
11
- def each_with_deps(image_names, &block)
12
- compile_limit = configs.compile_simultaneous_limit
13
-
14
- resolved_dependencies = []
15
- next_dependencies = get_next(image_names, limit: compile_limit)
16
-
17
- while (next_dependencies - resolved_dependencies).any?
18
- block.call(next_dependencies)
19
- resolved_dependencies += next_dependencies
20
- next_dependencies = get_next(image_names, resolved: resolved_dependencies, limit: compile_limit)
21
- end
22
-
23
- (image_names - resolved_dependencies).each_slice(compile_limit) do |group|
24
- block.call(group)
25
- end
26
- end
27
6
 
28
- Contract Or[Symbol, ArrayOf[Symbol]], KeywordArgs[
29
- resolved: Optional[ArrayOf[Symbol]],
30
- limit: Optional[Maybe[Num]]
31
- ] => Any
32
- def get_next(image_names, resolved: [], limit: nil)
33
- deps = Array(image_names).map { |i| get_recursive_deps(i) }.flatten.uniq
34
-
35
- ready_to_resolve = deps.select do |dep_name|
36
- unresolved_deps = get_deps(dep_name) - resolved
37
- unresolved_deps.empty?
38
- end
39
- unresolved_deps = ready_to_resolve - resolved
40
- unresolved_deps = unresolved_deps.take(limit) if limit
41
- unresolved_deps
42
- end
43
-
44
- def get_recursive_deps(image_name, dependency_tree: [])
45
- deps = get_deps(image_name)
46
-
47
- if dependency_tree.include?(image_name)
48
- raise CircularDependencyError, "Circular dependency found for #{image_name}. Dependency tree: #{dependency_tree.inspect}"
49
- end
50
-
51
- child_deps = []
52
- deps.each do |i|
53
- child_deps += get_recursive_deps(i, dependency_tree: dependency_tree + [image_name])
54
- end
55
-
56
- (deps + child_deps).uniq
57
- end
58
-
59
7
  def get_deps(image_name)
60
8
  image_store.get_definition(image_name).dependencies
61
9
  end
10
+
11
+ def dependency_batch_size
12
+ configs.compile_simultaneous_limit
13
+ end
62
14
  end
@@ -0,0 +1,33 @@
1
+ class KuberKit::Kubernetes::ResourceSelector
2
+ include KuberKit::Import[
3
+ "kubernetes.resources_fetcher",
4
+ "shell.local_shell",
5
+ "ui"
6
+ ]
7
+
8
+ Contract String, KeywordArgs[
9
+ include_ingresses: Optional[Bool],
10
+ include_pods: Optional[Bool]
11
+ ] => Any
12
+ def call(action_name, include_ingresses: false, include_pods: false)
13
+ deployments = resources_fetcher.call("deployments")
14
+ options = deployments.map{|d| "deploy/#{d}" }
15
+ options << "ingresses" if include_ingresses
16
+ options << "pods" if include_pods
17
+ option = ui.prompt("Please select resource to #{action_name}", options)
18
+
19
+ if option == "ingresses" && include_ingresses
20
+ ingresses = resources_fetcher.call("ingresses")
21
+ options = ingresses.map{|d| "ingresses/#{d}" }
22
+ return ui.prompt("Please select ingress to #{action_name}", options)
23
+ end
24
+
25
+ if option == "pods" && include_pods
26
+ ingresses = resources_fetcher.call("pods")
27
+ options = ingresses.map{|d| "pods/#{d}" }
28
+ return ui.prompt("Please select pod to #{action_name}", options)
29
+ end
30
+
31
+ option
32
+ end
33
+ end
@@ -2,40 +2,17 @@ class KuberKit::Kubernetes::ResourcesFetcher
2
2
  include KuberKit::Import[
3
3
  "shell.kubectl_commands",
4
4
  "shell.local_shell",
5
- "ui"
6
5
  ]
7
6
 
8
- Contract String, KeywordArgs[
9
- include_ingresses: Optional[Bool],
10
- include_pods: Optional[Bool]
11
- ] => Any
12
- def call(action_name, include_ingresses: false, include_pods: false)
13
- deployments = get_resources("deployments")
14
- options = deployments.split(" ").map{|d| "deploy/#{d}" }
15
- options << "ingresses" if include_ingresses
16
- options << "pods" if include_pods
17
- option = ui.prompt("Please select resource to #{action_name}", options)
18
-
19
- if option == "ingresses" && include_ingresses
20
- ingresses = get_resources("ingresses")
21
- options = ingresses.split(" ").map{|d| "ingresses/#{d}" }
22
- return ui.prompt("Please select ingress to #{action_name}", options)
23
- end
24
-
25
- if option == "pods" && include_pods
26
- ingresses = get_resources("pods")
27
- options = ingresses.split(" ").map{|d| "pods/#{d}" }
28
- return ui.prompt("Please select pod to #{action_name}", options)
29
- end
7
+ Contract String => ArrayOf[String]
8
+ def call(resource_type)
9
+ current_configuration = KuberKit.current_configuration
30
10
 
31
- option
32
- end
33
-
34
- def get_resources(type)
35
11
  kubectl_commands.get_resources(
36
- local_shell, type,
37
- jsonpath: ".items[*].metadata.name",
38
- namespace: KuberKit.current_configuration.deployer_namespace
12
+ local_shell, resource_type,
13
+ jsonpath: ".items[*].metadata.name",
14
+ kubeconfig_path: current_configuration.kubeconfig_path,
15
+ namespace: current_configuration.deployer_namespace
39
16
  )
40
17
  end
41
18
  end
@@ -0,0 +1,14 @@
1
+ class KuberKit::ServiceDeployer::ServiceDependencyResolver < KuberKit::Core::Dependencies::AbstractDependencyResolver
2
+ include KuberKit::Import[
3
+ "core.service_store",
4
+ "configs"
5
+ ]
6
+
7
+ def get_deps(service_name)
8
+ service_store.get_definition(service_name).dependencies
9
+ end
10
+
11
+ def dependency_batch_size
12
+ configs.deploy_simultaneous_limit
13
+ end
14
+ end
@@ -6,7 +6,9 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
6
6
  ]
7
7
 
8
8
  STRATEGY_OPTIONS = [
9
+ :namespace,
9
10
  :container_name,
11
+ :env_file,
10
12
  :image_name,
11
13
  :detached,
12
14
  :command_name,
@@ -14,6 +16,8 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
14
16
  :delete_if_exists,
15
17
  :volumes,
16
18
  :networks,
19
+ :expose,
20
+ :publish,
17
21
  ]
18
22
 
19
23
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
@@ -24,11 +28,15 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
24
28
  raise KuberKit::Error, "Unknow options for deploy strategy: #{unknown_options}. Available options: #{STRATEGY_OPTIONS}"
25
29
  end
26
30
 
27
- container_name = strategy_options.fetch(:container_name, service.uri)
31
+ namespace = strategy_options.fetch(:namespace, nil)
32
+ container_name = strategy_options.fetch(:container_name, [namespace, service.name].compact.join("_"))
28
33
  command_name = strategy_options.fetch(:command_name, nil)
34
+ env_file = strategy_options.fetch(:env_file, nil)
29
35
  custom_args = strategy_options.fetch(:custom_args, nil)
30
36
  networks = strategy_options.fetch(:networks, [])
31
37
  volumes = strategy_options.fetch(:volumes, [])
38
+ expose_ports = strategy_options.fetch(:expose, [])
39
+ publish_ports = strategy_options.fetch(:publish, [])
32
40
  hostname = strategy_options.fetch(:hostname, container_name)
33
41
 
34
42
  image_name = strategy_options.fetch(:image_name, nil)
@@ -46,6 +54,9 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
46
54
  if container_name
47
55
  custom_args << "--name #{container_name}"
48
56
  end
57
+ if env_file
58
+ custom_args << "--env-file #{env_file}"
59
+ end
49
60
  if hostname
50
61
  custom_args << "--hostname #{hostname}"
51
62
  end
@@ -58,6 +69,12 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
58
69
  docker_commands.create_volume(shell, volume_name) unless volume_name.start_with?("/")
59
70
  custom_args << "--volume #{volume}"
60
71
  end
72
+ Array(expose_ports).each do |expose_port|
73
+ custom_args << "--expose #{expose_port}"
74
+ end
75
+ Array(publish_ports).each do |publish_port|
76
+ custom_args << "--publish #{publish_port}"
77
+ end
61
78
 
62
79
  docker_commands.run(
63
80
  shell, image.remote_registry_url,
@@ -9,7 +9,8 @@ class KuberKit::ServiceDeployer::Strategies::Kubernetes < KuberKit::ServiceDeplo
9
9
  :resource_type,
10
10
  :resource_name,
11
11
  :delete_if_exists,
12
- :restart_if_exists
12
+ :restart_if_exists,
13
+ :wait_for_rollout
13
14
  ]
14
15
 
15
16
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
@@ -41,12 +42,18 @@ class KuberKit::ServiceDeployer::Strategies::Kubernetes < KuberKit::ServiceDeplo
41
42
 
42
43
  apply_result = kubectl_commands.apply_file(shell, config_path, kubeconfig_path: kubeconfig_path, namespace: namespace)
43
44
 
44
- restart_enabled = strategy_options.fetch(:restart_if_exists, true)
45
+ restart_enabled = strategy_options.fetch(:restart_if_exists, true)
46
+ wait_for_rollout = strategy_options.fetch(:wait_for_rollout, true)
45
47
  if restart_enabled && resource_exists
46
48
  kubectl_commands.rolling_restart(
47
49
  shell, resource_type, resource_name,
48
50
  kubeconfig_path: kubeconfig_path, namespace: namespace
49
51
  )
52
+
53
+ kubectl_commands.rollout_status(
54
+ shell, resource_type, resource_name, wait: true,
55
+ kubeconfig_path: kubeconfig_path, namespace: namespace
56
+ ) if wait_for_rollout
50
57
  end
51
58
 
52
59
  apply_result
@@ -60,19 +60,19 @@ class KuberKit::Shell::Commands::KubectlCommands
60
60
  command_parts << "-o jsonpath='{#{jsonpath}}'"
61
61
  end
62
62
 
63
- result = kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, namespace: namespace)
63
+ result = kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, namespace: namespace).to_s
64
64
 
65
65
  # Hide warnings manually, until appropriate kubectl option will be available
66
- result = result.split("\n").reject{|n| n.start_with?("Warning:") }.join("\n") if result.is_a?(String)
66
+ result = result.split("\n").reject{|n| n.start_with?("Warning:") }.join("\n")
67
67
 
68
- result
68
+ Array(result.split(" ")).reject(&:empty?)
69
69
  end
70
70
 
71
71
  def resource_exists?(shell, resource_type, resource_name, kubeconfig_path: nil, namespace: nil)
72
72
  result = get_resources(shell, resource_type,
73
73
  field_selector: "metadata.name=#{resource_name}", kubeconfig_path: kubeconfig_path, namespace: namespace
74
74
  )
75
- result && result != ""
75
+ result.any?
76
76
  end
77
77
 
78
78
  def delete_resource(shell, resource_type, resource_name, kubeconfig_path: nil, namespace: nil)
@@ -102,4 +102,12 @@ class KuberKit::Shell::Commands::KubectlCommands
102
102
  }
103
103
  }, kubeconfig_path: kubeconfig_path, namespace: namespace)
104
104
  end
105
+
106
+ def rollout_status(shell, resource_type, resource_name, wait: true, kubeconfig_path: nil, namespace: nil)
107
+ command_parts = []
108
+ command_parts << %Q{rollout status #{resource_type} #{resource_name}}
109
+ command_parts << "-w" if wait
110
+
111
+ kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, namespace: namespace)
112
+ end
105
113
  end
@@ -0,0 +1,32 @@
1
+ class KuberKit::Shell::Commands::SystemCommands
2
+ def kill_process(shell, pid)
3
+ # we need to use kill command directly sometimes,
4
+ # because Process.kill doesn't kill processes created by system() call
5
+ shell.exec!("kill -9 #{pid}")
6
+ true
7
+ rescue
8
+ false
9
+ end
10
+
11
+ def find_pids_by_name(shell, name)
12
+ shell
13
+ .exec!("ps auxww | grep '#{name}' | grep -v 'grep' | awk '{print $2}'")
14
+ .split("\n")
15
+ .reject(&:empty?)
16
+ .map(&:chomp)
17
+ .map(&:to_i)
18
+ rescue
19
+ []
20
+ end
21
+
22
+ def get_child_pids(shell, pid)
23
+ shell
24
+ .exec!("pgrep -P #{pid}")
25
+ .split("\n")
26
+ .reject(&:empty?)
27
+ .map(&:chomp)
28
+ .map(&:to_i)
29
+ rescue
30
+ []
31
+ end
32
+ end
@@ -15,7 +15,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
15
15
  end
16
16
 
17
17
  result = nil
18
- IO.popen(command, err: [:child, :out]) do |io|
18
+ IO.popen(wrap_command_with_pid(command), err: [:child, :out]) do |io|
19
19
  result = io.read.chomp.strip
20
20
  end
21
21
 
@@ -37,7 +37,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
37
37
  ui.print_debug("LocalShell", "Interactive: [#{command_number}]: #{command.to_s.cyan}")
38
38
  end
39
39
 
40
- result = system(command)
40
+ result = system(wrap_command_with_pid(command))
41
41
 
42
42
  if !$?.success?
43
43
  raise ShellError, "Shell command failed: #{command}\r\n#{result}"
@@ -86,6 +86,10 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
86
86
  end
87
87
  end
88
88
 
89
+ def wrap_command_with_pid(command)
90
+ "KIT=#{Process.pid} #{command}"
91
+ end
92
+
89
93
  private
90
94
  def ensure_directory_exists(file_path)
91
95
  dir_path = File.dirname(file_path)
@@ -27,7 +27,7 @@ class KuberKit::Shell::SshShell < KuberKit::Shell::LocalShell
27
27
  ui.print_debug("SshShell", "#{ssh_session.host.green} > Execute: [#{command_number}]: #{command.to_s.cyan}")
28
28
  end
29
29
 
30
- result = ssh_session.exec!(command)
30
+ result = ssh_session.exec!(wrap_command_with_pid(command))
31
31
 
32
32
  if result && result != "" && log_command
33
33
  ui.print_debug("SshShell", "#{ssh_session.host.green} > Finished [#{command_number}] with result: \n#{result.grey}")
@@ -0,0 +1,38 @@
1
+ class KuberKit::Tools::ProcessCleaner
2
+ include KuberKit::Import[
3
+ "shell.system_commands",
4
+ "shell.local_shell"
5
+ ]
6
+
7
+ def clean
8
+ stop_threads
9
+ stop_child_proceses
10
+ end
11
+
12
+ def stop_threads
13
+ Thread.list.each do |t|
14
+ t.abort_on_exception = false
15
+ t.report_on_exception = false
16
+ Thread.kill(t) if t != Thread.current
17
+ end
18
+ end
19
+
20
+ def stop_child_proceses
21
+ find_all_child_processes.each do |pid|
22
+ system_commands.kill_process(local_shell, pid)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def find_all_child_processes
29
+ pids = system_commands.find_pids_by_name(local_shell, "KIT=#{Process.pid}")
30
+ pids + get_child_pids(pids)
31
+ end
32
+
33
+ def get_child_pids(pids)
34
+ pids
35
+ .map{ |p| system_commands.get_child_pids(local_shell, p) }
36
+ .flatten
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module KuberKit
2
- VERSION = "0.4.7"
2
+ VERSION = "0.5.2"
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.4.7
4
+ version: 0.5.2
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-02-10 00:00:00.000000000 Z
11
+ date: 2021-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: contracts-lite
@@ -165,6 +165,7 @@ files:
165
165
  - ".ruby-gemset"
166
166
  - ".ruby-version"
167
167
  - ".travis.yml"
168
+ - CHANGELOG.md
168
169
  - Gemfile
169
170
  - Gemfile.lock
170
171
  - LICENSE.txt
@@ -209,7 +210,9 @@ files:
209
210
  - lib/kuber_kit/actions/kubectl_attacher.rb
210
211
  - lib/kuber_kit/actions/kubectl_console.rb
211
212
  - lib/kuber_kit/actions/kubectl_describe.rb
213
+ - lib/kuber_kit/actions/kubectl_env.rb
212
214
  - lib/kuber_kit/actions/kubectl_logs.rb
215
+ - lib/kuber_kit/actions/service_checker.rb
213
216
  - lib/kuber_kit/actions/service_deployer.rb
214
217
  - lib/kuber_kit/actions/service_reader.rb
215
218
  - lib/kuber_kit/actions/template_reader.rb
@@ -237,6 +240,7 @@ files:
237
240
  - lib/kuber_kit/core/context_helper/context_vars.rb
238
241
  - lib/kuber_kit/core/context_helper/image_helper.rb
239
242
  - lib/kuber_kit/core/context_helper/service_helper.rb
243
+ - lib/kuber_kit/core/dependencies/abstract_dependency_resolver.rb
240
244
  - lib/kuber_kit/core/env_files/abstract_env_file.rb
241
245
  - lib/kuber_kit/core/env_files/artifact_file.rb
242
246
  - lib/kuber_kit/core/env_files/env_file_store.rb
@@ -273,11 +277,13 @@ files:
273
277
  - lib/kuber_kit/image_compiler/image_builder.rb
274
278
  - lib/kuber_kit/image_compiler/image_dependency_resolver.rb
275
279
  - lib/kuber_kit/image_compiler/version_tag_builder.rb
280
+ - lib/kuber_kit/kubernetes/resource_selector.rb
276
281
  - lib/kuber_kit/kubernetes/resources_fetcher.rb
277
282
  - lib/kuber_kit/preprocessing/file_preprocessor.rb
278
283
  - lib/kuber_kit/preprocessing/text_preprocessor.rb
279
284
  - lib/kuber_kit/service_deployer/action_handler.rb
280
285
  - lib/kuber_kit/service_deployer/deployer.rb
286
+ - lib/kuber_kit/service_deployer/service_dependency_resolver.rb
281
287
  - lib/kuber_kit/service_deployer/service_list_resolver.rb
282
288
  - lib/kuber_kit/service_deployer/strategies/abstract.rb
283
289
  - lib/kuber_kit/service_deployer/strategies/docker.rb
@@ -294,6 +300,7 @@ files:
294
300
  - lib/kuber_kit/shell/commands/git_commands.rb
295
301
  - lib/kuber_kit/shell/commands/kubectl_commands.rb
296
302
  - lib/kuber_kit/shell/commands/rsync_commands.rb
303
+ - lib/kuber_kit/shell/commands/system_commands.rb
297
304
  - lib/kuber_kit/shell/local_shell.rb
298
305
  - lib/kuber_kit/shell/ssh_session.rb
299
306
  - lib/kuber_kit/shell/ssh_shell.rb
@@ -303,6 +310,7 @@ files:
303
310
  - lib/kuber_kit/template_reader/strategies/artifact_file.rb
304
311
  - lib/kuber_kit/tools/file_presence_checker.rb
305
312
  - lib/kuber_kit/tools/logger_factory.rb
313
+ - lib/kuber_kit/tools/process_cleaner.rb
306
314
  - lib/kuber_kit/ui.rb
307
315
  - lib/kuber_kit/ui/api.rb
308
316
  - lib/kuber_kit/ui/debug.rb