/usr/lib/ruby/1.8/mcprovision/runner.rb is in mcollective-server-provisioner 0.0.1~git20110120-0ubuntu5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | module MCProvision
class Runner
attr_reader :config
def initialize(configfile)
@config = MCProvision::Config.new(configfile)
@master = MCProvision::PuppetMaster.new(@config)
@notifier = Notifier.new(@config)
Signal.trap("INT") do
MCProvision.info("Received INT signal, exiting.")
exit!
end
end
def run
begin
MCProvision.info("Starting runner")
loop do
MCProvision.info("Looking for machines to provision")
provisionable = Nodes.new(@config.settings["target"]["agent"], @config.settings["target"]["filter"], @config)
provisionable.nodes.each do |server|
begin
provision(server)
rescue Exception => e
MCProvision.warn("Could not provision node #{server.hostname}: #{e.class}: #{e}")
MCProvision.warn(e.backtrace.join("\n\t")) if @config.settings["loglevel"] == "debug"
end
end
sleep @config.settings["sleeptime"] || 5
end
rescue SignalException => e
rescue Exception => e
MCProvision.warn("Runner failed: #{e.class}: #{e}")
MCProvision.warn(e.backtrace.join("\n\t")) if @config.settings["loglevel"] == "debug"
sleep 2
retry
end
end
# Main provisioner body, does the following:
#
# - Find the node ip address based on target/ipaddress_fact
# - picks a puppet master based on configured criteria
# - determines the ip address of the picked master
# - creates a lock file on the node so no other provisioner threads will interfere with it
# - calls to the set_puppet_hostname action which typically adds 'puppet' to /etc/hosts
# - checks if the node already has a cert
# - if it doesnt
# - clean the cert from all masters
# - instructs the client to do a run which would request the cert
# - signs it on all masters
# - call puppet_bootstrap_stage which could run a small bootstrap environment client
# - call puppet_final_run which would do a normal puppet run, this steps block till completed
# - deletes the lock file
# - sends a notification to administrators
def provision(node)
node_inventory = node.inventory
node_ipaddress_fact = @config.settings["target"]["ipaddress_fact"] || "ipaddress"
master_ipaddress_fact = @config.settings["master"]["ipaddress_fact"] || "ipaddress"
begin
raise "Could not determine node ip address from fact #{node_ipaddress_fact}" unless node_inventory[:facts].include?(node_ipaddress_fact)
rescue StandardError => e
raise "Node didn't reply on allocated time"
end
steps = @config.settings["steps"].keys.select{|s| @config.settings["steps"][s] }
chosen_master, master_inventory = pick_master_from(@config.settings["master"]["criteria"], node_inventory[:facts])
begin
raise "Could not determine master ip address from fact #{master_ipaddress_fact}" unless master_inventory[:facts].include?(master_ipaddress_fact)
rescue StandardError => e
raise "Node didn't reply on allocated time"
end
master_ip = master_inventory[:facts][master_ipaddress_fact]
MCProvision.info("Potential provisioning for #{node.hostname}")
# Only do certificate management if the node is clean and doesnt already have a cert
unless node.has_cert?
MCProvision.info("Provisioning #{node.hostname} / #{node_inventory[:facts][node_ipaddress_fact]} with steps #{steps.join ' '}")
MCProvision.info("Provisioning node against #{chosen_master.hostname} / #{master_ip}")
node.lock if @config.settings["steps"]["lock"]
node.stop_puppet if @config.settings["steps"]["stop_puppet"]
node.set_puppet_host(master_ip) if @config.settings["steps"]["set_puppet_hostname"]
node.clean_cert if @config.settings["steps"]["clean_node_certname"]
@master.clean_cert(node.hostname.downcase) if @config.settings["steps"]["clean_node_certname"]
node.send_csr if @config.settings["steps"]["send_node_csr"]
@master.sign(node.hostname.downcase) if @config.settings["steps"]["sign_node_csr"]
node.cycle_puppet_run if @config.settings["steps"]["cycle_puppet_run"]
node.bootstrap if @config.settings["steps"]["puppet_bootstrap_stage"]
node.run_puppet if @config.settings["steps"]["puppet_final_run"]
node.start_puppet if @config.settings["steps"]["start_puppet"]
node.fact_mod("provision-status","provisioned") if @config.settings["steps"]["set_role_provisioned"]
node.unlock if @config.settings["steps"]["unlock"]
MCProvision.info("Node #{node.hostname} provisioned")
else
MCProvision.info("Node is already provisioned")
end
@notifier.notify("Provisioned #{node.hostname} against #{chosen_master.hostname}", "New Node") if @config.settings["steps"]["notify"]
end
private
# Take an array of facts and the node facts.
# Discovers all masters and go through their inventories
# till we find a match, else return the first one.
def pick_master_from(facts, node)
masters = @master.find_all
chosen_master = masters.first
master_inventories = {}
# build up a list of the master inventories
masters.each do |master|
master_inventories[master.hostname] = master.inventory
end
# For every configured fact
begin
facts.each do |fact|
# Check if the node has it
if node.include?(fact)
# Now check every master
masters.each do |master|
master_facts = master_inventories[master.hostname][:facts]
if master_facts.include?(fact)
# if they match, we have a winner
if master_facts[fact] == node[fact]
MCProvision.info("Picking #{master.hostname} for puppetmaster based on #{fact} == #{node[fact]}")
chosen_master = master
end
end
end
end
end
rescue
end
raise "Could not find any masters" if chosen_master.nil?
return [chosen_master, master_inventories[chosen_master.hostname]]
end
end
end
|