[Pkg-puppet-devel] [facter] 104/180: Revert "Merge branch 'stable' into facter-2"
Stig Sandbeck Mathisen
ssm at debian.org
Mon Jun 30 15:06:36 UTC 2014
This is an automated email from the git hooks/post-receive script.
ssm pushed a commit to branch master
in repository facter.
commit 4fad4dece13e08209a95011a6e94381562df59ca
Author: Kylo Ginsberg <kylo at puppetlabs.com>
Date: Fri May 23 13:17:53 2014 -0700
Revert "Merge branch 'stable' into facter-2"
This reverts commit 14eef77237ac1c9c0906890af696ad35e0f3b78e, reversing
changes made to 07629d6a8b4f9c7a5d00cdb87dbc90befd6d1f3f.
---
lib/facter/core/suitable.rb | 6 +-
lib/facter/ec2.rb | 59 ++++----
lib/facter/ec2/rest.rb | 129 ++++++++++++++++
lib/facter/util/ec2.rb | 5 +
lib/facter/util/values.rb | 29 ++++
spec/fixtures/unit/ec2/rest/meta-data/root | 20 +++
spec/unit/core/suitable_spec.rb | 10 ++
spec/unit/ec2/rest_spec.rb | 140 +++++++++++++++++
spec/unit/ec2_spec.rb | 234 +++++++++++------------------
spec/unit/util/ec2_spec.rb | 4 +
spec/unit/util/values_spec.rb | 40 +++++
11 files changed, 498 insertions(+), 178 deletions(-)
diff --git a/lib/facter/core/suitable.rb b/lib/facter/core/suitable.rb
index 1b3c04f..0262470 100644
--- a/lib/facter/core/suitable.rb
+++ b/lib/facter/core/suitable.rb
@@ -108,10 +108,6 @@ module Facter::Core::Suitable
#
# @api private
def suitable?
- unless defined? @suitable
- @suitable = ! @confines.detect { |confine| ! confine.true? }
- end
-
- return @suitable
+ @confines.all? { |confine| confine.true? }
end
end
diff --git a/lib/facter/ec2.rb b/lib/facter/ec2.rb
index 09e0109..2e57592 100644
--- a/lib/facter/ec2.rb
+++ b/lib/facter/ec2.rb
@@ -1,37 +1,44 @@
-require 'facter/util/ec2'
-require 'open-uri'
+require 'facter/ec2/rest'
-def metadata(id = "")
- open("http://169.254.169.254/2008-02-01/meta-data/#{id||=''}").read.
- split("\n").each do |o|
- key = "#{id}#{o.gsub(/\=.*$/, '/')}"
- if key[-1..-1] != '/'
- value = open("http://169.254.169.254/2008-02-01/meta-data/#{key}").read.
- split("\n")
- symbol = "ec2_#{key.gsub(/\-|\//, '_')}".to_sym
- Facter.add(symbol) { setcode { value.join(',') } }
- else
- metadata(key)
+Facter.define_fact(:ec2_metadata) do
+ define_resolution(:rest) do
+ confine do
+ Facter.value(:virtual).match /^xen/
+ end
+
+ @querier = Facter::EC2::Metadata.new
+ confine do
+ @querier.reachable?
+ end
+
+ setcode do
+ @querier.fetch
end
end
-rescue => details
- Facter.warn "Could not retrieve ec2 metadata: #{details.message}"
end
-def userdata()
- Facter.add(:ec2_userdata) do
+Facter.define_fact(:ec2_userdata) do
+ define_resolution(:rest) do
+ confine do
+ Facter.value(:virtual).match /^xen/
+ end
+
+ @querier = Facter::EC2::Userdata.new
+ confine do
+ @querier.reachable?
+ end
+
setcode do
- if userdata = Facter::Util::EC2.userdata
- userdata.split
- end
+ @querier.fetch
end
end
end
-if (Facter::Util::EC2.has_euca_mac? || Facter::Util::EC2.has_openstack_mac? ||
- Facter::Util::EC2.has_ec2_arp?) && Facter::Util::EC2.can_connect?
- metadata
- userdata
-else
- Facter.debug "Not an EC2 host"
+# The flattened version of the EC2 facts are deprecated and will be removed in
+# a future release of Facter.
+if (ec2_metadata = Facter.value(:ec2_metadata))
+ ec2_facts = Facter::Util::Values.flatten_structure("ec2", ec2_metadata)
+ ec2_facts.each_pair do |factname, factvalue|
+ Facter.add(factname, :value => factvalue)
+ end
end
diff --git a/lib/facter/ec2/rest.rb b/lib/facter/ec2/rest.rb
new file mode 100644
index 0000000..e9c1fca
--- /dev/null
+++ b/lib/facter/ec2/rest.rb
@@ -0,0 +1,129 @@
+require 'timeout'
+require 'open-uri'
+
+module Facter
+ module EC2
+ CONNECTION_ERRORS = [
+ Errno::EHOSTDOWN,
+ Errno::EHOSTUNREACH,
+ Errno::ENETUNREACH,
+ Errno::ECONNABORTED,
+ Errno::ECONNREFUSED,
+ Errno::ECONNRESET,
+ Errno::ETIMEDOUT,
+ ]
+
+ class Base
+ def reachable?(retry_limit = 3)
+ timeout = 0.2
+ able_to_connect = false
+ attempts = 0
+
+ begin
+ Timeout.timeout(timeout) do
+ open(@baseurl).read
+ end
+ able_to_connect = true
+ rescue OpenURI::HTTPError => e
+ if e.message.match /404 Not Found/i
+ able_to_connect = false
+ else
+ retry if attempts < retry_limit
+ end
+ rescue Timeout::Error
+ retry if attempts < retry_limit
+ rescue *CONNECTION_ERRORS
+ retry if attempts < retry_limit
+ ensure
+ attempts = attempts + 1
+ end
+
+ able_to_connect
+ end
+ end
+
+ class Metadata < Base
+
+ DEFAULT_URI = "http://169.254.169.254/latest/meta-data/"
+
+ def initialize(uri = DEFAULT_URI)
+ @baseurl = uri
+ end
+
+ def fetch(path = '')
+ results = {}
+
+ keys = fetch_endpoint(path)
+ keys.each do |key|
+ if key.match(%r[/$])
+ # If a metadata key is suffixed with '/' then it's a general metadata
+ # resource, so we have to recursively look up all the keys in the given
+ # collection.
+ name = key[0..-2]
+ results[name] = fetch("#{path}#{key}")
+ else
+ # This is a simple key/value pair, we can just query the given endpoint
+ # and store the results.
+ ret = fetch_endpoint("#{path}#{key}")
+ results[key] = ret.size > 1 ? ret : ret.first
+ end
+ end
+
+ results
+ end
+
+ # @param path [String] The path relative to the object base url
+ #
+ # @return [Array, NilClass]
+ def fetch_endpoint(path)
+ uri = @baseurl + path
+ body = open(uri).read
+ parse_results(body)
+ rescue OpenURI::HTTPError => e
+ if e.message.match /404 Not Found/i
+ return nil
+ else
+ Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+ return nil
+ end
+ rescue *CONNECTION_ERRORS => e
+ Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+ return nil
+ end
+
+ private
+
+ def parse_results(body)
+ lines = body.split("\n")
+ lines.map do |line|
+ if (match = line.match(/^(\d+)=.*$/))
+ # Metadata arrays are formatted like '<index>=<associated key>/', so
+ # we need to extract the index from that output.
+ "#{match[1]}/"
+ else
+ line
+ end
+ end
+ end
+ end
+
+ class Userdata < Base
+ DEFAULT_URI = "http://169.254.169.254/latest/user-data/"
+
+ def initialize(uri = DEFAULT_URI)
+ @baseurl = uri
+ end
+
+ def fetch
+ open(@baseurl).read
+ rescue OpenURI::HTTPError => e
+ if e.message.match /404 Not Found/i
+ return nil
+ else
+ Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+ return nil
+ end
+ end
+ end
+ end
+end
diff --git a/lib/facter/util/ec2.rb b/lib/facter/util/ec2.rb
index c6e5dca..b81c8fe 100644
--- a/lib/facter/util/ec2.rb
+++ b/lib/facter/util/ec2.rb
@@ -11,6 +11,7 @@ module Facter::Util::EC2
# The +wait_sec+ parameter provides you with an adjustable timeout.
#
def can_connect?(wait_sec=2)
+ Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
url = "http://169.254.169.254:80/"
Timeout::timeout(wait_sec) {open(url)}
return true
@@ -23,6 +24,7 @@ module Facter::Util::EC2
# Test if this host has a mac address used by Eucalyptus clouds, which
# normally is +d0:0d+.
def has_euca_mac?
+ Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
!!(Facter.value(:macaddress) =~ %r{^[dD]0:0[dD]:})
end
@@ -30,12 +32,14 @@ module Facter::Util::EC2
# normally starts with FA:16:3E (older versions of OpenStack
# may generate mac addresses starting with 02:16:3E)
def has_openstack_mac?
+ Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
!!(Facter.value(:macaddress) =~ %r{^(02|[fF][aA]):16:3[eE]})
end
# Test if the host has an arp entry in its cache that matches the EC2 arp,
# which is normally +fe:ff:ff:ff:ff:ff+.
def has_ec2_arp?
+ Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
kernel = Facter.value(:kernel)
mac_address_re = case kernel
@@ -73,6 +77,7 @@ module Facter::Util::EC2
#
# @return [String] containing the response body or `nil`
def self.userdata(version="latest")
+ Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
uri = "http://169.254.169.254/#{version}/user-data/"
begin
read_uri(uri)
diff --git a/lib/facter/util/values.rb b/lib/facter/util/values.rb
index a7048d5..1fbb1b6 100644
--- a/lib/facter/util/values.rb
+++ b/lib/facter/util/values.rb
@@ -1,3 +1,4 @@
+
module Facter
module Util
# A util module for facter containing helper methods
@@ -75,6 +76,34 @@ module Facter
value = value.downcase if value.is_a?(String)
value
end
+
+ # Flatten the given data structure to something that's suitable to return
+ # as flat facts.
+ #
+ # @param path [String] The fact path to be prefixed to the given value.
+ # @param structure [Object] The data structure to flatten. Nested hashes
+ # will be recursively flattened, everything else will be returned as-is.
+ #
+ # @return [Hash] The given data structure prefixed with the given path
+ def flatten_structure(path, structure)
+ results = {}
+
+ if structure.is_a? Hash
+ structure.each_pair do |name, value|
+ new_path = "#{path}_#{name}".gsub(/\-|\//, '_')
+ results.merge! flatten_structure(new_path, value)
+ end
+ elsif structure.is_a? Array
+ structure.each_with_index do |value, index|
+ new_path = "#{path}_#{index}"
+ results.merge! flatten_structure(new_path, value)
+ end
+ else
+ results[path] = structure
+ end
+
+ results
+ end
end
end
end
diff --git a/spec/fixtures/unit/ec2/rest/meta-data/root b/spec/fixtures/unit/ec2/rest/meta-data/root
new file mode 100644
index 0000000..9ec3bbe
--- /dev/null
+++ b/spec/fixtures/unit/ec2/rest/meta-data/root
@@ -0,0 +1,20 @@
+ami-id
+ami-launch-index
+ami-manifest-path
+block-device-mapping/
+hostname
+instance-action
+instance-id
+instance-type
+kernel-id
+local-hostname
+local-ipv4
+mac
+metrics/
+network/
+placement/
+profile
+public-hostname
+public-ipv4
+public-keys/
+reservation-id
diff --git a/spec/unit/core/suitable_spec.rb b/spec/unit/core/suitable_spec.rb
index 4c0b1fd..8277408 100644
--- a/spec/unit/core/suitable_spec.rb
+++ b/spec/unit/core/suitable_spec.rb
@@ -92,5 +92,15 @@ describe Facter::Core::Suitable do
expect(subject).to_not be_suitable
end
+
+ it "recalculates suitability on every invocation" do
+ subject.confine :kernel => 'Linux'
+
+ subject.confines.first.stubs(:true?).returns false
+ expect(subject).to_not be_suitable
+ subject.confines.first.unstub(:true?)
+ subject.confines.first.stubs(:true?).returns true
+ expect(subject).to be_suitable
+ end
end
end
diff --git a/spec/unit/ec2/rest_spec.rb b/spec/unit/ec2/rest_spec.rb
new file mode 100644
index 0000000..5c74b49
--- /dev/null
+++ b/spec/unit/ec2/rest_spec.rb
@@ -0,0 +1,140 @@
+require 'spec_helper'
+require 'facter/ec2/rest'
+
+shared_examples_for "an ec2 rest querier" do
+ describe "determining if the uri is reachable" do
+ it "retries if the connection times out" do
+ subject.stubs(:open).returns(stub(:read => nil))
+ Timeout.expects(:timeout).with(0.2).twice.raises(Timeout::Error).returns(true)
+ expect(subject).to be_reachable
+ end
+
+ it "retries if the connection is reset" do
+ subject.expects(:open).twice.raises(Errno::ECONNREFUSED).returns(StringIO.new("woo"))
+ expect(subject).to be_reachable
+ end
+
+ it "is false if the given uri returns a 404" do
+ subject.expects(:open).with(anything).once.raises(OpenURI::HTTPError.new("404 Not Found", StringIO.new("woo")))
+ expect(subject).to_not be_reachable
+ end
+ end
+
+end
+
+describe Facter::EC2::Metadata do
+
+ subject { described_class.new('http://0.0.0.0/latest/meta-data/') }
+
+ let(:response) { StringIO.new }
+
+ describe "fetching a metadata endpoint" do
+ it "splits the body into an array" do
+ response.string = my_fixture_read("meta-data/root")
+ subject.stubs(:open).with("http://0.0.0.0/latest/meta-data/").returns response
+ output = subject.fetch_endpoint('')
+
+ expect(output).to eq %w[
+ ami-id ami-launch-index ami-manifest-path block-device-mapping/ hostname
+ instance-action instance-id instance-type kernel-id local-hostname
+ local-ipv4 mac metrics/ network/ placement/ profile public-hostname
+ public-ipv4 public-keys/ reservation-id
+ ]
+ end
+
+ it "reformats keys that are array indices" do
+ response.string = "0=adrien at grey/"
+ subject.stubs(:open).with("http://0.0.0.0/latest/meta-data/public-keys/").returns response
+ output = subject.fetch_endpoint("public-keys/")
+
+ expect(output).to eq %w[0/]
+ end
+
+ it "returns nil if the endpoint returns a 404" do
+ Facter.expects(:log_exception).never
+ subject.stubs(:open).with("http://0.0.0.0/latest/meta-data/public-keys/1/").raises OpenURI::HTTPError.new("404 Not Found", response)
+ output = subject.fetch_endpoint('public-keys/1/')
+
+ expect(output).to be_nil
+ end
+
+ it "logs an error if the endpoint raises a non-404 HTTPError" do
+ Facter.expects(:log_exception).with(instance_of(OpenURI::HTTPError), anything)
+
+ subject.stubs(:open).with("http://0.0.0.0/latest/meta-data/").raises OpenURI::HTTPError.new("418 I'm a Teapot", response)
+ output = subject.fetch_endpoint("")
+
+ expect(output).to be_nil
+ end
+
+ it "logs an error if the endpoint raises a connection error" do
+ Facter.expects(:log_exception).with(instance_of(Errno::ECONNREFUSED), anything)
+
+ subject.stubs(:open).with("http://0.0.0.0/latest/meta-data/").raises Errno::ECONNREFUSED
+ output = subject.fetch_endpoint('')
+
+ expect(output).to be_nil
+ end
+ end
+
+ describe "recursively fetching the EC2 metadata API" do
+ it "queries the given endpoint for metadata keys" do
+ subject.expects(:fetch_endpoint).with("").returns([])
+ subject.fetch
+ end
+
+ it "fetches the value for a simple metadata key" do
+ subject.expects(:fetch_endpoint).with("").returns(['indexthing'])
+ subject.expects(:fetch_endpoint).with("indexthing").returns(['first', 'second'])
+
+ output = subject.fetch
+ expect(output).to eq({'indexthing' => ['first', 'second']})
+ end
+
+ it "unwraps metadata values that are in single element arrays" do
+ subject.expects(:fetch_endpoint).with("").returns(['ami-id'])
+ subject.expects(:fetch_endpoint).with("ami-id").returns(['i-12x'])
+
+ output = subject.fetch
+ expect(output).to eq({'ami-id' => 'i-12x'})
+ end
+
+ it "recursively queries an endpoint if the key ends with '/'" do
+ subject.expects(:fetch_endpoint).with("").returns(['metrics/'])
+ subject.expects(:fetch_endpoint).with("metrics/").returns(['vhostmd'])
+ subject.expects(:fetch_endpoint).with("metrics/vhostmd").returns(['woo'])
+
+ output = subject.fetch
+ expect(output).to eq({'metrics' => {'vhostmd' => 'woo'}})
+ end
+ end
+
+ it_behaves_like "an ec2 rest querier"
+end
+
+describe Facter::EC2::Userdata do
+
+ subject { described_class.new('http://0.0.0.0/latest/user-data/') }
+
+ let(:response) { StringIO.new }
+
+ describe "reaching the userdata" do
+ it "queries the userdata URI" do
+ subject.expects(:open).with('http://0.0.0.0/latest/user-data/').returns(response)
+ subject.fetch
+ end
+
+ it "returns the result of the query without modification" do
+ response.string = "clooouuuuud"
+ subject.expects(:open).with('http://0.0.0.0/latest/user-data/').returns(response)
+ expect(subject.fetch).to eq "clooouuuuud"
+ end
+
+ it "is nil if the URI returned a 404" do
+ subject.expects(:open).with('http://0.0.0.0/latest/user-data/').once.raises(OpenURI::HTTPError.new("404 Not Found", StringIO.new("woo")))
+ expect(subject.fetch).to be_nil
+ end
+ end
+
+ it_behaves_like "an ec2 rest querier"
+end
diff --git a/spec/unit/ec2_spec.rb b/spec/unit/ec2_spec.rb
index f26a613..28ad20a 100755
--- a/spec/unit/ec2_spec.rb
+++ b/spec/unit/ec2_spec.rb
@@ -1,187 +1,127 @@
-#! /usr/bin/env ruby
-
require 'spec_helper'
-require 'facter/util/ec2'
-
-describe "ec2 facts" do
- # This is the standard prefix for making an API call in EC2 (or fake)
- # environments.
- let(:api_prefix) { "http://169.254.169.254" }
-
- describe "when running on ec2" do
- before :each do
- # This is an ec2 instance, not a eucalyptus instance
- Facter::Util::EC2.stubs(:has_euca_mac?).returns(false)
- Facter::Util::EC2.stubs(:has_openstack_mac?).returns(false)
- Facter::Util::EC2.stubs(:has_ec2_arp?).returns(true)
-
- # Assume we can connect
- Facter::Util::EC2.stubs(:can_connect?).returns(true)
- end
+require 'facter/ec2/rest'
- it "should create flat meta-data facts" do
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").
- at_least_once.returns(StringIO.new("foo"))
+describe "ec2_metadata" do
+ let(:querier) { stub('EC2 metadata querier') }
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/foo").
- at_least_once.returns(StringIO.new("bar"))
+ before do
+ Facter::EC2::Metadata.stubs(:new).returns querier
- Facter.collection.internal_loader.load(:ec2)
-
- Facter.fact(:ec2_foo).value.should == "bar"
- end
+ # Prevent flattened facts from forcing evaluation of the ec2 metadata fact
+ Facter.stubs(:value).with(:ec2_metadata)
+ Facter.collection.internal_loader.load(:ec2)
+ Facter.unstub(:value)
+ end
- it "should create flat meta-data facts with comma seperation" do
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").
- at_least_once.returns(StringIO.new("foo"))
+ subject { Facter.fact(:ec2_metadata).resolution(:rest) }
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/foo").
- at_least_once.returns(StringIO.new("bar\nbaz"))
+ it "is unsuitable if the virtual fact is not xen" do
+ querier.stubs(:reachable?).returns false
+ Facter.fact(:virtual).stubs(:value).returns "kvm"
+ expect(subject).to_not be_suitable
+ end
- Facter.collection.internal_loader.load(:ec2)
+ it "is unsuitable if ec2 endpoint is not reachable" do
+ Facter.fact(:virtual).stubs(:value).returns "xen"
+ querier.stubs(:reachable?).returns false
+ expect(subject).to_not be_suitable
+ end
- Facter.fact(:ec2_foo).value.should == "bar,baz"
+ describe "when the ec2 endpoint is reachable" do
+ before do
+ querier.stubs(:reachable?).returns true
end
- it "should create structured meta-data facts" do
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").
- at_least_once.returns(StringIO.new("foo/"))
-
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/foo/").
- at_least_once.returns(StringIO.new("bar"))
+ it "is suitable if the virtual fact is xen" do
+ Facter.fact(:virtual).stubs(:value).returns "xen"
+ subject.suitable?
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/foo/bar").
- at_least_once.returns(StringIO.new("baz"))
-
- Facter.collection.internal_loader.load(:ec2)
-
- Facter.fact(:ec2_foo_bar).value.should == "baz"
+ expect(subject).to be_suitable
end
- it "should create ec2_user_data fact" do
- # No meta-data
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").
- at_least_once.returns(StringIO.new(""))
-
- Facter::Util::EC2.stubs(:read_uri).
- with("#{api_prefix}/latest/user-data/").
- returns("test")
-
- Facter.collection.internal_loader.load(:ec2)
- Facter.fact(:ec2_userdata).value.should == ["test"]
+ it "is suitable if the virtual fact is xenu" do
+ Facter.fact(:virtual).stubs(:value).returns "xenu"
+ expect(subject).to be_suitable
end
end
- describe "when running on eucalyptus" do
- before :each do
- # Return false for ec2, true for eucalyptus
- Facter::Util::EC2.stubs(:has_euca_mac?).returns(true)
- Facter::Util::EC2.stubs(:has_openstack_mac?).returns(false)
- Facter::Util::EC2.stubs(:has_ec2_arp?).returns(false)
+ it "resolves the value by recursively querying the rest endpoint" do
+ querier.expects(:fetch).returns({"hello" => "world"})
+ expect(subject.value).to eq({"hello" => "world"})
+ end
+end
- # Assume we can connect
- Facter::Util::EC2.stubs(:can_connect?).returns(true)
- end
+describe "ec2_userdata" do
+ let(:querier) { stub('EC2 metadata querier') }
- it "should create ec2_user_data fact" do
- # No meta-data
- Object.any_instance.expects(:open).\
- with("#{api_prefix}/2008-02-01/meta-data/").\
- at_least_once.returns(StringIO.new(""))
+ before do
+ Facter::EC2::Userdata.stubs(:new).returns querier
- Facter::Util::EC2.stubs(:read_uri).
- with("#{api_prefix}/latest/user-data/").
- returns("test")
+ # Prevent flattened facts from forcing evaluation of the ec2 metadata fact
+ Facter.stubs(:value).with(:ec2_metadata)
+ Facter.collection.internal_loader.load(:ec2)
+ Facter.unstub(:value)
+ end
- # Force a fact load
- Facter.collection.internal_loader.load(:ec2)
+ subject { Facter.fact(:ec2_userdata).resolution(:rest) }
- Facter.fact(:ec2_userdata).value.should == ["test"]
- end
+ it "is unsuitable if the virtual fact is not xen" do
+ querier.stubs(:reachable?).returns(true)
+ Facter.fact(:virtual).stubs(:value).returns "kvm"
+ expect(subject).to_not be_suitable
end
- describe "when running on openstack" do
- before :each do
- # Return false for ec2, true for eucalyptus
- Facter::Util::EC2.stubs(:has_openstack_mac?).returns(true)
- Facter::Util::EC2.stubs(:has_euca_mac?).returns(false)
- Facter::Util::EC2.stubs(:has_ec2_arp?).returns(false)
+ it "is unsuitable if ec2 endpoint is not reachable" do
+ Facter.fact(:virtual).stubs(:value).returns "xen"
+ querier.stubs(:reachable?).returns false
+ expect(subject).to_not be_suitable
+ end
- # Assume we can connect
- Facter::Util::EC2.stubs(:can_connect?).returns(true)
+ describe "when the ec2 endpoint is reachable" do
+ before do
+ querier.stubs(:reachable?).returns true
end
- it "should create ec2_user_data fact" do
- # No meta-data
- Object.any_instance.expects(:open).\
- with("#{api_prefix}/2008-02-01/meta-data/").\
- at_least_once.returns(StringIO.new(""))
-
- Facter::Util::EC2.stubs(:read_uri).
- with("#{api_prefix}/latest/user-data/").
- returns("test")
-
- # Force a fact load
- Facter.collection.internal_loader.load(:ec2)
-
- Facter.fact(:ec2_userdata).value.should == ["test"]
+ it "is suitable if the virtual fact is xen" do
+ Facter.fact(:virtual).stubs(:value).returns "xen"
+ expect(subject).to be_suitable
end
- it "should return nil if open fails" do
- Facter.stubs(:warn) # do not pollute test output
- Facter.expects(:warn).with('Could not retrieve ec2 metadata: host unreachable')
-
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").
- at_least_once.raises(RuntimeError, 'host unreachable')
-
- Facter::Util::EC2.stubs(:read_uri).
- with("#{api_prefix}/latest/user-data/").
- raises(RuntimeError, 'host unreachable')
-
- # Force a fact load
- Facter.collection.internal_loader.load(:ec2)
-
- Facter.fact(:ec2_userdata).value.should be_nil
+ it "is suitable if the virtual fact is xenu" do
+ Facter.fact(:virtual).stubs(:value).returns "xenu"
+ expect(subject).to be_suitable
end
+ end
+ it "resolves the value by fetching the rest endpoint" do
+ querier.expects(:fetch).returns "user data!"
+ expect(subject.value).to eq "user data!"
end
+end
- describe "when api connect test fails" do
- before :each do
- Facter.stubs(:warnonce)
- end
+describe "flattened versions of ec2 facts" do
+ # These facts are tricky to test because they are dynamic facts, and they are
+ # generated from a fact that is defined in the same file. In order to pull
+ # this off we need to define the ec2_metadata fact ahead of time so that we
+ # can stub the value, and then manually load the correct files.
- it "should not populate ec2_userdata" do
- # Emulate ec2 for now as it matters little to this test
- Facter::Util::EC2.stubs(:has_euca_mac?).returns(true)
- Facter::Util::EC2.stubs(:has_ec2_arp?).never
- Facter::Util::EC2.expects(:can_connect?).at_least_once.returns(false)
+ it "unpacks the ec2_metadata fact" do
+ Facter.define_fact(:ec2_metadata).stubs(:value).returns({"hello" => "world"})
+ Facter.collection.internal_loader.load(:ec2)
- # The API should never be called at this point
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/meta-data/").never
- Object.any_instance.expects(:open).
- with("#{api_prefix}/2008-02-01/user-data/").never
+ expect(Facter.value("ec2_hello")).to eq "world"
+ end
- # Force a fact load
- Facter.collection.internal_loader.load(:ec2)
+ it "does not set any flat ec2 facts if the ec2_metadata fact is nil" do
+ Facter.define_fact(:ec2_metadata).stubs(:value)
+ Facter.define_fact(:ec2_userdata).stubs(:value).returns(nil)
- Facter.fact(:ec2_userdata).should == nil
- end
+ Facter.collection.internal_loader.load(:ec2)
- it "should rescue the exception" do
- Facter::Util::EC2.expects(:open).with("#{api_prefix}:80/").raises(Timeout::Error)
+ all_facts = Facter.collection.to_hash
- Facter::Util::EC2.should_not be_can_connect
- end
+ ec2_facts = all_facts.keys.select { |k| k =~ /^ec2_/ }
+ expect(ec2_facts).to be_empty
end
+
end
diff --git a/spec/unit/util/ec2_spec.rb b/spec/unit/util/ec2_spec.rb
index f963db6..7af59d8 100755
--- a/spec/unit/util/ec2_spec.rb
+++ b/spec/unit/util/ec2_spec.rb
@@ -4,6 +4,10 @@ require 'spec_helper'
require 'facter/util/ec2'
describe Facter::Util::EC2 do
+ before do
+ # Squelch deprecation notices
+ Facter.stubs(:warnonce)
+ end
# This is the standard prefix for making an API call in EC2 (or fake)
# environments.
let(:api_prefix) { "http://169.254.169.254" }
diff --git a/spec/unit/util/values_spec.rb b/spec/unit/util/values_spec.rb
index 557eb19..bc347c4 100644
--- a/spec/unit/util/values_spec.rb
+++ b/spec/unit/util/values_spec.rb
@@ -128,4 +128,44 @@ describe Facter::Util::Values do
end
end
end
+
+ describe "flatten_structure" do
+ it "converts a string to a hash containing that string" do
+ input = "foo"
+ output = described_class.flatten_structure("path", input)
+ expect(output).to eq({"path" => "foo"})
+ end
+
+ it "converts an array to a hash with the array elements with indexes" do
+ input = ["foo"]
+ output = described_class.flatten_structure("path", input)
+ expect(output).to eq({"path_0" => "foo"})
+ end
+
+ it "prefixes a non-nested hash with the given path" do
+ input = {"foo" => "bar"}
+ output = described_class.flatten_structure("path", input)
+ expect(output).to eq({"path_foo" => "bar"})
+ end
+
+ it "flattens elements till it reaches the first non-flattenable structure" do
+ input = {
+ "first" => "second",
+ "arr" => ["zero", "one"],
+ "nested_array" => [
+ "hash" => "string",
+ ],
+ "top" => {"middle" => ['bottom']},
+ }
+ output = described_class.flatten_structure("path", input)
+
+ expect(output).to eq({
+ "path_first" => "second",
+ "path_arr_0" => "zero",
+ "path_arr_1" => "one",
+ "path_nested_array_0_hash" => "string",
+ "path_top_middle_0" => "bottom"
+ })
+ end
+ end
end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git
More information about the Pkg-puppet-devel
mailing list