Created
July 22, 2012 17:14
-
-
Save marthag/3160342 to your computer and use it in GitHub Desktop.
Zone creation script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
%w(erb git net/ssh resolv chef chef/knife/cookbook_upload chef/cookbook_uploader chef/knife/node_run_list_add chef/knife/bootstrap net/ssh/multi chef/knife/core/bootstrap_context chef/knife/ssh mixlib/cli).each do |gem| | |
begin | |
require gem | |
rescue LoadError | |
raise "Could not load gem #{gem}, please install with sudo gem install #{gem}" | |
end | |
end | |
# setup the command line options | |
class MyCLI | |
include Mixlib::CLI | |
option :debug, | |
:short => "-d", | |
:long => "--debug", | |
:description => "Turn on debugging messages", | |
:boolean => true, | |
:default => false | |
option :git, | |
:short => "-t", | |
:long => "--git", | |
:description => "Add/commit/push new recipes to git", | |
:boolean => true, | |
:default => false | |
option :global, | |
:short => "-g GLOBAL", | |
:long => "--global GLOBAL", | |
:description => "The FQDN of the server to create the zone on", | |
:required => true | |
option :help, | |
:short => "-h", | |
:long => "--help", | |
:description => "Show this message", | |
:on => :tail, | |
:boolean => true, | |
:show_options => true, | |
:exit => 0 | |
option :knife_config, | |
:short => "-c KNIFE_CONFIG", | |
:long => "--config KNIFE_CONFIG", | |
:description => "Knife configuration file (defaults to ~/.chef/knife.rb)", | |
:default => "~/.chef/knife.rb" | |
option :net, | |
:short => "-n NET", | |
:long => "--net NET", | |
:description => "Network information for the new zone, in the form: ipaddress[/cidr]:interface", | |
:required => true | |
option :run_list, | |
:short => "-r", | |
:long => "--run_list RUN_LIST", | |
:description => "Specify the run_list for the new zone", | |
:default => "" | |
option :ssh_password, | |
:short => "-s SSH_PASSWORD", | |
:long => "--password SSH_PASSWORD", | |
:description => "SSH password to use", | |
:required => true | |
option :ssh_port, | |
:short => "-P SSH_PORT", | |
:long => "--port SSH_PORT", | |
:description => "SSH port to use (defaults to 22)", | |
:default => 22 | |
option :zone, | |
:short => "-z ZONE", | |
:long => "--zone ZONE", | |
:description => "The hostname of the new zone", | |
:required => true | |
option :zpool, | |
:short => "-p ZPOOL", | |
:long => "--zpool ZPOOL", | |
:description => "Name of the zpool to use (defaults to rpool)", | |
:default => "rpool" | |
end | |
# parse the command line options | |
cli = MyCLI.new | |
cli.parse_options | |
debug = cli.config[:debug] | |
zone_hostname = cli.config[:zone] | |
net = cli.config[:net] | |
global = cli.config[:global] | |
zpool = cli.config[:zpool] | |
run_list = cli.config[:run_list] | |
use_git = cli.config[:git] | |
ssh_password = cli.config[:ssh_password] | |
ssh_port = cli.config[:ssh_port] | |
knife_rb = File.expand_path(cli.config[:knife_config]) | |
if debug | |
p cli.config | |
end | |
crypted_password = ssh_password.crypt("wh") | |
zone_ip = net.split(/\/|:/)[0] | |
if debug | |
puts "Zone ip is " + zone_ip | |
end | |
# set the FQDN | |
zone_name_array = global.split('.') | |
zone_fqdn = zone_hostname + '.' + zone_name_array[1..-1].join('.') | |
# check if the zone name resolves | |
no_dns = false | |
begin | |
Resolv.getaddress(zone_fqdn) | |
rescue Exception => e | |
no_dns = true | |
puts "Warning: #{zone_fqdn} does not resolve, please add to DNS!" | |
end | |
if debug | |
puts "Zpool is " + zpool | |
end | |
# load the user's knife.rb | |
Chef::Config.from_file(knife_rb) | |
#server_url = Chef::Config[:server_url] | |
cookbook_path = Chef::Config[:cookbook_path][0] | |
if debug | |
puts "Putting recipes in " + cookbook_path | |
# puts "Server URL is " + server_url | |
end | |
# setup the recipe templates | |
def write_template(template,file) | |
File.open(file, "w") do |f| | |
f.write(template.result) | |
end | |
end | |
template = ERB.new <<-EOF | |
zfs "<%= zpool %>/<%= zone_hostname %>" | |
directory "/<%= zpool %>/<%= zone_hostname %>" do | |
mode "0700" | |
end | |
zone "<%= zone_hostname %>" do | |
path "/<%= zpool %>/<%= zone_hostname %>" | |
password "<%= crypted_password %>" | |
nets [ "<%= net %>" ] | |
<% if no_dns %> sysidcfg_template "sysidcfg_nodns.erb"<% end %> | |
end | |
EOF | |
# write the recipe files | |
print "Creating new recipes..." | |
write_template(template, File.expand_path("#{cookbook_path}/zone/recipes/#{zone_hostname}.rb")) | |
puts "done." | |
# add the recipes you created to git | |
if use_git | |
print "Adding new recipes to git..." | |
g = Git.open(chef_path) #, :log => Logger.new(STDOUT)) | |
g.add("#{cookbook_path}/zone/recipes/#{zone_hostname}.rb") | |
# don't fail if recipes haven't changed | |
begin | |
g.commit("adding zone #{zone_hostname}") | |
rescue | |
end | |
# don't fail if push fails | |
begin | |
g.push | |
rescue | |
end | |
puts "done." | |
end | |
# upload the new cookbook | |
begin | |
puts "Uploading zone cookbook..." | |
ck = Chef::Knife::CookbookUpload.new(["zone"]) | |
ck.read_config_file(knife_rb) | |
ck.run | |
puts "done." | |
rescue Exception => e | |
raise "Uploading zone cookbook failed: " + e.message | |
end | |
# add the new recipe to the global node | |
global_node=Chef::Node.load(global) | |
if debug | |
puts global_node.recipes | |
end | |
unless global_node.recipe?("zone::#{zone_hostname}") | |
begin | |
print "Adding new recipe zone::#{zone_hostname} to #{global}..." | |
gn=Chef::Knife::NodeRunListAdd.new([global, "recipe[zone::#{zone_hostname}]"]) | |
gn.read_config_file(knife_rb) | |
gn.run | |
rescue Exception => e | |
raise "Adding new recipe zone::#{zone_hostname} to #{global} failed: " + e.message | |
end | |
puts "done." | |
end | |
# run chef-client on the global zone to create the new zone | |
exit_code = 0 | |
begin | |
puts "Running chef-client on #{global}..." | |
Net::SSH.start(global, "root", :port => ssh_port, :password => ssh_password ) do |session| | |
channel = session.open_channel do |chan| | |
chan.request_pty | |
chan.exec("chef-client -l warn") do |ch, success| | |
raise "chef-client run failed." unless success | |
chan.on_request('exit-status') do |ch, data| | |
exit_code += data.read_long | |
if debug | |
puts("ssh exec exit-status: #{exit_code}") | |
end | |
if exit_code != 0 | |
raise "chef-client run failed, zone was not created!" | |
end | |
end | |
ch.on_data do |c, data| | |
print data | |
end | |
ch.on_close { puts "done." } | |
end | |
end | |
channel.wait | |
end | |
rescue Exception => e | |
raise "SSH to #{global} failed: " + e.message | |
end | |
# wait for boot to finish | |
begin | |
Net::SSH.start(zone_ip, "root", :port => ssh_port, :password => ssh_password ) do |session| | |
end | |
rescue Exception => e | |
print "Waiting for zone to finish booting..." | |
sleep 90 | |
puts "done." | |
end | |
if no_dns | |
begin | |
Net::SSH.start(global, "root", :port => ssh_port, :password => ssh_password ) do |session| | |
session.exec!("cp /etc/resolv.conf /#{zpool}/#{zone_hostname}/root/etc/ ;cp /etc/nsswitch.conf /#{zpool}/#{zone_hostname}/root/etc/") | |
end | |
rescue Exception => e | |
raise "SSH to #{global} failed: " + e.message | |
end | |
end | |
begin | |
print "Bootstrapping #{zone_fqdn} with roles #{run_list}..." | |
bs=Chef::Knife::Bootstrap.new(["-d", "solaris", "-r", run_list, "-p", ssh_port, "-P", ssh_password, "--no-host-key-verify", zone_ip]) | |
bs.read_config_file(knife_rb) | |
bs.run | |
puts "done." | |
rescue Exception => e | |
raise "Bootstrap of #{zone_fqdn} failed: " + e.message | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment