summaryrefslogtreecommitdiffstats
path: root/lib/puppet/face/node
diff options
context:
space:
mode:
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..d2852de04
--- /dev/null
+++ b/lib/puppet/face/node/clean.rb
@@ -0,0 +1,154 @@
+Puppet::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
+
+ nodes.each { |node| cleanup(node.downcase, options[:unexport]) }
+ end
+ end
+
+ def cleanup(node, unexport)
+ clean_cert(node)
+ clean_cached_facts(node)
+ clean_cached_node(node)
+ clean_reports(node)
+
+ # This is roughly functional, but seems to introduce order-dependent test
+ # failures; this can be re-added when those issues are resolved.
+ # clean_storeconfigs(node, unexport)
+ end
+
+ # clean signed cert for +host+
+ def clean_cert(node)
+ if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::Face[:ca, :current].revoke(node)
+ Puppet::Face[:ca, :current].destroy(node)
+ Puppet.info "#{node} certificates removed from ca"
+ else
+ Puppet.info "Not managing #{node} certs as this host is not a CA"
+ end
+ end
+
+ # clean facts for +host+
+ def clean_cached_facts(node)
+ Puppet::Node::Facts.indirection.destroy(node)
+ Puppet.info "#{node}'s facts removed"
+ end
+
+ # clean cached node +host+
+ def clean_cached_node(node)
+ Puppet::Node.indirection.destroy(node)
+ Puppet.info "#{node}'s cached node removed"
+ end
+
+ # clean node reports for +host+
+ def clean_reports(node)
+ Puppet::Transaction::Report.indirection.destroy(node)
+ Puppet.info "#{node}'s reports removed"
+ 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 #{node} in storedconfigs."
+ return
+ end
+
+ if do_unexport
+ unexport(rails_node)
+ Puppet.notice "Force #{node}'s exported resources to absent"
+ 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 "#{node} storeconfigs removed"
+ 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("#{resource.name} has been marked as \"absent\"")
+ end
+ end
+ end
+
+ def environment
+ @environment ||= Puppet::Node::Environment.new
+ end
+
+ def type_is_ensurable(resource)
+ if (type = Puppet::Type.type(resource.restype)) && type.validattr?(:ensure)
+ return true
+ else
+ type = environment.known_resource_types.find_definition('', resource.restype)
+ return true if type && type.arguments.keys.include?('ensure')
+ end
+ return false
+ end
+end