kuber_kit 0.4.0 → 0.4.5

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: 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