Conflicts:

	lib/puppet/util/settings.rb
	spec/integration/defaults.rb
	spec/unit/node/catalog.rb
	spec/unit/type/interface.rb
	spec/unit/type/ssh_authorized_key.rb
This commit is contained in:
Luke Kanies 2008-07-04 22:14:37 -05:00
Родитель df528a66ca 81be1c5c3f
Коммит b0febd263c
45 изменённых файлов: 573 добавлений и 1464 удалений

Просмотреть файл

@ -8,6 +8,14 @@
set file paths to 'false' to disable the CRL.
0.24.?
Fixed #1232 - the rundir no longer specifies a user/group,
and there are now client- and server-specific yaml directories.
Fixed 1240 - puppet will function more like puppetd if graphing
or reporting are enabled.
Fixed #1231 - Exceptions during initialization should now be clearer.
Fixed #1006 - puppetrun --class works again. I added the class
membership testing to the Ldap node terminus, and added tests,
so it shouldn't break again.

Просмотреть файл

@ -163,8 +163,9 @@ end
# Now parse the config
Puppet.parse_config
Puppet.genconfig
Puppet.genmanifest
if Puppet.settings.print_configs?
exit(Puppet.settings.print_configs ? 0 : 1)
end
begin
if options[:local] or options[:bucket]

Просмотреть файл

@ -212,6 +212,8 @@ begin
# Translate it to a RAL catalog
catalog = catalog.to_ral
catalog.host_config = true if Puppet[:graph] or Puppet[:report]
catalog.finalize
# And apply it

Просмотреть файл

@ -138,8 +138,9 @@ server = nil
end
end
Puppet.genconfig
Puppet.genmanifest
if Puppet.settings.print_configs?
exit(Puppet.settings.print_configs ? 0 : 1)
end
unless ARGV.length > 0
$stderr.puts "You must pass a script to parse"

Просмотреть файл

@ -63,8 +63,6 @@ module Puppet
:rundir => {
:default => rundir,
:mode => 01777,
:owner => "$user",
:group => "$group",
:desc => "Where Puppet PID files are kept."
},
:genconfig => [false,
@ -382,7 +380,9 @@ module Puppet
# To make sure this directory is created before we try to use it on the server, we need
# it to be in the server section (#1138).
:yamldir => {:default => "$vardir/yaml", :owner => "$user", :group => "$user", :mode => "750",
:desc => "The directory in which YAML data is stored, usually in a subdirectory."}
:desc => "The directory in which YAML data is stored, usually in a subdirectory."},
:clientyamldir => {:default => "$vardir/client_yaml", :mode => "750",
:desc => "The directory in which client-side YAML data is stored."}
)
self.setdefaults(:puppetd,

Просмотреть файл

@ -1,28 +0,0 @@
require 'puppet'
require 'puppet/util/methodhelper'
require 'puppet/util/errors'
module Puppet
# events are transient packets of information; they result in one or more (or none)
# subscriptions getting triggered, and then they get cleared
# eventually, these will be passed on to some central event system
class Event
include Puppet
include Puppet::Util::MethodHelper
include Puppet::Util::Errors
attr_accessor :event, :source, :transaction
@@events = []
def initialize(args)
set_options symbolize_options(args)
requiredopts(:event, :source)
end
def to_s
@source.to_s + " -> " + self.event.to_s
end
end
end

Просмотреть файл

@ -14,7 +14,7 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
end
# Separate this out so it's relatively atomic. It's tempting to call
# process() instead of entry2hash() here, but it ends up being
# process() instead of name2hash() here, but it ends up being
# difficult to test because all exceptions get caught by ldapsearch.
# LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything
# but LDAP::ResultError, even on bad connections, so we are rough handed
@ -35,21 +35,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
node = nil
names.each do |name|
break if node = process(name)
end
return nil unless node
next unless info = name2hash(name)
node.name = request.key
break if node = info2node(request.key, info)
end
return node
end
def process(name)
return nil unless info = name2hash(name)
info2node(name, info)
end
# Find more than one node. LAK:NOTE This is a bit of a clumsy API, because the 'search'
# method currently *requires* a key. It seems appropriate in some cases but not others,
# and I don't really know how to get rid of it as a requirement but allow it when desired.

Просмотреть файл

@ -36,7 +36,8 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
# Return the path to a given node's file.
def path(name)
File.join(Puppet[:yamldir], self.class.indirection_name.to_s, name.to_s + ".yaml")
base = (Puppet[:name] == "puppetmasterd") ? Puppet[:yamldir] : Puppet[:clientyamldir]
File.join(base, self.class.indirection_name.to_s, name.to_s + ".yaml")
end
private

Просмотреть файл

@ -139,7 +139,7 @@ class Puppet::Type
end
if ensureparam and ! ensureparam.insync?(currentvalues[ensureparam])
changes << Puppet::PropertyChange.new(ensureparam, currentvalues[ensureparam])
changes << Puppet::Transaction::Change.new(ensureparam, currentvalues[ensureparam])
# Else, if the 'ensure' property is correctly absent, then do
# nothing
elsif ensureparam and currentvalues[ensureparam] == :absent
@ -149,7 +149,7 @@ class Puppet::Type
currentvalues[property] ||= :absent
! property.insync?(currentvalues[property])
}.collect { |property|
Puppet::PropertyChange.new(property, currentvalues[property])
Puppet::Transaction::Change.new(property, currentvalues[property])
}
end

Просмотреть файл

@ -75,6 +75,8 @@ class Puppet::Node
def fact_merge
if facts = Puppet::Node::Facts.find(name)
merge(facts.values)
else
Puppet.warning "Could not find facts for %s; you probably have a discrepancy between the node and fact names" % name
end
end

Просмотреть файл

@ -95,6 +95,7 @@ class Puppet::Node::Catalog < Puppet::PGraph
# isn't sufficient.
return if newref == resource.ref
if existing = @resource_table[newref]
return if existing == resource
raise(ArgumentError, "Cannot alias %s to %s; resource %s already exists" % [resource.ref, name, newref])
end
@resource_table[newref] = resource

Просмотреть файл

@ -58,7 +58,7 @@ class Puppet::PGraph < Puppet::SimpleGraph
# to, which is the same thing as saying all edges directly below
# This vertex in the graph.
adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
edge.match?(event.event)
edge.match?(event.name)
end
end.compact.flatten
end

Просмотреть файл

@ -2,7 +2,6 @@
# blocks for actually doing work on the system.
require 'puppet'
require 'puppet/propertychange'
require 'puppet/parameter'
module Puppet

Просмотреть файл

@ -1,141 +0,0 @@
# the class responsible for actually doing any work
# enables no-op and logging/rollback
module Puppet
# Handle all of the work around performing an actual change,
# including calling 'sync' on the properties and producing events.
class PropertyChange
attr_accessor :is, :should, :type, :path, :property, :transaction, :changed, :proxy
# The log file generated when this object was changed.
attr_reader :report
# Switch the goals of the property, thus running the change in reverse.
def backward
@property.should = @is
@is = @property.retrieve
unless defined? @transaction
raise Puppet::Error,
"PropertyChange '%s' tried to be executed outside of transaction" %
self
end
unless @property.insync?(@is)
@property.info "Backing %s" % self
return self.go
else
@property.debug "rollback is already in sync: %s vs. %s" %
[@is, @property.should.inspect]
return nil
end
end
def changed?
self.changed
end
# Create our event object.
def event(name)
# default to a simple event type
unless name.is_a?(Symbol)
@property.warning("Property '%s' returned invalid event '%s'; resetting to default" %
[@property.class, name])
event = @property.resource.class.name.id2name + "_changed"
end
Puppet::Event.new(
:event => name,
:transaction => @transaction,
:source => self.source
)
end
def initialize(property, currentvalue)
unless property.is_a?(Puppet::Property)
raise Puppet::DevError, "Got a %s instead of a property" %
property.class
end
@property = property
@path = [property.path,"change"].flatten
@is = currentvalue
@should = property.should
@changed = false
end
# Perform the actual change. This method can go either forward or
# backward, and produces an event.
def go
if skip?
if self.noop
return [event(:noop)]
else
return nil
end
end
# The transaction catches any exceptions here.
events = @property.sync
if events.nil?
return nil
end
if events.is_a?(Array)
if events.empty?
return nil
end
else
events = [events]
end
return events.collect { |name|
@report = @property.log(@property.change_to_s(@is, @should))
event(name)
}
end
def forward
#@property.debug "moving change forward"
unless defined? @transaction
raise Puppet::Error,
"PropertyChange '%s' tried to be executed outside of transaction" %
self
end
return self.go
end
def noop
return @property.noop
end
def skip?
if @property.insync?(@is)
@property.info "Already in sync"
return true
end
if @property.noop
@property.log "is %s, should be %s (noop)" %
[property.is_to_s(@is), property.should_to_s(@should)]
#@property.debug "%s is noop" % @property
return true
end
return false
end
def source
self.proxy || @property.resource
end
def to_s
return "change %s.%s(%s)" %
[@transaction.object_id, self.object_id, @property.change_to_s(@is, @should)]
#return "change %s.%s" % [@transaction.object_id, self.object_id]
end
end
end

Просмотреть файл

@ -1,250 +0,0 @@
require 'puppet/provider/parsedfile'
require 'erb'
Puppet::Type.type(:interface).provide(:redhat) do
desc "Manage network interfaces on Red Hat operating systems. This provider
parses and generates configuration files in ``/etc/sysconfig/network-scripts``."
INTERFACE_DIR = "/etc/sysconfig/network-scripts"
confine :exists => INTERFACE_DIR
defaultfor :operatingsystem => [:fedora, :centos, :redhat]
# Create the setter/gettor methods to match the model.
mk_resource_methods
@templates = {}
# Register a template.
def self.register_template(name, string)
@templates[name] = ERB.new(string)
end
# Retrieve a template by name.
def self.template(name)
@templates[name]
end
register_template :alias, <<-ALIAS
DEVICE=<%= self.device %>
ONBOOT=<%= self.on_boot %>
BOOTPROTO=none
IPADDR=<%= self.name %>
NETMASK=<%= self.netmask %>
BROADCAST=
ALIAS
register_template :normal, <<-LOOPBACKDUMMY
DEVICE=<%= self.device %>
ONBOOT=<%= self.on_boot %>
BOOTPROTO=static
IPADDR=<%= self.name %>
NETMASK=<%= self.netmask %>
BROADCAST=
LOOPBACKDUMMY
# maximum number of dummy interfaces
@max_dummies = 10
# maximum number of aliases per interface
@max_aliases_per_iface = 10
@@dummies = []
@@aliases = Hash.new { |hash, key| hash[key] = [] }
# calculate which dummy interfaces are currently already in
# use prior to needing to call self.next_dummy later on.
def self.instances
# parse all of the config files at once
Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).collect do |file|
record = parse(file)
# store the existing dummy interfaces
@@dummies << record[:ifnum] if (record[:interface_type] == :dummy and ! @@dummies.include?(record[:ifnum]))
@@aliases[record[:interface]] << record[:ifnum] if record[:interface_type] == :alias
new(record)
end
end
# return the next avaliable dummy interface number, in the case where
# ifnum is not manually specified
def self.next_dummy
@max_dummies.times do |i|
unless @@dummies.include?(i.to_s)
@@dummies << i.to_s
return i.to_s
end
end
end
# return the next available alias on a given interface, in the case
# where ifnum if not manually specified
def self.next_alias(interface)
@max_aliases_per_iface.times do |i|
unless @@aliases[interface].include?(i.to_s)
@@aliases[interface] << i.to_s
return i.to_s
end
end
end
# base the ifnum, for dummy / loopback interface in linux
# on the last octect of the IP address
# Parse the existing file.
def self.parse(file)
instance = new()
return instance unless FileTest.exist?(file)
File.readlines(file).each do |line|
if line =~ /^(\w+)=(.+)$/
instance.send($1.downcase + "=", $2)
end
end
return instance
end
# Prefetch our interface list, yo.
def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end
def create
self.class.resource_type.validproperties.each do |property|
if value = @resource.should(property)
@property_hash[property] = value
end
end
@property_hash[:name] = @resource.name
return (@resource.class.name.to_s + "_created").intern
end
def destroy
File.unlink(file_path)
end
def exists?
FileTest.exist?(file_path)
end
# generate the content for the interface file, so this is dependent
# on whether we are adding an alias to a real interface, or a loopback
# address (also dummy) on linux. For linux it's quite involved, and we
# will use an ERB template
def generate
itype = self.interface_type == :alias ? :alias : :normal
self.class.template(itype).result(binding)
end
# Where should the file be written out?
# This defaults to INTERFACE_DIR/ifcfg-<namevar>, but can have a
# more symbolic name by setting interface_desc in the type.
def file_path
if resource and val = resource[:interface_desc]
desc = val
else
desc = self.name
end
self.fail("Could not get name for interface") unless desc
if self.interface_type == :alias
return File.join(INTERFACE_DIR, "ifcfg-" + self.interface + ":" + desc)
else
return File.join(INTERFACE_DIR, "ifcfg-" + desc)
end
end
# Use the device value to figure out all kinds of nifty things.
def device=(value)
case value
when /:/:
@property_hash[:interface], @property_hash[:ifnum] = value.split(":")
@property_hash[:interface_type] = :alias
when /^dummy/:
@property_hash[:interface_type] = :loopback
@property_hash[:interface] = "dummy"
# take the number of the dummy interface, as this is used
# when working out whether to call next_dummy when dynamically
# creating these
@property_hash[:ifnum] = value.sub("dummy",'')
@@dummies << @property_hash[:ifnum].to_s unless @@dummies.include?(@property_hash[:ifnum].to_s)
else
@property_hash[:interface_type] = :normal
@property_hash[:interface] = value
end
end
# create the device name, so this based on the IP, and interface + type
def device
case @resource.should(:interface_type)
when :loopback
@property_hash[:ifnum] ||= self.class.next_dummy
return "dummy" + @property_hash[:ifnum]
when :alias
@property_hash[:ifnum] ||= self.class.next_alias(@resource[:interface])
return @resource[:interface] + ":" + @property_hash[:ifnum]
end
end
# Set the name to our ip address.
def ipaddr=(value)
@property_hash[:name] = value
end
# whether the device is to be brought up on boot or not. converts
# the true / false of the type, into yes / no values respectively
# writing out the ifcfg-* files
def on_boot
case @property_hash[:onboot].to_s
when "true"
return "yes"
when "false"
return "no"
else
return "neither"
end
end
# Mark whether the interface should be started on boot.
def on_boot=(value)
# translate whether we come up on boot to true/false
case value.downcase
when "yes":
@property_hash[:onboot] = :true
else
@property_hash[:onboot] = :false
end
end
# Write the new file out.
def flush
# Don't flush to disk if we're removing the config.
return if self.ensure == :absent
@property_hash.each do |name, val|
if val == :absent
raise ArgumentError, "Propety %s must be provided" % val
end
end
File.open(file_path, "w") do |f|
f.puts generate()
end
end
def prefetch
@property_hash = self.class.parse(file_path)
end
end

Просмотреть файл

@ -1,133 +0,0 @@
require 'puppet/provider/parsedfile'
require 'erb'
Puppet::Type.type(:interface).provide(:sunos) do
confine :kernel => "SunOS"
# Add accessor/getter methods for each property/parameter; these methods
# modify @property_hash.
mk_resource_methods
# Get a list of interface instances.
def self.instances
Dir.glob("/etc/hostname.*").collect do |file|
device = File.basename(file).split(".").pop
instance = new(:interface => device)
instance.parse
instance
end
end
def self.match(hash)
# see if we can match the has against an existing object
if model.find { |obj| obj.value(:name) == hash[:name] }
return obj
else
return false
end
end
# Prefetch our interface list, yo.
def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end
def initialize(*args)
@property_hash = {}
super
end
def create
self.class.resource_type.validproperties.each do |property|
if value = resource.should(property)
@property_hash[property] = value
end
end
@property_hash[:name] = resource.name
return (@resource.class.name.to_s + "_created").intern
end
def destroy
File.unlink(file_path)
@property_hash[:ensure] = :absent
end
def exists?
FileTest.exist?(file_path)
end
# Where should the file be written out? Can be overridden by setting
# :target in the model.
def file_path
self.fail("Could not determine interface") unless interface = @property_hash[:interface] || (resource and resource[:interface])
return File.join("/etc", "hostname." + interface)
end
def flush
return if self.ensure == :absent
File.open(file_path, "w") { |f| f.print generate() + "\n" }
end
# Turn our record into a line.
def generate
ret = []
if self.interface_type == :alias
ret << "addif"
end
ret << self.name
if self.ifopts != :absent
if @property_hash[:ifopts].is_a?(Array)
ret << @property_hash[:ifopts].join(" ")
else
ret << @property_hash[:ifopts]
end
end
if self.onboot and ! [:absent, :false].include?(self.onboot)
ret << "up"
end
return ret.join(" ")
end
# Parse our interface file.
def parse
(@property_hash = {:ensure => :absent} and return) unless FileTest.exist?(file_path)
values = File.read(file_path).chomp.split(/\s+/)
@property_hash[:ensure] = :present
#@property_hash = {:ensure => :present}
# Are we the primary interface?
if values[0] == "addif"
@property_hash[:interface_type] = :alias
values.shift
else
@property_hash[:interface_type] = :normal
end
# Should the interface be up by default?
if values[-1] == "up"
@property_hash[:onboot] = :true
values.pop
else
@property_hash[:onboot] = :false
end
# Set the interface name.
@property_hash[:name] = values.shift
# Handle any interface options
unless values.empty?
@property_hash[:ifopts] = values.join(" ")
end
end
end

Просмотреть файл

@ -29,21 +29,5 @@ Puppet::Type.type(:ssh_authorized_key).provide(:parsed,
record[:options] = record[:options].join(',')
end
}
def prefetch
if not @resource.should(:target)
#
# Set default target when user is given
if val = @resource.should(:user)
target = File.expand_path("~%s/.ssh/authorized_keys" % val)
Puppet::debug("Setting target to %s" % target)
@resource[:target] = target
else
raise Puppet::Error, "Missing attribute 'user' or 'target'"
end
end
super
end
end

Просмотреть файл

@ -2,10 +2,12 @@
# and performs them
require 'puppet'
require 'puppet/propertychange'
module Puppet
class Transaction
require 'puppet/transaction/change'
require 'puppet/transaction/event'
attr_accessor :component, :catalog, :ignoreschedules
attr_accessor :sorted_resources, :configurator
@ -96,7 +98,7 @@ class Transaction
# Create an edge with this resource as both the source and
# target. The triggering method treats these specially for
# logging.
events = resourceevents.collect { |e| e.event }
events = resourceevents.collect { |e| e.name }
set_trigger(Puppet::Relationship.new(resource, resource, :callback => :refresh, :event => events))
end
end
@ -109,7 +111,6 @@ class Transaction
changes.collect { |change|
@changes << change
@count += 1
change.transaction = self
events = nil
begin
# use an array, so that changes can return more than one
@ -278,7 +279,7 @@ class Transaction
# of course, bad.
edge = orig_edge.class.new(orig_edge.source, orig_edge.target)
label = orig_edge.label.dup
label[:event] = events.collect { |e| e.event }
label[:event] = events.collect { |e| e.name }
edge.label = label
set_trigger(edge)
end
@ -680,11 +681,7 @@ class Transaction
[callback, subs.length]
# And then add an event for it.
return [Puppet::Event.new(
:event => :noop,
:transaction => self,
:source => resource
)]
return [Puppet::Transaction::Event.new(:noop, resource)]
end
if subs.length == 1 and subs[0].source == resource
@ -712,11 +709,7 @@ class Transaction
end
# And then add an event for it.
trigged << Puppet::Event.new(
:event => :triggered,
:transaction => self,
:source => resource
)
trigged << Puppet::Transaction::Event.new(:triggered, resource)
triggered(resource, callback)
end

Просмотреть файл

@ -0,0 +1,94 @@
require 'puppet/transaction'
require 'puppet/transaction/event'
# Handle all of the work around performing an actual change,
# including calling 'sync' on the properties and producing events.
class Puppet::Transaction::Change
attr_accessor :is, :should, :path, :property, :changed, :proxy
# Switch the goals of the property, thus running the change in reverse.
def backward
@is, @should = @should, @is
@property.should = @should
@property.info "Reversing %s" % self
return self.go
end
def changed?
self.changed
end
# Create our event object.
def event(name)
# default to a simple event type
unless name.is_a?(Symbol)
@property.warning("Property '%s' returned invalid event '%s'; resetting to default" %
[@property.class, name])
name = @property.event(should)
end
Puppet::Transaction::Event.new(name, self.resource)
end
def initialize(property, currentvalue)
@property = property
@path = [property.path,"change"].flatten
@is = currentvalue
@should = property.should
@changed = false
end
# Perform the actual change. This method can go either forward or
# backward, and produces an event.
def go
if self.noop?
@property.log "is %s, should be %s (noop)" % [property.is_to_s(@is), property.should_to_s(@should)]
return [event(:noop)]
end
# The transaction catches any exceptions here.
events = @property.sync
if events.nil?
return nil
end
if events.is_a?(Array)
if events.empty?
return nil
end
else
events = [events]
end
return events.collect { |name|
@report = @property.log(@property.change_to_s(@is, @should))
event(name)
}
end
def forward
return self.go
end
# Is our property noop? This is used for generating special events.
def noop?
return @property.noop
end
# The resource that generated this change. This is used for handling events,
# and the proxy resource is used for generated resources, since we can't
# send an event to a resource we don't have a direct relationship. If we
# have a proxy resource, then the events will be considered to be from
# that resource, rather than us, so the graph resolution will still work.
def resource
self.proxy || @property.resource
end
def to_s
return "change %s" % @property.change_to_s(@is, @should)
end
end

Просмотреть файл

@ -0,0 +1,21 @@
require 'puppet'
require 'puppet/util/methodhelper'
require 'puppet/util/errors'
# events are transient packets of information; they result in one or more (or none)
# subscriptions getting triggered, and then they get cleared
# eventually, these will be passed on to some central event system
class Puppet::Transaction::Event
include Puppet::Util::MethodHelper
include Puppet::Util::Errors
attr_reader :name, :source
def initialize(name, source)
@name, @source = name, source
end
def to_s
source.to_s + " -> " + name.to_s
end
end

Просмотреть файл

@ -1,6 +1,5 @@
require 'puppet'
require 'puppet/util/log'
require 'puppet/event'
require 'puppet/util/metric'
require 'puppet/property'
require 'puppet/parameter'
@ -415,7 +414,6 @@ class Type
end # Puppet::Type
end
require 'puppet/propertychange'
require 'puppet/provider'
# Always load these types.

Просмотреть файл

@ -138,11 +138,6 @@ module Puppet
# We have to treat :present specially, because it works with any
# type of file.
def insync?(currentvalue)
if property = @resource.property(:source) and ! property.described?
warning "No specified sources exist"
return true
end
if self.should == :present
if currentvalue.nil? or currentvalue == :absent
return false

Просмотреть файл

@ -135,18 +135,8 @@ module Puppet
return args
end
# Have we successfully described the remote source?
def described?
! @stats.nil? and ! @stats[:type].nil? #and @is != :notdescribed
end
# Use the info we get from describe() to check if we're in sync.
def insync?(currentvalue)
unless described?
warning "No specified sources exist"
return true
end
if currentvalue == :nocopy
return true
end
@ -180,7 +170,11 @@ module Puppet
def pinparams
[:mode, :type, :owner, :group]
end
def found?
! (@stats.nil? or @stats[:type].nil?)
end
# This basically calls describe() on our file, and then sets all
# of the local states appropriately. If the remote file is a normal
# file then we set it to copy; if it's a directory, then we just mark
@ -202,8 +196,8 @@ module Puppet
}
end
if @stats.nil? or @stats[:type].nil?
return nil # :notdescribed
if !found?
raise Puppet::Error, "No specified source was found from" + @should.inject("") { |s, source| s + " #{source},"}.gsub(/,$/,"")
end
case @stats[:type]

Просмотреть файл

@ -1,60 +0,0 @@
Puppet::Type.newtype(:interface) do
require 'erb'
@doc = "Create configuration for IP address aliases and loopback addresses."
newparam(:name, :namevar => true) do
desc "The ipaddress to add to alias or loopback/dummy interface"
end
ensurable
newparam(:interface) do
desc "The interface the IP should be added to"
end
newproperty(:interface_type) do
desc "The interface type, loopback (also dummy) or alias"
newvalue(:loopback)
newvalue(:alias)
newvalue(:normal)
# Make dummy and loopback equivalent
aliasvalue(:dummy, :loopback)
defaultto :normal
end
newparam(:interface_desc) do
desc "On Linux, the description / symbolic name you wish to refer to the
interface by. When absent, Redhat Linux defaults to uses the namevar
which will be either the IP address, or hostname."
end
newproperty(:onboot) do
desc "Whether the interface should be configured to come up on boot"
newvalue(:true)
newvalue(:false)
end
newproperty(:ifnum) do
desc "If not automatically configuring the dummy interface or
and alias. This is use to force a given number to be used"
end
newproperty(:netmask) do
desc "The netmask for the interface."
end
newproperty(:ifopts) do
desc "Interface options."
end
newparam(:target) do
include Puppet::Util::Warnings
desc "The path to the file this resource creates."
munge { |value| warnonce "Interface targets are deprecated and no longer have any function" }
end
end

Просмотреть файл

@ -5,14 +5,14 @@ module Puppet
ensurable
newparam(:name) do
desc "The ssh key comment."
desc "The SSH key comment."
isnamevar
end
newproperty(:type) do
desc "The encryption type used. Probably ssh-dss or ssh-rsa for
ssh version 2. Not used for ssh version 1."
desc "The encryption type used. Usually ssh-dss or ssh-rsa for
SSH version 2. Not used for SSH version 1."
newvalue("ssh-dss")
newvalue("ssh-rsa")
@ -26,19 +26,55 @@ module Puppet
end
newproperty(:user) do
desc "The user account in which the ssh key should be installed."
desc "The user account in which the SSH key should be installed."
def value=(value)
@resource[:target] = File.expand_path("~%s/.ssh/authorized_keys" % value)
super
end
end
newproperty(:target) do
desc "The file in which to store the ssh key."
desc "The file in which to store the SSH key."
end
newproperty(:options, :array_matching => :all) do
desc "Key options, see sshd(8) for possible values. Multiple values
should be specified as an array."
desc "Key options, see sshd(8) for possible values. Multiple values
should be specified as an array."
defaultto do :absent end
end
def generate
atype = Puppet::Type.type(:file)
target = self.should(:target)
dir = File.dirname(target)
user = should(:user) ? should(:user) : "root"
rels = []
unless catalog.resource(:file, dir)
rels << atype.create(:name => dir, :ensure => :directory, :mode => 0700, :owner => user)
end
unless catalog.resource(:file, target)
rels << atype.create(:name => target, :ensure => :present, :mode => 0600, :owner => user)
end
rels
end
autorequire(:user) do
if should(:user)
should(:user)
end
end
validate do
unless should(:target)
raise Puppet::Error, "Attribute 'user' or 'target' is mandatory"
end
end
end
end

Просмотреть файл

@ -1,6 +1,5 @@
# Description of yum repositories
require 'puppet/propertychange'
require 'puppet/util/inifile'
module Puppet

Просмотреть файл

@ -63,7 +63,6 @@ class Puppet::Util::Ldap::Connection
@connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
@connection.simple_bind(user, password)
rescue => detail
puts detail.class
raise Puppet::Error, "Could not connect to LDAP: %s" % detail
end
end

Просмотреть файл

@ -644,13 +644,10 @@ Generated on #{Time.now}.
begin
catalog.host_config = false
catalog.apply do |transaction|
if failures = transaction.any_failed?
# LAK:NOTE We should do something like this for some cases,
# since it can otherwise be hard to know what failed.
#transaction.report.logs.find_all { |log| log.level == :err }.each do |log|
# puts log.message
#end
raise "Could not configure myself; got %s failure(s)" % failures
if transaction.any_failed?
report = transaction.report
failures = report.logs.find_all { |log| log.level == :err }
raise "Got %s failure(s) while initializing: %s" % [failures.length, failures.collect { |l| l.to_s }.join("; ")]
end
end
end

Просмотреть файл

@ -27,4 +27,24 @@ describe "Puppet defaults" do
Puppet.settings[:cacrl] = 'false'
end
end
it "should have a clientyamldir setting" do
Puppet.settings[:clientyamldir].should_not be_nil
end
it "should have different values for the yamldir and clientyamldir" do
Puppet.settings[:yamldir].should_not == Puppet.settings[:clientyamldir]
end
# See #1232
it "should not specify a user or group for the clientyamldir" do
Puppet.settings.element(:clientyamldir).owner.should be_nil
Puppet.settings.element(:clientyamldir).group.should be_nil
end
# See #1232
it "should not specify a user or group for the rundir" do
Puppet.settings.element(:rundir).owner.should be_nil
Puppet.settings.element(:rundir).group.should be_nil
end
end

Просмотреть файл

@ -136,6 +136,14 @@ describe Puppet::Node::Ldap do
@searcher.stubs(:name2hash).returns @result
end
it "should create the node with the correct name, even if it was found by a different name" do
@searcher.expects(:name2hash).with("mynode.domain.com").returns nil
@searcher.expects(:name2hash).with("mynode").returns @result
Puppet::Node.expects(:new).with("mynode.domain.com").returns @node
@searcher.find(@request)
end
it "should add any classes from ldap" do
@result[:classes] = %w[a b c d]
@node.expects(:classes=).with(%w{a b c d})
@ -161,6 +169,19 @@ describe Puppet::Node::Ldap do
@searcher.find(@request)
end
it "should merge the node's facts after the parameters from ldap are assigned" do
# Make sure we've got data to start with, so the parameters are actually set.
@result[:parameters] = {}
@result[:parameters]["one"] = "yay"
# A hackish way to enforce order.
set = false
@node.expects(:parameters=).with { |*args| set = true }
@node.expects(:fact_merge).with { |*args| raise "Facts were merged before parameters were set" unless set; true }
@searcher.find(@request)
end
describe "and a parent node is specified" do
before do
@entry = {:classes => [], :parameters => {}}
@ -304,13 +325,22 @@ describe Puppet::Node::Ldap do
@searcher.search @request
end
it "should return a node for each processed entry" do
@searcher.expects(:ldapsearch).yields("one")
@searcher.expects(:entry2hash).with("one").returns(:name => "foo")
it "should return a node for each processed entry with the name from the entry" do
@searcher.expects(:ldapsearch).yields("whatever")
@searcher.expects(:entry2hash).with("whatever").returns(:name => "foo")
result = @searcher.search(@request)
result[0].should be_instance_of(Puppet::Node)
result[0].name.should == "foo"
end
it "should merge each node's facts" do
node = mock 'node'
Puppet::Node.expects(:new).with("foo").returns node
node.expects(:fact_merge)
@searcher.stubs(:ldapsearch).yields("one")
@searcher.stubs(:entry2hash).with("one").returns(:name => "foo")
@searcher.search(@request)
end
end
end

Просмотреть файл

@ -20,12 +20,25 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do
@subject.name = :me
@dir = "/what/ever"
Puppet.settings.stubs(:value).with(:yamldir).returns(@dir)
Puppet.settings.stubs(:value).returns("fakesettingdata")
Puppet.settings.stubs(:value).with(:clientyamldir).returns(@dir)
@request = stub 'request', :key => :me, :instance => @subject
end
describe Puppet::Indirector::Yaml, " when choosing file location" do
it "should use the yamldir if the process name is 'puppetmasterd'" do
Puppet.settings.expects(:value).with(:name).returns "puppetmasterd"
Puppet.settings.expects(:value).with(:yamldir).returns "/main/yaml/dir"
@store.path(:me).should =~ %r{^/main/yaml/dir}
end
it "should use the client yamldir if the process name is not 'puppetmasterd'" do
Puppet.settings.expects(:value).with(:name).returns "cient"
Puppet.settings.expects(:value).with(:clientyamldir).returns "/client/yaml/dir"
@store.path(:me).should =~ %r{^/client/yaml/dir}
end
it "should store all files in a single file root set in the Puppet defaults" do
@store.path(:me).should =~ %r{^#{@dir}}
end

Просмотреть файл

@ -492,7 +492,12 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
@catalog.resource("me", "other").should equal(@one)
end
it "should fail to add an alias if the aliased name already exists as a resource" do
it "should ignore conflicting aliases that point to the aliased resource" do
@catalog.alias(@one, "other")
lambda { @catalog.alias(@one, "other") }.should_not raise_error
end
it "should fail to add an alias if the aliased name already exists" do
@catalog.add_resource @one
proc { @catalog.alias @two, "one" }.should raise_error(ArgumentError)
end

Просмотреть файл

@ -47,8 +47,8 @@ end
describe Puppet::PGraph, " when matching edges" do
before do
@graph = Puppet::PGraph.new
@event = Puppet::Event.new(:source => "a", :event => :yay)
@none = Puppet::Event.new(:source => "a", :event => :NONE)
@event = Puppet::Transaction::Event.new(:yay, "a")
@none = Puppet::Transaction::Event.new(:NONE, "a")
@edges = {}
@edges["a/b"] = Puppet::Relationship.new("a", "b", {:event => :yay, :callback => :refresh})

Просмотреть файл

@ -1,268 +0,0 @@
#!/usr/bin/env ruby
#
# Created by Luke Kanies on 2007-11-20.
# Copyright (c) 2006. All rights reserved.
require File.dirname(__FILE__) + '/../../../spec_helper'
provider_class = Puppet::Type.type(:interface).provider(:redhat)
describe provider_class do
it "should not be functional on systems without a network-scripts directory" do
FileTest.expects(:exist?).with("/etc/sysconfig/network-scripts").returns(false)
provider_class.should_not be_suitable
end
it "should be functional on systems with a network-scripts directory" do
FileTest.expects(:exist?).with("/etc/sysconfig/network-scripts").returns(true)
provider_class.should be_suitable
end
end
describe provider_class, " when determining the file path" do
it "should always contain '/etc/sysconfig/network-scripts/ifcfg-'" do
provider = provider_class.new(:name => "192.168.0.1")
provider.file_path.should =~ %r{^/etc/sysconfig/network-scripts/ifcfg-}
end
it "should include the interface name and the description when the interface is an alias" do
provider = provider_class.new(:name => "192.168.0.1", :interface => "eth0")
provider.interface_type = :alias
resource = stub 'resource'
resource.stubs(:[]).with(:interface_desc).returns("blah")
provider.resource = resource
provider.file_path.should == "/etc/sysconfig/network-scripts/ifcfg-eth0:blah"
end
it "should just include the description when the interface is not an alias" do
provider = provider_class.new(:name => "192.168.0.1")
provider.interface_type = :normal
resource = stub 'resource'
resource.stubs(:[]).with(:interface_desc).returns("eth0")
provider.resource = resource
provider.file_path.should == "/etc/sysconfig/network-scripts/ifcfg-eth0"
end
it "should use the interface description if one is available" do
provider = provider_class.new(:name => "192.168.0.1")
provider.interface_type = :normal
resource = stub 'resource'
resource.stubs(:[]).with(:interface_desc).returns("eth0")
provider.resource = resource
provider.file_path.should == "/etc/sysconfig/network-scripts/ifcfg-eth0"
end
it "should use the name if no interface description is available" do
provider = provider_class.new(:name => "192.168.0.1")
provider.interface_type = :normal
provider.file_path.should == "/etc/sysconfig/network-scripts/ifcfg-192.168.0.1"
end
it "should fail if no name or interface description can be found" do
provider = provider_class.new()
proc { provider.file_path }.should raise_error
end
end
describe provider_class, " when returning instances" do
it "should consider each file in the network-scripts directory an interface instance" do
Dir.expects(:glob).with("/etc/sysconfig/network-scripts/ifcfg-*").returns(%w{one two})
one = {:name => "one"}
two = {:name => "two"}
Puppet::Type::Interface::ProviderRedhat.expects(:parse).with("one").returns(one)
Puppet::Type::Interface::ProviderRedhat.expects(:parse).with("two").returns(two)
Puppet::Type::Interface::ProviderRedhat.expects(:new).with(one).returns(:one)
Puppet::Type::Interface::ProviderRedhat.expects(:new).with(two).returns(:two)
Puppet::Type::Interface::ProviderRedhat.instances.should == [:one, :two]
end
end
describe provider_class, " when parsing" do
it "should return an unmodified provider if the file does not exist" do
FileTest.expects(:exist?).with("/my/file").returns(false)
provider = mock 'provider'
Puppet::Type::Interface::ProviderRedhat.expects(:new).returns(provider)
Puppet::Type::Interface::ProviderRedhat.parse("/my/file").should equal(provider)
end
it "should set each attribute in the file on the provider" do
FileTest.expects(:exist?).with("/my/file").returns(true)
File.expects(:readlines).with("/my/file").returns(%w{one=two three=four})
provider = mock 'provider'
Puppet::Type::Interface::ProviderRedhat.expects(:new).returns(provider)
provider.expects(:one=).with('two')
provider.expects(:three=).with('four')
Puppet::Type::Interface::ProviderRedhat.parse("/my/file").should equal(provider)
end
end
describe provider_class, " when setting the device to a value containing ':'" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
@provider.device = "one:two"
end
it "should set the interface type to :alias" do
@provider.interface_type.should == :alias
end
it "should set the interface to the string to the left of the ':'" do
@provider.interface.should == "one"
end
it "should set the ifnum to the string to the right of the ':'" do
@provider.ifnum.should == "two"
end
end
describe provider_class, " when setting the device to a value starting with 'dummy-'" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
@provider.device = "dummy5"
end
it "should set the interface type to :loopback" do
@provider.interface_type.should == :loopback
end
it "should set the interface to 'dummy'" do
@provider.interface.should == "dummy"
end
it "should set the ifnum to remainder of value after removing 'dummy'" do
@provider.ifnum.should == "5"
end
end
describe provider_class, " when setting the device to a value containing neither 'dummy-' nor ':'" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
@provider.device = "whatever"
end
it "should set the interface type to :normal" do
@provider.interface_type.should == :normal
end
it "should set the interface to the device value" do
@provider.interface.should == "whatever"
end
end
describe provider_class, " when setting the on_boot value" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
end
it "should set it to :true if the value is 'yes'" do
@provider.on_boot = "yes"
@provider.onboot.should == :true
end
it "should set it to :false if the value is not 'yes'" do
@provider.on_boot = "no"
@provider.onboot.should == :false
end
end
describe provider_class, " when setting the ipaddr value" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
end
it "should set the name to the provided value" do
@provider.ipaddr = "yay"
@provider.name.should == "yay"
end
end
describe provider_class, " when generating" do
before do
@provider = Puppet::Type::Interface::ProviderRedhat.new
@provider.interface_type = :alias
@provider.stubs(:device).returns("mydevice")
@provider.stubs(:on_boot).returns("myboot")
@provider.stubs(:name).returns("myname")
@provider.stubs(:netmask).returns("mynetmask")
@provider.interface_type = :alias
@text = @provider.generate
end
it "should set the bootproto to none if the interface is an alias" do
@text.should =~ /^BOOTPROTO=none$/
end
it "should set the bootproto to static if the interface is a loopback" do
@provider.interface_type = :loopback
@text = @provider.generate
@text.should =~ /^BOOTPROTO=static$/
end
it "should set the broadcast address to nothing" do
@text.should =~ /^BROADCAST=$/
end
it "should set the netmask to mynetmask" do
@text.should =~ /^NETMASK=mynetmask$/
end
it "should set the device to the provider's device" do
@text.should =~ /^DEVICE=mydevice$/
end
it "should set the onboot to the provider's on_boot value" do
@text.should =~ /^ONBOOT=myboot$/
end
it "should set the ipaddr to the provider's name" do
@text.should =~ /^IPADDR=myname$/
end
end
describe provider_class, " when creating and destroying" do
before do
@provider = provider_class.new(:interface => "eth0", :name => "testing")
@path = "/etc/sysconfig/network-scripts/ifcfg-testing"
end
it "should consider the interface present if the file exists" do
FileTest.expects(:exist?).with(@path).returns(true)
@provider.should be_exists
end
it "should consider the interface absent if the file does not exist" do
FileTest.expects(:exist?).with(@path).returns(false)
@provider.should_not be_exists
end
it "should remove the file if the interface is being destroyed" do
File.expects(:unlink).with(@path)
@provider.destroy
end
it "should mark :ensure as :absent if the interface is destroyed" do
File.stubs(:unlink)
@provider.destroy
@provider.ensure.should == :absent
end
it "should mark :ensure as :present if the interface is being created" do
resource = stub 'resource', :name => 'testing'
resource.stubs(:should).with { |name| name == :ensure }.returns(:present)
resource.stubs(:should).with { |name| name != :ensure }.returns(nil)
@provider.resource = resource
@provider.create
@provider.ensure.should == :present
end
it "should write the generated text to disk when the interface is flushed" do
fh = mock("filehandle")
File.expects(:open).yields(fh)
fh.expects(:puts).with("generated")
resource = stub 'resource', :name => 'testing'
resource.stubs(:[]).with(:interface_desc).returns(nil)
resource.stubs(:should).with { |name| name == :ensure }.returns(:present)
resource.stubs(:should).with { |name| name != :ensure }.returns(nil)
@provider.resource = resource
@provider.create
@provider.stubs(:generate).returns("generated")
@provider.flush
end
it "should not write the generated text to disk when the interface is flushed if :ensure == :absent" do
@provider.ensure = :absent
@provider.flush
end
end

Просмотреть файл

@ -1,239 +0,0 @@
#!/usr/bin/env ruby
#
# Created by Luke Kanies on 2007-11-25.
# Copyright (c) 2006. All rights reserved.
require File.dirname(__FILE__) + '/../../../spec_helper'
require 'puppet/provider/interface/sunos'
provider_class = Puppet::Type.type(:interface).provider(:sunos)
describe provider_class do
it "should not be functional on non-SunOS kernels" do
Facter.expects(:value).with(:kernel).returns("Linux")
provider_class.should_not be_suitable
end
it "should be functional on SunOS kernels" do
Facter.expects(:value).with(:kernel).returns("SunOS")
provider_class.should be_suitable
end
it "should pick its file path by combining '/etc/hostname.' with the interface if one is set" do
provider = provider_class.new(:record_type => :sunos, :interface_type => :normal, :name => "testing", :interface => 'eth0')
provider.file_path.should == "/etc/hostname.eth0"
end
it "should pick its file path by combining '/etc/hostname.' with the resource's interface if one is not set in the provider" do
provider = provider_class.new(:record_type => :sunos, :interface_type => :normal, :name => "testing")
resource = mock 'resource'
resource.stubs(:[]).with(:interface).returns("eth0")
provider.resource = resource
provider.file_path.should == "/etc/hostname.eth0"
end
it "should fail when picking its file path if there is no resource nor an interface set in the provider" do
provider = provider_class.new(:record_type => :sunos, :interface_type => :normal, :name => "testing")
proc { provider.file_path }.should raise_error(Puppet::Error)
end
end
describe provider_class, " when listing interfaces" do
it "should return an instance for every file matching /etc/hostname.*, created with the interface name set from the file" do
Dir.expects(:glob).with("/etc/hostname.*").returns(%w{/etc/hostname.one /etc/hostname.two})
one_instance = stub 'one_instance', :parse => nil
two_instance = stub 'two_instance', :parse => nil
provider_class.expects(:new).with(:interface => "one").returns(one_instance)
provider_class.expects(:new).with(:interface => "two").returns(two_instance)
provider_class.instances.should == [one_instance, two_instance]
end
it "should call parse on each instance being returned" do
Dir.expects(:glob).with("/etc/hostname.*").returns(%w{/etc/hostname.one})
one_instance = mock 'one_instance'
provider_class.expects(:new).with(:interface => "one").returns(one_instance)
one_instance.expects(:parse)
provider_class.instances
end
it "should assign matching providers to any prefetched instances" do
Dir.expects(:glob).with("/etc/hostname.*").returns(%w{one two})
one_instance = stub 'one_instance', :name => "one", :parse => nil
two_instance = stub 'two_instance', :name => "two", :parse => nil
provider_class.expects(:new).with(:interface => "one").returns(one_instance)
provider_class.expects(:new).with(:interface => "two").returns(two_instance)
resources = {"one" => mock("one"), "three" => mock('three')}
resources["one"].expects(:provider=).with(one_instance)
provider_class.prefetch(resources)
end
end
describe provider_class, " when creating and destroying" do
before do
@provider = provider_class.new(:interface => "eth0", :name => "testing")
end
it "should consider the interface present if the file exists" do
FileTest.expects(:exist?).with("/etc/hostname.eth0").returns(true)
@provider.should be_exists
end
it "should consider the interface absent if the file does not exist" do
FileTest.expects(:exist?).with("/etc/hostname.eth0").returns(false)
@provider.should_not be_exists
end
it "should remove the file if the interface is being destroyed" do
File.expects(:unlink).with("/etc/hostname.eth0")
@provider.destroy
end
it "should mark :ensure as :absent if the interface is destroyed" do
File.stubs(:unlink)
@provider.destroy
@provider.ensure.should == :absent
end
it "should mark :ensure as :present if the interface is being created" do
resource = stub 'resource', :name => 'testing'
resource.stubs(:should).with { |name| name == :ensure }.returns(:present)
resource.stubs(:should).with { |name| name != :ensure }.returns(nil)
@provider.resource = resource
@provider.create
@provider.ensure.should == :present
end
it "should write the generated text to disk when the interface is flushed" do
fh = mock("filehandle")
File.expects(:open).yields(fh)
fh.expects(:print).with("testing\n")
resource = stub 'resource', :name => 'testing'
resource.stubs(:should).with { |name| name == :ensure }.returns(:present)
resource.stubs(:should).with { |name| name != :ensure }.returns(nil)
@provider.resource = resource
@provider.create
@provider.flush
end
it "should not write the generated text to disk when the interface is flushed if :ensure == :absent" do
@provider.ensure = :absent
@provider.flush
end
end
describe provider_class, " when parsing a non-existant file" do
it "should mark the interface as absent" do
@provider = provider_class.new(:interface => "eth0", :name => "testing")
FileTest.expects(:exist?).with("/etc/hostname.eth0").returns(false)
@provider.parse
@provider.ensure.should == :absent
end
end
describe provider_class, " when parsing an existing file" do
before do
@provider = provider_class.new(:interface => "eth0", :name => "testing")
FileTest.stubs(:exist?).with("/etc/hostname.eth0").returns(true)
end
def set_text(text)
File.stubs(:read).with("/etc/hostname.eth0").returns(text)
end
it "should retain the interface name" do
set_text "testing"
@provider.parse
@provider.ensure.should == :present
@provider.interface.should == "eth0"
end
it "should mark the interface as present" do
set_text "testing"
@provider.parse
@provider.ensure.should == :present
end
it "should mark the interface as an alias if the first word is 'addif'" do
set_text "addif testing"
@provider.parse
@provider.interface_type.should == :alias
end
it "should not mark the interface as normal if the first word is not 'addif'" do
set_text "testing"
@provider.parse
@provider.interface_type.should == :normal
end
it "should start the interface on boot of the last word is 'up'" do
set_text "testing up"
@provider.parse
@provider.onboot.should == :true
end
it "should not start the interface on boot of the last word is not 'up'" do
set_text "testing"
@provider.parse
@provider.onboot.should == :false
end
it "should set the interface to the first non-behavioural word" do
set_text "addif testing up"
@provider.parse
@provider.name.should == "testing"
end
it "should consider any remaining terms to be interface options" do
set_text "addif testing -O up"
@provider.parse
@provider.ifopts.should == "-O"
end
end
describe provider_class, " when generating" do
before do
@provider = provider_class.new(:interface => "eth0", :name => "testing")
end
it "should prefix the text with 'addif' if the interface is an alias" do
@provider.interface_type = :alias
@provider.generate.should == "addif testing"
end
it "should not prefix the text with 'addif' if the interface is not an alias" do
@provider.generate.should == "testing"
end
it "should put the ifopts after the name if they are present" do
@provider.ifopts = "-O"
@provider.generate.should == "testing -O"
end
it "should mark the interface up if onboot is enabled" do
@provider.onboot = :true
@provider.generate.should == "testing up"
end
it "should use the resource name if no provider name is present" do
provider = provider_class.new(:interface => "eth0")
resource = stub 'resource', :name => "rtest"
provider.resource = resource
provider.generate.should == "rtest"
end
it "should use the provider name if present" do
@provider.generate.should == "testing"
end
it "should fail if neither a resource nor the provider name is present" do
provider = provider_class.new(:interface => "eth0")
proc { provider.generate }.should raise_error
end
end

182
spec/unit/transaction/change.rb Executable file
Просмотреть файл

@ -0,0 +1,182 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/transaction/change'
describe Puppet::Transaction::Change do
Change = Puppet::Transaction::Change
describe "when initializing" do
before do
@property = stub 'property', :path => "/property/path", :should => "shouldval"
end
it "should require the property and current value" do
lambda { Change.new() }.should raise_error
end
it "should set its property to the provided property" do
Change.new(@property, "value").property.should == :property
end
it "should set its 'is' value to the provided value" do
Change.new(@property, "value").is.should == "value"
end
it "should retrieve the 'should' value from the property" do
# Yay rspec :)
Change.new(@property, "value").should.should == @property.should
end
it "should set its path to the path of the property plus 'change'" do
Change.new(@property, "value").path.should == [@property.path, "change"]
end
end
describe "when an instance" do
before do
@property = stub 'property', :path => "/property/path", :should => "shouldval"
@change = Change.new(@property, "value")
end
it "should be noop if the property is noop" do
@property.expects(:noop).returns true
@change.noop?.should be_true
end
it "should set its resource to the proxy if it has one" do
@change.proxy = :myresource
@change.resource.should == :myresource
end
it "should set its resource to the property's resource if no proxy is set" do
@property.expects(:resource).returns :myresource
@change.resource.should == :myresource
end
it "should have a method for marking that it's been execution" do
@change.changed = true
@change.changed?.should be_true
end
describe "and creating an event" do
before do
@property.stubs(:resource).returns "myresource"
end
it "should produce a warning if the event name is not a symbol" do
@property.expects(:warning)
@property.stubs(:event).returns :myevent
@change.event("a string")
end
it "should use the property to generate the event name if the provided name is not a symbol" do
@property.stubs(:warning)
@property.expects(:event).with(@change.should).returns :myevent
Puppet::Transaction::Event.expects(:new).with { |name, source| name == :myevent }
@change.event("a string")
end
end
describe "and executing" do
describe "in noop mode" do
before { @change.stubs(:noop?).returns true }
it "should log that it is in noop" do
@property.expects(:is_to_s)
@property.expects(:should_to_s)
@property.expects(:log)
@change.stubs :event
@change.forward
end
it "should produce a :noop event and return" do
@property.stub_everything
@change.expects(:event).with(:noop).returns :noop_event
@change.forward.should == [:noop_event]
end
end
describe "without noop" do
before do
@change.stubs(:noop?).returns false
@property.stub_everything
@property.stubs(:resource).returns "myresource"
end
it "should sync the property" do
@property.expects(:sync)
@change.forward
end
it "should return nil if syncing the property returns nil" do
@property.stubs(:sync).returns nil
@change.forward.should be_nil
end
it "should return nil if syncing the property returns an empty array" do
@property.stubs(:sync).returns []
@change.forward.should be_nil
end
it "should log the change" do
@property.expects(:sync).returns [:one]
@property.expects(:log)
@property.expects(:change_to_s)
@change.forward
end
it "should return an array of events" do
@property.expects(:sync).returns [:one, :two]
@change.expects(:event).with(:one).returns :uno
@change.expects(:event).with(:two).returns :dos
@change.forward.should == [:uno, :dos]
end
end
describe "backward" do
before do
@property = stub 'property'
@property.stub_everything
@property.stubs(:should).returns "shouldval"
@change = Change.new(@property, "value")
@change.stubs :go
end
it "should swap the 'is' and 'should' values" do
@change.backward
@change.is.should == "shouldval"
@change.should.should == "value"
end
it "should set the 'should' value on the property to the previous 'is' value" do
@property.expects(:should=).with "value"
@change.backward
end
it "should log that it's reversing the change" do
@property.expects(:info)
@change.backward
end
it "should execute" do
@change.expects(:go)
@change.backward
end
end
end
end
end

25
spec/unit/transaction/event.rb Executable file
Просмотреть файл

@ -0,0 +1,25 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/transaction/event'
describe Puppet::Transaction::Event do
Event = Puppet::Transaction::Event
it "should require a name and a source" do
lambda { Event.new }.should raise_error(ArgumentError)
end
it "should have a name getter" do
Event.new(:foo, "bar").name.should == :foo
end
it "should have a source accessor" do
Event.new(:foo, "bar").source.should == "bar"
end
it "should be able to produce a string containing the event name and the source" do
Event.new(:event, :source).to_s.should == "source -> event"
end
end

Просмотреть файл

@ -31,6 +31,18 @@ describe Puppet::Type.type(:file) do
end
end
describe "when specifying a source" do
before do
@file[:source] = "/bar"
end
it "should raise if source doesn't exist" do
@file.property(:source).expects(:found?).returns(false)
lambda { @file.retrieve }.should raise_error(Puppet::Error)
end
end
describe "when retrieving remote files" do
before do
@filesource = Puppet::Type::File::FileSource.new

Просмотреть файл

@ -1,93 +0,0 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../spec_helper'
interface = Puppet::Type.type(:interface)
describe interface do
before do
@class = Puppet::Type.type(:interface)
@provider_class = stub 'provider_class', :name => "fake", :suitable? => true, :supports_parameter? => true
@class.stubs(:defaultprovider).returns(@provider_class)
@class.stubs(:provider).returns(@provider_class)
@provider = stub 'provider', :class => @provider_class, :file_path => "/tmp/whatever", :clear => nil
@provider_class.stubs(:new).returns(@provider)
end
it "should have a name parameter" do
@class.attrtype(:name).should == :param
end
it "should have :name be its namevar" do
@class.namevar.should == :name
end
it "should have a :provider parameter" do
@class.attrtype(:provider).should == :param
end
it "should have an ensure property" do
@class.attrtype(:ensure).should == :property
end
it "should support :present as a value for :ensure" do
proc { @class.create(:name => "whev", :ensure => :present) }.should_not raise_error
end
it "should support :absent as a value for :ensure" do
proc { @class.create(:name => "whev", :ensure => :absent) }.should_not raise_error
end
it "should have an interface_type property" do
@class.attrtype(:interface_type).should == :property
end
it "should support :loopback as an interface_type value" do
proc { @class.create(:name => "whev", :interface_type => :loopback) }.should_not raise_error
end
it "should support :alias as an interface_type value" do
proc { @class.create(:name => "whev", :interface_type => :alias) }.should_not raise_error
end
it "should support :normal as an interface_type value" do
proc { @class.create(:name => "whev", :interface_type => :normal) }.should_not raise_error
end
it "should alias :dummy to the :loopback interface_type value" do
int = @class.create(:name => "whev", :interface_type => :dummy)
int.should(:interface_type).should == :loopback
end
it "should not support values other than :loopback, :alias, :normal, and :dummy in the interface_type" do
proc { @class.create(:name => "whev", :interface_type => :something) }.should raise_error(Puppet::Error)
end
it "should have an interface_desc parameter" do
@class.attrtype(:interface_desc).should == :param
end
it "should have an onboot property" do
@class.attrtype(:onboot).should == :property
end
it "should support :true as an onboot value" do
proc { @class.create(:name => "whev", :onboot => :true) }.should_not raise_error
end
it "should support :false as an onboot value" do
proc { @class.create(:name => "whev", :onboot => :false) }.should_not raise_error
end
it "should have an ifnum property" do
@class.attrtype(:ifnum).should == :property
end
it "should have a netmask property" do
@class.attrtype(:netmask).should == :property
end
it "should have an ifopts property" do
@class.attrtype(:ifopts).should == :property
end
it "should have a target parameter" do
@class.attrtype(:target).should == :param
end
end

Просмотреть файл

@ -14,6 +14,7 @@ describe ssh_authorized_key do
@provider = stub 'provider', :class => @provider_class, :file_path => "/tmp/whatever", :clear => nil
@provider_class.stubs(:new).returns(@provider)
@catalog = Puppet::Node::Catalog.new
end
it "should have a name parameter" do
@ -33,27 +34,27 @@ describe ssh_authorized_key do
end
it "should support :present as a value for :ensure" do
proc { @class.create(:name => "whev", :ensure => :present) }.should_not raise_error
proc { @class.create(:name => "whev", :ensure => :present, :user => "nobody") }.should_not raise_error
end
it "should support :absent as a value for :ensure" do
proc { @class.create(:name => "whev", :ensure => :absent) }.should_not raise_error
proc { @class.create(:name => "whev", :ensure => :absent, :user => "nobody") }.should_not raise_error
end
it "should have an type property" do
@class.attrtype(:type).should == :property
end
it "should support ssh-dss as an type value" do
proc { @class.create(:name => "whev", :type => "ssh-dss") }.should_not raise_error
proc { @class.create(:name => "whev", :type => "ssh-dss", :user => "nobody") }.should_not raise_error
end
it "should support ssh-rsa as an type value" do
proc { @class.create(:name => "whev", :type => "ssh-rsa") }.should_not raise_error
proc { @class.create(:name => "whev", :type => "ssh-rsa", :user => "nobody") }.should_not raise_error
end
it "should support :dsa as an type value" do
proc { @class.create(:name => "whev", :type => :dsa) }.should_not raise_error
proc { @class.create(:name => "whev", :type => :dsa, :user => "nobody") }.should_not raise_error
end
it "should support :rsa as an type value" do
proc { @class.create(:name => "whev", :type => :rsa) }.should_not raise_error
proc { @class.create(:name => "whev", :type => :rsa, :user => "nobody") }.should_not raise_error
end
it "should not support values other than ssh-dss, ssh-rsa, dsa, rsa in the ssh_authorized_key_type" do
@ -75,4 +76,55 @@ describe ssh_authorized_key do
it "should have a target property" do
@class.attrtype(:target).should == :property
end
it "should autorequire parent directories when user is given" do
@catalog.add_resource @class.create(
:name => "Test",
:key => "AAA",
:type => "ssh-rsa",
:ensure => :present,
:user => "root")
@catalog.apply
target = File.expand_path("~root/.ssh")
@catalog.resource(:file, target).should be_an_instance_of(Puppet::Type.type(:file))
end
it "should set target when user is given" do
@catalog.add_resource @class.create(
:name => "Test",
:key => "AAA",
:type => "ssh-rsa",
:ensure => :present,
:user => "root")
@catalog.apply
target = File.expand_path("~root/.ssh/authorized_keys")
@catalog.resource(:file, target).should be_an_instance_of(Puppet::Type.type(:file))
end
it "should autorequire parent directories when target is given" do
target = "/tmp/home/foo/bar/.ssh/authorized_keys"
@catalog.add_resource @class.create(
:name => "Test",
:key => "AAA",
:type => "ssh-rsa",
:ensure => :present,
:target => target)
@catalog.apply
@catalog.resource(:file, target).should be_an_instance_of(Puppet::Type.type(:file))
end
it "should raise an error when neither user nor target is given" do
proc do
@class.create(
:name => "Test",
:key => "AAA",
:type => "ssh-rsa",
:ensure => :present)
end.should raise_error(Puppet::Error)
end
end

Просмотреть файл

@ -668,11 +668,17 @@ describe Puppet::Util::Settings do
@settings.reuse
end
it "should fail if any resources fail" do
it "should fail with an appropriate message if any resources fail" do
stub_transaction
@trans.expects(:any_failed?).returns(true)
report = mock 'report'
@trans.expects(:report).returns report
proc { @settings.use(:whatever) }.should raise_error(RuntimeError)
log = mock 'log', :to_s => "My failure", :level => :err
report.expects(:logs).returns [log]
@settings.expects(:raise).with { |msg| msg.include?("My failure") }
@settings.use(:whatever)
end
end

Просмотреть файл

@ -82,7 +82,7 @@ module PuppetTest::Support::Utils
newevents = nil
assert_nothing_raised("Transaction %s %s failed" % [type, msg]) {
newevents = trans.send(method).reject { |e| e.nil? }.collect { |e|
e.event
e.name
}
}

Просмотреть файл

@ -1,140 +0,0 @@
#!/usr/bin/env ruby
#
# Created by Luke A. Kanies on 2006-12-21.
# Copyright (c) 2006. All rights reserved.
require File.dirname(__FILE__) + '/../lib/puppettest'
require 'puppettest'
class TestPropertyChange < Test::Unit::TestCase
include PuppetTest
class FakeProperty < Puppet::Property
attr_accessor :is, :should, :resource
attr_reader :noop
def change_to_s(currentvalue, newvalue)
"fake change"
end
def insync?(is)
is == @should
end
def log(msg)
Puppet::Util::Log.create(
:level => :info,
:source => self,
:message => msg
)
end
def noop
if defined? @noop
@noop
else
false
end
end
def path
"fakechange"
end
def should_to_s(newvalue)
newvalue.to_s
end
def sync
if insync?(@is)
return nil
else
@is = @should
return :fake_change
end
end
def to_s
path
end
end
def mkchange
property = FakeProperty.new :resource => "fakeparent"
property.is = :start
property.should = :finish
property.resource = :parent
change = nil
assert_nothing_raised do
change = Puppet::PropertyChange.new(property, :start)
end
change.transaction = :trans
assert_equal(:start, change.is, "@is did not get copied")
assert_equal(:finish, change.should, "@should did not get copied")
assert_equal(%w{fakechange change}, change.path, "path did not get set correctly")
assert(! change.changed?, "change defaulted to already changed")
return change
end
def test_go
change = mkchange
coll = logcollector()
events = nil
# First make sure we get an immediate return
assert_nothing_raised do
events = change.go
end
assert_instance_of(Array, events, "events were not returned in an array")
assert_instance_of(Puppet::Event, events[0], "event array did not contain events")
event = events.shift
{:event => :fake_change, :transaction => :trans, :source => :parent}.each do |method, val|
assert_equal(val, event.send(method), "Event did not set %s correctly" % method)
end
# Disabled, because it fails when running the whole suite at once.
#assert(coll.detect { |l| l.message == "fake change" }, "Did not log change")
assert_equal(change.property.is, change.property.should, "did not call sync method")
# Now make sure that proxy sources can be set.
assert_nothing_raised do
change.proxy = :other
end
# Reset, so we change again
change.property.is = :start
change.is = :start
assert_nothing_raised do
events = change.go
end
assert_instance_of(Array, events, "events were not returned in an array")
assert_instance_of(Puppet::Event, events[0], "event array did not contain events")
event = events.shift
{:event => :fake_change, :transaction => :trans, :source => :other}.each do |method, val|
assert_equal(val, event.send(method), "Event did not set %s correctly" % method)
end
#assert(coll.detect { |l| l.message == "fake change" }, "Did not log change")
assert_equal(change.property.is, change.property.should, "did not call sync method")
end
# Related to #542. Make sure changes in noop mode produce the :noop event.
def test_noop_event
change = mkchange
assert(! change.skip?, "Change is already being skipped")
Puppet[:noop] = true
change.property.noop = true
assert(change.noop, "did not set noop")
assert(change.skip?, "setting noop did not mark change for skipping")
event = nil
assert_nothing_raised("Could not generate noop event") do
event = change.forward
end
assert_equal(1, event.length, "got wrong number of events")
assert_equal(:noop, event[0].event, "did not generate noop mode when in noop")
end
end

Просмотреть файл

@ -792,7 +792,7 @@ class TestTransactions < Test::Unit::TestCase
def test_proxy_resources
type = mkreducer do
def evaluate
return Puppet::PropertyChange.new(Fakeprop.new(
return Puppet::Transaction::Change.new(Fakeprop.new(
:path => :path, :is => :is, :should => :should, :name => self.name, :resource => "a parent"), :is)
end
end
@ -811,7 +811,7 @@ class TestTransactions < Test::Unit::TestCase
assert(changes.length > 0, "did not get any changes")
changes.each do |change|
assert_equal(resource, change.source, "change did not get proxy set correctly")
assert_equal(resource, change.resource, "change did not get proxy set correctly")
end
end
@ -901,10 +901,9 @@ class TestTransactions < Test::Unit::TestCase
assert(result, "c did not trigger anything")
assert_instance_of(Array, result)
event = result.shift
assert_instance_of(Puppet::Event, event)
assert_equal(:triggered, event.event, "event was not set correctly")
assert_instance_of(Puppet::Transaction::Event, event)
assert_equal(:triggered, event.name, "event was not set correctly")
assert_equal(c, event.source, "source was not set correctly")
assert_equal(trans, event.transaction, "transaction was not set correctly")
assert(trans.triggered?(c, :refresh),
"Transaction did not store the trigger")
@ -991,7 +990,7 @@ class TestTransactions < Test::Unit::TestCase
newparam(:name) {}
newproperty(:testing) do
def sync
self.is = self.should
# noop
:ran_testing
end
end

Просмотреть файл

@ -3,7 +3,6 @@
require File.dirname(__FILE__) + '/../../lib/puppettest'
require 'puppettest'
require 'puppet/type/sshkey'
require 'facter'
class TestSSHKey < Test::Unit::TestCase