ec2-host 0.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 +7 -0
- data/.gitignore +17 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +104 -0
- data/Rakefile +30 -0
- data/bin/ec2-host +4 -0
- data/doc.sh +5 -0
- data/ec2-host.gemspec +29 -0
- data/example/aws-sdk.rb +15 -0
- data/example/example.rb +6 -0
- data/lib/ec2-host.rb +9 -0
- data/lib/ec2/host.rb +113 -0
- data/lib/ec2/host/cli.rb +74 -0
- data/lib/ec2/host/client_util.rb +27 -0
- data/lib/ec2/host/config.rb +111 -0
- data/lib/ec2/host/hash_util.rb +11 -0
- data/lib/ec2/host/host_data.rb +128 -0
- data/lib/ec2/host/role_data.rb +60 -0
- data/lib/ec2/host/string_util.rb +31 -0
- data/sample.conf +8 -0
- data/spec/README.md +35 -0
- data/spec/host_spec.rb +163 -0
- data/spec/spec_helper.rb +22 -0
- metadata +241 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 94ae5ab54d79d7e269102382f12b40c31f16c349
|
4
|
+
data.tar.gz: 14ccb9795b4629b607899c7192ad1567e50c4132
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 82e4d30e8df2b2311146a37db0e13e6adac9f70383fb892f4342908401ef37582b4c4ff30defc1f56265f559ba7d7954540b2fc21b0646088b89a94b22aad952
|
7
|
+
data.tar.gz: 43d10651c6b326ff1ab898e0807c366926288b3b7fefed673ce04a006eeb7a1b4f1e0523158e4e09cb01f83708b8a844706945c69617c61e9ebfe39966e4adc6
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Naotoshi Seo
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# ec2-host
|
2
|
+
|
3
|
+
Search hosts on AWS EC2
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install ec2-host
|
9
|
+
```
|
10
|
+
|
11
|
+
## Configuration
|
12
|
+
|
13
|
+
You can write a configuration file located at `/etc/sysconfig/ec2-host` (You can configure this path by `EC2_HOST_CONFIG_FILE` environment variable), or as environment variables:
|
14
|
+
|
15
|
+
AWS SDK (CLI) parameters:
|
16
|
+
|
17
|
+
* **AWS_REGION**; AWS SDK (CLI) region such as `ap-northeast-1`, `us-east-1`.
|
18
|
+
* **AWS_ACCESS_KEY_ID**: AWS SDK (CLI) crendentials. Default loads a credentials file
|
19
|
+
* **AWS_SECRET_ACCESS_KEY**: AWS SDK (CLI) credentials. Default load a credentials file
|
20
|
+
* **AWS_PROFILE**: The profile key of the AWS SDK (CLI) credentails file. Default is `default`
|
21
|
+
* **AWS_CREDENTIALS_FILE**: Path of the AWS SDK (CLI) credentails file. Default is `$HOME/.aws/credentials`. See [Configuring the AWS Command Line Interface](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files) for details.
|
22
|
+
|
23
|
+
ec2-host parameters:
|
24
|
+
|
25
|
+
* **HOSTNAME_TAG**: EC2 tag key used to express a hostname. The default is `Name`.
|
26
|
+
* **ROLES_TAG**: EC2 tag keys used to express roles. The default is `Roles`
|
27
|
+
* You can assign multiple roles seperated by `,` comma
|
28
|
+
* Also, you can express levels of roles delimited by `:`.
|
29
|
+
* Example: admin:ami, then `EC2::Host.new(role: 'admin:ami')` and also `EC2::Host.new(role1: 'admin')` returns this host
|
30
|
+
* **OPTIONAL_STRING_TAGS**: You may add optional non-array tags. You can specify multiple tags like `Service,Status`.
|
31
|
+
* **OPTIONAL_ARRAY_TAGS**: You may add optional array tags. Array tags allows multiple values delimited by `,` (comma) as `Roles` tag.
|
32
|
+
* **LOG_LEVEL**: Log level such as `info`, `debug`, `error`. The default is `info`.
|
33
|
+
|
34
|
+
See [sampel.conf](./sample.conf)
|
35
|
+
|
36
|
+
## Tag Example
|
37
|
+
|
38
|
+
* **Name**: hostname
|
39
|
+
* **Roles**: app:web,app:db
|
40
|
+
* **Service**: sugoi
|
41
|
+
* **Status**: setup
|
42
|
+
|
43
|
+
## CLI Usage
|
44
|
+
|
45
|
+
```
|
46
|
+
$ ec2-host --role1 admin
|
47
|
+
host1
|
48
|
+
ip-XXX-XXX-XXX-XXX # if Name tag is not assigned
|
49
|
+
```
|
50
|
+
|
51
|
+
See `ec2-host help get-hosts` for details:
|
52
|
+
|
53
|
+
```
|
54
|
+
Usage:
|
55
|
+
ec2-host get-hosts
|
56
|
+
|
57
|
+
Options:
|
58
|
+
-h, [--hostname=one two three] # name or private_dns_name
|
59
|
+
--usage, [--role=one two three] # role
|
60
|
+
--r1, --usage1, --u1, [--role1=one two three] # role1, the 1st part of role delimited by :
|
61
|
+
--r2, --usage2, --u2, [--role2=one two three] # role2, the 2nd part of role delimited by :
|
62
|
+
--r3, --usage3, --u3, [--role3=one two three] # role3, the 3rd part of role delimited by :
|
63
|
+
-i, [--info], [--no-info] # show host info, not only hostname
|
64
|
+
[--debug], [--no-debug] # debug mode
|
65
|
+
|
66
|
+
Search EC2 hosts
|
67
|
+
```
|
68
|
+
|
69
|
+
## Library Usage
|
70
|
+
|
71
|
+
See http://sonots.github.io/ec2-host/doc/frames.html.
|
72
|
+
|
73
|
+
## ChangeLog
|
74
|
+
|
75
|
+
See [CHANGELOG.md](CHANGELOG.md) for details.
|
76
|
+
|
77
|
+
## For Developers
|
78
|
+
|
79
|
+
### ToDo
|
80
|
+
|
81
|
+
* Support assume-roles
|
82
|
+
* Use mock/stub to run test (currently, directly accessing to EC2)
|
83
|
+
* Should cache a result of describe-instances in like 30 seconds?
|
84
|
+
|
85
|
+
### How to Run test
|
86
|
+
|
87
|
+
See [spec/README.md](spec/README.md)
|
88
|
+
|
89
|
+
### How to Release Gem
|
90
|
+
|
91
|
+
1. Update gem.version in the gemspec
|
92
|
+
2. Update CHANGELOG.md
|
93
|
+
3. git commit && git push
|
94
|
+
4. Run `bundle exec rake release`
|
95
|
+
|
96
|
+
### How to Update doc
|
97
|
+
|
98
|
+
1. Run `./doc.sh`
|
99
|
+
2. git commit && git push (to gh-pages branch)
|
100
|
+
|
101
|
+
### Licenses
|
102
|
+
|
103
|
+
See [LICENSE](LICENSE)
|
104
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new :spec do |spec|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
task default: :spec
|
10
|
+
rescue LoadError, NameError
|
11
|
+
# OK, they can be absent on non-development mode.
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "irb console"
|
15
|
+
task :console do
|
16
|
+
require_relative "lib/ec2-host"
|
17
|
+
require 'irb'
|
18
|
+
require 'irb/completion'
|
19
|
+
ARGV.clear
|
20
|
+
IRB.start
|
21
|
+
end
|
22
|
+
task :c => :console
|
23
|
+
|
24
|
+
desc "pry console"
|
25
|
+
task :pry do
|
26
|
+
require_relative "lib/ec2-host"
|
27
|
+
require 'pry'
|
28
|
+
ARGV.clear
|
29
|
+
Pry.start
|
30
|
+
end
|
data/bin/ec2-host
ADDED
data/doc.sh
ADDED
data/ec2-host.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = "ec2-host"
|
3
|
+
gem.version = '0.0.1'
|
4
|
+
gem.author = ['Naotoshi Seo']
|
5
|
+
gem.email = ['sonots@gmail.com']
|
6
|
+
gem.homepage = 'https://github.com/sonots/ec2-host'
|
7
|
+
gem.summary = "Search hosts on AWS EC2"
|
8
|
+
gem.description = "Search hosts on AWS EC2"
|
9
|
+
gem.licenses = ['MIT']
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
|
16
|
+
gem.add_runtime_dependency 'aws-sdk'
|
17
|
+
gem.add_runtime_dependency 'hashie'
|
18
|
+
gem.add_runtime_dependency 'thor'
|
19
|
+
gem.add_runtime_dependency 'dotenv'
|
20
|
+
|
21
|
+
gem.add_development_dependency 'yard'
|
22
|
+
gem.add_development_dependency 'rdoc'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'simplecov'
|
25
|
+
gem.add_development_dependency 'pry'
|
26
|
+
gem.add_development_dependency 'pry-nav'
|
27
|
+
gem.add_development_dependency 'rake'
|
28
|
+
gem.add_development_dependency 'bundler'
|
29
|
+
end
|
data/example/aws-sdk.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'aws-sdk'
|
3
|
+
require 'dotenv'
|
4
|
+
Dotenv.load
|
5
|
+
|
6
|
+
# Aws.config.update({
|
7
|
+
# region: 'us-west-2',
|
8
|
+
# credentials: Aws::Credentials.new('akid', 'secret'),
|
9
|
+
# })
|
10
|
+
|
11
|
+
ec2 = Aws::EC2::Client.new
|
12
|
+
pp instances = ec2.describe_instances.reservations.map(&:instances)
|
13
|
+
|
14
|
+
require 'pry'
|
15
|
+
binding.pry
|
data/example/example.rb
ADDED
data/lib/ec2-host.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
3
|
+
require_relative 'ec2/host/string_util'
|
4
|
+
require_relative 'ec2/host/hash_util'
|
5
|
+
require_relative 'ec2/host/config'
|
6
|
+
require_relative 'ec2/host/host_data'
|
7
|
+
require_relative 'ec2/host/role_data'
|
8
|
+
require_relative 'ec2/host/client_util'
|
9
|
+
require_relative 'ec2/host'
|
data/lib/ec2/host.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
class EC2
|
2
|
+
# Search EC2 hosts from tags
|
3
|
+
#
|
4
|
+
# require 'ec2-host'
|
5
|
+
# # Search by `Name` tag
|
6
|
+
# EC2::Host.new(hostname: 'test').first # => test
|
7
|
+
#
|
8
|
+
# # Search by `Roles` tag
|
9
|
+
# EC2::Host.new(
|
10
|
+
# role: 'admin:haikanko',
|
11
|
+
# ).each do |host|
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# or
|
16
|
+
#
|
17
|
+
# EC2::Host.new(
|
18
|
+
# role1: 'admin',
|
19
|
+
# role2: 'haikanko',
|
20
|
+
# ).each do |host|
|
21
|
+
# # ...
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # Or search
|
25
|
+
# EC2::Host.new(
|
26
|
+
# {
|
27
|
+
# role1: 'db',
|
28
|
+
# role2: 'master',
|
29
|
+
# },
|
30
|
+
# {
|
31
|
+
# role1: 'web',
|
32
|
+
# }
|
33
|
+
# ).each do |host|
|
34
|
+
# # ...
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# EC2::Host.me.hostname # => 'test'
|
38
|
+
class Host
|
39
|
+
include Enumerable
|
40
|
+
|
41
|
+
# @return [Host::Data] representing myself
|
42
|
+
def self.me
|
43
|
+
new(instance_id: ClientUtil.get_instance_id).each do |d|
|
44
|
+
return d
|
45
|
+
end
|
46
|
+
raise 'Not Found'
|
47
|
+
end
|
48
|
+
|
49
|
+
# Configure EC2::Host
|
50
|
+
#
|
51
|
+
# @params [Hash] params see EC2::Host::Config for configurable parameters
|
52
|
+
def self.configure(params = {})
|
53
|
+
Config.configure(params)
|
54
|
+
end
|
55
|
+
|
56
|
+
ARRAY_TAG_DELIMITER = ','
|
57
|
+
ROLE_TAG_DELIMITER = ':'
|
58
|
+
|
59
|
+
attr_reader :conditions, :options
|
60
|
+
|
61
|
+
# @param [Array of Hash, or Hash] conditions (and options)
|
62
|
+
#
|
63
|
+
# EC2::Host.new(
|
64
|
+
# hostname: 'test',
|
65
|
+
# options: {a: 'b'}
|
66
|
+
# )
|
67
|
+
#
|
68
|
+
# EC2::Host.new(
|
69
|
+
# {
|
70
|
+
# hostname: 'foo',
|
71
|
+
# },
|
72
|
+
# {
|
73
|
+
# hostname: 'bar',
|
74
|
+
# },
|
75
|
+
# options: {a: 'b'}
|
76
|
+
# )
|
77
|
+
def initialize(*conditions)
|
78
|
+
conditions = [{}] if conditions.empty?
|
79
|
+
conditions = [conditions] if conditions.kind_of?(Hash)
|
80
|
+
@options = {}
|
81
|
+
if conditions.size == 1
|
82
|
+
@options = conditions.first.delete(:options) || {}
|
83
|
+
else
|
84
|
+
index = conditions.find_index {|condition| condition.has_key?(:options) }
|
85
|
+
@options = conditions.delete_at(index)[:options] if index
|
86
|
+
end
|
87
|
+
raise ArgumentError, "Hash expected (options)" unless @options.is_a?(Hash)
|
88
|
+
@conditions = []
|
89
|
+
conditions.each do |condition|
|
90
|
+
@conditions << Hash[condition.map {|k, v| [k, Array(v).map(&:to_s)]}]
|
91
|
+
end
|
92
|
+
raise ArgumentError, "Array of Hash, or Hash expected (conditions)" unless @conditions.all? {|h| h.kind_of?(Hash)}
|
93
|
+
end
|
94
|
+
|
95
|
+
# @yieldparam [Host::Data] data entry
|
96
|
+
def each(&block)
|
97
|
+
@conditions.each do |condition|
|
98
|
+
search(ClientUtil.get_instances, condition, &block)
|
99
|
+
end
|
100
|
+
return self
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def search(instances, condition)
|
106
|
+
instances.each do |i|
|
107
|
+
d = EC2::Host::HostData.initialize(i)
|
108
|
+
next unless d.match?(condition)
|
109
|
+
yield d
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/ec2/host/cli.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'ec2-host'
|
3
|
+
|
4
|
+
class EC2
|
5
|
+
class Host
|
6
|
+
class CLI < Thor
|
7
|
+
default_command :get_hosts
|
8
|
+
|
9
|
+
desc 'get-hosts', 'Search EC2 hosts (default)'
|
10
|
+
option :hostname,
|
11
|
+
:aliases => '-h',
|
12
|
+
:type => :array,
|
13
|
+
:desc => "name or private_dns_name"
|
14
|
+
option :role,
|
15
|
+
:aliases => %w[--usage],
|
16
|
+
:type => :array,
|
17
|
+
:desc => "role"
|
18
|
+
option :role1,
|
19
|
+
:aliases => %w[--r1 --usage1 --u1], # hmm, -r1 is not suppored by thor
|
20
|
+
:type => :array,
|
21
|
+
:desc => "role1, the 1st part of role delimited by #{ROLE_TAG_DELIMITER}"
|
22
|
+
option :role2,
|
23
|
+
:aliases => %w[--r2 --usage2 --u2],
|
24
|
+
:type => :array,
|
25
|
+
:desc => "role2, the 2nd part of role delimited by #{ROLE_TAG_DELIMITER}"
|
26
|
+
option :role3,
|
27
|
+
:aliases => %w[--r3 --usage3 --u3],
|
28
|
+
:type => :array,
|
29
|
+
:desc => "role3, the 3rd part of role delimited by #{ROLE_TAG_DELIMITER}"
|
30
|
+
Config.optional_options.each do |opt, tag|
|
31
|
+
option opt, :type => :array, :desc => opt
|
32
|
+
end
|
33
|
+
option :info,
|
34
|
+
:aliases => %w[-i],
|
35
|
+
:type => :boolean,
|
36
|
+
:desc => "show host info, not only hostname"
|
37
|
+
option :debug,
|
38
|
+
:type => :boolean,
|
39
|
+
:desc => "debug mode"
|
40
|
+
def get_hosts
|
41
|
+
if options[:info]
|
42
|
+
EC2::Host.new(condition).each do |host|
|
43
|
+
$stdout.puts host.info
|
44
|
+
end
|
45
|
+
else
|
46
|
+
EC2::Host.new(condition).each do |host|
|
47
|
+
$stdout.puts host.hostname
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def condition
|
55
|
+
return @condition if @condition
|
56
|
+
_condition = HashUtil.except(options, :info, :debug)
|
57
|
+
@condition = {}
|
58
|
+
_condition.each do |key, val|
|
59
|
+
if tag = Config.optional_options[key.to_s]
|
60
|
+
field = StringUtil.underscore(tag)
|
61
|
+
@condition[field.to_sym] = val
|
62
|
+
else
|
63
|
+
@condition[key.to_sym] = val
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if options[:debug]
|
67
|
+
$stderr.puts(options: options)
|
68
|
+
$stderr.puts(condition: @condition)
|
69
|
+
end
|
70
|
+
@condition
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
class EC2
|
5
|
+
class Host
|
6
|
+
class ClientUtil
|
7
|
+
def self.get_instances
|
8
|
+
# I do not use describe_instances(filter:) because it does not support array tag ..
|
9
|
+
return @instances if @instances
|
10
|
+
Aws.config.update(region: Config.aws_region, credentials: Config.aws_credentials)
|
11
|
+
ec2 = Aws::EC2::Client.new
|
12
|
+
@instances = ec2.describe_instances.reservations.map(&:instances).flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_instance_id
|
16
|
+
return @instance_id if @instance_id
|
17
|
+
begin
|
18
|
+
http_conn = Net::HTTP.new('169.254.169.254')
|
19
|
+
http_conn.open_timeout = 5
|
20
|
+
@instance_id = http_conn.start {|http| http.get('/latest/meta-data/instance-id').body }
|
21
|
+
rescue Net::OpenTimeout
|
22
|
+
raise "HTTP connection to 169.254.169.254 is timeout. Probably, not an EC2 instance?"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'dotenv'
|
2
|
+
Dotenv.load
|
3
|
+
|
4
|
+
class EC2
|
5
|
+
class Host
|
6
|
+
class Config
|
7
|
+
class << self
|
8
|
+
attr_writer :config_file,
|
9
|
+
:aws_region,
|
10
|
+
:aws_profile,
|
11
|
+
:aws_access_key_id,
|
12
|
+
:aws_secret_access_key,
|
13
|
+
:aws_credentials_file,
|
14
|
+
:log_level,
|
15
|
+
:hostname_tag,
|
16
|
+
:roles_tag,
|
17
|
+
:optional_array_tags,
|
18
|
+
:optional_string_tags
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.configure(params)
|
22
|
+
params.each do |key, val|
|
23
|
+
send("#{key}=", val)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.config_file
|
28
|
+
@config_file ||= ENV.fetch('EC2_HOST_CONFIG_FILE', '/etc/sysconfig/ec2-host')
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.aws_region
|
32
|
+
@aws_region ||= ENV['AWS_REGION'] || config.fetch('AWS_REGION')
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.aws_profile
|
36
|
+
@aws_profile ||= ENV['AWS_PROFILE'] || config.fetch('AWS_PROFILE', 'default')
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.aws_access_key_id
|
40
|
+
@aws_access_key_id ||= ENV['AWS_ACCESS_KEY_ID'] || config.fetch('AWS_ACCESS_KEY_ID', nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.aws_secret_access_key
|
44
|
+
@aws_secret_access_key ||= ENV['AWS_SECRET_ACCESS_KEY'] || config.fetch('AWS_SECRET_ACCESS_KEY', nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
# this is not an official aws sdk environment variable
|
48
|
+
def self.aws_credentials_file
|
49
|
+
@aws_credentials_file ||= ENV['AWS_CREDENTIALS_FILE'] || config.fetch('AWS_CREDENTIALS_FILE', nil)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.log_level
|
53
|
+
@log_level ||= ENV['LOG_LEVEL'] || config.fetch('LOG_LEVEL', 'info')
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.hostname_tag
|
57
|
+
@hostname_tag ||= ENV['HOSTNAME_TAG'] || config.fetch('HOSTNAME_TAG', 'Name')
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.roles_tag
|
61
|
+
@roles_tag ||= ENV['ROLES_TAG'] || config.fetch('ROLES_TAG', 'Roles')
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.optional_array_tags
|
65
|
+
@optional_array_tags ||= (ENV['OPTIONAL_ARRAY_TAGS'] || config.fetch('OPTIONAL_ARRAY_TAGS', '')).split(',')
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.optional_string_tags
|
69
|
+
@optional_string_tags ||= (ENV['OPTIONAL_STRING_TAGS'] || config.fetch('OPTIONAL_STRING_TAGS', '')).split(',')
|
70
|
+
end
|
71
|
+
|
72
|
+
# private
|
73
|
+
|
74
|
+
def self.aws_credentials
|
75
|
+
@aws_credentials ||=
|
76
|
+
if aws_access_key_id and aws_secret_access_key
|
77
|
+
Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
|
78
|
+
else
|
79
|
+
Aws::SharedCredentials.new(profile_name: aws_profile, path: aws_credentials_file)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.optional_array_options
|
84
|
+
@optional_array_options ||= Hash[optional_array_tags.map {|tag|
|
85
|
+
[StringUtil.singularize(StringUtil.underscore(tag)), tag]
|
86
|
+
}]
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.optional_string_options
|
90
|
+
@optional_string_options ||= Hash[optional_string_tags.map {|tag|
|
91
|
+
[StringUtil.underscore(tag), tag]
|
92
|
+
}]
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.optional_options
|
96
|
+
@optional_options ||= optional_array_options.merge(optional_string_options)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.config
|
100
|
+
return @config if @config
|
101
|
+
@config = {}
|
102
|
+
File.readlines(config_file).each do |line|
|
103
|
+
next if line.start_with?('#')
|
104
|
+
key, val = line.chomp.split('=', 2)
|
105
|
+
@config[key] = val
|
106
|
+
end
|
107
|
+
@config
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'hashie/mash'
|
3
|
+
|
4
|
+
class EC2
|
5
|
+
class Host
|
6
|
+
# Represents each host
|
7
|
+
class HostData < Hashie::Mash
|
8
|
+
# :hostname, # tag:Name or hostname part of private_dns_name
|
9
|
+
# :roles, # tag:Roles.split(',') such as web:app1,db:app1
|
10
|
+
# :region, # ENV['AWS_REGION'],
|
11
|
+
# :instance, # Aws::EC2::Types::Instance itself
|
12
|
+
#
|
13
|
+
# and OPTIONAL_ARRAY_TAGS, OPTIONAL_STRING_TAGS
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
def_delegators :instance,
|
17
|
+
:instance_id,
|
18
|
+
:private_ip_address,
|
19
|
+
:public_ip_address,
|
20
|
+
:launch_time,
|
21
|
+
:state,
|
22
|
+
:monitoring
|
23
|
+
|
24
|
+
alias_method :ip, :private_ip_address
|
25
|
+
alias_method :start_date, :launch_time
|
26
|
+
def usages; roles; end
|
27
|
+
|
28
|
+
def self.initialize(instance)
|
29
|
+
d = self.new
|
30
|
+
d.instance = instance
|
31
|
+
d.set_hostname
|
32
|
+
d.set_roles
|
33
|
+
d.set_region
|
34
|
+
d.set_string_tags
|
35
|
+
d.set_array_tags
|
36
|
+
d
|
37
|
+
end
|
38
|
+
|
39
|
+
# match with condition or not
|
40
|
+
#
|
41
|
+
# @param [Hash] condition search parameters
|
42
|
+
def match?(condition)
|
43
|
+
return false unless role_match?(condition)
|
44
|
+
condition = HashUtil.except(condition,
|
45
|
+
:role, :role1, :role2, :role3,
|
46
|
+
:usage, :usage1, :usage2, :usage3
|
47
|
+
)
|
48
|
+
condition.each do |key, values|
|
49
|
+
if self.send(key).is_a?(Array)
|
50
|
+
return false unless self.send(key).find {|v| values.include?(v) }
|
51
|
+
else
|
52
|
+
return false unless values.include?(self.send(key))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
sprintf "#<Aws::Host::HostData %s>", info
|
60
|
+
end
|
61
|
+
|
62
|
+
def info
|
63
|
+
if hostname and status and roles and tags and service
|
64
|
+
# special treatment for DeNA ;)
|
65
|
+
sprintf "%s:%s(%s)[%s]{%s}", \
|
66
|
+
hostname, status, roles.join(' '), tags.join(' '), service
|
67
|
+
else
|
68
|
+
HashUtil.except(self, :instance).to_s
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# private
|
73
|
+
|
74
|
+
def role_match?(condition)
|
75
|
+
# usage is an alias of role
|
76
|
+
if role = (condition[:role] || condition[:usage])
|
77
|
+
role1, role2, role3 = role.first.split(':')
|
78
|
+
else
|
79
|
+
role1 = (condition[:role1] || condition[:usage1] || []).first
|
80
|
+
role2 = (condition[:role2] || condition[:usage2] || []).first
|
81
|
+
role3 = (condition[:role3] || condition[:usage3] || []).first
|
82
|
+
end
|
83
|
+
if role1
|
84
|
+
return false unless self.roles.find {|role| role.match?(role1, role2, role3) }
|
85
|
+
end
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_hostname
|
90
|
+
self.hostname = find_string_tag(Config.hostname_tag)
|
91
|
+
self.hostname = instance.private_dns_name.split('.').first if self.hostname.empty?
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_roles
|
95
|
+
roles = find_array_tag(Config.roles_tag)
|
96
|
+
self.roles = roles.map {|role| EC2::Host::RoleData.initialize(role) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_region
|
100
|
+
self.region = Config.aws_region
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_string_tags
|
104
|
+
Config.optional_string_tags.each do |tag|
|
105
|
+
field = StringUtil.underscore(tag)
|
106
|
+
self[field] = find_string_tag(tag)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_array_tags
|
111
|
+
Config.optional_array_tags.each do |tag|
|
112
|
+
field = StringUtil.underscore(tag)
|
113
|
+
self[field] = find_array_tag(tag)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def find_string_tag(key)
|
118
|
+
v = instance.tags.find {|tag| tag.key == key }
|
119
|
+
v ? v.value : ''
|
120
|
+
end
|
121
|
+
|
122
|
+
def find_array_tag(key)
|
123
|
+
v = instance.tags.find {|tag| tag.key == key }
|
124
|
+
v ? v.value.split(ARRAY_TAG_DELIMITER) : []
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class EC2
|
2
|
+
class Host
|
3
|
+
RoleData = Struct.new(
|
4
|
+
:role1, :role2, :role3
|
5
|
+
)
|
6
|
+
|
7
|
+
# Represents each role
|
8
|
+
class RoleData
|
9
|
+
def self.initialize(role)
|
10
|
+
role1, role2, role3 = role.split(ROLE_TAG_DELIMITER)
|
11
|
+
self.new(role1, role2, role3)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [String] something like "admin:jenkins:slave"
|
15
|
+
def role
|
16
|
+
@role ||= [role1, role2, role3].compact.reject(&:empty?).join(ROLE_TAG_DELIMITER)
|
17
|
+
end
|
18
|
+
alias :to_s :role
|
19
|
+
|
20
|
+
# @return [Array] something like ["admin", "admin:jenkins", "admin:jenkins:slave"]
|
21
|
+
def uppers
|
22
|
+
uppers = [RoleData.new(role1)]
|
23
|
+
uppers << RoleData.new(role1, role2) if role2 and !role2.empty?
|
24
|
+
uppers << RoleData.new(role1, role2, role3) if role3 and !role3.empty?
|
25
|
+
uppers
|
26
|
+
end
|
27
|
+
|
28
|
+
def match?(role1, role2 = nil, role3 = nil)
|
29
|
+
if role3
|
30
|
+
role1 == self.role1 and role2 == self.role2 and role3 == self.role3
|
31
|
+
elsif role2
|
32
|
+
role1 == self.role1 and role2 == self.role2
|
33
|
+
else
|
34
|
+
role1 == self.role1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Equality
|
39
|
+
#
|
40
|
+
# Role::Data.new('admin') == Role::Data.new('admin') #=> true
|
41
|
+
# Role::Data.new('admin', 'jenkin') == "admin:jenkins" #=> true
|
42
|
+
#
|
43
|
+
# @param [Object] other
|
44
|
+
def ==(other)
|
45
|
+
case other
|
46
|
+
when String
|
47
|
+
self.role == other
|
48
|
+
when EC2::Host::RoleData
|
49
|
+
super(other)
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def inspect
|
56
|
+
"\"#{to_s}\""
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class EC2
|
2
|
+
class Host
|
3
|
+
# If want sophisticated utility, better to use ActiveSupport
|
4
|
+
module StringUtil
|
5
|
+
def self.camelize(string)
|
6
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
7
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { $2.capitalize }
|
8
|
+
string.gsub!(/\//, '::')
|
9
|
+
string
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.underscore(camel_cased_word)
|
13
|
+
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
|
14
|
+
word = camel_cased_word.to_s.gsub(/::/, '/')
|
15
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
16
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
17
|
+
word.tr!("-", "_")
|
18
|
+
word.downcase!
|
19
|
+
word
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.pluralize(string)
|
23
|
+
"#{string.chomp('s')}s"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.singularize(string)
|
27
|
+
string.chomp('s')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/sample.conf
ADDED
data/spec/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# How to run test
|
2
|
+
|
3
|
+
NOTE: Currently, mock is not supported yet. So, you have to create your own AWS account, and instances.
|
4
|
+
|
5
|
+
Configure .env file as
|
6
|
+
|
7
|
+
```
|
8
|
+
AWS_ACCESS_KEY_ID=
|
9
|
+
AWS_SECRET_ACCESS_KEY=
|
10
|
+
AWS_REGION=
|
11
|
+
EC2_HOST_CONFIG_FILE=.env
|
12
|
+
OPTIONAL_ARRAY_TAGS=Tags
|
13
|
+
OPTIONAL_STRING_TAGS=Service,Status
|
14
|
+
```
|
15
|
+
|
16
|
+
EC2 instance tags must be configured as followings:
|
17
|
+
|
18
|
+
```
|
19
|
+
[
|
20
|
+
{
|
21
|
+
Name: test
|
22
|
+
Roles: admin:admin,test
|
23
|
+
Service: test
|
24
|
+
Status: reserve
|
25
|
+
Tags: standby
|
26
|
+
}
|
27
|
+
{
|
28
|
+
Name: isucon4
|
29
|
+
Roles: isucon4:qual
|
30
|
+
Service: isucon4
|
31
|
+
Status: active
|
32
|
+
Tags: master
|
33
|
+
}
|
34
|
+
]
|
35
|
+
```
|
data/spec/host_spec.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'host' do
|
4
|
+
it 'should have parameters' do
|
5
|
+
[ :hostname,
|
6
|
+
:roles,
|
7
|
+
:status,
|
8
|
+
:tags,
|
9
|
+
:service,
|
10
|
+
:region,
|
11
|
+
:instance,
|
12
|
+
:instance_id,
|
13
|
+
:private_ip_address,
|
14
|
+
:public_ip_address,
|
15
|
+
:launch_time,
|
16
|
+
:state,
|
17
|
+
:monitoring,
|
18
|
+
:ip,
|
19
|
+
:start_date,
|
20
|
+
:usages,
|
21
|
+
].each do |k|
|
22
|
+
expect{ subject.__send__(k) }.not_to raise_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe EC2::Host do
|
28
|
+
describe 'options' do
|
29
|
+
context do
|
30
|
+
let(:subject) { EC2::Host.new(hostname: 'test', options: {foo:'bar'}) }
|
31
|
+
it { expect(subject.options).to eq({foo:'bar'}) }
|
32
|
+
it { expect(subject.conditions).to eq([{hostname: ['test']}]) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context do
|
36
|
+
let(:subject) { EC2::Host.new({hostname: 'foo'}, {hostname: 'bar'}, options: {foo:'bar'}) }
|
37
|
+
it { expect(subject.options).to eq({foo:'bar'}) }
|
38
|
+
it { expect(subject.conditions).to eq([{hostname: ['foo']}, {hostname: ['bar']}]) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'by hostname' do
|
43
|
+
let(:hosts) { EC2::Host.new(hostname: 'test').to_a }
|
44
|
+
let(:subject) { hosts.first }
|
45
|
+
it_should_behave_like 'host'
|
46
|
+
it { expect(hosts.size).to eq(1) }
|
47
|
+
it { expect(subject.hostname).to eq('test') }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'by role' do
|
51
|
+
context 'by a role' do
|
52
|
+
let(:subject) { EC2::Host.new(role1: 'admin').first }
|
53
|
+
it_should_behave_like 'host'
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'by multiple roles (or)' do
|
57
|
+
let(:hosts) {
|
58
|
+
EC2::Host.new(
|
59
|
+
{
|
60
|
+
role1: 'admin',
|
61
|
+
role2: 'ami',
|
62
|
+
},
|
63
|
+
{
|
64
|
+
role1: 'isucon4',
|
65
|
+
}
|
66
|
+
).to_a
|
67
|
+
}
|
68
|
+
let(:subject) { hosts.first }
|
69
|
+
it { expect(hosts.size).to be >= 2 }
|
70
|
+
it_should_behave_like 'host'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# This is for DeNA use
|
75
|
+
context 'by usage (an alias of usage)' do
|
76
|
+
context 'by a usage' do
|
77
|
+
let(:subject) { EC2::Host.new(usage1: 'admin').first }
|
78
|
+
it_should_behave_like 'host'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'by multiple usages (or)' do
|
82
|
+
let(:hosts) {
|
83
|
+
EC2::Host.new(
|
84
|
+
{
|
85
|
+
usage1: 'admin',
|
86
|
+
usage2: 'ami',
|
87
|
+
},
|
88
|
+
{
|
89
|
+
usage1: 'isucon4',
|
90
|
+
}
|
91
|
+
).to_a
|
92
|
+
}
|
93
|
+
let(:subject) { hosts.first }
|
94
|
+
it { expect(hosts.size).to be >= 2 }
|
95
|
+
it_should_behave_like 'host'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'by status' do
|
100
|
+
context 'by a status' do
|
101
|
+
let(:subject) { EC2::Host.new(status: :active).first }
|
102
|
+
it_should_behave_like 'host'
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'by multiple status (or)' do
|
106
|
+
let(:hosts) { EC2::Host.new(status: [:reserve, :active]).to_a }
|
107
|
+
let(:subject) { hosts.first }
|
108
|
+
it_should_behave_like 'host'
|
109
|
+
it { expect(hosts.size).to be >= 2 }
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'by a string status' do
|
113
|
+
let(:subject) { EC2::Host.new(status: 'active').first }
|
114
|
+
it_should_behave_like 'host'
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'by multiple string status (or)' do
|
118
|
+
let(:hosts) { EC2::Host.new(status: ['reserve', 'active']).to_a }
|
119
|
+
let(:subject) { hosts.first }
|
120
|
+
it_should_behave_like 'host'
|
121
|
+
it { expect(hosts.size).to be >= 2 }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'by service' do
|
126
|
+
context 'by a service' do
|
127
|
+
let(:subject) { EC2::Host.new(service: 'isucon4').first }
|
128
|
+
it_should_behave_like 'host'
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'by multiple services (or)' do
|
132
|
+
let(:hosts) { EC2::Host.new(service: ['test', 'isucon4']) }
|
133
|
+
let(:subject) { hosts.first }
|
134
|
+
it_should_behave_like 'host'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'by region' do
|
139
|
+
context 'by a region' do
|
140
|
+
let(:subject) { EC2::Host.new(region: 'ap-northeast-1').first }
|
141
|
+
it_should_behave_like 'host'
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'by multiple regions (or)' do
|
145
|
+
let(:hosts) { EC2::Host.new(region: ['ap-northeast-1']) }
|
146
|
+
let(:subject) { hosts.first }
|
147
|
+
it_should_behave_like 'host'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'by tags' do
|
152
|
+
context 'by a tag' do
|
153
|
+
let(:subject) { EC2::Host.new(tags: 'master').first }
|
154
|
+
it_should_behave_like 'host'
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'by multiple tags (or)' do
|
158
|
+
let(:hosts) { EC2::Host.new(tags: ['standby', 'master']) }
|
159
|
+
let(:subject) { hosts.first }
|
160
|
+
it_should_behave_like 'host'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
Bundler.require :test
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter 'vendor/'
|
7
|
+
add_filter 'spec/'
|
8
|
+
add_group 'libs', 'lib'
|
9
|
+
end
|
10
|
+
|
11
|
+
Bundler.require :default # <- need this *after* simplecov
|
12
|
+
require 'pry'
|
13
|
+
require 'ec2-host'
|
14
|
+
require 'dotenv'
|
15
|
+
Dotenv.load
|
16
|
+
|
17
|
+
# Requires supporting files with custom matchers and macros, etc,
|
18
|
+
# in ./support/ and its subdirectories.
|
19
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ec2-host
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Naotoshi Seo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '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: dotenv
|
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: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdoc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry-nav
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: bundler
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description: Search hosts on AWS EC2
|
182
|
+
email:
|
183
|
+
- sonots@gmail.com
|
184
|
+
executables:
|
185
|
+
- ec2-host
|
186
|
+
extensions: []
|
187
|
+
extra_rdoc_files: []
|
188
|
+
files:
|
189
|
+
- ".gitignore"
|
190
|
+
- CHANGELOG.md
|
191
|
+
- Gemfile
|
192
|
+
- LICENSE
|
193
|
+
- README.md
|
194
|
+
- Rakefile
|
195
|
+
- bin/ec2-host
|
196
|
+
- doc.sh
|
197
|
+
- ec2-host.gemspec
|
198
|
+
- example/aws-sdk.rb
|
199
|
+
- example/example.rb
|
200
|
+
- lib/ec2-host.rb
|
201
|
+
- lib/ec2/host.rb
|
202
|
+
- lib/ec2/host/cli.rb
|
203
|
+
- lib/ec2/host/client_util.rb
|
204
|
+
- lib/ec2/host/config.rb
|
205
|
+
- lib/ec2/host/hash_util.rb
|
206
|
+
- lib/ec2/host/host_data.rb
|
207
|
+
- lib/ec2/host/role_data.rb
|
208
|
+
- lib/ec2/host/string_util.rb
|
209
|
+
- sample.conf
|
210
|
+
- spec/README.md
|
211
|
+
- spec/host_spec.rb
|
212
|
+
- spec/spec_helper.rb
|
213
|
+
homepage: https://github.com/sonots/ec2-host
|
214
|
+
licenses:
|
215
|
+
- MIT
|
216
|
+
metadata: {}
|
217
|
+
post_install_message:
|
218
|
+
rdoc_options: []
|
219
|
+
require_paths:
|
220
|
+
- lib
|
221
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
222
|
+
requirements:
|
223
|
+
- - ">="
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
version: '0'
|
226
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: '0'
|
231
|
+
requirements: []
|
232
|
+
rubyforge_project:
|
233
|
+
rubygems_version: 2.2.2
|
234
|
+
signing_key:
|
235
|
+
specification_version: 4
|
236
|
+
summary: Search hosts on AWS EC2
|
237
|
+
test_files:
|
238
|
+
- spec/README.md
|
239
|
+
- spec/host_spec.rb
|
240
|
+
- spec/spec_helper.rb
|
241
|
+
has_rdoc:
|