kubes 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/docs/_docs/config/reference.md +1 -0
  4. data/docs/_docs/config/skip.md +1 -1
  5. data/docs/_docs/dsl/multiple-resources.md +3 -3
  6. data/docs/_docs/dsl/resources/job.md +62 -0
  7. data/docs/_docs/extra-env/dsl.md +2 -2
  8. data/docs/_docs/extra-env/yaml.md +1 -1
  9. data/docs/_docs/generators.md +41 -0
  10. data/docs/_docs/helpers.md +10 -3
  11. data/docs/_docs/helpers/aws.md +15 -0
  12. data/docs/_docs/helpers/aws/iam-role.md +91 -0
  13. data/docs/_docs/helpers/aws/secrets.md +129 -0
  14. data/docs/_docs/helpers/aws/ssm.md +76 -0
  15. data/docs/_docs/helpers/custom.md +40 -0
  16. data/docs/_docs/helpers/google.md +17 -0
  17. data/docs/_docs/helpers/google/secrets.md +76 -0
  18. data/docs/_docs/helpers/google/service-account.md +60 -0
  19. data/docs/_docs/intro.md +3 -1
  20. data/docs/_docs/intro/docker-image.md +66 -0
  21. data/docs/_docs/layering/merge.md +1 -1
  22. data/docs/_docs/learn/dsl/delete.md +10 -2
  23. data/docs/_docs/learn/dsl/review-project.md +2 -2
  24. data/docs/_docs/learn/yaml/delete.md +10 -2
  25. data/docs/_docs/learn/yaml/review-project.md +2 -2
  26. data/docs/_docs/patterns/clock-web-worker.md +3 -3
  27. data/docs/_docs/patterns/migrations.md +1 -1
  28. data/docs/_docs/patterns/secrets.md +0 -2
  29. data/docs/_docs/yaml.md +2 -2
  30. data/docs/_includes/commands.html +2 -2
  31. data/docs/_includes/helpers/base64.md +1 -0
  32. data/docs/_includes/layering/layers.md +1 -1
  33. data/docs/_includes/sidebar.html +23 -1
  34. data/docs/_reference/kubes-delete.md +1 -1
  35. data/docs/_reference/kubes-exec.md +17 -1
  36. data/docs/_reference/kubes-init.md +2 -2
  37. data/docs/_reference/kubes-logs.md +2 -1
  38. data/docs/_reference/kubes-new.md +58 -0
  39. data/docs/_reference/kubes-prune.md +22 -0
  40. data/docs/reference.md +2 -0
  41. data/kubes.gemspec +1 -0
  42. data/lib/kubes.rb +3 -1
  43. data/lib/kubes/autoloader.rb +9 -0
  44. data/lib/kubes/cli.rb +9 -1
  45. data/lib/kubes/cli/build.rb +6 -0
  46. data/lib/kubes/cli/compile.rb +7 -0
  47. data/lib/kubes/cli/deploy.rb +1 -6
  48. data/lib/kubes/cli/exec.rb +5 -1
  49. data/lib/kubes/cli/help/exec.md +15 -0
  50. data/lib/kubes/cli/help/new.md +30 -0
  51. data/lib/kubes/cli/init.rb +1 -1
  52. data/lib/kubes/cli/new.rb +97 -0
  53. data/lib/kubes/cli/sequence.rb +1 -0
  54. data/lib/kubes/command.rb +7 -0
  55. data/lib/kubes/compiler.rb +19 -21
  56. data/lib/kubes/compiler/dsl/syntax/job.rb +217 -0
  57. data/lib/kubes/compiler/shared/custom_helpers.rb +17 -0
  58. data/lib/kubes/compiler/shared/helpers.rb +12 -3
  59. data/lib/kubes/compiler/shared/helpers/deprecated.rb +37 -0
  60. data/lib/kubes/compiler/strategy/base.rb +3 -3
  61. data/lib/kubes/compiler/strategy/dsl.rb +3 -2
  62. data/lib/kubes/compiler/strategy/erb.rb +10 -1
  63. data/lib/kubes/compiler/strategy/erb/yaml_error.rb +60 -0
  64. data/lib/kubes/compiler/util/normalize.rb +1 -1
  65. data/lib/kubes/compiler/util/save_file.rb +8 -0
  66. data/lib/kubes/config.rb +1 -1
  67. data/lib/kubes/core.rb +6 -0
  68. data/lib/kubes/docker/strategy/image_name.rb +1 -1
  69. data/lib/kubes/kubectl.rb +5 -23
  70. data/lib/kubes/kubectl/batch.rb +27 -33
  71. data/lib/kubes/kubectl/ordering.rb +42 -0
  72. data/lib/kubes/version.rb +1 -1
  73. data/lib/templates/base/.kubes/config.rb.tt +1 -1
  74. data/lib/templates/base/.kubes/config/env/dev.rb +1 -1
  75. data/lib/templates/base/.kubes/config/env/prod.rb +1 -1
  76. data/lib/templates/dsl/.kubes/resources/web/deployment.rb +1 -1
  77. data/lib/templates/new/dsl/backend_config.rb +10 -0
  78. data/lib/templates/new/dsl/config_map.rb +5 -0
  79. data/lib/templates/new/dsl/daemon_set.rb +11 -0
  80. data/lib/templates/new/dsl/deployment.rb +4 -0
  81. data/lib/templates/new/dsl/ingress.rb +3 -0
  82. data/lib/templates/new/dsl/job.rb +2 -0
  83. data/lib/templates/new/dsl/managed_certificate.rb +2 -0
  84. data/lib/templates/new/dsl/namespace.rb +2 -0
  85. data/lib/templates/new/dsl/network_policy.rb +7 -0
  86. data/lib/templates/new/dsl/pod.rb +6 -0
  87. data/lib/templates/new/dsl/role.rb +4 -0
  88. data/lib/templates/new/dsl/role_binding.rb +7 -0
  89. data/lib/templates/new/dsl/secret.rb +5 -0
  90. data/lib/templates/new/dsl/service.rb +2 -0
  91. data/lib/templates/new/dsl/service_account.rb +1 -0
  92. data/lib/templates/new/yaml/backend_config.yaml +10 -0
  93. data/lib/templates/new/yaml/config_map.yaml +9 -0
  94. data/lib/templates/new/yaml/daemon_set.yaml +11 -0
  95. data/lib/templates/new/yaml/deployment.yaml +20 -0
  96. data/lib/templates/new/yaml/ingress.yaml +12 -0
  97. data/lib/templates/new/yaml/job.yaml +19 -0
  98. data/lib/templates/new/yaml/managed_certificate.yaml +7 -0
  99. data/lib/templates/new/yaml/namespace.yaml +6 -0
  100. data/lib/templates/new/yaml/network_policy.yaml +20 -0
  101. data/lib/templates/new/yaml/pod.yaml +11 -0
  102. data/lib/templates/new/yaml/role.yaml +13 -0
  103. data/lib/templates/new/yaml/role_binding.yaml +11 -0
  104. data/lib/templates/new/yaml/secret.yaml +9 -0
  105. data/lib/templates/new/yaml/service.yaml +14 -0
  106. data/lib/templates/new/yaml/service_account.yaml +4 -0
  107. data/lib/templates/yaml/.kubes/resources/base/all.yaml.tt +2 -0
  108. data/lib/templates/yaml/.kubes/resources/web/deployment.yaml.tt +1 -1
  109. data/spec/kubes/cli/prune_spec.rb +1 -0
  110. data/spec/kubes/compiler_spec.rb +5 -1
  111. metadata +67 -2
@@ -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
@@ -1,13 +1,13 @@
1
1
  class Kubes::Compiler::Strategy
2
2
  class Base
3
3
  include Kubes::Logging
4
+ include Kubes::Compiler::Util::SaveFile
5
+ include Kubes::Compiler::Shared::CustomHelpers
4
6
 
5
7
  def initialize(options={})
6
8
  @options = options
7
9
  @path = options[:path]
8
-
9
- @filename = @path.sub(%r{.*\.kubes/resources/},'') # IE: web/deployment.rb or web/deployment.yaml
10
- @save_file = @filename.sub('.yml','.yaml').sub('.rb','.yaml')
10
+ @save_file = save_file(@path)
11
11
  end
12
12
  end
13
13
  end
@@ -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)
@@ -17,7 +18,7 @@ class Kubes::Compiler::Strategy
17
18
  end
18
19
 
19
20
  def syntax_class
20
- klass_name = normalize_kind(@filename)
21
+ klass_name = normalize_kind(@save_file)
21
22
  "Kubes::Compiler::Dsl::Syntax::#{klass_name}".constantize
22
23
  rescue NameError
23
24
  logger.debug "Using default resource for: #{klass_name}"
@@ -25,7 +26,7 @@ class Kubes::Compiler::Strategy
25
26
  end
26
27
 
27
28
  def block_form?
28
- type = extract_type(@filename)
29
+ type = extract_type(@save_file)
29
30
  type.pluralize == type
30
31
  end
31
32
  end
@@ -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,11 +34,18 @@ class Kubes::Compiler::Strategy
32
34
  def render_result(path)
33
35
  if File.exist?(path)
34
36
  yaml = RenderMePretty.result(path, context: self)
35
- result = YAML.load(yaml)
37
+ result = yaml_load(path, yaml)
36
38
  result.is_a?(Hash) ? result : {} # in case of blank yaml doc a Boolean false is returned
37
39
  else
38
40
  {}
39
41
  end
40
42
  end
43
+
44
+ def yaml_load(path, yaml)
45
+ YAML.load(yaml)
46
+ rescue Psych::SyntaxError
47
+ YamlError.new(path, yaml).show
48
+ exit 1
49
+ end
41
50
  end
42
51
  end
@@ -0,0 +1,60 @@
1
+ class Kubes::Compiler::Strategy::Erb
2
+ class YamlError
3
+ include Kubes::Compiler::Util::SaveFile
4
+
5
+ def initialize(path, rendered_yaml)
6
+ @path, @rendered_yaml = path, rendered_yaml
7
+ end
8
+
9
+ def show
10
+ FileUtils.mkdir_p(File.dirname(dest))
11
+ IO.write(dest, @rendered_yaml)
12
+ show_error(dest)
13
+ end
14
+
15
+ def dest
16
+ save_file = save_file(@path)
17
+ "#{Kubes.root}/.kubes/output/#{save_file}"
18
+ end
19
+
20
+ def show_error(path)
21
+ text = IO.read(path)
22
+ begin
23
+ YAML.load(text)
24
+ rescue Psych::SyntaxError => e
25
+ handle_yaml_syntax_error(e, path)
26
+ end
27
+ end
28
+
29
+ def handle_yaml_syntax_error(e, path)
30
+ io = StringIO.new
31
+ io.puts "Invalid yaml. Output written for debugging: #{path}".color(:red)
32
+ io.puts "ERROR: #{e.message}".color(:red)
33
+
34
+ # Grab line info. Example error:
35
+ # ERROR: (<unknown>): could not find expected ':' while scanning a simple key at line 2 column 1
36
+ md = e.message.match(/at line (\d+) column (\d+)/)
37
+ line = md[1].to_i
38
+
39
+ lines = IO.read(path).split("\n")
40
+ context = 5 # lines of context
41
+ top, bottom = [line-context-1, 0].max, line+context-1
42
+ spacing = lines.size.to_s.size
43
+ lines[top..bottom].each_with_index do |line_content, index|
44
+ line_number = top+index+1
45
+ if line_number == line
46
+ io.printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
47
+ else
48
+ io.printf("%#{spacing}d %s\n", line_number, line_content)
49
+ end
50
+ end
51
+
52
+ if ENV['KUBES_TEST']
53
+ io.string
54
+ else
55
+ puts io.string
56
+ exit 1
57
+ end
58
+ end
59
+ end
60
+ end
@@ -5,7 +5,7 @@ module Kubes::Compiler::Util
5
5
  end
6
6
 
7
7
  def extract_type(path)
8
- File.basename(path).sub('.rb','').sub(/-.*/,'')
8
+ File.basename(path).sub('.yaml','').sub('.yml','').sub('.rb','').sub(/-.*/,'')
9
9
  end
10
10
  end
11
11
  end
@@ -0,0 +1,8 @@
1
+ module Kubes::Compiler::Util
2
+ module SaveFile
3
+ def save_file(path)
4
+ filename = path.sub(%r{.*\.kubes/resources/},'') # IE: web/deployment.rb or web/deployment.yaml
5
+ filename.sub('.yml','.yaml').sub('.rb','.yaml')
6
+ end
7
+ end
8
+ end
@@ -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.3"
2
+ VERSION = "0.5.0"
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
+ )