aws-ssh 1.0.0 → 1.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 +4 -4
- data/bin/aws-ssh +162 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78ca737b88d4a338e7f18dfab077b2fe7948d1ba
|
4
|
+
data.tar.gz: 3b14eb94c34a986a0afe5412e5167681ad599b93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7643046e0babf3bd28ee73ebc595148929dd14524aa02992c4b1e91c05f385d31b65521c43470181af647cb0082689eb8aada2567fe21f580a364064dcfbd78b
|
7
|
+
data.tar.gz: fe55c550ecda8d8dfdd1577a06b1ca7a97becce04299218d6d332f95bf1708d4f251b02a2b5c686d4e6a1da3c0913ad01236672e885a58c824d9da719922d83a
|
data/bin/aws-ssh
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'slop'
|
4
|
+
require 'aws-sdk'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module AWSSH
|
8
|
+
class Runner
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
'user' => ENV['user'],
|
11
|
+
'format' => 'ssh',
|
12
|
+
'verbose' => false
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_accessor :host_regex
|
16
|
+
|
17
|
+
def run
|
18
|
+
self.host_regex = cli.args.first
|
19
|
+
exit_error! 'AWS Region not set' unless cli[:region]
|
20
|
+
exit_error! 'AWS Profile not set' unless cli[:profile]
|
21
|
+
|
22
|
+
shout "Hostname: #{host_regex}"
|
23
|
+
shout "Options: #{cli.to_h.inspect}"
|
24
|
+
shout "Defaults: #{defaults.inspect}"
|
25
|
+
|
26
|
+
Aws.config.merge!(profile: cli[:profile], region: cli[:region])
|
27
|
+
|
28
|
+
if cli['show-only']
|
29
|
+
print_output
|
30
|
+
else
|
31
|
+
ssh!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def cli
|
36
|
+
@cli ||= Slop.parse do |o|
|
37
|
+
o.banner = <<-USAGE
|
38
|
+
awssh - a tool that makes easy to ssh into AWS EC2 servers
|
39
|
+
|
40
|
+
Usage: awssh [hostname regex]
|
41
|
+
|
42
|
+
Examples:
|
43
|
+
$ awssh prod.*app2
|
44
|
+
... will SSH into the instance and you will see:
|
45
|
+
user@prod-rails-app4~$
|
46
|
+
|
47
|
+
$ awssh --show-only --stack qa -u worker
|
48
|
+
... will show all instances registered in QA stack of Opsworks
|
49
|
+
ssh worker@10.20.30.40 => MyApp QA - qa-rails-app
|
50
|
+
ssh worker@10.20.30.41 => MyApp QA - qa-sidekiq
|
51
|
+
|
52
|
+
# All hosts in one-line (suitable for CSSH):
|
53
|
+
worker@10.20.30.40 worker@10.20.30.41
|
54
|
+
USAGE
|
55
|
+
|
56
|
+
o.separator "Options:"
|
57
|
+
o.string '-s', '--stack', 'stack name regex. E.g: `-s prod` will match "Production" stack name'
|
58
|
+
o.string '-p', '--profile', 'AWS config profile name. Default: profile set in .awssh file', default: defaults['profile']
|
59
|
+
o.string '-r', '--region', 'region. E.g: us-east-1. Default: region set in .awssh file', default: defaults['region']
|
60
|
+
o.string '-u', '--user', 'SSH username to use. Default: user set in .awssh file or current machine user', default: defaults['user']
|
61
|
+
o.bool '-so', '--show-only', 'Only show the matched hosts instead of ssh. Default: false', default: false
|
62
|
+
o.bool '-cs', '--csensitive', 'Uses case-sensitive for regex matching. Default: false', default: false
|
63
|
+
o.bool '-v', '--verbose', 'Verbose mode. Default: false', default: false
|
64
|
+
o.on '--help', 'Shows help' do
|
65
|
+
puts o
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def ssh!
|
72
|
+
if instances.size > 1
|
73
|
+
print_output
|
74
|
+
exit_error! "\nMultiple hostnames matched. Please be more specific in hostnames regex or use the last output line to use CSSH.\n"
|
75
|
+
end
|
76
|
+
exec "ssh #{connection_string(instances.first)}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def print_output
|
80
|
+
instances.each do |i|
|
81
|
+
puts "ssh #{connection_string(i)} \t => #{i.name}"
|
82
|
+
end
|
83
|
+
puts "\n# All hosts in one-line (suitable for CSSH):"
|
84
|
+
puts instances.map { |i| connection_string(i) }.join(' ')
|
85
|
+
end
|
86
|
+
|
87
|
+
def connection_string(instance)
|
88
|
+
"#{cli[:user]}@#{instance.ip}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def defaults
|
92
|
+
@defaults ||= begin
|
93
|
+
defaults = File.exist?('.awssh') ? YAML.load_file('.awssh') : {}
|
94
|
+
DEFAULT_OPTIONS.merge(defaults)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def instances
|
99
|
+
@instances ||= AWSEC2.new.instances(host_regex, cli[:stack], cli[:csensitive]).select do |i|
|
100
|
+
shout "Instance #{i.name} is not part of an Opsworks Stack" unless i.stack_name
|
101
|
+
shout "Instance #{i.name} not running. Current state: #{i.state}" unless i.running?
|
102
|
+
i.running?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def exit_error!(msg)
|
107
|
+
$stderr.puts msg
|
108
|
+
exit(1)
|
109
|
+
end
|
110
|
+
|
111
|
+
def shout(msg)
|
112
|
+
puts "[DEBUG] #{msg}" if cli.verbose?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
EC2Instance = Struct.new(:name, :hostname, :stack_name, :state, :ip) do
|
117
|
+
def initialize(instance)
|
118
|
+
name = extract_tag(instance, 'Name')
|
119
|
+
hostname = extract_tag(instance, 'opsworks:instance')
|
120
|
+
stack_name = extract_tag(instance, 'opsworks:stack')
|
121
|
+
|
122
|
+
super(name, hostname, stack_name, instance.state.name, instance.public_ip_address)
|
123
|
+
end
|
124
|
+
|
125
|
+
def running?
|
126
|
+
state == 'running'
|
127
|
+
end
|
128
|
+
|
129
|
+
def extract_tag(instance, tag)
|
130
|
+
tag = instance.tags.find { |t| t.key == tag }
|
131
|
+
tag ? tag.value : nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class AWSEC2
|
136
|
+
def instances(host_regex, stack_regex, case_sensitive)
|
137
|
+
ec2.describe_instances.reservations.map(&:instances).flatten.map do |instance_data|
|
138
|
+
instance = EC2Instance.new(instance_data)
|
139
|
+
if stack_regex
|
140
|
+
next unless word_match?(instance.stack_name, stack_regex, case_sensitive)
|
141
|
+
end
|
142
|
+
if host_regex
|
143
|
+
next unless word_match?(instance.hostname, host_regex, case_sensitive)
|
144
|
+
next unless word_match?(instance.name, host_regex, case_sensitive)
|
145
|
+
end
|
146
|
+
|
147
|
+
instance
|
148
|
+
end.compact.sort_by(&:name)
|
149
|
+
end
|
150
|
+
|
151
|
+
def ec2
|
152
|
+
@ec2 ||= Aws::EC2::Client.new
|
153
|
+
end
|
154
|
+
|
155
|
+
def word_match?(value, regex_str, case_sensitive)
|
156
|
+
regex = case_sensitive ? /#{regex_str}/ : /#{regex_str}/i
|
157
|
+
!!(value =~ regex)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
AWSSH::Runner.new.run
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafael Sales
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|
@@ -43,11 +43,13 @@ email:
|
|
43
43
|
- rafaelcds@gmail.com
|
44
44
|
executables:
|
45
45
|
- awssh
|
46
|
+
- aws-ssh
|
46
47
|
extensions: []
|
47
48
|
extra_rdoc_files: []
|
48
49
|
files:
|
50
|
+
- bin/aws-ssh
|
49
51
|
- bin/awssh
|
50
|
-
homepage: https://github.com/buzzstarter/
|
52
|
+
homepage: https://github.com/buzzstarter/aws-ssh
|
51
53
|
licenses:
|
52
54
|
- MIT
|
53
55
|
metadata: {}
|