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,88 @@
1
+ module Kerbi
2
+ module Cli
3
+ class StateHandler < BaseHandler
4
+ cmd_meta Kerbi::Consts::CommandSchemas::LIST_STATE
5
+ def list(release_name)
6
+ prep_opts(Kerbi::Consts::OptionDefaults::LIST_STATE)
7
+ mem_release_name(release_name)
8
+ echo_data(
9
+ state_backend.entries,
10
+ table_serializer: Kerbi::Cli::EntryRowSerializer,
11
+ serializer: Kerbi::Cli::EntryYamlJsonSerializer
12
+ )
13
+ end
14
+
15
+ cmd_meta Kerbi::Consts::CommandSchemas::SHOW_STATE
16
+ # @param [String] tag_expr e.g 1.9.1, @latest
17
+ def show(release_name, tag_expr)
18
+ prep_opts(Kerbi::Consts::OptionDefaults::LIST_STATE)
19
+ mem_release_name(release_name)
20
+ entry = find_readable_entry(tag_expr)
21
+ echo_data(
22
+ entry,
23
+ table_serializer: Kerbi::Cli::FullEntryRowSerializer,
24
+ serializer: Kerbi::Cli::EntryYamlJsonSerializer
25
+ )
26
+ end
27
+
28
+ cmd_meta Kerbi::Consts::CommandSchemas::RETAG_STATE
29
+ # @param [String] old_tag_expr e.g 1.9.1, @latest
30
+ # @param [String] new_tag_expr e.g 1.9.1, @latest
31
+ def retag(release_name, old_tag_expr, new_tag_expr)
32
+ mem_release_name(release_name)
33
+ entry = find_readable_entry(old_tag_expr)
34
+ old_tag = entry.retag(new_tag_expr)
35
+ touch_and_save_entry(entry, tag: old_tag)
36
+ end
37
+
38
+ cmd_meta Kerbi::Consts::CommandSchemas::PROMOTE_STATE
39
+ # @param [String] tag_expr e.g 1.9.1, @latest
40
+ def promote(release_name, tag_expr)
41
+ mem_release_name(release_name)
42
+ entry = find_readable_entry(tag_expr)
43
+ old_name = entry.promote
44
+ touch_and_save_entry(entry, tag: old_name)
45
+ end
46
+
47
+ cmd_meta Kerbi::Consts::CommandSchemas::DEMOTE_STATE
48
+ # @param [String] tag_expr e.g 1.9.1, @latest
49
+ def demote(release_name, tag_expr)
50
+ mem_release_name(release_name)
51
+ entry = find_readable_entry(tag_expr)
52
+ old_name = entry.demote
53
+ touch_and_save_entry(entry, tag: old_name)
54
+ end
55
+
56
+ cmd_meta Kerbi::Consts::CommandSchemas::SET_STATE_ATTR
57
+ # @param [String] tag_expr e.g 1.9.1, @latest
58
+ # @param [String] attr_name e.g message
59
+ # @param [String] new_value e.g i am a new message
60
+ def set(release_name, tag_expr, attr_name, new_value)
61
+ mem_release_name(release_name)
62
+ entry = find_readable_entry(tag_expr)
63
+ old_value = entry.assign_attr(attr_name, new_value)
64
+ touch_and_save_entry(entry, attr_name => old_value)
65
+ end
66
+
67
+ cmd_meta Kerbi::Consts::CommandSchemas::DELETE_STATE
68
+ # @param [String] tag_expr e.g 1.9.1, @latest
69
+ def delete(release_name, tag_expr)
70
+ mem_release_name(release_name)
71
+ entry = find_readable_entry(tag_expr)
72
+ state_backend.delete_entry(entry)
73
+ new_count = state_backend.entries.count
74
+ puts "Deleted state[#{entry.tag}]. Remaining entries: #{new_count}"
75
+ end
76
+
77
+ cmd_meta Kerbi::Consts::CommandSchemas::PRUNE_CANDIDATES_STATE
78
+ def prune_candidates(release_name)
79
+ mem_release_name(release_name)
80
+ old_count = entry_set.entries.count
81
+ entry_set.prune_candidates
82
+ state_backend.save
83
+ new_count = entry_set.entries.count
84
+ puts "Pruned #{old_count - new_count} state entries"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,10 +1,11 @@
1
1
  module Kerbi
2
2
  module Cli
3
3
  class ValuesHandler < BaseHandler
4
- thor_meta Kerbi::Consts::CommandSchemas::SHOW_VALUES
4
+ cmd_meta Kerbi::Consts::CommandSchemas::SHOW_VALUES
5
5
  def show
6
- values = self.compile_values
7
- print_dicts(values)
6
+ values = compile_values
7
+ persist_compiled_values
8
+ echo_data(values, coerce_type: "Hash")
8
9
  end
9
10
  end
10
11
  end
@@ -0,0 +1,9 @@
1
+ module <%= (module_name = data[:user_module_name]) %>
2
+ class RootMixer < Kerbi::Mixer
3
+ def mix
4
+ push dict(text: "#{values[:message]} #{release_name} message")
5
+ end
6
+ end
7
+ end
8
+
9
+ Kerbi::Globals.mixers << <%= module_name %>::RootMixer
@@ -0,0 +1 @@
1
+ message: "normal"
@@ -2,51 +2,194 @@ module Kerbi
2
2
  module Consts
3
3
 
4
4
  module OptionKeys
5
- OUTPUT_FMT = "output"
5
+ PROJECT_ROOT = "project-root"
6
+
7
+ OUTPUT_FMT = "output-format"
6
8
  INLINE_ASSIGNMENT = "inline-value"
9
+ LOAD_DEFAULT_VALUES = "load-defaults"
7
10
  VALUE_FNAMES = "values-file"
8
- USE_STATE_VALUES = "use-state-values"
11
+
9
12
  RUBY_VER = "ruby-version"
10
13
  VERBOSE = "verbose"
14
+ PRE_CONFIRM = "confirm"
15
+
16
+ STATE_BACKEND_TYPE = "state-backend"
17
+ READ_STATE = "read-state"
18
+ STRICT_READ_STATE = "strict-read"
19
+ WRITE_STATE = "write-state"
20
+ NAMESPACE = "namespace"
21
+ WRITE_STATE_MESSAGE = "message"
22
+
23
+ K8S_AUTH_TYPE = "k8s-auth-type"
24
+ KUBE_CONFIG_PATH = "kube-config-path"
25
+ KUBE_CONFIG_CONTEXT = "kube-config-context"
26
+ KUBE_ACCESS_TOKEN = "k8s-access-token"
27
+ K8S_USERNAME = "k8s-username"
28
+ K8S_PASSWORD = "k8s-password"
29
+ K8S_TOKEN = "k8s-access-token"
30
+
31
+ LEGAL_CONFIG_FILE_KEYS = [
32
+ STATE_BACKEND_TYPE,
33
+ K8S_AUTH_TYPE,
34
+ KUBE_CONFIG_CONTEXT,
35
+ K8S_USERNAME,
36
+ K8S_PASSWORD,
37
+ KUBE_ACCESS_TOKEN
38
+ ]
39
+ end
40
+
41
+ module OptionDefaults
42
+ BASE = {
43
+ OptionKeys::LOAD_DEFAULT_VALUES => true,
44
+ OptionKeys::INLINE_ASSIGNMENT => [],
45
+ OptionKeys::VALUE_FNAMES => [],
46
+ OptionKeys::OUTPUT_FMT => "yaml",
47
+ OptionKeys::STATE_BACKEND_TYPE => "configmap",
48
+ OptionKeys::K8S_AUTH_TYPE => "kube-config"
49
+ }.freeze
50
+
51
+ LIST_STATE = BASE.merge(
52
+ OptionKeys::OUTPUT_FMT => "table"
53
+ ).freeze
54
+
55
+ LIST_RELEASE = BASE.merge(
56
+ OptionKeys::OUTPUT_FMT => "table"
57
+ ).freeze
11
58
  end
12
59
 
13
60
  module OptionSchemas
14
- OUTPUT_FMT = {
15
- key: OptionKeys::OUTPUT_FMT,
16
- desc: "Specify YAML or JSON. Defaults to YAML",
17
- enum: %w[yaml json]
18
- }
19
61
 
20
- USE_STATE_VALUES = {
21
- key: OptionKeys::USE_STATE_VALUES,
22
- desc: "If true, merges in values loaded from state ConfigMap",
23
- type: "boolean"
62
+ PROJECT_ROOT = {
63
+ key: OptionKeys::PROJECT_ROOT,
64
+ desc: "Project root. An abs path, a rel path, "\
65
+ "or remote (/foo, foo, @foo/bar)",
66
+ aliases: "-p"
24
67
  }
25
68
 
69
+ K8S_AUTH_TYPE = {
70
+ key: OptionKeys::K8S_AUTH_TYPE,
71
+ desc: "Strategy for connecting to target cluster "\
72
+ "(defaults to kube-config)",
73
+ enum: %w[kube-config in-cluster basic token]
74
+ }.freeze
75
+
76
+ KUBE_CONFIG_PATH = {
77
+ key: OptionKeys::KUBE_CONFIG_PATH,
78
+ desc: "path to your kube-config file, defaults to ~/.kube/config"
79
+ }.freeze
80
+
81
+ KUBE_CONFIG_CONTEXT = {
82
+ key: OptionKeys::KUBE_CONFIG_CONTEXT,
83
+ desc: "context to use in your kube config,
84
+ defaults to $(kubectl config current-context)"
85
+ }.freeze
86
+
87
+ K8S_USERNAME = {
88
+ key: OptionKeys::K8S_USERNAME,
89
+ desc: "Kubernetes auth username for basic password auth"
90
+ }.freeze
91
+
92
+ K8S_PASSWORD = {
93
+ key: OptionKeys::K8S_PASSWORD,
94
+ desc: "Kubernetes auth password for basic password auth"
95
+ }.freeze
96
+
97
+ LOAD_DEFAULT_VALUES = {
98
+ key: OptionKeys::LOAD_DEFAULT_VALUES,
99
+ desc: "Automatically load values.yaml. Defaults to true.",
100
+ type: "boolean",
101
+ default: true
102
+ }.freeze
103
+
104
+ K8S_TOKEN = {
105
+ key: OptionKeys::K8S_TOKEN,
106
+ desc: "Kubernetes auth bearer token for token auth"
107
+ }.freeze
108
+
109
+ STATE_BACKEND_TYPE = {
110
+ key: OptionKeys::STATE_BACKEND_TYPE,
111
+ desc: "Persistent store to keep track of applied "\
112
+ "values (configmap, secret)",
113
+ enum: %w[configmap secret]
114
+ }.freeze
115
+
116
+ OUTPUT_FMT = {
117
+ key: OptionKeys::OUTPUT_FMT,
118
+ aliases: "-o",
119
+ desc: "Specify YAML, JSON, or table",
120
+ enum: %w[yaml json table]
121
+ }.freeze
122
+
26
123
  INLINE_ASSIGNMENT = {
27
124
  key: OptionKeys::INLINE_ASSIGNMENT,
28
125
  aliases: "--set",
29
- desc: "An inline variable assignment, e.g --set x.y=foo --set x.z=bar",
126
+ desc: "An inline variable assignment, e.g --set x.y=foo "\
127
+ "--set x.z=bar",
30
128
  repeatable: true
31
- }
129
+ }.freeze
130
+
131
+ READ_STATE = {
132
+ key: OptionKeys::READ_STATE,
133
+ desc: "Merge values from given state record into final values.",
134
+ }.freeze
135
+
136
+ STRICT_READ_STATE = {
137
+ key: OptionKeys::STRICT_READ_STATE,
138
+ desc: "Makes read-state operations fail if the " \
139
+ "state does not exist for the given tag",
140
+ }.freeze
141
+
142
+ WRITE_STATE = {
143
+ key: OptionKeys::WRITE_STATE,
144
+ desc: "write compiled values into given state record"
145
+ }.freeze
146
+
147
+ NAMESPACE = {
148
+ key: OptionKeys::NAMESPACE,
149
+ aliases: "-n",
150
+ desc: "for state operations, tell kerbi that the state
151
+ configmap/secret is in this namespace"
152
+ }.freeze
32
153
 
33
154
  VALUE_FNAMES = {
34
155
  key: OptionKeys::VALUE_FNAMES,
35
156
  aliases: "-f",
36
157
  desc: "Name of a values file to be loaded.",
37
158
  repeatable: true
38
- }
159
+ }.freeze
39
160
 
40
161
  RUBY_VER = {
41
162
  key: OptionKeys::RUBY_VER,
42
163
  desc: "Specify ruby version for Gemfile in a new project"
43
- }
164
+ }.freeze
44
165
 
45
166
  VERBOSE = {
46
167
  key: OptionKeys::VERBOSE,
47
168
  desc: "Run in verbose mode",
48
169
  enum: %w[true false]
49
- }
170
+ }.freeze
171
+
172
+ PRE_CONFIRM = {
173
+ key: OptionKeys::PRE_CONFIRM,
174
+ desc: "Skip CLI confirmation",
175
+ enum: %w[true false]
176
+ }.freeze
177
+
178
+ KUBERNETES_OPTIONS = [
179
+ NAMESPACE,
180
+ STATE_BACKEND_TYPE,
181
+ READ_STATE,
182
+ WRITE_STATE,
183
+ K8S_AUTH_TYPE,
184
+ KUBE_CONFIG_PATH,
185
+ KUBE_CONFIG_CONTEXT
186
+ ].freeze
187
+
188
+ VALUES_OPTIONS = [
189
+ VALUE_FNAMES,
190
+ INLINE_ASSIGNMENT,
191
+ LOAD_DEFAULT_VALUES,
192
+ ].freeze
50
193
  end
51
194
 
52
195
  module CommandSchemas
@@ -54,31 +197,54 @@ module Kerbi
54
197
  VALUES_SUPER = {
55
198
  name: "values",
56
199
  desc: "Command group for values actions: show, get"
57
- }
200
+ }.freeze
58
201
 
59
202
  PROJECT_SUPER = {
60
203
  name: "project",
61
204
  desc: "Command group for project actions: new, info"
62
- }
205
+ }.freeze
206
+
207
+ STATE_SUPER = {
208
+ name: "state",
209
+ desc: "Command group for state actions"
210
+ }.freeze
211
+
212
+ RELEASE_SUPER = {
213
+ name: "release",
214
+ desc: "Command group for release actions"
215
+ }.freeze
216
+
217
+ CONFIG_SUPER = {
218
+ name: "config",
219
+ desc: "Command group for config actions: set, get, show"
220
+ }.freeze
63
221
 
64
222
  TEMPLATE = {
65
223
  name: "template [KERBIFILE] [RELEASE_NAME]",
66
224
  desc: "Runs mixers for RELEASE_NAME",
67
225
  options: [
226
+ OptionSchemas::PROJECT_ROOT,
68
227
  OptionSchemas::OUTPUT_FMT,
69
- OptionSchemas::VALUE_FNAMES,
70
- OptionSchemas::INLINE_ASSIGNMENT
228
+ *OptionSchemas::VALUES_OPTIONS,
229
+ *OptionSchemas::KUBERNETES_OPTIONS
71
230
  ]
72
- }
231
+ }.freeze
73
232
 
74
233
  CONSOLE = {
75
234
  name: "console",
76
235
  desc: "Opens an IRB console so you can play with your mixers",
77
236
  options: [
237
+ OptionSchemas::PROJECT_ROOT,
78
238
  OptionSchemas::VALUE_FNAMES,
79
239
  OptionSchemas::INLINE_ASSIGNMENT
80
240
  ]
81
- }
241
+ }.freeze
242
+
243
+ VERSION = {
244
+ name: "version",
245
+ desc: "Prints the version of this RubyGem",
246
+ options: []
247
+ }.freeze
82
248
 
83
249
  NEW_PROJECT = {
84
250
  name: "new",
@@ -87,18 +253,167 @@ module Kerbi
87
253
  OptionSchemas::RUBY_VER,
88
254
  OptionSchemas::VERBOSE
89
255
  ]
90
- }
256
+ }.freeze
257
+
258
+ RELEASE_STATUS = {
259
+ name: "status [RELEASE_NAME]",
260
+ desc: "Verbosely assesses the readiness of your "\
261
+ "state-tracking backend.",
262
+ options: [
263
+ *OptionSchemas::KUBERNETES_OPTIONS,
264
+ OptionSchemas::VERBOSE
265
+ ]
266
+ }.freeze
267
+
268
+ RELEASE_LIST = {
269
+ name: "list",
270
+ desc: "Lists all known Kerbi releases by scanning cluster" \
271
+ " ConfigMaps/Secrets",
272
+ options: [
273
+ *OptionSchemas::KUBERNETES_OPTIONS,
274
+ OptionSchemas::VERBOSE
275
+ ]
276
+ }.freeze
277
+
278
+ RELEASE_DELETE = {
279
+ name: "delete [RELEASE_NAME]",
280
+ desc: "Delete the ConfigMap/Secret storing states for"\
281
+ " this release",
282
+ options: [
283
+ *OptionSchemas::KUBERNETES_OPTIONS,
284
+ OptionSchemas::PRE_CONFIRM
285
+ ]
286
+ }.freeze
287
+
288
+ LIST_STATE = {
289
+ name: "list [RELEASE_NAME]",
290
+ desc: "Print all recorded states for [RELEASE_NAME]",
291
+ options: [
292
+ *OptionSchemas::KUBERNETES_OPTIONS,
293
+ OptionSchemas::OUTPUT_FMT
294
+ ],
295
+ defaults: OptionDefaults::LIST_STATE
296
+ }.freeze
297
+
298
+ INIT_RELEASE = {
299
+ name: "init [RELEASE_NAME]",
300
+ desc: "Provision the resources for persisting the state",
301
+ options: [
302
+ *OptionSchemas::KUBERNETES_OPTIONS,
303
+ OptionSchemas::VERBOSE
304
+ ]
305
+ }.freeze
306
+
307
+ SHOW_STATE = {
308
+ name: "show [RELEASE_NAME] [TAG]",
309
+ desc: "Print summary of state identified by [TAG]",
310
+ options: [
311
+ *OptionSchemas::KUBERNETES_OPTIONS,
312
+ OptionSchemas::OUTPUT_FMT
313
+ ],
314
+ defaults: OptionDefaults::LIST_STATE
315
+ }.freeze
316
+
317
+ RETAG_STATE = {
318
+ name: "retag [RELEASE_NAME] [OLD_TAG] [NEW_TAG]",
319
+ desc: "Updates entry's tag given by [OLD_TAG] to [NEW_TAG]",
320
+ options: [
321
+ *OptionSchemas::KUBERNETES_OPTIONS,
322
+ OptionSchemas::OUTPUT_FMT
323
+ ],
324
+ defaults: OptionDefaults::LIST_STATE
325
+ }.freeze
326
+
327
+ PROMOTE_STATE = {
328
+ name: "promote [RELEASE_NAME] [TAG]",
329
+ desc: "Removes the [cand]- prefix from the given entry,
330
+ removing its candidate status.",
331
+ options: [
332
+ *OptionSchemas::KUBERNETES_OPTIONS,
333
+ ],
334
+ defaults: OptionDefaults::LIST_STATE
335
+ }.freeze
336
+
337
+ DEMOTE_STATE = {
338
+ name: "promote [RELEASE_NAME] [TAG]",
339
+ desc: "Adds the [cand]- prefix from the given entry,
340
+ giving it candidate status.",
341
+ options: [
342
+ *OptionSchemas::KUBERNETES_OPTIONS,
343
+ ],
344
+ defaults: OptionDefaults::LIST_STATE
345
+ }.freeze
346
+
347
+ DELETE_STATE = {
348
+ name: "delete [RELEASE_NAME] [TAG]",
349
+ desc: "Deletes the state entry given by [TAG]",
350
+ options: [
351
+ *OptionSchemas::KUBERNETES_OPTIONS,
352
+ ]
353
+ }.freeze
354
+
355
+ SET_STATE_ATTR = {
356
+ name: "set [RELEASE_NAME] [TAG] [ATTR_NAME] [NEW_VALUE]",
357
+ desc: "Updates state entry [TAG], attribute "\
358
+ "[ATTR_NAME] to value [NEW_VALUE]",
359
+ options: [
360
+ *OptionSchemas::KUBERNETES_OPTIONS,
361
+ ]
362
+ }.freeze
363
+
364
+ PRUNE_CANDIDATES_STATE = {
365
+ name: "prune-candidates [RELEASE_NAME]",
366
+ desc: "Deletes all state entries flagged as candidates",
367
+ options: [
368
+ *OptionSchemas::KUBERNETES_OPTIONS,
369
+ ]
370
+ }.freeze
371
+
372
+ SHOW_VERSION = {
373
+ name: "version",
374
+ desc: "Print kerbi version",
375
+ options: []
376
+ }.freeze
91
377
 
92
378
  SHOW_VALUES = {
93
379
  name: "show",
94
380
  desc: "Print out loaded values as YAML",
95
381
  options: [
382
+ OptionSchemas::PROJECT_ROOT,
96
383
  OptionSchemas::OUTPUT_FMT,
97
- OptionSchemas::VALUE_FNAMES,
98
- OptionSchemas::INLINE_ASSIGNMENT
384
+ *OptionSchemas::VALUES_OPTIONS,
385
+ *OptionSchemas::KUBERNETES_OPTIONS
99
386
  ]
100
- }
387
+ }.freeze
388
+
389
+ CONFIG_LOCATION = {
390
+ name: "location",
391
+ desc: "Prints out filesystem path for global Kerbi config"
392
+ }.freeze
393
+
394
+ CONFIG_SET = {
395
+ name: "set [KEY] [VALUE]",
396
+ desc: "Writes an x=y configuration to the global kerbi config"
397
+ }.freeze
398
+
399
+ CONFIG_GET = {
400
+ name: "get [KEY]",
401
+ desc: "Prints out the value of KEY as loaded into the options"
402
+ }.freeze
403
+
404
+ CONFIG_SHOW = {
405
+ name: "show",
406
+ desc: "Prints out the value of KEY as loaded into the options",
407
+ options: [
408
+ OptionSchemas::OUTPUT_FMT
409
+ ]
410
+ }.freeze
411
+
412
+ CONFIG_RESET = {
413
+ name: "reset",
414
+ desc: "Resets the config file to its default state",
415
+ options: []
416
+ }.freeze
101
417
  end
102
418
  end
103
- end
104
-
419
+ end
@@ -0,0 +1,60 @@
1
+ module Kerbi
2
+
3
+ module ConfigFile
4
+
5
+ DIR_NAME = ".kerbi"
6
+ FILE_NAME = "config.yaml"
7
+
8
+ def self.file_path
9
+ "#{Dir.home}/#{DIR_NAME}/#{FILE_NAME}"
10
+ end
11
+
12
+ def self.dir_path
13
+ "#{Dir.home}/#{DIR_NAME}"
14
+ end
15
+
16
+ def self.create_file_if_missing
17
+ unless File.exists?(file_path)
18
+ unless Dir.exists?(dir_path)
19
+ Dir.mkdir(dir_path)
20
+ end
21
+ write({}, skip_check: true)
22
+ end
23
+ end
24
+
25
+ # @return [Hash{Symbol, String}]
26
+ def self.read
27
+ begin
28
+ create_file_if_missing
29
+ contents = YAML.load_file(file_path)
30
+ contents.slice(*legal_keys)
31
+ rescue StandardError => e
32
+ puts "[WARN] failed to read config #{file_path} (#{e})"
33
+ {}
34
+ end
35
+ end
36
+
37
+ # @param [Hash] config
38
+ def self.write(config, skip_check: false)
39
+ create_file_if_missing unless skip_check
40
+ config = config.deep_dup.stringify_keys.slice(*legal_keys)
41
+ File.write(file_path, YAML.dump(config))
42
+ end
43
+
44
+ # @param [Hash] config
45
+ def self.patch(config)
46
+ existing_config = read
47
+ new_config = existing_config.merge(config)
48
+ write(new_config)
49
+ end
50
+
51
+ def self.reset
52
+ create_file_if_missing
53
+ write({})
54
+ end
55
+
56
+ def self.legal_keys
57
+ Kerbi::Consts::OptionKeys::LEGAL_CONFIG_FILE_KEYS
58
+ end
59
+ end
60
+ end
@@ -3,5 +3,9 @@ module Kerbi
3
3
  def self.mixers
4
4
  $_mixers ||= []
5
5
  end
6
+
7
+ def self.reset
8
+ $_mixers = []
9
+ end
6
10
  end
7
11
  end