From 27c9ad8299473bc0cef633beddc5258e6159fa8c Mon Sep 17 00:00:00 2001 From: Tony Spataro Date: Mon, 19 Sep 2011 14:56:33 -0700 Subject: [PATCH] Fix minor bug in Rakefile; finishing touches for system configurator. --- Rakefile | 2 +- bin/setup.sh | 2 +- bin/system.rb | 4 -- scripts/system_configurator.rb | 119 ++++++++++++++++++++------------- 4 files changed, 74 insertions(+), 53 deletions(-) diff --git a/Rakefile b/Rakefile index cca3b57a..d41cfa42 100644 --- a/Rakefile +++ b/Rakefile @@ -10,7 +10,7 @@ require 'spec/rake/spectask' # Project-specific dependencies RIGHT_LINK_ROOT = File.dirname(__FILE__) -require File.expand_path(RIGHT_LINK_ROOT, 'lib', 'run_shell')) +require File.join(RIGHT_LINK_ROOT, 'lib', 'run_shell') include RunShell diff --git a/bin/setup.sh b/bin/setup.sh index a2587273..edd8b746 100755 --- a/bin/setup.sh +++ b/bin/setup.sh @@ -200,4 +200,4 @@ echo install_public_wrappers || exit 1 echo install_private_wrappers || true -exit 0 \ No newline at end of file +exit 0 diff --git a/bin/system.rb b/bin/system.rb index 3b142250..5f922268 100644 --- a/bin/system.rb +++ b/bin/system.rb @@ -15,8 +15,4 @@ $:.push(File.join(File.dirname(__FILE__), '..', 'scripts')) require 'system_configurator' -# Cloud meta-data -require '/var/spool/cloud/meta-data-cache' if File.exists?('/var/spool/cloud/meta-data-cache') -require '/var/spool/cloud/user-data.rb' if File.exists?('/var/spool/cloud/user-data.rb') - Kernel.exit RightScale::SystemConfigurator.run diff --git a/scripts/system_configurator.rb b/scripts/system_configurator.rb index cf309e31..3a9dca10 100644 --- a/scripts/system_configurator.rb +++ b/scripts/system_configurator.rb @@ -4,12 +4,12 @@ # This utility performs miscellaneous system configuration tasks. # # === Examples: -# config hostname -# config ssh -# config proxy +# config --action=hostname +# config --action=ssh +# config --action=proxy # # === Usage -# config [options] +# config --action= [options] # # Options: # --help: Display help @@ -20,11 +20,18 @@ require 'right_agent/scripts/usage' require 'right_agent/scripts/common_parser' +cloud_dir = File.join(RightScale::Platform.filesystem.spool_dir, 'cloud') + begin - require '/var/spool/cloud/meta-data-cache' - require '/var/spool/cloud/user-data' + require File.join(cloud_dir, 'meta-data-cache') rescue LoadError => e + puts "No cloud metadata is available on this machine - some modules may not work correctly!" +end +begin + require File.join(cloud_dir, 'user-data') +rescue LoadError => e + puts "No cloud user-data is available on this machine - some modules may not work correctly!" end module RightScale @@ -60,12 +67,17 @@ def self.run if options[:action] actions = [ options[:action] ] else - actions = all_actions + actions = [] + end + + if actions.empty? + raise StandardError, "No action specified; try --help" end actions.each do |action| method_name = "configure_#{action}".to_sym if action && configurator.respond_to?(method_name) + puts "Configuring #{action}" configurator.__send__(method_name) else raise StandardError, "Unknown action #{action}" @@ -137,19 +149,16 @@ def configure_ssh def configure_hostname return 0 unless Platform.linux? - begin - hostname = Socket.gethostname - hostname_f = Socket.gethostbyname(hostname) - rescue Exception => e - #TO DISCUSS: this block - end + hostname = Socket.gethostname + hostname_f = Socket.gethostbyname(hostname)[0] rescue nil + # If hostname is already fully-qualified, then do nothing - if hostname_f[0].include?('.') - puts "Hostname (#{hostname_f[0]}) is a well-formed and valid FQDN." + if hostname_f && hostname_f.include?('.') + puts "Hostname (#{hostname_f.inspect}) is a well-formed and valid FQDN." else - puts "Hostname (#{hostname_f[0]}) looks suspect; changing it" - my_fqdn, my_addr = retrieve_cloud_hostname_and_local_ip(hostname_f[0]) - add_new_host_record(my_fqdn,my_addr) + puts "Hostname (#{hostname_f.inspect}) looks suspect; changing it" + my_fqdn, my_addr = retrieve_cloud_hostname_and_local_ip + add_new_host_record(my_fqdn, my_addr) end end @@ -207,19 +216,46 @@ def restart_sshd runshell("/etc/init.d/#{sshd_name} restart") end - def retrieve_cloud_hostname_and_local_ip(hostname) - rs_cloud = get_cloud_type + def retrieve_cloud_hostname_and_local_ip + # Cloud-specific case: query EC2/Eucalyptus metadata to learn local + # hostname and local public IP address + if Platform.ec2? || Platform.eucalyptus? + my_fqdn = ENV['EC2_LOCAL_HOSTNAME'] + my_addr = ENV['EC2_PUBLIC_IPV4'] + + # Some clouds are buggy and report an IP address as EC2_LOCAL_HOSTNAME. + # An IP address is not a valid hostname! In this case we must transform + # it to a valid hostname using the form ip-x-y-z-w where x,y,z,w are + # the decimal octets of the IP address x.y.z.w + if my_fqdn =~ /[0-9.]+/ + components = my_fqdn.split('.') + my_fqdn = "ip-#{components.join('-')}.internal" + end + end - case rs_cloud - when 'ec2' - my_fqdn = ENV['EC2_LOCAL_HOSTNAME'] - my_addr = ENV['EC2_PUBLIC_IPV4'] - when 'eucalyptus' - #my_fqdn = "ip-" + name.gsub(".","-") if my_fqdn.include?('.') - else - my_fqdn = "#{hostname}.localdomain" - my_addr = IPSocket.getaddress(hostname) + # Generic case: use existing hostname and append fake "internal" suffix + unless my_fqdn + my_fqdn ||= "#{Socket.gethostname}.internal" + end + + unless my_addr + bdns, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true + begin + # Generic case: create a UDP "connection" to our hostname + # and look at socket data to determine local IP address. + my_addr = UDPSocket.open do |socket| + socket.connect(Socket.gethostname, 8000) + socket.addr.last + end + rescue Exception => e + # Absolute last-ditch effort: use localhost IP. + # Not ideal, but at least it works... + my_addr = '127.0.0.1' + ensure + Socket.do_not_reverse_lookup = bdns + end end + [ my_fqdn, my_addr ] end @@ -242,17 +278,15 @@ def add_new_host_record(my_fqdn, my_addr) end def get_proxy_exclude_list - rs_cloud = get_cloud_type no_proxy = [] - no_proxy = [] - case rs_cloud - when 'eucalyptus' - meta_server = IPSocket.getaddress(euca_metadata) rescue '169.254.169.254' - no_proxy << meta_server - else - #a reasonable default... - no_proxy << '169.254.169.254' + if Platform.eucalyptus? + meta_server = IPSocket.getaddress(euca_metadata) rescue '169.254.169.254' + no_proxy << meta_server + else + #a reasonable default, e.g. for EC2 and for some CloudStack/OpenStack + #configurations + no_proxy << '169.254.169.254' end #parse "skip proxy for these servers" setting out of metadata element @@ -263,15 +297,6 @@ def get_proxy_exclude_list no_proxy end - # Hack for detecting current Cloud - def get_cloud_type - return ENV['RS_CLOUD'] if env['RS_CLOUD'] - cloud_path = '/etc/rightscale.d/cloud' - rs_cloud = '' - File.open(cloud_path) { |f| rs_cloud = f.gets } if File.exists?(cloud_path) - rs_cloud - end - def create_subversion_servers_config(proxy_uri, no_proxy_list) subversion_servers_path = '/etc/subversion/servers' File.open(subversion_servers_path, 'w') do |f|