ey_info 0.1.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.
@@ -0,0 +1,72 @@
1
+ Ey Info
2
+ =======
3
+
4
+ Summary
5
+ -------
6
+ Quickly set up your ~/.ssh/config shortcuts for your ey cloud servers.
7
+
8
+ Install
9
+ -------
10
+
11
+ <pre>
12
+ gem install --no-ri --no-rdoc ey_info # sudo if you need to
13
+ </pre>
14
+
15
+ Usage Command Line
16
+ -------
17
+
18
+ <pre>
19
+ # will set up your ~/ssh/config shortcuts.
20
+ $ ey_info -i "id_rsa" -u "root" # same as defaults
21
+ $ ey_info # same as above
22
+ </pre>
23
+
24
+ If you're environment in the ey cloud dashboard is called 'production' with an app_master, and 2 app instances.
25
+
26
+ <pre>
27
+ $ ssh production_app_master
28
+ vs
29
+ $ ssh -i ~/.ssh/id-rsa root@ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com
30
+
31
+ $ ssh production_app1
32
+ $ ssh production_app2
33
+ $ ssh production_db_master
34
+ $ ssh production_db_slave1
35
+ </pre>
36
+
37
+ Usage With Capistrano
38
+ -------
39
+
40
+ I still find capistrano a very useful utility for debugging and still use wanted to use it with EY's cloud.
41
+
42
+ <pre>
43
+ $ cap invoke COMMAND="..." is extremely useful. The engineyard gem provides a
44
+ "ey ssh 'uptime' --all -e production" command but it loops through the servers one by one instead of running
45
+ the commands in parallel, which can be slow if you have lots of servers.
46
+ </pre>
47
+
48
+ You can use this gem to dynamically grab the ec2 hosts information from your ey environment and set up your
49
+ capistrano roles.
50
+
51
+ Here are a few examples of how you can use it in your config/deploy.rb:
52
+
53
+ <pre>
54
+ require 'ey_info'
55
+ task :production do
56
+ @info = EyInfo::Hosts.new
57
+ hosts = @info.hosts("production") # parameter is the environment name in EY's gui interface
58
+
59
+ role :db, hosts.find {|x| x[:role] == "app_master" }[:ssh_key], :primary => true
60
+ # app instances
61
+ hosts.select {|x| x[:role] =~ /app/ }.each do |h|
62
+ role :web, h[:ssh_key]
63
+ role :app, h[:ssh_key], :sphinx => true
64
+ end
65
+ # utility instances
66
+ hosts.select {|x| x[:role] =~ /util/ }.each do |h|
67
+ role :web, h[:ssh_key]
68
+ role :app, h[:ssh_key], :sphinx => true
69
+ end
70
+ end
71
+ </pre>
72
+
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../lib/ey_info', __FILE__)
2
+ begin
3
+ require 'jeweler'
4
+ Jeweler::Tasks.new do |gem|
5
+ gem.version = EyInfo::Version
6
+ gem.name = "ey_info"
7
+ gem.executables = %W(ey_info)
8
+ gem.summary = %Q{Ey Info - Easy way to setup ssh keys for ey cloud servers}
9
+ gem.description = %Q{Ey Info - Easy way to setup ssh keys for ey cloud servers and also to dynamically pull server information from your ey servers and just it within capistrano.}
10
+ gem.homepage = "http://github.com/tongueroo/ey_info"
11
+ gem.email = [ "tongueroo@gmail.com" ]
12
+ gem.authors = [ "Tung Nguyen" ]
13
+ gem.add_dependency "engineyard", ">=1.3.11"
14
+ # gem.add_dependency "net-sftp", ">=2.0.0"
15
+ # gem.add_development_dependency "mocha", ">= 0"
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ task :test => :check_dependencies
29
+ task :default => :test
30
+
data/TODO ADDED
@@ -0,0 +1,23 @@
1
+ CloudInfo::Instances outline
2
+ 1. connect to ec2
3
+
4
+ 2. find instances that are in the ey-env
5
+ find ey instances from ey-recipes for specific environment
6
+ grab aws_group from one of the instances in the ey-env
7
+ instances in group
8
+ I can simply also just grab the instances from ey-recipes instead of working back from the aws_group..
9
+
10
+ 3. connect to instances (ssh) and build info
11
+ connect to servers
12
+ download json and store in dictionary lookup
13
+ at this point we have enough data about the servers to build up the info we want
14
+
15
+ 4. hosts
16
+ {:prod_app0 => 'xx.xx.xx.xx', :prod_app1 => 'xx.xx.xx.xx'}
17
+
18
+ ============
19
+ good stopping point:
20
+ * figure out a way to test exception from ssh.connect
21
+ * bad password
22
+ * timeout
23
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../lib/ey_info', __FILE__)
4
+
5
+ EyInfo::CLI.run(ARGV)
@@ -0,0 +1,54 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ey_info}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tung Nguyen"]
12
+ s.date = %q{2011-01-03}
13
+ s.default_executable = %q{ey_info}
14
+ s.description = %q{Ey Info - Easy way to setup ssh keys for ey cloud servers and also to dynamically pull server information from your ey servers and just it within capistrano.}
15
+ s.email = ["tongueroo@gmail.com"]
16
+ s.executables = ["ey_info"]
17
+ s.extra_rdoc_files = [
18
+ "README.markdown",
19
+ "TODO"
20
+ ]
21
+ s.files = [
22
+ "README.markdown",
23
+ "Rakefile",
24
+ "TODO",
25
+ "bin/ey_info",
26
+ "lib/ey_info.rb",
27
+ "lib/templates/default_ssh_config.erb",
28
+ "lib/text_injector.rb",
29
+ "test/ey_info_test.rb",
30
+ "test/test_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/tongueroo/ey_info}
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.7}
35
+ s.summary = %q{Ey Info - Easy way to setup ssh keys for ey cloud servers}
36
+ s.test_files = [
37
+ "test/ey_info_test.rb",
38
+ "test/test_helper.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<engineyard>, [">= 1.3.11"])
47
+ else
48
+ s.add_dependency(%q<engineyard>, [">= 1.3.11"])
49
+ end
50
+ else
51
+ s.add_dependency(%q<engineyard>, [">= 1.3.11"])
52
+ end
53
+ end
54
+
@@ -0,0 +1,190 @@
1
+ require 'yaml'
2
+ require 'rubygems'
3
+ require 'engineyard'
4
+ require 'optparse'
5
+ require 'erb'
6
+ require 'pp'
7
+ require File.expand_path("../text_injector", __FILE__)
8
+
9
+ module EyInfo
10
+ Version = "0.1.0"
11
+
12
+ class CLI
13
+ def self.run(args)
14
+ cli = new(args)
15
+ cli.parse_options!
16
+ cli.run
17
+ end
18
+
19
+ # The array of (unparsed) command-line options
20
+ attr_reader :args
21
+ # The hash of (parsed) command-line options
22
+ attr_reader :options
23
+
24
+ def initialize(args)
25
+ @args = args.dup
26
+ end
27
+
28
+ def option_parser
29
+ # @logger = Logger.new
30
+ @option_parser ||= OptionParser.new do |opts|
31
+ opts.banner = "Usage: #{File.basename($0)} ssh_config"
32
+
33
+ opts.on("-i", "--identity-file [IDENTITY_FILE]", "ssh key default id_rsa.") do |value|
34
+ options[:ssh_key] = value
35
+ end
36
+
37
+ opts.on("-u", "--user [USER]", "ssh key default root.") do |value|
38
+ options[:user] = value
39
+ end
40
+
41
+ opts.on("-h", "--help", "Display this help message.") do
42
+ puts opts
43
+ exit
44
+ end
45
+
46
+ opts.on("-V", "--version",
47
+ "Display the ey_info version, and exit."
48
+ ) do
49
+ puts "EyInfo Version #{EyInfo::Version}"
50
+ exit
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ def parse_options!
57
+ # defaults
58
+ @options = {:actions => [], :user => 'root', :ssh_key => 'id_rsa'}
59
+
60
+ if args.empty?
61
+ warn "Please specifiy an action to execute."
62
+ warn option_parser
63
+ exit 1
64
+ end
65
+
66
+ option_parser.parse!(args)
67
+ extract_environment_variables!
68
+
69
+ options[:actions].concat(args)
70
+ end
71
+
72
+ # Extracts name=value pairs from the remaining command-line arguments
73
+ # and assigns them as environment variables.
74
+ def extract_environment_variables! #:nodoc:
75
+ args.delete_if do |arg|
76
+ next unless arg.match(/^(\w+)=(.*)$/)
77
+ ENV[$1] = $2
78
+ end
79
+ end
80
+
81
+ def run
82
+ write_ssh_config
83
+ puts "Your #{ENV['HOME']}/.ssh/config now has shortcuts your ey cloud servers."
84
+ end
85
+
86
+ def write_ssh_config
87
+ @ssh_config = "#{ENV['HOME']}/.ssh/config"
88
+ @info = EyInfo::Hosts.new
89
+
90
+ # clear out old known_hosts
91
+ `grep -v 'compute-1.amazonaws.com' ~/.ssh/known_hosts > ~/.ssh/known_hosts.tmp`
92
+ `mv ~/.ssh/known_hosts.tmp ~/.ssh/known_hosts`
93
+
94
+ # for erb template
95
+ @identify_file = "~/.ssh/#{options[:ssh_key]}"
96
+ @user = options[:user]
97
+
98
+ if File.exist?(@ssh_config)
99
+ injector = TextInjector.new(
100
+ :file => @ssh_config,
101
+ :update => true,
102
+ :content => ssh_servers
103
+ )
104
+ else
105
+ injector = TextInjector.new(
106
+ :file => @ssh_config,
107
+ :write => true,
108
+ :content => ssh_servers
109
+ )
110
+ end
111
+ injector.run
112
+ end
113
+
114
+ def ssh_servers
115
+ @hosts = {}
116
+ @info = EyInfo::Hosts.new
117
+ all_hosts = @info.all_hosts
118
+ all_hosts.keys.each do |env_name|
119
+ all_hosts[env_name].each do |server|
120
+ @hosts["#{server[:ssh_key]}"] = server[:hostname]
121
+ end
122
+ end
123
+ # content = IO.readlines(RAILS_ROOT+"/dev/ssh_config.erb").join("")
124
+ content = IO.readlines(File.expand_path("../templates/default_ssh_config.erb", __FILE__)).join("")
125
+ template = ERB.new(content)
126
+ template.result(binding)
127
+ end
128
+
129
+ end
130
+
131
+ class Hosts
132
+ def initialize(options = {})
133
+ @api_token = YAML.load_file(File.expand_path("~/.eyrc"))["api_token"]
134
+ @api = EY::API.new(@api_token)
135
+ @envs = @api.apps.map{ |a| a.environments }
136
+ end
137
+
138
+ def all_hosts
139
+ hosts = {}
140
+ @envs.flatten.map{|x| x.name}.sort.uniq.each do |env_name, index|
141
+ env_name = env_name.to_sym
142
+ arr = []
143
+ app_count = 0
144
+ db_count = 0
145
+
146
+ @api.environments.match_one!(env_name.to_s).instances.sort_by {|x| x.hostname}.each do |i, idx|
147
+ # if i.role == 'app_master'
148
+ # key = "app0"
149
+ # elsif i.role == 'app'
150
+ # app_count += 1
151
+ # key = "app#{app_count}"
152
+ # elsif i.role == 'db_master'
153
+ # key = "db0"
154
+ # elsif i.role == 'db_slave'
155
+ # db_count += 1
156
+ # key = "db#{db_count}"
157
+ # elsif i.role == 'util'
158
+ # key = "#{i.name}"
159
+ # elsif i.role == 'solo'
160
+ # key = "solo"
161
+ # end
162
+
163
+ key = i.role == 'util' ? i.name : i.role
164
+ if key == 'app'
165
+ app_count += 1
166
+ key = "app#{app_count}"
167
+ elsif key == 'db_slave'
168
+ db_count += 1
169
+ key = "db_slave#{db_count}"
170
+ end
171
+
172
+ arr << {
173
+ :ssh_key => "#{env_name}_#{key}",
174
+ :hostname => i.hostname,
175
+ :role => i.role,
176
+ :name => i.name
177
+ }
178
+ end
179
+
180
+ hosts[env_name] = arr
181
+ end
182
+ hosts
183
+ end
184
+
185
+ def hosts(env_name)
186
+ all_hosts[env_name.to_sym]
187
+ end
188
+
189
+ end
190
+ end
@@ -0,0 +1,12 @@
1
+ ##########################################
2
+ # ey cloud environments
3
+ StrictHostKeyChecking no
4
+
5
+ <% @hosts.keys.sort.each do |name| %>
6
+ Host <%= name %>
7
+ Hostname <%= @hosts[name] %>
8
+ Port 22
9
+ User <%= @user %>
10
+ IdentityFile <%= @identify_file %>
11
+
12
+ <% end %>
@@ -0,0 +1,92 @@
1
+ class TextInjector
2
+ def initialize(options={})
3
+ @options = options
4
+
5
+ @options[:file] ||= raise "required :file option missing"
6
+ @identifier ||= (@options[:identifier] || default_identifier)
7
+ @content ||= @options[:content]
8
+
9
+ if @options[:update] && !File.exists?(@options[:file])
10
+ warn("[fail] Can't find file: #{@options[:file]}")
11
+ exit(1)
12
+ end
13
+
14
+ if @options[:update] && @options[:write]
15
+ warn("[fail] Can't update AND write. choose one.")
16
+ exit(1)
17
+ end
18
+ end
19
+
20
+ # both setter and getter for the dsl
21
+ def content(text = nil)
22
+ text.nil? ? @content : @content = text
23
+ end
24
+ def identifier(id = nil)
25
+ id.nil? ? @identifier : @identifier = id
26
+ end
27
+
28
+ def run
29
+ if @options[:update]
30
+ write_file(updated_file)
31
+ elsif @options[:write]
32
+ write_file(marked_content)
33
+ else
34
+ puts marked_content
35
+ exit
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def default_identifier
42
+ File.expand_path(@options[:file])
43
+ end
44
+
45
+ def marked_content
46
+ @marked_content ||= [comment_open, @content, comment_close].join("\n")
47
+ end
48
+
49
+ def read_file
50
+ return @current_file if @current_file
51
+ results = ''
52
+ File.open(@options[:file], 'r') {|f| results = f.readlines.join("") }
53
+ @current_file = results
54
+ end
55
+
56
+ def write_file(contents)
57
+ File.open(@options[:file], 'w') do |file|
58
+ file.write(contents)
59
+ end
60
+ end
61
+
62
+ def updated_file
63
+ # Check for unopened or unclosed identifier blocks
64
+ if read_file.index(comment_open) && !read_file.index(comment_close)
65
+ warn "[fail] Unclosed indentifier; Your file contains '#{comment_open}', but no '#{comment_close}'"
66
+ exit(1)
67
+ elsif !read_file.index(comment_open) && read_file.index(comment_close)
68
+ warn "[fail] Unopened indentifier; Your file contains '#{comment_close}', but no '#{comment_open}'"
69
+ exit(1)
70
+ end
71
+
72
+ # If an existing identifier block is found, replace it with the content text
73
+ if read_file.index(comment_open) && read_file.index(comment_close)
74
+ read_file.gsub(Regexp.new("#{comment_open}.+#{comment_close}", Regexp::MULTILINE), marked_content)
75
+ else # Otherwise, append the new content after
76
+ [read_file, marked_content].join("\n\n")
77
+ end
78
+ end
79
+
80
+ def comment_base
81
+ "TextInjector marker for: #{@identifier}"
82
+ end
83
+
84
+ def comment_open
85
+ "# Begin #{comment_base}"
86
+ end
87
+
88
+ def comment_close
89
+ "# End #{comment_base}"
90
+ end
91
+
92
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path("../test_helper", __FILE__)
2
+
3
+ class EyInfoTest < Test::Unit::TestCase
4
+ def setup
5
+ @info = EyInfo::Hosts.new
6
+ end
7
+
8
+ def test_all_hosts_hash
9
+ # pp @info.all_hosts
10
+ assert_equal @info.all_hosts.class, Hash
11
+ assert @info.all_hosts.keys.include?(:beta)
12
+ end
13
+
14
+ def test_hosts_hash
15
+ pp @info.hosts(:alpha)
16
+ assert @info.hosts(:alpha).class, Array
17
+ end
18
+
19
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENV['RAILS_ENV'] = 'test'
4
+
5
+ require 'rubygems'
6
+ require 'test/unit'
7
+ require 'mocha'
8
+ require 'pp'
9
+ require File.expand_path("../../lib/ey_info", __FILE__)
10
+
11
+ module TestExtensions
12
+ end
13
+
14
+ class Test::Unit::TestCase
15
+ include TestExtensions
16
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ey_info
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Tung Nguyen
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-03 00:00:00 -08:00
19
+ default_executable: ey_info
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: engineyard
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 3
33
+ - 11
34
+ version: 1.3.11
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Ey Info - Easy way to setup ssh keys for ey cloud servers and also to dynamically pull server information from your ey servers and just it within capistrano.
38
+ email:
39
+ - tongueroo@gmail.com
40
+ executables:
41
+ - ey_info
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - README.markdown
46
+ - TODO
47
+ files:
48
+ - README.markdown
49
+ - Rakefile
50
+ - TODO
51
+ - bin/ey_info
52
+ - ey_info.gemspec
53
+ - lib/ey_info.rb
54
+ - lib/templates/default_ssh_config.erb
55
+ - lib/text_injector.rb
56
+ - test/ey_info_test.rb
57
+ - test/test_helper.rb
58
+ has_rdoc: true
59
+ homepage: http://github.com/tongueroo/ey_info
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Ey Info - Easy way to setup ssh keys for ey cloud servers
92
+ test_files:
93
+ - test/ey_info_test.rb
94
+ - test/test_helper.rb