Hi Peter, Would it make sense to have this as a 'clean' argument on a 'puppet node' application?
That is, should 'clean' be a full application by itself, or is it more a sub-command of a 'node' application? Would that work for you? On Jan 10, 2011, at 12:41 PM, Peter Meier wrote: > Here is a changeset that adds a new puppet application to > the puppet application portfolio: puppetcleaner. > > This application removes all traces of a node on the puppetmaster > (including certs, cached facts and nodes, reports, and storedconfig > entries). > > Furthermore it is capable of unexporting exported resources of a > host so that consumers of these resources can remove the exported > resources and we will safely remove the node from our > infrastructure. > > Usage: > puppet clean [-u] <host> [<host2> ...] > > To achieve this we add different destroy methods to the different > parts of the indirector. So for example for yaml indirections we > already offer read access for the yaml, this changeset adds > the destroy handler which only removes the yaml file for > a request. This can be used to remove cached entries. > > This work is based on the initial work of Brice Figureau > <[email protected]> > > Signed-off-by: Peter Meier <[email protected]> > --- > lib/puppet/application/clean.rb | 141 +++++++++++++ > lib/puppet/indirector/report/processor.rb | 43 +++-- > lib/puppet/indirector/yaml.rb | 5 + > lib/puppet/reports/store.rb | 15 ++ > lib/puppet/util/command_line.rb | 3 +- > lib/puppet/util/command_line/clean | 58 ++++++ > spec/unit/application/clean_spec.rb | 270 +++++++++++++++++++++++++ > spec/unit/indirector/report/processor_spec.rb | 31 +++- > spec/unit/indirector/yaml_spec.rb | 18 ++ > 9 files changed, 561 insertions(+), 23 deletions(-) > create mode 100644 lib/puppet/application/clean.rb > create mode 100644 lib/puppet/util/command_line/clean > create mode 100644 spec/unit/application/clean_spec.rb > > diff --git a/lib/puppet/application/clean.rb b/lib/puppet/application/clean.rb > new file mode 100644 > index 0000000..da94f4d > --- /dev/null > +++ b/lib/puppet/application/clean.rb > @@ -0,0 +1,141 @@ > +require 'puppet/application' > + > +class Puppet::Application::Clean < Puppet::Application > + > + should_parse_config > + run_mode :master > + > + attr_reader :nodes > + > + option("--unexport","-u") > + > + def main > + raise "At least one node should be passed" if nodes.empty? > + begin > + nodes.each do |node| > + self.clean_cert(node) > + self.clean_cached_facts(node) > + self.clean_cached_node(node) > + self.clean_reports(node) > + self.clean_storeconfigs(node) > + end > + rescue => detail > + puts detail.backtrace if Puppet[:trace] > + puts detail.to_s > + end > + end > + > + # clean signed cert for +host+ > + def clean_cert(node) > + if Puppet::SSL::Host.ca_location == :local > + ca.apply(:revoke, :to => [node]) > + ca.apply(:destroy, :to => [node]) > + Puppet.info "%s certificates removed from ca" % node > + else > + Puppet.info "Not managing %s certs as this host is not a CA" % node > + end > + end > + > + # clean facts for +host+ > + def clean_cached_facts(node) > + Puppet::Node::Facts.destroy(node) > + Puppet.info "%s's facts removed" % node > + end > + > + # clean cached node +host+ > + def clean_cached_node(node) > + Puppet::Node.destroy(node) > + Puppet.info "%s's cached node removed" % node > + end > + > + # clean node reports for +host+ > + def clean_reports(node) > + Puppet::Transaction::Report.destroy(node) > + Puppet.info "%s's reports removed" % node > + end > + > + # clean store config for +host+ > + def clean_storeconfigs(node) > + return unless Puppet[:storeconfigs] && Puppet.features.rails? > + Puppet::Rails.connect > + unless rails_node = Puppet::Rails::Host.find_by_name(node) > + Puppet.notice "No entries found for %s in storedconfigs." % node > + return > + end > + > + if options[:unexport] > + unexport(rails_node) > + Puppet.notice "Force %s's exported resources to absent" % node > + Puppet.warning "Please wait other host have checked-out their > configuration before finishing clean-up wih:" > + Puppet.warning "$ puppetclean #{node}" > + else > + rails_node.destroy > + Puppet.notice "%s storeconfigs removed" % node > + end > + end > + > + def unexport(node) > + # fetch all exported resource > + query = {:include => {:param_values => :param_name}} > + query[:conditions] = ["exported=? AND host_id=?", true, node.id] > + > + Puppet::Rails::Resource.find(:all, query).each do |resource| > + if type_is_ensurable(resource) > + line = 0 > + param_name = > Puppet::Rails::ParamName.find_or_create_by_name("ensure") > + > + if ensure_param = resource.param_values.find(:first, :conditions => > [ 'param_name_id = ?', param_name.id]) > + line = ensure_param.line.to_i > + Puppet::Rails::ParamValue.delete(ensure_param.id); > + end > + > + # force ensure parameter to "absent" > + resource.param_values.create(:value => "absent", > + :line => line, > + :param_name => param_name) > + Puppet.info("%s has been marked as \"absent\"" % resource.name) > + end > + end > + end > + > + def setup > + super > + Puppet::Util::Log.newdestination(:console) > + > + Puppet.parse_config > + > + if options[:debug] > + Puppet::Util::Log.level = :debug > + elsif options[:verbose] > + Puppet::Util::Log.level = :info > + end > + > + @nodes = command_line.args.collect { |h| h.downcase } > + > + if Puppet::SSL::CertificateAuthority.ca? > + Puppet::SSL::Host.ca_location = :local > + else > + Puppet::SSL::Host.ca_location = :none > + end > + > + Puppet::Node::Facts.terminus_class = :yaml > + Puppet::Node::Facts.cache_class = :yaml > + Puppet::Node.terminus_class = :yaml > + Puppet::Node.cache_class = :yaml > + end > + > + private > + def ca > + @ca ||= Puppet::SSL::CertificateAuthority.instance > + end > + > + def environment > + @environemnt ||= Puppet::Node::Environment.new > + end > + > + def type_is_ensurable(resource) > + (type=Puppet::Type.type(resource.restype)) && type.validattr?(:ensure) > || \ > + (type = > environment.known_resource_types.find_definition('',resource.restype)) && > type.arguments.keys.include?('ensure') > + end > + > +end > \ No newline at end of file > diff --git a/lib/puppet/indirector/report/processor.rb > b/lib/puppet/indirector/report/processor.rb > index 88fe4b4..8fbc4f7 100644 > --- a/lib/puppet/indirector/report/processor.rb > +++ b/lib/puppet/indirector/report/processor.rb > @@ -14,28 +14,28 @@ class Puppet::Transaction::Report::Processor < > Puppet::Indirector::Code > process(request.instance) > end > > + def destroy(request) > + processors do |mod| > + mod.destroy(request.key) if mod.respond_to?(:destroy) > + end > + end > + > private > > # Process the report with each of the configured report types. > # LAK:NOTE This isn't necessarily the best design, but it's backward > # compatible and that's good enough for now. > def process(report) > - return if Puppet[:reports] == "none" > - > - reports.each do |name| > - if mod = Puppet::Reports.report(name) > - # We have to use a dup because we're including a module in the > - # report. > - newrep = report.dup > - begin > - newrep.extend(mod) > - newrep.process > - rescue => detail > - puts detail.backtrace if Puppet[:trace] > - Puppet.err "Report #{name} failed: #{detail}" > - end > - else > - Puppet.warning "No report named '#{name}'" > + processors do |mod| > + # We have to use a dup because we're including a module in the > + # report. > + newrep = report.dup > + begin > + newrep.extend(mod) > + newrep.process > + rescue => detail > + puts detail.backtrace if Puppet[:trace] > + Puppet.err "Report #{name} failed: #{detail}" > end > end > end > @@ -45,4 +45,15 @@ class Puppet::Transaction::Report::Processor < > Puppet::Indirector::Code > # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] > x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/) > end > + > + def processors(&blk) > + return if Puppet[:reports] == "none" > + reports.each do |name| > + if mod = Puppet::Reports.report(name) > + yield(mod) > + else > + Puppet.warning "No report named '#{name}'" > + end > + end > + end > end > diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb > index 23997e9..7b12d25 100644 > --- a/lib/puppet/indirector/yaml.rb > +++ b/lib/puppet/indirector/yaml.rb > @@ -47,6 +47,11 @@ class Puppet::Indirector::Yaml < > Puppet::Indirector::Terminus > File.join(base, self.class.indirection_name.to_s, name.to_s + ext) > end > > + def destroy(request) > + file_path = path(request.key) > + File.unlink(file_path) if File.exists?(file_path) > + end > + > def search(request) > Dir.glob(path(request.key,'')).collect do |file| > YAML.load_file(file) > diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb > index 99a9fc1..bc20773 100644 > --- a/lib/puppet/reports/store.rb > +++ b/lib/puppet/reports/store.rb > @@ -38,5 +38,20 @@ Puppet::Reports.register_report(:store) do > # Only testing cares about the return value > file > end > + > + # removes all reports for a given host > + def self.destroy(host) > + client = host.gsub("..",".") > + dir = File.join(Puppet[:reportdir], client) > + > + if File.exists?(dir) > + Dir.entries(dir).each do |file| > + next if ['.','..'].include?(file) > + file = File.join(dir, file) > + File.unlink(file) if File.file?(file) > + end > + Dir.rmdir(dir) > + end > + end > end > > diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb > index 3562a3d..0535a4b 100644 > --- a/lib/puppet/util/command_line.rb > +++ b/lib/puppet/util/command_line.rb > @@ -2,7 +2,7 @@ module Puppet > module Util > class CommandLine > > - LegacyName = Hash.new{|h,k| k}.update( > + LegacyName = Hash.new{|h,k| k}.update( > { > 'agent' => 'puppetd', > 'cert' => 'puppetca', > @@ -14,6 +14,7 @@ module Puppet > 'resource' => 'ralsh', > 'kick' => 'puppetrun', > 'master' => 'puppetmasterd', > + 'clean' => 'clean', > > }) > > diff --git a/lib/puppet/util/command_line/clean > b/lib/puppet/util/command_line/clean > new file mode 100644 > index 0000000..c32bcfe > --- /dev/null > +++ b/lib/puppet/util/command_line/clean > @@ -0,0 +1,58 @@ > +#!/usr/bin/env ruby > + > +# > +# = Synopsis > +# > +# Fully clean a puppetmaster view of a host > +# > +# = Usage > +# > +# puppet clean [-h|--help] [-d|--debug] [-v|--verbose] [-u|--unexport] host > +# > +# = Description > +# > +# This command cleans everything a puppetmaster knows about a node, including > +# > +# * Signed certificates ($vardir/ssl/ca/signed/node.domain.pem) > +# * Cached facts ($vardir/yaml/facts/node.domain.yaml) > +# * Cached node stuff ($vardir/yaml/node/node.domain.yaml) > +# * Reports ($vardir/reports/node.domain) > +# * Stored configs: it can either remove all data from an host in your > storedconfig > +# database, or with --unexport turn every exported resource supporting > ensure to absent > +# so that any other host checking out their config can remove those exported > configurations. > +# > +# = Options > +# > +# Note that any configuration parameter that's valid in the configuration > file > +# is also a valid long argument. For example, 'ssldir' is a valid > configuration > +# parameter, so you can specify '--ssldir <directory>' as an argument. > +# > +# See the configuration file documentation at > +http://docs.puppetlabs.com/references/latest/configuration.html for > +# the full list of acceptable parameters. A commented list of all > +# configuration options can also be generated by running puppet with > +# '--genconfig'. > +# > +# help: > +# Print this help message. > +# > +# unexport:: > +# Instead of removing all the storedconfig data, it changes all exported > resource's ensure parameter > +# of this host to "absent". Then it is necessary to wait that all other > host have checked out their > +# configuration to run again puppetclean whithout this option to finish > the clean-up. > +# > +# > +# = Example > +# > +# puppeclean some-random-host.reductivelabs.com > +# > +# = Author > +# > +# Brice Figureau / Peter Meier > +# > +# = Copyright > +# > +# Copyright (c) 2005 Puppet Labs, LLC > +# Licensed under the GNU Public License > + > +#Puppet::Application[:clean].run > diff --git a/spec/unit/application/clean_spec.rb > b/spec/unit/application/clean_spec.rb > new file mode 100644 > index 0000000..6de9f37 > --- /dev/null > +++ b/spec/unit/application/clean_spec.rb > @@ -0,0 +1,270 @@ > +#!/usr/bin/env ruby > + > +require File.dirname(__FILE__) + '/../../spec_helper' > + > +require 'puppet/application/clean' > + > +describe Puppet::Application::Clean do > + before :each do > + @clean_app = Puppet::Application[:clean] > + Puppet::Util::Log.stubs(:newdestination) > + Puppet::Util::Log.stubs(:level=) > + end > + > + it "should operate in master run_mode" do > + @clean_app.class.run_mode.name.should equal(:master) > + end > + > + it "should ask Puppet::Application to parse Puppet configuration file" do > + @clean_app.should_parse_config?.should be_true > + end > + > + it "should declare a main command" do > + @clean_app.should respond_to(:main) > + end > + > + describe "when handling options" do > + it "should declare handle_unexport method" do > + @clean_app.should respond_to(:handle_unexport) > + end > + > + it "should store argument value when calling handle_unexport" do > + @clean_app.options.expects(:[]=).with(:unexport, 'arg') > + @clean_app.send(:handle_unexport, 'arg') > + end > + end > + > + describe "during setup" do > + before :each do > + Puppet::Log.stubs(:newdestination) > + Puppet::Log.stubs(:level=) > + Puppet.stubs(:parse_config) > + Puppet::Node::Facts.stubs(:terminus_class=) > + Puppet::Node.stubs(:cache_class=) > + end > + > + it "should set console as the log destination" do > + Puppet::Log.expects(:newdestination).with(:console) > + > + @clean_app.setup > + end > + > + it "should set facts terminus and cache class to yaml" do > + Puppet::Node::Facts.expects(:terminus_class=).with(:yaml) > + Puppet::Node::Facts.expects(:cache_class=).with(:yaml) > + > + @clean_app.setup > + end > + > + it "should set node cache as yaml" do > + Puppet::Node.expects(:terminus_class=).with(:yaml) > + Puppet::Node.expects(:cache_class=).with(:yaml) > + > + @clean_app.setup > + end > + > + it "should handle all other arguments as hostnames" do > + > @clean_app.command_line.stubs(:args).returns(['foo1.example.com','foo2.example.com']) > + @clean_app.setup > + @clean_app.nodes.should == ['foo1.example.com','foo2.example.com'] > + end > + > + it "should manage the certs if the host is a CA" do > + Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true) > + Puppet::SSL::Host.expects(:ca_location=).with(:local) > + @clean_app.setup > + end > + > + it "should not manage the certs if the host is not a CA" do > + Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(false) > + Puppet::SSL::Host.expects(:ca_location=).with(:none) > + @clean_app.setup > + end > + end > + > + describe "when running" do > + > + before :each do > + @host = 'node' > + Puppet.stubs(:info) > + [ "cert", "cached_facts", "cached_node", "reports", "storeconfigs" > ].each do |m| > + @clean_app.stubs("clean_#{m}".to_sym).with(@host) > + end > + @clean_app.stubs(:nodes).returns([...@host]) > + end > + > + it "should raise an error if no host is given" do > + @clean_app.stubs(:nodes).returns([]) > + lambda { @clean_app.main }.should raise_error > + end > + > + [ "cert", "cached_facts", "cached_node", "reports", "storeconfigs" > ].each do |m| > + it "should clean #{m.sub('_',' ')}" do > + @clean_app.expects("clean_#{m}".to_sym).with(@host) > + > + @clean_app.main > + end > + end > + > + end > + > + describe "when cleaning certificate" do > + before :each do > + Puppet::SSL::Host.stubs(:destroy) > + @ca = mock() > + Puppet::SSL::CertificateAuthority.stubs(:instance).returns(@ca) > + end > + > + it "should send the :destroy order to the ca if we are a CA" do > + Puppet::SSL::Host.stubs(:ca_location).returns(:local) > + @ca.expects(:apply).with { |cert_mode,to| cert_mode == :revoke } > + @ca.expects(:apply).with { |cert_mode,to| cert_mode == :destroy } > + > + @clean_app.clean_cert(@host) > + end > + > + it "should not destroy the certs if we are not a CA" do > + Puppet::SSL::Host.stubs(:ca_location).returns(:none) > + @ca.expects(:apply).never > + @clean_app.clean_cert(@host) > + end > + end > + > + describe "when cleaning cached facts" do > + it "should destroy facts" do > + @host = 'node' > + Puppet::Node::Facts.expects(:destroy).with(@host) > + > + @clean_app.clean_cached_facts(@host) > + end > + end > + > + describe "when cleaning cached node" do > + it "should destroy the cached node" do > + Puppet::Node::Yaml.any_instance.expects(:destroy) > + @clean_app.clean_cached_node(@host) > + end > + end > + > + describe "when cleaning archived reports" do > + it "should tell the reports to remove themselves" do > + Puppet::Transaction::Report.stubs(:destroy).with(@host) > + > + @clean_app.clean_reports(@host) > + end > + end > + > + describe "when cleaning storeconfigs entries for host", :if => > Puppet.features.rails? do > + before :each do > + # Stub this so we don't need access to the DB. > + require 'puppet/rails/host' > + > + @clean_app.options.stubs(:[]).with(:unexport).returns(false) > + Puppet.stubs(:[]).with(:storeconfigs).returns(true) > + > + Puppet::Rails.stubs(:connect) > + @rails_node = stub_everything 'rails_node' > + Puppet::Rails::Host.stubs(:find_by_name).returns(@rails_node) > + @clean_app.stubs(:destroy) > + end > + > + it "should connect to the database" do > + Puppet::Rails.expects(:connect) > + @clean_app.clean_storeconfigs(@host) > + end > + > + it "should find the right host entry" do > + > Puppet::Rails::Host.expects(:find_by_name).with(@host).returns(@rails_node) > + > + @clean_app.clean_storeconfigs(@host) > + end > + > + describe "without unexport" do > + it "should remove the host and it's content" do > + @rails_node.expects(:destroy) > + > + @clean_app.clean_storeconfigs(@host) > + end > + end > + > + describe "with unexport" do > + before :each do > + @clean_app.options.stubs(:[]).with(:unexport).returns(true) > + @rails_node.stubs(:id).returns(1234) > + > + @type = stub_everything 'type' > + @type.stubs(:validattr?).with(:ensure).returns(true) > + > + @ensure_name = stub_everything 'ensure_name', :id => 23453 > + > Puppet::Rails::ParamName.stubs(:find_or_create_by_name).returns(@ensure_name) > + > + @param_values = stub_everything 'param_values' > + @resource = stub_everything 'resource', :param_values => > @param_values, :restype => "File" > + Puppet::Rails::Resource.stubs(:find).returns([...@resource]) > + end > + > + it "should find all resources" do > + Puppet::Rails::Resource.expects(:find).with(:all, {:include => > {:param_values => :param_name}, :conditions => ["exported=? AND host_id=?", > true, 1234]}).returns([]) > + > + @clean_app.clean_storeconfigs(@host) > + end > + > + describe "with an exported native type" do > + before :each do > + Puppet::Type.stubs(:type).returns(@type) > + @type.expects(:validattr?).with(:ensure).returns(true) > + end > + > + it "should test a native type for ensure as an attribute" do > + @clean_app.clean_storeconfigs(@host) > + end > + > + it "should delete the old ensure parameter" do > + ensure_param = stub 'ensure_param', :id => 12345, :line => 12 > + @param_values.stubs(:find).returns(ensure_param) > + Puppet::Rails::ParamValue.expects(:delete).with(12345); > + @clean_app.clean_storeconfigs(@host) > + end > + > + it "should add an ensure => absent parameter" do > + @param_values.expects(:create).with(:value => "absent", > + :line => 0, > + :param_name => > @ensure_name) > + @clean_app.clean_storeconfigs(@host) > + end > + end > + > + describe "with an exported definition" do > + it "should try to lookup a definition and test it for the ensure > argument" do > + Puppet::Type.stubs(:type).returns(nil) > + definition = stub_everything 'definition', :arguments => { > 'ensure' => 'present' } > + > Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('',"File").returns(definition) > + @clean_app.clean_storeconfigs(@host) > + end > + end > + > + it "should not unexport the resource of an unkown type" do > + Puppet::Type.stubs(:type).returns(nil) > + > Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('',"File").returns(nil) > + Puppet::Rails::ParamName.expects(:find_or_create_by_name).never > + @clean_app.clean_storeconfigs(@host) > + end > + > + it "should not unexport the resource of a not ensurable native type" do > + Puppet::Type.stubs(:type).returns(@type) > + @type.expects(:validattr?).with(:ensure).returns(false) > + > Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('',"File").returns(nil) > + Puppet::Rails::ParamName.expects(:find_or_create_by_name).never > + @clean_app.clean_storeconfigs(@host) > + end > + > + it "should not unexport the resource of a not ensurable definition" do > + Puppet::Type.stubs(:type).returns(nil) > + definition = stub_everything 'definition', :arguments => { 'foobar' > => 'someValue' } > + > Puppet::Resource::TypeCollection.any_instance.expects(:find_definition).with('',"File").returns(definition) > + Puppet::Rails::ParamName.expects(:find_or_create_by_name).never > + @clean_app.clean_storeconfigs(@host) > + end > + end > + end > +end > diff --git a/spec/unit/indirector/report/processor_spec.rb > b/spec/unit/indirector/report/processor_spec.rb > index 5602a27..76420df 100755 > --- a/spec/unit/indirector/report/processor_spec.rb > +++ b/spec/unit/indirector/report/processor_spec.rb > @@ -15,26 +15,45 @@ describe Puppet::Transaction::Report::Processor do > it "should provide a method for saving reports" do > Puppet::Transaction::Report::Processor.new.should respond_to(:save) > end > + > + it "should provide a method for cleaning reports" do > + Puppet::Transaction::Report::Processor.new.should respond_to(:destroy) > + end > + > end > > -describe Puppet::Transaction::Report::Processor, " when saving a report" do > +describe Puppet::Transaction::Report::Processor, " when processing a report" > do > before do > Puppet.settings.stubs(:use) > @reporter = Puppet::Transaction::Report::Processor.new > + @request = stub 'request', :instance => mock("report"), :key => 'node' > end > > - it "should not process the report if reports are set to 'none'" do > + it "should not save the report if reports are set to 'none'" do > Puppet::Reports.expects(:report).never > Puppet.settings.expects(:value).with(:reports).returns("none") > > - request = stub 'request', :instance => mock("report") > - > - @reporter.save(request) > + @reporter.save(@request) > end > > - it "should process the report with each configured report type" do > + it "should save the report with each configured report type" do > Puppet.settings.stubs(:value).with(:reports).returns("one,two") > @reporter.send(:reports).should == %w{one two} > + > + Puppet::Reports.expects(:report).with('one') > + Puppet::Reports.expects(:report).with('two') > + > + @reporter.save(@request) > + end > + > + it "should destroy reports for each processor that responds to destroy" do > + Puppet.settings.stubs(:value).with(:reports).returns("http,store") > + http_report = mock() > + store_report = mock() > + store_report.expects(:destroy).with(@request.key) > + Puppet::Reports.expects(:report).with('http').returns(http_report) > + Puppet::Reports.expects(:report).with('store').returns(store_report) > + @reporter.destroy(@request) > end > end > > diff --git a/spec/unit/indirector/yaml_spec.rb > b/spec/unit/indirector/yaml_spec.rb > index 86c13c5..e193727 100755 > --- a/spec/unit/indirector/yaml_spec.rb > +++ b/spec/unit/indirector/yaml_spec.rb > @@ -154,5 +154,23 @@ describe Puppet::Indirector::Yaml, " when choosing file > location" do > Dir.expects(:glob).with(:glob).returns [] > @store.search(@request).should == [] > end > + > + describe Puppet::Indirector::Yaml, " when destroying" do > + it "should unlink the right yaml file if it exists" do > + path = File.join("/what/ever", @store.class.indirection_name.to_s, > @request.key.to_s + ".yaml") > + File.expects(:exists?).with(path).returns true > + File.expects(:unlink).with(path) > + > + @store.destroy(@request) > + end > + > + it "should not unlink the yaml file if it does not exists" do > + path = File.join("/what/ever", @store.class.indirection_name.to_s, > @request.key.to_s + ".yaml") > + File.expects(:exists?).with(path).returns false > + File.expects(:unlink).with(path).never > + > + @store.destroy(@request) > + end > + end > end > end > -- > 1.7.3.4 > > -- > You received this message because you are subscribed to the Google Groups > "Puppet Developers" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/puppet-dev?hl=en. > -- Nothing is impossible for the man who doesn't have to do it himself. -- A. H. Weiler --------------------------------------------------------------------- Luke Kanies -|- http://puppetlabs.com -|- +1(615)594-8199 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
