stax-helm 0.0.3 → 0.0.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: 915820e964fa23b1d20b876f7e89d22ee55a97e4aa60fec75e508e47f36daf54
4
- data.tar.gz: 6da2869fac93946398ec4c0c83df102f4cb2a883b0b5dd72ce6486d5a804ea63
3
+ metadata.gz: 90efb4bc5fd77b16200e4693747b303df7644ebfe21149d715327a56397f1d25
4
+ data.tar.gz: 19d2b39ef1cbd165dbd32091f317f8c11b12624d381920bdffd5295b8b8c5b68
5
5
  SHA512:
6
- metadata.gz: 80d9424da2501a5b209af37868fd4b615d53acb125517effb7c3a759019cf3de9ef8c025f0e10b3473b48823b986ec11c4e9cf7a010b36e2f829ca2b878c939e
7
- data.tar.gz: 4bef3ab94b44a3fec3c20d3df75b353bd89a823f2c5ad0959985130a8797cbe694388f4649bd1152cf53b3265e4d5e49ce897a0e1a6da8b90847632e34e25020
6
+ metadata.gz: 5566799f8341ace21b46a2ec7c3d90a3c5dc11d26f54c7efa1dc593df439e6dd59732286153823995573a53337252f8249000d54f26dd4813e72ebad23e943ff
7
+ data.tar.gz: 8d1b6ca7b1e7465cac0f77754438ccff9ad880e12bf7d1eb9b2c58a6f48921bbad3471696ab4cd2e609aeee1cd749c0ce6304c23ad248ece555a2291140c5785
@@ -1,4 +1,9 @@
1
+ require 'stax/helm/base'
1
2
  require 'stax/helm/cmd'
2
3
  require 'stax/helm/kubectl'
4
+ require 'stax/helm/ingress'
5
+ require 'stax/helm/pod'
6
+ require 'stax/helm/deployment'
3
7
  require 'stax/helm/stern'
8
+ require 'stax/helm/runcmd'
4
9
  Stax.add_command(:helm, Stax::Helm::Cmd)
@@ -0,0 +1,16 @@
1
+ module Stax
2
+ class Base < Thor
3
+
4
+ no_commands do
5
+ def helm_release_name
6
+ @_helm_release_name ||= helm_safe("#{app_name}-#{branch_name}")
7
+ end
8
+
9
+ ## make string safe to use in naming helm stuff
10
+ def helm_safe(string)
11
+ string.slice(0, 53).gsub(/[\W_]/, '-').downcase
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -1,13 +1,10 @@
1
1
  module Stax
2
2
  module Helm
3
+
3
4
  class Cmd < Base
4
5
  class_option :recon, aliases: '--just-print', type: :boolean, default: false, desc: 'print command that would be run'
5
6
 
6
7
  no_commands do
7
- def helm_release_name
8
- @_helm_release_name ||= "#{app_name}-#{branch_name}"
9
- end
10
-
11
8
  ## location of helm chart
12
9
  def helm_dir
13
10
  File.join(Stax.root_path, 'helm')
@@ -0,0 +1,56 @@
1
+ ## tasks to work on deployments
2
+ module Stax
3
+ module Helm
4
+ class Cmd < Base
5
+
6
+ no_commands do
7
+ def helm_deployments
8
+ jsonpath = '{.items[*].metadata.name}'
9
+ %x[kubectl get deployments -o=jsonpath='#{jsonpath}' -l #{helm_selector}].split
10
+ end
11
+
12
+ ## prompt user with a list of deployments to choose
13
+ def helm_ask_deployments(msg)
14
+ deployments = helm_deployments
15
+ if deployments.count > 1
16
+ puts deployments.each_with_index.map { |d, i| "#{i}: #{d}" }
17
+ resp = ask(msg, default: 'all')
18
+ if resp != 'all'
19
+ indices = resp.split.map(&:to_i)
20
+ deployments = Array(deployments.slice(*indices))
21
+ end
22
+ end
23
+ deployments
24
+ end
25
+ end
26
+
27
+ desc 'deployments', 'list deployments'
28
+ def deployments
29
+ kubectl_run(:get, :deployments, '-l', helm_selector)
30
+ end
31
+
32
+ desc 'restart', 'restart deployments'
33
+ def restart
34
+ helm_ask_deployments('choose deployments').each do |deployment|
35
+ kubectl_run(:rollout, :restart, :deployment, deployment)
36
+ end
37
+ end
38
+
39
+ desc 'scale', 'show/set scale for deployments'
40
+ method_option :replicas, aliases: '-r', type: :numeric, default: nil, desc: 'replicas'
41
+ def scale
42
+ if options[:replicas]
43
+ deployments = helm_ask_deployments('choose deployments').join(' ')
44
+ kubectl_run(:scale, :deployment, deployments, '--replicas', options[:replicas])
45
+ else
46
+ debug("Deployment replicas for #{helm_release_name}")
47
+ deployments = kubectl_json(:get, :deployments, '-l', helm_selector)
48
+ print_table deployments['items'].map { |i|
49
+ [ i['metadata']['name'], i['status']['replicas'] || 0 ]
50
+ }
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ ## tasks to get ingress details
2
+ module Stax
3
+ module Helm
4
+ class Cmd < Base
5
+
6
+ desc 'ingresses', 'list ingresses'
7
+ def ingresses
8
+ kubectl_run(:get, :ingresses, '-l', helm_selector)
9
+ end
10
+
11
+ desc 'dns', 'list external-dns hostnames'
12
+ def dns
13
+ jsonpath = '{.items[].metadata.annotations.external-dns\.alpha\.kubernetes\.io/hostname}' + "\n"
14
+ kubectl_run(:get, :ingresses, "-o=jsonpath='#{jsonpath}'", '-l', helm_selector)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -9,54 +9,24 @@ module Stax
9
9
 
10
10
  def kubectl_run(*args)
11
11
  cmd = [kubectl_bin, *args].join(' ')
12
- options[:dry_run] ? puts(cmd) : system(cmd)
12
+ options[:recon] ? puts(cmd) : system(cmd)
13
13
  end
14
14
 
15
- ## build a selector argument from a hash of label and value pairs
16
- def selector(hash)
17
- '-l ' + hash.compact.map { |k,v| "#{k}=#{v}" }.join(',')
15
+ def kubectl_json(*args)
16
+ args.push('-o=json')
17
+ cmd = [kubectl_bin, *args].join(' ')
18
+ options[:recon] ? puts(cmd) : JSON.parse(%x(#{cmd}))
19
+ end
20
+
21
+ ## override this to match all objects in your helm release
22
+ def helm_selector
23
+ "app.kubernetes.io/instance=#{helm_release_name}"
18
24
  end
19
25
  end
20
26
 
21
27
  desc 'services', 'list services'
22
28
  def services
23
- kubectl_run(:get, :services, selector('app.kubernetes.io/instance': helm_release_name))
24
- end
25
-
26
- desc 'ingresses', 'list ingresses'
27
- def ingresses
28
- kubectl_run(:get, :ingresses, selector('app.kubernetes.io/instance': helm_release_name))
29
- end
30
-
31
- desc 'deployments', 'list deployments'
32
- def deployments
33
- kubectl_run(:get, :deployments, selector('app.kubernetes.io/instance': helm_release_name))
34
- end
35
-
36
- desc 'pods', 'list pods'
37
- def pods
38
- kubectl_run(:get, :pods, selector('app.kubernetes.io/instance': helm_release_name))
39
- end
40
-
41
- desc 'containers', 'list containers'
42
- def containers
43
- columns = 'NAME:.metadata.name,CONTAINERS:.spec.containers[*].name'
44
- kubectl_run(:get, :pods, '-o', "custom-columns=#{columns}", selector('app.kubernetes.io/instance': helm_release_name))
45
- end
46
-
47
- ## FIXME this is terrible, will be replaced with something better later
48
- desc 'logs COMPONENT [CONTAINER]', 'show container logs'
49
- method_option :container, aliases: '-c', type: :string, default: nil, desc: 'container from pod'
50
- def logs(component)
51
- container = options[:container] ? "-c #{options[:container]}" : ''
52
- kubectl_run(
53
- :logs,
54
- container,
55
- selector(
56
- 'app.kubernetes.io/instance': helm_release_name,
57
- 'app.kubernetes.io/component': component,
58
- )
59
- )
29
+ kubectl_run(:get, :services, '-l', helm_selector)
60
30
  end
61
31
 
62
32
  end
@@ -0,0 +1,49 @@
1
+ ## tasks to work on pods
2
+ module Stax
3
+ module Helm
4
+ class Cmd < Base
5
+
6
+ no_commands do
7
+ def helm_pods
8
+ jsonpath = '{.items[*].metadata.name}'
9
+ %x[kubectl get pods -o=jsonpath='#{jsonpath}' -l #{helm_selector}].split
10
+ end
11
+
12
+ def helm_ask_pod(msg)
13
+ pods = helm_pods
14
+ index = 0
15
+ if pods.count > 1
16
+ puts pods.each_with_index.map { |p, i| "#{i}: #{p}" }
17
+ index = ask(msg, default: index)
18
+ end
19
+ pods[index.to_i]
20
+ end
21
+ end
22
+
23
+ desc 'pods', 'list pods'
24
+ def pods
25
+ kubectl_run(:get, :pods, '-l', helm_selector)
26
+ end
27
+
28
+ desc 'containers', 'list containers'
29
+ def containers
30
+ columns = 'NAME:.metadata.name,CONTAINERS:.spec.containers[*].name'
31
+ kubectl_run(:get, :pods, '-o', "custom-columns=#{columns}", '-l', helm_selector)
32
+ end
33
+
34
+ desc 'logs [OPTIONS]', 'run kubectl logs with same options'
35
+ def logs(*args)
36
+ trap('SIGINT', 'EXIT') # clean exit with ctrl-c
37
+ args = [ '--all-containers', '--prefix', '--follow' ] if args.empty? # helpful default args
38
+ kubectl_run(:logs, '-l', helm_selector, *args)
39
+ end
40
+
41
+ desc 'exec [CMD]', 'exec command in a web pod'
42
+ def exec(cmd = 'sh')
43
+ pod = helm_ask_pod('choose a pod')
44
+ kubectl_run(:exec, '-it', pod, '--', cmd)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,101 @@
1
+ require 'securerandom'
2
+
3
+ module Stax
4
+ module Helm
5
+ class Cmd
6
+
7
+ no_commands do
8
+ ## construct a Job template from passed container spec
9
+ def helm_run_template(name, container_spec)
10
+ {
11
+ apiVersion: 'batch/v1',
12
+ kind: :Job,
13
+ metadata: {
14
+ name: name,
15
+ labels: {
16
+ 'app.kubernetes.io/managed-by' => :stax
17
+ }
18
+ },
19
+ spec: {
20
+ template: {
21
+ spec: {
22
+ restartPolicy: :Never,
23
+ containers: [ container_spec ],
24
+ }
25
+ }
26
+ }
27
+ }.to_json
28
+ end
29
+
30
+ ## Deployment to clone for container
31
+ def helm_run_deployment
32
+ "#{helm_release_name}-web"
33
+ end
34
+
35
+ ## name of container to clone from Deployment
36
+ def helm_run_container
37
+ 'web'
38
+ end
39
+
40
+ ## name for Job to create based on container
41
+ def helm_run_job
42
+ "#{helm_release_name}-run-#{SecureRandom.hex(4)}"
43
+ end
44
+
45
+ ## default command to run
46
+ def helm_run_cmd
47
+ 'bash'
48
+ end
49
+ end
50
+
51
+ ## task creates a dedicated unique kubernetes Job, with
52
+ ## container spec based on the helm release deployment
53
+ ## requested, then does an interactive exec to the pod and
54
+ ## container created, and deletes the Job on exit
55
+ desc 'runcmd [CMD]', 'run dedicated interactive container'
56
+ method_option :sleep, type: :string, default: '1h', description: 'kill container after time'
57
+ method_option :keep, type: :boolean, default: false, description: 'do not delete job'
58
+ def runcmd(*cmd)
59
+ ## use default if not set
60
+ cmd = Array(helm_run_cmd) if cmd.empty?
61
+
62
+ ## name of k8s Job to create
63
+ job = helm_run_job
64
+
65
+ ## get deployment and extract container spec
66
+ deployment = kubectl_json(:get, :deployment, helm_run_deployment)
67
+ spec = deployment['spec']['template']['spec']['containers'].find do |c|
68
+ c['name'] == helm_run_container
69
+ end
70
+
71
+ ## cleanup the container spec so we can use it in a Job
72
+ spec.delete('livenessProbe')
73
+ spec.delete('readinessProbe')
74
+ spec.delete('volumeMounts')
75
+ spec['name'] = 'run'
76
+ spec['args'] = ['sleep', options[:sleep]]
77
+
78
+ ## create new unique Job based on the container spec
79
+ debug("Creating job #{job}")
80
+ Open3.popen2('kubectl create -f -') { |stdin, stdout, _|
81
+ stdin.print(helm_run_template(job, spec))
82
+ stdin.close
83
+ puts stdout.gets
84
+ }
85
+
86
+ ## get name of the Pod created by the Job
87
+ pod = kubectl_json(:get, :pod, '-l', "job-name=#{job}")['items'].first['metadata']['name']
88
+
89
+ ## exec into the pod and run interactive command
90
+ debug("Connecting to pod #{pod}")
91
+ kubectl_run(:wait, '--for=condition=Ready', '--timeout=5m', :pod, pod)
92
+ kubectl_run(:exec, '-it', pod, '--', *cmd)
93
+ rescue JSON::ParserError
94
+ fail_task('cannot get kubernetes resource')
95
+ ensure
96
+ ## delete Job
97
+ kubectl_run(:delete, :job, job) unless options[:keep]
98
+ end
99
+ end
100
+ end
101
+ end
@@ -16,7 +16,8 @@ module Stax
16
16
  ## pass through args to stern
17
17
  desc 'stern [STERN_ARGS]', 'use stern to show logs'
18
18
  def stern(*args)
19
- stern_run(selector('app.kubernetes.io/instance': helm_release_name), *args)
19
+ trap('SIGINT', 'EXIT') # clean exit with ctrl-c
20
+ stern_run('-l', helm_selector, *args)
20
21
  end
21
22
 
22
23
  end
@@ -1,5 +1,5 @@
1
1
  module Stax
2
2
  module Helm
3
- VERSION = '0.0.3'
3
+ VERSION = '0.0.8'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stax-helm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Lister
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-30 00:00:00.000000000 Z
11
+ date: 2020-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,8 +67,13 @@ files:
67
67
  - README.md
68
68
  - Rakefile
69
69
  - lib/stax/helm.rb
70
+ - lib/stax/helm/base.rb
70
71
  - lib/stax/helm/cmd.rb
72
+ - lib/stax/helm/deployment.rb
73
+ - lib/stax/helm/ingress.rb
71
74
  - lib/stax/helm/kubectl.rb
75
+ - lib/stax/helm/pod.rb
76
+ - lib/stax/helm/runcmd.rb
72
77
  - lib/stax/helm/stern.rb
73
78
  - lib/stax/helm/version.rb
74
79
  - stax-helm.gemspec
@@ -76,7 +81,7 @@ homepage: https://github.com/rlister/stax-helm
76
81
  licenses:
77
82
  - MIT
78
83
  metadata: {}
79
- post_install_message:
84
+ post_install_message:
80
85
  rdoc_options: []
81
86
  require_paths:
82
87
  - lib
@@ -91,8 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
96
  - !ruby/object:Gem::Version
92
97
  version: '0'
93
98
  requirements: []
94
- rubygems_version: 3.1.2
95
- signing_key:
99
+ rubygems_version: 3.0.3
100
+ signing_key:
96
101
  specification_version: 4
97
102
  summary: Control helm charts with stax.
98
103
  test_files: []