summaryrefslogtreecommitdiff
path: root/bin/puppet_command
diff options
context:
space:
mode:
Diffstat (limited to 'bin/puppet_command')
-rwxr-xr-xbin/puppet_command117
1 files changed, 98 insertions, 19 deletions
diff --git a/bin/puppet_command b/bin/puppet_command
index cdb0b027..bc4bfc5b 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,11 @@ 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'
+APPLY_START_STR = "STARTING APPLY"
+APPLY_FINISH_STR = "APPLY COMPLETE"
def main
process_command_line_arguments
@@ -28,15 +36,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 +76,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 +86,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 +109,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
@@ -104,17 +140,55 @@ 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!
+ if @info["platform"]
+ new_version = @info["platform"].split(' ').first
+ if File.exists?(SUMMARY_LOG) && new_version
+ most_recent_line = `tail '#{SUMMARY_LOG}'`.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
+ 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 +224,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 +253,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 +272,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