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.
- checksums.yaml +4 -4
- data/lib/cli/base_handler.rb +194 -0
- data/lib/cli/base_serializer.rb +120 -0
- data/lib/cli/config_handler.rb +51 -0
- data/lib/cli/entry_serializers.rb +99 -0
- data/lib/cli/project_handler.rb +2 -2
- data/lib/cli/release_handler.rb +41 -0
- data/lib/cli/release_serializer.rb +46 -0
- data/lib/cli/root_handler.rb +34 -13
- data/lib/cli/state_handler.rb +88 -0
- data/lib/cli/values_handler.rb +4 -3
- data/{boilerplate → lib/code-gen/new-project}/Gemfile.erb +0 -0
- data/lib/code-gen/new-project/kerbifile.rb.erb +9 -0
- data/lib/code-gen/new-project/values.yaml.erb +1 -0
- data/lib/config/cli_schema.rb +343 -28
- data/lib/config/config_file.rb +60 -0
- data/lib/config/globals.rb +4 -0
- data/lib/config/run_opts.rb +162 -0
- data/lib/config/state_consts.rb +11 -0
- data/lib/kerbi.rb +35 -10
- data/lib/main/code_gen.rb +1 -1
- data/lib/main/errors.rb +115 -0
- data/lib/main/mixer.rb +20 -10
- data/lib/mixins/cli_state_helpers.rb +108 -0
- data/lib/mixins/cm_backend_testing.rb +109 -0
- data/lib/mixins/entry_tag_logic.rb +183 -0
- data/lib/state/base_backend.rb +93 -0
- data/lib/state/config_map_backend.rb +173 -0
- data/lib/state/entry.rb +173 -0
- data/lib/state/entry_set.rb +137 -0
- data/lib/state/metadata.yaml.erb +11 -0
- data/lib/state/mixers.rb +23 -0
- data/lib/state/resources.yaml.erb +17 -0
- data/lib/utils/cli.rb +108 -9
- data/lib/utils/helm.rb +10 -12
- data/lib/utils/k8s_auth.rb +87 -0
- data/lib/utils/misc.rb +36 -1
- data/lib/utils/mixing.rb +1 -1
- data/lib/utils/values.rb +13 -22
- data/spec/cli/config_handler_spec.rb +38 -0
- data/spec/cli/release_handler_spec.rb +127 -0
- data/spec/cli/root_handler_spec.rb +100 -0
- data/spec/cli/state_handler_spec.rb +108 -0
- data/spec/cli/values_handler_spec.rb +17 -0
- data/spec/fixtures/expectations/common/bad-tag.txt +1 -0
- data/spec/fixtures/expectations/config/bad-set.txt +1 -0
- data/spec/fixtures/expectations/config/set.txt +1 -0
- data/spec/fixtures/expectations/config/show-default.yaml +6 -0
- data/spec/fixtures/expectations/release/delete.txt +1 -0
- data/spec/fixtures/expectations/release/init-already-existed.txt +2 -0
- data/spec/fixtures/expectations/release/init-both-created.txt +2 -0
- data/spec/fixtures/expectations/release/list.txt +5 -0
- data/spec/fixtures/expectations/release/status-all-working.txt +5 -0
- data/spec/fixtures/expectations/release/status-data-unreadable.txt +5 -0
- data/spec/fixtures/expectations/release/status-not-provisioned.txt +5 -0
- data/spec/fixtures/expectations/root/template-inlines.yaml +31 -0
- data/spec/fixtures/expectations/root/template-production.yaml +31 -0
- data/spec/fixtures/expectations/root/template-read-inlines.yaml +31 -0
- data/spec/fixtures/expectations/root/template-read.yaml +31 -0
- data/spec/fixtures/expectations/root/template-write.yaml +31 -0
- data/spec/fixtures/expectations/root/template.yaml +31 -0
- data/spec/fixtures/expectations/root/values.json +28 -0
- data/spec/fixtures/expectations/state/delete.txt +1 -0
- data/spec/fixtures/expectations/state/demote.txt +1 -0
- data/spec/fixtures/expectations/state/list.json +51 -0
- data/spec/fixtures/expectations/state/list.txt +6 -0
- data/spec/fixtures/expectations/state/list.yaml +35 -0
- data/spec/fixtures/expectations/state/promote.txt +1 -0
- data/spec/fixtures/expectations/state/prune-candidates.txt +1 -0
- data/spec/fixtures/expectations/state/retag.txt +1 -0
- data/spec/fixtures/expectations/state/set.txt +1 -0
- data/spec/fixtures/expectations/state/show.json +13 -0
- data/spec/fixtures/expectations/state/show.txt +13 -0
- data/spec/fixtures/expectations/state/show.yaml +8 -0
- data/spec/fixtures/expectations/values/order-of-precedence.yaml +4 -0
- data/spec/main/configmap_backend_spec.rb +110 -0
- data/spec/main/project_code_gen_spec.rb +8 -2
- data/spec/main/state_entry_set_spec.rb +112 -0
- data/spec/main/state_entry_spec.rb +109 -0
- data/spec/mini-projects/hello-kerbi/common/metadata.yaml.erb +5 -0
- data/spec/mini-projects/hello-kerbi/consts.rb +5 -0
- data/spec/mini-projects/hello-kerbi/helpers.rb +8 -0
- data/spec/mini-projects/hello-kerbi/kerbifile.rb +18 -0
- data/spec/mini-projects/hello-kerbi/pod-and-service.yaml.erb +23 -0
- data/spec/mini-projects/hello-kerbi/values/production.yaml +2 -0
- data/spec/mini-projects/hello-kerbi/values/v2.yaml +2 -0
- data/spec/mini-projects/hello-kerbi/values/values.yaml +4 -0
- data/spec/spec_helper.rb +143 -1
- data/spec/utils/helm_spec.rb +89 -109
- data/spec/utils/k8s_auth_spec.rb +32 -0
- data/spec/utils/misc_utils_spec.rb +9 -0
- data/spec/utils/values_utils_spec.rb +12 -19
- metadata +143 -16
- data/boilerplate/kerbifile.rb.erb +0 -9
- data/boilerplate/values.yaml.erb +0 -1
- data/lib/cli/base.rb +0 -83
- data/lib/config/cli_opts.rb +0 -50
- data/lib/config/manager.rb +0 -36
- data/lib/main/state_manager.rb +0 -47
- data/lib/utils/kubectl.rb +0 -58
- data/spec/main/examples_spec.rb +0 -12
- data/spec/main/state_manager_spec.rb +0 -84
- 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
|
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/
|
33
|
+
require_relative './config/state_consts'
|
34
|
+
require_relative './config/config_file'
|
27
35
|
require_relative './config/globals'
|
28
|
-
require_relative './config/
|
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
|
-
|
35
|
-
require_relative './utils/cli'
|
45
|
+
|
36
46
|
require_relative './utils/values'
|
37
47
|
require_relative './main/code_gen'
|
38
48
|
|
39
|
-
require_relative './
|
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/
|
43
|
-
require_relative './
|
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
data/lib/main/errors.rb
ADDED
@@ -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]
|
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
|
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
|
-
|
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
|
-
|
209
|
-
"#{
|
210
|
-
"#{
|
211
|
-
"#{dir}/#{
|
212
|
-
"#{dir}/#{
|
213
|
-
"#{dir}/#{
|
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
|