ec2l 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,5 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.1.0
4
4
  - jruby-19mode
5
- - rbx-2
6
5
  - jruby-head
6
+ addons:
7
+ code_climate:
8
+ repo_token: b8d2d2e6c25619ddc2efa605b020bf716623bc65c08bd7bc044d90c264def66d
data/Gemfile CHANGED
@@ -2,3 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in ec2l.gemspec
4
4
  gemspec
5
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/README.md CHANGED
@@ -1,8 +1,13 @@
1
1
  # Ec2l
2
2
 
3
3
  [![Build Status](https://travis-ci.org/yazgoo/ec2l.svg?branch=master)](https://travis-ci.org/yazgoo/ec2l)
4
+ [![Test Coverage](https://codeclimate.com/github/yazgoo/ec2l/coverage.png)](https://codeclimate.com/github/yazgoo/ec2l)
5
+ [![Code Climate](https://codeclimate.com/github/yazgoo/ec2l.png)](https://codeclimate.com/github/yazgoo/ec2l)
6
+ [![Inline docs](http://inch-ci.org/github/yazgoo/ec2l.png?branch=master)](http://inch-ci.org/github/yazgoo/ec2l)
7
+ [![Gem Version](https://badge.fury.io/rb/ec2l.svg)](http://badge.fury.io/rb/ec2l)
4
8
 
5
- TODO: Write a gem description
9
+
10
+ Ec2l aims to provide an efficient ruby developer oriented UI to EC2.
6
11
 
7
12
  ## Installation
8
13
 
@@ -20,7 +25,35 @@ Or install it yourself as:
20
25
 
21
26
  ## Usage
22
27
 
23
- TODO: Write usage instructions here
28
+ You can call public client methods directly from the ec2l command line,
29
+ though a better way is to use the shell, which relies on pry:
30
+
31
+ $ ec2l shell
32
+
33
+
34
+ ```ruby
35
+ ...
36
+ [2] pry(#<Ec2l::Client>)> h # print help
37
+ Usage: action parameters...
38
+ available actions:
39
+ [
40
+ [0] associate(address, id) Ec2l::Client
41
+ [1] ins() Ec2l::Client
42
+ ...
43
+ [2] pry(#<Ec2l::Client>)> show-doc ins # print documentation on ins method
44
+ ...
45
+ Public: return virtual machines instances with few details
46
+
47
+ Examples
48
+
49
+ ins[0]
50
+ => {:instanceId=>"i-deadbeef", :instanceState=>
51
+ {"code"=>"16", "name"=>"running"},
52
+ :ipAddress=>"10.1.1.2", :tagSet=>{:k=>"v"}}
53
+
54
+ Returns an array with instanceId, ipAddress, tagSet, instanceState in a hash
55
+ [7] pry(#<Ec2l::Client>)> ins # launch ins method
56
+ ```
24
57
 
25
58
  ## Contributing
26
59
 
@@ -2,30 +2,137 @@ require "ec2l/version"
2
2
  require 'base64'
3
3
  require 'awesome_print'
4
4
  require 'pry'
5
+ # Public: Utilities to facilitate amazon EC2 administration
6
+ #
7
+ # Examples
8
+ #
9
+ # Ec2l::Client.new.i
10
+ # => {:instanceId=>"i-deadbeef", :instanceState=>
11
+ # {"code"=>"16", "name"=>"running"},
12
+ # :ipAddress=>"10.1.1.2", :tagSet=>{:k=>"v"}
13
+ # ...
5
14
  module Ec2l
15
+ # Public: Client to use amazon EC2 apis
16
+ #
17
+ # Examples
18
+ #
19
+ # Client.new.instances(["ipAddress"])[0..1]
20
+ # => [{:ipAddress=>"10.1.1.2"}, {:ipAddress=>"10.1.1.1"}]
6
21
  class Client
22
+ # Public: return virtual machines instances
23
+ #
24
+ # keep - what field you want to extract.
25
+ # valid fields names are documented in ec2 apis
26
+ # groups is an arranged shortcut for groupSet
27
+ # tagSet is also rearranged
28
+ #
29
+ # Examples
30
+ #
31
+ # instances(["ipAddress"])[0..1]
32
+ # => [{:ipAddress=>"10.1.1.2"}, {:ipAddress=>"10.1.1.1"}]
33
+ #
34
+ # Returns an array with all fields requested for each VM in a hash
7
35
  def instances keep = ["instanceId", "ipAddress", "groups",
8
36
  "launchType", "instanceType", "tagSet"]
9
37
  @ec2.describe_instances.reservationSet.item.collect do |item|
10
- group = item.groupSet if keep.include? "groups"
38
+ rearrange_fields item, keep
11
39
  item = item.instancesSet.item[0].reject{|k, v| not keep.include? k}
12
- item["groups"] = group.item.map{|x| x.groupId } if not group.nil?
13
- item["tagSet"] = to_hash(item["tagSet"].item) if item["tagSet"]
14
40
  Hash[item.map { |k, v| [k.to_sym, v] }]
15
41
  end
16
42
  end
43
+ # Public: displays inforation about a VM instance
44
+ #
45
+ # id - the VM instance id
46
+ #
47
+ # Examples
48
+ #
49
+ # instance "i-deadbeef"
50
+ # => {"xmlns"=>"http://ec2.amazonaws.com/doc/2010-08-31/",
51
+ # "requestId"=>"89375055-16de-4ab7-84b5-5651670e7e3b",
52
+ # "reservationSet"=>
53
+ # {"item"=>
54
+ # ...
55
+ #
56
+ # Returns a hash with description of the instance
17
57
  def instance(id) @ec2.describe_instances(instance_id: id) end
58
+ # Public: associate an elastic address with a VM instance
59
+ #
60
+ # address - the elastic IP address
61
+ # id - the VM instance id
62
+ #
63
+ # Examples
64
+ #
65
+ # associate '10.1.1.2', 'i-deadbeef'
66
+ #
67
+ # Returns info about the association
68
+ def associate address, id
69
+ @ec2.associate_address public_ip: address, instance_id: id
70
+ end
71
+ # Public: return a list of inforation about declared security groups
72
+ #
73
+ # Examples
74
+ #
75
+ # sgs[0..1]
76
+ # => [{"ownerId"=>"424242", "groupName"=>"sg1"},
77
+ # {"ownerId"=>"424242", "groupName"=>"sg2"}]
78
+ #
79
+ # Returns an array with for each SG, the ownerID and the groupName
18
80
  def sgs
19
81
  @ec2.describe_security_groups.securityGroupInfo.item.collect do |item|
20
82
  item.reject { |k, v| not ["groupName", "ownerId"].include? k }
21
83
  end
22
84
  end
23
- def i() instances ["instanceId", "ipAddress", "tagSet", "instanceState"] end
85
+ # Public: return virtual machines instances with few details
86
+ #
87
+ # Examples
88
+ #
89
+ # ins[0]
90
+ # => {:instanceId=>"i-deadbeef", :instanceState=>
91
+ # {"code"=>"16", "name"=>"running"},
92
+ # :ipAddress=>"10.1.1.2", :tagSet=>{:k=>"v"}}
93
+ #
94
+ # Returns an array with instanceId, ipAddress, tagSet, instanceState in a hash
95
+ def ins() instances ["instanceId", "ipAddress", "tagSet", "instanceState"] end
96
+ # Public: get system log
97
+ #
98
+ # id - VM instance id
99
+ #
100
+ # Examples
101
+ #
102
+ # log("i-deadbeef")[0..1]
103
+ # => ["Initializing cgroup subsys cpuset", "Initializing cgroup subsys cpu"]
104
+ #
105
+ # Returns an array containing the lines of the system log
24
106
  def log id
25
- puts Base64.decode64 @ec2.get_console_output(instance_id: id)["output"]
107
+ Base64.decode64(@ec2.get_console_output(instance_id: id)["output"]).split("\r\n")
26
108
  end
109
+ # Public: terminates a VM instance
110
+ #
111
+ # id - the VM instance id
112
+ #
113
+ # Examples
114
+ #
115
+ # terminate "i-deadbeef"
116
+ #
117
+ # Returns information about the termination status
27
118
  def terminate(id) @ec2.terminate_instances(instance_id: id) end
119
+ # Public: opens up a pry shell
28
120
  def shell() binding.pry end
121
+ # Public: update the credentials configuration
122
+ #
123
+ # creds - current credentials
124
+ #
125
+ # Examples
126
+ # update_configuration
127
+ # Will try and update configuration in /home/yazgoo/.awssecret
128
+ # access key (foo):
129
+ # secret access key (bar):
130
+ # entry point (default being https://aws.amazon.com if blank)
131
+ # (http://ec2.aws.com):
132
+ # => ["access key", "secret access key",
133
+ # "entry point ..."]
134
+ #
135
+ # Returns the description of the updated fields
29
136
  def update_configuration creds = nil
30
137
  puts "Will try and update configuration in #{@conf}"
31
138
  creds = read_credentials if creds.nil?
@@ -33,19 +140,30 @@ module Ec2l
33
140
  ["access key", "secret access key",
34
141
  "entry point (default being https://aws.amazon.com if blank)"
35
142
  ].each_with_index do |prompt, i|
36
- printf "#{prompt} (#{creds.size > i ? creds[i]:""}): "
37
- line = $stdin.gets.chomp
38
- line = creds[i] if line.empty? and creds.size > i
143
+ line = prompt_line prompt, creds[i]
39
144
  f.puts line if not line.empty?
40
145
  end
41
146
  end
42
147
  end
148
+ # Public: reads credentials from configuration file
149
+ #
150
+ # Examples
151
+ #
152
+ # read_credentials
153
+ # => ["accesskey", "scretkey", "https://entry.com"]
154
+ #
155
+ # Return a list with the credentials and entrypoint if defined
43
156
  def read_credentials
44
157
  creds = []
45
158
  File.open(@conf) { |f| f.each_line { |l| creds << l.chomp } } if File.exists?(@conf)
46
159
  creds
47
160
  end
48
161
  private
162
+ def prompt_line prompt, cred
163
+ printf "#{prompt} (#{creds? creds:""}): "
164
+ line = $stdin.gets.chomp
165
+ if line.empty? and creds.size > i then creds else line end
166
+ end
49
167
  def to_hash array
50
168
  Hash[array.collect { |i| [i["key"].to_sym, i["value"]] }]
51
169
  end
@@ -55,18 +173,64 @@ private
55
173
  update_configuration credentials
56
174
  read_credentials
57
175
  end
58
- def initialize
59
- @conf = ENV['awssecret'] || "#{ENV['HOME']}/.awssecret"
60
- credentials = load_credentials
176
+ def build_underlying_client credentials
61
177
  ENV['EC2_URL'] = credentials[2] if credentials.size >= 3
62
178
  require 'AWS' # *must* load AWS after setting EC2_URL
63
- @ec2 = AWS::EC2::Base.new access_key_id: credentials[0],
179
+ AWS::EC2::Base.new access_key_id: credentials[0],
64
180
  secret_access_key: credentials[1]
65
181
  end
182
+ def initialize
183
+ @conf = ENV['awssecret'] || "#{ENV['HOME']}/.awssecret"
184
+ @ec2 = build_underlying_client load_credentials
185
+ end
186
+ # Internal: try and find/launch the method on the
187
+ # underlying client called by the method name
188
+ # or by describe_#{name}
189
+ #
190
+ # Examples
191
+ #
192
+ # method_missing_ec2 :addresses
193
+ # => {"xmlns"=>"http://ec2.amazonaws.com/doc/2010-08-31/",
194
+ # ...
195
+ #
196
+ # Return the result of the underlying method call
197
+ def method_missing_ec2 method, *args, &block
198
+ [method, "describe_#{method.to_s}".to_sym].each do |meth|
199
+ if @ec2.public_methods.include? meth
200
+ return @ec2.send meth, *args, &block
201
+ end
202
+ end
203
+ nil
204
+ end
205
+ # Internal: try and call method_missing_ec2
206
+ # if its result is nil, display a list of the class
207
+ # public methods
208
+ #
209
+ # Examples
210
+ #
211
+ # h
212
+ # =>Usage: action parameters...
213
+ # available actions:
214
+ # [
215
+ # [0] associate(address, id) Ec2l::Client
216
+ # [1] i() Ec2l::Client
217
+ #
218
+ # Return the result of method_missing_ec2 or nil
66
219
  def method_missing method, *args, &block
220
+ result = method_missing_ec2(method, *args, &block)
221
+ return result if not result.nil?
67
222
  puts "Usage: action parameters...", "available actions:"
68
223
  awesome_print (public_methods - "".public_methods)
69
224
  nil
70
225
  end
226
+ def rearrange_fields item, keep
227
+ it = item.instancesSet.item[0]
228
+ if keep.include? "groups" and item.groupSet
229
+ it["groups"] = item.groupSet.item.map{|x| x.groupId }
230
+ end
231
+ if keep.include? "tagSet" and it.tagSet
232
+ it["tagSet"] = to_hash(it.tagSet.item)
233
+ end
234
+ end
71
235
  end
72
236
  end
@@ -1,3 +1,3 @@
1
1
  module Ec2l
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,20 +1,97 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
1
3
  require 'test/unit'
2
4
  require 'tempfile'
5
+ require 'base64'
3
6
  require 'ec2l'
7
+ class Hash
8
+ def method_missing method, *args, &block
9
+ method = method.to_s
10
+ if method.end_with? "="
11
+ self[method.to_s[0..-2]] = args[0]
12
+ else
13
+ self[method]
14
+ end
15
+ end
16
+ end
17
+ class Client < Ec2l::Client
18
+ def build_underlying_client credentials
19
+ if credentials.size == 3 and credentials[2] == 'through'
20
+ super credentials
21
+ else
22
+ MockEc2.new
23
+ end
24
+ end
25
+ end
26
+ $instance_set = {"reservationSet" => {"item" => [{"instancesSet" => {
27
+ "item" => [{"instanceId" => "lol"}]}}]}}
28
+ class MockEc2
29
+ def method_missing method, *args, &block
30
+ nil
31
+ end
32
+ def describe_instances stuff = nil
33
+ $instance_set
34
+ end
35
+ def describe_security_groups
36
+ {"securityGroupInfo" => {"item" => [{'groupName' => 'test'}] }}
37
+ end
38
+ def get_console_output stuff
39
+ {"output" => Base64.encode64("hello")}
40
+ end
41
+ end
4
42
  class EC2lTest < Test::Unit::TestCase
5
- def test_initialize
43
+ def create_conf creds
6
44
  conf = Tempfile.new "a"
7
- conf.write "a\nb\n"
45
+ conf.write creds.join "\n"
8
46
  conf.close
9
- ENV['awssecret'] = conf.path
10
- client = Ec2l::Client.new
47
+ conf.path
48
+ end
49
+ def setup
50
+ ENV['awssecret'] = create_conf ['a', 'b']
51
+ @cli = Client.new
11
52
  end
12
53
  def test_configuration
13
- client = test_initialize
14
54
  def $stdin.gets() 'same_old' end
15
- client.update_configuration
16
- creds = client.read_credentials
17
- assert creds.size == 3
55
+ @cli.update_configuration
56
+ creds = @cli.read_credentials
57
+ assert creds.size == 3, creds.to_s
18
58
  creds.each { |cred| assert cred == 'same_old' }
59
+ ENV['awssecret'] = create_conf([])
60
+ Client.new.send :load_credentials
61
+ end
62
+ def test_method_missing
63
+ assert @cli.h.nil?
64
+ assert @cli.send(:method_missing_ec2, :h).nil?
65
+ end
66
+ def test_utilities
67
+ result = @cli.send :to_hash, [{"key" => "hello", "value" => "world"}]
68
+ assert result == {hello: "world"}
69
+ end
70
+ def test_basic_underlying_calls
71
+ assert @cli.associate(nil, nil).nil?
72
+ assert @cli.instance(nil) == $instance_set
73
+ assert @cli.log(nil) == ["hello"]
74
+ assert @cli.terminate(nil).nil?
75
+ end
76
+ def test_rearrange_fields
77
+ item = {"instancesSet" => {"item" => [{"tagSet" => {"item" => []}}]},
78
+ "groupSet" => {"item" => [{}] } }
79
+ @cli.send :rearrange_fields, item, ["groups", "tagSet"]
80
+ end
81
+ def test_complex_calls
82
+ assert @cli.describe_instances == $instance_set
83
+ instances = [{:instanceId=>"lol"}]
84
+ assert @cli.instances == instances
85
+ assert @cli.ins == instances
86
+ assert @cli.sgs == [{"groupName"=>"test"}]
87
+ end
88
+ def test_underlying_client_initialization
89
+ x = nil
90
+ begin
91
+ @cli.build_underlying_client ['a', 'b', 'through']
92
+ rescue Exception => e
93
+ x = e
94
+ end
95
+ assert not(x.nil?)
19
96
  end
20
97
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ec2l
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-18 00:00:00.000000000 Z
12
+ date: 2014-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -125,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
125
  version: '0'
126
126
  segments:
127
127
  - 0
128
- hash: 3534822186710217201
128
+ hash: 4414468867736333160
129
129
  required_rubygems_version: !ruby/object:Gem::Requirement
130
130
  none: false
131
131
  requirements:
@@ -134,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
134
  version: '0'
135
135
  segments:
136
136
  - 0
137
- hash: 3534822186710217201
137
+ hash: 4414468867736333160
138
138
  requirements: []
139
139
  rubyforge_project:
140
140
  rubygems_version: 1.8.23