kuber_kit 0.4.0 → 0.4.5

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: 88b8c2ffe3973bc966b245ceba37047030243d88119fd672db31efb002c67f86
4
- data.tar.gz: 5fafd218e63a669da3951b723f7167700704902006d4dd4fef13541e8ad1559b
3
+ metadata.gz: dfc1d29b7283361acaed01c9ddd08a29d121020c75af2d6ec7e4245d347021fb
4
+ data.tar.gz: 7e9063497954963223629beaa6d6ec914851c5e8c9633fa35d50986a95149aec
5
5
  SHA512:
6
- metadata.gz: a1c79c0056820500948580504c533be1ba2f9ceafe282802a0bbe44021a34196706c23eb97b05e6905efc26f565719fd9a1c668ec99afdbda642261ad6e8b6e1
7
- data.tar.gz: 3e4e33cc19ff7917ee5210dcdecae40ed22cb29d93f884bdb27adf3ec8565d3397ee8715ed8e89e75ae0316a0cf9192075d5afd66ba55caf3fe4f060064c88b9
6
+ metadata.gz: d0dd8904d21b8ca6648111856a6a5d8b4b3d1950a5db786f108f2906bdfc2388c6f515b4d833ce87f30f3c5098ebd1807aa0e3ef832903a4bec180b66788f3dc
7
+ data.tar.gz: b9cb8446b31460a27571b8a91defbf7882ff0ecf1d8d97dd581edaa496d2f60dae58b4bd8bd6fad091c5448a16830cee48259821751211e4e6751d2128d88fe2
data/Gemfile.lock CHANGED
@@ -1,19 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kuber_kit (0.4.0)
4
+ kuber_kit (0.4.5)
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,6 @@
1
- - https://ttytoolkit.org/
1
+ - add kit get method for interactive kubernetes
2
+ - do not show result for images list, if list is too large
2
3
  - kit status should show the list of services and their status, with ability to select & view logs
3
- - list services and require confirmation before deployment
4
- - add kit logs support, should work similar to kit attach
5
- - allow deploying only services enabled for specific configuration
6
4
  - find a way to always deploy some service, e.g. for migrations and env_files
7
5
  - template should be able to set default attributes
8
6
  - template should be able to depend on image?
@@ -2,4 +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
6
  #.use_build_server(:remote_bs)
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
@@ -167,6 +167,7 @@ module KuberKit
167
167
  autoload :KubectlApplier, 'actions/kubectl_applier'
168
168
  autoload :KubectlAttacher, 'actions/kubectl_attacher'
169
169
  autoload :KubectlConsole, 'actions/kubectl_console'
170
+ autoload :KubectlDescribe, 'actions/kubectl_describe'
170
171
  autoload :KubectlLogs, 'actions/kubectl_logs'
171
172
  end
172
173
 
@@ -254,6 +255,14 @@ module KuberKit
254
255
  KuberKit::Core::ContextHelper::BaseHelper.class_exec(&proc)
255
256
  end
256
257
 
258
+ def user
259
+ @user ||= ENV["KUBER_KIT_USERNAME"] || `whoami`.chomp
260
+ end
261
+
262
+ def user_id
263
+ @user_id ||= `id -u #{user}`.chomp
264
+ end
265
+
257
266
  def configure(&proc)
258
267
  yield(Container["configs"])
259
268
  end
@@ -17,7 +17,8 @@ class KuberKit::Actions::ConfigurationLoader
17
17
  services_path = options[:services_path] || File.join(root_path, configs.services_dirname)
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
- configuration_name = ENV["KUBER_KIT_CONFIGURATION"] || options[:configuration]
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)
@@ -3,6 +3,7 @@ class KuberKit::Actions::ImageCompiler
3
3
  "image_compiler.image_dependency_resolver",
4
4
  "image_compiler.build_server_pool_factory",
5
5
  "shell.local_shell",
6
+ "configs",
6
7
  "ui",
7
8
  image_compiler: "image_compiler.action_handler",
8
9
  ]
@@ -15,6 +16,7 @@ class KuberKit::Actions::ImageCompiler
15
16
  compiled_images = []
16
17
  compilation_result = {}
17
18
  image_dependency_resolver.each_with_deps(image_names) do |dep_image_names|
19
+ ui.print_debug("ImageCompiler", "Scheduling to compile: #{dep_image_names.inspect}. Limit: #{configs.compile_simultaneous_limit}")
18
20
  result = compile_simultaneously(dep_image_names, build_id, build_server_pool)
19
21
  compiled_images += dep_image_names
20
22
  compilation_result = compilation_result.merge(result)
@@ -0,0 +1,56 @@
1
+ class KuberKit::Actions::KubectlDescribe
2
+ include KuberKit::Import[
3
+ "shell.kubectl_commands",
4
+ "shell.local_shell",
5
+ "ui"
6
+ ]
7
+
8
+ Contract Maybe[String], Hash => Any
9
+ def call(resource_name, options)
10
+ kubeconfig_path = KuberKit.current_configuration.kubeconfig_path
11
+ deployer_namespace = KuberKit.current_configuration.deployer_namespace
12
+
13
+ if !resource_name
14
+ resource_name = get_resource_name
15
+ end
16
+
17
+ args = nil
18
+ if options[:follow]
19
+ args = "-f"
20
+ end
21
+
22
+ kubectl_commands.describe(
23
+ local_shell, resource_name,
24
+ args: args,
25
+ kubeconfig_path: kubeconfig_path,
26
+ namespace: deployer_namespace
27
+ )
28
+
29
+ true
30
+ rescue KuberKit::Error => e
31
+ ui.print_error("Error", e.message)
32
+
33
+ false
34
+ end
35
+
36
+ def get_resource_name
37
+ deployments = kubectl_commands.get_resources(local_shell, "deployments", jsonpath: ".items[*].metadata.name")
38
+ options = deployments.split(" ").map{|d| "deploy/#{d}" }
39
+ options += ["ingresses", "pods"]
40
+ option = ui.prompt("Please select resource to describe", options)
41
+
42
+ if option == "ingresses"
43
+ ingresses = kubectl_commands.get_resources(local_shell, "ingresses", jsonpath: ".items[*].metadata.name")
44
+ options = ingresses.split(" ").map{|d| "ingresses/#{d}" }
45
+ return ui.prompt("Please select ingress to describe", options)
46
+ end
47
+
48
+ if option == "pods"
49
+ ingresses = kubectl_commands.get_resources(local_shell, "pods", jsonpath: ".items[*].metadata.name")
50
+ options = ingresses.split(" ").map{|d| "pods/#{d}" }
51
+ return ui.prompt("Please select pod to describe", options)
52
+ end
53
+
54
+ option
55
+ end
56
+ end
@@ -9,22 +9,33 @@ class KuberKit::Actions::ServiceDeployer
9
9
  ]
10
10
 
11
11
  Contract KeywordArgs[
12
- services: Maybe[ArrayOf[String]],
13
- tags: Maybe[ArrayOf[String]],
14
- skip_compile: Maybe[Bool],
12
+ services: Maybe[ArrayOf[String]],
13
+ tags: Maybe[ArrayOf[String]],
14
+ skip_compile: Maybe[Bool],
15
+ require_confirmation: Maybe[Bool],
15
16
  ] => Any
16
- def call(services:, tags:, skip_compile: false)
17
+ def call(services:, tags:, skip_compile: false, require_confirmation: false)
17
18
  if services.empty? && tags.empty?
18
19
  services, tags = show_tags_selection
19
20
  end
20
21
 
21
22
  service_names = service_list_resolver.resolve(
22
- services: services || [],
23
- tags: tags || []
23
+ services: services || [],
24
+ tags: tags || [],
25
+ enabled_services: KuberKit.current_configuration.enabled_services.map(&:to_s)
24
26
  )
25
27
 
26
28
  unless service_names.any?
27
29
  ui.print_warning "ServiceDeployer", "No service found with given options, nothing will be deployed."
30
+ return false
31
+ end
32
+
33
+ services_list = service_names.map(&:to_s).map(&:yellow).join(", ")
34
+ ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
35
+
36
+ if require_confirmation
37
+ result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
38
+ return false unless ["confirm".green, "confirm", "yes"].include?(result)
28
39
  end
29
40
 
30
41
  services = service_names.map do |service_name|
@@ -33,7 +44,11 @@ class KuberKit::Actions::ServiceDeployer
33
44
 
34
45
  images_names = services.map(&:images).flatten.uniq
35
46
 
36
- compile_images(images_names) unless skip_compile
47
+ unless skip_compile
48
+ compile_result = compile_images(images_names)
49
+ return false unless compile_result
50
+ end
51
+
37
52
  deployment_result = deploy_services(service_names)
38
53
 
39
54
  { services: service_names, deployment: deployment_result }
@@ -65,7 +80,8 @@ class KuberKit::Actions::ServiceDeployer
65
80
  end
66
81
 
67
82
  def compile_images(images_names)
68
- image_compiler.call(images_names, {}) if images_names.any?
83
+ return true if images_names.empty?
84
+ image_compiler.call(images_names, {})
69
85
  end
70
86
 
71
87
  def show_tags_selection()
@@ -82,12 +98,12 @@ class KuberKit::Actions::ServiceDeployer
82
98
  .sort
83
99
  .map(&:to_s)
84
100
 
85
- ui.prompt("Please select which tag to deploy", tags) do |selected_tag|
86
- if selected_tag == specific_service_option
87
- show_service_selection
88
- else
89
- return [[], [selected_tag]]
90
- end
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]]
91
107
  end
92
108
  end
93
109
 
@@ -100,8 +116,11 @@ class KuberKit::Actions::ServiceDeployer
100
116
  .sort
101
117
  .map(&:to_s)
102
118
 
103
- ui.prompt("Please select which service to deploy", services) do |selected_service|
104
- return [[selected_service], []]
119
+ if services.empty?
120
+ return [[], []]
105
121
  end
122
+
123
+ selected_service = ui.prompt("Please select which service to deploy", services)
124
+ [[selected_service], []]
106
125
  end
107
126
  end
data/lib/kuber_kit/cli.rb CHANGED
@@ -15,6 +15,7 @@ class KuberKit::CLI < Thor
15
15
  def compile(image_names_str)
16
16
  setup(options)
17
17
 
18
+ started_at = Time.now.to_i
18
19
  image_names = image_names_str.split(",").map(&:strip).map(&:to_sym)
19
20
 
20
21
  if KuberKit::Container['actions.configuration_loader'].call(options)
@@ -22,29 +23,37 @@ class KuberKit::CLI < Thor
22
23
  end
23
24
 
24
25
  if result
25
- print_result("Image compilation finished!", result: result)
26
+ time = (Time.now.to_i - started_at)
27
+ print_result("Image compilation finished! (#{time}s)", result: result)
26
28
  else
27
29
  exit 1
28
30
  end
29
31
  end
30
32
 
31
- desc "deploy CONTEXT_NAME", "Deploy CONTEXT_NAME with kubectl"
32
- method_option :services, :type => :array, aliases: ["-s"]
33
- method_option :tags, :type => :array, aliases: ["-t"]
34
- method_option :skip_compile, :type => :boolean, aliases: ["-B"]
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
+ method_option :skip_compile, :type => :boolean, aliases: ["-B"]
37
+ method_option :require_confirmation, :type => :boolean, aliases: ["-r"]
35
38
  def deploy
36
39
  setup(options)
37
40
 
38
41
  if KuberKit::Container['actions.configuration_loader'].call(options)
42
+ require_confirmation = options[:require_confirmation] ||
43
+ KuberKit.current_configuration.deployer_require_confirimation ||
44
+ false
45
+ started_at = Time.now.to_i
39
46
  result = KuberKit::Container['actions.service_deployer'].call(
40
- services: options[:services] || [],
41
- tags: options[:tags] || [],
42
- skip_compile: options[:skip_compile] || false
47
+ services: (options[:services] || []).flatten.uniq,
48
+ tags: (options[:tags] || []).flatten.uniq,
49
+ skip_compile: options[:skip_compile] || false,
50
+ require_confirmation: require_confirmation
43
51
  )
44
52
  end
45
53
 
46
54
  if result
47
- print_result("Service deployment finished!", result: result)
55
+ time = (Time.now.to_i - started_at)
56
+ print_result("Service deployment finished! (#{time}s)", result: result)
48
57
  else
49
58
  exit 1
50
59
  end
@@ -99,7 +108,7 @@ class KuberKit::CLI < Thor
99
108
  def console(pod_name = nil)
100
109
  setup(options)
101
110
 
102
- if KuberKit::Container['actions.configuration_loader'].call(options)
111
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
103
112
  KuberKit::Container['actions.kubectl_console'].call(pod_name, options)
104
113
  end
105
114
  end
@@ -109,11 +118,20 @@ class KuberKit::CLI < Thor
109
118
  def logs(pod_name = nil)
110
119
  setup(options)
111
120
 
112
- if KuberKit::Container['actions.configuration_loader'].call(options)
121
+ if KuberKit::Container['actions.configuration_loader'].call(options.merge(load_inventory: false))
113
122
  KuberKit::Container['actions.kubectl_logs'].call(pod_name, options)
114
123
  end
115
124
  end
116
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
+
117
135
  desc "version", "Print current version"
118
136
  def version
119
137
  puts KuberKit::VERSION
@@ -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
@@ -1,35 +1,39 @@
1
1
  class KuberKit::Core::Configuration
2
2
  attr_reader :name, :artifacts, :registries, :env_files, :templates, :kubeconfig_path,
3
- :deployer_strategy, :deployer_namespace, :services_attributes, :build_servers,
4
- :global_build_vars
3
+ :services_attributes, :enabled_services, :build_servers, :global_build_vars,
4
+ :deployer_strategy, :deployer_namespace, :deployer_require_confirimation
5
5
 
6
6
  Contract KeywordArgs[
7
- name: Symbol,
8
- artifacts: Hash,
9
- registries: Hash,
10
- env_files: Hash,
11
- templates: Hash,
12
- kubeconfig_path: Maybe[String],
13
- deployer_strategy: Symbol,
14
- deployer_namespace: Maybe[Symbol],
15
- services_attributes: HashOf[Symbol => Hash],
16
- build_servers: ArrayOf[KuberKit::Core::BuildServers::AbstractBuildServer],
17
- global_build_vars: HashOf[Symbol => Any],
7
+ name: Symbol,
8
+ artifacts: Hash,
9
+ registries: Hash,
10
+ env_files: Hash,
11
+ templates: Hash,
12
+ kubeconfig_path: Maybe[String],
13
+ services_attributes: HashOf[Symbol => Hash],
14
+ enabled_services: ArrayOf[Symbol],
15
+ build_servers: ArrayOf[KuberKit::Core::BuildServers::AbstractBuildServer],
16
+ global_build_vars: HashOf[Symbol => Any],
17
+ deployer_strategy: Symbol,
18
+ deployer_namespace: Maybe[Symbol],
19
+ deployer_require_confirimation: Bool,
18
20
  ] => Any
19
21
  def initialize(name:, artifacts:, registries:, env_files:, templates:, kubeconfig_path:,
20
- deployer_strategy:, deployer_namespace:, services_attributes:, build_servers:,
21
- global_build_vars:)
22
- @name = name
23
- @artifacts = artifacts
24
- @registries = registries
25
- @env_files = env_files
26
- @templates = templates
27
- @kubeconfig_path = kubeconfig_path
28
- @deployer_strategy = deployer_strategy
29
- @deployer_namespace = deployer_namespace
30
- @build_servers = build_servers
22
+ services_attributes:, enabled_services:, build_servers:, global_build_vars:,
23
+ deployer_strategy:, deployer_namespace:, deployer_require_confirimation:)
24
+ @name = name
25
+ @artifacts = artifacts
26
+ @registries = registries
27
+ @env_files = env_files
28
+ @templates = templates
29
+ @kubeconfig_path = kubeconfig_path
30
+ @build_servers = build_servers
31
31
  @services_attributes = services_attributes
32
+ @enabled_services = enabled_services
32
33
  @global_build_vars = global_build_vars
34
+ @deployer_strategy = deployer_strategy
35
+ @deployer_namespace = deployer_namespace
36
+ @deployer_require_confirimation = deployer_require_confirimation
33
37
  end
34
38
 
35
39
  def service_attributes(service_name)
@@ -17,18 +17,19 @@ class KuberKit::Core::ConfigurationDefinition
17
17
 
18
18
  def to_attrs
19
19
  OpenStruct.new(
20
- name: @configuration_name,
21
- artifacts: @artifacts,
22
- registries: @registries,
23
- env_files: @env_files,
24
- templates: @templates,
25
- kubeconfig_path: @kubeconfig_path,
26
- deployer_strategy: @deployer_strategy,
27
- deployer_namespace: @deployer_namespace,
28
- enabled_services: @enabled_services,
29
- build_servers: @build_servers,
20
+ name: @configuration_name,
21
+ artifacts: @artifacts,
22
+ registries: @registries,
23
+ env_files: @env_files,
24
+ templates: @templates,
25
+ kubeconfig_path: @kubeconfig_path,
26
+ enabled_services: @enabled_services,
27
+ build_servers: @build_servers,
30
28
  services_attributes: @services_attributes,
31
29
  global_build_vars: @global_build_vars,
30
+ deployer_strategy: @deployer_strategy,
31
+ deployer_namespace: @deployer_namespace,
32
+ deployer_require_confirimation: @deployer_require_confirimation || false,
32
33
  )
33
34
  end
34
35
 
@@ -94,6 +95,12 @@ class KuberKit::Core::ConfigurationDefinition
94
95
  self
95
96
  end
96
97
 
98
+ def deployer_require_confirimation
99
+ @deployer_require_confirimation = true
100
+
101
+ self
102
+ end
103
+
97
104
  def enabled_services(services)
98
105
  if services.is_a?(Hash)
99
106
  @enabled_services += services.keys.map(&:to_sym)
@@ -20,17 +20,19 @@ class KuberKit::Core::ConfigurationFactory
20
20
  build_servers = fetch_build_servers(configuration_attrs.build_servers)
21
21
 
22
22
  KuberKit::Core::Configuration.new(
23
- name: configuration_attrs.name,
24
- artifacts: artifacts,
25
- registries: registries,
26
- env_files: env_files,
27
- templates: templates,
28
- kubeconfig_path: configuration_attrs.kubeconfig_path,
29
- deployer_strategy: configuration_attrs.deployer_strategy || configs.deployer_strategy,
30
- deployer_namespace: configuration_attrs.deployer_namespace,
31
- build_servers: build_servers,
23
+ name: configuration_attrs.name,
24
+ artifacts: artifacts,
25
+ registries: registries,
26
+ env_files: env_files,
27
+ templates: templates,
28
+ kubeconfig_path: configuration_attrs.kubeconfig_path,
29
+ build_servers: build_servers,
32
30
  services_attributes: configuration_attrs.services_attributes,
31
+ enabled_services: configuration_attrs.enabled_services,
33
32
  global_build_vars: configuration_attrs.global_build_vars || {},
33
+ deployer_strategy: configuration_attrs.deployer_strategy || configs.deployer_strategy,
34
+ deployer_namespace: configuration_attrs.deployer_namespace,
35
+ deployer_require_confirimation: configuration_attrs.deployer_require_confirimation,
34
36
  )
35
37
  end
36
38
 
@@ -20,7 +20,9 @@ class KuberKit::ImageCompiler::ImageDependencyResolver
20
20
  next_dependencies = get_next(image_names, resolved: resolved_dependencies, limit: compile_limit)
21
21
  end
22
22
 
23
- block.call(image_names - resolved_dependencies)
23
+ (image_names - resolved_dependencies).each_slice(compile_limit) do |group|
24
+ block.call(group)
25
+ end
24
26
  end
25
27
 
26
28
  Contract Or[Symbol, ArrayOf[Symbol]], KeywordArgs[
@@ -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
@@ -10,8 +10,10 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
10
10
  :image_name,
11
11
  :detached,
12
12
  :command_name,
13
- :command_args,
14
- :delete_if_exists
13
+ :custom_args,
14
+ :delete_if_exists,
15
+ :volumes,
16
+ :networks,
15
17
  ]
16
18
 
17
19
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
@@ -23,8 +25,11 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
23
25
  end
24
26
 
25
27
  container_name = strategy_options.fetch(:container_name, service.uri)
26
- command_name = strategy_options.fetch(:command_name, "bash")
27
- command_args = strategy_options.fetch(:command_args, nil)
28
+ command_name = strategy_options.fetch(:command_name, nil)
29
+ custom_args = strategy_options.fetch(:custom_args, nil)
30
+ networks = strategy_options.fetch(:networks, [])
31
+ volumes = strategy_options.fetch(:volumes, [])
32
+ hostname = strategy_options.fetch(:hostname, container_name)
28
33
 
29
34
  image_name = strategy_options.fetch(:image_name, nil)
30
35
  if image_name.nil?
@@ -37,15 +42,27 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
37
42
  docker_commands.delete_container(shell, container_name)
38
43
  end
39
44
 
40
- command_args = Array(command_args)
45
+ custom_args = Array(custom_args)
41
46
  if container_name
42
- command_args << "--name #{container_name}"
47
+ custom_args << "--name #{container_name}"
48
+ end
49
+ if hostname
50
+ custom_args << "--hostname #{hostname}"
51
+ end
52
+ networks.each do |network|
53
+ docker_commands.create_network(shell, network)
54
+ custom_args << "--network #{network}"
55
+ end
56
+ volumes.each do |volume|
57
+ volume_name, _ = volume.split(":")
58
+ docker_commands.create_volume(shell, volume_name) unless volume_name.start_with?("/")
59
+ custom_args << "--volume #{volume}"
43
60
  end
44
61
 
45
62
  docker_commands.run(
46
63
  shell, image.remote_registry_url,
47
64
  command: command_name,
48
- args: command_args,
65
+ args: custom_args,
49
66
  detached: !!strategy_options[:detached]
50
67
  )
51
68
  end
@@ -8,7 +8,7 @@ class KuberKit::ServiceDeployer::Strategies::DockerCompose < KuberKit::ServiceDe
8
8
  STRATEGY_OPTIONS = [
9
9
  :service_name,
10
10
  :command_name,
11
- :command_args,
11
+ :custom_args,
12
12
  :detached
13
13
  ]
14
14
 
@@ -25,13 +25,13 @@ class KuberKit::ServiceDeployer::Strategies::DockerCompose < KuberKit::ServiceDe
25
25
  end
26
26
 
27
27
  service_name = strategy_options.fetch(:service_name, service.name.to_s)
28
- command_name = strategy_options.fetch(:command_name, "bash")
29
- command_args = strategy_options.fetch(:command_args, nil)
28
+ command_name = strategy_options.fetch(:command_name, nil)
29
+ custom_args = strategy_options.fetch(:custom_args, nil)
30
30
 
31
31
  docker_compose_commands.run(shell, config_path,
32
32
  service: service_name,
33
33
  command: command_name,
34
- args: command_args,
34
+ args: custom_args,
35
35
  detached: !!strategy_options[:detached]
36
36
  )
37
37
  end
@@ -30,15 +30,11 @@ class KuberKit::Shell::Commands::DockerCommands
30
30
  end
31
31
 
32
32
  def container_exists?(shell, container_name, status: nil)
33
- result = get_container_id(shell, container_name, status: status)
33
+ result = get_containers(shell, container_name, status: status)
34
34
  result && result != ""
35
35
  end
36
36
 
37
- def delete_container(shell, container_name)
38
- shell.exec!(%Q{docker rm -f #{container_name}})
39
- end
40
-
41
- def get_container_id(shell, container_name, only_healthy: false, status: nil)
37
+ def get_containers(shell, container_name, only_healthy: false, status: nil)
42
38
  command_parts = []
43
39
  command_parts << "docker ps -a -q"
44
40
 
@@ -52,4 +48,48 @@ class KuberKit::Shell::Commands::DockerCommands
52
48
 
53
49
  shell.exec!(command_parts.join(" "))
54
50
  end
51
+
52
+ def delete_container(shell, container_name)
53
+ shell.exec!("docker rm -f #{container_name}")
54
+ end
55
+
56
+ def create_network(shell, name)
57
+ unless network_exists?(shell, name)
58
+ shell.exec!("docker network create #{name}")
59
+ end
60
+ end
61
+
62
+ def network_exists?(shell, network_name)
63
+ result = get_networks(shell, network_name)
64
+ result && result != ""
65
+ end
66
+
67
+ def get_networks(shell, network_name)
68
+ command_parts = []
69
+ command_parts << "docker network ls"
70
+ command_parts << "--filter=\"name=#{network_name}\""
71
+ command_parts << "--format \"{{.Name}}\""
72
+
73
+ shell.exec!(command_parts.join(" "))
74
+ end
75
+
76
+ def create_volume(shell, name)
77
+ unless volume_exists?(shell, name)
78
+ shell.exec!("docker volume create #{name}")
79
+ end
80
+ end
81
+
82
+ def volume_exists?(shell, volume_name)
83
+ result = get_volumes(shell, volume_name)
84
+ result && result != ""
85
+ end
86
+
87
+ def get_volumes(shell, volume_name)
88
+ command_parts = []
89
+ command_parts << "docker volume ls"
90
+ command_parts << "--filter=\"name=#{volume_name}\""
91
+ command_parts << "--format \"{{.Name}}\""
92
+
93
+ shell.exec!(command_parts.join(" "))
94
+ end
55
95
  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)
@@ -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.0"
2
+ VERSION = "0.4.5"
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.0
4
+ version: 0.4.5
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-13 00:00:00.000000000 Z
11
+ date: 2021-02-09 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