sshwrap 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Jason Heiss
1
+ Copyright (c) 2013 Jason Heiss
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # SSHwrap
2
2
 
3
3
  This provides a wrapper for ssh that execute a command on multiple machines,
4
- optionally in parallel, and handles any sudo prompts that result.
4
+ optionally in parallel, and handles any ssh and sudo password prompts that
5
+ result.
5
6
 
6
7
  ## Installation
7
8
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ $LOAD_PATH << File.expand_path('../lib', File.dirname(__FILE__))
3
4
  require 'sshwrap'
4
5
  require 'optparse'
5
6
 
@@ -1,24 +1,53 @@
1
+ require 'etc'
2
+ require 'yaml'
1
3
  require 'net/ssh'
2
4
  require 'highline/import'
5
+ require 'sshwrap/prompter'
6
+
7
+ # Monkey patch our prompt method into Net::SSH
8
+ module Net::SSH
9
+ def KeyFactory.prompt(prompt, echo=true)
10
+ @prompter ||= SSHwrap::Prompter.new
11
+ @prompter.prompt(prompt + ' ', echo)
12
+ end
13
+ module Authentication::Methods
14
+ def KeyboardInteractive.prompt(prompt, echo=true)
15
+ @prompter ||= SSHwrap::Prompter.new
16
+ @prompter.prompt(prompt + ' ', echo)
17
+ end
18
+ end
19
+ end
3
20
 
4
21
  class SSHwrap::Main
5
22
  def initialize(options={})
23
+ home = Dir.respond_to?(:home) ? Dir.home : ENV['HOME'] || ENV['LOGDIR']
24
+ conffile = "#{home}/.sshwrap.yaml"
25
+ if File.exist?(conffile)
26
+ conf = YAML.load_file(conffile)
27
+ else
28
+ conf = {}
29
+ end
30
+
6
31
  @mutex = Mutex.new
7
32
  @max_workers = options[:max_workers] || 1
8
33
  @abort_on_failure = options[:abort_on_failure]
9
34
  @user = options[:user] || Etc.getlogin
10
35
  @ssh_key = options[:ssh_key]
11
36
  @debug = options[:debug]
12
- @password = nil
13
- end
14
-
15
- def get_password
16
- @mutex.synchronize do
17
- if !@password
18
- @password = ask("Password for #{@user}: ") { |q| q.echo = "x" }
19
- end
37
+ @prompter = SSHwrap::Prompter.new
38
+ @ssh_prompt = "Password for #{@user}: "
39
+
40
+ if conf['password_regexp']
41
+ @password_regexp = Regexp.new('(' + conf['password_regexp'] + ')')
42
+ elsif options[:password_regexp]
43
+ @password_regexp = options[:password_regexp]
44
+ else
45
+ # sudo on Mac OS X:
46
+ # Password:
47
+ # sudo on Red Hat, Debian, Ubuntu:
48
+ # [sudo] password for <user>:
49
+ @password_regexp = /(Password: |\[sudo\] password for .*: )/
20
50
  end
21
- @password
22
51
  end
23
52
 
24
53
  def ssh_execute(cmd, target)
@@ -31,9 +60,9 @@ class SSHwrap::Main
31
60
  params[:keys] = [@ssh_key]
32
61
  end
33
62
  using_password = false
34
- if @password
63
+ if @prompter.passwords[@ssh_prompt]
35
64
  using_password = true
36
- params[:password] = @password
65
+ params[:password] = @prompter.passwords[@ssh_prompt]
37
66
  end
38
67
 
39
68
  begin
@@ -63,9 +92,9 @@ class SSHwrap::Main
63
92
  # if it's a password prompt, and interactively return data if so
64
93
  # (see request_pty above).
65
94
  channel.on_data do |ch_data, data|
66
- # This is the standard sudo password prompt
67
- if data =~ /Password:/
68
- channel.send_data "#{get_password}\n"
95
+ if data =~ @password_regexp
96
+ prompt = $1
97
+ channel.send_data "#{@prompter.prompt(prompt)}\n"
69
98
  else
70
99
  stdout << data unless (data.nil? or data.empty?)
71
100
  end
@@ -85,7 +114,7 @@ class SSHwrap::Main
85
114
  end
86
115
  rescue Net::SSH::AuthenticationFailed
87
116
  if !using_password
88
- get_password
117
+ @prompter.prompt(@ssh_prompt)
89
118
  return ssh_execute(cmd, target)
90
119
  else
91
120
  stderr << "Authentication failed to #{target}"
@@ -0,0 +1,15 @@
1
+ class SSHwrap::Prompter
2
+ attr_reader :passwords
3
+ def initialize
4
+ @mutex = Mutex.new
5
+ @passwords = {}
6
+ end
7
+ def prompt(prompt, echo=false)
8
+ @mutex.synchronize do
9
+ if !@passwords[prompt]
10
+ @passwords[prompt] = ask(prompt) { |q| q.echo = echo }
11
+ end
12
+ end
13
+ @passwords[prompt]
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module SSHwrap
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -4,7 +4,7 @@ require File.expand_path('../lib/sshwrap/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ['Jason Heiss']
6
6
  gem.email = ['jheiss@aput.net']
7
- gem.description = 'This provides a wrapper for ssh that execute a command on multiple machines, optionally in parallel, and handles any sudo prompts that result.'
7
+ gem.description = 'This provides a wrapper for ssh that execute a command on multiple machines, optionally in parallel, and handles any ssh and sudo password prompts that result.'
8
8
  gem.summary = 'Perform batch SSH operations, handling sudo prompts'
9
9
  gem.homepage = 'https://github.com/jheiss/sshwrap'
10
10
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sshwrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-13 00:00:00.000000000 Z
12
+ date: 2013-03-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-ssh
@@ -44,7 +44,7 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  description: This provides a wrapper for ssh that execute a command on multiple machines,
47
- optionally in parallel, and handles any sudo prompts that result.
47
+ optionally in parallel, and handles any ssh and sudo password prompts that result.
48
48
  email:
49
49
  - jheiss@aput.net
50
50
  executables:
@@ -61,6 +61,7 @@ files:
61
61
  - bin/sshwrap
62
62
  - lib/sshwrap.rb
63
63
  - lib/sshwrap/main.rb
64
+ - lib/sshwrap/prompter.rb
64
65
  - lib/sshwrap/version.rb
65
66
  - sshwrap.gemspec
66
67
  - test/test_options.rb