kerbi 0.0.1 → 0.0.5

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cli/base_handler.rb +194 -0
  3. data/lib/cli/base_serializer.rb +120 -0
  4. data/lib/cli/config_handler.rb +51 -0
  5. data/lib/cli/entry_serializers.rb +99 -0
  6. data/lib/cli/project_handler.rb +2 -2
  7. data/lib/cli/release_handler.rb +41 -0
  8. data/lib/cli/release_serializer.rb +46 -0
  9. data/lib/cli/root_handler.rb +34 -13
  10. data/lib/cli/state_handler.rb +88 -0
  11. data/lib/cli/values_handler.rb +4 -3
  12. data/{boilerplate → lib/code-gen/new-project}/Gemfile.erb +0 -0
  13. data/lib/code-gen/new-project/kerbifile.rb.erb +9 -0
  14. data/lib/code-gen/new-project/values.yaml.erb +1 -0
  15. data/lib/config/cli_schema.rb +343 -28
  16. data/lib/config/config_file.rb +60 -0
  17. data/lib/config/globals.rb +4 -0
  18. data/lib/config/run_opts.rb +162 -0
  19. data/lib/config/state_consts.rb +11 -0
  20. data/lib/kerbi.rb +35 -10
  21. data/lib/main/code_gen.rb +1 -1
  22. data/lib/main/errors.rb +115 -0
  23. data/lib/main/mixer.rb +20 -10
  24. data/lib/mixins/cli_state_helpers.rb +108 -0
  25. data/lib/mixins/cm_backend_testing.rb +109 -0
  26. data/lib/mixins/entry_tag_logic.rb +183 -0
  27. data/lib/state/base_backend.rb +93 -0
  28. data/lib/state/config_map_backend.rb +173 -0
  29. data/lib/state/entry.rb +173 -0
  30. data/lib/state/entry_set.rb +137 -0
  31. data/lib/state/metadata.yaml.erb +11 -0
  32. data/lib/state/mixers.rb +23 -0
  33. data/lib/state/resources.yaml.erb +17 -0
  34. data/lib/utils/cli.rb +108 -9
  35. data/lib/utils/helm.rb +10 -12
  36. data/lib/utils/k8s_auth.rb +87 -0
  37. data/lib/utils/misc.rb +36 -1
  38. data/lib/utils/mixing.rb +1 -1
  39. data/lib/utils/values.rb +13 -22
  40. data/spec/cli/config_handler_spec.rb +38 -0
  41. data/spec/cli/release_handler_spec.rb +127 -0
  42. data/spec/cli/root_handler_spec.rb +100 -0
  43. data/spec/cli/state_handler_spec.rb +108 -0
  44. data/spec/cli/values_handler_spec.rb +17 -0
  45. data/spec/fixtures/expectations/common/bad-tag.txt +1 -0
  46. data/spec/fixtures/expectations/config/bad-set.txt +1 -0
  47. data/spec/fixtures/expectations/config/set.txt +1 -0
  48. data/spec/fixtures/expectations/config/show-default.yaml +6 -0
  49. data/spec/fixtures/expectations/release/delete.txt +1 -0
  50. data/spec/fixtures/expectations/release/init-already-existed.txt +2 -0
  51. data/spec/fixtures/expectations/release/init-both-created.txt +2 -0
  52. data/spec/fixtures/expectations/release/list.txt +5 -0
  53. data/spec/fixtures/expectations/release/status-all-working.txt +5 -0
  54. data/spec/fixtures/expectations/release/status-data-unreadable.txt +5 -0
  55. data/spec/fixtures/expectations/release/status-not-provisioned.txt +5 -0
  56. data/spec/fixtures/expectations/root/template-inlines.yaml +31 -0
  57. data/spec/fixtures/expectations/root/template-production.yaml +31 -0
  58. data/spec/fixtures/expectations/root/template-read-inlines.yaml +31 -0
  59. data/spec/fixtures/expectations/root/template-read.yaml +31 -0
  60. data/spec/fixtures/expectations/root/template-write.yaml +31 -0
  61. data/spec/fixtures/expectations/root/template.yaml +31 -0
  62. data/spec/fixtures/expectations/root/values.json +28 -0
  63. data/spec/fixtures/expectations/state/delete.txt +1 -0
  64. data/spec/fixtures/expectations/state/demote.txt +1 -0
  65. data/spec/fixtures/expectations/state/list.json +51 -0
  66. data/spec/fixtures/expectations/state/list.txt +6 -0
  67. data/spec/fixtures/expectations/state/list.yaml +35 -0
  68. data/spec/fixtures/expectations/state/promote.txt +1 -0
  69. data/spec/fixtures/expectations/state/prune-candidates.txt +1 -0
  70. data/spec/fixtures/expectations/state/retag.txt +1 -0
  71. data/spec/fixtures/expectations/state/set.txt +1 -0
  72. data/spec/fixtures/expectations/state/show.json +13 -0
  73. data/spec/fixtures/expectations/state/show.txt +13 -0
  74. data/spec/fixtures/expectations/state/show.yaml +8 -0
  75. data/spec/fixtures/expectations/values/order-of-precedence.yaml +4 -0
  76. data/spec/main/configmap_backend_spec.rb +110 -0
  77. data/spec/main/project_code_gen_spec.rb +8 -2
  78. data/spec/main/state_entry_set_spec.rb +112 -0
  79. data/spec/main/state_entry_spec.rb +109 -0
  80. data/spec/mini-projects/hello-kerbi/common/metadata.yaml.erb +5 -0
  81. data/spec/mini-projects/hello-kerbi/consts.rb +5 -0
  82. data/spec/mini-projects/hello-kerbi/helpers.rb +8 -0
  83. data/spec/mini-projects/hello-kerbi/kerbifile.rb +18 -0
  84. data/spec/mini-projects/hello-kerbi/pod-and-service.yaml.erb +23 -0
  85. data/spec/mini-projects/hello-kerbi/values/production.yaml +2 -0
  86. data/spec/mini-projects/hello-kerbi/values/v2.yaml +2 -0
  87. data/spec/mini-projects/hello-kerbi/values/values.yaml +4 -0
  88. data/spec/spec_helper.rb +143 -1
  89. data/spec/utils/helm_spec.rb +89 -109
  90. data/spec/utils/k8s_auth_spec.rb +32 -0
  91. data/spec/utils/misc_utils_spec.rb +9 -0
  92. data/spec/utils/values_utils_spec.rb +12 -19
  93. metadata +143 -16
  94. data/boilerplate/kerbifile.rb.erb +0 -9
  95. data/boilerplate/values.yaml.erb +0 -1
  96. data/lib/cli/base.rb +0 -83
  97. data/lib/config/cli_opts.rb +0 -50
  98. data/lib/config/manager.rb +0 -36
  99. data/lib/main/state_manager.rb +0 -47
  100. data/lib/utils/kubectl.rb +0 -58
  101. data/spec/main/examples_spec.rb +0 -12
  102. data/spec/main/state_manager_spec.rb +0 -84
  103. data/spec/utils/state_utils.rb +0 -15
@@ -0,0 +1,162 @@
1
+ module Kerbi
2
+
3
+ ##
4
+ # Convenience accessor struct for getting values from
5
+ # the CLI args.
6
+ #noinspection RubyTooManyMethodsInspection
7
+ class RunOpts
8
+
9
+ attr_reader :options
10
+ attr_accessor :release_name
11
+
12
+ # @param [Hash{Symbol, Object}] cli_opts CLI args as a hash via Thor
13
+ # @param [Hash{Symbol, Object}] defaults contextual defaults (per cmd)
14
+ # @return [Kerbi::RunOpts]
15
+ def initialize(cli_opts, defaults)
16
+ @options = defaults.deep_dup.
17
+ merge(Kerbi::ConfigFile.read.deep_dup).
18
+ merge(cli_opts.deep_dup).
19
+ freeze
20
+ end
21
+
22
+ # @return [String]
23
+ def output_format
24
+ value = options[consts::OUTPUT_FMT]
25
+ value || default
26
+ end
27
+
28
+ # @return [TrueClass, FalseClass]
29
+ def output_yaml?
30
+ self.output_format == 'yaml'
31
+ end
32
+
33
+ # @return [TrueClass, FalseClass]
34
+ def output_table?
35
+ self.output_format == 'table'
36
+ end
37
+
38
+ # @return [TrueClass, FalseClass]
39
+ def output_json?
40
+ self.output_format == 'json'
41
+ end
42
+
43
+ # @return [String]
44
+ def ruby_version
45
+ options[consts::RUBY_VER]
46
+ end
47
+
48
+ # @return [Array<String>]
49
+ def fname_exprs
50
+ options[consts::VALUE_FNAMES]
51
+ end
52
+
53
+ # @return [Array<String>]
54
+ def inline_val_exprs
55
+ options[consts::INLINE_ASSIGNMENT]
56
+ end
57
+
58
+ # @return [TrueClass, FalseClass]
59
+ def load_defaults?
60
+ options[consts::LOAD_DEFAULT_VALUES].present?
61
+ end
62
+
63
+ # @return [String]
64
+ def read_state_from
65
+ options[consts::READ_STATE].presence
66
+ end
67
+
68
+ # @return [String]
69
+ def write_state_to
70
+ options[consts::WRITE_STATE].presence
71
+ end
72
+
73
+ # @return [TrueClass, FalseClass]
74
+ def verbose?
75
+ options[consts::VERBOSE].present?
76
+ end
77
+
78
+ # @return [TrueClass, FalseClass]
79
+ def reads_state?
80
+ read_state_from.present?
81
+ end
82
+
83
+ # @return [TrueClass, FalseClass]
84
+ def reads_state_strictly?
85
+ options[consts::STRICT_READ_STATE]
86
+ end
87
+
88
+ # @return [TrueClass, FalseClass]
89
+ def writes_state?
90
+ write_state_to.present?
91
+ end
92
+
93
+ # @return [String]
94
+ def k8s_auth_type
95
+ options[consts::K8S_AUTH_TYPE]
96
+ end
97
+
98
+ # @return [String]
99
+ def kube_config_path
100
+ options[consts::KUBE_CONFIG_PATH]
101
+ end
102
+
103
+ # @return [String]
104
+ def kube_context_name
105
+ options[consts::KUBE_CONFIG_CONTEXT]
106
+ end
107
+
108
+ # @return [String]
109
+ def cluster_namespace
110
+ options[consts::NAMESPACE]
111
+ end
112
+
113
+ # @return [String]
114
+ def state_backend_type
115
+ value = options[consts::STATE_BACKEND_TYPE]
116
+ value.is_a?(String) ? value : ''
117
+ end
118
+
119
+ # @return [String]
120
+ def k8s_auth_username
121
+ options[consts::K8S_USERNAME]
122
+ end
123
+
124
+ # @return [String]
125
+ def k8s_auth_password
126
+ options[consts::K8S_PASSWORD]
127
+ end
128
+
129
+ # @return [String]
130
+ def k8s_auth_token
131
+ options[consts::K8S_TOKEN]
132
+ end
133
+
134
+ # @return [String]
135
+ def write_state_msg
136
+ options[consts::WRITE_STATE_MESSAGE]
137
+ end
138
+
139
+ # @return [String]
140
+ def project_root
141
+ options[consts::PROJECT_ROOT].presence
142
+ end
143
+
144
+ # @return [TrueClass, FalseClass]
145
+ def in_cluster?
146
+ options[consts::K8S_AUTH_TYPE] == 'in-cluster'
147
+ end
148
+
149
+ # @return [TrueClass, FalseClass]
150
+ def confirmed?
151
+ options[consts::PRE_CONFIRM].present?
152
+ end
153
+
154
+ private
155
+
156
+ # @return [Module<Kerbi::Consts::OptionKeys>]
157
+ def consts
158
+ Kerbi::Consts::OptionKeys
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,11 @@
1
+ module Kerbi
2
+ module State
3
+ module Consts
4
+ CREATOR_ATTR = :creator
5
+ CREATOR_VAL = "kerbi"
6
+ ENTRIES_ATTR = :entries
7
+ RESOURCE_NAME = "kerbi-db"
8
+ CM_REGEX = /kerbi-(.*)-db/
9
+ end
10
+ end
11
+ end
data/lib/kerbi.rb CHANGED
@@ -3,41 +3,66 @@
3
3
  #
4
4
  require 'erb'
5
5
  require "irb"
6
- require 'open3'
7
- require "http"
8
6
  require 'json'
9
7
  require 'yaml'
8
+ require 'time'
10
9
  require "thor"
10
+ require 'open3'
11
11
  require "base64"
12
12
  require 'optparse'
13
13
  require 'colorize'
14
+ require 'kubeclient'
15
+ require 'spicy-proton'
16
+ require 'terminal-table'
14
17
 
15
- require 'active_support/concern'
16
18
  require 'active_support/inflector'
17
19
  require 'active_support/core_ext/object/deep_dup'
18
20
  require 'active_support/core_ext/hash/keys'
19
21
  require 'active_support/core_ext/hash/deep_merge'
20
22
  require 'active_support/core_ext/object/blank'
21
23
  require 'active_support/core_ext/string/indent.rb'
24
+ require 'active_support/core_ext/string/filters'
25
+ require 'active_support/callbacks'
22
26
 
23
27
  require_relative './utils/misc'
28
+ require_relative './utils/k8s_auth'
29
+ require_relative './state/entry'
30
+ require_relative './cli/base_serializer'
24
31
 
25
32
  require_relative './config/cli_schema'
26
- require_relative './config/manager'
33
+ require_relative './config/state_consts'
34
+ require_relative './config/config_file'
27
35
  require_relative './config/globals'
28
- require_relative './config/cli_opts'
36
+ require_relative './config/run_opts'
29
37
 
30
38
  require_relative './mixins/mixer'
39
+ require_relative './mixins/cm_backend_testing'
40
+ require_relative './utils/cli'
41
+ require_relative './mixins/cli_state_helpers'
31
42
 
32
43
  require_relative './utils/mixing'
33
44
  require_relative './utils/helm'
34
- require_relative './utils/kubectl'
35
- require_relative './utils/cli'
45
+
36
46
  require_relative './utils/values'
37
47
  require_relative './main/code_gen'
38
48
 
39
- require_relative './cli/base'
49
+ require_relative './main/mixer'
50
+
51
+ require_relative './cli/entry_serializers'
52
+ require_relative './cli/release_serializer'
53
+
54
+ require_relative './mixins/entry_tag_logic'
55
+ require_relative './state/entry_set'
56
+
57
+ require_relative './state/base_backend'
58
+ require_relative './state/mixers'
59
+ require_relative './state/config_map_backend'
60
+
61
+ require_relative './main/errors'
62
+ require_relative './cli/base_handler'
63
+ require_relative './cli/config_handler'
40
64
  require_relative './cli/values_handler'
41
65
  require_relative './cli/project_handler'
42
- require_relative './cli/root_handler'
43
- require_relative './main/mixer'
66
+ require_relative './cli/state_handler'
67
+ require_relative './cli/release_handler'
68
+ require_relative './cli/root_handler'
data/lib/main/code_gen.rb CHANGED
@@ -3,7 +3,7 @@ module Kerbi
3
3
  class ProjectGenerator
4
4
 
5
5
  ERB_EXT = ".erb"
6
- BOILER_REL_PATH = "/../../boilerplate"
6
+ BOILER_REL_PATH = "/../code-gen/new-project"
7
7
 
8
8
  ##
9
9
  # Serves as both the new project's dir name and the mixer's _module name
@@ -0,0 +1,115 @@
1
+ module Kerbi
2
+ class Error < ::StandardError
3
+ end
4
+
5
+ class StateBackendNotReadyError < Error
6
+ MSG = "State-keeping backend not ready. Run 'kerbi state status' for more."
7
+
8
+ def initialize(msg = MSG)
9
+ super
10
+ end
11
+ end
12
+
13
+ class IllegalEntryTag < Error
14
+ def initialize(msg = "State entry tag cannot be 'latest'")
15
+ super
16
+ end
17
+ end
18
+
19
+ class IllegalConfigWrite < Error
20
+ LEGAL = Kerbi::Consts::OptionKeys::LEGAL_CONFIG_FILE_KEYS
21
+ def initialize(key)
22
+ super("Illegal config assignment. '#{key}' not in #{LEGAL}")
23
+ end
24
+ end
25
+
26
+ class BadEntryQueryForWrite < Error
27
+ MSG = "write-state needs an existing entry id/tag, 'candidate', or 'latest'"
28
+ def initialize(msg = MSG)
29
+ super
30
+ end
31
+ end
32
+
33
+ class IllegalWriteStateTagWordError < Error
34
+ MSG = "Tag names for writing cannot contain special words exclusive to tag "
35
+ def initialize(msg = MSG)
36
+ super
37
+ end
38
+ end
39
+
40
+ class StateNotFoundError < Error
41
+ def initialize(tag='')
42
+ super("State given by tag #{tag} not found")
43
+ end
44
+ end
45
+
46
+ class StateNotPromotable < Error
47
+ MSG = "Non-candidate states cannot be promoted"
48
+ def initialize(msg = MSG)
49
+ super
50
+ end
51
+ end
52
+
53
+ class StateNotDemotable < Error
54
+ MSG = "Candidate states cannot be demoted"
55
+ def initialize(msg = MSG)
56
+ super
57
+ end
58
+ end
59
+
60
+ class NoSuchStateAttrName < Error
61
+ MSG = "This attribute does not exist or is not writeable"
62
+ def initialize(msg = MSG)
63
+ super(MSG)
64
+ end
65
+ end
66
+
67
+ class ValuesFileNotFoundError < Error
68
+ def initialize(fname_expr: , root: )
69
+ msg = "Could not resolve values file '#{fname_expr}' in #{root}"
70
+ super(msg)
71
+ end
72
+ end
73
+
74
+ class KerbifileNotFoundError < Error
75
+ def initialize(root: )
76
+ msg = "Could not resolve kerbifile in #{root}"
77
+ super(msg)
78
+ end
79
+ end
80
+
81
+ class UnsupportedBackendError < Error
82
+ def initialize(name)
83
+ super("Unsupported state backend type")
84
+ end
85
+ end
86
+
87
+ class EntryValidationError < Error
88
+ MSG = "Cannot write state because of validation errors: "
89
+
90
+ # @param [Hash] errors
91
+ def initialize(errors)
92
+ message = self.class.build_message(errors)
93
+ super(message)
94
+ end
95
+
96
+ # @param [Hash] errors
97
+ def self.error_line(error)
98
+ "#{error[:attr]}['#{error[:value]}']: #{error[:msg]}".indent(1)
99
+ end
100
+
101
+ # @param [String] tag
102
+ # @param [Array<Hash>] errors
103
+ def self.entry_line(tag, error_dicts)
104
+ per_tag_parts = error_dicts.map{ |d| error_line(d) }
105
+ "Entry['#{tag}'] \n #{per_tag_parts.join("\n")}".indent(1)
106
+ end
107
+
108
+ # @param [Hash] errors
109
+ def self.build_message(errors)
110
+ parts = errors.map { |h| entry_line(h[0], h[1]) }
111
+ "#{MSG} \n#{parts.join("\n")}"
112
+ end
113
+ end
114
+
115
+ end
data/lib/main/mixer.rb CHANGED
@@ -12,6 +12,11 @@ module Kerbi
12
12
  # @return [String] symbol-keyed hash
13
13
  attr_reader :release_name
14
14
 
15
+ ##
16
+ # Namespace (defaults to release_name) from CLI options
17
+ # @return [String] symbol-keyed hash
18
+ attr_reader :namespace
19
+
15
20
  ##
16
21
  # Array of res-hashes being aggregated
17
22
  # @return [Array<Hash>] list of hashes
@@ -27,12 +32,13 @@ module Kerbi
27
32
  # @param [Hash] values the values tree that will be accessible to the subclass
28
33
  def initialize(values, opts={})
29
34
  @output = []
30
- @release_name = opts[:release_name] || "default"
35
+ @release_name = opts[:release_name]
36
+ @namespace = opts[:namespace] || @release_name
31
37
  @patch_stack = []
32
38
  @values = self.class.compute_own_values_subtree(
33
39
  values,
34
40
  opts[:overwrite_values_root]
35
- )
41
+ ).freeze
36
42
  end
37
43
 
38
44
  ##
@@ -45,7 +51,7 @@ module Kerbi
45
51
  def run
46
52
  begin
47
53
  self.mix
48
- rescue Exception => e
54
+ rescue Error => e
49
55
  puts "Exception below caused by mixer #{self.class.name}"
50
56
  raise e
51
57
  end
@@ -202,15 +208,19 @@ module Kerbi
202
208
  subtree.freeze
203
209
  end
204
210
 
205
- def resolve_file_name(fname)
211
+ ## Resolves a user-given short name for a file to interpolate,
212
+ # like 'pod', 'pod.yaml', into an absolute file path.
213
+ # @param [String] fname_expr e.g 'pod', 'pod.yaml'
214
+ # @return [?String]
215
+ def resolve_file_name(fname_expr)
206
216
  dir = self.pwd
207
217
  Kerbi::Utils::Misc.real_files_for(
208
- fname,
209
- "#{fname}.yaml",
210
- "#{fname}.yaml.erb",
211
- "#{dir}/#{fname}",
212
- "#{dir}/#{fname}.yaml",
213
- "#{dir}/#{fname}.yaml.erb"
218
+ fname_expr,
219
+ "#{fname_expr}.yaml",
220
+ "#{fname_expr}.yaml.erb",
221
+ "#{dir}/#{fname_expr}",
222
+ "#{dir}/#{fname_expr}.yaml",
223
+ "#{dir}/#{fname_expr}.yaml.erb"
214
224
  ).first
215
225
  end
216
226
 
@@ -0,0 +1,108 @@
1
+ module Kerbi
2
+ module Mixins
3
+ module CliStateHelpers
4
+
5
+ protected
6
+
7
+ ##
8
+ # Convenience method that returns the state backend's entry set.
9
+ # @return [Kerbi::State::EntrySet]
10
+ def entry_set
11
+ state_backend.entry_set
12
+ end
13
+
14
+ ##
15
+ # For commands that need a working state backend,
16
+ # ask the backend if it is operational, and raise otherwise.
17
+ def raise_unless_backend_ready
18
+ unless state_backend.read_write_ready?
19
+ raise Kerbi::StateBackendNotReadyError
20
+ end
21
+ end
22
+
23
+ ##
24
+ # Convenience method for invoking #find_entry_for_read
25
+ # on the state backend's entry-set.
26
+ # @return [Kerbi::State::Entry]
27
+ def find_readable_entry(tag_expr)
28
+ entry_set.find_entry_for_read(tag_expr)
29
+ end
30
+
31
+ ##
32
+ # Convenience method for updating a state entry's created_at
33
+ # and then persisting the new list of entries via the state backend.
34
+ # Also optionally pretty prints changes.
35
+ # @param [Kerbi::State::Entry] entry
36
+ def touch_and_save_entry(entry, changes={})
37
+ entry.created_at = Time.now
38
+ state_backend.save
39
+ if changes && (change = changes.first)
40
+ key, old_value = change
41
+ new_value = entry.send(key) rescue "ERR"
42
+ name = "state[#{entry.tag}].#{key}"
43
+ change_str = "from #{old_value} => #{new_value}"
44
+ echo "Updated #{name} #{change_str}".colorize(:green)
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Given a tag by read-state [TAG], find the corresponding
50
+ # state entry and return its values dict.
51
+ #
52
+ # If the state entry is NOT found, an empty dict is returned,
53
+ # unless the strict-read option is also passed, in which
54
+ # case it raises a fatal exception.
55
+ # @return [Hash{Symbol->String}]
56
+ def read_state_values
57
+ if run_opts.reads_state?
58
+ expr = run_opts.read_state_from
59
+ begin
60
+ entry = entry_set.find_entry_for_read(expr)
61
+ entry.values.deep_dup.deep_symbolize_keys
62
+ rescue Kerbi::StateNotFoundError => e
63
+ raise e if run_opts.reads_state_strictly?
64
+ {}
65
+ end
66
+ else
67
+ {}
68
+ end
69
+ end
70
+
71
+ ##
72
+ # Given a tag by write-state [TAG], find or create a state entry
73
+ # and assign its values and default_values to the respective
74
+ # just values and default_values just compiled.
75
+ def persist_compiled_values
76
+ if run_opts.writes_state?
77
+ raise_unless_backend_ready
78
+ expr = run_opts.write_state_to
79
+ entry = entry_set.find_or_init_entry_for_write(expr)
80
+
81
+ entry.values = compile_values.deep_dup
82
+ entry.default_values = compile_default_values.deep_dup
83
+ entry.created_at = Time.now
84
+
85
+ state_backend.save
86
+ end
87
+ end
88
+
89
+ ##
90
+ # Given the state-backend parameter or config value,
91
+ # generate an instance of the corresponding backend
92
+ # class.
93
+ # @return [Kerbi::State::Backend]
94
+ def generate_state_backend(release_name: nil, namespace: nil)
95
+ if run_opts.state_backend_type.downcase.strip == 'configmap'
96
+ auth_bundle = Kerbi::Utils::Cli.make_k8s_auth_bundle(run_opts)
97
+ Kerbi::State::ConfigMapBackend.new(
98
+ auth_bundle,
99
+ release_name || run_opts.release_name,
100
+ namespace || run_opts.cluster_namespace
101
+ )
102
+ else
103
+ raise Kerbi::UnsupportedBackendError
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,109 @@
1
+ module Kerbi
2
+ module Mixins
3
+ module CmBackendTesting
4
+
5
+ # @return [TrueClass, FalseClass]
6
+ def namespace_exists?
7
+ begin
8
+ !!client("v1").get_namespace(namespace)
9
+ rescue Kubeclient::ResourceNotFoundError
10
+ false
11
+ end
12
+ end
13
+
14
+ def resource_exists?
15
+ begin
16
+ !!resource
17
+ rescue Kubeclient::ResourceNotFoundError
18
+ false
19
+ end
20
+ end
21
+
22
+ def read_write_ready?
23
+ namespace_exists? && \
24
+ resource_exists? && \
25
+ data_readable?
26
+ end
27
+
28
+ def test_connection(options={})
29
+ exceptions = []
30
+
31
+ schema = [
32
+ {
33
+ method: :client,
34
+ message: "1. Create Kubernetes client"
35
+ },
36
+ {
37
+ method: :test_list_namespaces,
38
+ message: "2. List cluster namespaces"
39
+ },
40
+ {
41
+ method: :test_target_ns_exists,
42
+ message: "3. Target namespace #{namespace} exists"
43
+ },
44
+ {
45
+ method: :load_resource,
46
+ message: "4. Resource #{namespace}/cm/#{cm_name} exists"
47
+ },
48
+ {
49
+ method: :entries,
50
+ message: "5. Data from resource is readable"
51
+ }
52
+ ]
53
+
54
+ schema.each do |spec|
55
+ begin
56
+ self.send(spec[:method])
57
+ puts_outcome(spec[:message], true)
58
+ rescue StandardError => e
59
+ puts_outcome(spec[:message], false)
60
+ exceptions << { exception: e, test: spec[:message] }
61
+ end
62
+ end
63
+
64
+ if exceptions.any? && options[:verbose]
65
+ #noinspection RubyResolve
66
+ puts "\n---EXCEPTIONS---\n".colorize(:red).bold
67
+ exceptions.each do |exc|
68
+ base = "[#{exc[:test]}] #{exc[:exception]}"
69
+ #noinspection RubyResolve
70
+ puts base.to_s.colorize(:red).bold
71
+ puts exc[:exception].backtrace
72
+ puts "\n\n"
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_list_namespaces
78
+ #noinspection RubyResolve
79
+ client("v1").get_namespaces.any?
80
+ end
81
+
82
+ def test_target_ns_exists
83
+ client.get_namespace namespace
84
+ end
85
+
86
+ def data_readable?
87
+ entries.is_a?(Array)
88
+ end
89
+
90
+ #noinspection RubyResolve
91
+ def puts_outcome(msg, result)
92
+ outcome_str = result.present? ? "Success" : "Failure"
93
+ color = result.present? ? :green : :red
94
+ outcome_str = outcome_str.colorize(color)
95
+ puts "#{msg}: #{outcome_str}".bold
96
+ end
97
+
98
+ def echo_init(msg, result, options={})
99
+ unless options[:quiet].present?
100
+ outcome_str = result.present? ? "Already existed" : "Created"
101
+ color = result.present? ? :green : :blue
102
+ outcome_str = outcome_str.colorize(color)
103
+ #noinspection RubyResolve
104
+ puts "#{msg}: #{outcome_str}".bold
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end