kubes 0.4.4 → 0.5.1

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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/README.md +1 -1
  4. data/docs/_docs/config/reference.md +1 -0
  5. data/docs/_docs/config/skip.md +1 -1
  6. data/docs/_docs/dsl/multiple-resources.md +3 -3
  7. data/docs/_docs/dsl/resources/job.md +62 -0
  8. data/docs/_docs/extra-env/dsl.md +2 -2
  9. data/docs/_docs/extra-env/yaml.md +1 -1
  10. data/docs/_docs/generators.md +41 -0
  11. data/docs/_docs/helpers.md +10 -3
  12. data/docs/_docs/helpers/aws.md +15 -0
  13. data/docs/_docs/helpers/aws/iam-role.md +91 -0
  14. data/docs/_docs/helpers/aws/secrets.md +129 -0
  15. data/docs/_docs/helpers/aws/ssm.md +76 -0
  16. data/docs/_docs/helpers/custom.md +40 -0
  17. data/docs/_docs/helpers/google.md +17 -0
  18. data/docs/_docs/helpers/google/secrets.md +76 -0
  19. data/docs/_docs/helpers/google/service-account.md +60 -0
  20. data/docs/_docs/intro.md +3 -1
  21. data/docs/_docs/intro/docker-image.md +66 -0
  22. data/docs/_docs/intro/how-kubes-works.md +7 -11
  23. data/docs/_docs/layering/merge.md +1 -1
  24. data/docs/_docs/learn/dsl/delete.md +10 -2
  25. data/docs/_docs/learn/dsl/review-project.md +2 -2
  26. data/docs/_docs/learn/yaml/delete.md +10 -2
  27. data/docs/_docs/learn/yaml/review-project.md +2 -2
  28. data/docs/_docs/patterns/clock-web-worker.md +3 -3
  29. data/docs/_docs/patterns/migrations.md +1 -1
  30. data/docs/_docs/patterns/secrets.md +0 -2
  31. data/docs/_docs/yaml.md +2 -2
  32. data/docs/_includes/commands.html +2 -2
  33. data/docs/_includes/helpers/base64.md +1 -0
  34. data/docs/_includes/sidebar.html +23 -1
  35. data/docs/_reference/kubes-delete.md +1 -1
  36. data/docs/_reference/kubes-exec.md +17 -1
  37. data/docs/_reference/kubes-init.md +2 -2
  38. data/docs/_reference/kubes-logs.md +2 -1
  39. data/docs/_reference/kubes-new.md +58 -0
  40. data/docs/_reference/kubes-prune.md +22 -0
  41. data/docs/reference.md +2 -0
  42. data/kubes.gemspec +1 -0
  43. data/lib/kubes.rb +2 -0
  44. data/lib/kubes/autoloader.rb +9 -0
  45. data/lib/kubes/cli.rb +9 -1
  46. data/lib/kubes/cli/build.rb +6 -0
  47. data/lib/kubes/cli/compile.rb +7 -0
  48. data/lib/kubes/cli/deploy.rb +1 -6
  49. data/lib/kubes/cli/exec.rb +5 -1
  50. data/lib/kubes/cli/help/exec.md +15 -0
  51. data/lib/kubes/cli/help/new.md +30 -0
  52. data/lib/kubes/cli/init.rb +1 -1
  53. data/lib/kubes/cli/new.rb +97 -0
  54. data/lib/kubes/cli/sequence.rb +1 -0
  55. data/lib/kubes/command.rb +7 -0
  56. data/lib/kubes/compiler.rb +19 -21
  57. data/lib/kubes/compiler/dsl/syntax/job.rb +217 -0
  58. data/lib/kubes/compiler/shared/custom_helpers.rb +17 -0
  59. data/lib/kubes/compiler/shared/helpers.rb +12 -3
  60. data/lib/kubes/compiler/shared/helpers/deprecated.rb +37 -0
  61. data/lib/kubes/compiler/strategy/base.rb +1 -0
  62. data/lib/kubes/compiler/strategy/dsl.rb +1 -0
  63. data/lib/kubes/compiler/strategy/erb.rb +2 -0
  64. data/lib/kubes/config.rb +1 -1
  65. data/lib/kubes/core.rb +6 -0
  66. data/lib/kubes/docker/strategy/image_name.rb +1 -1
  67. data/lib/kubes/kubectl.rb +5 -23
  68. data/lib/kubes/kubectl/batch.rb +27 -33
  69. data/lib/kubes/kubectl/ordering.rb +42 -0
  70. data/lib/kubes/version.rb +1 -1
  71. data/lib/templates/base/.kubes/config.rb.tt +1 -1
  72. data/lib/templates/base/.kubes/config/env/dev.rb +1 -1
  73. data/lib/templates/base/.kubes/config/env/prod.rb +1 -1
  74. data/lib/templates/dsl/.kubes/resources/web/deployment.rb +1 -1
  75. data/lib/templates/new/dsl/backend_config.rb +10 -0
  76. data/lib/templates/new/dsl/config_map.rb +5 -0
  77. data/lib/templates/new/dsl/daemon_set.rb +11 -0
  78. data/lib/templates/new/dsl/deployment.rb +4 -0
  79. data/lib/templates/new/dsl/ingress.rb +3 -0
  80. data/lib/templates/new/dsl/job.rb +2 -0
  81. data/lib/templates/new/dsl/managed_certificate.rb +2 -0
  82. data/lib/templates/new/dsl/namespace.rb +2 -0
  83. data/lib/templates/new/dsl/network_policy.rb +7 -0
  84. data/lib/templates/new/dsl/pod.rb +6 -0
  85. data/lib/templates/new/dsl/role.rb +4 -0
  86. data/lib/templates/new/dsl/role_binding.rb +7 -0
  87. data/lib/templates/new/dsl/secret.rb +5 -0
  88. data/lib/templates/new/dsl/service.rb +2 -0
  89. data/lib/templates/new/dsl/service_account.rb +1 -0
  90. data/lib/templates/new/yaml/backend_config.yaml +10 -0
  91. data/lib/templates/new/yaml/config_map.yaml +9 -0
  92. data/lib/templates/new/yaml/daemon_set.yaml +11 -0
  93. data/lib/templates/new/yaml/deployment.yaml +19 -0
  94. data/lib/templates/new/yaml/ingress.yaml +12 -0
  95. data/lib/templates/new/yaml/job.yaml +19 -0
  96. data/lib/templates/new/yaml/managed_certificate.yaml +7 -0
  97. data/lib/templates/new/yaml/namespace.yaml +6 -0
  98. data/lib/templates/new/yaml/network_policy.yaml +20 -0
  99. data/lib/templates/new/yaml/pod.yaml +11 -0
  100. data/lib/templates/new/yaml/role.yaml +13 -0
  101. data/lib/templates/new/yaml/role_binding.yaml +11 -0
  102. data/lib/templates/new/yaml/secret.yaml +9 -0
  103. data/lib/templates/new/yaml/service.yaml +14 -0
  104. data/lib/templates/new/yaml/service_account.yaml +4 -0
  105. data/lib/templates/yaml/.kubes/resources/base/all.yaml.tt +2 -0
  106. data/lib/templates/yaml/.kubes/resources/web/deployment.yaml.tt +1 -1
  107. data/spec/kubes/cli/prune_spec.rb +1 -0
  108. data/spec/kubes/compiler_spec.rb +5 -1
  109. metadata +65 -2
@@ -0,0 +1,17 @@
1
+ module Kubes::Compiler::Shared
2
+ module CustomHelpers
3
+ # Load custom helper methods from project
4
+ @@custom_helpers_loaded = false
5
+ def load_custom_helpers
6
+ return if @@custom_helpers_loaded
7
+ paths = Dir.glob("#{Kubes.root}/.kubes/helpers/**/*.rb")
8
+ paths.sort_by! { |p| p.size } # so namespaces are loaded first
9
+ paths.each do |path|
10
+ filename = path.sub(%r{.*.kubes/helpers/},'').sub('.rb','')
11
+ module_name = filename.camelize
12
+ self.class.send :include, module_name.constantize
13
+ end
14
+ @@custom_helpers_loaded = true
15
+ end
16
+ end
17
+ end
@@ -5,12 +5,21 @@ module Kubes::Compiler::Shared
5
5
  extend Kubes::Compiler::Dsl::Core::Fields
6
6
  fields "name"
7
7
 
8
- def built_image
8
+ def docker_image
9
9
  return @options[:image] if @options[:image] # override
10
+ return Kubes.config.image if Kubes.config.image
11
+ built_image_helper
12
+ end
13
+
14
+ def built_image
15
+ Deprecated.new.built_image
16
+ built_image_helper
17
+ end
10
18
 
19
+ def built_image_helper
11
20
  path = Kubes.config.state.docker_image_path
12
21
  unless File.exist?(path)
13
- raise "Missing file with docker image built by kubes: #{path}. Try first running: kubes docker build"
22
+ raise Kubes::MissingDockerImage.new("Missing file with docker image built by kubes: #{path}. Try first running: kubes docker build")
14
23
  end
15
24
  IO.read(path)
16
25
  end
@@ -25,7 +34,7 @@ module Kubes::Compiler::Shared
25
34
  end
26
35
 
27
36
  def encode64(v)
28
- Base64.strict_encode64(v).strip
37
+ Base64.strict_encode64(v.to_s).strip
29
38
  end
30
39
  alias_method :base64, :encode64
31
40
 
@@ -0,0 +1,37 @@
1
+ module Kubes::Compiler::Shared::Helpers
2
+ class Deprecated
3
+ def built_image
4
+ puts "DEPRECATED: built_image is deprecated, use docker_image helper instead.".color(:yellow)
5
+ print_source
6
+ end
7
+
8
+ def error_info
9
+ error_info = caller.find { |l| l.include?('.kubes/resources') }
10
+ path, line_number, _ = error_info.split(':')
11
+ {path: path, line_number: line_number}
12
+ end
13
+
14
+ def print_source
15
+ info = error_info
16
+ path = info[:path]
17
+ line_number = info[:line_number].to_i
18
+
19
+ pretty_path = path.sub("#{Kubes.root}/",'')
20
+ puts "Here's the line in #{pretty_path} that calls built_image:\n\n"
21
+
22
+ contents = IO.read(path)
23
+ content_lines = contents.split("\n")
24
+ context = 5 # lines of context
25
+ top, bottom = [line_number-context-1, 0].max, line_number+context-1
26
+ lpad = content_lines.size.to_s.size
27
+ content_lines[top..bottom].each_with_index do |line_content, index|
28
+ current_line = top+index+1
29
+ if current_line == line_number
30
+ printf("%#{lpad}d %s\n".color(:red), current_line, line_content)
31
+ else
32
+ printf("%#{lpad}d %s\n", current_line, line_content)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,6 +2,7 @@ class Kubes::Compiler::Strategy
2
2
  class Base
3
3
  include Kubes::Logging
4
4
  include Kubes::Compiler::Util::SaveFile
5
+ include Kubes::Compiler::Shared::CustomHelpers
5
6
 
6
7
  def initialize(options={})
7
8
  @options = options
@@ -3,6 +3,7 @@ class Kubes::Compiler::Strategy
3
3
  include Kubes::Compiler::Util::Normalize
4
4
 
5
5
  def run
6
+ load_custom_helpers
6
7
  dsl = dsl_class.new(@options) # Deployment, Service, etc
7
8
  data = dsl.run
8
9
  Result.new(@save_file, data)
@@ -4,10 +4,12 @@ class Kubes::Compiler::Strategy
4
4
  class Erb < Base
5
5
  extend Kubes::Compiler::Dsl::Core::Fields
6
6
  include Kubes::Compiler::Dsl::Core::Helpers
7
+ include Kubes::Compiler::Shared::CustomHelpers
7
8
  include Kubes::Compiler::Shared::Helpers
8
9
  include Kubes::Compiler::Layering
9
10
 
10
11
  def run
12
+ load_custom_helpers
11
13
  @data = {}
12
14
 
13
15
  render_files(pre_layers)
@@ -32,7 +32,7 @@ module Kubes
32
32
 
33
33
  config.repo = nil # expected to be set by .kubes/config.rb
34
34
 
35
- config.logger = Logger.new($stdout)
35
+ config.logger = Logger.new($stderr)
36
36
  config.logger.level = ENV['KUBES_LOG_LEVEL'] || :info
37
37
 
38
38
  config.skip = []
@@ -28,5 +28,11 @@ module Kubes
28
28
  def kustomize?
29
29
  Kubectl::Kustomize.detect?
30
30
  end
31
+
32
+ def check_project!
33
+ return if File.exist?("#{Kubes.root}/.kubes/config.rb")
34
+ logger.error "ERROR: It doesnt look like this is a kubes project. Are you sure you are in a kubes project?".color(:red)
35
+ ENV['TS_TEST'] ? raise : exit(1)
36
+ end
31
37
  end
32
38
  end
@@ -30,7 +30,7 @@ module Kubes::Docker::Strategy
30
30
  return "tongueroo/demo-kubes:kubes-12345678" if ENV['TEST']
31
31
 
32
32
  unless File.exist?(image_state_path)
33
- puts "Unable to find #{image_state_path} which contains the last docker image name built with kubes build. Please run `kubes docker build` first."
33
+ logger.error "ERROR: Unable to find #{image_state_path} which contains the last docker image name built with kubes build. Please run `kubes docker build` first."
34
34
  exit 1
35
35
  end
36
36
  IO.read(image_state_path).strip
@@ -17,13 +17,11 @@ module Kubes
17
17
  params = args.flatten.join(' ')
18
18
  args = "#{@name} #{params}" # @name: apply or delete
19
19
 
20
- switch_context do
21
- run_hooks("kubectl.rb", name: @name, file: @options[:file]) do
22
- if options[:capture]
23
- self.class.capture(args, options) # already includes kubectl
24
- else
25
- self.class.execute(args, options)
26
- end
20
+ run_hooks("kubectl.rb", name: @name, file: @options[:file]) do
21
+ if options[:capture]
22
+ self.class.capture(args, options) # already includes kubectl
23
+ else
24
+ self.class.execute(args, options)
27
25
  end
28
26
  end
29
27
  end
@@ -44,22 +42,6 @@ module Kubes
44
42
  Kubes.config.kubectl.exit_on_fail[@name]
45
43
  end
46
44
 
47
- def switch_context(&block)
48
- kubectl = Kubes.config.kubectl
49
- context = kubectl.context
50
- if context
51
- previous_context = capture("kubectl config current-context")
52
- sh("kubectl config use-context #{context}", mute: true)
53
- result = block.call
54
- if !previous_context.blank? && !kubectl.context_keep
55
- sh("kubectl config use-context #{previous_context}", mute: true)
56
- end
57
- result
58
- else
59
- block.call
60
- end
61
- end
62
-
63
45
  def args
64
46
  # base at end in case of redirection. IE: command > /path
65
47
  custom.args + default.args
@@ -3,6 +3,7 @@ class Kubes::Kubectl
3
3
  include Kubes::Hooks::Concern
4
4
  include Kubes::Logging
5
5
  include Kubes::Util::Consider
6
+ include Kubes::Util::Sh
6
7
  include Ordering
7
8
 
8
9
  def initialize(name, options={})
@@ -12,48 +13,41 @@ class Kubes::Kubectl
12
13
  def run
13
14
  # @options[:preview] is really only used for kubectl delete
14
15
  logger.info "Will run:" if @options[:preview]
15
- run_hooks("kubes.rb", name: @name) do
16
- sorted_files.each do |file|
17
- if @options[:preview]
18
- logger.info " kubectl #{@name} -f #{file}"
19
- else
20
- Kubes::Kubectl.run(@name, @options.merge(file: file))
16
+ switch_context do
17
+ run_hooks("kubes.rb", name: @name) do
18
+ sorted_files.each do |file|
19
+ if @options[:preview]
20
+ logger.info " kubectl #{@name} -f #{file}"
21
+ else
22
+ Kubes::Kubectl.run(@name, @options.merge(file: file))
23
+ end
21
24
  end
22
25
  end
23
26
  end
24
27
  end
25
28
 
26
- # kubes apply # {role: nil, resource: nil}
27
- # kubes apply clock # {role: "clock", resource: nil}
28
- # kubes apply clock deployment # {role: "clock", resource: "deployment"}
29
- def search_expr
30
- role, resource = @options[:role], @options[:resource]
31
- if role && resource
32
- "#{Kubes.root}/.kubes/output/#{role}/#{resource}.yaml"
33
- elsif role
34
- "#{Kubes.root}/.kubes/output/#{role}/*.yaml"
35
- else
36
- "#{Kubes.root}/.kubes/output/**/*.yaml"
37
- end
38
- end
29
+ def switch_context(&block)
30
+ kubectl = Kubes.config.kubectl
31
+ context = kubectl.context
39
32
 
40
- def files
41
- files = []
42
- Dir.glob(search_expr).each do |path|
43
- next unless process?(path)
44
- file = path.sub("#{Kubes.root}/", '')
45
- files << file
33
+ unless context
34
+ block.call
35
+ return
46
36
  end
47
- files
48
- end
49
37
 
50
- def process?(path)
51
- consider?(path) && two_levels_deep?(path)
52
- end
38
+ previous_context = sh_capture("kubectl config current-context")
39
+ if previous_context == context
40
+ block.call
41
+ return
42
+ end
53
43
 
54
- def two_levels_deep?(path)
55
- rel_path = path.sub(%r{.*\.kubes/output/},'')
56
- rel_path.split('/').size == 2
44
+ logger.debug "Switching kubectl context to: #{context}"
45
+ sh("kubectl config use-context #{context}", mute: true)
46
+ result = block.call
47
+ if !previous_context.blank? && !kubectl.context_keep
48
+ sh("kubectl config use-context #{previous_context}", mute: true)
49
+ end
50
+ result
57
51
  end
58
52
  end
59
53
  end
@@ -35,5 +35,47 @@ class Kubes::Kubectl
35
35
  i = index.to_s.rjust(3, "0") # pad with 0
36
36
  "#{i}-#{value}" # append name so that terms with same index get order alphabetically
37
37
  end
38
+
39
+ # kubes apply # {role: nil, resource: nil}
40
+ # kubes apply clock # {role: "clock", resource: nil}
41
+ # kubes apply clock deployment # {role: "clock", resource: "deployment"}
42
+ def search_expr
43
+ role, resource = @options[:role], @options[:resource]
44
+ if role && resource
45
+ "#{Kubes.root}/.kubes/output/#{role}/#{resource}.yaml"
46
+ elsif role
47
+ "#{Kubes.root}/.kubes/output/#{role}/*.yaml"
48
+ else
49
+ "#{Kubes.root}/.kubes/output/**/*.yaml"
50
+ end
51
+ end
52
+
53
+ def files
54
+ files = []
55
+ Dir.glob(search_expr).each do |path|
56
+ next unless process?(path)
57
+ file = path.sub("#{Kubes.root}/", '')
58
+ files << file
59
+ end
60
+ files
61
+ end
62
+
63
+ # Only considering files 2 layers deep. So:
64
+ #
65
+ # Yes = web/deployment.yaml
66
+ # No = web/deployment/dev.yaml
67
+ #
68
+ def process?(path)
69
+ if Kubes.kustomize?
70
+ File.file?(path)
71
+ else
72
+ consider?(path) && two_levels_deep?(path)
73
+ end
74
+ end
75
+
76
+ def two_levels_deep?(path)
77
+ rel_path = path.sub(%r{.*\.kubes/(resources|output)/},'')
78
+ rel_path.split('/').size == 2
79
+ end
38
80
  end
39
81
  end
@@ -1,3 +1,3 @@
1
1
  module Kubes
2
- VERSION = "0.4.4"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -2,7 +2,7 @@ Kubes.configure do |config|
2
2
  config.repo = "<%= @options[:repo] %>"
3
3
  config.logger.level = "info"
4
4
  # auto-switching
5
- # config.kubectl.context = "dev-services"
5
+ # config.kubectl.context = "dev-cluster"
6
6
  # config.kubectl.context_keep = true # keep context after switching
7
7
  # config.kubectl.exit_on_fail_for_apply = true # whether or not continue if the kubectl command fails
8
8
  # config.kubectl.exit_on_fail_for_delete = false # whether or not continue if the kubectl command fails
@@ -2,5 +2,5 @@
2
2
  #
3
3
  # Example:
4
4
  # Kubes.configure do |config|
5
- # config.kubectl.context = "dev-services"
5
+ # config.kubectl.context = "dev-cluster"
6
6
  # end
@@ -2,5 +2,5 @@
2
2
  #
3
3
  # Example:
4
4
  # Kubes.configure do |config|
5
- # config.kubectl.context = "prod-services"
5
+ # config.kubectl.context = "prod-cluster"
6
6
  # end
@@ -2,7 +2,7 @@ name "web"
2
2
  labels(role: "web")
3
3
 
4
4
  replicas 1 # overridden on a env basis
5
- image built_image # IE: user/<%= app %>:kubes-2020-06-13T19-55-16-43afc6e
5
+ image docker_image # IE: user/<%= app %>:kubes-2020-06-13T19-55-16-43afc6e
6
6
 
7
7
  # revisionHistoryLimit 1 # uncomment to reduce old ReplicaSets, default is 10 https://bit.ly/3hqrzyP
8
8
  # maxUnavailable 25
@@ -0,0 +1,10 @@
1
+ name "<%= app %>"
2
+ spec(
3
+ timeoutSec: 40,
4
+ connectionDraining: {
5
+ drainingTimeoutSec: 60,
6
+ },
7
+ sessionAffinity: {
8
+ affinityType: "CLIENT_IP",
9
+ }
10
+ )
@@ -0,0 +1,5 @@
1
+ name "<%= app %>"
2
+ data(
3
+ KEY1: "value1",
4
+ KEY2: "value2",
5
+ )
@@ -0,0 +1,11 @@
1
+ name "<%= app %>"
2
+ labels("app": "<%= app %>")
3
+ updateStrategy(
4
+ type: "RollingUpdate",
5
+ rollingUpdate: {
6
+ maxUnavailable: 1
7
+ }
8
+ )
9
+ # annotations(
10
+ # "*scheduler**.alpha.kubernetes.io/critical-pod": '*'
11
+ # )
@@ -0,0 +1,4 @@
1
+ name "<%= role %>"
2
+ labels(role: "<%= role %>")
3
+ replicas 2
4
+ image "<%%= docker_image %>"
@@ -0,0 +1,3 @@
1
+ name "<%= app %>"
2
+ serviceName "<%= app %>"
3
+ servicePort 80
@@ -0,0 +1,2 @@
1
+ name "<%= app %>"
2
+ image(docker_image)
@@ -0,0 +1,2 @@
1
+ name "cert1"
2
+ domains(["cert1.example.com"])
@@ -0,0 +1,2 @@
1
+ name "<%= app %>"
2
+ labels(app: "<%= app %>") # useful with NetworkPolicy
@@ -0,0 +1,7 @@
1
+ name "web"
2
+ labels(app: "<%= app %>") # IE: backend
3
+ namespace "<%= app %>" # IE: backend
4
+
5
+ matchLabels(app: "<%= app %>", role: "<%= role %>") # IE: app: backend
6
+ fromNamespace(app: "<%= app %>") # IE: app: frontend
7
+ fromPod(app: "<%= app %>") # IE: backend
@@ -0,0 +1,6 @@
1
+ name "<%= app %>"
2
+ containers([
3
+ image: docker_image,
4
+ command: ["sleep", "3600"],
5
+ name: "<%= app %>",
6
+ ])
@@ -0,0 +1,4 @@
1
+ name "<%= app %>"
2
+ apiGroups([""])
3
+ resources(["pods"])
4
+ verbs(["get", "watch", "list"])
@@ -0,0 +1,7 @@
1
+ name "<%= app %>"
2
+
3
+ subjects([
4
+ {kind: "User", name: "me@email.com"},
5
+ ])
6
+
7
+ roleName "<%= app %>"