Created
February 13, 2013 15:23
-
-
Save swinton/4945349 to your computer and use it in GitHub Desktop.
Ugly way of opening a Django shell via a Vagrant command... there must be a better way?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Vagrant::Config.run do |config| | |
| config.vm.box = "lucid64" | |
| config.vm.box_url = "http://files.vagrantup.com/lucid64.box" | |
| config.vm.host_name = "myvagrantbox" | |
| # etc. | |
| end | |
| class DjangoShellCommand < Vagrant::Command::Base | |
| def execute | |
| # Open the interactive Django shell on the Vagrant box | |
| exec 'ssh -t myvagrantbox "python manage.py shell"' | |
| end | |
| end | |
| Vagrant.commands.register(:shell) { DjangoShellCommand } |
Author
Author
content of vagrant/ssh.rb
require 'log4r'
require 'vagrant/util/file_util'
require 'vagrant/util/file_mode'
require 'vagrant/util/platform'
require 'vagrant/util/safe_exec'
module Vagrant
# Manages SSH connection information as well as allows opening an
# SSH connection.
class SSH
include Util::SafeExec
def initialize(vm)
@vm = vm
@logger = Log4r::Logger.new("vagrant::ssh")
end
# Returns a hash of information necessary for accessing this
# virtual machine via SSH.
#
# @return [Hash]
def info
results = {
:host => @vm.config.ssh.host,
:port => @vm.config.ssh.port || @vm.driver.ssh_port(@vm.config.ssh.guest_port),
:username => @vm.config.ssh.username,
:forward_agent => @vm.config.ssh.forward_agent,
:forward_x11 => @vm.config.ssh.forward_x11
}
# This can happen if no port is set and for some reason Vagrant
# can't detect an SSH port.
raise Errors::SSHPortNotDetected if !results[:port]
# Determine the private key path, which is either set by the
# configuration or uses just the built-in insecure key.
pk_path = @vm.config.ssh.private_key_path || @vm.env.default_private_key_path
results[:private_key_path] = File.expand_path(pk_path, @vm.env.root_path)
# We need to check and fix the private key permissions
# to make sure that SSH gets a key with 0600 perms.
check_key_permissions(results[:private_key_path])
# Return the results
return results
end
# Connects to the environment's virtual machine, replacing the ruby
# process with an SSH process.
#
# @param [Hash] opts Options hash
# @options opts [Boolean] :plain_mode If True, doesn't authenticate with
# the machine, only connects, allowing the user to connect.
def exec(opts={})
# Get the SSH information and cache it here
ssh_info = info
# Ensure the platform supports ssh. On Windows there are several programs which
# include ssh, notably git, mingw and cygwin, but make sure ssh is in the path!
if !Util::FileUtil.which("ssh")
if Util::Platform.windows?
raise Errors::SSHUnavailableWindows, :host => ssh_info[:host],
:port => ssh_info[:port],
:username => ssh_info[:username],
:key_path => ssh_info[:private_key_path]
end
raise Errors::SSHUnavailable
end
# If plain mode is enabled then we don't do any authentication (we don't
# set a user or an identity file)
plain_mode = opts[:plain_mode]
options = {}
options[:host] = ssh_info[:host]
options[:port] = ssh_info[:port]
options[:username] = ssh_info[:username]
options[:private_key_path] = ssh_info[:private_key_path]
# Command line options
command_options = ["-p", options[:port].to_s, "-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no", "-o", "LogLevel=QUIET"]
# Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the IdentitiesOnly option
# (Also don't use it in plain mode, it'll skip user agents.)
command_options += ["-o", "IdentitiesOnly=yes"] if !(Util::Platform.solaris? || plain_mode)
command_options += ["-i", options[:private_key_path]] if !plain_mode
command_options += ["-o", "ForwardAgent=yes"] if ssh_info[:forward_agent]
# If there are extra options, then we append those
command_options.concat(opts[:extra_args]) if opts[:extra_args]
if ssh_info[:forward_x11]
# Both are required so that no warnings are shown regarding X11
command_options += ["-o", "ForwardX11=yes"]
command_options += ["-o", "ForwardX11Trusted=yes"]
end
host_string = options[:host]
host_string = "#{options[:username]}@#{host_string}" if !plain_mode
command_options << host_string
@logger.info("Invoking SSH: #{command_options.inspect}")
safe_exec("ssh", *command_options)
end
# Checks the file permissions for a private key, resetting them
# if needed.
def check_key_permissions(key_path)
# Windows systems don't have this issue
return if Util::Platform.windows?
@logger.debug("Checking key permissions: #{key_path}")
stat = File.stat(key_path)
if stat.owned? && Util::FileMode.from_octal(stat.mode) != "600"
@logger.info("Attempting to correct key permissions to 0600")
File.chmod(0600, key_path)
stat = File.stat(key_path)
if Util::FileMode.from_octal(stat.mode) != "600"
raise Errors::SSHKeyBadPermissions, :key_path => key_path
end
end
rescue Errno::EPERM
# This shouldn't happen since we verified we own the file, but
# it is possible in theory, so we raise an error.
raise Errors::SSHKeyBadPermissions, :key_path => key_path
end
end
end
Author
More clues, from https://github.com/mitchellh/vagrant/blob/v1.0.6/lib/vagrant/command/ssh.rb
require 'optparse'
module Vagrant
module Command
class SSH < Base
def execute
options = {}
opts = OptionParser.new do |opts|
opts.banner = "Usage: vagrant ssh [vm-name] [-c command] [-- extra ssh args]"
opts.separator ""
opts.on("-c", "--command COMMAND", "Execute an SSH command directly.") do |c|
options[:command] = c
end
opts.on("-p", "--plain", "Plain mode, leaves authentication up to user.") do |p|
options[:plain_mode] = p
end
end
# Parse the options and return if we don't have any target.
argv = parse_options(opts)
return if !argv
# Parse out the extra args to send to SSH, which is everything
# after the "--"
ssh_args = ARGV.drop_while { |i| i != "--" }
ssh_args = ssh_args[1..-1]
options[:ssh_args] = ssh_args
# If the remaining arguments ARE the SSH arguments, then just
# clear it out. This happens because optparse returns what is
# after the "--" as remaining ARGV, and Vagrant can think it is
# a multi-vm name (wrong!)
argv = [] if argv == ssh_args
# Execute the actual SSH
with_target_vms(argv, :single_target => true) do |vm|
# Basic checks that are required for proper SSH
raise Errors::VMNotCreatedError if !vm.created?
raise Errors::VMInaccessible if !vm.state == :inaccessible
raise Errors::VMNotRunningError if vm.state != :running
if options[:command]
ssh_execute(vm, options[:command])
else
opts = {
:plain_mode => options[:plain_mode],
:extra_args => options[:ssh_args]
}
ssh_connect(vm, opts)
end
end
# Success, exit status 0
0
end
protected
def ssh_execute(vm, command=nil)
exit_status = 0
@logger.debug("Executing command: #{command}")
exit_status = vm.channel.execute(command, :error_check => false) do |type, data|
# Determine the proper channel to send the output onto depending
# on the type of data we are receiving.
channel = type == :stdout ? :out : :error
# Print the SSH output as it comes in, but don't prefix it and don't
# force a new line so that the output is properly preserved
vm.ui.info(data.to_s,
:prefix => false,
:new_line => false,
:channel => channel)
end
# Exit with the exit status we got from executing the command
exit exit_status
end
def ssh_connect(vm, opts)
@logger.debug("`exec` into ssh prompt")
vm.ssh.exec(opts)
end
end
end
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For some hints, look at https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/ssh.rb