puppet-retrospec 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +17 -0
  3. data/CHANGELOG.md +11 -0
  4. data/DEVELOPMENT.md +3 -0
  5. data/Gemfile +10 -9
  6. data/Gemfile.lock +2 -0
  7. data/README.md +211 -273
  8. data/Rakefile +8 -8
  9. data/VERSION +1 -1
  10. data/lib/retrospec-puppet.rb +3 -3
  11. data/lib/retrospec/plugins/v1/plugin/conditional.rb +5 -6
  12. data/lib/retrospec/plugins/v1/plugin/exceptions.rb +17 -0
  13. data/lib/retrospec/plugins/v1/plugin/generators.rb +7 -0
  14. data/lib/retrospec/plugins/v1/plugin/generators/fact_generator.rb +18 -10
  15. data/lib/retrospec/plugins/v1/plugin/generators/function_generator.rb +187 -0
  16. data/lib/retrospec/plugins/v1/plugin/generators/module_generator.rb +25 -26
  17. data/lib/retrospec/plugins/v1/plugin/generators/{facter.rb → parsers/facter.rb} +28 -35
  18. data/lib/retrospec/plugins/v1/plugin/generators/parsers/function.rb +91 -0
  19. data/lib/retrospec/plugins/v1/plugin/generators/parsers/type.rb +79 -0
  20. data/lib/retrospec/plugins/v1/plugin/generators/provider_generator.rb +107 -0
  21. data/lib/retrospec/plugins/v1/plugin/generators/schema_generator.rb +221 -0
  22. data/lib/retrospec/plugins/v1/plugin/generators/type_generator.rb +118 -0
  23. data/lib/retrospec/plugins/v1/plugin/helpers.rb +3 -7
  24. data/lib/retrospec/plugins/v1/plugin/puppet.rb +141 -60
  25. data/lib/retrospec/plugins/v1/plugin/puppet_module.rb +29 -26
  26. data/lib/retrospec/plugins/v1/plugin/resource.rb +6 -7
  27. data/lib/retrospec/plugins/v1/plugin/spec_object.rb +5 -8
  28. data/lib/retrospec/plugins/v1/plugin/template_helpers.rb +9 -10
  29. data/lib/retrospec/plugins/v1/plugin/templates/clone-hook +15 -8
  30. data/lib/retrospec/plugins/v1/plugin/type_code.rb +4 -4
  31. data/lib/retrospec/plugins/v1/plugin/variable_store.rb +26 -30
  32. data/lib/retrospec/plugins/v1/plugin/version.rb +1 -1
  33. data/puppet-retrospec.gemspec +43 -4
  34. data/spec/fixtures/facts/oracle_controls.rb +38 -0
  35. data/spec/fixtures/fixture_modules/required_parameters/manifests/init.pp +8 -0
  36. data/spec/fixtures/fixture_modules/sample_module/lib/facter/fix_installed.rb +11 -0
  37. data/spec/fixtures/fixture_modules/sample_module/lib/puppet/functions/awesome_parser.rb +13 -0
  38. data/spec/fixtures/fixture_modules/sample_module/lib/puppet/functions/reduce.rb +31 -0
  39. data/spec/fixtures/fixture_modules/sample_module/lib/puppet/parser/functions/bad_sha1.rb +6 -0
  40. data/spec/fixtures/fixture_modules/sample_module/lib/puppet/parser/functions/defined.rb +94 -0
  41. data/spec/fixtures/fixture_modules/sample_module/lib/puppet/parser/functions/sha1.rb +6 -0
  42. data/spec/fixtures/fixture_modules/sample_module/spec/unit/facter/fix_installed_spec.rb +21 -0
  43. data/spec/fixtures/modules/tomcat/files/.gitkeep +0 -0
  44. data/spec/fixtures/modules/tomcat/templates/.gitkeep +0 -0
  45. data/spec/fixtures/modules/tomcat/tests/.gitkeep +0 -0
  46. data/spec/fixtures/providers/bmc/ipmitool.rb +188 -0
  47. data/spec/fixtures/providers/bmcuser/ipmitool.rb +140 -0
  48. data/spec/fixtures/types/bmc.rb +102 -0
  49. data/spec/fixtures/types/bmcuser.rb +46 -0
  50. data/spec/fixtures/types/db_opatch.rb +93 -0
  51. data/spec/integration/retrospec_spec.rb +1 -3
  52. data/spec/spec_helper.rb +33 -6
  53. data/spec/unit/conditional_spec.rb +12 -15
  54. data/spec/unit/generators/fact_generater_spec.rb +49 -17
  55. data/spec/unit/generators/function_generator_spec.rb +301 -0
  56. data/spec/unit/generators/function_spec.rb +67 -0
  57. data/spec/unit/generators/parsers/fact_spec.rb +62 -0
  58. data/spec/unit/generators/parsers/provider_spec.rb +44 -0
  59. data/spec/unit/generators/parsers/type_spec.rb +93 -0
  60. data/spec/unit/generators/provider_generator_spec.rb +120 -0
  61. data/spec/unit/generators/schema_generator_spec.rb +122 -0
  62. data/spec/unit/generators/type_generator_spec.rb +173 -0
  63. data/spec/unit/module_spec.rb +7 -10
  64. data/spec/unit/plugin_spec.rb +213 -15
  65. data/spec/unit/puppet-retrospec_spec.rb +81 -100
  66. data/spec/unit/resource_spec.rb +16 -17
  67. data/spec/unit/spec_object_spec.rb +46 -0
  68. data/spec/unit/type_code_spec.rb +9 -11
  69. data/spec/unit/variable_store_spec.rb +41 -43
  70. metadata +54 -4
  71. data/spec/unit/generators/fact_spec.rb +0 -58
@@ -1,5 +1,4 @@
1
1
  require 'ostruct'
2
-
3
2
  # this is required to use when processing erb templates
4
3
  class OpenStruct
5
4
  def get_binding
@@ -16,20 +15,14 @@ module Retrospec
16
15
  class Execution
17
16
  def self.execute(command, options={})
18
17
  value = {:klass => self.to_s.gsub('Retrospec::Puppet::Generators::', ''),
19
- :method => :execute, :value => command}
18
+ :method => :execute, :value => command}
20
19
  Retrospec::Puppet::Generators::Facter.exec_calls[command] = value
21
20
  end
22
21
  end
23
22
  end
24
23
 
25
- @model = OpenStruct.new(:facts => {})
26
- @used_facts = {}
27
- @confines = []
28
- @methods_defined = []
29
-
30
24
  def initialize(name, options, &block)
31
25
  @fact_name = name
32
- #block.call
33
26
  end
34
27
 
35
28
  def self.exec_calls
@@ -40,6 +33,10 @@ module Retrospec
40
33
  @used_facts ||= {}
41
34
  end
42
35
 
36
+ def self.methods_defined
37
+ @methods_defined ||= []
38
+ end
39
+
43
40
  def self.value(name)
44
41
  used_facts[name] = {:name => name}
45
42
  end
@@ -51,12 +48,16 @@ module Retrospec
51
48
  end
52
49
 
53
50
  def self.method_missing(method_sym, *arguments, &block)
54
- @methods_defined << method_sym
51
+ unless methods_defined.include?(method_sym)
52
+ methods_defined << method_sym
53
+ end
54
+ method_sym
55
55
  end
56
56
 
57
57
  def self.setcode(&block)
58
58
  begin
59
59
  block.call
60
+ rescue Exception => e
60
61
  rescue NameError => e
61
62
  end
62
63
  end
@@ -68,49 +69,41 @@ module Retrospec
68
69
  # loads the fact into the loader for evaluation
69
70
  # and data collection
70
71
  def self.load_fact(file)
71
- @model = OpenStruct.new(:facts => {})
72
- @used_facts = {}
73
- @model = eval(File.read(file))
74
- transform_data(@model)
72
+ @model = OpenStruct.new(:facts => {}, :defined_methods => [], :global_used_facts => {}, :global_used_execs => {})
73
+ begin
74
+ proc = Proc.new {}
75
+ eval(File.read(file), proc.binding, file)
76
+ rescue LoadError => e
77
+ puts "Error loading dependency for file: #{file}, skipping".fatal
78
+ rescue Exception => e
79
+ puts "Error evaluating file: #{file}, skipping".fatal
80
+ end
81
+ @model
75
82
  end
76
83
 
77
84
  # every fact will have a Facter.add functionality
78
85
  # this is the startign point to collect all data
79
86
  def self.add(name, options={}, &block)
80
- @model.facts[name] = OpenStruct.new(:fact_name => name)
81
87
  # calls the facter.add block
82
88
  # this may call separate confine statements
83
- @model.global_used_facts = used_facts
84
- @used_facts = {} # clear before fact specific are evaluated
85
- @model.global_used_execs = exec_calls
89
+ # for each Facter.add block that gets called we need to reset a few things
90
+ @confines = {}
91
+ @used_facts = {}
86
92
  @exec_calls = {}
87
93
  begin
88
94
  block.call
95
+ rescue Exception => e
89
96
  rescue NameError => e
90
97
  end
98
+
99
+ @model.facts[name] = OpenStruct.new(:fact_name => name)
91
100
  @model.facts[name].used_facts = used_facts
92
101
  @model.facts[name].confines = @confines
93
- # clear any persistant data
94
- @confines = []
95
- @model.defined_methods = @methods_defined
102
+ @model.defined_methods = methods_defined
96
103
  @model.facts[name].exec_calls = exec_calls
97
104
  @model
98
105
  end
99
-
100
- def self.transform_data(data)
101
- #ObenStruct.new(:)
102
- # {:method_fact=>
103
- # {:fact_name=>:method_fact,
104
- # :used_facts=>{:is_virtual=>{:name=>:is_virtual}},
105
- # :confines=>[{:kernel=>"Linux"}],
106
- # :exec_calls=>["which lsb"]},
107
- # :global_used_facts=>{},
108
- # :global_used_execs=>[],
109
- # :defined_methods=>[:default_kernel]}
110
- data
111
- end
112
106
  end
113
-
114
107
  end
115
108
  end
116
- end
109
+ end
@@ -0,0 +1,91 @@
1
+ require 'ostruct'
2
+ require 'retrospec/plugins/v1/plugin/puppet_module'
3
+ # this is required to use when processing erb templates
4
+ class OpenStruct
5
+ def get_binding
6
+ binding
7
+ end
8
+ end
9
+
10
+ module Retrospec
11
+ module Puppet
12
+ module Functions
13
+ # for puppet 4 functions
14
+ def self.create_function(func_name, function_base = nil, &block)
15
+ # the bundled version of puppet with this gem is quite old and is preventing me from creating a function
16
+ # to get the actual properties of it. For now we can just skip the creation and stub enough functions
17
+ # to get at the data. However, if we just eval the file we can probably bypass all this code and use class
18
+ # methods instead
19
+ #require 'puppet/pops'
20
+ #f = ::Puppet::Functions.create_function(func_name, function_base, &block)
21
+ block.call
22
+ @model.name = func_name
23
+ end
24
+
25
+ def self.load_function(file)
26
+ begin
27
+ ::Puppet.initialize_settings
28
+ rescue
29
+ # do nothing otherwise calling init twice raises an error
30
+ end
31
+ @model = OpenStruct.new(:name => File.basename(file, '.rb'), :dispatched_methods => {},
32
+ :required_methods => [])
33
+
34
+ f = eval(File.read(file))
35
+ @model.required_methods = find_required_methods(@model.name, @model.dispatched_methods.keys)
36
+ @model
37
+ end
38
+
39
+ # figures out which methods need to be present in the function so that we can create a test for them
40
+ def self.find_required_methods(name, dispatched_methods=[])
41
+ if dispatched_methods.empty?
42
+ [name]
43
+ else
44
+ dispatched_methods
45
+ end
46
+ end
47
+
48
+ def self.dispatch(meth_name, &block)
49
+ @params = [] # reset the variable
50
+ args = block.call
51
+ @model.dispatched_methods[meth_name] = {:name => meth_name, :args => args}
52
+ end
53
+
54
+ # this is a catch all method that helps us discover which dsl methods are used
55
+ def self.method_missing(meth_sym, *arguments, &block)
56
+ @params << {:name => meth_sym, :args => arguments}
57
+ end
58
+
59
+ end
60
+
61
+ module Parser
62
+ module Functions
63
+ # for puppet 3 functions
64
+ def self.newfunction(name, options = {}, &block)
65
+ options.merge({:name => name})
66
+ end
67
+
68
+ # for puppet 4 functions
69
+ def self.create_function(func_name, function_base = Function, &block)
70
+ {:name => func_name }
71
+ end
72
+
73
+ def self.load_function(file)
74
+ begin
75
+ ::Puppet.initialize_settings
76
+ rescue
77
+ # do nothing otherwise calling init twice raises an error
78
+ end
79
+ @model = OpenStruct.new(:name => File.basename(file, '.rb'), :arity => nil, :doc => '', :type => nil,
80
+ :class_methods => [], :instance_methods => [], :options => {})
81
+ f = eval(File.read(file))
82
+ @model.name = f[:name]
83
+ @model.arity = f[:arity]
84
+ @model.doc = f[:doc]
85
+ @model.type = f[:type]
86
+ @model
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,79 @@
1
+ require 'ostruct'
2
+
3
+ # this is required to use when processing erb templates
4
+ class OpenStruct
5
+ def get_binding
6
+ binding
7
+ end
8
+ end
9
+ # we could also create a new instance of the type and use instances methods to retrieve many things
10
+ # Puppet::Type.type(type_name) after loading the file
11
+ module Retrospec
12
+ module Puppet
13
+ class Type
14
+ # loads the type_file and provider_file if given
15
+ # determines if type or provider is being used and
16
+ # evals the code
17
+ # if the provider_file is not loadable we cannot build a full context
18
+ # for the template to be rendered with so we use a default context instead
19
+ def self.load_type(type_file, provider_file = nil)
20
+ if provider_file
21
+ begin
22
+ file = provider_file
23
+ @model = OpenStruct.new(:name => File.basename(file, '.rb'), :file => file,
24
+ :class_methods => [], :instance_methods => [],
25
+ :properties => [], :parameters => [])
26
+ require type_file
27
+ require provider_file
28
+ t = eval(File.read(file))
29
+ @model.parameters = t.resource_type.parameters
30
+ @model.properties = t.resource_type.validproperties
31
+ @model.name = t.name
32
+ @model.class_methods = t.methods(false)
33
+ @model.instance_methods = t.instance_methods(false)
34
+ rescue LoadError => e
35
+ puts "#{e.message}, generating empty file".fatal
36
+ rescue NameError => e
37
+ puts "#{e.message}, is this valid provider code?".fatal
38
+ rescue NoMethodError => e
39
+ puts "#{e.message}, is this valid provider code?".fatal
40
+ rescue ::Puppet::Context::UndefinedBindingError => e
41
+ puts "There was an issue with loading the provider code for #{file}, skipping".fatal
42
+ end
43
+ @model
44
+ else
45
+ begin
46
+ require type_file
47
+ file = type_file
48
+ @model = OpenStruct.new(:name => File.basename(file, '.rb'), :file => file,
49
+ :properties => [], :instance_methods => [],
50
+ :parameters => [], :methods_defined => [])
51
+ t = eval(File.read(file))
52
+ @model.name = t.name
53
+ @model.parameters = t.parameters
54
+ @model.properties = t.properties.collect(&:name)
55
+ @model.instance_methods = t.instance_methods(false)
56
+ @model
57
+ rescue LoadError => e
58
+ puts "#{e.message}, generating empty file".fatal
59
+ rescue NameError => e
60
+ puts "#{e.message}, is this valid type code?".fatal
61
+ rescue NoMethodError => e
62
+ puts "#{e.message}, is this valid type code?".fatal
63
+ end
64
+ end
65
+ @model
66
+ end
67
+
68
+ def self.type(name, _options = {}, &_block)
69
+ ::Puppet::Type.type(name)
70
+ end
71
+
72
+ # I don't know of a better way to get the name of the type
73
+ def self.newtype(name, _options = {}, &_block)
74
+ ::Puppet::Type.type(name)
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,107 @@
1
+ require_relative 'parsers/type'
2
+ require 'facets'
3
+
4
+ module Retrospec::Puppet::Generators
5
+ class ProviderGenerator < Retrospec::Plugins::V1::Plugin
6
+ attr_reader :template_dir, :context
7
+ attr_accessor :provider_type
8
+
9
+ # retrospec will initaialize this class so its up to you
10
+ # to set any additional variables you need in the context in feed the templates.
11
+ def initialize(module_path, spec_object = {})
12
+ super
13
+ # below is the Spec Object which serves as a context for template rendering
14
+ # you will need to initialize this object, so the erb templates can get the binding
15
+ # the SpecObject can be customized to your liking as its different for every plugin gem.
16
+ @context = OpenStruct.new(:provider_name => spec_object[:name], :type_name => spec_object[:type])
17
+ @provider_type = context.type_name
18
+ end
19
+
20
+ # returns the path to the templates
21
+ # first looks inside the external templates directory for specific file
22
+ # then looks inside the gem path templates directory, which is really only useful
23
+ # when developing new templates.
24
+ def template_dir
25
+ external_templates = File.expand_path(File.join(config_data[:template_dir], 'providers', 'provider_template.rb.retrospec.erb'))
26
+ if File.exist?(external_templates)
27
+ File.join(config_data[:template_dir], 'providers')
28
+ else
29
+ File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'templates', 'providers'))
30
+ end
31
+ end
32
+
33
+ # used to display subcommand options to the cli
34
+ # the global options are passed in for your usage
35
+ # http://trollop.rubyforge.org
36
+ # all options here are available in the config passed into config object
37
+ # returns the parameters
38
+ def self.run_cli(global_opts, args=ARGV)
39
+ sub_command_opts = Trollop.options(args) do
40
+ banner <<-EOS
41
+ Generates a new provider with the given name.
42
+
43
+ EOS
44
+ opt :name, 'The name of the provider you wish to create', :type => :string, :required => true, :short => '-n'
45
+ opt :type, 'The type name of the provider', :type => :string, :required => true, :short => '-t'
46
+ end
47
+ unless sub_command_opts[:name]
48
+ Trollop.educate
49
+ exit 1
50
+ end
51
+ plugin_data = global_opts.merge(sub_command_opts)
52
+ plugin_data
53
+ end
54
+
55
+ def provider_dir
56
+ File.join(module_path, 'lib', 'puppet', 'provider')
57
+ end
58
+
59
+ def type_dir
60
+ File.join(module_path, 'lib', 'puppet', 'type')
61
+ end
62
+
63
+ # returns the type file that the provider uses
64
+ # if the type file does not exist it assumes a core puppet type
65
+ # because we could potentially dealing with multiple
66
+ def type_file(p_type = provider_type)
67
+ if TypeGenerator::CORE_TYPES.include?(p_type)
68
+ type_file = "puppet/type/#{p_type}.rb"
69
+ else
70
+ type_file = File.join(type_dir, "#{p_type}.rb")
71
+ end
72
+ type_file
73
+ end
74
+
75
+ def provider_spec_dir
76
+ File.join(module_path, 'spec', 'unit', 'puppet', 'provider')
77
+ end
78
+
79
+ def provider_name_path
80
+ File.join(provider_dir, provider_type, "#{provider_name}.rb")
81
+ end
82
+
83
+ def provider_name
84
+ context.provider_name
85
+ end
86
+
87
+ def generate_provider_files
88
+ safe_create_template_file(provider_name_path, File.join(template_dir, 'provider_template.rb.retrospec.erb'), context)
89
+ provider_name_path
90
+ end
91
+
92
+ def generate_provider_spec_files
93
+ provider_files = Dir.glob(File.join(provider_dir, '**', '*.rb')).sort
94
+ spec_files = []
95
+ provider_files.each do |provider_file|
96
+ t_name = File.basename(File.dirname(provider_file))
97
+ provider_file_data = Retrospec::Puppet::Type.load_type(type_file(t_name), provider_file)
98
+ provider_file_data.type_name = t_name # add the provider type
99
+ # because many facts can be in a single file we want to create a unique file for each fact
100
+ provider_spec_path = File.join(provider_spec_dir, t_name, "#{provider_file_data.name}_spec.rb")
101
+ spec_files << provider_spec_path
102
+ safe_create_template_file(provider_spec_path, File.join(template_dir, 'provider_spec.rb.retrospec.erb'), provider_file_data)
103
+ end
104
+ spec_files
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,221 @@
1
+ require 'yaml'
2
+
3
+ module Retrospec
4
+ module Puppet
5
+ module Generators
6
+ class SchemaGenerator < Retrospec::Plugins::V1::Plugin
7
+ attr_reader :template_dir, :schema
8
+ attr_accessor :context
9
+ # retrospec will initilalize this class so its up to you
10
+ # to set any additional variables you need to get the job done.
11
+ def initialize(module_path, spec_object = {})
12
+ super
13
+ # below is the Spec Object which serves as a context for template rendering
14
+ # you will need to initialize this object, so the erb templates can get the binding
15
+ # the SpecObject can be customized to your liking as its different for every plugin gem.
16
+ @context = OpenStruct.new(:puppet_context => spec_object[:puppet_context])
17
+ @schema = base_schema
18
+ @parameter_count = 0
19
+ end
20
+
21
+ # returns the path to the templates
22
+ # first looks inside the external templates directory for specific file
23
+ # then looks inside the gem path templates directory, which is really only useful
24
+ # when developing new templates.
25
+ def template_dir
26
+ external_templates = File.expand_path(File.join(config_data[:template_dir], 'schemas', 'schema_file.yaml.retrospec.erb'))
27
+ if File.exist?(external_templates)
28
+ File.join(config_data[:template_dir], 'schemas')
29
+ else
30
+ File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'templates', 'schemas'))
31
+ end
32
+ end
33
+
34
+ # used to display subcommand options to the cli
35
+ # the global options are passed in for your usage
36
+ # http://trollop.rubyforge.org
37
+ # all options here are available in the config passed into config object
38
+ # returns the parameters
39
+ def self.run_cli(global_opts, args=ARGV)
40
+ sub_command_opts = Trollop.options(args) do
41
+ banner <<-EOS
42
+ Generates a kwalify schema based off class parameters.
43
+
44
+ EOS
45
+ end
46
+ plugin_data = global_opts.merge(sub_command_opts)
47
+ plugin_data
48
+ end
49
+
50
+ # creates the schema in ruby object format
51
+ def create_map_content
52
+ all_hiera_data.each do |name, opts|
53
+ add_mapping(name => opts)
54
+ end
55
+ schema
56
+ end
57
+
58
+ def schema_name
59
+ puppet_context.module_name || File.basename(module_path)
60
+ end
61
+
62
+ # absolute path of schema file
63
+ def schema_path
64
+ File.join(module_path, "#{schema_name}_schema.yaml")
65
+ end
66
+
67
+ # generates the schema file, using a template
68
+ def generate_schema_file
69
+ map_content = create_map_content
70
+ context[:map_content] = map_content.to_yaml
71
+ context[:raw_maps] = map_content
72
+ context[:parameter_count] = @parameter_count
73
+ context[:schema_path] = schema_path
74
+ context[:schema_name] = schema_name
75
+ template_file = File.join(template_dir, 'schema_file.yaml.retrospec.erb')
76
+ safe_create_template_file(schema_path, template_file, context)
77
+ schema_path
78
+ end
79
+
80
+ # example
81
+ # "motd::motd_content" => {
82
+ # "type" => "str",
83
+ # "required" => false
84
+ # },
85
+ def add_mapping(map_value)
86
+ schema['mapping'].merge!(map_value)
87
+ end
88
+
89
+ def types
90
+ context.puppet_context.types
91
+ end
92
+
93
+ private
94
+
95
+ # generates a class or defination map
96
+ def generate_type_map(puppet_type)
97
+ type_name = puppet_type.type.to_s
98
+ arg_map = {}
99
+ #arg_map = {'mapping' => {}, 'required' => false, 'type' => 'map' }
100
+ puppet_type.arguments.each do |k, _v|
101
+ key = "#{puppet_type.name}::#{k}"
102
+ kwalify_type = type_map(_v.class)
103
+ @parameter_count = @parameter_count + 1
104
+ arg_map.deep_merge!(generate_map(key, _v, kwalify_type))
105
+ end
106
+ t_map = {type_name => { 'type' => 'map', 'mapping' => arg_map}}
107
+ end
108
+
109
+ # returns a hash of parameters with their classes
110
+ def parameter_schema(found_types)
111
+ parameter_data = {}
112
+ found_types.each do |t|
113
+ parameter_data = parameter_data.deep_merge(generate_type_map(t))
114
+ end
115
+ parameter_data
116
+ end
117
+
118
+ # gathers all the class parameters that could be used in hiera data mocking
119
+ # this is the only function that generates the necessary data to be used for schema
120
+ # creation.
121
+ def all_hiera_data
122
+ if @all_hiera_data.nil?
123
+ @all_hiera_data = parameter_schema(types)
124
+ end
125
+ @all_hiera_data
126
+ end
127
+
128
+ def is_required?(item)
129
+ item.nil?
130
+ end
131
+
132
+ def base_schema
133
+ @base_schema ||= {
134
+ "type" => "map",
135
+ "mapping" => {
136
+ "hostclass" => {
137
+ "type" => "map",
138
+ "mapping" => {}
139
+ },
140
+ "definition" => {
141
+ "type" => "map",
142
+ "mapping" => {}
143
+ }
144
+ }
145
+ }
146
+ end
147
+
148
+ def any_map
149
+ {"=" => {
150
+ "type" => "any",
151
+ "required" => false
152
+ }
153
+ }
154
+ end
155
+
156
+ def puppet_context
157
+ context.puppet_context
158
+ end
159
+
160
+ # conversion table from ruby types to kwalify types
161
+ def type_table
162
+ @type_table ||= {
163
+ 'Array'=>"seq",
164
+ 'Hash'=>"map",
165
+ 'String'=>"str",
166
+ 'Integer'=>"int",
167
+ 'Float'=>"float",
168
+ 'Numeric'=>"number",
169
+ 'Date'=>"date",
170
+ 'Time'=>"timestamp",
171
+ 'Object'=>"any",
172
+ 'FalseClass' => 'bool',
173
+ 'TrueClass' => 'bool',
174
+ 'Fixnum' => 'number',
175
+ 'NilClass' => 'any',
176
+ 'Puppet::Parser::AST::Variable' => 'any',
177
+ 'Puppet::Parser::AST::Boolean' => 'bool',
178
+ 'Puppet::Parser::AST::String' => 'str',
179
+ 'Puppet::Parser::AST::ASTHash' => 'map',
180
+ 'Puppet::Parser::AST::ASTArray' => 'seq',
181
+ }
182
+ end
183
+
184
+ # convert the given class to a kwalify class, defaults to any
185
+ def type_map(klass)
186
+ type_table[klass.to_s] || 'any'
187
+ end
188
+
189
+ # given a kwalify key undefined error
190
+ # this method will produce a map of how the key should be defined
191
+ # example
192
+ #"motd::motd_content" => {
193
+ # "type" => "str",
194
+ # "required" => false
195
+ # },
196
+ def generate_map(key, value, value_type)
197
+ case value_type
198
+ when 'seq'
199
+ {key => {
200
+ "type" => 'seq',
201
+ "sequence" => [{'type' => 'str'}],
202
+ "required" => is_required?(value)
203
+ }}
204
+ when 'map'
205
+ {key => {
206
+ "type" => 'map',
207
+ "mapping" => {'=' => {'type' => 'any', 'required' => false}},
208
+ "required" => is_required?(value)
209
+ }}
210
+ else
211
+ {key => {
212
+ "type" => value_type,
213
+ "required" => is_required?(value)
214
+ }}
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+