minfra-cli 1.13.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -2
  3. data/.rubocop.yml +31 -0
  4. data/CHANGELOG.md +15 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +13 -1
  7. data/exe/minfra +1 -3
  8. data/lib/deep_merge.rb +35 -36
  9. data/lib/hash.rb +19 -18
  10. data/lib/minfra/cli/ask.rb +18 -16
  11. data/lib/minfra/cli/cli_starter.rb +173 -0
  12. data/lib/minfra/cli/command.rb +4 -1
  13. data/lib/minfra/cli/commands/dev.rb +26 -15
  14. data/lib/minfra/cli/commands/kube.rb +97 -88
  15. data/lib/minfra/cli/commands/plugin.rb +9 -8
  16. data/lib/minfra/cli/commands/project/branch.rb +7 -5
  17. data/lib/minfra/cli/commands/project/tag.rb +7 -6
  18. data/lib/minfra/cli/commands/project.rb +40 -40
  19. data/lib/minfra/cli/commands/setup.rb +18 -18
  20. data/lib/minfra/cli/commands/stack/app_template.rb +10 -13
  21. data/lib/minfra/cli/commands/stack/client_template.rb +10 -8
  22. data/lib/minfra/cli/commands/stack/kube_stack_template.rb +49 -51
  23. data/lib/minfra/cli/commands/stack.rb +55 -46
  24. data/lib/minfra/cli/commands/tag.rb +9 -8
  25. data/lib/minfra/cli/common.rb +7 -10
  26. data/lib/minfra/cli/config.rb +36 -63
  27. data/lib/minfra/cli/core_ext.rb +7 -0
  28. data/lib/minfra/cli/document.rb +5 -2
  29. data/lib/minfra/cli/env.rb +24 -0
  30. data/lib/minfra/cli/errors.rb +10 -0
  31. data/lib/minfra/cli/helm_runner.rb +3 -1
  32. data/lib/minfra/cli/hiera_looker.rb +54 -0
  33. data/lib/minfra/cli/hook.rb +36 -24
  34. data/lib/minfra/cli/kubectl_runner.rb +3 -1
  35. data/lib/minfra/cli/logging.rb +5 -1
  36. data/lib/minfra/cli/main_command.rb +2 -1
  37. data/lib/minfra/cli/plugin.rb +74 -0
  38. data/lib/minfra/cli/plugins.rb +18 -87
  39. data/lib/minfra/cli/runner.rb +23 -23
  40. data/lib/minfra/cli/templater.rb +17 -17
  41. data/lib/minfra/cli/version.rb +3 -1
  42. data/lib/minfra/cli.rb +20 -114
  43. data/lib/orchparty/ast.rb +13 -14
  44. data/lib/orchparty/cli.rb +35 -33
  45. data/lib/orchparty/context.rb +15 -15
  46. data/lib/orchparty/dsl_parser.rb +7 -11
  47. data/lib/orchparty/dsl_parser_kubernetes.rb +46 -56
  48. data/lib/orchparty/plugin.rb +10 -9
  49. data/lib/orchparty/plugins/env.rb +14 -13
  50. data/lib/orchparty/transformations/all.rb +3 -1
  51. data/lib/orchparty/transformations/mixin.rb +24 -24
  52. data/lib/orchparty/transformations/remove_internal.rb +3 -2
  53. data/lib/orchparty/transformations/sort.rb +2 -1
  54. data/lib/orchparty/transformations/variable.rb +6 -5
  55. data/lib/orchparty/transformations.rb +2 -0
  56. data/lib/orchparty/version.rb +3 -1
  57. data/lib/orchparty.rb +14 -14
  58. metadata +9 -2
data/lib/minfra/cli.rb CHANGED
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
  require 'open3'
3
5
  require 'json'
4
6
  require 'ostruct'
5
7
  require 'hiera'
6
8
 
9
+ require_relative 'cli/core_ext'
10
+ require_relative 'cli/errors'
7
11
  require_relative 'cli/logging'
8
12
  require_relative 'cli/templater'
9
13
 
@@ -19,137 +23,39 @@ require_relative 'cli/runner'
19
23
  require_relative 'cli/helm_runner'
20
24
  require_relative 'cli/kubectl_runner'
21
25
  require_relative 'cli/plugins'
26
+ require_relative 'cli/plugin'
27
+ require_relative 'cli/hiera_looker'
28
+ require_relative 'cli/env'
29
+ require_relative 'cli/cli_starter'
22
30
 
23
31
  require 'active_support'
24
32
  require 'active_support/core_ext'
25
33
 
26
- require "#{ENV['MINFRA_PATH']}/config/preload.rb" if File.exist?("#{ENV['MINFRA_PATH']}/config/preload.rb")
34
+ require "#{ENV.fetch('MINFRA_PATH', nil)}/config/preload.rb" if File.exist?("#{ENV.fetch('MINFRA_PATH', nil)}/config/preload.rb")
27
35
 
28
36
  module Minfra
29
37
  module Cli
30
-
31
38
  extend Minfra::Cli::Logging
32
39
  include Minfra::Cli::Hook
33
40
 
34
- def self.logger
35
- @logger
36
- end
37
-
38
- def self.init(argv)
39
- @argv = argv
40
- # we'll set the context very early!
41
-
42
- if idx=@argv.index("-e")
43
- @config = Config.load(@argv[idx+1])
44
- @argv.delete_at(idx)
45
- @argv.delete_at(idx)
46
- else
47
- @config = Config.load('dev')
48
- end
49
-
50
- @logger=Logger.new(STDERR)
51
- logger.level=ENV["MINFRA_LOGGING_LEVEL"] || @config.project.minfra.logging_level || 'warn'
52
-
53
- project_minfrarc_path = @config.base_path.join("config",'minfrarc.rb')
54
- require project_minfrarc_path if project_minfrarc_path.exist?
55
- me_minfrarc_path = @config.me_path.join('minfrarc.rb')
56
- require @me_minfrarc_path if me_minfrarc_path.exist?
57
-
58
- @logger.debug("Minfra: loglevel: #{@logger.level}, env: #{@config.orch_env}")
59
-
60
- hiera_init
61
-
62
- @plugins = Minfra::Cli::Plugins.load
63
- @plugins.prepare
64
-
65
- Minfra::Cli.scan
66
- require_relative 'cli/main_command'
67
- Minfra::Cli.resolve
68
-
69
-
70
-
71
- end
72
-
73
- def self.run
74
- Minfra::Cli::Main.start(@argv)
75
- end
76
-
77
- def self.root_path
78
- Pathname.new(File.expand_path(File.join(__FILE__, '../../../')))
79
- end
80
-
81
- def self.hiera_init
82
- @hiera_root = Pathname.new("#{ENV["MINFRA_PATH"]}/hiera")
83
- hiera = Hiera.new(:config => @hiera_root.join('hiera.yaml').to_s)
84
- Hiera.logger=:noop
85
- env= @config.orch_env
86
- hiera_main_path=@hiera_root.join("hieradata/#{config.project.minfra.hiera.env_path}/#{env}.eyaml")
87
- raise("unknown environment #{env}, I expact a file at #{hiera_main_path}") unless hiera_main_path.exist?
88
-
89
- scope={ "minfra_path" => ENV["MINFRA_PATH"], "hieraroot" => @hiera_root.to_s, "env" => env}
90
- special_lookups=hiera.lookup("lookup_options", {}, scope, nil, :priority)
91
-
92
- node_scope=hiera.lookup("env", {}, scope, nil, :deeper)
93
- scope=scope.merge(node_scope)
94
- cache={}
95
- Kernel.define_method(:l) do |value,default=nil|
96
-
97
- return cache[value] if cache.has_key?(value)
98
-
99
- values=value.split(".")
100
- fst_value=values.shift
41
+ cattr_accessor :logger, :config, :subcommands,:cli
101
42
 
102
- if special_lookups[fst_value]
103
- lookup_type={ merge_behavior: special_lookups[fst_value]["merge"].to_sym }
104
- else
105
- lookup_type=:deep
106
- end
107
-
108
- result=hiera.lookup(fst_value, default, scope, nil, lookup_type)
109
- if !values.empty? && result.kind_of?(Hash) # we return nil or the scalar value and only drill down on hashes
110
- result=result.dig(*values)
111
- end
112
-
113
- result=Hashie::Mash.new(result) if result.kind_of?(Hash)
114
- cache[value] = result
115
- result
116
- end
117
- Kernel.define_method(:l!) do |value,default=nil|
118
- v=l(value,default)
119
- raise("Value not found! #{value}") if v.nil?
120
- v
121
- end
43
+ def self.init?
44
+ !!cli
122
45
  end
123
46
 
124
-
125
- def self.config
126
- @config
127
- end
128
-
129
- def self.scan
130
- #loading built in commands
131
- root_path.join("lib/minfra/cli/commands").each_child do |command_path|
132
- require command_path if command_path.to_s.match(/\.rb$/) && !command_path.to_s.match(/\#/)
133
- end
134
- @plugins.setup
135
- end
136
-
137
- def self.plugins
138
- @plugins
47
+ def self.init(argv = [])
48
+ self.subcommands ||= {}
49
+ self.cli = CliStarter.new(argv)
139
50
  end
140
51
 
141
- def self.register(subcommand,info,command)
142
- #debug("Registered command #{subcommand}")
143
- @subcommands ||= {}
144
- @subcommands[subcommand.to_sym]= OpenStruct.new(name: subcommand, info: info, command: command)
52
+ def self.exec(argv)
53
+ init(argv) unless init?
54
+ cli.run
145
55
  end
146
56
 
147
- def self.resolve
148
- @subcommands.values.each do |sub|
149
- Minfra::Cli::Main.desc(sub.name,sub.info)
150
- Minfra::Cli::Main.subcommand(sub.name,sub.command)
151
- end
57
+ def self.register(subcommand, info, command)
58
+ self.subcommands[subcommand.to_sym] = OpenStruct.new(name: subcommand, info:, command:)
152
59
  end
153
-
154
60
  end
155
61
  end
data/lib/orchparty/ast.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'hashie'
2
4
 
3
5
  module Orchparty
@@ -13,14 +15,12 @@ module Orchparty
13
15
  binding
14
16
  end
15
17
 
16
- def inspect(indent=0)
17
- start="\n"
18
+ def inspect(indent = 0)
19
+ start = "\n"
18
20
  each_pair do |name, ast|
19
- begin
20
- start << "#{' ' * indent}#{name}: #{ast.inspect(indent+1)}\n"
21
- rescue ArgumentError
22
- start << "#{' ' * indent}#{name}: #{ast.inspect}\n"
23
- end
21
+ start << "#{' ' * indent}#{name}: #{ast.inspect(indent + 1)}\n"
22
+ rescue ArgumentError
23
+ start << "#{' ' * indent}#{name}: #{ast.inspect}\n"
24
24
  end
25
25
  start
26
26
  end
@@ -39,28 +39,27 @@ module Orchparty
39
39
  end
40
40
 
41
41
  def self.mixin(args = {})
42
- Node.new({services: {}, _mixins: {}, volumes: {}, _variables: {}, networks: {}, _service_order: []}).merge(args)
42
+ Node.new({ services: {}, _mixins: {}, volumes: {}, _variables: {}, networks: {}, _service_order: [] }).merge(args)
43
43
  end
44
44
 
45
45
  def self.application(args = {})
46
- Node.new({services: {}, _mixins: {}, _mix:[], volumes: {}, _variables: {}, networks: {}, _service_order: []}).merge(args)
46
+ Node.new({ services: {}, _mixins: {}, _mix: [], volumes: {}, _variables: {}, networks: {}, _service_order: [] }).merge(args)
47
47
  end
48
48
 
49
49
  def self.all(args = {})
50
- Node.new(_mix:[], _variables: {}).merge(args)
50
+ Node.new(_mix: [], _variables: {}).merge(args)
51
51
  end
52
52
 
53
53
  def self.application_mixin(args = {})
54
- Node.new(_mix:[], _variables: {}).merge(args)
54
+ Node.new(_mix: [], _variables: {}).merge(args)
55
55
  end
56
56
 
57
57
  def self.service(args = {})
58
- Node.new(_mix:[], _variables: {}).merge(args)
58
+ Node.new(_mix: [], _variables: {}).merge(args)
59
59
  end
60
60
 
61
61
  def self.chart(args = {})
62
- Node.new(_mix:[], _variables: {}, _services: []).merge(args)
62
+ Node.new(_mix: [], _variables: {}, _services: []).merge(args)
63
63
  end
64
-
65
64
  end
66
65
  end
data/lib/orchparty/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'orchparty'
2
4
  require 'gli'
3
5
 
@@ -11,57 +13,57 @@ class OrchPartyApp
11
13
 
12
14
  subcommand_option_handling :normal
13
15
 
14
- desc "install kubernetes application"
16
+ desc 'install kubernetes application'
15
17
  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'
18
+ com.flag [:cluster_name, :c, 'cluster-name'], required: true, desc: 'The cluster to install the app'
19
+ com.flag [:filename, :f, 'file-name'], required: true, desc: 'The Orchparty input file'
20
+ com.flag %i[application a], required: true, desc: 'The application that should be installed'
21
+ com.switch :'force-variable-definition', default_value: false, desc: 'Raises an Error if the input contains a not defined variable'
22
+ com.flag %i[method m], required: true, desc: 'method to print upgrade/install'
21
23
  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])
24
+ 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
25
  end
24
26
  end
25
27
 
26
- desc "install kubernetes application"
28
+ desc 'install kubernetes application'
27
29
  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"
30
+ com.flag [:cluster_name, :c, 'cluster-name'], required: true, desc: 'The cluster to install the app'
31
+ com.flag [:filename, :f, 'file-name'], required: true, desc: 'The Orchparty input file'
32
+ com.flag %i[application a], required: true, desc: 'The application that should be installed'
33
+ com.switch :'force-variable-definition', default_value: false, desc: 'Raises an Error if the input contains a not defined variable'
32
34
  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])
35
+ Orchparty.install(cluster_name: args[:c], application_name: args[:a], force_variable_definition: args['force-variable-definition'], file_name: args[:f])
34
36
  end
35
37
  end
36
38
 
37
- desc "upgrade kubernetes application"
39
+ desc 'upgrade kubernetes application'
38
40
  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"
41
+ com.flag [:cluster_name, :c, 'cluster-name'], required: true, desc: 'The cluster to install the app'
42
+ com.flag [:filename, :f, 'file-name'], required: true, desc: 'The Orchparty input file'
43
+ com.flag %i[application a], required: true, desc: 'The application that should be installed'
44
+ com.switch :'force-variable-definition', default_value: false, desc: 'Raises an Error if the input contains a not defined variable'
43
45
  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])
46
+ Orchparty.upgrade(cluster_name: args[:c], application_name: args[:a], force_variable_definition: args['force-variable-definition'], file_name: args[:f])
45
47
  end
46
48
  end
47
49
 
48
- desc "Compiles a Orchparty input file to a orchestration framework configuration"
50
+ desc 'Compiles a Orchparty input file to a orchestration framework configuration'
49
51
  command :generate do |com|
50
52
  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
53
+ com.desc plugin.desc
54
+ com.command(name) do |plugin_command|
55
+ plugin_command.flag [:filename, :f, 'file-name'], required: true, desc: 'The Orchparty input file'
56
+ plugin_command.flag %i[application a], required: true, desc: 'The application that should be compiled'
57
+ plugin_command.switch :'force-variable-definition', default_value: false, desc: 'Raises an Error if the input contains a not defined variable'
58
+ plugin.define_flags(plugin_command)
59
+ plugin_command.action do |_global_options, plugin_options, _args|
60
+ options = plugin_options.delete(GLI::Command::PARENT)
61
+ options[:application] = plugin_options[:application]
62
+ options[:filename] = plugin_options[:filename]
63
+ options[:force_variable_definition] = plugin_options[:'force-variable-definition']
64
+ Orchparty.generate(name, options, plugin_options)
64
65
  end
66
+ end
65
67
  end
66
68
  end
67
69
  end
@@ -1,22 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  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
4
+ class Context < ::Hashie::Mash
5
+ include Hashie::Extensions::DeepMerge
6
+ include Hashie::Extensions::DeepMergeConcat
7
+ include Hashie::Extensions::MethodAccess
8
+ include Hashie::Extensions::Mash::KeepOriginalKeys
7
9
 
10
+ def method_missing(name, *args)
11
+ raise "#{name} not declared for #{application.name}.#{service.name}" if @_force_variable_definition && !key?(name) && !key?(name.to_s)
8
12
 
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
+ super
14
+ end
13
15
 
14
- def _force_variable_definition=(v)
15
- @_force_variable_definition = v
16
- end
16
+ attr_writer :_force_variable_definition
17
17
 
18
- def context
19
- self
20
- end
18
+ def context
19
+ self
21
20
  end
21
+ end
22
22
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  module Orchparty
3
5
  class DSLParser
@@ -17,7 +19,7 @@ module Orchparty
17
19
 
18
20
  class Builder
19
21
  def self.build(*args, block)
20
- builder = self.new(*args)
22
+ builder = new(*args)
21
23
  builder.instance_eval(&block)
22
24
  builder._build
23
25
  end
@@ -35,7 +37,6 @@ module Orchparty
35
37
  end
36
38
 
37
39
  class RootBuilder < Builder
38
-
39
40
  def initialize
40
41
  @root = AST.root
41
42
  end
@@ -64,9 +65,8 @@ module Orchparty
64
65
  end
65
66
 
66
67
  class MixinBuilder < Builder
67
-
68
68
  def initialize(name)
69
- @mixin = AST.mixin(name: name)
69
+ @mixin = AST.mixin(name:)
70
70
  end
71
71
 
72
72
  def service(name, &block)
@@ -99,9 +99,8 @@ module Orchparty
99
99
  end
100
100
 
101
101
  class ApplicationBuilder < Builder
102
-
103
102
  def initialize(name)
104
- @application = AST.application(name: name)
103
+ @application = AST.application(name:)
105
104
  end
106
105
 
107
106
  def mix(name)
@@ -143,7 +142,6 @@ module Orchparty
143
142
  end
144
143
 
145
144
  class HashBuilder < Builder
146
-
147
145
  def method_missing(_, *values, &block)
148
146
  if block_given?
149
147
  value = HashBuilder.build(block)
@@ -180,7 +178,6 @@ module Orchparty
180
178
  end
181
179
 
182
180
  class CommonBuilder < Builder
183
-
184
181
  def initialize(node)
185
182
  @node = node
186
183
  end
@@ -191,7 +188,7 @@ module Orchparty
191
188
 
192
189
  def method_missing(name, *values, &block)
193
190
  if block_given?
194
- assign_or_merge(@node, name, HashBuilder.build(block))
191
+ assign_or_merge(@node, name, HashBuilder.build(block))
195
192
  else
196
193
  assign_or_merge(@node, name, values.first)
197
194
  end
@@ -221,9 +218,8 @@ module Orchparty
221
218
  end
222
219
 
223
220
  class ServiceBuilder < CommonBuilder
224
-
225
221
  def initialize(name)
226
- super AST.service(name: name)
222
+ super AST.service(name:)
227
223
  end
228
224
  end
229
225
  end