[Pkg-puppet-devel] [facter] 102/180: Revert "Merge pull request #661 from adrienthebo/feature/facter-2/fact-185-structured-ec2-metadata"

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 75402bee698cc5c8d5049af5ce0e15b928f5021b
Author: Kylo Ginsberg <kylo at puppetlabs.com>
Date:   Fri May 23 13:15:27 2014 -0700

    Revert "Merge pull request #661 from adrienthebo/feature/facter-2/fact-185-structured-ec2-metadata"
    
    This reverts commit e3da03097164fd973aef79bef507426edb7e5ced, reversing
    changes made to 2ce8849b75339f577f08375adabfdbf50d932c71.
---
 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                      | 228 +++++++++++++++++++----------
 spec/unit/util/ec2_spec.rb                 |   4 -
 spec/unit/util/values_spec.rb              |  40 -----
 11 files changed, 180 insertions(+), 490 deletions(-)

diff --git a/lib/facter/core/suitable.rb b/lib/facter/core/suitable.rb
index 0262470..1b3c04f 100644
--- a/lib/facter/core/suitable.rb
+++ b/lib/facter/core/suitable.rb
@@ -108,6 +108,10 @@ module Facter::Core::Suitable
   #
   # @api private
   def suitable?
-    @confines.all? { |confine| confine.true? }
+    unless defined? @suitable
+      @suitable = ! @confines.detect { |confine| ! confine.true? }
+    end
+
+    return @suitable
   end
 end
diff --git a/lib/facter/ec2.rb b/lib/facter/ec2.rb
index 2e57592..09e0109 100644
--- a/lib/facter/ec2.rb
+++ b/lib/facter/ec2.rb
@@ -1,44 +1,37 @@
-require 'facter/ec2/rest'
+require 'facter/util/ec2'
+require 'open-uri'
 
-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
+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)
     end
   end
+rescue => details
+  Facter.warn "Could not retrieve ec2 metadata: #{details.message}"
 end
 
-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
-
+def userdata()
+  Facter.add(:ec2_userdata) do
     setcode do
-      @querier.fetch
+      if userdata = Facter::Util::EC2.userdata
+        userdata.split
+      end
     end
   end
 end
 
-# 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
+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"
 end
diff --git a/lib/facter/ec2/rest.rb b/lib/facter/ec2/rest.rb
deleted file mode 100644
index e9c1fca..0000000
--- a/lib/facter/ec2/rest.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-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 b81c8fe..c6e5dca 100644
--- a/lib/facter/util/ec2.rb
+++ b/lib/facter/util/ec2.rb
@@ -11,7 +11,6 @@ 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
@@ -24,7 +23,6 @@ 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
 
@@ -32,14 +30,12 @@ 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
@@ -77,7 +73,6 @@ 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 1fbb1b6..a7048d5 100644
--- a/lib/facter/util/values.rb
+++ b/lib/facter/util/values.rb
@@ -1,4 +1,3 @@
-
 module Facter
   module Util
     # A util module for facter containing helper methods
@@ -76,34 +75,6 @@ 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
deleted file mode 100644
index 9ec3bbe..0000000
--- a/spec/fixtures/unit/ec2/rest/meta-data/root
+++ /dev/null
@@ -1,20 +0,0 @@
-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 8277408..4c0b1fd 100644
--- a/spec/unit/core/suitable_spec.rb
+++ b/spec/unit/core/suitable_spec.rb
@@ -92,15 +92,5 @@ 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
deleted file mode 100644
index 5c74b49..0000000
--- a/spec/unit/ec2/rest_spec.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-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 bf2aa2f..f26a613 100755
--- a/spec/unit/ec2_spec.rb
+++ b/spec/unit/ec2_spec.rb
@@ -1,117 +1,187 @@
+#! /usr/bin/env ruby
+
 require 'spec_helper'
-require 'facter/ec2/rest'
+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
 
-describe "ec2_metadata" do
-  let(:querier) { stub('EC2 metadata querier') }
+    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"))
 
-  before do
-    Facter::EC2::Metadata.stubs(:new).returns querier
-    Facter.collection.internal_loader.load(:ec2)
-  end
+      Object.any_instance.expects(:open).
+        with("#{api_prefix}/2008-02-01/meta-data/foo").
+        at_least_once.returns(StringIO.new("bar"))
 
-  subject { Facter.fact(:ec2_metadata).resolution(:rest) }
+      Facter.collection.internal_loader.load(:ec2)
 
-  it "is unsuitable if the virtual fact is not xen" do
-    Facter.fact(:virtual).stubs(:value).returns "kvm"
-    expect(subject).to_not be_suitable
-  end
+      Facter.fact(:ec2_foo).value.should == "bar"
+    end
 
-  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
+    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"))
+
+      Object.any_instance.expects(:open).
+        with("#{api_prefix}/2008-02-01/meta-data/foo").
+        at_least_once.returns(StringIO.new("bar\nbaz"))
 
-  describe "when the ec2 endpoint is reachable" do
-    before do
-      querier.stubs(:reachable?).returns true
+      Facter.collection.internal_loader.load(:ec2)
+
+      Facter.fact(:ec2_foo).value.should == "bar,baz"
     end
 
-    it "is suitable if the virtual fact is xen" do
-      Facter.fact(:virtual).stubs(:value).returns "xen"
-      subject.suitable?
+    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"))
 
-      expect(subject).to be_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"
     end
 
-    it "is suitable if the virtual fact is xenu" do
-      Facter.fact(:virtual).stubs(:value).returns "xenu"
-      expect(subject).to be_suitable
+    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"]
     end
   end
 
-  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
+  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)
 
-describe "ec2_userdata" do
-  let(:querier) { stub('EC2 metadata querier') }
+      # Assume we can connect
+      Facter::Util::EC2.stubs(:can_connect?).returns(true)
+    end
 
-  before do
-    Facter::EC2::Userdata.stubs(:new).returns querier
-    Facter.collection.internal_loader.load(:ec2)
-  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(""))
 
-  subject { Facter.fact(:ec2_userdata).resolution(:rest) }
+      Facter::Util::EC2.stubs(:read_uri).
+        with("#{api_prefix}/latest/user-data/").
+        returns("test")
 
-  it "is unsuitable if the virtual fact is not xen" do
-    Facter.fact(:virtual).stubs(:value).returns "kvm"
-    expect(subject).to_not be_suitable
-  end
+      # Force a fact load
+      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
+      Facter.fact(:ec2_userdata).value.should == ["test"]
+    end
   end
 
-  describe "when the ec2 endpoint is reachable" do
-    before do
-      querier.stubs(:reachable?).returns true
+  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)
+
+      # Assume we can connect
+      Facter::Util::EC2.stubs(:can_connect?).returns(true)
     end
 
-    it "is suitable if the virtual fact is xen" do
-      Facter.fact(:virtual).stubs(:value).returns "xen"
-      expect(subject).to be_suitable
+    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"]
     end
 
-    it "is suitable if the virtual fact is xenu" do
-      Facter.fact(:virtual).stubs(:value).returns "xenu"
-      expect(subject).to be_suitable
+    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
     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 "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.
+  describe "when api connect test fails" do
+    before :each do
+      Facter.stubs(:warnonce)
+    end
 
-  it "unpacks the ec2_metadata fact" do
-    Facter.define_fact(:ec2_metadata).stubs(:value).returns({"hello" => "world"})
-    Facter.collection.internal_loader.load(:ec2)
+    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)
 
-    expect(Facter.value("ec2_hello")).to eq "world"
-  end
+      # 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
 
-  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)
+      # Force a fact load
+      Facter.collection.internal_loader.load(:ec2)
 
-    Facter.collection.internal_loader.load(:ec2)
+      Facter.fact(:ec2_userdata).should == nil
+    end
 
-    all_facts = Facter.collection.to_hash
+    it "should rescue the exception" do
+      Facter::Util::EC2.expects(:open).with("#{api_prefix}:80/").raises(Timeout::Error)
 
-    ec2_facts = all_facts.keys.select { |k| k =~ /^ec2_/ }
-    expect(ec2_facts).to be_empty
+      Facter::Util::EC2.should_not be_can_connect
+    end
   end
-
 end
diff --git a/spec/unit/util/ec2_spec.rb b/spec/unit/util/ec2_spec.rb
index 7af59d8..f963db6 100755
--- a/spec/unit/util/ec2_spec.rb
+++ b/spec/unit/util/ec2_spec.rb
@@ -4,10 +4,6 @@ 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 bc347c4..557eb19 100644
--- a/spec/unit/util/values_spec.rb
+++ b/spec/unit/util/values_spec.rb
@@ -128,44 +128,4 @@ 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