class Dust::Runner
Public Class Methods
default_options()
click to toggle source
default options for all tasks
# File lib/dust/runner.rb, line 16 def self.default_options method_option 'yaml', :type => :string, :desc => 'use only this server.yaml' method_option 'filter', :type => :hash, :desc => 'only deploy to these hosts (e.g. environment:staging)' method_option 'proxy', :type => :string, :desc => 'socks proxy to use' method_option 'parallel', :type => :boolean, :desc => 'deploy to all hosts at the same time using threads' method_option 'summary', :type => :string, :desc => 'print summary of all events (all, warning, failed)' end
recipe_options()
click to toggle source
# File lib/dust/runner.rb, line 24 def self.recipe_options method_option 'recipes', :type => :array, :desc => 'only deploy these recipes' end
Public Instance Methods
deploy()
click to toggle source
# File lib/dust/runner.rb, line 35 def deploy return unless check_dust_dir initialize_thorfiles puts 'no servers match this filter'.red if load_servers.empty? # set global variables $summary = options['summary'] $parallel = options['parallel'] $summary = 'all' if $parallel and not $summary threads = [] @nodes.each_with_index do |node, i| if $parallel threads[i] = Thread.new do Thread.current['hostname'] = node['hostname'] if run_recipes(node, 'deploy') end else run_recipes(node, 'deploy') end end if $parallel print 'waiting for servers: ' threads.each do |t| t.join # wait for thread print t['hostname'].blue + ' ' if t['hostname'] end puts end display_summary($summary) if $summary end
exec(cmd, yaml='')
click to toggle source
# File lib/dust/runner.rb, line 148 def exec cmd, yaml='' return unless check_dust_dir initialize_thorfiles puts 'no servers match this filter'.red if load_servers.empty? # set global variables $summary = options['summary'] $parallel = options['parallel'] $summary = 'all' if $parallel and not $summary threads = [] @nodes.each_with_index do |node, i| if $parallel threads[i] = Thread.new do run_exec(node, cmd) Thread.current['hostname'] = node['hostname'] end else run_exec(node, cmd) end end if $parallel print 'waiting for servers: ' threads.each do |t| t.join # wait for thread print t['hostname'].blue + ' ' if t['hostname'] end puts end display_summary($summary) if $summary end
new(name)
click to toggle source
# File lib/dust/runner.rb, line 185 def new(name) puts "spawning new dust directory skeleton with examples into '#{name}.dust'" FileUtils.cp_r(File.dirname(__FILE__) + '/examples', "#{name}.dust") end
status()
click to toggle source
# File lib/dust/runner.rb, line 73 def status return unless check_dust_dir initialize_thorfiles puts 'no servers match this filter'.red if load_servers.empty? # set global variables $summary = options['summary'] $parallel = options['parallel'] $summary = 'all' if $parallel and not $summary threads = [] @nodes.each_with_index do |node, i| if $parallel threads[i] = Thread.new do Thread.current['hostname'] = node['hostname'] if run_recipes(node, 'status') end else run_recipes(node, 'status') end end if $parallel print 'waiting for servers: ' threads.each do |t| t.join # wait for thread print t['hostname'].blue + ' ' if t['hostname'] end puts end display_summary($summary) if $summary end
system_update()
click to toggle source
# File lib/dust/runner.rb, line 110 def system_update return unless check_dust_dir initialize_thorfiles puts 'no servers match this filter'.red if load_servers.empty? # set global variables $summary = options['summary'] $parallel = options['parallel'] $summary = 'all' if $parallel and not $summary threads = [] @nodes.each_with_index do |node, i| if $parallel threads[i] = Thread.new do run_system_update(node) Thread.current['hostname'] = node['hostname'] end else run_system_update(node) end end if $parallel print 'waiting for servers: ' threads.each do |t| t.join # wait for thread print t['hostname'].blue + ' ' if t['hostname'] end puts end display_summary($summary) if $summary end
version()
click to toggle source
# File lib/dust/runner.rb, line 191 def version puts "dust-deploy-#{Dust::VERSION}, running on ruby-#{RUBY_VERSION}" end
Private Instance Methods
check_dust_dir()
click to toggle source
# File lib/dust/runner.rb, line 198 def check_dust_dir if Dir.pwd.split('.').last != 'dust' puts 'current directory does not end with .dust, are you in your dust directory?'.red puts "try running 'dust new mynetwork' to let me create one for you with tons of examples!\n" return false end unless File.directory?('./nodes') puts 'could not find \'nodes\' folder in your dust directory. cannot continue.'.red return false end true end
display_summary(level)
click to toggle source
# File lib/dust/runner.rb, line 274 def display_summary(level) puts "\n\n------------------------------ SUMMARY ------------------------------".red unless $parallel @nodes.each do |node| next unless node['server'] messages = node['server'].messages.collect(level) next if messages.empty? node['server'].messages.print_hostname_header(node['hostname']) # display non-recipe messages first msgs = messages.delete '_node' msgs.each { |m| print m } if msgs # display messages from recipes messages.each do |recipe, msgs| node['server'].messages.print_recipe_header(recipe) msgs.each { |m| print m } end end end
filtered?(node)
click to toggle source
checks if this node was filtered out by command line argument e.g. –filter environment:staging filters out all machines but those in the environment staging
# File lib/dust/runner.rb, line 374 def filtered?(node) # if filter is not specified, instantly return false return false unless options['filter'] # remove items if other filter arguments don't match options['filter'].each do |k, v| next unless v # skip empty filters # filter if this node doesn't even have the attribute return true unless node[k] # allow multiple filters of the same type, divided by ',' # e.g. --filter environment:staging,production return true unless v.split(',').include? node[k] end # no filter matched, so this host is not filtered. false end
generate_recipes(node, context)
click to toggle source
generate list of recipes for this node
# File lib/dust/runner.rb, line 254 def generate_recipes(node, context) recipes = {} node['recipes'].each do |recipe, config| # in case --recipes was set, skip unwanted recipes next unless options['recipes'].include?(recipe) if options['recipes'] # skip disabled recipes next if config == 'disabled' or config.is_a? FalseClass # check if method and thor task actually exist k = Thor::Util.find_by_namespace(recipe) next unless k next unless k.method_defined?(context) recipes[recipe] = config end recipes end
load_servers()
click to toggle source
loads servers
# File lib/dust/runner.rb, line 303 def load_servers @nodes = [] # if the argument is empty, load all yaml files in the ./nodes/ directory # if the argument is a directory, load yaml files in this directory # if the argument is a file, load the file. if options['yaml'] if File.directory?(options['yaml']) yaml_files = Dir["#{options['yaml']}/**/*.yaml"] elsif File.exists?(options['yaml']) yaml_files = options['yaml'] end else yaml_files = Dir['./nodes/**/*.yaml'] end unless yaml_files puts "#{yaml} doesn't exist. exiting.".red exit end Array(yaml_files).each do |file| node = YAML.load ERB.new( File.read(file), nil, '%<>').result # if the file is empty, just skip it next unless node # if there is not hostname field in the yaml file, # treat this node file as a template, and skip to the next one next unless node['hostname'] # look for the inherits field in the yaml file, # and merge the templates recursively into this node if node['inherits'] inherited = {} node.delete('inherits').each do |file| template = YAML.load ERB.new( File.read("./nodes/#{file}.yaml"), nil, '%<>').result inherited.deep_merge!(template) end node = inherited.deep_merge(node) end # if more than one hostname is specified, create a node # with the same settings for each hostname Array(node['hostname']).each do |hostname| n = node.clone # overwrite hostname with single hostname (in case there are multiple) n['hostname'] = hostname # create a new field with the fully qualified domain name n['fqdn'] = hostname # if hostname is a valid ip address, don't add domain # so we can connect via ip address only unless IPAddress.valid?(hostname) n['fqdn'] += '.' + n['domain'] if n['domain'] end # pass command line proxy option n['proxy'] = options['proxy'] if options['proxy'] # add this node to the global node array @nodes.push(n) unless filtered?(n) end end end
run_exec(node, cmd)
click to toggle source
# File lib/dust/runner.rb, line 246 def run_exec(node, cmd) node['server'] = Server.new(node) return unless node['server'].connect node['server'].exec(cmd, :live => true) node['server'].disconnect end
run_recipes(node, context)
click to toggle source
run specified recipes in the given context returns false if no recipes where found true if recipes were run (doesn’t indicate, whether the run was sucessful or not)
# File lib/dust/runner.rb, line 216 def run_recipes(node, context) # skip this node if there are no recipes found return false unless node['recipes'] recipes = generate_recipes(node, context) # skip this node unless we're actually having recipes to cook return false if recipes.empty? # connect to server node['server'] = Server.new(node) return true unless node['server'].connect # runs the method with the recipe name, defined and included in recipe/*.rb # call recipes for each recipe that is defined for this node recipes.each do |recipe, config| send(recipe, 'prepare', node['server'], recipe, context, config, options) end node['server'].disconnect true end
run_system_update(node)
click to toggle source
# File lib/dust/runner.rb, line 239 def run_system_update(node) node['server'] = Server.new(node) return unless node['server'].connect node['server'].system_update node['server'].disconnect end
thorfiles(relevant_to=nil, skip_lookup=false)
click to toggle source
overwrite thorfiles to look for tasks in the recipes directories
# File lib/dust/runner.rb, line 298 def thorfiles(relevant_to=nil, skip_lookup=false) Dir[File.dirname(__FILE__) + '/recipes/*.rb'] | Dir['recipes/*.rb'] end