awslanes 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f486f2c037fce100109559631026a4d7931b4919
4
+ data.tar.gz: 3f61bf12739800e7a0244106ab8ab168496022f4
5
+ SHA512:
6
+ metadata.gz: 72c8d2819328dc9b3506c57aba600ec84ad1be191539f74ff8cc036f1bac42852c40a5ea66bd0baa19e26e0c0d6dfbe94dd29f65f2cc73d24284823537e318ed
7
+ data.tar.gz: 5adfdabee2bcdf407c54868288920f10bd2f5fb923bb7354d9b6fddfc426ebde3fb55601abb47d2de211563ac59f59c9494e9dd1d75e37819431426cdf246e24
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in awslanes.gemspec
4
+ gemspec
5
+
6
+ gem 'awslanes', :path => ''
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dave Welch
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.
@@ -0,0 +1,34 @@
1
+ # Lanes
2
+
3
+ This helpful little command line tool helps manage "lanes" of servers on AWS.
4
+
5
+ TODO: Describe lanes philosophy
6
+
7
+
8
+ ## Installation & Usage
9
+
10
+ 1. Create some default profiles (TODO: have the app generate this itself)
11
+ ```
12
+ mkdir ~/.lanes
13
+ echo 'profile: myapp' >> ~/.lanes/lanes.yml
14
+ cat <<EOF >> ~/.lanes/myapp.yml
15
+ aws_access_key_id: [AWS_ACCESS_KEY_HERE
16
+ aws_secret_access_key: [AWS_SECRET_KEY_HERE]
17
+ ssh:
18
+ mods:
19
+ dev:
20
+ identity: ~/.ssh/myapp-dev.pem
21
+ tunnel: 7979:localhost:5432
22
+ EOF
23
+ ```
24
+ 2. Install the gem: `gem install awslanes`
25
+ 3. Run it and toy around: `lanes`
26
+
27
+
28
+ ## Contributing
29
+
30
+ 1. Fork it ( https://github.com/lemniscate/aws-lanes/fork )
31
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
32
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
33
+ 4. Push to the branch (`git push origin my-new-feature`)
34
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lanes/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "awslanes"
8
+ spec.version = AwsLanes::VERSION
9
+ spec.authors = ["Dave Welch"]
10
+ spec.email = ["david@davidwelch.co"]
11
+ spec.summary = %q{Manage "lanes" of AWS machines}
12
+ spec.description = %q{Manage "lanes" of AWS machines, according to [principle here]}
13
+ spec.homepage = "https://github.com/Lemniscate/aws-lanes"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ # spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.executables << 'lanes'
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_dependency "thor"
26
+ spec.add_dependency "awscli"
27
+ spec.add_dependency "rest_client"
28
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'lanes'
4
+
5
+ # load the Lanes settings file
6
+ config = YAML.load_file( ENV['HOME'] + '/.lanes/lanes.yml')
7
+ profile = config['profile']
8
+
9
+ # hijack the AwsCli file variable
10
+ ENV['AWSCLI_CONFIG_FILE']="~/.lanes/#{profile}.yml"
11
+
12
+ # Populate our properties singleton as well
13
+ settings = YAML.load_file( ENV['HOME'] + "/.lanes/#{profile}.yml")
14
+
15
+ Props.instance.set(settings)
16
+ Lanes.start(ARGV)
17
+
18
+ # TODO close the connection in the singleton
@@ -0,0 +1,153 @@
1
+ require "lanes/version"
2
+ require "lanes/aws"
3
+ require "lanes/props"
4
+ require "thor"
5
+ require 'yaml'
6
+ require 'AwsCli'
7
+ require 'AwsCli/CLI/EC2/Instances'
8
+ require 'rest_client'
9
+
10
+ class Lanes < Thor
11
+ desc "list [LANE]", "Lists all servers name + ip + Instance ID, optionally filtered by lane 2"
12
+ def list(lane=nil)
13
+ servers = AWS.instance.fetchServers(lane)
14
+ servers.sort_by{ |s| s[:lane] }
15
+ servers.each{|server|
16
+ puts "\t%{name} (%{lane}) \t %{ip} \t %{id} " % server
17
+ }
18
+ end
19
+
20
+ desc "ssh [LANE]", "Lists all servers name + ip + Instance ID, optionally filtered by lane, and prompts which one for ssh"
21
+ def ssh(lane=nil)
22
+ chosen = chooseServer(lane)
23
+ if chosen != nil
24
+ mods = Props.instance.sshMod(chosen[:lane])
25
+ identity = if mods['identity'] then '-i ' + mods['identity'] else '' end
26
+ tunnel = if mods['tunnel'] then '-L' + mods['tunnel'] else '' end
27
+
28
+ cmd = "ssh ec2-user@%{ip} #{identity} #{tunnel}" % chosen
29
+ exec cmd
30
+ else
31
+ puts 'Canceled'
32
+ end
33
+ end
34
+
35
+ method_option :cmd, :type => :array
36
+ method_option :urlConfirm, :type => :string
37
+ method_option :urlConfirmTimeout, :type => :numeric
38
+ method_option :v, :type => :boolean
39
+ desc "sh [LANE] ", "Executes a command on all machines with support for confirming an endpoint is available after"
40
+ def sh(lane)
41
+ servers = AWS.instance.fetchServers(lane)
42
+ servers.sort_by{ |s| s[:ip] }
43
+
44
+ puts "Available Servers: "
45
+ servers.each_with_index {|server|
46
+ puts "\t%{name} (%{lane}) \t %{ip} \t %{id} " % server
47
+ }
48
+
49
+
50
+ mods = Props.instance.sshMod(lane)
51
+ identity = if mods['identity'] then mods['identity'] else '' end
52
+ puts "Identity file #{mods['identity']} will be used" if identity
53
+
54
+ if options[:confirm] then
55
+ puts "Confirmed via command line. Moving forward with execution"
56
+ else
57
+ command = options[:cmd].join(' ')
58
+ confirm = ask "Type CONFIRM to execute \"#{command} \" on these machines:"
59
+ if confirm == 'CONFIRM' then
60
+ servers.each{ |server|
61
+ Net::SSH.start( server[:ip], 'ec2-user',
62
+ :keys => [identity],
63
+ # :verbose => :debug,
64
+ :encryption => "blowfish-cbc",
65
+ :compression => "zlib",
66
+ :host_key => "ssh-rsa") do |ssh|
67
+ puts "Executing on %{name} ( %{ip} ):\t #{command} \n" % server
68
+ stdout = ''
69
+ ssh.exec!(command) do |channel, stream, data|
70
+ stdout << data
71
+ end
72
+ puts "Completed. %{name}\n\tOutput: #{stdout}\n\n " % server
73
+ end
74
+ }
75
+
76
+
77
+ confirmPath = options[:urlConfirm]
78
+ if confirmPath != nil then
79
+ confirmTimeout = (options[:urlConfirmTimeout] or 30);
80
+ startTime = Time.new.to_i
81
+
82
+ # we better sleep for a few, otherwise the shutdown won't have executed
83
+ puts "Sleeping for 5 seconds, then trying the confirmation endpoint for #{confirmTimeout} seconds..."
84
+ sleep 5
85
+ while Time.new.to_i - startTime < confirmTimeout && servers.length > 0 do
86
+ servers.each_with_index{ |server, index|
87
+ begin
88
+ res = RestClient.get (confirmPath % server)
89
+ if res.code >= 200 && res.code < 300 then
90
+ puts "\t => #{server[:ip]} responded with #{res.code}"
91
+ servers.delete_at(index)
92
+ else
93
+ puts "\t XX #{server[:ip]} responded with #{res.code}" if options[:v]
94
+ end
95
+ rescue => e
96
+ puts "\t XX #{server[:ip]} connection failed: #{e}" if options[:v]
97
+ end
98
+ }
99
+
100
+ sleep 5 if servers.length > 0
101
+ puts "\t => #{servers.length} server(s) remaining..." if servers.length > 0
102
+ end
103
+
104
+ if servers.length == 0 then
105
+ puts "Successfully confirmed endpoints responded with a 2XX"
106
+ else
107
+ puts "The following server(s) did not respond with a 2XX:"
108
+ servers.each{ |server|
109
+ puts "\t%{name} (%{lane}) \t %{ip} \t %{id} " % server
110
+ }
111
+ end
112
+ end
113
+ else
114
+ puts 'Aborted!'
115
+ exit 1
116
+ end
117
+ end
118
+ end
119
+
120
+
121
+ no_commands{
122
+ def chooseServer(lane=nul)
123
+ servers = AWS.instance.fetchServers(lane)
124
+ servers.sort_by{ |s| s[:lane] }
125
+
126
+ puts "Available Servers: "
127
+ servers.each_with_index {|server, index|
128
+ i = index + 1
129
+ puts "\t#{i}) %{name} (%{lane}) \t %{ip} \t %{id} " % server
130
+ }
131
+
132
+ choice = ask "Which server: "
133
+ chosen = servers[ choice.to_i - 1 ] if choice != ''
134
+ end
135
+ }
136
+ end
137
+
138
+ if ENV['RUBYMINE'] != nil
139
+ # load the Lanes settings file
140
+ config = YAML.load_file( ENV['HOME'] + '/.lanes/lanes.yml')
141
+ profile = config['profile']
142
+
143
+ # hijack the AwsCli file variable
144
+ ENV['AWSCLI_CONFIG_FILE']="~/.lanes/#{profile}.yml"
145
+
146
+ # Populate our properties singleton as well
147
+ settings = YAML.load_file( ENV['HOME'] + "/.lanes/#{profile}.yml")
148
+
149
+ Props.instance.set(settings)
150
+ Lanes.start( ENV['RUBYMINE'].split(' ') )
151
+ # TODO close the connection in the singleton
152
+ end
153
+
@@ -0,0 +1,30 @@
1
+ require 'singleton'
2
+
3
+ class AWS
4
+ include Singleton
5
+
6
+ def initialize
7
+ @conn = Awscli::Connection.new.request_ec2('us-west-2')
8
+ end
9
+
10
+ # Fetch any servers in a given lane
11
+ def fetchServers(lane=nil)
12
+ servers = []
13
+
14
+ @conn.servers.each{ |server|
15
+ s = {
16
+ :ip => server.public_ip_address,
17
+ :lane => server.tags['Lane'],
18
+ :name => server.tags['Name'],
19
+ :id => server.id
20
+ }
21
+ if s[:ip]
22
+ if s[:lane] != nil and (lane == nil or lane == s[:lane])
23
+ servers.push s
24
+ end
25
+ end
26
+ };
27
+
28
+ return servers
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ require 'singleton'
2
+
3
+ class Props
4
+ include Singleton
5
+
6
+ def initialize
7
+ @props = {}
8
+ end
9
+
10
+ def get(key)
11
+ @props[key]
12
+ end
13
+
14
+ def set(props)
15
+ @props = props
16
+ @props.delete 'aws_access_key_id'
17
+ @props.delete 'aws_secret_access_key'
18
+
19
+ # puts @props
20
+ end
21
+
22
+ def sshMod(lane)
23
+ ssh = @props['ssh']
24
+ if ssh then
25
+ mods = ssh['mods']
26
+ if mods then
27
+ p = mods[lane]
28
+ return p
29
+ end
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,3 @@
1
+ module AwsLanes
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,2 @@
1
+ To test it locally:
2
+ ```gem build awslanes.gemspec && gem install awslanes-*.gem```
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awslanes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dave Welch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: awscli
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest_client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Manage "lanes" of AWS machines, according to [principle here]
84
+ email:
85
+ - david@davidwelch.co
86
+ executables:
87
+ - lanes
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - awslanes.gemspec
97
+ - bin/lanes
98
+ - lib/lanes.rb
99
+ - lib/lanes/aws.rb
100
+ - lib/lanes/props.rb
101
+ - lib/lanes/version.rb
102
+ - notes.md
103
+ homepage: https://github.com/Lemniscate/aws-lanes
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.0.2
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Manage "lanes" of AWS machines
127
+ test_files: []