kubes 0.4.4 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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 %>"