summaryrefslogtreecommitdiffstats
path: root/lib/puppet/face/node
diff options
context:
space:
mode:
authorPeter Meier <peter.meier@immerda.ch>2011-04-29 15:56:15 +0200
committerPieter van de Bruggen <pieter@puppetlabs.com>2011-07-27 14:20:42 -0700
commitc315da0efeace1878a877dc4b2f4aebc1ec13f0d (patch)
tree1d3faf4e63d214c5ed10a48629acb1437ac93e71 /lib/puppet/face/node
parent5682125e1800f4c7b69b20fdd28f97a473d5d93c (diff)
downloadpuppet-c315da0efeace1878a877dc4b2f4aebc1ec13f0d.tar.gz
puppet-c315da0efeace1878a877dc4b2f4aebc1ec13f0d.tar.xz
puppet-c315da0efeace1878a877dc4b2f4aebc1ec13f0d.zip
Fix #1886 - Add node cleanup capability
Here is a changeset that adds a new action to the puppet node face. 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 node clean [--unexport] <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 <brice-puppet@daysofwonder.com>
Diffstat (limited to 'lib/puppet/face/node')
-rw-r--r--lib/puppet/face/node/clean.rb154
1 files changed, 154 insertions, 0 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