diff options
| author | elijah <elijah@riseup.net> | 2012-11-09 01:22:48 -0800 | 
|---|---|---|
| committer | elijah <elijah@riseup.net> | 2012-11-09 01:22:48 -0800 | 
| commit | febeb64a801f3b4c72193bc93ee0400dee3a2a0a (patch) | |
| tree | a31d0efc4f9ef563c3f9e9023d09e9dfb8b954af /lib | |
| parent | e0471e278c3baf7fc74f288281c7219cbcf0172c (diff) | |
vagrant support
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/leap_cli.rb | 1 | ||||
| -rw-r--r-- | lib/leap_cli/commands/shell.rb | 13 | ||||
| -rw-r--r-- | lib/leap_cli/commands/util.rb | 100 | ||||
| -rw-r--r-- | lib/leap_cli/commands/vagrant.rb | 72 | ||||
| -rw-r--r-- | lib/leap_cli/config/manager.rb | 15 | ||||
| -rw-r--r-- | lib/leap_cli/config/object.rb | 14 | ||||
| -rw-r--r-- | lib/leap_cli/config/object_list.rb | 5 | ||||
| -rw-r--r-- | lib/leap_cli/path.rb | 3 | ||||
| -rw-r--r-- | lib/leap_cli/util/remote_command.rb | 98 | 
9 files changed, 219 insertions, 102 deletions
| diff --git a/lib/leap_cli.rb b/lib/leap_cli.rb index 728e501..5ed5033 100644 --- a/lib/leap_cli.rb +++ b/lib/leap_cli.rb @@ -9,6 +9,7 @@ require 'leap_cli/init'  require 'leap_cli/path'  require 'leap_cli/util'  require 'leap_cli/util/secret' +require 'leap_cli/util/remote_command'  require 'leap_cli/log'  require 'leap_cli/ssh_key' diff --git a/lib/leap_cli/commands/shell.rb b/lib/leap_cli/commands/shell.rb index a84c671..f73a706 100644 --- a/lib/leap_cli/commands/shell.rb +++ b/lib/leap_cli/commands/shell.rb @@ -2,10 +2,19 @@ module LeapCli; module Commands    desc 'Log in to the specified node with an interactive shell'    arg_name '<node-name>', :optional => false, :multiple => false -  command :shell, :ssh do |c| +  command :ssh do |c|      c.action do |global_options,options,args|        node = get_node_from_args(args) -      exec "ssh -l root -o 'HostName=#{node.ip_address}' -o 'HostKeyAlias=#{node.name}' -o 'GlobalKnownHostsFile=#{path(:known_hosts)}' -o 'StrictHostKeyChecking=yes' -p #{node.ssh.port} #{node.name}" +      options = [ +        "-o 'HostName=#{node.ip_address}'", +        "-o 'HostKeyAlias=#{node.name}'", +        "-o 'GlobalKnownHostsFile=#{path(:known_hosts)}'", +        "-o 'StrictHostKeyChecking=yes'" +      ] +      if node.vagrant? +        options << "-i #{vagrant_ssh_key_file}" +      end +      exec "ssh -l root -p #{node.ssh.port} #{options.join(' ')} {node.name}"      end    end diff --git a/lib/leap_cli/commands/util.rb b/lib/leap_cli/commands/util.rb index 164ce0d..c1da570 100644 --- a/lib/leap_cli/commands/util.rb +++ b/lib/leap_cli/commands/util.rb @@ -2,6 +2,7 @@ module LeapCli; module Commands    extend self    extend LeapCli::Util +  extend LeapCli::Util::RemoteCommand    def path(name)      Path.named_path(name) @@ -33,105 +34,6 @@ module LeapCli; module Commands      end    end -  # -  # -  # -  # FYI -  #  Capistrano::Logger::IMPORTANT = 0 -  #  Capistrano::Logger::INFO      = 1 -  #  Capistrano::Logger::DEBUG     = 2 -  #  Capistrano::Logger::TRACE     = 3 -  # -  def ssh_connect(nodes, options={}, &block) -    node_list = parse_node_list(nodes) - -    cap = new_capistrano -    cap.logger.level = LeapCli.log_level -    user = options[:user] || 'root' -    cap.set :user, user -    cap.set :ssh_options, ssh_options -    cap.set :use_sudo, false # we may want to change this in the future - -    # # supply drop options -    # cap.set :puppet_source, [Path.platform, 'puppet'].join('/') -    # cap.set :puppet_destination, '/root/leap' -    # #cap.set :puppet_command, 'puppet apply' -    # cap.set :puppet_lib, "puppet/modules" -    # cap.set :puppet_parameters, '--confdir=puppet puppet/manifests/site.pp' -    # #cap.set :puppet_stream_output, false -    # #puppet apply --confdir=puppet puppet/manifests/site.pp  | grep -v 'warning:.*is deprecated' -    # #puppet_cmd = "cd #{puppet_destination} && #{sudo_cmd} #{puppet_command} --modulepath=#{puppet_lib} #{puppet_parameters}" - -    # -    # allow password authentication when we are bootstraping a single node. -    # -    if options[:bootstrap] && node_list.size == 1 -      hostname = node_list.values.first.name - -      # the 'password' block is only called if key auth fails -      if options[:echo] -        cap.set(:password) { ask "Root SSH password for #{user}@#{hostname}> " } -      else -        cap.set(:password) { Capistrano::CLI.password_prompt " * Typed password will be hidden (use --echo to make it visible)\nRoot SSH password for #{user}@#{hostname}> " } -      end -    end - -    node_list.each do |name, node| -      cap.server node.name, :dummy_arg, node_options(node) -    end - -    yield cap -  end - - -  private - - -  # -  # For available options, see http://net-ssh.github.com/net-ssh/classes/Net/SSH.html#method-c-start -  # -  def ssh_options -    { -      :config => false, -      :global_known_hosts_file => path(:known_hosts), -      :paranoid => true -    } -  end - -  # -  # For notes on advanced ways to set server-specific options, see -  # http://railsware.com/blog/2011/11/02/advanced-server-definitions-in-capistrano/ -  # -  def node_options(node) -    #password_proc = Proc.new {Capistrano::CLI.password_prompt "Root SSH password for #{node.name}"}  # only called if needed -    { -      #:password => password_proc, -      :ssh_options => { -        :host_key_alias => node.name, -        :host_name => node.ip_address, -        :port => node.ssh.port -      } -    } -  end - -  def new_capistrano -    # load once the library files -    @capistrano_enabled ||= begin -      require 'capistrano' -      require 'capistrano/cli' -      require 'leap_cli/remote/plugin' -      Capistrano.plugin :leap, LeapCli::Remote::Plugin -      true -    end - -    # create capistrano instance -    cap = Capistrano::Configuration.new - -    # add tasks to capistrano instance -    cap.load File.dirname(__FILE__) + '/../remote/tasks.rb' - -    return cap -  end    def parse_node_list(nodes)      if nodes.is_a? Config::Object diff --git a/lib/leap_cli/commands/vagrant.rb b/lib/leap_cli/commands/vagrant.rb new file mode 100644 index 0000000..587e5e1 --- /dev/null +++ b/lib/leap_cli/commands/vagrant.rb @@ -0,0 +1,72 @@ +require 'ipaddr' + +module LeapCli; module Commands + +  desc 'Bring up one or more local virtual machines' +  arg_name '[node-filter]', :optional => true, :multiple => false +  command :'local-up' do |c| +    c.action do |global_options,options,args| +      vagrant_command("up", args) +    end +  end + +  desc 'Halt one or more local virtual machines' +  arg_name '[node-filter]', :optional => true, :multiple => false +  command :'local-down' do |c| +    c.action do |global_options,options,args| +      vagrant_command("halt", args) +    end +  end + +  desc 'Destroy one or more local virtual machines' +  arg_name '[node-filter]', :optional => true, :multiple => false +  command :'local-reset' do |c| +    c.action do |global_options,options,args| +      vagrant_command("destroy", args) +    end +  end + +  public + +  def vagrant_ssh_key_file +    file = File.expand_path('../../../vendor/vagrant_ssh_keys/vagrant.key', File.dirname(__FILE__)) +    Util.assert_files_exist! file +    return file +  end + +  private + +  def vagrant_command(cmd, args) +    create_vagrant_file +    nodes = manager.filter(args)[:local => true].field(:name) +    if nodes.any? +      execute "cd #{File.dirname(Path.named_path(:vagrantfile))}; vagrant #{cmd} #{nodes.join(' ')}" +    else +      bail! "No nodes found" +    end +  end + +  def execute(cmd) +    progress2 "Running: #{cmd}" +    exec cmd +  end + +  def create_vagrant_file +    lines = [] +    netmask = IPAddr.new('255.255.255.255').mask(manager.provider.vagrant.network.split('/').last).to_s +    lines << %[Vagrant::Config.run do |config|] +    manager.each_node do |node| +      if node.vagrant? +        lines << %[  config.vm.define :#{node.name} do |config|] +        lines << %[    config.vm.box = "minimal-wheezy"] +        lines << %[    config.vm.box_url = "http://cloud.github.com/downloads/leapcode/minimal-debian-vagrant/minimal-wheezy.box"] +        lines << %[    config.vm.network :hostonly, "#{node.ip_address}", :netmask => "#{netmask}"] +        lines << %[  end] +      end +    end +    lines << %[end] +    lines << "" +    write_file! :vagrantfile, lines.join("\n") +  end + +end; end
\ No newline at end of file diff --git a/lib/leap_cli/config/manager.rb b/lib/leap_cli/config/manager.rb index 88f21be..00b4ec5 100644 --- a/lib/leap_cli/config/manager.rb +++ b/lib/leap_cli/config/manager.rb @@ -113,6 +113,13 @@ module LeapCli          nodes[name]        end +      # +      # yields each node, in sorted order +      # +      def each_node(&block) +        nodes.each_node &block +      end +        private        def load_all_json(pattern) @@ -232,6 +239,14 @@ module LeapCli          end        end +      # +      # TODO: apply JSON spec +      # +      PRIVATE_IP_RANGES = /(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/ +      def validate_provider(provider) +        Util::assert! provider.vagrant.network =~ PRIVATE_IP_RANGES, 'provider.json error: vagrant.network is not a local private network' +      end +      end    end  end diff --git a/lib/leap_cli/config/object.rb b/lib/leap_cli/config/object.rb index ad32f54..731f3ff 100644 --- a/lib/leap_cli/config/object.rb +++ b/lib/leap_cli/config/object.rb @@ -145,6 +145,20 @@ module LeapCli        end        ## +      ## NODE SPECIFIC +      ## maybe these should be moved to a Node class. +      ## + +      # +      # returns true if this node has an ip address in the range of the vagrant network +      # +      def vagrant? +        vagrant_range = IPAddr.new @manager.provider.vagrant.network +        ip_address    = IPAddr.new @node.ip_address +        vagrant_range.include?(ip_address) +      end + +      ##        ## MACROS        ## these are methods used when eval'ing a value in the .json configuration        ## diff --git a/lib/leap_cli/config/object_list.rb b/lib/leap_cli/config/object_list.rb index 708afc1..b0839ca 100644 --- a/lib/leap_cli/config/object_list.rb +++ b/lib/leap_cli/config/object_list.rb @@ -46,6 +46,11 @@ module LeapCli          end        end +      def each_node(&block) +        self.keys.sort.each do |node_name| +          yield self[node_name] +        end +      end        # def <<(object)        #   if object.is_a? Config::ObjectList diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb index 6d68546..48b0d11 100644 --- a/lib/leap_cli/path.rb +++ b/lib/leap_cli/path.rb @@ -29,7 +29,8 @@ module LeapCli; module Path      :ca_cert          => 'files/ca/ca.crt',      :dh_params        => 'files/ca/dh.pem',      :node_x509_key    => 'files/nodes/#{arg}/#{arg}.key', -    :node_x509_cert   => 'files/nodes/#{arg}/#{arg}.crt' +    :node_x509_cert   => 'files/nodes/#{arg}/#{arg}.crt', +    :vagrantfile      => 'test/Vagrantfile'    }    # diff --git a/lib/leap_cli/util/remote_command.rb b/lib/leap_cli/util/remote_command.rb new file mode 100644 index 0000000..118a65e --- /dev/null +++ b/lib/leap_cli/util/remote_command.rb @@ -0,0 +1,98 @@ +module LeapCli; module Util; module RemoteCommand +  extend self + +  # +  # FYI +  #  Capistrano::Logger::IMPORTANT = 0 +  #  Capistrano::Logger::INFO      = 1 +  #  Capistrano::Logger::DEBUG     = 2 +  #  Capistrano::Logger::TRACE     = 3 +  # +  def ssh_connect(nodes, options={}, &block) +    node_list = parse_node_list(nodes) + +    cap = new_capistrano +    cap.logger.level = LeapCli.log_level +    user = options[:user] || 'root' +    cap.set :user, user +    cap.set :ssh_options, ssh_options # ssh options common to all nodes +    cap.set :use_sudo, false          # we may want to change this in the future + +    # Allow password authentication when we are bootstraping a single node +    # (and key authentication fails). +    if options[:bootstrap] && node_list.size == 1 +      hostname = node_list.values.first.name +      if options[:echo] +        cap.set(:password) { ask "Root SSH password for #{user}@#{hostname}> " } +      else +        cap.set(:password) { Capistrano::CLI.password_prompt " * Typed password will be hidden (use --echo to make it visible)\nRoot SSH password for #{user}@#{hostname}> " } +      end +    end + +    node_list.each do |name, node| +      cap.server node.name, :dummy_arg, node_options(node) +    end + +    yield cap +  end + +  private + +  # +  # For available options, see http://net-ssh.github.com/net-ssh/classes/Net/SSH.html#method-c-start +  # +  def ssh_options +    { +      :config => false, +      :global_known_hosts_file => path(:known_hosts), +      :paranoid => true +    } +  end + +  # +  # For notes on advanced ways to set server-specific options, see +  # http://railsware.com/blog/2011/11/02/advanced-server-definitions-in-capistrano/ +  # +  # if, in the future, we want to do per-node password options, it would be done like so: +  # +  #  password_proc = Proc.new {Capistrano::CLI.password_prompt "Root SSH password for #{node.name}"} +  #  return {:password => password_proc} +  # +  def node_options(node) +    { +      :ssh_options => { +        :host_key_alias => node.name, +        :host_name => node.ip_address, +        :port => node.ssh.port +      }.merge(contingent_ssh_options_for_node(node)) +    } +  end + +  def new_capistrano +    # load once the library files +    @capistrano_enabled ||= begin +      require 'capistrano' +      require 'capistrano/cli' +      require 'leap_cli/remote/plugin' +      Capistrano.plugin :leap, LeapCli::Remote::Plugin +      true +    end + +    # create capistrano instance +    cap = Capistrano::Configuration.new + +    # add tasks to capistrano instance +    cap.load File.dirname(__FILE__) + '/../remote/tasks.rb' + +    return cap +  end + +  def contingent_ssh_options_for_node(node) +    if node.vagrant? +      {:keys => [vagrant_ssh_key_file]} +    else +      {} +    end +  end + +end; end; end
\ No newline at end of file | 
