aws-ssh 1.0.0

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.
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: