lib/vagabond/vagabond.rb in vagabond-0.1.4 vs lib/vagabond/vagabond.rb in vagabond-0.2.0
- old
+ new
@@ -1,103 +1,191 @@
+require 'thor'
+require 'chef/knife/core/ui'
+require File.join(File.dirname(__FILE__), 'cookbooks/lxc/libraries/lxc.rb')
+
+%w(vagabondfile internal_configuration helpers).each do |dep|
+ require "vagabond/#{dep}"
+end
+
Dir.glob(
File.join(
File.dirname(__FILE__), 'actions', '*.rb'
)
-).each do |action_module|
- require action_module
+).each do |action|
+ require "vagabond/actions/#{File.basename(action).sub('.rb', '')}"
end
-require 'vagabond/vagabondfile'
-require 'vagabond/internal_configuration'
-require 'vagabond/helpers'
-require 'chef/knife/core/ui'
-require File.join(File.dirname(__FILE__), 'cookbooks/lxc/libraries/lxc.rb')
-
module Vagabond
- class Vagabond
-
+ class Vagabond < Thor
+
+ include Thor::Actions
include Helpers
- class << self
- attr_accessor :ui
+ Actions.constants.each do |const|
+ klass = Actions.const_get(const)
+ include klass if klass.is_a?(Module)
end
- # Load available actions
- Actions.constants.each do |const_sym|
- const = Actions.const_get(const_sym)
- include const if const.is_a?(Module)
- end
-
attr_reader :name
- attr_reader :lxc
attr_reader :vagabondfile
- attr_reader :config
attr_reader :internal_config
attr_reader :ui
+ attr_reader :options
+ attr_accessor :mappings_key
+ attr_accessor :lxc
+ attr_accessor :config
+ attr_accessor :action
+
+ CLI_OPTIONS = lambda do
+ class_option(:debug,
+ :type => :boolean,
+ :default => false
+ )
+
+ class_option(:force_solo,
+ :aliases => '--force-configure',
+ :type => :boolean,
+ :default => false,
+ :desc => 'Force configuration of system'
+ )
+
+ class_option(:color,
+ :type => :boolean,
+ :default => true,
+ :desc => 'Enable/disable colorized output'
+ )
+
+ class_option(:vagabond_file,
+ :aliases => '-f',
+ :type => :string,
+ :desc => 'Provide path to Vagabondfile'
+ )
+
+ class_option(:local_server,
+ :type => :boolean,
+ :default => true,
+ :desc => 'Enable/disable local Chef server usage if available'
+ )
+ end
+
+ CLI_OPTIONS.call
+
+
# action:: Action to perform
# name:: Name of vagabond
# config:: Hash configuration
#
- # Creates an instance
- def initialize(action, name_args)
+ # Creates an instance
+ def initialize(*args)
+ super
+ @mappings_key = :mappings
+ end
+
+ ## COMMANDS
+
+ COMMANDS = lambda do |show_node=true|
+ Actions.constants.find_all do |const|
+ Actions.const_get(const).is_a?(Module)
+ end.map(&:to_s).map(&:downcase).each do |meth|
+ if(self.respond_to?("_#{meth}_desc"))
+ args = self.send("_#{meth}_desc")
+ else
+ args = ["#{meth}#{' NODE' if show_node}", "#{meth.capitalize} instance#{' of NODE' if show_node}"]
+ end
+ desc(*args)
+ if(self.respond_to?("_#{meth}_options"))
+ self.send("_#{meth}_options").each do |opts|
+ method_option(*opts)
+ end
+ end
+ define_method meth do |*args|
+ setup(meth, *args)
+ execute
+ end
+ end
+ end
+
+ COMMANDS.call
+
+ protected
+
+ def version
setup_ui
+ ui.info "#{ui.color('Vagabond:', :yellow, :bold)} - Advocating idleness and work-shyness"
+ ui.info " #{ui.color('Version:', :blue)} - #{VERSION.version} (#{VERSION.codename})"
+ exit EXIT_CODES[:success]
+ end
+
+ def execute
+ self.send("_#{@action}")
+ end
+
+ def setup(action, name=nil, *args)
@action = action
- @name = name_args.shift
+ @name = name
+ @options = options.dup
+ if(args.last.is_a?(Hash))
+ _ui = args.delete(:ui)
+ @options.merge!(args.last)
+ end
+ setup_ui(_ui)
load_configurations
validate!
end
+ def name_required!
+ unless(name)
+ ui.fatal "Node name is required!"
+ exit EXIT_CODES[:missing_node_name]
+ end
+ end
+
+ def provision_solo(path)
+ ui.info "#{ui.color('Vagabond:', :bold)} Provisioning node: #{ui.color(name, :magenta)}"
+ lxc.container_ip(20) # force wait for container to appear and do so quietly
+ direct_container_command(
+ "chef-solo -c #{File.join(path, 'solo.rb')} -j #{File.join(path, 'dna.json')}",
+ :live_stream => STDOUT
+ )
+ end
+
def load_configurations
- @vagabondfile = Vagabondfile.new(Config[:vagabond_file])
- Config[:sudo] = sudo
- Config[:disable_solo] = true if @action.to_sym == :status
+ @vagabondfile = Vagabondfile.new(options[:vagabond_file])
+ options[:sudo] = sudo
+ options[:disable_solo] = true if @action.to_s == 'status' && lxc_installed?
Lxc.use_sudo = @vagabondfile[:sudo].nil? ? true : @vagabondfile[:sudo]
- @internal_config = InternalConfiguration.new(@vagabondfile, ui)
+ @internal_config = InternalConfiguration.new(@vagabondfile, ui, options)
@config = @vagabondfile[:boxes][name]
- @lxc = Lxc.new(@internal_config[:mappings][name] || '____nonreal____')
- unless(Config[:disable_local_server])
+ @lxc = Lxc.new(@internal_config[mappings_key][name] || '____nonreal____')
+ if(options[:local_server] && lxc_installed?)
if(@vagabondfile[:local_chef_server] && @vagabondfile[:local_chef_server][:enabled])
- srv = Lxc.new(@internal_config[:mappings][:server])
- if(srv.running?)
- Config[:knife_opts] = " --server-url https://#{srv.container_ip(10, true)}"
+ srv_name = @internal_config[:mappings][:server]
+ srv = Lxc.new(srv_name) if srv_name
+ if(srv_name && srv.running?)
+ options[:knife_opts] = " --server-url https://#{srv.container_ip(10, true)}"
else
ui.warn 'Local chef server is not currently running!' unless @action.to_sym == :status
- Config[:knife_opts] = ' --server-url https://no-local-server'
+ options[:knife_opts] = ' --server-url https://no-local-server'
end
end
end
end
- protected
-
- def setup_ui
- Chef::Config[:color] = Config[:color].nil? ? true : Config[:color]
- @ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
- self.class.ui = @ui
- end
-
def validate!
if(name.to_s == 'server')
- ui.fatal "Invalid name supplied: #{ui.color(name, :red)}"
+ ui.fatal "RESERVED node name supplied: #{ui.color(name, :red)}"
ui.info ui.color(" -> Try: vagabond server #{@action}", :cyan)
- exit -1
+ exit EXIT_CODES[:reserved_name]
end
- end
-
- def execute
- if(public_methods.include?(@action.to_sym))
- send(@action)
- else
- ui.error "Invalid action received: #{@action}"
+ if(name && config.nil? && !options[:disable_name_validate])
+ ui.fatal "Invalid node name supplied: #{ui.color(name, :red)}"
+ ui.info ui.color(" -> Available: #{vagabondfile[:nodes].keys.sort.join(', ')}", :cyan)
+ exit EXIT_CODES[:invalid_name]
end
end
-
- def generate_hash
- Digest::MD5.hexdigest(@vagabondfile.path)
- end
-
+
def check_existing!
if(@lxc.exists?)
ui.error "LXC: #{name} already exists!"
true
end
@@ -107,8 +195,12 @@
File.dirname(vagabondfile.path)
end
def vagabond_dir
File.join(base_dir, '.vagabond')
+ end
+
+ def lxc_installed?
+ system('which lxc-info > /dev/null')
end
end
end