diff options
author | Luke Kanies <luke@madstop.com> | 2007-10-18 20:47:56 -0500 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2007-10-18 20:47:56 -0500 |
commit | fc607513faa54d64186a674a36d81ea010745569 (patch) | |
tree | d409b20c752cdb50e2fe72e8f6ef815951c360b4 | |
parent | 64c6700bc7530f1213e124d248cc176a7cfe6180 (diff) | |
download | puppet-fc607513faa54d64186a674a36d81ea010745569.tar.gz puppet-fc607513faa54d64186a674a36d81ea010745569.tar.xz puppet-fc607513faa54d64186a674a36d81ea010745569.zip |
I've now split the file-serving termini into two separate types (in
addition to Rest): A local terminus that just uses direct file paths,
and a mounts terminus that uses the file server to figure out what
the path should be.
It looks like it also makes sense to split the 'mounts' terminus further,
so there is a 'modules' terminus used to look files up in the terminus.
I've added some integration tests to verify that everything is
hooked together correctly.
Lastly, I added a directory for shared behaviours. There's a ton of
duplication in this setup, because the Content and Metadata classes
behave almost but not quite identically across the board.
25 files changed, 594 insertions, 65 deletions
diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb index b1512e14e..6cd99b267 100644 --- a/lib/puppet/file_serving/configuration.rb +++ b/lib/puppet/file_serving/configuration.rb @@ -30,13 +30,22 @@ class Puppet::FileServing::Configuration # Return a content instance. def content(path, options = {}) - mount, file_path = splitpath(path, options[:node]) + mount, file_path = split_path(path, options[:node]) return nil unless mount mount.file_instance :content, file_path, options end + # Search for a file. + def file_path(key, options = {}) + mount, file_path = split_path(key, options[:node]) + + return nil unless mount + + return mount.file(file_path, options) + end + def initialize @mounts = {} @config_file = nil @@ -48,32 +57,13 @@ class Puppet::FileServing::Configuration # Return a metadata instance. def metadata(path, options = {}) - mount, file_path = splitpath(path, options[:node]) + mount, file_path = split_path(path, options[:node]) return nil unless mount mount.file_instance :metadata, file_path, options end - # Mount a new directory with a name. - def mount(path, name) - if @mounts.include?(name) - if @mounts[name] != path - raise FileServerError, "%s is already mounted at %s" % - [@mounts[name].path, name] - else - # it's already mounted; no problem - return - end - end - - # Let the mounts do their own error-checking. - @mounts[name] = Mount.new(name, path) - @mounts[name].info "Mounted %s" % path - - return @mounts[name] - end - # Is a given mount available? def mounted?(name) @mounts.include?(name) @@ -137,7 +127,7 @@ class Puppet::FileServing::Configuration end # Split the path into the separate mount point and path. - def splitpath(uri, node) + def split_path(uri, node) # Reparse the configuration if necessary. readconfig diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb index 73e1f53d4..7adb66981 100644 --- a/lib/puppet/file_serving/metadata.rb +++ b/lib/puppet/file_serving/metadata.rb @@ -23,12 +23,7 @@ class Puppet::FileServing::Metadata @checksum_type = type end - def initialize(path, checksum_type = "md5") - raise ArgumentError.new("Files must be fully qualified") unless path =~ /^#{::File::SEPARATOR}/ - raise ArgumentError.new("Files must exist") unless FileTest.exists?(path) - - @path = path - + def get_attributes stat = File.stat(path) @owner = stat.uid @group = stat.gid @@ -36,10 +31,20 @@ class Puppet::FileServing::Metadata # Set the octal mode, but as a string. @mode = "%o" % (stat.mode & 007777) - @checksum_type = checksum_type @checksum = get_checksum end + def initialize(path = nil) + if path + raise ArgumentError.new("Files must be fully qualified") unless path =~ /^#{::File::SEPARATOR}/ + raise ArgumentError.new("Files must exist") unless FileTest.exists?(path) + + @path = path + end + + @checksum_type = "md5" + end + private # Retrieve our checksum. diff --git a/lib/puppet/file_serving/terminus_helper.rb b/lib/puppet/file_serving/terminus_helper.rb new file mode 100644 index 000000000..b7f560c57 --- /dev/null +++ b/lib/puppet/file_serving/terminus_helper.rb @@ -0,0 +1,22 @@ +# +# Created by Luke Kanies on 2007-10-16. +# Copyright (c) 2007. All rights reserved. + +require 'uri' +require 'puppet/file_serving' +require 'puppet/file_serving/configuration' + +module Puppet::FileServing::TerminusHelper + def key2uri(key) + # Return it directly if it's fully qualified. + if key =~ /^#{::File::SEPARATOR}/ + key = "file://" + key + end + + begin + uri = URI.parse(URI.escape(key)) + rescue => detail + raise ArgumentError, "Could not understand URI %s: %s" % [key, detail.to_s] + end + end +end diff --git a/lib/puppet/file_serving/terminus_selector.rb b/lib/puppet/file_serving/terminus_selector.rb index 0cec4bf98..4525a8570 100644 --- a/lib/puppet/file_serving/terminus_selector.rb +++ b/lib/puppet/file_serving/terminus_selector.rb @@ -9,18 +9,26 @@ require 'puppet/file_serving' # in file-serving indirections. This is necessary because # the terminus varies based on the URI asked for. module Puppet::FileServing::TerminusSelector - PROTOCOL_MAP = {"puppet" => :rest, "file" => :local} + PROTOCOL_MAP = {"puppet" => :rest, "file" => :local, "puppetmounts" => :mounts} # Pick an appropriate terminus based on the protocol. - def select_terminus(uri) + def select_terminus(full_uri) # Short-circuit to :local if it's a fully-qualified path. - return PROTOCOL_MAP["file"] if uri =~ /^#{::File::SEPARATOR}/ + return PROTOCOL_MAP["file"] if full_uri =~ /^#{::File::SEPARATOR}/ begin - uri = URI.parse(URI.escape(uri)) + uri = URI.parse(URI.escape(full_uri)) rescue => detail - raise ArgumentError, "Could not understand URI %s: %s" % [uri, detail.to_s] + raise ArgumentError, "Could not understand URI %s: %s" % [full_uri, detail.to_s] end - return PROTOCOL_MAP[uri.scheme] || raise(ArgumentError, "URI protocol '%s' is not supported for file serving" % uri.scheme) + terminus = PROTOCOL_MAP[uri.scheme] || raise(ArgumentError, "URI protocol '%s' is not supported for file serving" % uri.scheme) + + # This provides a convenient mechanism for people to write configurations work + # well in both a networked and local setting. + if uri.host.nil? and uri.scheme == "puppet" and Puppet.settings[:name] == "puppet" + terminus = :mounts + end + + return terminus end end diff --git a/lib/puppet/indirector/file_content/local.rb b/lib/puppet/indirector/file_content/local.rb index 34d1c7794..a597fea55 100644 --- a/lib/puppet/indirector/file_content/local.rb +++ b/lib/puppet/indirector/file_content/local.rb @@ -3,12 +3,19 @@ # Copyright (c) 2007. All rights reserved. require 'puppet/file_serving/content' +require 'puppet/file_serving/terminus_helper' require 'puppet/indirector/file_content' require 'puppet/indirector/file' class Puppet::Indirector::FileContent::Local < Puppet::Indirector::File desc "Retrieve file contents from disk." - def find(path) + include Puppet::FileServing::TerminusHelper + + def find(key) + uri = key2uri(key) + + return nil unless FileTest.exists?(uri.path) + Puppet::FileServing::Content.new uri.path end end diff --git a/lib/puppet/indirector/file_content/mounts.rb b/lib/puppet/indirector/file_content/mounts.rb new file mode 100644 index 000000000..3d147d65a --- /dev/null +++ b/lib/puppet/indirector/file_content/mounts.rb @@ -0,0 +1,28 @@ +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require 'puppet/file_serving/content' +require 'puppet/file_serving/terminus_helper' +require 'puppet/indirector/file_content' +require 'puppet/indirector/code' + +class Puppet::Indirector::FileContent::Mounts < Puppet::Indirector::Code + desc "Retrieve file contents using Puppet's fileserver." + + include Puppet::FileServing::TerminusHelper + + # This way it can be cleared or whatever and we aren't retaining + # a reference to the old one. + def configuration + Puppet::FileServing::Configuration.create + end + + def find(key) + uri = key2uri(key) + + return nil unless path = configuration.file_path(uri.path) and FileTest.exists?(path) + + Puppet::FileServing::Content.new path + end +end diff --git a/lib/puppet/indirector/file_content/rest.rb b/lib/puppet/indirector/file_content/rest.rb new file mode 100644 index 000000000..9e2de360c --- /dev/null +++ b/lib/puppet/indirector/file_content/rest.rb @@ -0,0 +1,12 @@ +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require 'puppet/file_serving/content' +require 'puppet/file_serving/terminus_helper' +require 'puppet/indirector/file_content' +require 'puppet/indirector/rest' + +class Puppet::Indirector::FileContent::Rest < Puppet::Indirector::REST + desc "Retrieve file contents via a REST HTTP interface." +end diff --git a/lib/puppet/indirector/file_metadata/local.rb b/lib/puppet/indirector/file_metadata/local.rb index f6cfa1f1c..e1d774cc8 100644 --- a/lib/puppet/indirector/file_metadata/local.rb +++ b/lib/puppet/indirector/file_metadata/local.rb @@ -4,13 +4,21 @@ require 'puppet/file_serving/metadata' require 'puppet/indirector/file_metadata' +require 'puppet/file_serving/terminus_helper' require 'puppet/indirector/code' class Puppet::Indirector::FileMetadata::Local < Puppet::Indirector::Code - desc "Retrieve file metadata using Puppet's Resource Abstraction Layer. - Returns everything about the file except its content." + desc "Retrieve file metadata directly from the local filesystem." - def find(file) - Puppet::Node::Facts.new(key, Facter.to_hash) + include Puppet::FileServing::TerminusHelper + + def find(key) + uri = key2uri(key) + + return nil unless FileTest.exists?(uri.path) + data = Puppet::FileServing::Metadata.new uri.path + data.get_attributes + + return data end end diff --git a/lib/puppet/indirector/file_metadata/mounts.rb b/lib/puppet/indirector/file_metadata/mounts.rb new file mode 100644 index 000000000..6d7fe15c6 --- /dev/null +++ b/lib/puppet/indirector/file_metadata/mounts.rb @@ -0,0 +1,28 @@ +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require 'puppet/file_serving/metadata' +require 'puppet/file_serving/terminus_helper' +require 'puppet/indirector/file_metadata' +require 'puppet/indirector/code' + +class Puppet::Indirector::FileMetadata::Mounts < Puppet::Indirector::Code + desc "Retrieve file metadata using Puppet's fileserver." + + include Puppet::FileServing::TerminusHelper + + # This way it can be cleared or whatever and we aren't retaining + # a reference to the old one. + def configuration + Puppet::FileServing::Configuration.create + end + + def find(key) + uri = key2uri(key) + + return nil unless path = configuration.file_path(uri.path) and FileTest.exists?(path) + + Puppet::FileServing::Metadata.new path + end +end diff --git a/lib/puppet/indirector/file_metadata/rest.rb b/lib/puppet/indirector/file_metadata/rest.rb new file mode 100644 index 000000000..dcf875b25 --- /dev/null +++ b/lib/puppet/indirector/file_metadata/rest.rb @@ -0,0 +1,12 @@ +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require 'puppet/file_serving/metadata' +require 'puppet/file_serving/terminus_helper' +require 'puppet/indirector/file_metadata' +require 'puppet/indirector/rest' + +class Puppet::Indirector::FileMetadata::Rest < Puppet::Indirector::REST + desc "Retrieve file metadata via a REST HTTP interface." +end diff --git a/spec/integration/file_serving/content.rb b/spec/integration/file_serving/content.rb new file mode 100755 index 000000000..aee2a9f2d --- /dev/null +++ b/spec/integration/file_serving/content.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/file_serving/content' +require 'shared_behaviours/file_serving' + +describe Puppet::FileServing::Content, " when finding files" do + it_should_behave_like "Puppet::FileServing::Files" + + before do + @test_class = Puppet::FileServing::Content + @indirection = Puppet::FileServing::Content.indirection + end +end diff --git a/spec/integration/file_serving/metadata.rb b/spec/integration/file_serving/metadata.rb new file mode 100755 index 000000000..5600365f1 --- /dev/null +++ b/spec/integration/file_serving/metadata.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/file_serving/metadata' +require 'shared_behaviours/file_serving' + +describe Puppet::FileServing::Metadata, " when finding files" do + it_should_behave_like "Puppet::FileServing::Files" + + before do + @test_class = Puppet::FileServing::Metadata + @indirection = Puppet::FileServing::Metadata.indirection + end +end + diff --git a/spec/integration/indirector/file_content/mounts.rb b/spec/integration/indirector/file_content/mounts.rb new file mode 100755 index 000000000..cd80825c7 --- /dev/null +++ b/spec/integration/indirector/file_content/mounts.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/indirector/file_content/mounts' +require 'shared_behaviours/file_server_mounts' + +describe Puppet::Indirector::FileContent::Mounts, " when finding files" do + it_should_behave_like "Puppet::Indirector::FileServerMounts" + + before do + @terminus = Puppet::Indirector::FileContent::Mounts.new + @test_class = Puppet::FileServing::Content + end +end diff --git a/spec/integration/indirector/file_metadata/mounts.rb b/spec/integration/indirector/file_metadata/mounts.rb new file mode 100755 index 000000000..5899a9dbd --- /dev/null +++ b/spec/integration/indirector/file_metadata/mounts.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/indirector/file_metadata/mounts' +require 'shared_behaviours/file_server_mounts' + +describe Puppet::Indirector::FileMetadata::Mounts, " when finding files" do + it_should_behave_like "Puppet::Indirector::FileServerMounts" + + before do + @terminus = Puppet::Indirector::FileMetadata::Mounts.new + @test_class = Puppet::FileServing::Metadata + end +end diff --git a/spec/lib/shared_behaviours/file_server_mounts.rb b/spec/lib/shared_behaviours/file_server_mounts.rb new file mode 100644 index 000000000..955f88b44 --- /dev/null +++ b/spec/lib/shared_behaviours/file_server_mounts.rb @@ -0,0 +1,37 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +describe "Puppet::Indirector::FileServerMounts", :shared => true do + # This only works if the shared behaviour is included before + # the 'before' block in the including context. + before do + Puppet::FileServing::Configuration.clear_cache + FileTest.stubs(:exists?).with(Puppet[:fileserverconfig]).returns(true) + FileTest.stubs(:exists?).with("/my/mount/path").returns(true) + FileTest.stubs(:directory?).with("/my/mount/path").returns(true) + FileTest.stubs(:readable?).with("/my/mount/path").returns(true) + + # Use a real mount, so the integration is a bit deeper. + @mount1 = Puppet::FileServing::Configuration::Mount.new("one") + @mount1.path = "/my/mount/path" + + @parser = stub 'parser', :changed? => false + @parser.stubs(:parse).returns("one" => @mount1) + + Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) + + Puppet::FileServing::Configuration.create.stubs(:modules_mount) + end + + it "should use the file server configuration to find files" do + path = "/my/mount/path/my/file" + FileTest.stubs(:exists?).with(path).returns(true) + @test_class.expects(:new).with(path).returns(:myinstance) + FileTest.stubs(:exists?).with("/my/mount/path").returns(true) + @mount1.expects(:file).with("my/file", {}).returns(path) + + @terminus.find("puppetmounts://myhost/one/my/file").should == :myinstance + end +end diff --git a/spec/lib/shared_behaviours/file_serving.rb b/spec/lib/shared_behaviours/file_serving.rb new file mode 100644 index 000000000..ffc96ee78 --- /dev/null +++ b/spec/lib/shared_behaviours/file_serving.rb @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +describe "Puppet::FileServing::Files", :shared => true do + it "should use the rest terminus when the 'puppet' URI scheme is used and a host name is present" do + uri = "puppet://myhost/mymod/my/file" + @indirection.terminus(:rest).expects(:find).with(uri) + @test_class.find(uri) + end + + it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet'" do + uri = "puppet:///mymod/my/file" + Puppet.settings.stubs(:value).with(:name).returns("puppetd") + Puppet.settings.stubs(:value).with(:modulepath).returns("") + @indirection.terminus(:rest).expects(:find).with(uri) + @test_class.find(uri) + end + + it "should use the mounts terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'puppet'" do + uri = "puppet:///mymod/my/file" + Puppet.settings.stubs(:value).with(:name).returns("puppet") + Puppet.settings.stubs(:value).with(:modulepath).returns("") + Puppet.settings.stubs(:value).with(:libdir).returns("") + Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") + @indirection.terminus(:mounts).expects(:find).with(uri) + @test_class.find(uri) + end + + it "should use the mounts terminus when the 'puppetmounts' URI scheme is used" do + uri = "puppetmounts:///mymod/my/file" + @indirection.terminus(:mounts).expects(:find).with(uri) + @test_class.find(uri) + end + + it "should use the local terminus when the 'file' URI scheme is used" do + uri = "file:///mymod/my/file" + @indirection.terminus(:local).expects(:find).with(uri) + @test_class.find(uri) + end + + it "should use the local terminus when a fully qualified path is provided" do + uri = "/mymod/my/file" + @indirection.terminus(:local).expects(:find).with(uri) + @test_class.find(uri) + end +end + diff --git a/spec/unit/file_serving/configuration.rb b/spec/unit/file_serving/configuration.rb index eabad0838..b0b3527e7 100755 --- a/spec/unit/file_serving/configuration.rb +++ b/spec/unit/file_serving/configuration.rb @@ -117,9 +117,7 @@ describe Puppet::FileServing::Configuration, " when using a module mount" do it "should prefer module mounts to static mounts" end -# We're kind of testing the implementation here, because we know that both -# content and metadata use the same internal method. Oh well. -describe Puppet::FileServing::Configuration, " when using File URIs to pick the correct mount and file" do +describe Puppet::FileServing::Configuration, " when finding files" do include FSConfigurationTesting before do @@ -139,48 +137,50 @@ describe Puppet::FileServing::Configuration, " when using File URIs to pick the it "should fail if the uri does not match a leading slash followed by a valid mount name" do @parser.expects(:parse).returns(@mounts) - proc { @config.metadata("something") }.should raise_error(ArgumentError) + proc { @config.file_path("something") }.should raise_error(ArgumentError) end it "should use the first term after the first slash for the mount name" do @parser.expects(:parse).returns(@mounts) - @mount1.expects(:file_instance) - @config.metadata("/one") + @mount1.expects(:file) + @config.file_path("/one") end it "should use the remainder of the URI after the mount name as the file name" do @parser.expects(:parse).returns(@mounts) - @mount1.expects(:file_instance).with(:metadata, "something/else", {}) - @config.metadata("/one/something/else") + @mount1.expects(:file).with("something/else", {}) + @config.file_path("/one/something/else") end it "should treat a bare name as a mount and no relative file" do @parser.expects(:parse).returns(@mounts) - @mount1.expects(:file_instance).with(:metadata, nil, {}) - @config.metadata("/one") + @mount1.expects(:file).with(nil, {}) + @config.file_path("/one") end it "should treat a name with a trailing slash equivalently to a name with no trailing slash" do @parser.expects(:parse).returns(@mounts) - @mount1.expects(:file_instance).with(:metadata, nil, {}) - @config.metadata("/one/") + @mount1.expects(:file).with(nil, {}) + @config.file_path("/one/") end it "should return nil if the mount cannot be found" do @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns({}) - @config.metadata("/one/something").should be_nil + @config.file_path("/one/something").should be_nil end + it "should return nil if the mount does not contain the file" + it "should reparse the configuration file when it has changed" do - @mount1.stubs(:file_instance).returns("whatever") + @mount1.stubs(:file).returns("whatever") @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns(@mounts) - @config.metadata("/one/something") + @config.file_path("/one/something") @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns({}) - @config.metadata("/one/something").should be_nil + @config.file_path("/one/something").should be_nil end end diff --git a/spec/unit/file_serving/content.rb b/spec/unit/file_serving/content.rb index 6d8e2d0ba..593278bf4 100755 --- a/spec/unit/file_serving/content.rb +++ b/spec/unit/file_serving/content.rb @@ -33,7 +33,7 @@ describe Puppet::FileServing::Content, " when initializing" do proc { Puppet::FileServing::Content.new(@path) }.should raise_error(ArgumentError) end - it "should not read the file" do + it "should not stat the file" do FileTest.expects(:exists?).with(@path).returns(true) File.expects(:read).with(@path).never Puppet::FileServing::Content.new(@path) @@ -52,3 +52,13 @@ describe Puppet::FileServing::Content, " when converting to yaml" do @content.to_yaml.should == "mycontent" end end + +describe Puppet::FileServing::Content, " when converting from yaml" do + # LAK:FIXME This isn't in the right place, but we need some kind of + # control somewhere that requires that all REST connections only pull + # from the file-server, thus guaranteeing they go through our authorization + # hook. + it "should set the URI scheme to 'puppetmounts'" do + pending "We need to figure out where this should be" + end +end diff --git a/spec/unit/file_serving/metadata.rb b/spec/unit/file_serving/metadata.rb index f54a6feb6..1237c3184 100755 --- a/spec/unit/file_serving/metadata.rb +++ b/spec/unit/file_serving/metadata.rb @@ -15,11 +15,19 @@ describe Puppet::FileServing::Metadata do end describe Puppet::FileServing::Metadata, " when initializing" do - it "should require a fully qualified file path" do + it "should allow initialization without a path" do + proc { Puppet::FileServing::Metadata.new() }.should_not raise_error + end + + it "should allow initialization with a path" do + proc { Puppet::FileServing::Metadata.new("unqualified") }.should raise_error(ArgumentError) + end + + it "should the path to be fully qualified if it is provied" do proc { Puppet::FileServing::Metadata.new("unqualified") }.should raise_error(ArgumentError) end - it "should require the path to exist" do + it "should require the path to exist if it is provided" do FileTest.expects(:exists?).with("/no/such/path").returns(false) proc { Puppet::FileServing::Metadata.new("/no/such/path") }.should raise_error(ArgumentError) end @@ -36,6 +44,7 @@ describe Puppet::FileServing::Metadata do @checksum = Digest::MD5.hexdigest("some content\n") FileTest.expects(:exists?).with(@path).returns(true) @metadata = Puppet::FileServing::Metadata.new(@path) + @metadata.get_attributes end it "should accept a file path" do @@ -76,3 +85,13 @@ describe Puppet::FileServing::Metadata do @metadata.checksum.should == "{md5}" + @checksum end end + +describe Puppet::FileServing::Metadata, " when converting from yaml" do + # LAK:FIXME This isn't in the right place, but we need some kind of + # control somewhere that requires that all REST connections only pull + # from the file-server, thus guaranteeing they go through our authorization + # hook. + it "should set the URI scheme to 'puppetmounts'" do + pending "We need to figure out where this should be" + end +end diff --git a/spec/unit/file_serving/terminus_helper.rb b/spec/unit/file_serving/terminus_helper.rb new file mode 100755 index 000000000..f136da553 --- /dev/null +++ b/spec/unit/file_serving/terminus_helper.rb @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/file_serving/terminus_helper' + +module TerminusHelperTesting + def setup + @helper = Object.new + @config = mock 'fs configuration' + Puppet::FileServing::Configuration.stubs(:create).returns(@config) + @helper.extend(Puppet::FileServing::TerminusHelper) + end +end + +describe Puppet::FileServing::TerminusHelper, " when converting a key to a URI" do + include TerminusHelperTesting + + it "should escape the key before parsing" do + URI.expects(:escape).with("mykey").returns("http://myhost/blah") + URI.expects(:parse).with("http://myhost/blah").returns(:myuri) + @helper.key2uri("mykey").should == :myuri + end + + it "should use the URI class to parse the key" do + URI.expects(:parse).with("http://myhost/blah").returns(:myuri) + @helper.key2uri("http://myhost/blah").should == :myuri + end + + it "should set the scheme to 'file' if the key is a fully qualified path" do + URI.expects(:parse).with("file:///myhost/blah").returns(:myuri) + @helper.key2uri("/myhost/blah").should == :myuri + end + + it "should set the host to 'nil' if the key is a fully qualified path" do + URI.expects(:parse).with("file:///myhost/blah").returns(:myuri) + @helper.key2uri("/myhost/blah").should == :myuri + end +end + +describe Puppet::FileServing::TerminusHelper, " when returning file paths" do + include TerminusHelperTesting + + it "should follow links if the links option is set to :follow" + + it "should ignore links if the links option is not set to follow" +end diff --git a/spec/unit/file_serving/terminus_selector.rb b/spec/unit/file_serving/terminus_selector.rb index 4a5683e88..d21e42839 100755 --- a/spec/unit/file_serving/terminus_selector.rb +++ b/spec/unit/file_serving/terminus_selector.rb @@ -13,10 +13,37 @@ describe Puppet::FileServing::TerminusSelector, " when being used to select term @object.extend(Puppet::FileServing::TerminusSelector) end + it "should escape the key before parsing" do + uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" + URI.expects(:escape).with("mykey").returns("http://myhost/blah") + URI.expects(:parse).with("http://myhost/blah").returns(uri) + @object.select_terminus("mykey") + end + + it "should use the URI class to parse the key" do + uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" + URI.expects(:parse).with("http://myhost/blah").returns(uri) + @object.select_terminus("http://myhost/blah") + end + it "should choose :rest when the protocol is 'puppet'" do @object.select_terminus("puppet://host/module/file").should == :rest end + it "should choose :mounts when the protocol is 'puppetmounts'" do + @object.select_terminus("puppetmounts://host/module/file").should == :mounts + end + + it "should choose :mounts when no server name is provided and the process name is 'puppet'" do + Puppet.settings.expects(:value).with(:name).returns("puppet") + @object.select_terminus("puppet:///module/file").should == :mounts + end + + it "should choose :rest when no server name is provided and the process name is not 'puppet'" do + Puppet.settings.expects(:value).with(:name).returns("puppetd") + @object.select_terminus("puppet:///module/file").should == :rest + end + it "should choose :local when the protocol is 'file'" do @object.select_terminus("file://host/module/file").should == :local end @@ -25,7 +52,7 @@ describe Puppet::FileServing::TerminusSelector, " when being used to select term @object.select_terminus("/module/file").should == :local end - it "should fail when a protocol other than :puppet or :file is used" do + it "should fail when a protocol other than :puppet, :file, or :puppetmounts is used" do proc { @object.select_terminus("http:///module/file") }.should raise_error(ArgumentError) end end diff --git a/spec/unit/indirector/file_content/local.rb b/spec/unit/indirector/file_content/local.rb index 81ebd8ed0..361628767 100755 --- a/spec/unit/indirector/file_content/local.rb +++ b/spec/unit/indirector/file_content/local.rb @@ -17,13 +17,21 @@ describe Puppet::Indirector::FileContent::Local do end end -describe Puppet::Indirector::FileContent::Local, "when finding a single local" do - before do +describe Puppet::Indirector::FileContent::Local, "when finding a single file" do + it "should return a Content instance created with the full path to the file if the file exists" do @content = Puppet::Indirector::FileContent::Local.new - @path = "/my/local" + @uri = "file:///my/local" + + FileTest.expects(:exists?).with("/my/local").returns true + Puppet::FileServing::Content.expects(:new).with("/my/local").returns(:mycontent) + @content.find(@uri).should == :mycontent end - it "should return nil if the local does not exist" + it "should return nil if the file does not exist" do + @content = Puppet::Indirector::FileContent::Local.new + @uri = "file:///my/local" - it "should return a Content instance with the path set to the local if the local exists" + FileTest.expects(:exists?).with("/my/local").returns false + @content.find(@uri).should be_nil + end end diff --git a/spec/unit/indirector/file_content/mounts.rb b/spec/unit/indirector/file_content/mounts.rb new file mode 100755 index 000000000..0a137d57e --- /dev/null +++ b/spec/unit/indirector/file_content/mounts.rb @@ -0,0 +1,53 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/indirector/file_content/mounts' + +describe Puppet::Indirector::FileContent::Mounts do + it "should be registered with the file_content indirection" do + Puppet::Indirector::Terminus.terminus_class(:file_content, :mounts).should equal(Puppet::Indirector::FileContent::Mounts) + end + + it "should be a subclass of the Code terminus" do + Puppet::Indirector::FileContent::Mounts.superclass.should equal(Puppet::Indirector::Code) + end +end + +describe Puppet::Indirector::FileContent::Mounts, "when finding a single file" do + before do + @content = Puppet::Indirector::FileContent::Mounts.new + @uri = "puppetmounts://host/my/local" + end + + it "should use the path portion of the URI as the file name" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local") + @content.find(@uri) + end + + it "should use the FileServing configuration to convert the file name to a fully qualified path" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local") + @content.find(@uri) + end + + it "should return nil if no fully qualified path is found" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns(nil) + @content.find(@uri).should be_nil + end + + it "should return nil if the configuration returns a file path that does not exist" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns("/some/file") + FileTest.expects(:exists?).with("/some/file").returns(false) + @content.find(@uri).should be_nil + end + + it "should return a Content instance if a file is found and it exists" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns("/some/file") + FileTest.expects(:exists?).with("/some/file").returns(true) + Puppet::FileServing::Content.expects(:new).with("/some/file").returns(:mycontent) + @content.find(@uri).should == :mycontent + end +end diff --git a/spec/unit/indirector/file_metadata/local.rb b/spec/unit/indirector/file_metadata/local.rb index 26837b911..604cdf6af 100755 --- a/spec/unit/indirector/file_metadata/local.rb +++ b/spec/unit/indirector/file_metadata/local.rb @@ -12,3 +12,32 @@ describe Puppet::Indirector::FileMetadata::Local do Puppet::Indirector::Terminus.terminus_class(:file_metadata, :local).should equal(Puppet::Indirector::FileMetadata::Local) end end + +describe Puppet::Indirector::FileMetadata::Local, "when finding a single file" do + before do + @content = Puppet::Indirector::FileMetadata::Local.new + @uri = "file:///my/local" + + @data = mock 'metadata' + end + it "should return a Metadata instance created with the full path to the file if the file exists" do + @data.stubs(:get_attributes) + + FileTest.expects(:exists?).with("/my/local").returns true + Puppet::FileServing::Metadata.expects(:new).with("/my/local").returns(@data) + @content.find(@uri).should == @data + end + + it "should collect its attributes when a file is found" do + @data.expects(:get_attributes) + + FileTest.expects(:exists?).with("/my/local").returns true + Puppet::FileServing::Metadata.expects(:new).with("/my/local").returns(@data) + @content.find(@uri).should == @data + end + + it "should return nil if the file does not exist" do + FileTest.expects(:exists?).with("/my/local").returns false + @content.find(@uri).should be_nil + end +end diff --git a/spec/unit/indirector/file_metadata/mounts.rb b/spec/unit/indirector/file_metadata/mounts.rb new file mode 100755 index 000000000..558e920ee --- /dev/null +++ b/spec/unit/indirector/file_metadata/mounts.rb @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-10-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/indirector/file_metadata/mounts' + +describe Puppet::Indirector::FileMetadata::Mounts do + it "should be registered with the file_metadata indirection" do + Puppet::Indirector::Terminus.terminus_class(:file_metadata, :mounts).should equal(Puppet::Indirector::FileMetadata::Mounts) + end + + it "should be a subclass of the Code terminus" do + Puppet::Indirector::FileMetadata::Mounts.superclass.should equal(Puppet::Indirector::Code) + end +end + +describe Puppet::Indirector::FileMetadata::Mounts, "when finding a single file" do + before do + @metadata = Puppet::Indirector::FileMetadata::Mounts.new + @uri = "puppetmounts://host/my/local" + end + + it "should use the path portion of the URI as the file name" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local") + @metadata.find(@uri) + end + + it "should use the FileServing configuration to convert the file name to a fully qualified path" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local") + @metadata.find(@uri) + end + + it "should return nil if no fully qualified path is found" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns(nil) + @metadata.find(@uri).should be_nil + end + + it "should return nil if the configuration returns a file path that does not exist" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns("/some/file") + FileTest.expects(:exists?).with("/some/file").returns(false) + @metadata.find(@uri).should be_nil + end + + it "should return a Metadata instance if a file is found and it exists" do + Puppet::FileServing::Configuration.create.expects(:file_path).with("/my/local").returns("/some/file") + FileTest.expects(:exists?).with("/some/file").returns(true) + Puppet::FileServing::Metadata.expects(:new).with("/some/file").returns(:mymetadata) + @metadata.find(@uri).should == :mymetadata + end +end + |