[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.5-639-g8f94f35
test branch
puppet-dev at googlegroups.com
Wed Jul 14 10:31:49 UTC 2010
The following commit has been merged in the upstream branch:
commit eda649b6395b38dcb1a5719483222bfbfa60302c
Author: Jesse Wolfe <jes5199 at gmail.com>
Date: Wed Mar 17 12:46:42 2010 -0700
Feature #3383 RAL over REST
ralsh --host works now, and is using REST.
A node running puppetd --listen will allow ralsh to find, search, and
modify live resources, via REST.
Signed-off-by: Jesse Wolfe <jes5199 at gmail.com>
diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb
index f914a1b..0046fc1 100644
--- a/lib/puppet/application/resource.rb
+++ b/lib/puppet/application/resource.rb
@@ -71,52 +71,24 @@ Puppet::Application.new(:resource) do
trans.to_manifest
}
- text = if @host
- client = Puppet::Network::Client.resource.new(:Server => @host, :Port => Puppet[:puppetport])
- unless client.read_cert
- raise "client.read_cert failed"
- end
- begin
- # They asked for a single resource.
- if name
- transbucket = [client.describe(type, name)]
- else
- # Else, list the whole thing out.
- transbucket = client.instances(type)
- end
- rescue Puppet::Network::XMLRPCClientError => exc
- raise "client.list(#{type}) failed: #{exc.message}"
- end
- transbucket.sort { |a,b| a.name <=> b.name }.collect(&format)
+ if @host
+ Puppet::Resource.indirection.terminus_class = :rest
+ port = Puppet[:puppetport]
+ key = ["https://#{host}:#{port}", "production", "resources", type, name].join('/')
else
- if name
- obj = typeobj.instances.find { |o| o.name == name } || typeobj.new(:name => name, :check => properties)
- vals = obj.retrieve
-
- unless params.empty?
- params.each do |param, value|
- obj[param] = value
- end
- catalog = Puppet::Resource::Catalog.new
- catalog.add_resource obj
- begin
- catalog.apply
- rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- end
- end
+ key = [type, name].join('/')
+ end
- end
- [format.call(obj.to_trans(true))]
+ text = if name
+ if params.empty?
+ [ Puppet::Resource.find( key ) ]
else
- typeobj.instances.collect do |obj|
- next if ARGV.length > 0 and ! ARGV.include? obj.name
- trans = obj.to_trans(true)
- format.call(trans)
- end
+ request = Puppet::Indirector::Request.new(:resource, :save, key) # Yuck.
+ [ Puppet::Resource.new( type, name, params ).save( request ) ]
end
- end.compact.join("\n")
+ else
+ Puppet::Resource.search( key, {} )
+ end.map(&format).join("\n")
if options[:edit]
file = "/tmp/x2puppet-#{Process.pid}.pp"
diff --git a/lib/puppet/indirector/resource/ral.rb b/lib/puppet/indirector/resource/ral.rb
new file mode 100644
index 0000000..f2c3f84
--- /dev/null
+++ b/lib/puppet/indirector/resource/ral.rb
@@ -0,0 +1,48 @@
+class Puppet::Resource::Ral < Puppet::Indirector::Code
+ def find( request )
+ # find by name
+ res = type(request).instances.find { |o| o.name == resource_name(request) }
+ res ||= type(request).new(:name => resource_name(request), :check => type(request).properties.collect { |s| s.name })
+
+ return res.to_resource
+ end
+
+ def search( request )
+ conditions = request.options.dup
+ conditions[:name] = resource_name(request) if resource_name(request)
+
+ type(request).instances.map do |res|
+ res.to_resource
+ end.find_all do |res|
+ conditions.all? {|property, value| res.to_resource[property].to_s == value.to_s}
+ end.sort do |a,b|
+ a.title <=> b.title
+ end
+ end
+
+ def save( request )
+ # In RAL-land, to "save" means to actually try to change machine state
+ res = request.instance
+ ral_res = res.to_ral
+
+ catalog = Puppet::Resource::Catalog.new
+ catalog.add_resource ral_res
+ catalog.apply
+
+ return ral_res.to_resource
+ end
+
+ private
+
+ def type_name( request )
+ request.key.split('/')[0]
+ end
+
+ def resource_name( request )
+ request.key.split('/')[1]
+ end
+
+ def type( request )
+ Puppet::Type.type(type_name(request)) or raise Puppet::Error "Could not find type #{type}"
+ end
+end
diff --git a/lib/puppet/indirector/status/rest.rb b/lib/puppet/indirector/resource/rest.rb
similarity index 52%
copy from lib/puppet/indirector/status/rest.rb
copy to lib/puppet/indirector/resource/rest.rb
index 22e7042..7848ae6 100644
--- a/lib/puppet/indirector/status/rest.rb
+++ b/lib/puppet/indirector/resource/rest.rb
@@ -1,5 +1,5 @@
require 'puppet/indirector/status'
require 'puppet/indirector/rest'
-class Puppet::Indirector::Status::Rest < Puppet::Indirector::REST
+class Puppet::Resource::Rest < Puppet::Indirector::REST
end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index a89e986..4fd3859 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -67,7 +67,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
def find(request)
return nil unless result = deserialize(network(request).get(indirection2uri(request), headers))
- result.name = request.key
+ result.name = request.key if result.respond_to?(:name=)
result
end
diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb
index 01ed412..7c0ef9c 100644
--- a/lib/puppet/network/rest_authconfig.rb
+++ b/lib/puppet/network/rest_authconfig.rb
@@ -16,6 +16,7 @@ module Puppet
{ :acl => "/certificate/", :method => :find, :authenticated => false },
{ :acl => "/certificate_request", :method => [:find, :save], :authenticated => false },
{ :acl => "/status", :method => [:find], :authenticated => true },
+ { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true },
]
def self.main
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb
index e733f3e..bdd11fc 100644
--- a/lib/puppet/resource.rb
+++ b/lib/puppet/resource.rb
@@ -1,6 +1,6 @@
require 'puppet'
require 'puppet/util/tagging'
-require 'puppet/resource/reference'
+#require 'puppet/resource/reference'
require 'puppet/util/pson'
# The simplest resource class. Eventually it will function as the
@@ -12,6 +12,10 @@ class Puppet::Resource
attr_accessor :file, :line, :catalog, :exported, :virtual
attr_writer :type, :title
+ require 'puppet/indirector'
+ extend Puppet::Indirector
+ indirects :resource, :terminus_class => :ral
+
ATTRIBUTES = [:file, :line, :exported]
def self.from_pson(pson)
@@ -225,6 +229,17 @@ class Puppet::Resource
return result
end
+ def name
+ # this is potential namespace conflict
+ # between the notion of an "indirector name"
+ # and a "resource name"
+ [ type, title ].join('/')
+ end
+
+ def to_resource
+ self
+ end
+
private
# Produce a canonical method name.
diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb
index c5ae8f5..6e064a9 100644
--- a/lib/puppet/resource/catalog.rb
+++ b/lib/puppet/resource/catalog.rb
@@ -1,3 +1,4 @@
+require 'puppet/resource'
require 'puppet/node'
require 'puppet/indirector'
require 'puppet/simple_graph'
@@ -79,7 +80,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph
# If the name and title differ, set up an alias
- if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title
+ if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.respond_to?(:isomorphic?) and resource.name != resource.title
self.alias(resource, resource.name) if resource.isomorphic?
end
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 1df84f2..2fb4abc 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -2025,6 +2025,12 @@ class Type
return trans
end
+ def to_resource
+ # this 'type instance' versus 'resource' distinction seems artificial
+ # I'd like to see it collapsed someday ~JW
+ self.to_trans.to_resource
+ end
+
%w{exported virtual}.each do |m|
define_method(m+"?") do
self.send(m)
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 08d42d9..ad1b947 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -1,6 +1,5 @@
require 'puppet'
require 'sync'
-require 'puppet/transportable'
require 'getoptlong'
require 'puppet/external/event-loop'
diff --git a/spec/unit/application/resource.rb b/spec/unit/application/resource.rb
index 98b4485..9d47ba5 100755
--- a/spec/unit/application/resource.rb
+++ b/spec/unit/application/resource.rb
@@ -179,75 +179,76 @@ describe "resource" do
before :each do
@resource.stubs(:puts)
@resource.host = 'host'
- @client = stub_everything 'client'
- @client.stubs(:read_cert).returns(true)
- @client.stubs(:instances).returns([])
- Puppet::Network::Client.resource.stubs(:new).returns(@client)
+
+ Puppet::Resource.stubs(:find ).never
+ Puppet::Resource.stubs(:search).never
+ Puppet::Resource.stubs(:save ).never
end
- it "should connect to it" do
- Puppet::Network::Client.resource.expects(:new).with { |h| h[:Server] == 'host' }.returns(@client)
+ it "should search for resources" do
+ Puppet::Resource.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([])
@resource.main
end
- it "should raise an error if there are no certs" do
- @client.stubs(:read_cert).returns(nil)
-
- lambda { @resource.main }.should raise_error
+ it "should describe the given resource" do
+ push_args('type','name')
+ x = stub_everything 'resource'
+ Puppet::Resource.expects(:find).with('https://host:8139/production/resources/type/name').returns(x)
+ @resource.main
+ pop_args
end
- it "should retrieve all the instances if there is no name" do
- @client.expects(:instances).returns([])
+ it "should add given parameters to the object" do
+ push_args('type','name','param=temp')
- @resource.main
- end
+ res = stub "resource"
+ res.expects(:save).with{|x| x.uri == 'https://host:8139/production/resources/type/name'}.returns(res)
+ res.expects(:collect)
+ res.expects(:to_manifest)
+ Puppet::Resource.expects(:new).with('type', 'name', {'param' => 'temp'}).returns(res)
- it "should describe the given resource" do
- push_args('type','name')
- @client.expects(:describe).returns(stub_everything)
@resource.main
pop_args
end
+
end
describe "without a host" do
before :each do
@resource.stubs(:puts)
@resource.host = nil
+
+ Puppet::Resource.stubs(:find ).never
+ Puppet::Resource.stubs(:search).never
+ Puppet::Resource.stubs(:save ).never
end
- it "should retrieve all the instances if there is no name" do
- @type.expects(:instances).returns([])
+ it "should search for resources" do
+ Puppet::Resource.expects(:search).with('type/', {}).returns([])
+ @resource.main
+ end
+ it "should describe the given resource" do
+ push_args('type','name')
+ x = stub_everything 'resource'
+ Puppet::Resource.expects(:find).with('type/name').returns(x)
@resource.main
+ pop_args
end
- describe 'but with a given name' do
- before :each do
- push_args('type','name')
- @type.stubs(:new).returns(:bob)
- end
-
- after :each do
- pop_args
- end
-
- it "should retrieve a specific instance if it exists" do
- pending
- end
-
- it "should create a stub instance if it doesn't exist" do
- pending
- end
-
- it "should add given parameters to the object" do
- push_args('type','name','param=temp')
- pending
- @object.expects(:[]=).with('param','temp')
- @resource.main
- pop_args
- end
+ it "should add given parameters to the object" do
+ push_args('type','name','param=temp')
+
+ res = stub "resource"
+ res.expects(:save).with{|x| x.uri == nil}.returns(res)
+ res.expects(:collect)
+ res.expects(:to_manifest)
+ Puppet::Resource.expects(:new).with('type', 'name', {'param' => 'temp'}).returns(res)
+
+ @resource.main
+ pop_args
end
+
end
end
end
diff --git a/spec/unit/indirector/resource/ral.rb b/spec/unit/indirector/resource/ral.rb
new file mode 100644
index 0000000..f74bf3d
--- /dev/null
+++ b/spec/unit/indirector/resource/ral.rb
@@ -0,0 +1,129 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe "Puppet::Resource::Ral" do
+ describe "find" do
+ before do
+ @request = stub 'request', :key => "user/root"
+ end
+
+ it "should find an existing instance" do
+ my_resource = stub "my user resource"
+
+ wrong_instance = stub "wrong user", :name => "bob"
+ my_instance = stub "my user", :name => "root", :to_resource => my_resource
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ wrong_instance, my_instance, wrong_instance ])
+ Puppet::Resource::Ral.new.find(@request).should == my_resource
+ end
+
+ it "if there is no instance, it should create one" do
+ wrong_instance = stub "wrong user", :name => "bob"
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ wrong_instance, wrong_instance ])
+ result = Puppet::Resource::Ral.new.find(@request)
+ result.should be_is_a Puppet::Resource
+ result.title.should == "root"
+ end
+ end
+
+ describe "search" do
+ before do
+ @request = stub 'request', :key => "user/", :options => {}
+ end
+
+ it "should convert ral resources into regular resources" do
+ my_resource = stub "my user resource"
+ my_instance = stub "my user", :name => "root", :to_resource => my_resource
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ my_instance ])
+ Puppet::Resource::Ral.new.search(@request).should == [my_resource]
+ end
+
+ it "should filter results by name if there's a name in the key" do
+ my_resource = stub "my user resource"
+ my_resource.stubs(:to_resource).returns(my_resource)
+ my_resource.stubs(:[]).with(:name).returns("root")
+
+ wrong_resource = stub "wrong resource"
+ wrong_resource.stubs(:to_resource).returns(wrong_resource)
+ wrong_resource.stubs(:[]).with(:name).returns("bad")
+
+ my_instance = stub "my user", :to_resource => my_resource
+ wrong_instance = stub "wrong user", :to_resource => wrong_resource
+
+ @request = stub 'request', :key => "user/root", :options => {}
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ my_instance, wrong_instance ])
+ Puppet::Resource::Ral.new.search(@request).should == [my_resource]
+ end
+
+ it "should filter results by query parameters" do
+ wrong_resource = stub "my user resource"
+ wrong_resource.stubs(:to_resource).returns(wrong_resource)
+ wrong_resource.stubs(:[]).with(:name).returns("root")
+
+ my_resource = stub "wrong resource"
+ my_resource.stubs(:to_resource).returns(my_resource)
+ my_resource.stubs(:[]).with(:name).returns("bob")
+
+ my_instance = stub "my user", :to_resource => my_resource
+ wrong_instance = stub "wrong user", :to_resource => wrong_resource
+
+ @request = stub 'request', :key => "user/", :options => {:name => "bob"}
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ my_instance, wrong_instance ])
+ Puppet::Resource::Ral.new.search(@request).should == [my_resource]
+ end
+
+ it "should return sorted results" do
+ a_resource = stub "alice resource"
+ a_resource.stubs(:to_resource).returns(a_resource)
+ a_resource.stubs(:title).returns("alice")
+
+ b_resource = stub "bob resource"
+ b_resource.stubs(:to_resource).returns(b_resource)
+ b_resource.stubs(:title).returns("bob")
+
+ a_instance = stub "alice user", :to_resource => a_resource
+ b_instance = stub "bob user", :to_resource => b_resource
+
+ @request = stub 'request', :key => "user/", :options => {}
+
+ require 'puppet/type/user'
+ Puppet::Type::User.expects(:instances).returns([ b_instance, a_instance ])
+ Puppet::Resource::Ral.new.search(@request).should == [a_resource, b_resource]
+ end
+ end
+
+ describe "save" do
+ before do
+ @rebuilt_res = stub 'rebuilt instance'
+ @ral_res = stub 'ral resource', :to_resource => @rebuilt_res
+ @instance = stub 'instance', :to_ral => @ral_res
+ @request = stub 'request', :key => "user/", :instance => @instance
+ @catalog = stub 'catalog'
+
+ Puppet::Resource::Catalog.stubs(:new).returns(@catalog)
+ @catalog.stubs(:apply)
+ @catalog.stubs(:add_resource)
+ end
+
+ it "should apply a new catalog with a ral object in it" do
+ Puppet::Resource::Catalog.expects(:new).returns(@catalog)
+ @catalog.expects(:add_resource).with(@ral_res)
+ @catalog.expects(:apply)
+ Puppet::Resource::Ral.new.save(@request)
+ end
+
+ it "should return a regular resource that used to be the ral resource" do
+ Puppet::Resource::Ral.new.save(@request).should == @rebuilt_res
+ end
+ end
+end
diff --git a/spec/unit/indirector/status/rest.rb b/spec/unit/indirector/resource/rest.rb
similarity index 57%
copy from spec/unit/indirector/status/rest.rb
copy to spec/unit/indirector/resource/rest.rb
index 8f803a2..d5f2a9d 100755
--- a/spec/unit/indirector/status/rest.rb
+++ b/spec/unit/indirector/resource/rest.rb
@@ -2,10 +2,10 @@
Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
-require 'puppet/indirector/status/rest'
+require 'puppet/indirector/resource/rest'
-describe Puppet::Indirector::Status::Rest do
+describe Puppet::Resource::Rest do
it "should be a sublcass of Puppet::Indirector::REST" do
- Puppet::Indirector::Status::Rest.superclass.should equal(Puppet::Indirector::REST)
+ Puppet::Resource::Rest.superclass.should equal(Puppet::Indirector::REST)
end
end
diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/rest.rb
index d12e3c6..1cb34c4 100755
--- a/spec/unit/indirector/rest.rb
+++ b/spec/unit/indirector/rest.rb
@@ -199,15 +199,26 @@ describe Puppet::Indirector::REST do
@searcher.find(@request)
end
- it "should deserialize and return the http response" do
+ it "should deserialize and return the http response, setting name" do
@connection.expects(:get).returns @response
- instance = stub 'object', :name= => nil
+ instance = stub 'object'
+ instance.expects(:name=)
@searcher.expects(:deserialize).with(@response).returns instance
@searcher.find(@request).should == instance
end
+ it "should deserialize and return the http response, and not require name=" do
+ @connection.expects(:get).returns @response
+
+ instance = stub 'object'
+ @searcher.expects(:deserialize).with(@response).returns instance
+
+ @searcher.find(@request).should == instance
+ end
+
+
it "should use the URI generated by the Handler module" do
@searcher.expects(:indirection2uri).with(@request).returns "/my/uri"
@connection.expects(:get).with { |path, args| path == "/my/uri" }.returns(@response)
diff --git a/spec/unit/network/rest_authconfig.rb b/spec/unit/network/rest_authconfig.rb
index 407fc43..fe17d56 100755
--- a/spec/unit/network/rest_authconfig.rb
+++ b/spec/unit/network/rest_authconfig.rb
@@ -17,6 +17,7 @@ describe Puppet::Network::RestAuthConfig do
{ :acl => "/certificate/", :method => :find, :authenticated => false },
{ :acl => "/certificate_request", :method => [:find, :save], :authenticated => false },
{ :acl => "/status", :method => [:find], :authenticated => true },
+ { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true },
]
before :each do
diff --git a/spec/unit/resource.rb b/spec/unit/resource.rb
index b26f4f9..2b1d49d 100755
--- a/spec/unit/resource.rb
+++ b/spec/unit/resource.rb
@@ -492,4 +492,23 @@ describe Puppet::Resource do
resource['foo'].should == %w{one}
end
end
+
+ describe "it should implement to_resource" do
+ resource = Puppet::Resource.new("file", "/my/file")
+ resource.to_resource.should == resource
+ end
+
+ describe "because it is an indirector model" do
+ it "should include Puppet::Indirector" do
+ Puppet::Resource.should be_is_a(Puppet::Indirector)
+ end
+
+ it "should have a default terminus" do
+ Puppet::Resource.indirection.terminus_class.should == :ral
+ end
+
+ it "should have a name" do
+ Puppet::Resource.new("file", "/my/file").name.should == "File//my/file"
+ end
+ end
end
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list