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.

Reply via email to