ec2l 0.0.1 → 0.0.2

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