Working #3139 - scheduling moved to resource harness

We previously had the schedule checking code in Puppet::Type,
but it's more of a transactional function, and in order to
do proper auditing in the transactional area, we need the
cache checking done there.  Scheduling is one
of the few functions that actually uses cached data currently.

Signed-off-by: Luke Kanies <luke@puppetlabs.com>
This commit is contained in:
Luke Kanies 2010-06-10 20:31:34 -07:00 коммит произвёл test branch
Родитель 4627b8fe11
Коммит 0b95a8528e
7 изменённых файлов: 161 добавлений и 118 удалений

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

@ -318,12 +318,11 @@ class Puppet::Transaction
# Is the resource currently scheduled?
def scheduled?(resource)
self.ignoreschedules or resource.scheduled?
self.ignoreschedules or resource_harness.scheduled?(resource)
end
# Should this resource be skipped?
def skip?(resource)
skip = false
if missing_tags?(resource)
resource.debug "Not tagged with %s" % tags.join(", ")
elsif ! scheduled?(resource)
@ -356,11 +355,10 @@ class Puppet::Transaction
# Is this resource tagged appropriately?
def missing_tags?(resource)
not appropriately_tagged?(resource)
end
return false if ignore_tags?
return false if tags.empty?
def appropriately_tagged?(resource)
self.ignore_tags? or tags.empty? or resource.tagged?(*tags)
not resource.tagged?(*tags)
end
end

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

@ -73,6 +73,28 @@ class Puppet::Transaction::ResourceHarness
@transaction = transaction
end
def scheduled?(resource)
return true if Puppet[:ignoreschedules]
return true unless schedule = schedule(resource)
# We use 'checked' here instead of 'synced' because otherwise we'll
# end up checking most resources most times, because they will generally
# have been synced a long time ago (e.g., a file only gets updated
# once a month on the server and its schedule is daily; the last sync time
# will have been a month ago, so we'd end up checking every run).
return schedule.match?(resource.cached(:checked).to_i)
end
def schedule(resource)
unless resource.catalog
resource.warning "Cannot schedule without a schedule-containing catalog"
return nil
end
return nil unless name = resource[:schedule]
resource.catalog.resource(:schedule, name) || resource.fail("Could not find schedule #{name}")
end
private
def absent_and_not_being_created?(current, param)

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

@ -1669,45 +1669,6 @@ class Type
end.flatten.reject { |r| r.nil? }
end
###############################
# All of the scheduling code.
# Look up the schedule and set it appropriately. This is done after
# the instantiation phase, so that the schedule can be anywhere in the
# file.
def schedule
unless catalog
warning "Cannot schedule without a schedule-containing catalog"
return nil
end
unless defined? @schedule
if name = self[:schedule]
if sched = catalog.resource(:schedule, name)
@schedule = sched
else
self.fail "Could not find schedule %s" % name
end
else
@schedule = nil
end
end
@schedule
end
# Check whether we are scheduled to run right now or not.
def scheduled?
return true if Puppet[:ignoreschedules]
return true unless schedule = self.schedule
# We use 'checked' here instead of 'synced' because otherwise we'll
# end up checking most resources most times, because they will generally
# have been synced a long time ago (e.g., a file only gets updated
# once a month on the server and its schedule is daily; the last sync time
# will have been a month ago, so we'd end up checking every run).
return schedule.match?(self.cached(:checked).to_i)
end
# Define the initial list of tags.
def tags=(list)
tag(self.class.name)
@ -1895,10 +1856,6 @@ class Type
# Set up all of our autorequires.
def finish
# Scheduling has to be done when the whole config is instantiated, so
# that file order doesn't matter in finding them.
self.schedule
# Make sure all of our relationships are valid. Again, must be done
# when the entire catalog is instantiated.
self.class.relationship_params.collect do |klass|

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

@ -181,8 +181,6 @@ describe Puppet::Transaction do
catalog.apply
FileTest.should be_exists(fname)
exec.should_not be_scheduled
# Now remove it, so it can get created again
File.unlink(fname)
@ -234,4 +232,16 @@ describe Puppet::Transaction do
FileTest.should_not be_exists(file1[:path])
FileTest.should_not be_exists(file2[:path])
end
# #801 -- resources only checked in noop should be rescheduled immediately.
it "should immediately reschedule noop resources" do
Puppet::Type.type(:schedule).mkdefaultschedules
resource = Puppet::Type.type(:notify).new(:name => "mymessage", :noop => true)
catalog = Puppet::Resource::Catalog.new
catalog.add_resource resource
trans = catalog.apply
trans.resource_harness.should be_scheduled(resource)
end
end

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

@ -241,39 +241,84 @@ describe Puppet::Transaction do
describe "when skipping a resource" do
before :each do
@resource = stub_everything 'res'
@resource = Puppet::Type.type(:notify).new :name => "foo"
@catalog = Puppet::Resource::Catalog.new
@resource.catalog = @catalog
@transaction = Puppet::Transaction.new(@catalog)
end
it "should skip resource with missing tags" do
@transaction.stubs(:missing_tags?).returns(true)
@transaction.skip?(@resource).should be_true
@transaction.should be_skip(@resource)
end
it "should ask the resource if it's tagged with any of the tags" do
tags = ['one', 'two']
@transaction.stubs(:ignore_tags?).returns(false)
@transaction.stubs(:tags).returns(tags)
@resource.expects(:tagged?).with(*tags).returns(true)
@transaction.missing_tags?(@resource).should be_false
end
it "should skip not scheduled resources" do
it "should skip unscheduled resources" do
@transaction.stubs(:scheduled?).returns(false)
@transaction.skip?(@resource).should be_true
@transaction.should be_skip(@resource)
end
it "should skip resources with failed dependencies" do
@transaction.stubs(:failed_dependencies?).returns(false)
@transaction.skip?(@resource).should be_true
@transaction.stubs(:failed_dependencies?).returns(true)
@transaction.should be_skip(@resource)
end
it "should skip virtual resource" do
@resource.stubs(:virtual?).returns true
@transaction.skip?(@resource).should be_true
@transaction.should be_skip(@resource)
end
end
describe "when determining if tags are missing" do
before :each do
@resource = Puppet::Type.type(:notify).new :name => "foo"
@catalog = Puppet::Resource::Catalog.new
@resource.catalog = @catalog
@transaction = Puppet::Transaction.new(@catalog)
@transaction.stubs(:ignore_tags?).returns false
end
it "should not be missing tags if tags are being ignored" do
@transaction.expects(:ignore_tags?).returns true
@resource.expects(:tagged?).never
@transaction.should_not be_missing_tags(@resource)
end
it "should not be missing tags if the transaction tags are empty" do
@transaction.tags = []
@resource.expects(:tagged?).never
@transaction.should_not be_missing_tags(@resource)
end
it "should otherwise let the resource determine if it is missing tags" do
tags = ['one', 'two']
@transaction.tags = tags
@resource.expects(:tagged?).with(*tags).returns(false)
@transaction.should be_missing_tags(@resource)
end
end
describe "when determining if a resource should be scheduled" do
before :each do
@resource = Puppet::Type.type(:notify).new :name => "foo"
@catalog = Puppet::Resource::Catalog.new
@resource.catalog = @catalog
@transaction = Puppet::Transaction.new(@catalog)
end
it "should always schedule resources if 'ignoreschedules' is set" do
@transaction.ignoreschedules = true
@transaction.resource_harness.expects(:scheduled?).never
@transaction.should be_scheduled(@resource)
end
it "should let the resource harness determine whether the resource should be scheduled" do
@transaction.resource_harness.expects(:scheduled?).with(@resource).returns "feh"
@transaction.scheduled?(@resource).should == "feh"
end
end

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

@ -265,4 +265,65 @@ describe Puppet::Transaction::ResourceHarness do
@harness.should_not be_allow_changes(@resource)
end
end
describe "when finding the schedule" do
before do
@catalog = Puppet::Resource::Catalog.new
@resource.catalog = @catalog
end
it "should warn and return nil if the resource has no catalog" do
@resource.catalog = nil
@resource.expects(:warning)
@harness.schedule(@resource).should be_nil
end
it "should return nil if the resource specifies no schedule" do
@harness.schedule(@resource).should be_nil
end
it "should fail if the named schedule cannot be found" do
@resource[:schedule] = "whatever"
@resource.expects(:fail)
@harness.schedule(@resource)
end
it "should return the named schedule if it exists" do
sched = Puppet::Type.type(:schedule).new(:name => "sched")
@catalog.add_resource(sched)
@resource[:schedule] = "sched"
@harness.schedule(@resource).to_s.should == sched.to_s
end
end
describe "when determining if a resource is scheduled" do
before do
@catalog = Puppet::Resource::Catalog.new
@resource.catalog = @catalog
end
it "should return true if 'ignoreschedules' is set" do
Puppet[:ignoreschedules] = true
@resource[:schedule] = "meh"
@harness.should be_scheduled(@resource)
end
it "should return true if the resource has no schedule set" do
@harness.should be_scheduled(@resource)
end
it "should return the result of matching the schedule with the cached 'checked' time if a schedule is set" do
t = Time.now
@resource.expects(:cached).with(:checked).returns(t)
sched = Puppet::Type.type(:schedule).new(:name => "sched")
@catalog.add_resource(sched)
@resource[:schedule] = "sched"
sched.expects(:match?).with(t.to_i).returns "feh"
@harness.scheduled?(@resource).should == "feh"
end
end
end

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

@ -315,54 +315,4 @@ class TestType < Test::Unit::TestCase
exec = Puppet::Type.newexec(:title => "yay", :command => "/bin/echo yay")
assert_equal("Exec[yay]", exec.ref)
end
# Partially test #704, but also cover the rest of the schedule management bases.
def test_schedule
schedule = Puppet::Type.type(:schedule).new(:name => "maint")
catalog = mk_catalog(schedule)
{"maint" => true, nil => false, :fail => :fail}.each do |name, should|
args = {:name => tempfile, :ensure => :file}
if name
args[:schedule] = name
end
resource = Puppet::Type.type(:file).new(args)
catalog.add_resource(resource)
if should == :fail
assert_raise(Puppet::Error, "Did not fail on missing schedule") do
resource.schedule
end
elsif should == false
assert_nil(resource.schedule, "Set the schedule tho it is set to nil")
else
sched = nil
assert_nothing_raised("Failed when schedule was %s" % sched) do
sched = resource.schedule
end
assert(sched, "Did not find schedule %s" % sched.inspect)
if should
assert_equal(name, sched.name, "did not get correct schedule back")
end
end
catalog.remove_resource(resource)
end
end
# #801 -- resources only checked in noop should be rescheduled immediately.
def test_reschedule_when_noop
Puppet::Type.type(:schedule).mkdefaultschedules
file = Puppet::Type.type(:file).new(:path => "/tmp/whatever", :mode => "755", :noop => true, :schedule => :daily, :ensure => :file)
catalog = Puppet::Resource::Catalog.new
catalog.add_resource
assert(file.noop?, "File not considered in noop")
assert(file.scheduled?, "File is not considered scheduled")
catalog.apply
assert(file.scheduled?, "File is not considered scheduled even though only a noop run was made")
end
end