kerbi 0.0.1 → 0.0.2

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cli/base_handler.rb +180 -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/root_handler.rb +32 -13
  8. data/lib/cli/state_handler.rb +95 -0
  9. data/lib/cli/values_handler.rb +4 -3
  10. data/lib/config/cli_schema.rb +299 -27
  11. data/lib/config/config_file.rb +60 -0
  12. data/lib/config/globals.rb +4 -0
  13. data/lib/config/run_opts.rb +150 -0
  14. data/lib/config/state_consts.rb +10 -0
  15. data/lib/kerbi.rb +31 -9
  16. data/lib/main/errors.rb +109 -0
  17. data/lib/main/mixer.rb +12 -8
  18. data/lib/mixins/cli_state_helpers.rb +136 -0
  19. data/lib/mixins/cm_backend_testing.rb +95 -0
  20. data/lib/mixins/entry_tag_logic.rb +183 -0
  21. data/lib/state/base_backend.rb +59 -0
  22. data/lib/state/config_map_backend.rb +119 -0
  23. data/lib/state/entry.rb +173 -0
  24. data/lib/state/entry_set.rb +137 -0
  25. data/lib/state/metadata.yaml.erb +11 -0
  26. data/lib/state/mixers.rb +23 -0
  27. data/lib/state/resources.yaml.erb +17 -0
  28. data/lib/utils/cli.rb +77 -10
  29. data/lib/utils/helm.rb +10 -12
  30. data/lib/utils/k8s_auth.rb +87 -0
  31. data/lib/utils/misc.rb +36 -1
  32. data/lib/utils/mixing.rb +1 -1
  33. data/lib/utils/values.rb +13 -22
  34. data/spec/cli/config_handler_spec.rb +38 -0
  35. data/spec/cli/root_handler_spec.rb +99 -0
  36. data/spec/cli/state_handler_spec.rb +139 -0
  37. data/spec/cli/values_handler_spec.rb +17 -0
  38. data/spec/expectations/common/bad-tag.txt +1 -0
  39. data/spec/expectations/config/bad-set.txt +1 -0
  40. data/spec/expectations/config/set.txt +1 -0
  41. data/spec/expectations/config/show-default.yaml +6 -0
  42. data/spec/expectations/root/template-inlines.yaml +31 -0
  43. data/spec/expectations/root/template-production.yaml +31 -0
  44. data/spec/expectations/root/template-read-inlines.yaml +31 -0
  45. data/spec/expectations/root/template-read.yaml +31 -0
  46. data/spec/expectations/root/template-write.yaml +31 -0
  47. data/spec/expectations/root/template.yaml +31 -0
  48. data/spec/expectations/root/values.json +28 -0
  49. data/spec/expectations/state/delete.txt +1 -0
  50. data/spec/expectations/state/demote.txt +1 -0
  51. data/spec/expectations/state/init-already-existed.txt +2 -0
  52. data/spec/expectations/state/init-both-created.txt +2 -0
  53. data/spec/expectations/state/list.json +51 -0
  54. data/spec/expectations/state/list.txt +6 -0
  55. data/spec/expectations/state/list.yaml +35 -0
  56. data/spec/expectations/state/promote.txt +1 -0
  57. data/spec/expectations/state/prune-candidates.txt +1 -0
  58. data/spec/expectations/state/retag.txt +1 -0
  59. data/spec/expectations/state/set.txt +1 -0
  60. data/spec/expectations/state/show.json +13 -0
  61. data/spec/expectations/state/show.txt +13 -0
  62. data/spec/expectations/state/show.yaml +8 -0
  63. data/spec/expectations/state/status-all-working.txt +4 -0
  64. data/spec/expectations/state/status-not-provisioned.txt +4 -0
  65. data/spec/expectations/values/order-of-precedence.yaml +4 -0
  66. data/spec/main/configmap_backend_spec.rb +109 -0
  67. data/spec/main/state_entry_set_spec.rb +112 -0
  68. data/spec/main/state_entry_spec.rb +109 -0
  69. data/spec/spec_helper.rb +87 -1
  70. data/spec/utils/helm_spec.rb +1 -21
  71. data/spec/utils/k8s_auth_spec.rb +32 -0
  72. data/spec/utils/misc_utils_spec.rb +9 -0
  73. data/spec/utils/values_utils_spec.rb +12 -19
  74. metadata +114 -13
  75. data/lib/cli/base.rb +0 -83
  76. data/lib/config/cli_opts.rb +0 -50
  77. data/lib/config/manager.rb +0 -36
  78. data/lib/main/state_manager.rb +0 -47
  79. data/lib/utils/kubectl.rb +0 -58
  80. data/spec/main/examples_spec.rb +0 -12
  81. data/spec/main/state_manager_spec.rb +0 -84
  82. data/spec/utils/state_utils.rb +0 -15
@@ -0,0 +1,119 @@
1
+ module Kerbi
2
+ module State
3
+
4
+ ##
5
+ # Treats a Kubernetes configmap in a namespace as a
6
+ # persistent store for state entries. Reads and writes
7
+ # to the configmap.
8
+ class ConfigMapBackend < Kerbi::State::BaseBackend
9
+ include Kerbi::Mixins::CmBackendTesting
10
+
11
+ attr_reader :auth_bundle
12
+ attr_reader :namespace
13
+
14
+ # @param [Hash] auth_bundle generated by Kerbi::Utils::K8sAuth
15
+ # @param [String] namespace Kubernetes namespace where configmap lives
16
+ def initialize(auth_bundle, namespace)
17
+ @auth_bundle = auth_bundle.freeze
18
+ @namespace = namespace.freeze
19
+ end
20
+
21
+ ##
22
+ # Checks for the namespace and configmap, creating along
23
+ # the way if missing. Does not raise if already exists.
24
+ # @param [Hash] opts for things like verbose
25
+ def provision_missing_resources(**opts)
26
+ create_namespace unless (ns_existed = namespace_exists?)
27
+ echo_init("namespaces/#{namespace}", ns_existed, opts)
28
+
29
+ create_resource unless (cm_existed = resource_exists?)
30
+ echo_init("#{namespace}/configmaps/#{cm_name}", cm_existed, opts)
31
+ end
32
+
33
+ ##
34
+ # Creates the configmap with 0 entries.
35
+ def create_resource
36
+ apply_resource(template_resource([]))
37
+ end
38
+
39
+ ##
40
+ # Creates the configmap given an exact dict representation
41
+ # of its contents. This method doesn't actually get used outside
42
+ # of rspec, but it's super useful there so keeping for time being.
43
+ # @param [Hash] resource_desc
44
+ def apply_resource(resource_desc)
45
+ #noinspection RubyResolve
46
+ client("v1").create_config_map(resource_desc)
47
+ end
48
+
49
+ ##
50
+ # Outputs the dict representation of the configmap, templated
51
+ # with the given entries.
52
+ # @param [Array<Kerbi::State::Entry>] entries
53
+ # @return [Hash]
54
+ def template_resource(entries)
55
+ values = { consts::ENTRIES_ATTR => entries.map(&:to_h) }
56
+ opts = { release_name: namespace }
57
+ Kerbi::State::ConfigMapMixer.new(values, **opts).run.first
58
+ end
59
+
60
+ ##
61
+ # Creates the required namespace resource for this configmap
62
+ # in the cluster.
63
+ def create_namespace
64
+ opts = { release_name: namespace }
65
+ dict = Kerbi::State::NamespaceMixer.new({}, **opts).run.first
66
+ #noinspection RubyResolve
67
+ client("v1").create_namespace(dict)
68
+ end
69
+
70
+ protected
71
+
72
+ ##
73
+ # Reads the configmap from Kubernetes, returns its dict representation.
74
+ def load_resource
75
+ #noinspection RubyResolve
76
+ client("v1").get_config_map(cm_name, namespace).to_h
77
+ end
78
+
79
+ ##
80
+ # Templates the updated version of the configmap given the entries
81
+ # in memory, and uses the new dict to overwrite the last configmap
82
+ # in the cluster.
83
+ def update_resource
84
+ new_resource = template_resource(entries)
85
+ #noinspection RubyResolve
86
+ client("v1").update_config_map(new_resource)
87
+ end
88
+
89
+ ##
90
+ # Deserializes the list of entries in the configmap. Calls
91
+ # #resources, which is memoized, so may trigger a cluster read.
92
+ # @return [Array<Hash>] entries
93
+ def read_entries
94
+ str_entries = resource[:data][:entries]
95
+ JSON.parse(str_entries)
96
+ end
97
+
98
+ ## Creates an instance of Kubeclient::Client given
99
+ # the auth_bundle in the state, and a Kubernetes API name
100
+ # like appsV1 (defaults to "v1" if not passed).
101
+ # @return [Kubeclient::Client]
102
+ def client(api_name="v1")
103
+ Kubeclient::Client.new(
104
+ auth_bundle[:endpoint],
105
+ api_name,
106
+ **auth_bundle[:options]
107
+ )
108
+ end
109
+
110
+ def consts
111
+ Kerbi::State::Consts
112
+ end
113
+
114
+ def cm_name
115
+ consts::RESOURCE_NAME
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,173 @@
1
+ module Kerbi
2
+ module State
3
+
4
+ ##
5
+ # Represents a single Kerbi state entry.
6
+ class Entry
7
+
8
+ CANDIDATE_PREFIX = "[cand]-"
9
+
10
+ ATTRS = %i[tag message values default_values created_at]
11
+ SETTABLE_ATTRS = %i[message created_at]
12
+
13
+ attr_accessor :set
14
+
15
+ attr_accessor :tag
16
+ attr_accessor :message
17
+ attr_accessor :default_values
18
+ attr_accessor :values
19
+ attr_accessor :created_at
20
+
21
+ attr_reader :validation_errors
22
+
23
+ def initialize(set, dict)
24
+ @set = set
25
+ ATTRS.each do |attr|
26
+ instance_variable_set("@#{attr}", dict[attr].freeze)
27
+ end
28
+ @_was_validated = false
29
+ @validation_errors = []
30
+ end
31
+
32
+ ## A state entry is a 'candidate' if its tag has the
33
+ # candidate signature - that is it starts with [cand]-.
34
+ # @return [TrueClass, FalseClass]
35
+ def candidate?
36
+ tag.start_with?(CANDIDATE_PREFIX)
37
+ end
38
+
39
+ ##
40
+ # Convenience method that returns the negation of #candidate?
41
+ # @return [TrueClass, FalseClass]
42
+ def committed?
43
+ !candidate?
44
+ end
45
+
46
+ ##
47
+ # Ghetto attribute validation. Pushes a attr => msg hash to the
48
+ # @validation_errors for every problem found. Does not raise on
49
+ # problems.
50
+ # @return [NilClass]
51
+ def validate
52
+ @validation_errors.push(
53
+ attr: 'tag',
54
+ msg: "Cannot be empty",
55
+ value: tag
56
+ ) unless tag.present?
57
+
58
+ @_was_validated = true
59
+ end
60
+
61
+ def valid?
62
+ raise "valid? called before #validate" unless @_was_validated
63
+ validation_errors.empty?
64
+ end
65
+
66
+ ##
67
+ # Computes a delta between this state's values and its
68
+ # default values.
69
+ # @return [Hash]
70
+ def overrides_delta
71
+ if values.is_a?(Hash) & default_values.is_a?(Hash)
72
+ Kerbi::Utils::Misc.deep_hash_diff(default_values, values)
73
+ else
74
+ nil
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Dynamically assign as a user.
80
+ # @param [String|Symbol] attr_name
81
+ # @param [Object] new_value
82
+ # @return [String] the old value, for convenience
83
+ def assign_attr(attr_name, new_value)
84
+ if SETTABLE_ATTRS.include?(attr_name.to_sym)
85
+ old_value = send(attr_name)
86
+ send("#{attr_name}=", new_value)
87
+ old_value
88
+ else
89
+ raise Kerbi::NoSuchStateAttrName
90
+ end
91
+ end
92
+
93
+ ##
94
+ # Replace current tag with a new one, where the new
95
+ # one can contain special interpolatable words like
96
+ # @candidate.
97
+ # @param [String] new_tag_expr
98
+ # @return [String] the old tag, for convenience
99
+ def retag(new_tag_expr)
100
+ old_tag = tag
101
+ self.tag = set.resolve_write_tag_expr(new_tag_expr)
102
+ old_tag
103
+ end
104
+
105
+ ##
106
+ # Removes the [cand]- part of the tag, making this
107
+ # entry lose its candidate status.
108
+ #
109
+ # Raises an exception if this entry was not a candidate.
110
+ # @return [String] the old tag, for convenience
111
+ def promote
112
+ raise Kerbi::StateNotPromotable unless candidate?
113
+ old_tag = tag
114
+ self.tag = tag[CANDIDATE_PREFIX.length..]
115
+ old_tag
116
+ end
117
+
118
+ ##
119
+ # Adds the [cand]- flag to this entry's tag, making this
120
+ # entry gain candidate status.
121
+ #
122
+ # Raises an exception if this entry was already a candidate.
123
+ # @return [String] the old tag, for convenience
124
+ def demote
125
+ raise Kerbi::StateNotDemotable unless committed?
126
+ old_tag = tag
127
+ self.tag = "#{CANDIDATE_PREFIX}#{tag}"
128
+ old_tag
129
+ end
130
+
131
+ ##
132
+ # Convenience method to get all overridden keys between
133
+ # the values and default_values dicts.
134
+ # @return [Array<String>]
135
+ def overridden_keys
136
+ (delta = overrides_delta) ? delta.keys.map(&:to_s) : []
137
+ end
138
+
139
+ def to_h
140
+ special_ser = {
141
+ values: values || {},
142
+ default_values: default_values || {},
143
+ created_at: created_at.to_s
144
+ }
145
+ Hash[ATTRS.map{|k|[k, send(k)]}].merge(special_ser)
146
+ end
147
+ alias_method :serialize, :to_h
148
+
149
+ def to_json
150
+ JSON.dump(serialize)
151
+ end
152
+
153
+ # @param [Hash] dict
154
+ # @return [Kerbi::State::Entry]
155
+ def self.from_dict(set, dict={})
156
+ dict.deep_symbolize_keys!
157
+ dict.slice!(*ATTRS)
158
+
159
+ self.new(
160
+ set,
161
+ **dict,
162
+ values: dict[:values] || {},
163
+ default_values: dict[:default_values] || {},
164
+ created_at: (Time.parse(dict[:created_at]) rescue nil)
165
+ )
166
+ end
167
+
168
+ def self.versioned?(expr)
169
+ Gem::Version.correct?(expr)
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,137 @@
1
+ module Kerbi
2
+ module State
3
+
4
+ ##
5
+ # Baby version of ActiveRecord::Relation. Holds an array of
6
+ # entries (i.e Kerbi::State::Entry) and exposes useful group-level
7
+ # operations, like sorting, find maximums, etc...
8
+ class EntrySet
9
+
10
+ include Kerbi::Mixins::EntryTagLogic
11
+
12
+ attr_reader :entries
13
+
14
+ # @param [Array<Hash>] dicts
15
+ def initialize(dicts)
16
+ @entries = dicts.map { |h| Entry.from_dict(self, h) }
17
+ sort_by_created_at
18
+ end
19
+
20
+ def validate!
21
+ entries.each(&:validate)
22
+ if (bad_entries = entries.reject(&:valid?)).any?
23
+ errors = Hash[bad_entries.map do |entry|
24
+ [entry.tag, entry.validation_errors.deep_dup]
25
+ end]
26
+ raise Kerbi::EntryValidationError.new(errors)
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Filters entries by candidate status, returning only the
32
+ # ones that are NOT candidates.
33
+ # @return [Array<Kerbi::State::Entry>]
34
+ def committed
35
+ entries.select(&:committed?)
36
+ end
37
+
38
+ ##
39
+ # Filters entries by candidate status, returning only the
40
+ # ones that ARE candidates.
41
+ # @return [Array<Kerbi::State::Entry>]
42
+ def candidates
43
+ entries.reject(&:committed?)
44
+ end
45
+
46
+ ##
47
+ # Finds the most recently created/updated entry in the list
48
+ # that is not a candidate.
49
+ # @return [?Kerbi::State::Entry]
50
+ def latest
51
+ committed.first
52
+ end
53
+
54
+ ##
55
+ # Finds the least recently created/updated entry in the list
56
+ # that is not a candidate.
57
+ # @return [?Kerbi::State::Entry]
58
+ def oldest
59
+ committed.last
60
+ end
61
+
62
+ ##
63
+ # Finds the most recently created/updated entry in the list
64
+ # that is a candidate.
65
+ # @return [?Kerbi::State::Entry]
66
+ def latest_candidate
67
+ candidates.first
68
+ end
69
+
70
+ ##
71
+ # Given a target entry tag expression, searches underlying array
72
+ # for the corresponding entry.
73
+ #
74
+ # Assumes the tag expression contains special interpolatable words,
75
+ # and thus resolves the tag expression into a literal tag first.
76
+ #
77
+ # Invokes tag resolution logic specific to reading entries, which
78
+ # is different than for writing entries (see #resolve_read_tag_expr).
79
+ # @param [String] tag_expr
80
+ # @return [Kerbi::State::Entry]
81
+ def find_entry_for_read(tag_expr)
82
+ resolved_tag = resolve_read_tag_expr(tag_expr)
83
+ entry = find_by_literal_tag(resolved_tag)
84
+ raise Kerbi::StateNotFoundError.new(tag_expr) unless entry
85
+ entry
86
+ end
87
+
88
+ ##
89
+ # Given a target entry tag expression, searches underlying array
90
+ # for the corresponding entry.
91
+ #
92
+ # Assumes the tag expression contains special interpolatable words,
93
+ # and thus resolves the tag expression into a literal tag first.
94
+ #
95
+ # Invokes tag resolution logic specific to writing entries, which
96
+ # is different than for reading entries (see #resolve_write_tag_expr).
97
+ #
98
+ # If an entry is not found, initializes a new empty entry with the
99
+ # given resolved tag, and adds it to the set's underlying array.
100
+ # @param [String] tag_expr
101
+ # @return [?Kerbi::State::Entry]
102
+ def find_or_init_entry_for_write(tag_expr)
103
+ resolved_tag = resolve_write_tag_expr(tag_expr)
104
+ if(existing_entry = find_by_literal_tag(resolved_tag))
105
+ existing_entry
106
+ else
107
+ entry = Kerbi::State::Entry.new(self, tag: resolved_tag)
108
+ entries.unshift(entry)
109
+ entry
110
+ end
111
+ end
112
+
113
+ ##
114
+ # Performs simple linear search for an entry whose tags matches
115
+ # exactly tag_expr.
116
+ # @param [String] tag_expr
117
+ # @return [?Kerbi::State::Entry]
118
+ def find_by_literal_tag(tag_expr)
119
+ return nil unless tag_expr.present?
120
+ entries.find { |e| e.tag == tag_expr }
121
+ end
122
+ alias_method :get, :find_by_literal_tag
123
+
124
+
125
+ def prune_candidates
126
+ entries.select!(&:committed?)
127
+ end
128
+
129
+ def sort_by_created_at
130
+ entries.sort! do |a, b|
131
+ both_defined = a.created_at && b.created_at
132
+ both_defined ? b.created_at <=> a.created_at : 0
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,11 @@
1
+ <% consts = Kerbi::State::Consts %>
2
+
3
+ metadata:
4
+ labels: <%= embed({
5
+ consts::CREATOR_ATTR => consts::CREATOR_VAL
6
+ }) %>
7
+
8
+ annotations: <%= embed({
9
+ consts::CREATOR_ATTR => consts::CREATOR_VAL,
10
+ description: "used by kerbi to keep records of previously applied values"
11
+ }) %>
@@ -0,0 +1,23 @@
1
+ module Kerbi
2
+ module State
3
+ class ConfigMapMixer < Kerbi::Mixer
4
+ locate_self __dir__
5
+
6
+ def mix
7
+ patched_with file("metadata") do
8
+ push file("resources", only: [{kind: "ConfigMap"}])
9
+ end
10
+ end
11
+ end
12
+
13
+ class NamespaceMixer < Kerbi::Mixer
14
+ locate_self __dir__
15
+
16
+ def mix
17
+ patched_with file("metadata") do
18
+ push file("resources", only: [{kind: "Namespace"}])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ <% consts = Kerbi::State::Consts %>
2
+
3
+ <% entries_json = JSON.dump(values[consts::ENTRIES_ATTR]) %>
4
+
5
+ apiVersion: v1
6
+ kind: ConfigMap
7
+ metadata:
8
+ name: <%= consts::RESOURCE_NAME %>
9
+ namespace: <%= release_name %>
10
+ data: <%= embed({consts::ENTRIES_ATTR => entries_json}) %>
11
+
12
+ ---
13
+
14
+ apiVersion: v1
15
+ kind: Namespace
16
+ metadata:
17
+ name: <%= release_name %>
data/lib/utils/cli.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module Kerbi
2
2
  module Utils
3
3
  module Cli
4
-
5
4
  ##
6
5
  # Convenience method for running and compiling the output
7
6
  # of several mixers. Returns all result dicts in a flat array
@@ -17,10 +16,24 @@ module Kerbi
17
16
  end
18
17
  end
19
18
 
19
+ def self.coerce_hash_or_array(actual, **options)
20
+ if (type = options[:coerce_type]).present?
21
+ if type == 'Array'
22
+ actual.is_a?(Array) ? actual : [actual]
23
+ elsif type == 'Hash'
24
+ actual.is_a?(Array) ? actual[0].to_h : actual.to_h
25
+ else
26
+ raise "Unrecognized type coercion #{type}"
27
+ end
28
+ else
29
+ actual
30
+ end
31
+ end
32
+
20
33
  ##
21
34
  # Turns list of key-symbol dicts into their
22
35
  # pretty YAML representation.
23
- # @param [Array<Hash>] dicts dicts to YAMLify
36
+ # @param [Array<Hash>|Hash] dicts dicts to YAMLify
24
37
  # @return [String] pretty YAML representation of input
25
38
  def self.dicts_to_yaml(dicts)
26
39
  if dicts.is_a?(Array)
@@ -29,15 +42,52 @@ module Kerbi
29
42
  raw.gsub("---\n", i.zero? ? '' : "---\n\n")
30
43
  end.join("\n")
31
44
  else
45
+ return "{}" if dicts.empty?
32
46
  as_yaml = YAML.dump(dicts.deep_stringify_keys)
33
47
  as_yaml.gsub("---\n", "")
34
48
  end
35
49
  end
36
50
 
51
+ # @param [Array<Object>] entries
52
+ def self.list_to_table(entries, serializer_cls)
53
+ if entries.is_a?(Array)
54
+ table = Terminal::Table.new(
55
+ headings: serializer_cls.header_titles,
56
+ rows: entries.map(&:values)
57
+ )
58
+ table.style = LIST_TABLE_STYLE
59
+ table.to_s
60
+ else
61
+ table = Terminal::Table.new do |t|
62
+ #noinspection RubyResolve
63
+ entries.each do |key, value|
64
+ new_key = key.upcase.to_s.bold
65
+ new_value = fmt_table_value(value)
66
+ t.add_row [new_key, new_value]
67
+ end
68
+ t.style = DESCRIBE_TABLE_STYLE
69
+
70
+ end
71
+ table.to_s
72
+ end
73
+ end
74
+
75
+ def self.fmt_table_value(value)
76
+ if value.is_a?(Hash)
77
+ flattened = Kerbi::Utils::Misc.flatten_hash(value)
78
+ stringified = flattened.deep_stringify_keys
79
+ dicts_to_yaml(stringified)
80
+ elsif value.is_a?(Array)
81
+ value.join(",")
82
+ else
83
+ value.to_s
84
+ end
85
+ end
86
+
37
87
  ##
38
88
  # Turns list of key-symbol dicts into their
39
89
  # pretty JSON representation.
40
- # @param [Array<Hash>] dicts dicts to YAMLify
90
+ # @param [Array<Hash>|Hash] dicts dicts to YAMLify
41
91
  # @return [String] pretty JSON representation of input
42
92
  def self.dicts_to_json(dicts)
43
93
  JSON.pretty_generate(dicts)
@@ -46,14 +96,31 @@ module Kerbi
46
96
  ##
47
97
  # Searches the expected paths for the kerbifile and ruby-loads it.
48
98
  # @param [String] root directory to search
49
- def self.load_kerbifile(fname_expr)
50
- fname_expr ||= Dir.pwd
51
- abs_path = "#{fname_expr}/kerbifile.rb"
52
- if File.exists?(abs_path)
53
- #noinspection RubyResolve
54
- load(abs_path)
55
- end
99
+ def self.load_kerbifile(root_dir)
100
+ root_dir ||= Dir.pwd
101
+ abs_path = "#{root_dir}/kerbifile.rb"
102
+ exists = File.exists?(abs_path)
103
+ raise Kerbi::KerbifileNotFoundError.new(root: root_dir) unless exists
104
+ #noinspection RubyResolve
105
+ load(abs_path)
56
106
  end
107
+
108
+ LIST_TABLE_STYLE = {
109
+ border_left: false,
110
+ border_right: false,
111
+ border_top: false,
112
+ border_x: "",
113
+ border_y: "",
114
+ border_i: ""
115
+ }.freeze
116
+
117
+ DESCRIBE_TABLE_STYLE = {
118
+ all_separators: true,
119
+ border_x: "-",
120
+ border_y: "",
121
+ border_i: ""
122
+ }.freeze
123
+
57
124
  end
58
125
  end
59
126
  end
data/lib/utils/helm.rb CHANGED
@@ -2,15 +2,14 @@ module Kerbi
2
2
  module Utils
3
3
  module Helm
4
4
 
5
- def self.config
6
- Kerbi::Config::Manager
7
- end
8
-
5
+ HELM_EXEC = "helm"
6
+ TMP_VALUES_PATH = "/tmp/kerbi-helm-tmp.yaml"
7
+
9
8
  ##
10
9
  # Tests whether Kerbi can invoke Helm commands
11
10
  # @return [Boolean] true if helm commands succeed locally
12
11
  def self.can_exec?
13
- !!system(config.helm_exec, out: File::NULL, err: File::NULL)
12
+ !!system(HELM_EXEC, out: File::NULL, err: File::NULL)
14
13
  end
15
14
 
16
15
  ##
@@ -18,18 +17,17 @@ module Kerbi
18
17
  # @param [Hash] values a hash of values
19
18
  # @return [String] the path of the file
20
19
  def self.make_tmp_values_file(values)
21
- File.open(config.tmp_helm_values_path, 'w') do |f|
22
- f.write(YAML.dump((values || {}).deep_stringify_keys))
23
- end
24
- config.tmp_helm_values_path
20
+ content = YAML.dump((values || {}).deep_stringify_keys)
21
+ File.write(TMP_VALUES_PATH, content)
22
+ TMP_VALUES_PATH
25
23
  end
26
24
 
27
25
  ##
28
26
  # Deletes the temp file
29
27
  # @return [void]
30
28
  def self.del_tmp_values_file
31
- if File.exists?(config.tmp_helm_values_path)
32
- File.delete(config.tmp_helm_values_path)
29
+ if File.exists?(TMP_VALUES_PATH)
30
+ File.delete(TMP_VALUES_PATH)
33
31
  end
34
32
  end
35
33
 
@@ -53,7 +51,7 @@ module Kerbi
53
51
  raise "Helm executable not working" unless can_exec?
54
52
  tmp_file = make_tmp_values_file(opts[:values])
55
53
  inline_flags = encode_inline_assigns(opts[:inline_assigns])
56
- command = "#{config.helm_exec} template #{release} #{project}"
54
+ command = "#{HELM_EXEC} template #{release} #{project}"
57
55
  command += " -f #{tmp_file} #{inline_flags} #{opts[:cli_args]}"
58
56
  output = `#{command}`
59
57
  del_tmp_values_file