Skip to content

(FM-7701) Support device providers when using Transport Wrapper #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions lib/puppet/resource_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'puppet/resource_api/puppet_context' unless RUBY_PLATFORM == 'java'
require 'puppet/resource_api/read_only_parameter'
require 'puppet/resource_api/transport'
require 'puppet/resource_api/transport/wrapper'
require 'puppet/resource_api/type_definition'
require 'puppet/resource_api/value_creator'
require 'puppet/resource_api/version'
Expand Down Expand Up @@ -40,7 +41,12 @@ def register_type(definition)
# Keeps a copy of the provider around. Weird naming to avoid clashes with puppet's own `provider` member
define_singleton_method(:my_provider) do
@my_provider ||= Hash.new { |hash, key| hash[key] = Puppet::ResourceApi.load_provider(definition[:name]).new }
@my_provider[Puppet::Util::NetworkDevice.current.class]

if Puppet::Util::NetworkDevice.current.is_a? Puppet::ResourceApi::Transport::Wrapper
@my_provider[Puppet::Util::NetworkDevice.current.transport.class]
else
@my_provider[Puppet::Util::NetworkDevice.current.class]
end
end

# make the provider available in the instance's namespace
Expand Down Expand Up @@ -412,8 +418,10 @@ def load_provider(type_name)
type_name_sym = type_name.to_sym
device_name = if Puppet::Util::NetworkDevice.current.nil?
nil
else
elsif Puppet::Util::NetworkDevice.current.is_a? Puppet::ResourceApi::Transport::Wrapper
# extract the device type from the currently loaded device's class
Puppet::Util::NetworkDevice.current.schema.name
else
Puppet::Util::NetworkDevice.current.class.name.split('::')[-2].downcase
end
device_class_name = class_name_from_type_name(device_name)
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/resource_api/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def connect(name, connection_info)

def self.validate(name, connection_info)
init_transports
require "puppet/transport/schema/#{name}" unless @transports.key? name
require "puppet/transport/schema/#{name}" unless @transports[@environment].key? name
transport_schema = @transports[@environment][name]
if transport_schema.nil?
raise Puppet::DevError, 'Transport for `%{target}` not registered with `%{environment}`' % {
Expand Down
1 change: 0 additions & 1 deletion lib/puppet/resource_api/transport/wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def respond_to_missing?(name, _include_private)

def method_missing(method_name, *args, &block)
if @transport.respond_to? method_name
puts "Delegating #{method_name}"
@transport.send(method_name, *args, &block)
else
super
Expand Down
2 changes: 1 addition & 1 deletion spec/puppet/resource_api/transport_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def change_environment(name = nil)

described_class.register(schema)

expect(described_class).to receive(:require).with('puppet/transport/schema/validate')
expect(described_class).not_to receive(:require).with('puppet/transport/schema/validate')
expect(schema_def).to receive(:check_schema).with('connection_info').and_return(nil)
expect(schema_def).to receive(:validate).with('connection_info').and_return(nil)

Expand Down
59 changes: 59 additions & 0 deletions spec/puppet/resource_api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,37 @@ class OtherDevice; end
it('loads the device provider') { expect(described_class.load_provider('multi_provider').name).to eq 'Puppet::Provider::MultiProvider::SomeDevice' }
end
end

context 'with a transport configured' do
let(:definition) { { name: 'multi_provider', attributes: {} } }
let(:transport) { instance_double('Puppet::ResourceApi::Transport::Wrapper', 'transport') }
let(:schema_def) { instance_double('Puppet::ResourceApi::TransportSchemaDef', 'schema_def') }

before(:each) do
allow(Puppet::Util::NetworkDevice).to receive(:current).with(no_args).and_return(transport)
allow(transport).to receive(:is_a?).with(Puppet::ResourceApi::Transport::Wrapper).and_return(true)
allow(transport).to receive(:schema).and_return(schema_def)
allow(schema_def).to receive(:name).and_return(schema_name)

module ::Puppet::Provider::MultiProvider
class MultiProvider; end
class SomeDevice; end
class OtherDevice; end
end
end

context 'with no device-specific provider' do
let(:schema_name) { 'multi_provider' }

it('loads the default provider') { expect(described_class.load_provider('multi_provider').name).to eq 'Puppet::Provider::MultiProvider::MultiProvider' }
end

context 'with a device-specific provider' do
let(:schema_name) { 'some_device' }

it('loads the device provider') { expect(described_class.load_provider('multi_provider').name).to eq 'Puppet::Provider::MultiProvider::SomeDevice' }
end
end
end

context 'with a provider that does canonicalization', agent_test: true do
Expand Down Expand Up @@ -1601,6 +1632,10 @@ def set(_context, changes)
stub_const('Puppet::Provider::Remoter::Remoter', provider_class)
allow(provider_class).to receive(:new).and_return(provider)
Puppet.settings[:strict] = :warning

module ::Puppet::Transport
class Wibble; end
end
end

it 'is seen as a supported feature' do
Expand All @@ -1618,6 +1653,30 @@ def set(_context, changes)
expect(type.context.type).to be_feature('remote_resource')
end
end

describe '#self.my_provider' do
subject(:type) { Puppet::Type.type(:remoter) }

let(:instance) { type.new(name: 'remote_thing', test_string: 'wibble') }
let(:wrapper) { instance_double('Puppet::ResourceApi::Transport::Wrapper', 'wrapper') }
let(:transport) { instance_double('Puppet::Transport::Wibble', 'transport') }

before(:each) do
allow(described_class).to receive(:load_provider).and_return(provider)
allow(provider).to receive(:new).and_return(provider)
end

context 'when a transport is returned by NetworkDevice.current' do
it 'stores the provider with the the name of the transport' do
allow(Puppet::Util::NetworkDevice).to receive(:current).and_return(wrapper)
allow(wrapper).to receive(:is_a?).with(Puppet::ResourceApi::Transport::Wrapper).and_return(true)
allow(wrapper).to receive(:transport).and_return(transport)
allow(transport).to receive(:class).and_return(Puppet::Transport::Wibble)

expect(instance.my_provider).to eq provider
end
end
end
end

context 'with a `supports_noop` provider', agent_test: true do
Expand Down