summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/face/node/clean.rb154
-rw-r--r--lib/puppet/indirector/report/processor.rb45
-rw-r--r--lib/puppet/indirector/yaml.rb5
-rw-r--r--lib/puppet/reports/store.rb15
4 files changed, 202 insertions, 17 deletions
diff --git a/lib/puppet/face/node/clean.rb b/lib/puppet/face/node/clean.rb
new file mode 100644
index 000000000..10d6239ba
--- /dev/null
+++ b/lib/puppet/face/node/clean.rb
@@ -0,0 +1,154 @@
+Puppet::Indirector::Face.define(:node, '0.0.1') do
+ action(:clean) do
+ option "--[no-]unexport" do
+ summary "Unexport exported resources"
+ end
+
+ summary "Clean up everything a puppetmaster knows about a node"
+
+ arguments "<host1> [<host2> ...]"
+
+ description <<-EOT
+This includes
+
+ * 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.
+
+This will unexport 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.
+EOT
+ when_invoked do |*args|
+ nodes = args[0..-2]
+ options = args.last
+ raise "At least one node should be passed" if nodes.empty? || nodes == options
+
+ # TODO: this is a hack and should be removed if faces provide the proper
+ # infrastructure to set the run mode.
+ require 'puppet/util/run_mode'
+ $puppet_application_mode = Puppet::Util::RunMode[:master]
+
+ if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::SSL::Host.ca_location = :local
+ else
+ Puppet::SSL::Host.ca_location = :none
+ end
+
+ Puppet::Node::Facts.indirection.terminus_class = :yaml
+ Puppet::Node::Facts.indirection.cache_class = :yaml
+ Puppet::Node.indirection.terminus_class = :yaml
+ Puppet::Node.indirection.cache_class = :yaml
+
+ begin
+ nodes.each do |node|
+ node = node.downcase
+ clean_cert(node)
+ clean_cached_facts(node)
+ clean_cached_node(node)
+ clean_reports(node)
+ clean_storeconfigs(node,options[:unexport])
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ puts detail.to_s
+ end
+ 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.indirection.destroy(node)
+ Puppet.info "%s's facts removed" % node
+ end
+
+ # clean cached node +host+
+ def clean_cached_node(node)
+ Puppet::Node.indirection.destroy(node)
+ Puppet.info "%s's cached node removed" % node
+ end
+
+ # clean node reports for +host+
+ def clean_reports(node)
+ Puppet::Transaction::Report.indirection.destroy(node)
+ Puppet.info "%s's reports removed" % node
+ end
+
+ # clean storeconfig for +node+
+ def clean_storeconfigs(node,do_unexport=false)
+ return unless Puppet[:storeconfigs] && Puppet.features.rails?
+ require 'puppet/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 do_unexport
+ unexport(rails_node)
+ Puppet.notice "Force %s's exported resources to absent" % node
+ Puppet.warning "Please wait until all other hosts have checked out their configuration before finishing the cleanup with:"
+ Puppet.warning "$ puppet node clean #{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 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 81b379eb8..7bdadcb36 100644
--- a/lib/puppet/indirector/report/processor.rb
+++ b/lib/puppet/indirector/report/processor.rb
@@ -14,6 +14,12 @@ 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.
@@ -21,23 +27,17 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
# compatible and that's good enough for now.
def process(report)
Puppet.debug "Recieved report to process from #{report.host}"
- return if Puppet[:reports] == "none"
-
- reports.each do |name|
- Puppet.debug "Processing report from #{report.host} with processor #{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|
+ Puppet.debug "Processing report from #{report.host} with processor #{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
@@ -47,4 +47,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 23997e97a..7b12d25e2 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 625a263b3..997206ec4 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -41,5 +41,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