puppet-retrospec 0.11.0 → 0.12.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 (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
+