diff --git a/lib/puppet/indirector/catalog/json.rb b/lib/puppet/indirector/catalog/json.rb deleted file mode 100644 index cb0ff2d4b..000000000 --- a/lib/puppet/indirector/catalog/json.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'puppet/resource/catalog' -require 'puppet/indirector/json' - -class Puppet::Resource::Catalog::Json < Puppet::Indirector::JSON - desc "Store catalogs as flat files, serialized using JSON." -end diff --git a/lib/puppet/indirector/json.rb b/lib/puppet/indirector/json.rb deleted file mode 100644 index 6eae7e67d..000000000 --- a/lib/puppet/indirector/json.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'puppet/indirector/terminus' -require 'puppet/util/file_locking' - -# The base class for JSON indirection terminus implementations. -# -# This should generally be preferred to the YAML base for any future -# implementations, since it is ~ three times faster despite being pure Ruby -# rather than a C implementation. -class Puppet::Indirector::JSON < Puppet::Indirector::Terminus - include Puppet::Util::FileLocking - - def find(request) - load_json_from_file(path(request.key), request.key) - end - - def save(request) - filename = path(request.key) - FileUtils.mkdir_p(File.dirname(filename)) - writelock(filename, 0660) {|f| f.print to_json(request.instance) } - rescue TypeError => detail - Puppet.log_exception "Could not save #{self.name} #{request.key}: #{detail}" - end - - def destroy(request) - File.unlink(path(request.key)) - rescue => detail - unless detail.is_a? Errno::ENOENT - raise Puppet::Error, "Could not destroy #{self.name} #{request.key}: #{detail}" - end - 1 # emulate success... - end - - def search(request) - Dir.glob(path(request.key)).collect do |file| - load_json_from_file(file, request.key) - end - end - - # Return the path to a given node's file. - def path(name, ext = '.json') - if name =~ Puppet::Indirector::BadNameRegexp then - Puppet.crit("directory traversal detected in #{self.class}: #{name.inspect}") - raise ArgumentError, "invalid key" - end - - base = Puppet.run_mode.master? ? Puppet[:server_datadir] : Puppet[:client_datadir] - File.join(base, self.class.indirection_name.to_s, name.to_s + ext) - end - - private - - def load_json_from_file(file, key) - json = nil - - begin - readlock(file) {|fh| json = fh.read } - rescue => detail - return nil unless FileTest.exist?(file) - raise Puppet::Error, "Could not read JSON data for #{indirection.name} #{key}: #{detail}" - end - - begin - return from_json(json) - rescue => detail - raise Puppet::Error, "Could not parse JSON data for #{indirection.name} #{key}: #{detail}" - end - end - - def from_json(text) - model.convert_from('pson', text) - end - - def to_json(object) - object.render('pson') - end -end diff --git a/spec/lib/puppet/indirector/indirector_testing/json.rb b/spec/lib/puppet/indirector/indirector_testing/json.rb deleted file mode 100644 index cc60640d2..000000000 --- a/spec/lib/puppet/indirector/indirector_testing/json.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'puppet/indirector_testing' -require 'puppet/indirector/json' - -class Puppet::IndirectorTesting::JSON < Puppet::Indirector::JSON - desc "Testing the JSON indirector" -end diff --git a/spec/lib/puppet/indirector_testing.rb b/spec/lib/puppet/indirector_testing.rb deleted file mode 100644 index 883812158..000000000 --- a/spec/lib/puppet/indirector_testing.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'puppet/indirector' -require 'puppet/util/pson' - -class Puppet::IndirectorTesting - extend Puppet::Indirector - indirects :indirector_testing - - # We should have some way to identify if we got a valid object back with the - # current values, no? - attr_accessor :value - def initialize(value) - self.value = value - end - - PSON.register_document_type('IndirectorTesting',self) - def self.from_pson(data) - new(data['value']) - end - - def to_pson - { - 'document_type' => 'IndirectorTesting', - 'data' => { 'value' => value }, - 'metadata' => { 'api_version' => 1 } - }.to_pson - end -end diff --git a/spec/unit/indirector/catalog/json_spec.rb b/spec/unit/indirector/catalog/json_spec.rb deleted file mode 100755 index 8074707cf..000000000 --- a/spec/unit/indirector/catalog/json_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env rspec -require 'spec_helper' -require 'puppet/resource/catalog' -require 'puppet/indirector/catalog/json' - -describe Puppet::Resource::Catalog::Json do - # This is it for local functionality: we don't *do* anything else. - it "should be registered with the catalog store indirection" do - Puppet::Resource::Catalog.indirection.terminus(:json). - should be_an_instance_of described_class - end -end diff --git a/spec/unit/indirector/json_spec.rb b/spec/unit/indirector/json_spec.rb deleted file mode 100755 index baecae2ed..000000000 --- a/spec/unit/indirector/json_spec.rb +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env rspec -require 'spec_helper' -require 'puppet_spec/files' -require 'puppet/indirector/indirector_testing/json' - -describe Puppet::Indirector::JSON do - include PuppetSpec::Files - - subject { Puppet::IndirectorTesting::JSON.new } - let :model do Puppet::IndirectorTesting end - let :indirection do model.indirection end - - context "#path" do - before :each do - Puppet[:server_datadir] = '/sample/datadir/master' - Puppet[:client_datadir] = '/sample/datadir/client' - end - - it "uses the :server_datadir setting if this is the master" do - Puppet.run_mode.stubs(:master?).returns(true) - expected = File.join(Puppet[:server_datadir], 'indirector_testing', 'testing.json') - subject.path('testing').should == expected - end - - it "uses the :client_datadir setting if this is not the master" do - Puppet.run_mode.stubs(:master?).returns(false) - expected = File.join(Puppet[:client_datadir], 'indirector_testing', 'testing.json') - subject.path('testing').should == expected - end - - it "overrides the default extension with a supplied value" do - Puppet.run_mode.stubs(:master?).returns(true) - expected = File.join(Puppet[:server_datadir], 'indirector_testing', 'testing.not-json') - subject.path('testing', '.not-json').should == expected - end - - ['../foo', '..\\foo', './../foo', '.\\..\\foo', - '/foo', '//foo', '\\foo', '\\\\goo', - "test\0/../bar", "test\0\\..\\bar", - "..\\/bar", "/tmp/bar", "/tmp\\bar", "tmp\\bar", - " / bar", " /../ bar", " \\..\\ bar", - "c:\\foo", "c:/foo", "\\\\?\\UNC\\bar", "\\\\foo\\bar", - "\\\\?\\c:\\foo", "//?/UNC/bar", "//foo/bar", - "//?/c:/foo", - ].each do |input| - it "should resist directory traversal attacks (#{input.inspect})" do - expect { subject.path(input) }.to raise_error ArgumentError, 'invalid key' - end - end - end - - context "handling requests" do - before :each do - Puppet.run_mode.stubs(:master?).returns(true) - Puppet[:server_datadir] = tmpdir('jsondir') - FileUtils.mkdir_p(File.join(Puppet[:server_datadir], 'indirector_testing')) - end - - let :file do subject.path(request.key) end - - def with_content(text) - FileUtils.mkdir_p(File.dirname(file)) - File.open(file, 'w') {|f| f.puts text } - yield if block_given? - end - - it "data saves and then loads again correctly" do - subject.save(indirection.request(:save, 'example', model.new('banana'))) - subject.find(indirection.request(:find, 'example')).value.should == 'banana' - end - - context "#find" do - let :request do indirection.request(:find, 'example') end - - it "returns nil if the file doesn't exist" do - subject.find(request).should be_nil - end - - it "raises a descriptive error when the file can't be read" do - with_content(model.new('foo').to_pson) do - # I don't like this, but there isn't a credible alternative that - # also works on Windows, so a stub it is. At least the expectation - # will fail if the implementation changes. Sorry to the next dev. - File.expects(:open).with(file).raises(Errno::EPERM) - expect { subject.find(request) }. - to raise_error Puppet::Error, /Could not read JSON/ - end - end - - it "raises a descriptive error when the file content is invalid" do - with_content("this is totally invalid JSON") do - expect { subject.find(request) }. - to raise_error Puppet::Error, /Could not parse JSON data/ - end - end - - it "should return an instance of the indirected object when valid" do - with_content(model.new(1).to_pson) do - instance = subject.find(request) - instance.should be_an_instance_of model - instance.value.should == 1 - end - end - end - - context "#save" do - let :instance do model.new(4) end - let :request do indirection.request(:find, 'example', instance) end - - it "should save the instance of the request as JSON to disk" do - subject.save(request) - content = File.read(file) - content.should =~ /"document_type"\s*:\s*"IndirectorTesting"/ - content.should =~ /"value"\s*:\s*4/ - end - - it "should create the indirection directory if required" do - target = File.join(Puppet[:server_datadir], 'indirector_testing') - Dir.rmdir(target) - - subject.save(request) - - File.should be_directory target - end - end - - context "#destroy" do - let :request do indirection.request(:find, 'example') end - - it "removes an existing file" do - with_content('hello') do - subject.destroy(request) - end - File.should_not be_exist file - end - - it "silently succeeds when files don't exist" do - File.unlink(file) rescue nil - subject.destroy(request).should be_true - end - - it "raises an informative error for other failures" do - File.stubs(:unlink).with(file).raises(Errno::EPERM, 'fake permission problem') - with_content('hello') do - expect { subject.destroy(request) }.to raise_error Puppet::Error - end - File.unstub(:unlink) # thanks, mocha - end - end - end - - context "#search" do - before :each do - Puppet.run_mode.stubs(:master?).returns(true) - Puppet[:server_datadir] = tmpdir('jsondir') - FileUtils.mkdir_p(File.join(Puppet[:server_datadir], 'indirector_testing')) - end - - def request(glob) - indirection.request(:search, glob) - end - - def create_file(name, value = 12) - File.open(subject.path(name, ''), 'w') do |f| - f.puts Puppet::IndirectorTesting.new(value).to_pson - end - end - - it "returns an empty array when nothing matches the key as a glob" do - subject.search(request('*')).should == [] - end - - it "returns an array with one item if one item matches" do - create_file('foo.json', 'foo') - create_file('bar.json', 'bar') - subject.search(request('f*')).map(&:value).should == ['foo'] - end - - it "returns an array of items when more than one item matches" do - create_file('foo.json', 'foo') - create_file('bar.json', 'bar') - create_file('baz.json', 'baz') - subject.search(request('b*')).map(&:value).should =~ ['bar', 'baz'] - end - - it "only items with the .json extension" do - create_file('foo.json', 'foo-json') - create_file('foo.pson', 'foo-pson') - create_file('foo.json~', 'foo-backup') - subject.search(request('f*')).map(&:value).should == ['foo-json'] - end - end -end