Skip to content
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
6 changes: 6 additions & 0 deletions lib/puppet/resource_api/transport.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# rubocop:disable Style/Documentation
module Puppet; end
module Puppet::ResourceApi; end
module Puppet::ResourceApi::Transport; end
# rubocop:enable Style/Documentation

# Remote target transport API
module Puppet::ResourceApi::Transport
def register(schema)
Expand Down
43 changes: 43 additions & 0 deletions lib/puppet/resource_api/transport/wrapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require 'puppet/resource_api/transport'
require 'hocon'
require 'hocon/config_syntax'

# Puppet::ResourceApi::Transport::Wrapper` to interface between the Util::NetworkDevice
class Puppet::ResourceApi::Transport::Wrapper
attr_reader :transport

def initialize(name, url_or_config)
if url_or_config.is_a? String
@url = URI.parse(url_or_config)
raise "Unexpected url '#{url_or_config}' found. Only file:/// URLs for configuration supported at the moment." unless @url.scheme == 'file'
else
@config = url_or_config
end

@transport = Puppet::ResourceApi::Transport.connect(name, config)
end

def config
raise "Trying to load config from '#{@url.path}, but file does not exist." if @url && !File.exist?(@url.path)
# symbolize top-level keys to match up with expected provider/resource data conventions
@config ||= (Hocon.load(@url.path, syntax: Hocon::ConfigSyntax::HOCON) || {}).map { |k, v| [k.to_sym, v] }.to_h
end

def facts
# @transport.facts + custom_facts # look into custom facts work by TP
@transport.facts
end

def respond_to_missing?(name, _include_private)
(@transport.respond_to? name) || super
end

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
end
end
end
8 changes: 7 additions & 1 deletion spec/acceptance/device_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@
<<DEVICE_CONF
[the_node]
type test_device
url file:///etc/credentials.txt
url file://#{device_credentials.path}
DEVICE_CONF
end
let(:device_credentials) { Tempfile.new('credentials.txt') }
let(:device_credentials_content) { {} }

def is_device_apply_supported?
Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('5.3.6') && Gem::Version.new(Puppet::PUPPETVERSION) != Gem::Version.new('5.4.0')
Expand All @@ -86,10 +88,14 @@ def is_device_apply_supported?
skip "No device --apply in puppet before v5.3.6 nor in v5.4.0 (v#{Puppet::PUPPETVERSION} is installed)" unless is_device_apply_supported?
device_conf.write(device_conf_content)
device_conf.close

device_credentials.write(device_credentials_content)
device_credentials.close
end

after(:each) do
device_conf.unlink
device_credentials.unlink
end

context 'with no config specified' do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require 'puppet/resource_api'

Puppet::ResourceApi.register_transport(
name: 'test_device', # points at class Puppet::Transport::TestDevice
desc: 'Connects to a device',
connection_info: {
},
)
21 changes: 21 additions & 0 deletions spec/fixtures/test_module/lib/puppet/transport/test_device.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Puppet::Transport
# a transport for a test_device
class TestDevice
def initialize(connection_info);
puts connection_info
end

def facts
{ 'foo' => 'bar' }
end

def verify
return true
end

def close
return
end
end

end
116 changes: 116 additions & 0 deletions spec/puppet/resource_api/transport/wrapper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
require 'spec_helper'
require 'puppet/resource_api/transport/wrapper'
require_relative '../../../fixtures/test_module/lib/puppet/transport/test_device'

RSpec.describe Puppet::ResourceApi::Transport::Wrapper, agent_test: true do
describe '#initialize(name, url_or_config)' do
context 'when called with a url' do
context 'with a file:// prefix' do
let(:url) { 'file:///etc/credentials' }

it 'will not throw an error' do
allow(File).to receive(:exist?).and_return(true)
expect(Puppet::ResourceApi::Transport).to receive(:connect)
expect(Hocon).to receive(:load)
expect { described_class.new('wibble', url) }.not_to raise_error
end
end

context 'with an http:// prefix' do
let(:url) { 'http://www.puppet.com' }

it { expect { described_class.new('wibble', url) }.to raise_error RuntimeError, %r{Only file:/// URLs for configuration supported} }
end
end

context 'when called with a config hash' do
let(:config) { {} }

it 'will use the configuration directly' do
expect(Hocon).not_to receive(:load)
expect(Puppet::ResourceApi::Transport).to receive(:connect)
described_class.new('wibble', config)
end
end
end

describe '#facts' do
context 'when called' do
let(:instance) { described_class.new('wibble', {}) }
let(:facts) { { 'foo' => 'bar' } }
let(:transport) { instance_double(Puppet::Transport::TestDevice, 'transport') }

it 'will return the facts provided by the transport' do
allow(Puppet::ResourceApi::Transport).to receive(:connect).and_return(transport)
allow(transport).to receive(:facts).and_return(facts)

expect(instance.facts).to eq(facts)
end
end
end

context 'when an unsupported method is called' do
context 'when the transport can handle the method' do
let(:instance) { described_class.new('wibble', {}) }
let(:transport) { instance_double(Puppet::Transport::TestDevice, 'transport') }

it 'will return the facts provided by the transport' do
allow(Puppet::ResourceApi::Transport).to receive(:connect).and_return(transport)
expect(transport).to receive(:close)

instance.close
end
end

context 'when the transport cannot handle the method' do
let(:instance) { described_class.new('wibble', {}) }
let(:transport) { instance_double(Puppet::Transport::TestDevice, 'transport') }

it 'will raise a NoMethodError' do
allow(Puppet::ResourceApi::Transport).to receive(:connect).and_return(transport)
expect { instance.wibble }.to raise_error NoMethodError
end
end
end

context 'when a method is checked for' do
let(:instance) { described_class.new('wibble', {}) }
let(:transport) { instance_double(Puppet::Transport::TestDevice, 'transport') }

before(:each) do
allow(Puppet::ResourceApi::Transport).to receive(:connect).and_return(transport)
end

context 'when the transport does not support the function' do
context 'when using respond_to?' do
it 'will return false' do
expect(instance.respond_to?(:wibble)).to eq(false)
end
end

context 'when using method?' do
it 'will return false' do
expect { instance.method :wibble }.to raise_error
end
end
end

context 'when the transport does support the function' do
before(:each) do
allow(transport).to receive(:close)
end

context 'when using respond_to?' do
it 'will return true' do
expect(instance.respond_to?(:close)).to eq(true)
end
end

context 'when using method?' do
it 'will return the method' do
expect(instance.method(:close)).to be_a(Method)
end
end
end
end
end
4 changes: 2 additions & 2 deletions spec/puppet/resource_api/transport_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@
end

context 'when the transport file does exist' do
context 'with and incorrectly defined transport' do
context 'with an incorrectly defined transport' do
it 'throws a DevError' do
expect(described_class).to receive(:validate).with(name, connection_info)
expect(described_class).to receive(:require).with('puppet/transport/test_target')
expect { described_class.connect(name, connection_info) }.to raise_error Puppet::DevError,
%r{uninitialized constant Puppet::Transport}
%r{uninitialized constant (Puppet::Transport|TestTarget)}
end
end

Expand Down