lib/guignol/commands/base.rb in guignol-0.1.2.1 vs lib/guignol/commands/base.rb in guignol-0.3.0

- old
+ new

@@ -1,88 +1,75 @@ -# Copyright (c) 2012, HouseTrip SA. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of the authors. - - +require 'thor' require 'pathname' require 'parallel' -require 'guignol/instance' -require 'guignol/array/collect_key' +require 'guignol' +require 'guignol/configuration' +require 'guignol/models/instance' +require 'core_ext/array/collect_key' module Guignol::Commands class Base - def initialize(*argv) - @all_configs = load_config_files - check_config_consistency - @configs = argv.map { |pattern| - @all_configs.select { |config| - config[:name] =~ /#{pattern}/ - } - }.flatten.uniq + def initialize(patterns, options = {}) + @configs = select_configs(patterns) + @options = options end + # Run the block for each server in +configs+ (in parallel). def run - before_run or return if respond_to?(:before_run) + before_run(@configs) or return + results = {} - Parallel.each(@configs) do |config| - run_on_server(config) + Parallel.each(@configs, parallel_options) do |name,config| + instance = Guignol::Models::Instance.new(name, config) + results[name] = run_on_server(instance, @options) end + + after_run(results) end - protected - def confirm(message) - $stdout.print "#{message}? [y/N] " - $stdout.flush - answer = $stdin.gets - return answer.strip =~ /y/i + protected + + # Override in subclasses + def before_run(configs) ; true ; end + + # Override in subclasses + def after_run(data) ; true ; end + + + def shell + Guignol::Shell.shared_shell end - private - # Read & return the first available config. - def load_config_files - [ - Pathname.new(ENV['GUIGNOL_YML'] || '/var/nonexistent'), - Pathname.new('guignol.yml'), - Pathname.new('config/guignol.yml'), - Pathname.new(ENV['HOME']).join('.guignol.yml') - ].each do |pathname| - next unless pathname.exist? - return YAML.load(pathname.read) + def synchronize + (@mutex ||= Mutex.new).synchronize do + yield end - return {} end - def check_config_consistency - errors = [] - errors << "Instance config lacks :name" unless @all_configs.collect_key(:name).all? - errors << "Instance config lacks :uuid" unless @all_configs.collect_key(:uuid).all? - errors << "Volume config lacks :uuid" unless @all_configs.collect_key(:volumes).collect_key(:uuid) - raise errors.join(', ') if errors.any? + + private + + + def parallel_options + if RUBY_VERSION >= '1.9.3' + # 1.9.3 has bugs with Excon / SSL connections + { :in_threads => 0 } + else + { :in_threads => @configs.size } + end end + + # Put all the servers matching one of the +names+ in +configs+. + def select_configs(patterns) + patterns = patterns.map { |pattern| + pattern.kind_of?(String) ? Regexp.new(pattern) : pattern + } + Guignol.configuration.delete_if { |name,config| + patterns.none? { |pattern| name.to_s =~ pattern } + } + end + end end