skipper-ssh 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 925d869492d476537b3ce3bbaebbd43458e19c41
4
+ data.tar.gz: d7f386189a0403db3297b026e771dc57f05ca64a
5
+ SHA512:
6
+ metadata.gz: b2de854783362763f24cb723a5538192796d9bd03f1d23a288f33116bf3db0b8c85e5202e84fc982ff9f1bfcb617d8e76292b5507b0c85cfce9f5e74bd932ab3
7
+ data.tar.gz: 3fd05b6fed7c0cce260a228f607e262e6760873e5baa71d3c1e7e26d48050e28308566ded55189abb7cb6b45ce383aa317845e91c2c38fd57e507ad6fc2f3f16
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in skipper.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 James Brennan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Skipper
2
+
3
+ A captain for your fleet.
4
+
5
+ ## Basic Usage
6
+
7
+ ### REPL Commands
8
+
9
+ ```
10
+ > help
11
+ Skipper Help
12
+
13
+ help - this message
14
+ servers - list the servers that commands will be executed on
15
+ exit - bye, bye
16
+ ```
17
+
18
+ ### Command Line Options
19
+
20
+ ```
21
+ Usage:
22
+ skipper
23
+
24
+ Options:
25
+ [--servers=one two three]
26
+ [--region=REGION]
27
+ # Default: us-east-1
28
+ [--tags=key:value]
29
+ [--auto-scaling-groups=one two three]
30
+ [--auto-scaling-roles=one two three]
31
+ [--identity-file=IDENTITY_FILE]
32
+ [--forward-agent=FORWARD_AGENT]
33
+ [--user=USER]
34
+ # Default: `whoami`
35
+ [--run-in=RUN_IN]
36
+ [--wait=N]
37
+ [--limit=N]
38
+ [--output], [--no-output]
39
+ # Default: true
40
+ [--file=FILE]
41
+
42
+ Run a command on remote servers
43
+ ```
44
+
45
+ ```
46
+ # Get a SSH for multiple servers
47
+ skipper --servers server-1.example.com server-2.example.com
48
+
49
+ # Use a SSH identity file other than your default
50
+ skipper --identity-file path/to/id_rsa.pub
51
+
52
+ # Enable SSH forward agent
53
+ skipper --forward-agent
54
+
55
+ # Set the SSH username (defaults to `whoami`)
56
+ skipper --user myusername
57
+
58
+ # Limit output (do no display the output of commands)
59
+ skipper --no-output
60
+
61
+ # Run commands from STDIN
62
+ echo 'pwd' | skipper
63
+
64
+ # Run commands from a file
65
+ skipper --file myscript.sh
66
+ ```
67
+
68
+ #### Running Commands in Sequence or Parallel
69
+
70
+ By default, commands will run on all servers in parallel.
71
+
72
+ ```
73
+ # Only run on two instances at one
74
+ skipper --limit 2
75
+
76
+ # Run on only one server at a time
77
+ skipper --run-in sequence # or
78
+ skipper --limit 1
79
+
80
+ # Wait 5 seconds between server groups (default group size is 1)
81
+ skipper --wait 5
82
+ ```
83
+
84
+ #### Search AWS EC2 Instances
85
+
86
+ ```
87
+ # Skipper can only run in the context of one region (default is `us-east-1`)
88
+ skipper --region us-west-1
89
+
90
+ # By tag(s)
91
+ skipper --tags name:value
92
+
93
+ # By auto scaling group name
94
+ skipper --auto-scaling-group groupname
95
+
96
+ # By auto scaling role
97
+ skipper --auto-scaling-role rolename
98
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/skipper ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+ require 'skipper'
6
+
7
+ $thor_runner = true
8
+ Skipper::Cli.start
@@ -0,0 +1,34 @@
1
+ module Skipper
2
+ module Banner
3
+
4
+ def self.print
5
+ puts %q[
6
+ SSSSSSSSSSSSSSS kkkkkkkk iiii
7
+ SS:::::::::::::::Sk::::::k i::::i
8
+ S:::::SSSSSS::::::Sk::::::k iiii
9
+ S:::::S SSSSSSSk::::::k
10
+ S:::::S k:::::k kkkkkkkiiiiiiippppp ppppppppp ppppp ppppppppp eeeeeeeeeeee rrrrr rrrrrrrrr
11
+ S:::::S k:::::k k:::::k i:::::ip::::ppp:::::::::p p::::ppp:::::::::p ee::::::::::::ee r::::rrr:::::::::r
12
+ S::::SSSS k:::::k k:::::k i::::ip:::::::::::::::::p p:::::::::::::::::p e::::::eeeee:::::eer:::::::::::::::::r
13
+ SS::::::SSSSS k:::::k k:::::k i::::ipp::::::ppppp::::::ppp::::::ppppp::::::pe::::::e e:::::err::::::rrrrr::::::r
14
+ SSS::::::::SS k::::::k:::::k i::::i p:::::p p:::::p p:::::p p:::::pe:::::::eeeee::::::e r:::::r r:::::r
15
+ SSSSSS::::S k:::::::::::k i::::i p:::::p p:::::p p:::::p p:::::pe:::::::::::::::::e r:::::r rrrrrrr
16
+ S:::::S k:::::::::::k i::::i p:::::p p:::::p p:::::p p:::::pe::::::eeeeeeeeeee r:::::r
17
+ S:::::S k::::::k:::::k i::::i p:::::p p::::::p p:::::p p::::::pe:::::::e r:::::r
18
+ SSSSSSS S:::::Sk::::::k k:::::k i::::::ip:::::ppppp:::::::p p:::::ppppp:::::::pe::::::::e r:::::r
19
+ S::::::SSSSSS:::::Sk::::::k k:::::k i::::::ip::::::::::::::::p p::::::::::::::::p e::::::::eeeeeeee r:::::r
20
+ S:::::::::::::::SS k::::::k k:::::k i::::::ip::::::::::::::pp p::::::::::::::pp ee:::::::::::::e r:::::r
21
+ SSSSSSSSSSSSSSS kkkkkkkk kkkkkkkiiiiiiiip::::::pppppppp p::::::pppppppp eeeeeeeeeeeeee rrrrrrr
22
+ p:::::p p:::::p
23
+ p:::::p p:::::p
24
+ p:::::::p p:::::::p
25
+ p:::::::p p:::::::p
26
+ p:::::::p p:::::::p
27
+ ppppppppp ppppppppp
28
+
29
+ ]
30
+ end
31
+
32
+ end
33
+ end
34
+
@@ -0,0 +1,39 @@
1
+ module Skipper
2
+ class Cli < Thor
3
+ include Thor::Actions
4
+
5
+ namespace :default
6
+ default_task :ssh
7
+
8
+ desc 'ssh', 'Run a command on remote servers'
9
+ method_option :servers, type: :array
10
+
11
+ method_option :region, type: :string, default: 'us-east-1'
12
+ method_option :tags, type: :hash, default: {}
13
+ method_option :auto_scaling_groups, type: :array, default: []
14
+ method_option :auto_scaling_roles, type: :array, default: []
15
+
16
+ method_option :identity_file, type: :string
17
+ method_option :forward_agent, tyep: :boolean, default: false
18
+ method_option :user, type: :string, default: `whoami`.strip
19
+
20
+ method_option :run_in, type: :string
21
+ method_option :wait, type: :numeric
22
+ method_option :limit, type: :numeric
23
+ method_option :output, type: :boolean, default: true
24
+
25
+ method_option :file, type: :string
26
+ def ssh
27
+ Skipper::Banner.print
28
+
29
+ if Skipper::File.stdin_has_data?
30
+ Skipper::File.new(options, self).run($stdin)
31
+ elsif options.file?
32
+ Skipper::File.new(options, self).run(::File.new(options.file))
33
+ else
34
+ Skipper::Repl.new(options, self).run
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require 'fcntl'
2
+
3
+ module Skipper
4
+ class File
5
+ attr_reader :options, :cli
6
+
7
+ def initialize(options, cli)
8
+ @options = options
9
+ @cli = cli
10
+
11
+ if options.servers?
12
+ servers = Skipper::Servers::Basic.new(options)
13
+ else
14
+ servers = Skipper::Servers::EC2.new(options)
15
+ end
16
+
17
+ @runner = Skipper::Runner.new(servers, options, cli)
18
+ end
19
+
20
+ def self.stdin_has_data?
21
+ $stdin.fcntl(Fcntl::F_GETFL, 0) == 0
22
+ end
23
+
24
+ def run(file)
25
+ @runner.run(file.read)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,71 @@
1
+ require 'readline'
2
+
3
+ module Skipper
4
+ class Repl
5
+ attr_accessor :options, :runner, :cli, :servers
6
+
7
+ def initialize(options, cli)
8
+ @options = options
9
+ @cli = cli
10
+
11
+ if options.servers?
12
+ @servers = Skipper::Servers::Basic.new(options)
13
+ else
14
+ @servers = Skipper::Servers::EC2.new(options)
15
+ end
16
+
17
+ @runner = Skipper::Runner.new(@servers, options, cli)
18
+ end
19
+
20
+ def run
21
+ loop do
22
+ begin
23
+ repl
24
+ rescue Interrupt
25
+ puts ''
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def repl
33
+ while command = Readline.readline("> ", true)
34
+ handle_command(command.chomp)
35
+ end
36
+ end
37
+
38
+ def handle_command(command)
39
+ case command
40
+ when 'h'
41
+ when 'help'
42
+ print_help
43
+ when 'servers'
44
+ print_servers
45
+ when 'quit'
46
+ when 'exit'
47
+ quit
48
+ else
49
+ runner.run(command)
50
+ end
51
+ end
52
+
53
+ def print_help
54
+ puts %q[Skipper Help
55
+
56
+ help - this message
57
+ servers - list the servers that commands will be executed on
58
+ exit - bye, bye]
59
+ end
60
+
61
+ def print_servers
62
+ puts servers.to_s
63
+ end
64
+
65
+ def quit
66
+ puts 'See ya!'
67
+ exit 0
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,64 @@
1
+ require 'sshkit'
2
+ require 'sshkit/dsl'
3
+
4
+ module Skipper
5
+ class Runner
6
+
7
+ def initialize(servers, options = {}, cli)
8
+ @servers = servers
9
+ @options = options
10
+ @cli = cli
11
+
12
+ SSHKit::Backend::Netssh.configure do |ssh|
13
+ ssh.ssh_options = ssh_options
14
+ end
15
+
16
+ SSHKit.config.output_verbosity = Logger::DEBUG if options.output?
17
+ end
18
+
19
+ def run(command)
20
+ on servers.hosts, on_options do
21
+ execute command
22
+ end
23
+ rescue SSHKit::Runner::ExecuteError => e
24
+ cli.say e, :red
25
+ rescue Interrupt
26
+ puts ''
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :servers, :options, :cli
32
+
33
+ def run_in
34
+ return options.run_in.to_sym if options.run_in?
35
+
36
+ if options.limit?
37
+ :groups
38
+ elsif options.wait?
39
+ :sequence
40
+ else
41
+ :parallel
42
+ end
43
+ end
44
+
45
+ def on_options
46
+ opts = { in: run_in }
47
+
48
+ [:limit, :wait].each do |key|
49
+ opts[key] = options[key].to_i if options.send("#{key}?")
50
+ end
51
+
52
+ opts
53
+ end
54
+
55
+ def ssh_options
56
+ opts = {}
57
+ opts[:keys] = [options.identity_file] if options.identiy_file?
58
+ opts[:user] = options.user
59
+ opts[:forward_agent] = options.foward_agent
60
+ opts
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,17 @@
1
+ module Skipper
2
+ module Servers
3
+ class Basic
4
+
5
+ attr_reader :hosts
6
+
7
+ def initialize(options)
8
+ @hosts = options.servers
9
+ end
10
+
11
+ def to_s
12
+ @hosts.join("\n")
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,70 @@
1
+ require 'aws'
2
+ require 'table_print'
3
+
4
+ module Skipper
5
+ module Servers
6
+ class EC2
7
+ attr_reader :options
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def instances
14
+ @instances ||= find_instances
15
+ end
16
+
17
+ def hosts
18
+ @hosts ||= instances.map { |instance| instance.ip_address }
19
+ end
20
+
21
+ def to_s
22
+ @to_s ||= details_table(instances)
23
+ end
24
+
25
+ private
26
+
27
+ def ec2
28
+ @ec2 ||= AWS::EC2.new(region: options[:region])
29
+ end
30
+
31
+ def find_instances
32
+ filtered = filter_tags(ec2.instances)
33
+ filtered = filter_auto_scaling_groups(filtered)
34
+ filter_auto_scaling_roles(filtered)
35
+ end
36
+
37
+ def filter_tags(filtered)
38
+ options.tags.each do |tag, value|
39
+ filtered = filtered.filter("tag:#{tag}", value.split(','))
40
+ end
41
+ filtered
42
+ end
43
+
44
+ def filter_auto_scaling_groups(filtered)
45
+ options.auto_scaling_groups.each do |value|
46
+ filtered = filtered.filter('tag:aws:autoscaling:groupName', value)
47
+ end
48
+ filtered
49
+ end
50
+
51
+ def filter_auto_scaling_roles(filtered)
52
+ options.auto_scaling_roles.each do |value|
53
+ filtered = filtered.filter('tag:aws:autoscaling:role', value)
54
+ end
55
+ filtered
56
+ end
57
+
58
+ def details_table(list)
59
+ table = StringIO.new
60
+ original_stdout, $stdout = $stdout, table
61
+
62
+ tp(list, :id, :ip_address)
63
+
64
+ $stdout = original_stdout
65
+ table.read
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Skipper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1 @@
1
+ require 'skipper'
data/lib/skipper.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'thor'
2
+ require 'thor/runner'
3
+ require 'skipper/version'
4
+ require 'skipper/banner'
5
+ require 'skipper/runner'
6
+ require 'skipper/servers/basic'
7
+ require 'skipper/servers/ec2'
8
+ require 'skipper/cli'
9
+ require 'skipper/repl'
10
+ require 'skipper/file'
11
+
12
+ module Skipper
13
+ end
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'skipper/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'skipper-ssh'
7
+ spec.version = Skipper::VERSION
8
+ spec.authors = ['James Brennan']
9
+ spec.email = ['james@jamesbrennan.ca']
10
+ spec.summary = 'A captain for your fleet.'
11
+ spec.description = 'An interactive SSH shell for multiple remote hosts, with EC2 search functionality.'
12
+ spec.homepage = 'https://github.com/jpb/skipper-ssh'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files`.split("\n")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'sshkit', '1.5.1'
21
+ spec.add_dependency 'thor', '0.19.1'
22
+ spec.add_dependency 'table_print', '1.5.2'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
25
+ spec.add_development_dependency 'rake', '~> 10.3.2'
26
+ spec.add_development_dependency 'rspec', '~> 3.0.0'
27
+ spec.add_development_dependency 'vcr', '~> 2.9.2'
28
+ spec.add_development_dependency 'simplecov', '~> 0.8.2'
29
+ spec.add_development_dependency 'webmock', '~> 1.18.0'
30
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+ require 'skipper/runner'
3
+ require 'thor/core_ext/hash_with_indifferent_access'
4
+
5
+ describe Skipper::Runner do
6
+
7
+ describe '#run' do
8
+ let(:servers) { double(hosts: ['example.com']) }
9
+ let(:params) { {} }
10
+ let(:options) { Thor::CoreExt::HashWithIndifferentAccess.new(params) }
11
+ let(:cli) { double(say: nil, execute: nil) }
12
+ let(:command) { 'echo cats' }
13
+ let(:runner) { Skipper::Runner.new(servers, options, cli) }
14
+ subject { runner }
15
+
16
+ before do
17
+ runner.stub(:execute)
18
+ end
19
+
20
+ context 'options' do
21
+ before do
22
+ runner.stub(:on).and_yield
23
+ runner.run(command)
24
+ end
25
+
26
+ context 'no params' do
27
+ it { should have_received(:on).with(['example.com'], in: :parallel) }
28
+ end
29
+
30
+ context 'with --limit' do
31
+ let(:params) { { limit: 5 } }
32
+ it { should have_received(:on).with(['example.com'], in: :groups, limit: 5) }
33
+ end
34
+
35
+ context 'with --limit and --wait' do
36
+ let(:params) { { limit: 5, wait: 10 } }
37
+ it { should have_received(:on).with(['example.com'], in: :groups, limit: 5, wait: 10) }
38
+ end
39
+
40
+ context 'with --wait' do
41
+ let(:params) { { wait: 10 } }
42
+ it { should have_received(:on).with(['example.com'], in: :sequence, wait: 10) }
43
+ end
44
+
45
+ context 'with --run-in' do
46
+ let(:params) { { run_in: 'cats' } }
47
+ it { should have_received(:on).with(['example.com'], in: :cats) }
48
+ end
49
+
50
+ context 'with all options' do
51
+ let(:params) { { run_in: 'cats', limit: 5, wait: 10 } }
52
+ it { should have_received(:on).with(['example.com'], in: :cats, limit: 5, wait: 10) }
53
+ end
54
+
55
+ end
56
+
57
+ context 'when Interrupt is encountered' do
58
+ before do
59
+ runner.stub(:on).and_raise(Interrupt.new)
60
+ end
61
+
62
+ it 'does not raise' do
63
+ expect { runner.run(command) }.not_to raise_error
64
+ end
65
+ end
66
+
67
+ context 'when a SSH error occurs' do
68
+ before do
69
+ runner.stub(:on).and_raise(SSHKit::Runner::ExecuteError.new(double(backtrace: 'cats')))
70
+ runner.run(command)
71
+ end
72
+
73
+ it 'does not raise' do
74
+ expect { runner.run(command) }.not_to raise_error
75
+ end
76
+
77
+ it 'should print the error' do
78
+ cli.should have_received(:say).with(instance_of(SSHKit::Runner::ExecuteError), :red)
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,26 @@
1
+ require 'vcr'
2
+ require 'simplecov'
3
+
4
+ SimpleCov.start
5
+
6
+ VCR.configure do |c|
7
+ c.configure_rspec_metadata!
8
+ c.hook_into :webmock
9
+ c.allow_http_connections_when_no_cassette = false
10
+ c.default_cassette_options = { record: :once }
11
+ c.cassette_library_dir = 'spec/support/vcr_cassettes'
12
+ end
13
+
14
+ RSpec.configure do |config|
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+ config.order = 'random'
18
+
19
+ config.mock_with :rspec do |c|
20
+ c.syntax = [:should, :expect]
21
+ end
22
+
23
+ config.expect_with :rspec do |c|
24
+ c.syntax = [:should, :expect]
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skipper-ssh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Brennan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sshkit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.19.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.19.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: table_print
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 10.3.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 10.3.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 3.0.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: vcr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 2.9.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 2.9.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.8.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 0.8.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 1.18.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: 1.18.0
139
+ description: An interactive SSH shell for multiple remote hosts, with EC2 search functionality.
140
+ email:
141
+ - james@jamesbrennan.ca
142
+ executables:
143
+ - skipper
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - .gitignore
148
+ - .rspec
149
+ - Gemfile
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/skipper
154
+ - lib/skipper-ssh.rb
155
+ - lib/skipper.rb
156
+ - lib/skipper/banner.rb
157
+ - lib/skipper/cli.rb
158
+ - lib/skipper/file.rb
159
+ - lib/skipper/repl.rb
160
+ - lib/skipper/runner.rb
161
+ - lib/skipper/servers/basic.rb
162
+ - lib/skipper/servers/ec2.rb
163
+ - lib/skipper/version.rb
164
+ - skipper-ssh.gemspec
165
+ - spec/lib/skipper/runner_spec.rb
166
+ - spec/spec_helper.rb
167
+ homepage: https://github.com/jpb/skipper-ssh
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - '>='
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.2.2
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: A captain for your fleet.
191
+ test_files:
192
+ - spec/lib/skipper/runner_spec.rb
193
+ - spec/spec_helper.rb
194
+ has_rdoc: