diff --git a/spec/fixtures/unit/data_providers/environments/sample/environment.conf b/spec/fixtures/unit/data_providers/environments/sample/environment.conf new file mode 100644 index 000000000..a5e17cf24 --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/environment.conf @@ -0,0 +1,2 @@ +# Use the 'sample' env data provider (in this fixture) +environment_data_provider=sample diff --git a/spec/fixtures/unit/data_providers/environments/sample/manifests/site.pp b/spec/fixtures/unit/data_providers/environments/sample/manifests/site.pp new file mode 100644 index 000000000..f60634bde --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/manifests/site.pp @@ -0,0 +1,6 @@ +class test($param_a = 1, $param_b = 2, $param_c = 3) { + notify { "$param_a, $param_b, $param_c": } +} + +include test +#include dataprovider::test diff --git a/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet/bindings/dataprovider/default.rb b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet/bindings/dataprovider/default.rb new file mode 100644 index 000000000..55cb0121f --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet/bindings/dataprovider/default.rb @@ -0,0 +1,54 @@ +# This registers the default bindings for this module. +# These bidnings are loaded at the start of a Puppet +# catalog production. +# +# The registrations makes 'sample' available as both a +# data provider for an environment, and individually +# selectable in modules. +# +# Note that there are two different implementation classes +# registered, one for environment, and one for modules. +# +# Also note that all data are strings including the names +# of the classes that implement the provider logic. This +# is to not cause loading of those classes until they +# are needed. +# +Puppet::Bindings.newbindings('dataprovider::default') do + + # Make the SampleEnvData provider available for use in environments + # as 'sample'. + # + bind { + name 'sample' + in_multibind 'puppet::environment_data_providers' + to_instance 'PuppetX::Helindbe::SampleEnvData' + } + + # Make the SampleModuleData provider available for use in environments + # as 'sample'. + # + bind { + name 'sample' + in_multibind 'puppet::module_data_providers' + to_instance 'PuppetX::Helindbe::SampleModuleData' + } + + # This is what users of the 'sample' module data provider should + # use in its default.rb bindings. The module providing the implementation + # of this data provider typically does not have any puppet logic, so it + # would not have this binding. This example module has this however since + # it would otherwise require an additional module with just some puppet code + # and this binding to demonstrate the functionality. + # + # This binding declares that this module wants to use the 'sample' data provider + # for this module. (Thus ending up using the SampleModuleData implementation + # bound above in this example). + # + bind { + name 'dataprovider' + to 'sample' + in_multibind 'puppet::module_data' + } +end + diff --git a/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb new file mode 100644 index 000000000..3ceea9af0 --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb @@ -0,0 +1,31 @@ +# The module is named after the author, to ensure that names under PuppetX namespace +# does not clash. +# +require 'puppetx' +module PuppetX::Helindbe + + # An env data provider that is hardcoded and provides data for + # the two names 'test::param_a' and 'test::param_b'. + # + # A real implementation would read the data from somewhere or invoke some + # other service to obtain the data. When doing so caching may be performance + # critical, and it is important that a cache is associated with the apropriate + # object to not cause memory leaks. See more details in the documentation + # for how to write a data provider and use adapters. + # + class SampleEnvData < Puppet::Plugins::DataProviders::EnvironmentDataProvider + def initialize() + @data = { + 'test::param_a' => 'env data param_a is 10', + 'test::param_b' => 'env data param_b is 20', + # demo: this overrides a parameter for a class in the dataprovider module + 'dataprovider::test::param_c' => 'env data param_c is 300', + } + end + + def lookup(name, scope) + @data[name] + end + end +end + diff --git a/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_module_data.rb b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_module_data.rb new file mode 100644 index 000000000..483ca147c --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_module_data.rb @@ -0,0 +1,32 @@ +# The module is named after the author, to ensure that names under PuppetX namespace +# does not clash. +# +require 'puppetx' +module PuppetX::Helindbe + + # A module data provider that is hardcoded and provides data for + # the three names 'test::param_a', 'test::param_b', and 'test::param_c' + # + # A real implementation would read the data from somewhere or invoke some + # other service to obtain the data. When doing so caching may be performance + # critical, and it is important that a cache is associated with the apropriate + # object to not cause memory leaks. See more details in the documentation + # for how to write a data provider and use adapters. + # + class SampleModuleData < Puppet::Plugins::DataProviders::ModuleDataProvider + def initialize() + @data = { + 'dataprovider::test::param_a' => 'module data param_a is 100', + 'dataprovider::test::param_b' => 'module data param_b is 200', + + # demo: uncomment the entry below to make it override the environment provided data + #'dataprovider::test::param_c' => 'env data param_c is 300', + } + end + + def lookup(name, scope) + @data[name] + end + end +end + diff --git a/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/manifests/init.pp b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/manifests/init.pp new file mode 100644 index 000000000..6b3f85da8 --- /dev/null +++ b/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/manifests/init.pp @@ -0,0 +1,5 @@ +class dataprovider { + class test($param_a = 1, $param_b = 2, $param_c = 3) { + notice "param_a = $param_a, param_b = $param_b, param_c = $param_c" + } +} diff --git a/spec/unit/data_providers/sample_data_provider_spec.rb b/spec/unit/data_providers/sample_data_provider_spec.rb new file mode 100644 index 000000000..e8e60ae27 --- /dev/null +++ b/spec/unit/data_providers/sample_data_provider_spec.rb @@ -0,0 +1,46 @@ +#! /usr/bin/env ruby +require 'spec_helper' +require 'puppet_spec/compiler' + +describe "when using a sample data provider from an external module" do + include PuppetSpec::Compiler + + # There is a fully configured 'sample' environment in fixtures at this location + let(:environmentpath) { parent_fixture('environments') } + + around(:each) do |example| + # Initialize settings to get a full compile as close as possible to a real + # environment load + Puppet.settings.initialize_global_settings + # Initialize loaders based on the environmentpath. It does not work to + # just set the setting environmentpath for some reason - this achieves the same: + # - first a loader is created, loading directory environments from the fixture (there is + # one environment, 'sample', which will be loaded since the node references this + # environment by name). + # - secondly, the created env loader is set as 'environments' in the puppet context. + # + loader = Puppet::Environments::Directories.new(environmentpath, []) + Puppet.override(:environments => loader) do + example.run + end + end + + it 'the environment data loader is used to set parameters' do +# Puppet[:code] = 'include test' + node = Puppet::Node.new("testnode", :facts => Puppet::Node::Facts.new("facts", {}), :environment => 'sample') + compiler = Puppet::Parser::Compiler.new(node) + catalog = compiler.compile() + resources_created_in_fixture = ["Notify[env data param_a is 10, env data param_b is 20, 3]"] + expect(resources_in(catalog)).to include(*resources_created_in_fixture) + end + + + def parent_fixture(dir_name) + File.absolute_path(File.join(my_fixture_dir(), "../#{dir_name}")) + end + + def resources_in(catalog) + catalog.resources.map(&:ref) + end + +end