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,6 @@
1
+ TAG MESSAGE ASSIGNMENTS OVERRIDES CREATED_AT
2
+
3
+ \e[0;33;49m[cand]-four\e[0m 0 0 2003-01-01 00:00:00 +0000
4
+ \e[0;33;49m[cand]-three\e[0m 0 0 2002-01-01 00:00:00 +0000
5
+ \e[0;34;49mtwo\e[0m message 0 0 2001-01-01 00:00:00 +0000
6
+ \e[0;34;49mone\e[0m 1 1 2000-01-01 00:00:00 +0000
@@ -0,0 +1,35 @@
1
+ tag: "[cand]-four"
2
+ message:
3
+ created_at: 2003-01-01 00:00:00.000000000 +00:00
4
+ values: {}
5
+ default_values: {}
6
+ overridden_keys: []
7
+
8
+ ---
9
+
10
+ tag: "[cand]-three"
11
+ message:
12
+ created_at: 2002-01-01 00:00:00.000000000 +00:00
13
+ values: {}
14
+ default_values: {}
15
+ overridden_keys: []
16
+
17
+ ---
18
+
19
+ tag: two
20
+ message: message
21
+ created_at: 2001-01-01 00:00:00.000000000 +00:00
22
+ values: {}
23
+ default_values: {}
24
+ overridden_keys: []
25
+
26
+ ---
27
+
28
+ tag: one
29
+ message:
30
+ created_at: 2000-01-01 00:00:00.000000000 +00:00
31
+ values:
32
+ x: x
33
+ default_values: {}
34
+ overridden_keys:
35
+ - x
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[four].tag from [cand]-four => four\e[0m
@@ -0,0 +1 @@
1
+ Pruned 2 state entries
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[born-again].tag from two => born-again\e[0m
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[two].message from message => new message\e[0m
@@ -0,0 +1,13 @@
1
+ {
2
+ "tag": "one",
3
+ "message": null,
4
+ "created_at": "2000-01-01 00:00:00 +0000",
5
+ "values": {
6
+ "x": "x"
7
+ },
8
+ "default_values": {
9
+ },
10
+ "overridden_keys": [
11
+ "x"
12
+ ]
13
+ }
@@ -0,0 +1,13 @@
1
+ --------------------------------------------
2
+ \e[1;39;49mTAG\e[0m \e[1;34;49mone\e[0m
3
+ --------------------------------------------
4
+ \e[1;39;49mMESSAGE\e[0m
5
+ --------------------------------------------
6
+ \e[1;39;49mCREATED_AT\e[0m 2000-01-01 00:00:00 +0000
7
+ --------------------------------------------
8
+ \e[1;39;49mVALUES\e[0m x: x
9
+ --------------------------------------------
10
+ \e[1;39;49mDEFAULT_VALUES\e[0m {}
11
+ --------------------------------------------
12
+ \e[1;39;49mOVERRIDDEN_KEYS\e[0m x
13
+ --------------------------------------------
@@ -0,0 +1,8 @@
1
+ tag: one
2
+ message:
3
+ created_at: 2000-01-01 00:00:00.000000000 +00:00
4
+ values:
5
+ x: x
6
+ default_values: {}
7
+ overridden_keys:
8
+ - x
@@ -0,0 +1,4 @@
1
+ pod:
2
+ image: nginx:1.20
3
+ service:
4
+ type: NodePort
@@ -0,0 +1,110 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::ConfigMapBackend do
4
+
5
+ let(:namespace) { "kerbi-spec" }
6
+ let(:cm_name) { Kerbi::State::ConfigMapBackend.mk_cm_name(namespace) }
7
+
8
+ before :each do
9
+ create_ns(namespace)
10
+ delete_cm(cm_name, namespace)
11
+ # sleep(2) #ADD ME BACK IF WEIRD ERRORS... :/
12
+ end
13
+
14
+ describe "#provision_missing_resources" do
15
+ let(:backend) { make_backend(namespace, namespace) }
16
+
17
+ context "when the namespace does not exist" do
18
+ it "provisions accordingly" do
19
+ delete_ns(namespace)
20
+ expect(backend.read_write_ready?).to be_falsey
21
+ backend.provision_missing_resources
22
+ end
23
+ end
24
+
25
+ context "when the namespace does exist" do
26
+ before :each do
27
+ create_ns(namespace)
28
+ expect(backend.read_write_ready?).to be_falsey
29
+ end
30
+
31
+ context "when the configmap does not exist" do
32
+ it "provisions accordingly" do
33
+ backend.provision_missing_resources
34
+ delete_cm(cm_name, namespace)
35
+ backend.provision_missing_resources
36
+ end
37
+ end
38
+
39
+ context "when the configmap does exist" do
40
+ it "provisions accordingly" do
41
+ backend.provision_missing_resources
42
+ backend.provision_missing_resources
43
+ end
44
+ end
45
+ end
46
+
47
+ after :each do
48
+ expect(backend.namespace_exists?).to eq(true)
49
+ expect(backend.read_write_ready?).to eq(true)
50
+ expect(backend.resource_exists?).to eq(true)
51
+ end
52
+ end
53
+
54
+ describe "#template_resource" do
55
+ context "with 0 entries" do
56
+ it "outputs a descriptor with the right basic properties" do
57
+ result = make_backend("xyz").template_resource([])
58
+ metadata = (result || {})[:metadata] || {}
59
+ expect(result[:kind]).to eq('ConfigMap')
60
+ expect(metadata[:name]).to eq('kerbi-xyz-db')
61
+ expect(metadata[:namespace]).to eq('xyz')
62
+ expect(result[:data][:entries]).to eq("[]")
63
+ end
64
+ end
65
+
66
+ context "with some entries (for puts only, uncomment)" do
67
+ it "puts it" do
68
+ # entry = new_state("1", created_at: "2022-01-01T00:00:00+00:00")
69
+ # puts entry.to_h
70
+ # result = make_backend("xyz").template_resource([entry])
71
+ # puts result
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "#namespace_exists?" do
77
+ context "when the namespace exists" do
78
+ it "returns true" do
79
+ expect(make_backend('', "default").namespace_exists?).to be_truthy
80
+ end
81
+ end
82
+ context "when the namespace does not exist" do
83
+ it "returns false" do
84
+ expect(make_backend('', "nope").namespace_exists?).to be_falsey
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#apply_resource and #read_entries" do
90
+ let(:entries) do
91
+ [
92
+ new_state("one", message: "m-one", created_at: "2022-01-01T00:00:00+00:00"),
93
+ new_state("two", message: "m-two", created_at: "2022-02-01T00:00:00+00:00"),
94
+ ]
95
+ end
96
+
97
+ it "creates a configmap with the right contents" do
98
+ subject = make_backend(namespace, namespace)
99
+ descriptor = subject.template_resource(entries)
100
+ subject.apply_resource(descriptor)
101
+ sleep(1)
102
+ actual = subject.send(:read_entries)
103
+ expect(actual.count).to eq(2)
104
+
105
+ actual_one = actual[0].values_at("tag", "message", "created_at")
106
+ expected_one = entries[0].to_h.values_at(:tag, :message, :created_at)
107
+ expect(actual_one).to eq(expected_one)
108
+ end
109
+ end
110
+ end
@@ -7,6 +7,13 @@ RSpec.describe Kerbi::CodeGen::ProjectGenerator do
7
7
  let(:project_name) { "test-project" }
8
8
  let(:dir_path) { "#{root}/#{project_name}" }
9
9
 
10
+ subject do
11
+ Kerbi::CodeGen::ProjectGenerator.new(
12
+ project_name: project_name,
13
+ root_dir: root
14
+ )
15
+ end
16
+
10
17
  before :each do
11
18
  Kerbi::Testing.reset_test_yamls_dir
12
19
  end
@@ -15,8 +22,7 @@ RSpec.describe Kerbi::CodeGen::ProjectGenerator do
15
22
  let(:expected_files) { %w[Gemfile kerbifile.rb values.yaml] }
16
23
  it "creates a new dir and writes the files" do
17
24
  expect(File.exists?(dir_path)).to be_falsey
18
- generator = klass.new(project_name: project_name, root_dir: root)
19
- generator.run
25
+ subject.run
20
26
  expect(File.exists?(dir_path)).to be_truthy
21
27
  actual = Dir.entries(dir_path)
22
28
  expect((expected_files - actual)).to be_empty
@@ -0,0 +1,112 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::EntrySet do
4
+
5
+ let(:set) do
6
+ new_state_set(
7
+ one: { created_at: Time.new(2000).to_s },
8
+ two: { created_at: Time.new(2001).to_s },
9
+ "[cand]-one".to_sym => { created_at: Time.new(2002).to_s },
10
+ "[cand]-two".to_sym => { created_at: Time.new(2003).to_s }
11
+ )
12
+ end
13
+
14
+ let(:bad_set) do
15
+ new_state_set(
16
+ "".to_sym => { },
17
+ )
18
+ end
19
+
20
+ describe "#initialize" do
21
+ it "sorts DESC on created_at" do
22
+ expect(set.entries[0].tag).to eq("[cand]-two")
23
+ end
24
+ end
25
+
26
+ describe "validate!" do
27
+ context "when there are no errors" do
28
+ it "does not raise an error" do
29
+ set.validate!
30
+ end
31
+ end
32
+
33
+ context "when there are errors" do
34
+ it "raises the right error" do
35
+ expect{
36
+ bad_set.validate!
37
+ }.to raise_exception(Kerbi::EntryValidationError)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#latest" do
43
+ it "returns the correct entry" do
44
+ expect(set.latest.tag).to eq("two")
45
+ end
46
+ end
47
+
48
+ describe "#latest_candidate" do
49
+ it "returns the correct entry" do
50
+ expect(set.latest_candidate.tag).to eq("[cand]-two")
51
+ end
52
+ end
53
+
54
+ describe "#candidates" do
55
+ it "returns the right entries" do
56
+ expected = %w[[cand]-two [cand]-one]
57
+ expect(set.candidates.map(&:tag)).to eq(expected)
58
+ end
59
+ end
60
+
61
+ describe "#committed" do
62
+ it "returns the right entries" do
63
+ expected = %w[two one]
64
+ expect(set.committed.map(&:tag)).to eq(expected)
65
+ end
66
+ end
67
+
68
+ describe "#find_entry_for_read" do
69
+ context "when the substitutions work and the entry exists" do
70
+ it "returns the right entry" do
71
+ actual = set.find_entry_for_read("two")
72
+ expect(actual.tag).to eq("two")
73
+
74
+ actual = set.find_entry_for_read("@latest")
75
+ expect(actual.tag).to eq("two")
76
+
77
+ actual = set.find_entry_for_read("@candidate")
78
+ expect(actual.tag).to eq("[cand]-two")
79
+ end
80
+ end
81
+
82
+ context "when either the resolution fails or the entry does not exist" do
83
+ it "raises Kerbi::StateNotFoundError" do
84
+ expect {
85
+ set.find_entry_for_read("three")
86
+ }.to raise_exception(Kerbi::StateNotFoundError)
87
+
88
+ expect {
89
+ set.find_entry_for_read("not-@latest")
90
+ }.to raise_exception(Kerbi::StateNotFoundError)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#find_or_init_entry_for_write" do
96
+ it "returns the right entry" do
97
+ actual = set.find_or_init_entry_for_write("two")
98
+ expect(actual.tag).to eq("two")
99
+
100
+ actual = set.find_or_init_entry_for_write("@latest")
101
+ expect(actual.tag).to eq("two")
102
+
103
+ actual = set.find_or_init_entry_for_write("@candidate")
104
+ expect(actual.tag).to eq("[cand]-two")
105
+
106
+ actual = set.find_or_init_entry_for_write("@new-candidate")
107
+ expect(actual.tag).to_not eq("[cand]-two")
108
+ expect(actual.tag).to_not be_falsey
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,109 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::Entry do
4
+
5
+ let(:subject_cls) { Kerbi::State::Entry }
6
+ let(:cand_prefix) { subject_cls::CANDIDATE_PREFIX }
7
+
8
+ let(:default_dict) do
9
+ {
10
+ tag: "tag",
11
+ message: "message",
12
+ values: {x: {y: "z"}},
13
+ default_values: {y: "z"},
14
+ created_at: "2020-01-02T03:04:00",
15
+ }
16
+ end
17
+
18
+ describe "#candiate? and #committed?" do
19
+ context "when it is a candidate" do
20
+ it "returns true for #candidate and false for #committed" do
21
+ expect(new_state("[cand]-one").candidate?).to be_truthy
22
+ expect(new_state("[cand]-one").committed?).to be_falsey
23
+ end
24
+ end
25
+ context "when it is a candidate" do
26
+ it "returns false for #candidate and true for #committed" do
27
+ expect(new_state("[cant]-one").candidate?).to be_falsey
28
+ expect(new_state("[cant]-one").committed?).to be_truthy
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#validate" do
34
+ context "when there is a tag error" do
35
+ it "finds validation errors" do
36
+ (state = new_state("")).validate
37
+ expect(state.valid?).to be_falsey
38
+
39
+ (state = new_state(" ")).validate
40
+ expect(state.valid?).to be_falsey
41
+ end
42
+ end
43
+
44
+ context "when there are zero tag errors" do
45
+ it "finds validation errors" do
46
+ (state = new_state("a")).validate
47
+ expect(state.valid?).to be_truthy
48
+
49
+ (state = new_state("|")).validate
50
+ expect(state.valid?).to be_truthy
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#promote" do
56
+ context "when the entry is a candidate" do
57
+ it "removes the [cand]- flag" do
58
+ old = (state = new_state("#{cand_prefix}foo")).promote
59
+ expect(state.tag).to eq("foo")
60
+ expect(old).to eq("#{cand_prefix}foo")
61
+ end
62
+ end
63
+
64
+ context "when the entry is not a candidate" do
65
+ it "raises" do
66
+ expect {
67
+ new_state("foo").promote
68
+ }.to raise_exception(Kerbi::StateNotPromotable)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#demote" do
74
+ context "when the entry is committed" do
75
+ it "adds the [cand]- flag" do
76
+ old = (state = new_state("foo")).demote
77
+ expect(state.tag).to eq("#{cand_prefix}foo")
78
+ expect(old).to eq("foo")
79
+ end
80
+ end
81
+
82
+ context "when the entry is not a candidate" do
83
+ it "raises" do
84
+ expect {
85
+ new_state("#{cand_prefix}foo").demote
86
+ }.to raise_exception(Kerbi::StateNotDemotable)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe ".from_dict" do
92
+ it "parses the created_at timestamp correctly" do
93
+ entry = subject_cls.from_dict(nil, default_dict)
94
+ expected = Time.new(2020, 1, 2, 3, 4, 0)
95
+ expect(entry.created_at).to eq(expected)
96
+ end
97
+ end
98
+
99
+ describe "#to_h" do
100
+ it "returns the right dict" do
101
+ entry = new_state("foo", default_dict)
102
+ actual = entry.to_h
103
+ actual.delete(:created_at)
104
+ expect = default_dict.deep_dup
105
+ expect.delete(:created_at)
106
+ expect(actual).to eq(expect)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,5 @@
1
+ metadata:
2
+ annotations:
3
+ author: person
4
+ labels:
5
+ app: hello-kerbi
@@ -0,0 +1,5 @@
1
+ module HelloKerbi
2
+ module Consts
3
+ APP_NAME = "hello-kerbi"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module HelloKerbi
2
+ module Helpers
3
+ def img2alpine(img_name)
4
+ return img_name if img_name.include?(":")
5
+ "#{img_name}:alpine"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'consts'
2
+ require_relative 'helpers'
3
+
4
+ module HelloKerbi
5
+ class Mixer < Kerbi::Mixer
6
+ include Helpers
7
+
8
+ locate_self __dir__
9
+
10
+ def mix
11
+ patched_with file("common/metadata") do
12
+ push file("pod-and-service")
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ Kerbi::Globals.mixers << HelloKerbi::Mixer
@@ -0,0 +1,23 @@
1
+ apiVersion: v1
2
+ kind: Pod
3
+ metadata:
4
+ name: <%= HelloKerbi::Consts::APP_NAME %>
5
+ namespace: <%= release_name %>
6
+ spec:
7
+ containers:
8
+ - name: main
9
+ image: <%= img2alpine(values[:pod][:image]) %>
10
+
11
+ ---
12
+
13
+ apiVersion: v1
14
+ kind: Service
15
+ metadata:
16
+ name: <%= HelloKerbi::Consts::APP_NAME %>
17
+ namespace: <%= release_name %>
18
+ spec:
19
+ type: <%= values[:service][:type] %>
20
+ selector:
21
+ app: <%= HelloKerbi::Consts::APP_NAME %>
22
+ ports:
23
+ - port: 80
@@ -0,0 +1,2 @@
1
+ service:
2
+ type: LoadBalancer
@@ -0,0 +1,2 @@
1
+ pod:
2
+ image: nginx:1.20
@@ -0,0 +1,4 @@
1
+ pod:
2
+ image: nginx
3
+ service:
4
+ type: ClusterIP
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,149 @@ SimpleCov.start
5
5
 
6
6
  require_relative './../lib/kerbi'
7
7
 
8
+ def run_opts
9
+ Kerbi::RunOpts.new({}, Kerbi::Consts::OptionDefaults::BASE)
10
+ end
11
+
12
+ # @param [String] namespace
13
+ # @return [Kerbi::State::ConfigMapBackend]
14
+ def make_backend(release_name, namespace=nil)
15
+ auth_bundle = Kerbi::Utils::Cli.make_k8s_auth_bundle(run_opts)
16
+ Kerbi::State::ConfigMapBackend.new(auth_bundle, release_name, namespace)
17
+ end
18
+
19
+ # @return [Kubeclient::Client]
20
+ def make_kube_client(api_name)
21
+ auth_bundle = Kerbi::Utils::Cli.make_k8s_auth_bundle(run_opts)
22
+ Kubeclient::Client.new(
23
+ auth_bundle[:endpoint],
24
+ api_name,
25
+ **auth_bundle[:options]
26
+ )
27
+ end
28
+
29
+ def create_ns(name)
30
+ dict = { metadata: { name: name } }
31
+ begin
32
+ #noinspection RubyResolve
33
+ make_kube_client("v1").create_namespace(dict)
34
+ rescue Kubeclient::HttpError
35
+ true
36
+ end
37
+ end
38
+
39
+ def delete_cm(name, namespace)
40
+ begin
41
+ #noinspection RubyResolve
42
+ make_kube_client("v1").delete_config_map(name, namespace)
43
+ begin
44
+ sleep(1)
45
+ #noinspection RubyResolve
46
+ exists = client.get_config_map(name, namespace) rescue nil
47
+ end while exists
48
+ rescue Kubeclient::ResourceNotFoundError
49
+ true
50
+ end
51
+ end
52
+
53
+ def delete_ns(name)
54
+ begin
55
+ #noinspection RubyResolve
56
+ (client = make_kube_client("v1")).delete_namespace(name)
57
+ begin
58
+ sleep(1)
59
+ exists = client.get_namespace(name) rescue nil
60
+ end while exists
61
+ rescue Kubeclient::ResourceNotFoundError
62
+ true
63
+ end
64
+ end
65
+
66
+ def corrupt_cm(backend)
67
+ cm_body = backend.template_resource([])
68
+ cm_body[:data][:entries] = "not json"
69
+ backend.send(:client).update_config_map(cm_body)
70
+ end
71
+
72
+ def new_state(tag, dict={})
73
+ set = dict.delete(:state)
74
+ dict[:tag] = tag
75
+ Kerbi::State::Entry.from_dict(set, dict)
76
+ end
77
+
78
+ def new_state_set(bundles)
79
+ dicts = bundles.map { |kv| { tag: kv[0].to_s, **kv[1] } }
80
+ Kerbi::State::EntrySet.new(dicts)
81
+ end
82
+
83
+ def cli(command, escaped: false)
84
+ $stdout = StringIO.new
85
+ begin
86
+ command = command.split(" ") if command.is_a?(String)
87
+ Kerbi::Cli::RootHandler.start(command)
88
+ output = $stdout.string
89
+ $stdout = STDOUT
90
+ escaped ? output.gsub("\e", "\\e") : output
91
+ ensure
92
+ $stdout = STDOUT
93
+ end
94
+ end
95
+
96
+ def load_exp_file(dir, file, ext)
97
+ path = "#{__dir__}/fixtures/expectations/#{dir}/#{file}.#{ext}"
98
+ File.read(path)
99
+ end
100
+
101
+ def read_exp_file(dir, file, ext)
102
+ expected_str = load_exp_file(dir, file, ext)
103
+ if ext == 'json'
104
+ JSON.parse(expected_str)
105
+ elsif ext == 'yaml'
106
+ YAML.load_stream(expected_str)
107
+ else
108
+ expected_str.gsub(/\s+/, "")
109
+ end
110
+ end
111
+
112
+ def exp_cli_eq_file(cmd, dir, file, ext='txt')
113
+ actual_str = cli(cmd)
114
+ expected = read_exp_file(dir, file, ext)
115
+
116
+ if ext == 'json'
117
+ expect(JSON.parse(actual_str)).to eq(expected)
118
+ elsif ext == 'yaml'
119
+ actual = YAML.load_stream(actual_str) rescue 0
120
+ if actual != 0
121
+ expect(actual).to eq(expected)
122
+ else
123
+ puts actual_str
124
+ raise "CMD #{cmd} echoed non-YAML (above)"
125
+ end
126
+ else
127
+ actual = actual_str.gsub(/\s+/, "").gsub("\e", "\\e")
128
+ expect(actual).to eq(expected)
129
+ end
130
+ end
131
+
132
+ def hello_kerbi(cmd, namespace=nil)
133
+ target = "#{__dir__}/mini-projects/hello-kerbi"
134
+ cmd = "#{cmd} --project-root #{target}"
135
+ cmd = "#{cmd} --namespace #{namespace}" if namespace
136
+ cmd
137
+ end
138
+
139
+ def cmd_group_spec(cmd, dir, file, opts={})
140
+ (opts[:formats] || %w[yaml json table]).each do |format|
141
+ context "with --output-format #{format} #{opts[:context_append]}" do
142
+ it "echos the expected text" do
143
+ extension = format == 'table' ? "txt" : format
144
+ cmd_with_fmt = "#{cmd} -o #{format}"
145
+ exp_cli_eq_file(cmd_with_fmt, dir, file, extension)
146
+ end
147
+ end
148
+ end
149
+ end
150
+
8
151
  module Kerbi
9
152
  module Testing
10
153
 
@@ -33,7 +176,6 @@ module Kerbi
33
176
  system "rm -rf #{TEST_YAMLS_DIR}"
34
177
  system "mkdir #{TEST_YAMLS_DIR}"
35
178
  end
36
-
37
179
  end
38
180
  end
39
181