class PuppetMasterless::Main

Public Class Methods

new() click to toggle source
# File bin/puppet-masterless, line 62
def initialize
  @files = []
  @args = []
  @path = "#{ARCHIVE_NAME}-#{SecureRandom.hex(4)}"
  @output = "#{ARCHIVE_NAME}-#{SecureRandom.hex(4)}"
  @puppet = DEFAULT_PUPPET
  @sudo = DEFAULT_SUDO
  @user = REMOTE_USER
  @workdir = REMOTE_WORKDIR
end

Public Instance Methods

apply() click to toggle source
# File bin/puppet-masterless, line 132
def apply
  @hostname ? apply_remote : apply_local
end
collect(args) click to toggle source
# File bin/puppet-masterless, line 83
def collect(args)
  while word = args.shift
    case word
    when 'with', 'and'
    when 'confdir' then @confdir = collect_file(args)
    when 'manifest' then @manifest = collect_file(args)
    when 'modulepath' then @modulepath = collect_file(args)
    when 'hiera_config' then @hiera_config = collect_file(args)
    when 'puppet' then @puppet = args.shift
    when 'sudo' then @sudo = args.shift
    when 'to' then @hostname = args.shift
    when 'as' then @user = args.shift
    when 'file' then @files << collect_file(args)
    when '--', nil then @args = args.slice!(0..-1)
    when 'output' then collect_output(args)
    else fail 'Invalid argument: ' << word
    end
  end
end
help() click to toggle source
# File bin/puppet-masterless, line 136
def help
  display_manual
end
package() click to toggle source
# File bin/puppet-masterless, line 128
def package
  create_distribution
end
usage(n = 1) click to toggle source
# File bin/puppet-masterless, line 73
def usage(n = 1)
  STDERR.puts(banner)
  exit(n)
end
validate() click to toggle source
# File bin/puppet-masterless, line 103
def validate
  fail 'No confdir specified' unless @confdir
  fail 'No puppet specified' unless @puppet
  fail 'No output file specified' unless @output

  data = File.join(@confdir, 'data')
  modules = File.join(@confdir, 'modules')
  manifests = File.join(@confdir, 'manifests')
  hiera_yaml = File.join(@confdir, 'hiera.yaml')
  puppet_conf = File.join(@confdir, 'puppet.conf')

  @manifest ||= manifests
  @modulepath ||= modules
  @hiera_config ||= hiera_yaml

  fail 'No such confdir: ' << @confdir unless File.directory?(@confdir)
  fail 'No such manifest: ' << @manifest unless File.exist?(@manifest)

  @files << data if File.directory?(data)
  @files << puppet_conf if File.file?(puppet_conf)

  @modulepath = nil unless File.directory?(@modulepath)
  @hiera_config = nil unless File.file?(@hiera_config)
end
version(n = 0) click to toggle source
# File bin/puppet-masterless, line 78
def version(n = 0)
  STDERR.puts("puppet-masterless #{VERSION}")
  exit(n)
end

Private Instance Methods

apply_local() click to toggle source
# File bin/puppet-masterless, line 192
def apply_local
  STDERR.puts('Notice: Applying locally')
  fail 'Apply command failed' unless system(local_apply_command)
end
apply_remote() click to toggle source
# File bin/puppet-masterless, line 197
def apply_remote
  STDERR.puts("Notice: Creating distribution")
  create_distribution

  begin
    STDERR.puts('Notice: Copying to ' << @hostname)
    fail 'Copy command failed' unless system("scp -q #{@output.shellescape} #{@hostname.shellescape}:#{@workdir.shellescape}")
  ensure
    FileUtils.rm_f(@output)
  end

  STDERR.puts('Notice: Applying to ' << @hostname)
  fail 'Apply command failed' unless system("ssh -q -t #{@hostname.shellescape} #{remote_apply_command.shellescape}")
end
archive_command() click to toggle source
# File bin/puppet-masterless, line 170
def archive_command
  command = "tar -cf- #{ARCHIVE_OPTIONS} --transform 's|^|#{@path.gsub("'", "'\''")}/|'"
  command << ' ' << @files.shelljoin
  command << ' ' << @manifest.shellescape
  command << ' ' << @modulepath.shellescape if @modulepath
  command << ' ' << @hiera_config.shellescape if @hiera_config
  command << ' | gzip -f'
end
banner() click to toggle source
collect_file(args) click to toggle source
# File bin/puppet-masterless, line 160
def collect_file(args)
  path = File.expand_path(file = args.shift)

  unless path.start_with?(Dir.pwd << '/')
    fail 'All files must be within the current directory: ' << file
  end

  path.sub(/#{Dir.pwd}\/*/, '')
end
collect_output(args) click to toggle source
# File bin/puppet-masterless, line 155
def collect_output(args)
  usage(1) unless args.shift == 'file'
  @output = args.shift
end
create_distribution() click to toggle source
# File bin/puppet-masterless, line 212
def create_distribution
  File.open(@output, 'w') do |o|
    o.puts('#!/bin/sh -e')
    o.puts('umask 077')
    o.puts('cd "$(dirname "$0")"')
    o.puts('trap "rm -rf ' << @workdir.shellescape << '/' << @path.shellescape << '" EXIT')
    o.puts('sed -n 10,\\$p "$0" | gunzip -f | tar -xf-')
    o.puts('cd ' << @path.shellescape)
    o.puts(local_apply_command)
    o.puts('exit 0')
    o.puts('# EOF')
    o.chmod(0755)
  end

  unless system(archive_command << ' >> ' << @output.shellescape)
    fail 'Archive command failed: ' << archive_command
  end
end
display_manual() click to toggle source
# File bin/puppet-masterless, line 146
def display_manual
  manual = File.read(__FILE__).lines.grep(/^#1/).map { |s| s.gsub(/^#1 ?/, '') }
  raise 'No manual entry' if manual.empty?
  i, o = IO.pipe
  o.puts(manual)
  STDIN.reopen(i)
  exec('man', '-l', '/dev/stdin')
end
local_apply_command() click to toggle source
# File bin/puppet-masterless, line 179
def local_apply_command
  command = "#{@puppet} apply #{@manifest.shellescape} --verbose --show_diff --color true"
  command << ' --confdir ' << @confdir.shellescape
  command << ' --modulepath ' << @modulepath.shellescape if @modulepath
  command << ' --hiera_config ' << @hiera_config.shellescape if @hiera_config
  command << ' ' << @args.shelljoin
end
remote_apply_command() click to toggle source
# File bin/puppet-masterless, line 187
def remote_apply_command
  command = "trap 'rm -f #{@workdir.shellescape}/#{@output.shellescape}' EXIT"
  command << "; #{@sudo} -u #{@user.shellescape} #{@workdir.shellescape}/#{@output.shellescape}"
end