minfra-cli 0.1.0

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +12 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG.md +2 -0
  6. data/Dockerfile +12 -0
  7. data/bin/build +20 -0
  8. data/bin/console +16 -0
  9. data/bin/container_exec +9 -0
  10. data/bin/run_tests +74 -0
  11. data/bin/setup.sh +22 -0
  12. data/exe/minfra +6 -0
  13. data/lib/deep_merge.rb +149 -0
  14. data/lib/hash.rb +28 -0
  15. data/lib/minfra/cli/ask.rb +43 -0
  16. data/lib/minfra/cli/command.rb +35 -0
  17. data/lib/minfra/cli/commands/dev.rb +54 -0
  18. data/lib/minfra/cli/commands/kube.rb +279 -0
  19. data/lib/minfra/cli/commands/project/branch.rb +17 -0
  20. data/lib/minfra/cli/commands/project/tag.rb +40 -0
  21. data/lib/minfra/cli/commands/project.rb +113 -0
  22. data/lib/minfra/cli/commands/setup.rb +49 -0
  23. data/lib/minfra/cli/commands/stack/app_template.rb +65 -0
  24. data/lib/minfra/cli/commands/stack/client_template.rb +36 -0
  25. data/lib/minfra/cli/commands/stack/kube_stack_template.rb +94 -0
  26. data/lib/minfra/cli/commands/stack.rb +120 -0
  27. data/lib/minfra/cli/commands/tag.rb +86 -0
  28. data/lib/minfra/cli/common.rb +41 -0
  29. data/lib/minfra/cli/config.rb +111 -0
  30. data/lib/minfra/cli/document.rb +19 -0
  31. data/lib/minfra/cli/hook.rb +65 -0
  32. data/lib/minfra/cli/logging.rb +26 -0
  33. data/lib/minfra/cli/main_command.rb +32 -0
  34. data/lib/minfra/cli/plugins.rb +34 -0
  35. data/lib/minfra/cli/runner.rb +59 -0
  36. data/lib/minfra/cli/templater.rb +63 -0
  37. data/lib/minfra/cli/version.rb +5 -0
  38. data/lib/minfra/cli.rb +80 -0
  39. data/lib/orchparty/ast.rb +53 -0
  40. data/lib/orchparty/cli.rb +69 -0
  41. data/lib/orchparty/context.rb +22 -0
  42. data/lib/orchparty/dsl_parser.rb +229 -0
  43. data/lib/orchparty/dsl_parser_kubernetes.rb +361 -0
  44. data/lib/orchparty/kubernetes_application.rb +305 -0
  45. data/lib/orchparty/plugin.rb +24 -0
  46. data/lib/orchparty/plugins/env.rb +41 -0
  47. data/lib/orchparty/transformations/all.rb +18 -0
  48. data/lib/orchparty/transformations/mixin.rb +73 -0
  49. data/lib/orchparty/transformations/remove_internal.rb +16 -0
  50. data/lib/orchparty/transformations/sort.rb +10 -0
  51. data/lib/orchparty/transformations/variable.rb +56 -0
  52. data/lib/orchparty/transformations.rb +24 -0
  53. data/lib/orchparty/version.rb +3 -0
  54. data/lib/orchparty.rb +59 -0
  55. data/minfra-cli.gemspec +40 -0
  56. data/project.json +7 -0
  57. data/templates/kind.yaml.erb +33 -0
  58. data/templates/kube_config.yaml.erb +7 -0
  59. data/templates/minfra_config.json.erb +26 -0
  60. metadata +196 -0
@@ -0,0 +1,361 @@
1
+ require 'pathname'
2
+ require 'securerandom'
3
+ module Orchparty
4
+ module Kubernetes
5
+ class DSLParser
6
+ attr_reader :filename
7
+
8
+ def initialize(filename)
9
+ @filename = filename
10
+ end
11
+
12
+ def parse
13
+ file_content = File.read(filename)
14
+ builder = RootBuilder.new
15
+ builder.instance_eval(file_content, filename)
16
+ builder._build
17
+ end
18
+ end
19
+
20
+ class Builder
21
+ def self.build(*args, block)
22
+ builder = self.new(*args)
23
+ builder.instance_eval(&block) if block
24
+ builder._build
25
+ end
26
+
27
+ def assign_or_merge(node, key, value)
28
+ if node[key]
29
+ node[key] = node[key].deep_merge_concat(value)
30
+ else
31
+ node[key] = value
32
+ end
33
+ end
34
+ end
35
+
36
+ class RootBuilder < Builder
37
+
38
+ def initialize
39
+ @root = AST.root
40
+ end
41
+
42
+ def import(rel_file)
43
+ old_file_path = Pathname.new(caller[0][/[^:]+/]).parent
44
+ rel_file_path = Pathname.new rel_file
45
+ new_file_path = old_file_path + rel_file_path
46
+ file_content = File.read(new_file_path)
47
+ instance_eval(file_content, new_file_path.expand_path.to_s)
48
+ end
49
+
50
+ def application(name, &block)
51
+ @root.applications[name] = ApplicationBuilder.build(name, block)
52
+ self
53
+ end
54
+
55
+ def mixin(name, &block)
56
+ @root._mixins[name] = MixinBuilder.build(name, block)
57
+ self
58
+ end
59
+
60
+ def _build
61
+ @root
62
+ end
63
+ end
64
+
65
+ class MixinBuilder < Builder
66
+
67
+ def initialize(name)
68
+ @mixin = AST.mixin(name: name)
69
+ end
70
+
71
+ def template(path)
72
+ chart_name = "_mixin_temp_name"
73
+ unless @mixin.services[chart_name]
74
+ @mixin.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
75
+ @mixin._service_order << chart_name
76
+ end
77
+ chart = @mixin.services[chart_name]
78
+ chart.template = path
79
+ self
80
+ end
81
+
82
+ def service(name, &block)
83
+
84
+ chart_name = "_mixin_temp_name"
85
+ unless @mixin.services[chart_name]
86
+ @mixin.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
87
+ @mixin._service_order << chart_name
88
+ end
89
+ chart = @mixin.services[chart_name]
90
+
91
+ result = ServiceBuilder.build(name, "chart-service", block)
92
+
93
+ name = "chart-#{chart.name}-#{name}"
94
+ @mixin.services[name] = result
95
+ @mixin._service_order << name
96
+ chart._services << name
97
+ self
98
+ end
99
+
100
+ def helm(name, &block)
101
+ result = ServiceBuilder.build(name, "helm", block)
102
+ @mixin.services[name] = result
103
+ @mixin._mixins[name] = result
104
+ self
105
+ end
106
+
107
+
108
+ def apply(name, &block)
109
+ result = ServiceBuilder.build(name, "apply", block)
110
+ @mixin.services[name] = result
111
+ @mixin._mixins[name] = result
112
+ self
113
+ end
114
+
115
+ def mixin(name, &block)
116
+ @mixin._mixins[name] = ServiceMixinBuilder.build(name, block)
117
+ end
118
+
119
+ def volumes(&block)
120
+ @mixin.volumes = HashBuilder.build(block)
121
+ end
122
+
123
+ def networks(&block)
124
+ @mixin.networks = HashBuilder.build(block)
125
+ end
126
+
127
+ def _build
128
+ @mixin
129
+ end
130
+ end
131
+
132
+ class ApplicationBuilder < Builder
133
+
134
+ def initialize(name)
135
+ @application = AST.application(name: name)
136
+ end
137
+
138
+ def mix(name)
139
+ @application._mix << name
140
+ end
141
+
142
+ def mixin(name, &block)
143
+ @application._mixins[name] = ApplicationMixinBuilder.build(block)
144
+ self
145
+ end
146
+
147
+ def all(&block)
148
+ @application.all = AllBuilder.build(block)
149
+ self
150
+ end
151
+
152
+ def variables(&block)
153
+ @application._variables = VariableBuilder.build(block)
154
+ self
155
+ end
156
+
157
+ def volumes(&block)
158
+ @application.volumes = HashBuilder.build(block)
159
+ self
160
+ end
161
+
162
+ def helm(name, &block)
163
+ result = ServiceBuilder.build(name, "helm", block)
164
+ @application.services[name] = result
165
+ @application._service_order << name
166
+ self
167
+ end
168
+
169
+ def label(&block)
170
+ name = SecureRandom.hex
171
+ result = ServiceWithoutNameBuilder.build("label", block)
172
+ @application.services[name] = result
173
+ @application._service_order << name
174
+ self
175
+ end
176
+
177
+ def apply(name, &block)
178
+ result = ServiceBuilder.build(name, "apply", block)
179
+ @application.services[name] = result
180
+ @application._service_order << name
181
+ self
182
+ end
183
+
184
+ def secret_generic(name, &block)
185
+ result = ServiceBuilder.build(name, "secret_generic", block)
186
+ @application.services[name] = result
187
+ @application._service_order << name
188
+ self
189
+ end
190
+
191
+ def wait(&block)
192
+ name = SecureRandom.hex
193
+ result = ServiceBuilder.build(name, "wait", block)
194
+ @application.services[name] = result
195
+ @application._service_order << name
196
+ self
197
+ end
198
+
199
+ def chart(name, &block)
200
+ @application.services[name] = ChartBuilder.build(name, @application, "chart", block)
201
+ @application._service_order << name
202
+ self
203
+ end
204
+
205
+ def template(path)
206
+ chart_name = @application.name
207
+ unless @application.services[chart_name]
208
+ @application.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
209
+ @application._service_order << chart_name
210
+ end
211
+ chart = @application.services[chart_name]
212
+ chart.template = path
213
+ self
214
+ end
215
+
216
+ def service(name, &block)
217
+
218
+ chart_name = @application.name
219
+ unless @application.services[chart_name]
220
+ @application.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
221
+ @application._service_order << chart_name
222
+ end
223
+ chart = @application.services[chart_name]
224
+
225
+ result = ServiceBuilder.build(name, "chart-service", block)
226
+
227
+ name = "chart-#{chart.name}-#{name}"
228
+ @application.services[name] = result
229
+ @application._service_order << name
230
+ chart._services << name
231
+ self
232
+ end
233
+
234
+ def _build
235
+ @application
236
+ end
237
+ end
238
+
239
+ class HashBuilder < Builder
240
+
241
+ def method_missing(_, *values, &block)
242
+ if block_given?
243
+ value = HashBuilder.build(block)
244
+ if values.count == 1
245
+ @hash ||= AST.hash
246
+ @hash[values.first.to_sym] = value
247
+ else
248
+ @hash ||= AST.array
249
+ @hash << value
250
+ end
251
+ else
252
+ value = values.first
253
+ if value.is_a? Hash
254
+ @hash ||= AST.hash
255
+ key, value = value.first
256
+ begin
257
+ @hash[key.to_sym] = value
258
+ rescue
259
+ warn "Problem with key: #{key} #{value}"
260
+ raise
261
+ end
262
+
263
+ else
264
+ @hash ||= AST.array
265
+ @hash << value
266
+ end
267
+ end
268
+ self
269
+ end
270
+
271
+ def _build
272
+ @hash
273
+ end
274
+ end
275
+
276
+ class VariableBuilder < HashBuilder
277
+ def _build
278
+ super || {}
279
+ end
280
+ end
281
+
282
+ class CommonBuilder < Builder
283
+
284
+ def initialize(node)
285
+ @node = node
286
+ end
287
+
288
+ def mix(name)
289
+ @node._mix << name
290
+ end
291
+
292
+ def method_missing(name, *values, &block)
293
+ if block_given?
294
+ assign_or_merge(@node, name, HashBuilder.build(block))
295
+ else
296
+ assign_or_merge(@node, name, values.first)
297
+ end
298
+ end
299
+
300
+ def _build
301
+ @node
302
+ end
303
+
304
+ def variables(&block)
305
+ @node._variables ||= {}
306
+ @node._variables = @node._variables.merge(VariableBuilder.build(block))
307
+ self
308
+ end
309
+ end
310
+
311
+ class AllBuilder < CommonBuilder
312
+ def initialize
313
+ super AST.all
314
+ end
315
+ end
316
+
317
+ class ApplicationMixinBuilder < CommonBuilder
318
+ def initialize
319
+ super AST.application_mixin
320
+ end
321
+ end
322
+
323
+ class ServiceWithoutNameBuilder < CommonBuilder
324
+
325
+ def initialize( type)
326
+ super AST.service(_type: type)
327
+ end
328
+ end
329
+
330
+ class ServiceBuilder < CommonBuilder
331
+
332
+ def initialize(name, type)
333
+ super AST.service(name: name, _type: type)
334
+ end
335
+ end
336
+
337
+ class ServiceMixinBuilder < CommonBuilder
338
+
339
+ def initialize(name)
340
+ super AST.service(name: name)
341
+ end
342
+ end
343
+
344
+ class ChartBuilder < CommonBuilder
345
+ def initialize(name, application, type)
346
+ super AST.chart(name: name, _type: type )
347
+ @application = application
348
+ end
349
+
350
+ def service(name, &block)
351
+ result = ServiceBuilder.build(name, "chart-service", block)
352
+
353
+ name = "chart-#{@node.name}-#{name}"
354
+ @application.services[name] = result
355
+ @application._service_order << name
356
+ @node._services << name
357
+ self
358
+ end
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,305 @@
1
+ require 'erb'
2
+ require 'erubis'
3
+ require 'open3'
4
+ require 'ostruct'
5
+ require 'yaml'
6
+ require 'tempfile'
7
+ require 'active_support'
8
+ require 'active_support/core_ext'
9
+
10
+ module Orchparty
11
+ module Services
12
+ class Context
13
+ attr_accessor :cluster_name
14
+ attr_accessor :namespace
15
+ attr_accessor :dir_path
16
+ attr_accessor :app_config
17
+ attr_accessor :options
18
+
19
+ def initialize(cluster_name: , namespace:, file_path: , app_config:, out_io: STDOUT)
20
+ self.cluster_name = cluster_name
21
+ self.namespace = namespace
22
+ self.dir_path = file_path
23
+ self.app_config = app_config
24
+ @out_io = out_io
25
+ self.options=options
26
+ end
27
+
28
+ def template(file_path, helm, flag: "-f ", fix_file_path: nil)
29
+ return "" unless file_path
30
+ puts "Rendering: #{file_path}"
31
+ file_path = File.join(self.dir_path, file_path)
32
+ if(file_path.end_with?(".erb"))
33
+ helm.application = OpenStruct.new(cluster_name: cluster_name, namespace: namespace)
34
+ template = Erubis::Eruby.new(File.read(file_path))
35
+ yaml = template.result(helm.get_binding)
36
+ file = Tempfile.new("kube-deploy.yaml")
37
+ file.write(yaml)
38
+ file.close
39
+ file_path = file.path
40
+ end
41
+ "#{flag}#{fix_file_path || file_path}"
42
+ end
43
+
44
+ def print_install(helm)
45
+ @out_io.puts "---"
46
+ @out_io.puts install_cmd(helm, value_path(helm))
47
+ @out_io.puts upgrade_cmd(helm, value_path(helm))
48
+ @out_io.puts "---"
49
+ @out_io.puts File.read(template(value_path(helm), helm, flag: "")) if value_path(helm)
50
+ end
51
+
52
+ # On 05.02.2021 we have decided that it would be best to print both commands.
53
+ # This way it would be possible to debug both upgrade and install and also people would not see git diffs all the time.
54
+ def print_upgrade(helm)
55
+ print_install(helm)
56
+ end
57
+
58
+ def upgrade(helm)
59
+ @out_io.puts system(upgrade_cmd(helm))
60
+ end
61
+
62
+ def install(helm)
63
+ @out_io.puts system(install_cmd(helm))
64
+ end
65
+ end
66
+
67
+ class Helm < Context
68
+ def value_path(helm)
69
+ helm[:values]
70
+ end
71
+
72
+ def upgrade_cmd(helm, fix_file_path = nil)
73
+ "helm upgrade --namespace #{namespace} --kube-context #{cluster_name} --version #{helm.version} #{helm.name} #{helm.chart} #{template(value_path(helm), helm, fix_file_path: fix_file_path)}"
74
+ end
75
+
76
+ def install_cmd(helm, fix_file_path = nil)
77
+ "helm install --create-namespace --namespace #{namespace} --kube-context #{cluster_name} --version #{helm.version} #{helm.name} #{helm.chart} #{template(value_path(helm), helm, fix_file_path: fix_file_path)}"
78
+ end
79
+ end
80
+
81
+ class Apply < Context
82
+ def value_path(apply)
83
+ apply[:name]
84
+ end
85
+
86
+ def upgrade_cmd(apply, fix_file_path = nil)
87
+ "kubectl apply --namespace #{namespace} --context #{cluster_name} #{template(value_path(apply), apply, fix_file_path: fix_file_path)}"
88
+ end
89
+
90
+ def install_cmd(apply, fix_file_path = nil)
91
+ "kubectl apply --namespace #{namespace} --context #{cluster_name} #{template(value_path(apply), apply, fix_file_path: fix_file_path)}"
92
+ end
93
+ end
94
+
95
+ class SecretGeneric < Context
96
+ def value_path(secret)
97
+ secret[:from_file]
98
+ end
99
+
100
+ def upgrade_cmd(secret, fix_file_path=nil)
101
+ "kubectl --namespace #{namespace} --context #{cluster_name} create secret generic --dry-run -o yaml #{secret[:name]} #{template(value_path(secret), secret, flag: "--from-file=", fix_file_path: fix_file_path)} | kubectl --context #{cluster_name} apply -f -"
102
+ end
103
+
104
+ def install_cmd(secret, fix_file_path=nil)
105
+ "kubectl --namespace #{namespace} --context #{cluster_name} create secret generic --dry-run -o yaml #{secret[:name]} #{template(value_path(secret), secret, flag: "--from-file=", fix_file_path: fix_file_path)} | kubectl --context #{cluster_name} apply -f -"
106
+ end
107
+ end
108
+
109
+ class Label < Context
110
+ def print_install(label)
111
+ @out_io.puts "---"
112
+ @out_io.puts install_cmd(label)
113
+ end
114
+
115
+ def print_upgrade(label)
116
+ @out_io.puts "---"
117
+ @out_io.puts upgrade_cmd(label)
118
+ end
119
+
120
+ def upgrade(label)
121
+ @out_io.puts system(upgrade_cmd(label))
122
+ end
123
+
124
+ def install(label)
125
+ @out_io.puts system(install_cmd(label))
126
+ end
127
+
128
+ def upgrade_cmd(label)
129
+ "kubectl --namespace #{namespace} --context #{cluster_name} label --overwrite #{label[:resource]} #{label[:name]} #{label["value"]}"
130
+ end
131
+
132
+ def install_cmd(label)
133
+ "kubectl --namespace #{namespace} --context #{cluster_name} label --overwrite #{label[:resource]} #{label[:name]} #{label["value"]}"
134
+ end
135
+ end
136
+
137
+ class Wait < Context
138
+ def print_install(wait)
139
+ @out_io.puts "---"
140
+ @out_io.puts wait.cmd
141
+ end
142
+
143
+ def print_upgrade(wait)
144
+ @out_io.puts "---"
145
+ @out_io.puts wait.cmd
146
+ end
147
+
148
+ def upgrade(wait)
149
+ eval(wait.cmd)
150
+ end
151
+
152
+ def install(wait)
153
+ eval(wait.cmd)
154
+ end
155
+ end
156
+
157
+ class Chart < Context
158
+ class CleanBinding
159
+ def get_binding(params)
160
+ params.instance_eval do
161
+ binding
162
+ end
163
+ end
164
+ end
165
+
166
+ def build_chart(chart)
167
+ params = chart._services.map {|s| app_config.services[s.to_sym] }.map{|s| [s.name, s]}.to_h
168
+ Dir.mktmpdir do |dir|
169
+ run(templates_path: File.expand_path(chart.template, self.dir_path), params: params, output_chart_path: dir, chart: chart)
170
+ yield dir
171
+ end
172
+ end
173
+
174
+ def run(templates_path:, params:, output_chart_path:, chart: )
175
+ system("mkdir -p #{output_chart_path}")
176
+ system("mkdir -p #{File.join(output_chart_path, 'templates')}")
177
+
178
+ system("cp #{File.join(templates_path, 'values.yaml')} #{File.join(output_chart_path, 'values.yaml')}")
179
+ system("cp #{File.join(templates_path, '.helmignore')} #{File.join(output_chart_path, '.helmignore')}")
180
+ system("cp #{File.join(templates_path, 'templates/_helpers.tpl')} #{File.join(output_chart_path, 'templates/_helpers.tpl')}")
181
+
182
+ generate_chart_yaml(
183
+ templates_path: templates_path,
184
+ output_chart_path: output_chart_path,
185
+ chart_name: chart.name,
186
+ )
187
+
188
+ params.each do |app_name, subparams|
189
+ subparams[:chart] = chart
190
+ generate_documents_from_erbs(
191
+ templates_path: templates_path,
192
+ app_name: app_name,
193
+ params: subparams,
194
+ output_chart_path: output_chart_path
195
+ )
196
+ end
197
+ end
198
+
199
+ def generate_documents_from_erbs(templates_path:, app_name:, params:, output_chart_path:)
200
+ if params[:kind].nil?
201
+ warn "ERROR: Could not generate service '#{app_name}'. Missing key: 'kind'."
202
+ exit 1
203
+ end
204
+
205
+ kind = params.fetch(:kind)
206
+
207
+ Dir[File.join(templates_path, kind, '*.erb')].each do |template_path|
208
+ template_name = File.basename(template_path, '.erb')
209
+ output_path = File.join(output_chart_path, 'templates', "#{app_name}-#{template_name}")
210
+
211
+ template = Erubis::Eruby.new(File.read(template_path))
212
+ params.app_name = app_name
213
+ params.templates_path = templates_path
214
+ begin
215
+ document = template.result(CleanBinding.new.get_binding(params))
216
+ rescue Exception
217
+ puts "#{template_path} has a problem: #{$!.inspect}"
218
+ raise
219
+ end
220
+ File.write(output_path, document)
221
+ end
222
+ end
223
+
224
+ def generate_chart_yaml(templates_path:, output_chart_path:, chart_name: )
225
+ template_path = File.join(templates_path, 'Chart.yaml.erb')
226
+ output_path = File.join(output_chart_path, 'Chart.yaml')
227
+
228
+ template = Erubis::Eruby.new(File.read(template_path))
229
+ params = Hashie::Mash.new(chart_name: chart_name)
230
+ document = template.result(CleanBinding.new.get_binding(params))
231
+ File.write(output_path, document)
232
+ end
233
+
234
+ def print_install(chart)
235
+ build_chart(chart) do |chart_path|
236
+ @out_io.puts `helm template --namespace #{namespace} --kube-context #{cluster_name} #{chart.name} #{chart_path}`
237
+ end
238
+ end
239
+
240
+ def print_upgrade(chart)
241
+ print_install(chart)
242
+ end
243
+
244
+ def install(chart)
245
+ build_chart(chart) do |chart_path|
246
+ @out_io.puts system("helm install --create-namespace --namespace #{namespace} --kube-context #{cluster_name} #{chart.name} #{chart_path}")
247
+ end
248
+ end
249
+
250
+ def upgrade(chart)
251
+ build_chart(chart) do |chart_path|
252
+ @out_io.puts system("helm upgrade --namespace #{namespace} --kube-context #{cluster_name} #{chart.name} #{chart_path}")
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ class KubernetesApplication
260
+ attr_accessor :cluster_name
261
+ attr_accessor :file_path
262
+ attr_accessor :namespace
263
+ attr_accessor :app_config
264
+
265
+ def initialize(app_config: [], namespace:, cluster_name:, file_name:, out_io: STDOUT)
266
+ self.file_path = Pathname.new(file_name).parent.expand_path
267
+ self.cluster_name = cluster_name
268
+ self.namespace = namespace
269
+ self.app_config = app_config
270
+ @out_io= out_io
271
+ end
272
+
273
+ def install
274
+ each_service(:install)
275
+ end
276
+
277
+ def upgrade
278
+ each_service(:upgrade)
279
+ end
280
+
281
+ def print(method)
282
+ each_service("print_#{method}".to_sym)
283
+ end
284
+
285
+ def combine_charts(app_config)
286
+ services = app_config._service_order.map(&:to_s)
287
+ app_config._service_order.each do |name|
288
+ current_service = app_config[:services][name]
289
+ if current_service._type == "chart"
290
+ current_service._services.each do |n|
291
+ services.delete n.to_s
292
+ end
293
+ end
294
+ end
295
+ services
296
+ end
297
+
298
+ def each_service(method)
299
+ services = combine_charts(app_config)
300
+ services.each do |name|
301
+ service = app_config[:services][name]
302
+ "::Orchparty::Services::#{service._type.classify}".constantize.new(cluster_name: cluster_name, namespace: namespace, file_path: file_path, app_config: app_config, out_io: @out_io).send(method, service)
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,24 @@
1
+ module Orchparty
2
+ module Plugin
3
+ @plugins = {}
4
+
5
+ def self.load_plugin(name)
6
+ begin
7
+ require "orchparty/plugins/#{name}"
8
+ raise "Plugin didn't correctly register itself" unless @plugins[name]
9
+ @plugins[name]
10
+ rescue LoadError
11
+ puts "could not load the plugin #{name}, you might install it as a gem or you need to write it by your self ;)"
12
+ false
13
+ end
14
+ end
15
+
16
+ def self.plugins
17
+ @plugins
18
+ end
19
+
20
+ def self.register_plugin(name, mod)
21
+ @plugins[name] = mod
22
+ end
23
+ end
24
+ end