diff options
| author | Micah Anderson <micah@leap.se> | 2015-06-11 12:10:09 -0400 | 
|---|---|---|
| committer | Micah Anderson <micah@leap.se> | 2015-06-11 12:10:09 -0400 | 
| commit | b429b30bda4dafc78cb02f6ece5d82f08e35de1f (patch) | |
| tree | 37efc30a4fcb642dec583c3accea76f7a7de9c39 /bin/puppet_command | |
| parent | 67b2bea2dfcfb06191bf5ed562309f264c6aed8c (diff) | |
| parent | d9146415db0e6b7dd0c945039c0a4ed4fd054a7d (diff) | |
Merge tag '0.7.0'
Releasing 0.7.0
Diffstat (limited to 'bin/puppet_command')
| -rwxr-xr-x | bin/puppet_command | 125 | 
1 files changed, 105 insertions, 20 deletions
| diff --git a/bin/puppet_command b/bin/puppet_command index cdb0b027..1e74522a 100755 --- a/bin/puppet_command +++ b/bin/puppet_command @@ -4,11 +4,14 @@  # This is a wrapper script around the puppet command used by the LEAP platform.  #  # We do this in order to make it faster and easier to control puppet remotely -# (exit codes, lockfile, multiple manifests, etc) +# (exit codes, logging, lockfile, version check, etc)  #  require 'pty'  require 'yaml' +require 'logger' +require 'socket' +require 'fileutils'  PUPPET_BIN        = '/usr/bin/puppet'  PUPPET_DIRECTORY  = '/srv/leap' @@ -18,6 +21,12 @@ SITE_MODULES      = 'puppet/modules'  CUSTOM_MODULES    = ':files/puppet/modules'  DEFAULT_TAGS      = 'leap_base,leap_service'  HIERA_FILE        = '/etc/leap/hiera.yaml' +LOG_DIR           = '/var/log/leap' +DEPLOY_LOG        = '/var/log/leap/deploy.log' +SUMMARY_LOG       = '/var/log/leap/deploy-summary.log' +SUMMARY_LOG_1     = '/var/log/leap/deploy-summary.log.1' +APPLY_START_STR   = "STARTING APPLY" +APPLY_FINISH_STR  = "APPLY COMPLETE"  def main    process_command_line_arguments @@ -28,15 +37,39 @@ def main    end  end -def puts(str) +def open_log_files +  FileUtils.mkdir_p(LOG_DIR) +  $logger = Logger.new(DEPLOY_LOG) +  $summary_logger = Logger.new(SUMMARY_LOG) +  [$logger, $summary_logger].each do |logger| +    logger.level = Logger::INFO +    logger.formatter = proc do |severity, datetime, progname, msg| +      "%s %s: %s\n" % [datetime.strftime("%b %d %H:%M:%S"), Socket.gethostname, msg] +    end +  end +end + +def close_log_files +  $logger.close +  $summary_logger.close +end + +def log(str, *args) +  str = str.strip    $stdout.puts str    $stdout.flush +  $logger.info(str) +  if args.include? :summary +    $summary_logger.info(str) +  end  end  def process_command_line_arguments    @commands = []    @verbosity = 1    @tags = DEFAULT_TAGS +  @info = {} +  @downgrade = false    loop do      case ARGV[0]        when 'apply'        then ARGV.shift; @commands << 'apply' @@ -44,6 +77,8 @@ def process_command_line_arguments        when '--verbosity'  then ARGV.shift; @verbosity = ARGV.shift.to_i        when '--force'      then ARGV.shift; remove_lockfile        when '--tags'       then ARGV.shift; @tags      = ARGV.shift +      when '--info'       then ARGV.shift; @info      = parse_info(ARGV.shift) +      when '--downgrade'  then ARGV.shift; @downgrade = true        when /^-/           then usage("Unknown option: #{ARGV[0].inspect}")        else break      end @@ -52,16 +87,18 @@ def process_command_line_arguments  end  def apply +  platform_version_check! unless @downgrade +  log "#{APPLY_START_STR} {#{format_info(@info)}}", :summary    exit_code = puppet_apply do |line| -    puts line +    log line    end -  puts "Puppet apply complete (#{exitcode_description(exit_code)})." +  log "#{APPLY_FINISH_STR} (#{exitcode_description(exit_code)}) {#{format_info(@info)}}", :summary  end  def set_hostname    hostname = hiera_file['name']    if hostname.nil? || hostname.empty? -    puts('ERROR: "name" missing from hiera file') +    log('ERROR: "name" missing from hiera file')      exit(1)    end    current_hostname_file = File.read('/etc/hostname') rescue nil @@ -73,18 +110,18 @@ def set_hostname        f.write hostname      end      if File.read('/etc/hostname') == hostname -      puts "Changed /etc/hostname to #{hostname}" +      log "Changed /etc/hostname to #{hostname}"      else -      puts "ERROR: failed to update /etc/hostname" +      log "ERROR: failed to update /etc/hostname"      end    end    # call /bin/hostname    if current_hostname != hostname      if run("/bin/hostname #{hostname}") == 0 -      puts "Changed hostname to #{hostname}" +      log "Changed hostname to #{hostname}"      else -      puts "ERROR: call to `/bin/hostname #{hostname}` returned an error." +      log "ERROR: call to `/bin/hostname #{hostname}` returned an error."      end    end  end @@ -96,7 +133,7 @@ def puppet_apply(options={}, &block)    options = {:verbosity => @verbosity, :tags => @tags}.merge(options)    manifest = options[:manifest] || SITE_MANIFEST    modulepath = options[:module_path] || SITE_MODULES + CUSTOM_MODULES -  fqdn = hiera_file['domain']['name'] +  fqdn = hiera_file['domain']['full']    domain = hiera_file['domain']['full_suffix']    Dir.chdir(PUPPET_DIRECTORY) do      return run("FACTER_fqdn='#{fqdn}' FACTER_domain='#{domain}' #{PUPPET_BIN} apply #{custom_parameters(options)} --modulepath='#{modulepath}' #{PUPPET_PARAMETERS} #{manifest}", &block) @@ -104,17 +141,60 @@ def puppet_apply(options={}, &block)  end  # +# parse the --info flag. example str: "key1: value1, key2: value2, ..." +# +def parse_info(str) +  str.split(', '). +    map {|i| i.split(': ')}. +    inject({}) {|h,i| h[i[0]] = i[1]; h} +rescue Exception => exc +  {"platform" => "INVALID_FORMAT"} +end + +def format_info(info) +  info.to_a.map{|i|i.join(': ')}.join(', ') +end + +# +# exits with a warning message if the last successful deployed +# platform was newer than the one we are currently attempting to +# deploy. +# +PLATFORM_RE = /\{.*platform: ([0-9\.]+)[ ,\}].*[\}$]/ +def platform_version_check! +  return unless @info["platform"] +  new_version = @info["platform"].split(' ').first +  return unless new_version +  if File.exists?(SUMMARY_LOG) && File.size(SUMMARY_LOG) != 0 +    file = SUMMARY_LOG +  elsif File.exists?(SUMMARY_LOG_1) && File.size(SUMMARY_LOG_1) != 0 +    file = SUMMARY_LOG_1 +  else +    return +  end +  most_recent_line = `tail '#{file}'`.split("\n").grep(PLATFORM_RE).last +  if most_recent_line +    prior_version = most_recent_line.match(PLATFORM_RE)[1] +    if Gem::Version.new(prior_version) > Gem::Version.new(new_version) +      log("ERROR: You are attempting to deploy platform v#{new_version} but this node uses v#{prior_version}.") +      log("       Run with --downgrade if you really want to deploy an older platform version.") +      exit(0) +    end +  end +end + +#  # Return a ruby object representing the contents of the hiera yaml file.  #  def hiera_file    unless File.exists?(HIERA_FILE) -    puts("ERROR: hiera file '#{HIERA_FILE}' does not exist.") +    log("ERROR: hiera file '#{HIERA_FILE}' does not exist.")      exit(1)    end    $hiera_contents ||= YAML.load_file(HIERA_FILE)    return $hiera_contents  rescue Exception => exc -  puts("ERROR: problem reading hiera file '#{HIERA_FILE}' (#{exc})") +  log("ERROR: problem reading hiera file '#{HIERA_FILE}' (#{exc})")    exit(1)  end @@ -150,13 +230,16 @@ def usage(s)    $stderr.puts("Usage: #{File.basename($0)} COMMAND [OPTIONS]")    $stderr.puts    $stderr.puts("COMMAND may be one or more of: -  set_hostname     -- set the hostname of this server -  apply            -- apply puppet manifests") +  set_hostname     -- set the hostname of this server. +  apply            -- apply puppet manifests.")    $stderr.puts    $stderr.puts("OPTIONS may be one or more of: -  --verbosity VERB -- set the verbosity level 0..5 -  --tags TAGS      -- set the tags to pass through to puppet -  --force          -- run even when lockfile is present") +  --verbosity VERB -- set the verbosity level 0..5. +  --tags TAGS      -- set the tags to pass through to puppet. +  --force          -- run even when lockfile is present. +  --info           -- additional info to include in logs (e.g. 'user: alice, platform: 0.6.1') +  --downgrade      -- allow a deploy even if the platform version is older than previous deploy. +  ")    exit(2)  end @@ -176,13 +259,15 @@ def with_lockfile(lock_file_path=DEFAULT_LOCKFILE)      File.open(lock_file_path, File::CREAT | File::EXCL | File::WRONLY) do |o|        o.write(Process.pid)      end +    open_log_files      yield      remove_lockfile +    close_log_files    rescue Errno::EEXIST -    puts("ERROR: the lock file '#{lock_file_path}' already exists. Wait a minute for the process to die, or run with --force to ignore. Bailing out.") +    log("ERROR: the lock file '#{lock_file_path}' already exists. Wait a minute for the process to die, or run with --force to ignore. Bailing out.")      exit(1)    rescue IOError => exc -    puts("ERROR: problem with lock file '#{lock_file_path}' (#{exc}). Bailing out.") +    log("ERROR: problem with lock file '#{lock_file_path}' (#{exc}). Bailing out.")      exit(1)    end  end @@ -193,7 +278,7 @@ end  ##  def run(cmd) -  puts cmd if @verbosity >= 3 +  log(cmd) if @verbosity >= 3    PTY.spawn("#{cmd}") do |output, input, pid|      begin        while line = output.gets do | 
