aws-ssh 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/awssh +162 -0
  3. metadata +75 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 528f3fee7a959f32e7e5cda371d4e35fe98fe403
4
+ data.tar.gz: d5d3faf114cd04448bd45ea259d4b1a9e69b8428
5
+ SHA512:
6
+ metadata.gz: 037d03e913644404aad34e487c3709d1a62c1b068efe018583c653066dfa7f96f3a1b1b390e6f9ceff0a2651bede193185fa95e5a9b5d2dc9f2c6e346e5c901b
7
+ data.tar.gz: 3560dd269f9687cd9f17a56cdd47b04d34031531887b948b527b537d4f419ab3d4d6a4f8c98aa9a8e53d04646b4b0c927356b530801f5700b6a0b10ba63a2c40
@@ -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 ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws-ssh
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rafael Sales
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: slop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ description: A tool that makes easy to ssh into AWS EC2 servers
42
+ email:
43
+ - rafaelcds@gmail.com
44
+ executables:
45
+ - awssh
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - bin/awssh
50
+ homepage: https://github.com/buzzstarter/awssh
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.4.3
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: A tool that makes easy to ssh into AWS EC2 servers
74
+ test_files: []
75
+ has_rdoc: