kuber_kit 0.4.3 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f88af58c1a98432ce14e5527ea39dda750b641c80deeddb76b281dc861b1814f
4
- data.tar.gz: 4b60492fae06a45b460d022ae540eb4e442e4aec65194791ba2e7306502612a9
3
+ metadata.gz: d221b8cd2f09dc4a239e125c2d53ebed3b6ba85c07cbf47f13b13f064b4acc35
4
+ data.tar.gz: fe87b38b80cf8e76bcd8f24a8c12e5e1564cf39ca184065d7f10463419ae3472
5
5
  SHA512:
6
- metadata.gz: 205b900fc00004c918108da19680c83f433b79d87b727421abdfec8680b7a0aef5ec0ad474605e7aa34e6370c047a8bbe20c1b81c4639684c8c6919a040e2ed4
7
- data.tar.gz: a18edd776b63ffca524819a06adad9031c47272e12f69e66006fc0220e43510cc01f7697d225516c0861dde37523b0293cbe51b004f1336c3ffdbcc0673fca86
6
+ metadata.gz: 9820d98b32ddb5876ad536c3a785360db92e6301b9d359f7fd6cc795cfdc996408eb52685d891b3ef7a058f7e6022247afa057ac0ed65f1db33adff7eb5d6274
7
+ data.tar.gz: 51376794f59eb73726187455144309c957b04850fd9c1c92b98de82109536105db94f4babd0734ff422907ae65a4722fad0fd2f271ee030819ff40173953d8fe
data/Gemfile.lock CHANGED
@@ -1,19 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kuber_kit (0.4.3)
4
+ kuber_kit (0.4.8)
5
5
  cli-ui
6
6
  contracts-lite
7
7
  dry-auto_inject
8
8
  net-ssh
9
9
  thor
10
+ tty-prompt
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
14
15
  cli-ui (1.4.0)
15
16
  coderay (1.1.3)
16
- concurrent-ruby (1.1.7)
17
+ concurrent-ruby (1.1.8)
17
18
  contracts-lite (0.15.0)
18
19
  diff-lcs (1.4.4)
19
20
  docile (1.3.2)
@@ -29,6 +30,8 @@ GEM
29
30
  concurrent-ruby (~> 1.0)
30
31
  method_source (1.0.0)
31
32
  net-ssh (6.1.0)
33
+ pastel (0.8.0)
34
+ tty-color (~> 0.5)
32
35
  pry (0.13.1)
33
36
  coderay (~> 1.1)
34
37
  method_source (~> 1.0)
@@ -52,7 +55,18 @@ GEM
52
55
  simplecov_json_formatter (~> 0.1)
53
56
  simplecov-html (0.12.3)
54
57
  simplecov_json_formatter (0.1.2)
55
- thor (1.0.1)
58
+ thor (1.1.0)
59
+ tty-color (0.6.0)
60
+ tty-cursor (0.7.1)
61
+ tty-prompt (0.23.0)
62
+ pastel (~> 0.8)
63
+ tty-reader (~> 0.8)
64
+ tty-reader (0.9.0)
65
+ tty-cursor (~> 0.7)
66
+ tty-screen (~> 0.8)
67
+ wisper (~> 2.0)
68
+ tty-screen (0.8.1)
69
+ wisper (2.0.1)
56
70
 
57
71
  PLATFORMS
58
72
  ruby
data/TODO.md CHANGED
@@ -1,8 +1,8 @@
1
- - https://ttytoolkit.org/
2
- - do not show result for images list, if list is too large
1
+ - do not show result for images list, if list is too large (Mikhail)
2
+ - add kit get method for interactive kubernetes
3
3
  - kit status should show the list of services and their status, with ability to select & view logs
4
- - allow deploying only services enabled for specific configuration
5
4
  - find a way to always deploy some service, e.g. for migrations and env_files
6
5
  - template should be able to set default attributes
7
6
  - template should be able to depend on image?
8
- - cleanup image builds older than some date
7
+ - cleanup image builds older than some date
8
+ - add some rotation for deploy log
@@ -2,5 +2,5 @@ KuberKit
2
2
  .define_configuration(:review)
3
3
  .use_registry(:review_default, as: :default)
4
4
  .use_artifact(:kuber_kit_repo, as: :kuber_kit_repo)
5
- .deployer_require_confirimation
5
+ #.deployer_require_confirimation
6
6
  #.use_build_server(:remote_bs)
@@ -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
data/kuber_kit.gemspec CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "thor"
29
29
  spec.add_dependency "cli-ui"
30
30
  spec.add_dependency "net-ssh"
31
+ spec.add_dependency "tty-prompt"
31
32
 
32
33
  spec.add_development_dependency "bundler", "~> 1.17"
33
34
  spec.add_development_dependency "rake", "~> 10.0"
data/lib/kuber_kit.rb CHANGED
@@ -76,6 +76,7 @@ module KuberKit
76
76
  module Tools
77
77
  autoload :FilePresenceChecker, 'tools/file_presence_checker'
78
78
  autoload :LoggerFactory, 'tools/logger_factory'
79
+ autoload :ProcessCleaner, 'tools/process_cleaner'
79
80
  end
80
81
 
81
82
  module Shell
@@ -92,6 +93,7 @@ module KuberKit
92
93
  autoload :GitCommands, 'shell/commands/git_commands'
93
94
  autoload :RsyncCommands, 'shell/commands/rsync_commands'
94
95
  autoload :KubectlCommands, 'shell/commands/kubectl_commands'
96
+ autoload :SystemCommands, 'shell/commands/system_commands'
95
97
  end
96
98
  end
97
99
 
@@ -167,6 +169,7 @@ module KuberKit
167
169
  autoload :KubectlApplier, 'actions/kubectl_applier'
168
170
  autoload :KubectlAttacher, 'actions/kubectl_attacher'
169
171
  autoload :KubectlConsole, 'actions/kubectl_console'
172
+ autoload :KubectlDescribe, 'actions/kubectl_describe'
170
173
  autoload :KubectlLogs, 'actions/kubectl_logs'
171
174
  end
172
175
 
@@ -174,6 +177,10 @@ module KuberKit
174
177
  autoload :Inspectable, 'extensions/inspectable'
175
178
  end
176
179
 
180
+ module Kubernetes
181
+ autoload :ResourcesFetcher, 'kubernetes/resources_fetcher'
182
+ end
183
+
177
184
  module UI
178
185
  autoload :Interactive, 'ui/interactive'
179
186
  autoload :Simple, 'ui/simple'
@@ -254,6 +261,14 @@ module KuberKit
254
261
  KuberKit::Core::ContextHelper::BaseHelper.class_exec(&proc)
255
262
  end
256
263
 
264
+ def user
265
+ @user ||= ENV["KUBER_KIT_USERNAME"] || `whoami`.chomp
266
+ end
267
+
268
+ def user_id
269
+ @user_id ||= `id -u #{user}`.chomp
270
+ end
271
+
257
272
  def configure(&proc)
258
273
  yield(Container["configs"])
259
274
  end
@@ -18,6 +18,7 @@ class KuberKit::Actions::ConfigurationLoader
18
18
  infra_path = options[:infra_path] || File.join(root_path, configs.infra_dirname)
19
19
  configurations_path = options[:configurations_path] || File.join(root_path, configs.configurations_dirname)
20
20
  configuration_name = options[:configuration] || ENV["KUBER_KIT_CONFIGURATION"]
21
+ load_inventory = options.fetch(:load_inventory, true)
21
22
 
22
23
  ui.print_debug "ConfigurationLoader", "Launching kuber_kit with:"
23
24
  ui.print_debug "ConfigurationLoader", " Root path: #{root_path.to_s.yellow}"
@@ -40,25 +41,27 @@ class KuberKit::Actions::ConfigurationLoader
40
41
  load_configurations(configurations_path, configuration_name)
41
42
  load_infrastructure(infra_path)
42
43
 
43
- ui.create_task("Updating artifacts") do |task|
44
- artifacts = KuberKit.current_configuration.artifacts.values
45
- artifacts_updater.update(local_shell, artifacts)
46
- task.update_title("Updated #{artifacts.count} artifacts")
47
- end
44
+ if load_inventory
45
+ ui.create_task("Updating artifacts") do |task|
46
+ artifacts = KuberKit.current_configuration.artifacts.values
47
+ artifacts_updater.update(local_shell, artifacts)
48
+ task.update_title("Updated #{artifacts.count} artifacts")
49
+ end
48
50
 
49
- ui.create_task("Loading image definitions") do |task|
50
- files = image_store.load_definitions(images_path)
51
+ ui.create_task("Loading image definitions") do |task|
52
+ files = image_store.load_definitions(images_path)
51
53
 
52
- configs.additional_images_paths.each do |path|
53
- files += image_store.load_definitions(path)
54
- end
54
+ configs.additional_images_paths.each do |path|
55
+ files += image_store.load_definitions(path)
56
+ end
55
57
 
56
- task.update_title("Loaded #{files.count} image definitions")
57
- end
58
+ task.update_title("Loaded #{files.count} image definitions")
59
+ end
58
60
 
59
- ui.create_task("Loading service definitions") do |task|
60
- files = service_store.load_definitions(services_path)
61
- task.update_title("Loaded #{files.count} service definitions")
61
+ ui.create_task("Loading service definitions") do |task|
62
+ files = service_store.load_definitions(services_path)
63
+ task.update_title("Loaded #{files.count} service definitions")
64
+ end
62
65
  end
63
66
 
64
67
  true
@@ -84,9 +87,7 @@ class KuberKit::Actions::ConfigurationLoader
84
87
 
85
88
  if configuration_store.count > 1 && configuration_name.nil?
86
89
  options = all_configurations.map(&:configuration_name).map(&:to_s)
87
- ui.prompt("Please select configuration name (or set it using -C option)", options) do |selection|
88
- configuration_name = selection
89
- end
90
+ configuration_name = ui.prompt("Please select configuration name (or set it using -C option)", options)
90
91
  end
91
92
 
92
93
  KuberKit.set_configuration_name(configuration_name)
@@ -2,6 +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
6
  "ui"
6
7
  ]
7
8
 
@@ -10,10 +11,8 @@ class KuberKit::Actions::KubectlAttacher
10
11
  kubeconfig_path = KuberKit.current_configuration.kubeconfig_path
11
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
12
13
 
13
- if !pod_name
14
- resources = kubectl_commands.get_resources(local_shell, "deployments", jsonpath: ".items[*].metadata.name")
15
- options = resources.split(" ").map{|d| "deploy/#{d}" }
16
- pod_name = ui.prompt("Please select deployment to attach", options)
14
+ if !pod_name
15
+ pod_name = resources_fetcher.call("attach")
17
16
  end
18
17
 
19
18
  kubectl_commands.exec(
@@ -2,6 +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
6
  "ui"
6
7
  ]
7
8
 
@@ -11,9 +12,7 @@ class KuberKit::Actions::KubectlConsole
11
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
12
13
 
13
14
  if !pod_name
14
- resources = kubectl_commands.get_resources(local_shell, "deployments", jsonpath: ".items[*].metadata.name")
15
- options = resources.split(" ").map{|d| "deploy/#{d}" }
16
- pod_name = ui.prompt("Please select deployment to attach", options)
15
+ pod_name = resources_fetcher.call("attach")
17
16
  end
18
17
 
19
18
  kubectl_commands.exec(
@@ -0,0 +1,36 @@
1
+ class KuberKit::Actions::KubectlDescribe
2
+ include KuberKit::Import[
3
+ "shell.kubectl_commands",
4
+ "shell.local_shell",
5
+ "kubernetes.resources_fetcher",
6
+ "ui"
7
+ ]
8
+
9
+ Contract Maybe[String], Hash => Any
10
+ def call(resource_name, options)
11
+ kubeconfig_path = KuberKit.current_configuration.kubeconfig_path
12
+ deployer_namespace = KuberKit.current_configuration.deployer_namespace
13
+
14
+ if !resource_name
15
+ resource_name = resources_fetcher.call("describe", include_ingresses: true, include_pods: true)
16
+ end
17
+
18
+ args = nil
19
+ if options[:follow]
20
+ args = "-f"
21
+ end
22
+
23
+ kubectl_commands.describe(
24
+ local_shell, resource_name,
25
+ args: args,
26
+ kubeconfig_path: kubeconfig_path,
27
+ namespace: deployer_namespace
28
+ )
29
+
30
+ true
31
+ rescue KuberKit::Error => e
32
+ ui.print_error("Error", e.message)
33
+
34
+ false
35
+ end
36
+ end
@@ -2,6 +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
6
  "ui"
6
7
  ]
7
8
 
@@ -11,9 +12,7 @@ class KuberKit::Actions::KubectlLogs
11
12
  deployer_namespace = KuberKit.current_configuration.deployer_namespace
12
13
 
13
14
  if !pod_name
14
- deployments = kubectl_commands.get_resources(local_shell, "deployments", jsonpath: ".items[*].metadata.name")
15
- deploy_options = deployments.split(" ").map{|d| "deploy/#{d}" }
16
- pod_name = ui.prompt("Please select deployment to attach", deploy_options)
15
+ pod_name = resources_fetcher.call("attach")
17
16
  end
18
17
 
19
18
  args = nil
@@ -4,6 +4,7 @@ class KuberKit::Actions::ServiceDeployer
4
4
  "service_deployer.service_list_resolver",
5
5
  "core.service_store",
6
6
  "shell.local_shell",
7
+ "tools.process_cleaner",
7
8
  "ui",
8
9
  service_deployer: "service_deployer.action_handler",
9
10
  ]
@@ -20,8 +21,9 @@ class KuberKit::Actions::ServiceDeployer
20
21
  end
21
22
 
22
23
  service_names = service_list_resolver.resolve(
23
- services: services || [],
24
- tags: tags || []
24
+ services: services || [],
25
+ tags: tags || [],
26
+ enabled_services: KuberKit.current_configuration.enabled_services.map(&:to_s)
25
27
  )
26
28
 
27
29
  unless service_names.any?
@@ -34,7 +36,7 @@ class KuberKit::Actions::ServiceDeployer
34
36
 
35
37
  if require_confirmation
36
38
  result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
37
- return false unless result == "confirm".green
39
+ return false unless ["confirm".green, "confirm", "yes"].include?(result)
38
40
  end
39
41
 
40
42
  services = service_names.map do |service_name|
@@ -43,7 +45,11 @@ class KuberKit::Actions::ServiceDeployer
43
45
 
44
46
  images_names = services.map(&:images).flatten.uniq
45
47
 
46
- compile_images(images_names) unless skip_compile
48
+ unless skip_compile
49
+ compile_result = compile_images(images_names)
50
+ return false unless compile_result
51
+ end
52
+
47
53
  deployment_result = deploy_services(service_names)
48
54
 
49
55
  { services: service_names, deployment: deployment_result }
@@ -51,6 +57,8 @@ class KuberKit::Actions::ServiceDeployer
51
57
  ui.print_error("Error", e.message)
52
58
 
53
59
  false
60
+ rescue Interrupt => e
61
+ process_cleaner.clean
54
62
  end
55
63
 
56
64
  def deploy_services(service_names)
@@ -75,7 +83,8 @@ class KuberKit::Actions::ServiceDeployer
75
83
  end
76
84
 
77
85
  def compile_images(images_names)
78
- image_compiler.call(images_names, {}) if images_names.any?
86
+ return true if images_names.empty?
87
+ image_compiler.call(images_names, {})
79
88
  end
80
89
 
81
90
  def show_tags_selection()
@@ -92,12 +101,12 @@ class KuberKit::Actions::ServiceDeployer
92
101
  .sort
93
102
  .map(&:to_s)
94
103
 
95
- ui.prompt("Please select which tag to deploy", tags) do |selected_tag|
96
- if selected_tag == specific_service_option
97
- show_service_selection
98
- else
99
- return [[], [selected_tag]]
100
- end
104
+ selected_tag = ui.prompt("Please select which tag to deploy", tags)
105
+
106
+ if selected_tag == specific_service_option
107
+ show_service_selection
108
+ else
109
+ [[], [selected_tag]]
101
110
  end
102
111
  end
103
112
 
@@ -110,8 +119,11 @@ class KuberKit::Actions::ServiceDeployer
110
119
  .sort
111
120
  .map(&:to_s)
112
121
 
113
- ui.prompt("Please select which service to deploy", services) do |selected_service|
114
- return [[selected_service], []]
122
+ if services.empty?
123
+ return [[], []]
115
124
  end
125
+
126
+ selected_service = ui.prompt("Please select which service to deploy", services)
127
+ [[selected_service], []]
116
128
  end
117
129
  end
data/lib/kuber_kit/cli.rb CHANGED
@@ -30,9 +30,9 @@ class KuberKit::CLI < Thor
30
30
  end
31
31
  end
32
32
 
33
- desc "deploy CONTEXT_NAME", "Deploy CONTEXT_NAME with kubectl"
34
- method_option :services, :type => :array, aliases: ["-s"]
35
- method_option :tags, :type => :array, aliases: ["-t"]
33
+ desc "deploy -t CONTEXT_NAME", "Deploy CONTEXT_NAME with kubectl"
34
+ method_option :services, :type => :array, aliases: ["-s"], repeatable: true
35
+ method_option :tags, :type => :array, aliases: ["-t"], repeatable: true
36
36
  method_option :skip_compile, :type => :boolean, aliases: ["-B"]
37
37
  method_option :require_confirmation, :type => :boolean, aliases: ["-r"]
38
38
  def deploy
@@ -44,8 +44,8 @@ class KuberKit::CLI < Thor
44
44
  false
45
45
  started_at = Time.now.to_i
46
46
  result = KuberKit::Container['actions.service_deployer'].call(
47
- services: options[:services] || [],
48
- tags: options[:tags] || [],
47
+ services: (options[:services] || []).flatten.uniq,
48
+ tags: (options[:tags] || []).flatten.uniq,
49
49
  skip_compile: options[:skip_compile] || false,
50
50
  require_confirmation: require_confirmation
51
51
  )
@@ -108,7 +108,7 @@ class KuberKit::CLI < Thor
108
108
  def console(pod_name = nil)
109
109
  setup(options)
110
110
 
111
- if KuberKit::Container['actions.configuration_loader'].call(options)
111
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
112
112
  KuberKit::Container['actions.kubectl_console'].call(pod_name, options)
113
113
  end
114
114
  end
@@ -118,11 +118,20 @@ class KuberKit::CLI < Thor
118
118
  def logs(pod_name = nil)
119
119
  setup(options)
120
120
 
121
- if KuberKit::Container['actions.configuration_loader'].call(options)
121
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
122
122
  KuberKit::Container['actions.kubectl_logs'].call(pod_name, options)
123
123
  end
124
124
  end
125
125
 
126
+ desc "describe RESOURCE_NAME", "Show description for RESOURCE_NAME using kubectl"
127
+ def describe(pod_name = nil)
128
+ setup(options)
129
+
130
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
131
+ KuberKit::Container['actions.kubectl_describe'].call(pod_name, options)
132
+ end
133
+ end
134
+
126
135
  desc "version", "Print current version"
127
136
  def version
128
137
  puts KuberKit::VERSION
@@ -151,4 +160,21 @@ class KuberKit::CLI < Thor
151
160
  def print_result(message, data = {})
152
161
  KuberKit::Container['ui'].print_result(message, data)
153
162
  end
163
+
164
+ def cleanup_processes
165
+ # Stop all threads
166
+ Thread.list.each do |t|
167
+ t.abort_on_exception = false
168
+ t.report_on_exception = false
169
+ Thread.kill(t) if t != Thread.current
170
+ end
171
+
172
+ # Find all system calls
173
+ child_pids_raw = `ps auxww | grep '[K]IT=#{Process.pid}' | awk '{print $2}'`
174
+ child_pids = child_pids_raw.to_s.split("\n").reject(&:empty?)
175
+ child_pids.each do |pid|
176
+ puts "Killing child process: #{pid}"
177
+ Process.kill("SIGHUP", pid.to_i)
178
+ end
179
+ end
154
180
  end
@@ -37,6 +37,10 @@ class KuberKit::Container
37
37
  KuberKit::Actions::KubectlConsole.new
38
38
  end
39
39
 
40
+ register "actions.kubectl_describe" do
41
+ KuberKit::Actions::KubectlDescribe.new
42
+ end
43
+
40
44
  register "actions.kubectl_logs" do
41
45
  KuberKit::Actions::KubectlLogs.new
42
46
  end
@@ -117,6 +121,10 @@ class KuberKit::Container
117
121
  KuberKit::Container["tools.logger_factory"].create()
118
122
  end
119
123
 
124
+ register "tools.process_cleaner" do
125
+ KuberKit::Tools::ProcessCleaner.new
126
+ end
127
+
120
128
  register "shell.bash_commands" do
121
129
  KuberKit::Shell::Commands::BashCommands.new
122
130
  end
@@ -141,6 +149,10 @@ class KuberKit::Container
141
149
  KuberKit::Shell::Commands::KubectlCommands.new
142
150
  end
143
151
 
152
+ register "shell.system_commands" do
153
+ KuberKit::Shell::Commands::SystemCommands.new
154
+ end
155
+
144
156
  register "shell.local_shell" do
145
157
  KuberKit::Shell::LocalShell.new
146
158
  end
@@ -257,6 +269,10 @@ class KuberKit::Container
257
269
  KuberKit::ServiceReader::Reader.new
258
270
  end
259
271
 
272
+ register "kubernetes.resources_fetcher" do
273
+ KuberKit::Kubernetes::ResourcesFetcher.new
274
+ end
275
+
260
276
  register "ui" do
261
277
  if KuberKit.ui_mode == :debug
262
278
  KuberKit::UI::Debug.new
@@ -1,6 +1,6 @@
1
1
  class KuberKit::Core::Configuration
2
2
  attr_reader :name, :artifacts, :registries, :env_files, :templates, :kubeconfig_path,
3
- :services_attributes, :build_servers, :global_build_vars,
3
+ :services_attributes, :enabled_services, :build_servers, :global_build_vars,
4
4
  :deployer_strategy, :deployer_namespace, :deployer_require_confirimation
5
5
 
6
6
  Contract KeywordArgs[
@@ -11,6 +11,7 @@ class KuberKit::Core::Configuration
11
11
  templates: Hash,
12
12
  kubeconfig_path: Maybe[String],
13
13
  services_attributes: HashOf[Symbol => Hash],
14
+ enabled_services: ArrayOf[Symbol],
14
15
  build_servers: ArrayOf[KuberKit::Core::BuildServers::AbstractBuildServer],
15
16
  global_build_vars: HashOf[Symbol => Any],
16
17
  deployer_strategy: Symbol,
@@ -18,7 +19,7 @@ class KuberKit::Core::Configuration
18
19
  deployer_require_confirimation: Bool,
19
20
  ] => Any
20
21
  def initialize(name:, artifacts:, registries:, env_files:, templates:, kubeconfig_path:,
21
- services_attributes:, build_servers:, global_build_vars:,
22
+ services_attributes:, enabled_services:, build_servers:, global_build_vars:,
22
23
  deployer_strategy:, deployer_namespace:, deployer_require_confirimation:)
23
24
  @name = name
24
25
  @artifacts = artifacts
@@ -28,6 +29,7 @@ class KuberKit::Core::Configuration
28
29
  @kubeconfig_path = kubeconfig_path
29
30
  @build_servers = build_servers
30
31
  @services_attributes = services_attributes
32
+ @enabled_services = enabled_services
31
33
  @global_build_vars = global_build_vars
32
34
  @deployer_strategy = deployer_strategy
33
35
  @deployer_namespace = deployer_namespace
@@ -28,6 +28,7 @@ class KuberKit::Core::ConfigurationFactory
28
28
  kubeconfig_path: configuration_attrs.kubeconfig_path,
29
29
  build_servers: build_servers,
30
30
  services_attributes: configuration_attrs.services_attributes,
31
+ enabled_services: configuration_attrs.enabled_services,
31
32
  global_build_vars: configuration_attrs.global_build_vars || {},
32
33
  deployer_strategy: configuration_attrs.deployer_strategy || configs.deployer_strategy,
33
34
  deployer_namespace: configuration_attrs.deployer_namespace,
@@ -0,0 +1,41 @@
1
+ class KuberKit::Kubernetes::ResourcesFetcher
2
+ include KuberKit::Import[
3
+ "shell.kubectl_commands",
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 = 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
30
+
31
+ option
32
+ end
33
+
34
+ def get_resources(type)
35
+ kubectl_commands.get_resources(
36
+ local_shell, type,
37
+ jsonpath: ".items[*].metadata.name",
38
+ namespace: KuberKit.current_configuration.deployer_namespace
39
+ )
40
+ end
41
+ end
@@ -4,10 +4,11 @@ class KuberKit::ServiceDeployer::ServiceListResolver
4
4
  ]
5
5
 
6
6
  Contract KeywordArgs[
7
- services: Optional[ArrayOf[String]],
8
- tags: Optional[ArrayOf[String]]
7
+ services: Optional[ArrayOf[String]],
8
+ tags: Optional[ArrayOf[String]],
9
+ enabled_services: Optional[ArrayOf[String]]
9
10
  ] => ArrayOf[String]
10
- def resolve(services: [], tags: [])
11
+ def resolve(services: [], tags: [], enabled_services: [])
11
12
  all_definitions = service_store.all_definitions.values
12
13
 
13
14
  included_services, excluded_services = split_by_inclusion(services)
@@ -29,7 +30,13 @@ class KuberKit::ServiceDeployer::ServiceListResolver
29
30
  matches_any?(service_tags, excluded_tags)
30
31
  end
31
32
 
32
- included_definitions.map(&:service_name).map(&:to_s)
33
+ included_services = included_definitions.map(&:service_name).map(&:to_s)
34
+
35
+ if enabled_services.any?
36
+ included_services = included_services.select{ |s| enabled_services.include?(s) }
37
+ end
38
+
39
+ included_services
33
40
  end
34
41
 
35
42
  Contract Array => Array
@@ -29,6 +29,7 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
29
29
  custom_args = strategy_options.fetch(:custom_args, nil)
30
30
  networks = strategy_options.fetch(:networks, [])
31
31
  volumes = strategy_options.fetch(:volumes, [])
32
+ hostname = strategy_options.fetch(:hostname, container_name)
32
33
 
33
34
  image_name = strategy_options.fetch(:image_name, nil)
34
35
  if image_name.nil?
@@ -45,6 +46,9 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
45
46
  if container_name
46
47
  custom_args << "--name #{container_name}"
47
48
  end
49
+ if hostname
50
+ custom_args << "--hostname #{hostname}"
51
+ end
48
52
  networks.each do |network|
49
53
  docker_commands.create_network(shell, network)
50
54
  custom_args << "--network #{network}"
@@ -57,9 +61,10 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
57
61
 
58
62
  docker_commands.run(
59
63
  shell, image.remote_registry_url,
60
- command: command_name,
61
- args: custom_args,
62
- detached: !!strategy_options[:detached]
64
+ command: command_name,
65
+ args: custom_args,
66
+ detached: !!strategy_options[:detached],
67
+ interactive: !strategy_options[:detached]
63
68
  )
64
69
  end
65
70
  end
@@ -29,10 +29,11 @@ class KuberKit::ServiceDeployer::Strategies::DockerCompose < KuberKit::ServiceDe
29
29
  custom_args = strategy_options.fetch(:custom_args, nil)
30
30
 
31
31
  docker_compose_commands.run(shell, config_path,
32
- service: service_name,
33
- command: command_name,
34
- args: custom_args,
35
- detached: !!strategy_options[:detached]
32
+ service: service_name,
33
+ command: command_name,
34
+ args: custom_args,
35
+ detached: !!strategy_options[:detached],
36
+ interactive: !strategy_options[:detached]
36
37
  )
37
38
  end
38
39
  end
@@ -14,7 +14,7 @@ class KuberKit::Shell::Commands::KubectlCommands
14
14
  command_parts << "-n #{namespace}"
15
15
  end
16
16
 
17
- command_parts += Array(command_list)
17
+ command_parts += Array(command_list).compact
18
18
 
19
19
  if interactive
20
20
  shell.interactive!(command_parts.join(" "))
@@ -41,15 +41,11 @@ class KuberKit::Shell::Commands::KubectlCommands
41
41
  end
42
42
 
43
43
  def logs(shell, pod_name, args: nil, kubeconfig_path: nil, namespace: nil)
44
- command_parts = []
45
- command_parts << "logs"
46
-
47
- if args
48
- command_parts << args
49
- end
44
+ kubectl_run(shell, ["logs", args, pod_name], kubeconfig_path: kubeconfig_path, interactive: true, namespace: namespace)
45
+ end
50
46
 
51
- command_parts << pod_name
52
- kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, interactive: true, namespace: namespace)
47
+ def describe(shell, resource_name, args: nil, kubeconfig_path: nil, namespace: nil)
48
+ kubectl_run(shell, ["describe", args, resource_name], kubeconfig_path: kubeconfig_path, interactive: true, namespace: namespace)
53
49
  end
54
50
 
55
51
  def get_resources(shell, resource_type, field_selector: nil, jsonpath: ".items[*].metadata.name", kubeconfig_path: nil, namespace: nil)
@@ -64,7 +60,12 @@ class KuberKit::Shell::Commands::KubectlCommands
64
60
  command_parts << "-o jsonpath='{#{jsonpath}}'"
65
61
  end
66
62
 
67
- kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, namespace: namespace)
63
+ result = kubectl_run(shell, command_parts, kubeconfig_path: kubeconfig_path, namespace: namespace)
64
+
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)
67
+
68
+ result
68
69
  end
69
70
 
70
71
  def resource_exists?(shell, resource_type, resource_name, kubeconfig_path: nil, namespace: nil)
@@ -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,4 +1,5 @@
1
1
  require 'cli/ui'
2
+ require "tty-prompt"
2
3
 
3
4
  class KuberKit::UI::Interactive
4
5
  include KuberKit::Import[
@@ -42,17 +43,10 @@ class KuberKit::UI::Interactive
42
43
  end
43
44
 
44
45
  def prompt(text, options, &callback)
45
- CLI::UI::Prompt.ask(text) do |handler|
46
- options.each do |option|
47
- if callback
48
- handler.option(option, &callback)
49
- else
50
- handler.option(option) do |selection|
51
- selection
52
- end
53
- end
54
- end
55
- end
46
+ prompt = TTY::Prompt.new
47
+ prompt.select(text, options, filter: true, per_page: 10)
48
+ rescue TTY::Reader::InputInterrupt
49
+ raise KuberKit::Error.new("Selection cancelled.")
56
50
  end
57
51
 
58
52
  private
@@ -97,10 +97,9 @@ class KuberKit::UI::Simple
97
97
  print_debug("Result", "---------------------------")
98
98
  end
99
99
 
100
- def prompt(text, options, &callback)
101
- print_info("Select", text)
100
+ def prompt(text, options)
101
+ print_info("Select", text + "(#{options.join(', ')})")
102
102
  result = $stdin.gets.chomp
103
- callback.call(result) if callback
104
103
  result
105
104
  end
106
105
 
@@ -1,3 +1,3 @@
1
1
  module KuberKit
2
- VERSION = "0.4.3"
2
+ VERSION = "0.4.8"
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.3
4
+ version: 0.4.8
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-01-14 00:00:00.000000000 Z
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: contracts-lite
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-prompt
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: bundler
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -194,6 +208,7 @@ files:
194
208
  - lib/kuber_kit/actions/kubectl_applier.rb
195
209
  - lib/kuber_kit/actions/kubectl_attacher.rb
196
210
  - lib/kuber_kit/actions/kubectl_console.rb
211
+ - lib/kuber_kit/actions/kubectl_describe.rb
197
212
  - lib/kuber_kit/actions/kubectl_logs.rb
198
213
  - lib/kuber_kit/actions/service_deployer.rb
199
214
  - lib/kuber_kit/actions/service_reader.rb
@@ -258,6 +273,7 @@ files:
258
273
  - lib/kuber_kit/image_compiler/image_builder.rb
259
274
  - lib/kuber_kit/image_compiler/image_dependency_resolver.rb
260
275
  - lib/kuber_kit/image_compiler/version_tag_builder.rb
276
+ - lib/kuber_kit/kubernetes/resources_fetcher.rb
261
277
  - lib/kuber_kit/preprocessing/file_preprocessor.rb
262
278
  - lib/kuber_kit/preprocessing/text_preprocessor.rb
263
279
  - lib/kuber_kit/service_deployer/action_handler.rb
@@ -278,6 +294,7 @@ files:
278
294
  - lib/kuber_kit/shell/commands/git_commands.rb
279
295
  - lib/kuber_kit/shell/commands/kubectl_commands.rb
280
296
  - lib/kuber_kit/shell/commands/rsync_commands.rb
297
+ - lib/kuber_kit/shell/commands/system_commands.rb
281
298
  - lib/kuber_kit/shell/local_shell.rb
282
299
  - lib/kuber_kit/shell/ssh_session.rb
283
300
  - lib/kuber_kit/shell/ssh_shell.rb
@@ -287,6 +304,7 @@ files:
287
304
  - lib/kuber_kit/template_reader/strategies/artifact_file.rb
288
305
  - lib/kuber_kit/tools/file_presence_checker.rb
289
306
  - lib/kuber_kit/tools/logger_factory.rb
307
+ - lib/kuber_kit/tools/process_cleaner.rb
290
308
  - lib/kuber_kit/ui.rb
291
309
  - lib/kuber_kit/ui/api.rb
292
310
  - lib/kuber_kit/ui/debug.rb