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
data/lib/minfra/cli.rb ADDED
@@ -0,0 +1,80 @@
1
+ require 'thor'
2
+ require 'open3'
3
+ require 'json'
4
+ require 'ostruct'
5
+ require 'orchparty'
6
+
7
+ require_relative 'cli/logging'
8
+ require_relative 'cli/config'
9
+ require_relative 'cli/version'
10
+ require_relative 'cli/hook'
11
+ require_relative 'cli/common'
12
+ require_relative 'cli/command'
13
+ require_relative 'cli/templater'
14
+ require_relative 'cli/ask'
15
+ require_relative 'cli/document'
16
+ require_relative 'cli/runner'
17
+ require_relative 'cli/plugins'
18
+
19
+ require 'active_support'
20
+ require 'active_support/core_ext'
21
+
22
+ require "ENV['MINFRA_PATH']/config/preload.rb" if File.exist?("ENV['MINFRA_PATH']/config/preload.rb")
23
+
24
+ module Minfra
25
+ module Cli
26
+ extend Minfra::Cli::Logging
27
+
28
+ def self.root_path
29
+ Pathname.new(File.expand_path(File.join(__FILE__, '../../../')))
30
+ end
31
+
32
+ def self.config
33
+ @config ||= Config.new
34
+ end
35
+ def self.scan
36
+ root_path.join("lib/minfra/cli/commands").each_child do |command_path|
37
+ require command_path if command_path.to_s.match(/\.rb$/) && !command_path.to_s.match(/\#/)
38
+ end
39
+ # this is like railties but their called minfracs
40
+ $LOAD_PATH.each do |path|
41
+ minfra_path = Pathname.new(path).join("..","minfracs","init.rb")
42
+ if minfra_path.exist?
43
+ require minfra_path # this should register the command
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.register(subcommand,info,command)
49
+ #debug("Registered command #{subcommand}")
50
+ @subcommands ||= {}
51
+ @subcommands[subcommand.to_sym]= OpenStruct.new(name: subcommand, info: info, command: command)
52
+ end
53
+
54
+ def self.resolve
55
+ @subcommands.values.each do |sub|
56
+ Minfra::Cli::Main.desc(sub.name,sub.info)
57
+ Minfra::Cli::Main.subcommand(sub.name,sub.command)
58
+ end
59
+ end
60
+
61
+ def self.subcommand(name)
62
+ @subcommands[name.to_sym]&.command
63
+ end
64
+
65
+ def self.before_hook(subcommand, command, &block)
66
+ subcommand(subcommand).before_hook(command, &block)
67
+ end
68
+
69
+ def self.after_hook(subcommand, command, &block)
70
+ subcommand(subcommand).after_hook(command, &block)
71
+ end
72
+ end
73
+ end
74
+
75
+ Minfra::Cli::Plugins.load
76
+ Minfra::Cli.scan
77
+ require_relative 'cli/main_command'
78
+ Minfra::Cli.resolve
79
+
80
+
@@ -0,0 +1,53 @@
1
+ require 'hashie'
2
+
3
+ module Orchparty
4
+ class AST
5
+ class Node < ::Hashie::Mash
6
+ include Hashie::Extensions::DeepMerge
7
+ include Hashie::Extensions::DeepMergeConcat
8
+ include Hashie::Extensions::MethodAccess
9
+ include Hashie::Extensions::Mash::KeepOriginalKeys
10
+ disable_warnings
11
+
12
+ def get_binding
13
+ binding
14
+ end
15
+ end
16
+
17
+ def self.hash(args = {})
18
+ Node.new.merge(args)
19
+ end
20
+
21
+ def self.array(args = [])
22
+ args
23
+ end
24
+
25
+ def self.root(args = {})
26
+ Node.new(applications: {}, _mixins: {}).merge(args)
27
+ end
28
+
29
+ def self.mixin(args = {})
30
+ Node.new({services: {}, _mixins: {}, volumes: {}, _variables: {}, networks: {}, _service_order: []}).merge(args)
31
+ end
32
+
33
+ def self.application(args = {})
34
+ Node.new({services: {}, _mixins: {}, _mix:[], volumes: {}, _variables: {}, networks: {}, _service_order: []}).merge(args)
35
+ end
36
+
37
+ def self.all(args = {})
38
+ Node.new(_mix:[], _variables: {}).merge(args)
39
+ end
40
+
41
+ def self.application_mixin(args = {})
42
+ Node.new(_mix:[], _variables: {}).merge(args)
43
+ end
44
+
45
+ def self.service(args = {})
46
+ Node.new(_mix:[], _variables: {}).merge(args)
47
+ end
48
+
49
+ def self.chart(args = {})
50
+ Node.new(_mix:[], _variables: {}, _services: []).merge(args)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,69 @@
1
+ require 'orchparty'
2
+ require 'gli'
3
+
4
+ Orchparty.load_all_available_plugins
5
+
6
+ class OrchPartyApp
7
+ extend GLI::App
8
+
9
+ program_desc 'Write your orchestration configuration with a Ruby DSL that allows you to have mixins, imports and variables.'
10
+ version Orchparty::VERSION
11
+
12
+ subcommand_option_handling :normal
13
+
14
+ desc "install kubernetes application"
15
+ command :print do |com|
16
+ com.flag [:cluster_name,:c,'cluster-name'], required: true, :desc => 'The cluster to install the app'
17
+ com.flag [:filename,:f,'file-name'], required: true, :desc => 'The Orchparty input file'
18
+ com.flag [:application,:a], required: true, :desc => 'The application that should be installed'
19
+ com.switch :"force-variable-definition", :default_value => false, :desc => "Raises an Error if the input contains a not defined variable"
20
+ com.flag [:method,:m], required: true, :desc => 'method to print upgrade/install'
21
+ com.action do |_, args|
22
+ Orchparty.print(cluster_name: args[:c], application_name: args[:a], force_variable_definition: args["force-variable-definition"], file_name: args[:f], method: args[:m])
23
+ end
24
+ end
25
+
26
+ desc "install kubernetes application"
27
+ command :install do |com|
28
+ com.flag [:cluster_name,:c,'cluster-name'], required: true, :desc => 'The cluster to install the app'
29
+ com.flag [:filename,:f,'file-name'], required: true, :desc => 'The Orchparty input file'
30
+ com.flag [:application,:a], required: true, :desc => 'The application that should be installed'
31
+ com.switch :"force-variable-definition", :default_value => false, :desc => "Raises an Error if the input contains a not defined variable"
32
+ com.action do |_, args|
33
+ Orchparty.install(cluster_name: args[:c], application_name: args[:a], force_variable_definition: args["force-variable-definition"], file_name: args[:f])
34
+ end
35
+ end
36
+
37
+ desc "upgrade kubernetes application"
38
+ command :upgrade do |com|
39
+ com.flag [:cluster_name,:c,'cluster-name'], required: true, :desc => 'The cluster to install the app'
40
+ com.flag [:filename,:f,'file-name'], required: true, :desc => 'The Orchparty input file'
41
+ com.flag [:application,:a], required: true, :desc => 'The application that should be installed'
42
+ com.switch :"force-variable-definition", :default_value => false, :desc => "Raises an Error if the input contains a not defined variable"
43
+ com.action do |_, args|
44
+ Orchparty.upgrade(cluster_name: args[:c], application_name: args[:a], force_variable_definition: args["force-variable-definition"], file_name: args[:f])
45
+ end
46
+ end
47
+
48
+ desc "Compiles a Orchparty input file to a orchestration framework configuration"
49
+ command :generate do |com|
50
+ Orchparty.plugins.each do |name, plugin|
51
+ com.desc plugin.desc
52
+ com.command(name) do |plugin_command|
53
+ plugin_command.flag [:filename,:f,'file-name'], required: true, :desc => 'The Orchparty input file'
54
+ plugin_command.flag [:application,:a], required: true, :desc => 'The application that should be compiled'
55
+ plugin_command.switch :"force-variable-definition", :default_value => false, :desc => "Raises an Error if the input contains a not defined variable"
56
+ plugin.define_flags(plugin_command)
57
+ plugin_command.action do |global_options,plugin_options,args|
58
+ options = plugin_options.delete(GLI::Command::PARENT)
59
+ options[:application] = plugin_options[:application]
60
+ options[:filename] = plugin_options[:filename]
61
+ options[:force_variable_definition] = plugin_options[:"force-variable-definition"]
62
+ Orchparty.generate(name, options, plugin_options)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ exit OrchPartyApp.run(ARGV)
@@ -0,0 +1,22 @@
1
+ module Orchparty
2
+ class Context < ::Hashie::Mash
3
+ include Hashie::Extensions::DeepMerge
4
+ include Hashie::Extensions::DeepMergeConcat
5
+ include Hashie::Extensions::MethodAccess
6
+ include Hashie::Extensions::Mash::KeepOriginalKeys
7
+
8
+
9
+ def method_missing(name, *args)
10
+ raise "#{name} not declared for #{application.name}.#{service.name}" if @_force_variable_definition && !key?(name) && !key?(name.to_s)
11
+ super
12
+ end
13
+
14
+ def _force_variable_definition=(v)
15
+ @_force_variable_definition = v
16
+ end
17
+
18
+ def context
19
+ self
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,229 @@
1
+ require 'pathname'
2
+ module Orchparty
3
+ class DSLParser
4
+ attr_reader :filename
5
+
6
+ def initialize(filename)
7
+ @filename = filename
8
+ end
9
+
10
+ def parse
11
+ file_content = File.read(filename)
12
+ builder = RootBuilder.new
13
+ builder.instance_eval(file_content, filename)
14
+ builder._build
15
+ end
16
+ end
17
+
18
+ class Builder
19
+ def self.build(*args, block)
20
+ builder = self.new(*args)
21
+ builder.instance_eval(&block)
22
+ builder._build
23
+ end
24
+
25
+ def assign_or_merge(node, key, value)
26
+ if node[key]
27
+ merged = node[key].deep_merge_concat(value)
28
+ puts "'#{key}' updated to '#{merged}'"
29
+ node[key] = merged
30
+ else
31
+ puts "'#{key}' set to '#{value}'"
32
+ node[key] = value
33
+ end
34
+ end
35
+ end
36
+
37
+ class RootBuilder < Builder
38
+
39
+ def initialize
40
+ @root = AST.root
41
+ end
42
+
43
+ def import(rel_file)
44
+ old_file_path = Pathname.new(caller[0][/[^:]+/]).parent
45
+ rel_file_path = Pathname.new rel_file
46
+ new_file_path = old_file_path + rel_file_path
47
+ file_content = File.read(new_file_path)
48
+ instance_eval(file_content, new_file_path.expand_path.to_s)
49
+ end
50
+
51
+ def application(name, &block)
52
+ @root.applications[name] = ApplicationBuilder.build(name, block)
53
+ self
54
+ end
55
+
56
+ def mixin(name, &block)
57
+ @root._mixins[name] = MixinBuilder.build(name, block)
58
+ self
59
+ end
60
+
61
+ def _build
62
+ @root
63
+ end
64
+ end
65
+
66
+ class MixinBuilder < Builder
67
+
68
+ def initialize(name)
69
+ @mixin = AST.mixin(name: name)
70
+ end
71
+
72
+ def service(name, &block)
73
+ result = ServiceBuilder.build(name, block)
74
+ @mixin.services[name] = result
75
+ @mixin._mixins[name] = result
76
+ self
77
+ end
78
+
79
+ def variables(&block)
80
+ @mixin._variables = VariableBuilder.build(block)
81
+ self
82
+ end
83
+
84
+ def mixin(name, &block)
85
+ @mixin._mixins[name] = ServiceBuilder.build(name, block)
86
+ end
87
+
88
+ def volumes(&block)
89
+ @mixin.volumes = HashBuilder.build(block)
90
+ end
91
+
92
+ def networks(&block)
93
+ @mixin.networks = HashBuilder.build(block)
94
+ end
95
+
96
+ def _build
97
+ @mixin
98
+ end
99
+ end
100
+
101
+ class ApplicationBuilder < Builder
102
+
103
+ def initialize(name)
104
+ @application = AST.application(name: name)
105
+ end
106
+
107
+ def mix(name)
108
+ @application._mix << name
109
+ end
110
+
111
+ def mixin(name, &block)
112
+ @application._mixins[name] = ApplicationMixinBuilder.build(block)
113
+ self
114
+ end
115
+
116
+ def all(&block)
117
+ @application.all = AllBuilder.build(block)
118
+ self
119
+ end
120
+
121
+ def variables(&block)
122
+ @application._variables = VariableBuilder.build(block)
123
+ self
124
+ end
125
+
126
+ def volumes(&block)
127
+ @application.volumes = HashBuilder.build(block)
128
+ self
129
+ end
130
+
131
+ def networks(&block)
132
+ @application.networks = HashBuilder.build(block)
133
+ end
134
+
135
+ def service(name, &block)
136
+ @application.services[name] = ServiceBuilder.build(name, block)
137
+ self
138
+ end
139
+
140
+ def _build
141
+ @application
142
+ end
143
+ end
144
+
145
+ class HashBuilder < Builder
146
+
147
+ def method_missing(_, *values, &block)
148
+ if block_given?
149
+ value = HashBuilder.build(block)
150
+ if values.count == 1
151
+ @hash ||= AST.hash
152
+ @hash[values.first.to_sym] = value
153
+ else
154
+ @hash ||= AST.array
155
+ @hash << value
156
+ end
157
+ else
158
+ value = values.first
159
+ if value.is_a? Hash
160
+ @hash ||= AST.hash
161
+ key, value = value.first
162
+ @hash[key.to_sym] = value
163
+ else
164
+ @hash ||= AST.array
165
+ @hash << value
166
+ end
167
+ end
168
+ self
169
+ end
170
+
171
+ def _build
172
+ @hash
173
+ end
174
+ end
175
+
176
+ class VariableBuilder < HashBuilder
177
+ def _build
178
+ super || {}
179
+ end
180
+ end
181
+
182
+ class CommonBuilder < Builder
183
+
184
+ def initialize(node)
185
+ @node = node
186
+ end
187
+
188
+ def mix(name)
189
+ @node._mix << name
190
+ end
191
+
192
+ def method_missing(name, *values, &block)
193
+ if block_given?
194
+ assign_or_merge(@node, name, HashBuilder.build(block))
195
+ else
196
+ assign_or_merge(@node, name, values.first)
197
+ end
198
+ end
199
+
200
+ def _build
201
+ @node
202
+ end
203
+
204
+ def variables(&block)
205
+ @node._variables ||= {}
206
+ @node._variables = @node._variables.merge(VariableBuilder.build(block))
207
+ self
208
+ end
209
+ end
210
+
211
+ class AllBuilder < CommonBuilder
212
+ def initialize
213
+ super AST.all
214
+ end
215
+ end
216
+
217
+ class ApplicationMixinBuilder < CommonBuilder
218
+ def initialize
219
+ super AST.application_mixin
220
+ end
221
+ end
222
+
223
+ class ServiceBuilder < CommonBuilder
224
+
225
+ def initialize(name)
226
+ super AST.service(name: name)
227
+ end
228
+ end
229
+ end