summaryrefslogtreecommitdiffstats
path: root/lib/puppet/application/kick.rb
diff options
context:
space:
mode:
authorJesse Wolfe <jes5199@gmail.com>2010-04-20 16:23:03 -0700
committertest branch <puppet-dev@googlegroups.com>2010-02-17 06:50:53 -0800
commitc79b2282ab0af181d354cfbae7d0b8da964cc03c (patch)
treed1bff1cff829566a07b896863fc62a053ae4c4f7 /lib/puppet/application/kick.rb
parent6bdda8c65e55fcdab896cee9985bca3593c66c95 (diff)
downloadpuppet-c79b2282ab0af181d354cfbae7d0b8da964cc03c.tar.gz
puppet-c79b2282ab0af181d354cfbae7d0b8da964cc03c.tar.xz
puppet-c79b2282ab0af181d354cfbae7d0b8da964cc03c.zip
feature #2276 Single Executable: "puppet kick"
Add "puppet kick" as the new invocation of "puppetrun" Signed-off-by: Jesse Wolfe <jes5199@gmail.com>
Diffstat (limited to 'lib/puppet/application/kick.rb')
-rw-r--r--lib/puppet/application/kick.rb214
1 files changed, 214 insertions, 0 deletions
diff --git a/lib/puppet/application/kick.rb b/lib/puppet/application/kick.rb
new file mode 100644
index 000000000..7b4993bb4
--- /dev/null
+++ b/lib/puppet/application/kick.rb
@@ -0,0 +1,214 @@
+require 'puppet'
+require 'puppet/application'
+
+Puppet.warning "RubyGems not installed" unless Puppet.features.rubygems?
+Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
+
+Puppet::Application.new(:kick) do
+
+ should_not_parse_config
+
+ attr_accessor :hosts, :tags, :classes
+
+ option("--all","-a")
+ option("--foreground","-f")
+ option("--debug","-d")
+ option("--ping","-P")
+ option("--test")
+
+ option("--host HOST") do |arg|
+ @hosts << arg
+ end
+
+ option("--tag TAG", "-t") do |arg|
+ @tags << arg
+ end
+
+ option("--class CLASS", "-c") do |arg|
+ @classes << arg
+ end
+
+ option("--no-fqdn", "-n") do |arg|
+ options[:fqdn] = false
+ end
+
+ option("--parallel PARALLEL", "-p") do |arg|
+ begin
+ options[:parallel] = Integer(arg)
+ rescue
+ $stderr.puts "Could not convert %s to an integer" % arg.inspect
+ exit(23)
+ end
+ end
+
+
+ dispatch do
+ options[:test] ? :test : :main
+ end
+
+ command(:test) do
+ puts "Skipping execution in test mode"
+ exit(0)
+ end
+
+ command(:main) do
+ require 'puppet/network/client'
+ require 'puppet/util/ldap/connection'
+
+ todo = @hosts.dup
+
+ failures = []
+
+ # Now do the actual work
+ go = true
+ while go
+ # If we don't have enough children in process and we still have hosts left to
+ # do, then do the next host.
+ if @children.length < options[:parallel] and ! todo.empty?
+ host = todo.shift
+ pid = fork do
+ run_for_host(host)
+ end
+ @children[pid] = host
+ else
+ # Else, see if we can reap a process.
+ begin
+ pid = Process.wait
+
+ if host = @children[pid]
+ # Remove our host from the list of children, so the parallelization
+ # continues working.
+ @children.delete(pid)
+ if $?.exitstatus != 0
+ failures << host
+ end
+ print "%s finished with exit code %s\n" % [host, $?.exitstatus]
+ else
+ $stderr.puts "Could not find host for PID %s with status %s" %
+ [pid, $?.exitstatus]
+ end
+ rescue Errno::ECHILD
+ # There are no children left, so just exit unless there are still
+ # children left to do.
+ next unless todo.empty?
+
+ if failures.empty?
+ puts "Finished"
+ exit(0)
+ else
+ puts "Failed: %s" % failures.join(", ")
+ exit(3)
+ end
+ end
+ end
+ end
+ end
+
+ def run_for_host(host)
+ if options[:ping]
+ out = %x{ping -c 1 #{host}}
+ unless $? == 0
+ $stderr.print "Could not contact %s\n" % host
+ next
+ end
+ end
+
+ require 'puppet/run'
+ Puppet::Run.indirection.terminus_class = :rest
+ port = Puppet[:puppetport]
+ url = ["https://#{host}:#{port}", "production", "run", host].join('/')
+
+ print "Triggering %s\n" % host
+ begin
+ run_options = {
+ :tags => @tags,
+ :background => ! options[:foreground],
+ :ignoreschedules => options[:ignoreschedules]
+ }
+ run = Puppet::Run.new( run_options ).save( url )
+ puts "Getting status"
+ result = run.status
+ puts "status is #{result}"
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts "Host %s failed: %s\n" % [host, detail]
+ exit(2)
+ end
+
+ case result
+ when "success";
+ exit(0)
+ when "running"
+ $stderr.puts "Host %s is already running" % host
+ exit(3)
+ else
+ $stderr.puts "Host %s returned unknown answer '%s'" % [host, result]
+ exit(12)
+ end
+ end
+
+ preinit do
+ [:INT, :TERM].each do |signal|
+ trap(signal) do
+ $stderr.puts "Cancelling"
+ exit(1)
+ end
+ end
+ options[:parallel] = 1
+ options[:verbose] = true
+ options[:fqdn] = true
+ options[:ignoreschedules] = false
+ options[:foreground] = false
+
+ @hosts = []
+ @classes = []
+ @tags = []
+ end
+
+ setup do
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
+
+ # Now parse the config
+ Puppet.parse_config
+
+ if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes)
+ if options[:all]
+ @hosts = Puppet::Node.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name }
+ puts "all: %s" % @hosts.join(", ")
+ else
+ @hosts = []
+ @classes.each do |klass|
+ list = Puppet::Node.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name }
+ puts "%s: %s" % [klass, list.join(", ")]
+
+ @hosts += list
+ end
+ end
+ elsif ! @classes.empty?
+ $stderr.puts "You must be using LDAP to specify host classes"
+ exit(24)
+ end
+
+ @children = {}
+
+ # If we get a signal, then kill all of our children and get out.
+ [:INT, :TERM].each do |signal|
+ trap(signal) do
+ Puppet.notice "Caught #{signal}; shutting down"
+ @children.each do |pid, host|
+ Process.kill("INT", pid)
+ end
+
+ waitall
+
+ exit(1)
+ end
+ end
+
+ end
+
+end