ey_instance_api_client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,56 @@
1
+ module EY
2
+ module InstanceAPIClient
3
+ class Backup
4
+ def initialize(connection, attributes)
5
+ @connection = connection
6
+ @attributes = attributes
7
+ end
8
+
9
+ def upload_urls
10
+ @attributes['upload_urls']
11
+ end
12
+
13
+ def download_urls
14
+ @attributes['download_urls']
15
+ end
16
+
17
+ def finish_url
18
+ @attributes['finish_url']
19
+ end
20
+
21
+ def extension
22
+ @attributes["extension"]
23
+ end
24
+
25
+ def started_at
26
+ if started_at = @attributes['started_at']
27
+ Time.at(started_at)
28
+ end
29
+ end
30
+
31
+ def finished_at
32
+ if finished_at = @attributes['finished_at']
33
+ Time.at(finished_at)
34
+ end
35
+ end
36
+
37
+ def pending?
38
+ status == "pending"
39
+ end
40
+
41
+ def status
42
+ if finished_at
43
+ "finished"
44
+ elsif started_at
45
+ "pending"
46
+ else
47
+ "unknown"
48
+ end
49
+ end
50
+
51
+ def finish!
52
+ @connection.finish_backup(finish_url)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ module EY
2
+ module InstanceAPIClient
3
+ class Config
4
+ def self.default_config
5
+ Config.from_file("/etc/engineyard/instance_api.yml")
6
+ end
7
+
8
+ class MissingConfig < StandardError; end
9
+
10
+ def self.from_file(file)
11
+ config = YAML::load_file(file)
12
+ base_url = config['base_url'] || (raise MissingConfig.new("couldn't find base_url in #{file.inspect}"))
13
+ instance_id = config['instance_id'] || (raise MissingConfig.new("couldn't find instance_id in #{file.inspect}"))
14
+ token = config['token'] || (raise MissingConfig.new("couldn't find token in #{file.inspect}"))
15
+ new(base_url, instance_id, token)
16
+ end
17
+
18
+ def initialize(base_url, instance_id, token)
19
+ @base_url = base_url
20
+ @instance_id = instance_id
21
+ @token = token
22
+ end
23
+
24
+ attr_reader :base_url, :instance_id, :token
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,81 @@
1
+ module EY
2
+ module InstanceAPIClient
3
+ class Connection
4
+ def initialize(base_url, instance_id, token)
5
+ unless base_url.match(/\/$/)
6
+ base_url += '/'
7
+ end
8
+ @base_url = base_url
9
+ @instance_id = instance_id
10
+ @token = token
11
+ end
12
+ attr_reader :base_url
13
+
14
+ #PUBLIC API:
15
+
16
+ def list_snapshots
17
+ r = api_call(snapshots_url, 200)
18
+ data = r.get(:params => params, :accept => "application/json")
19
+ data["snapshots"].collect{ |s| Snapshot.new(s) }
20
+ end
21
+
22
+ def request_snapshot
23
+ r = api_call(snapshots_url, 201)
24
+ r.post(params, :accept => "application/json")
25
+ end
26
+
27
+ def list_backups(database_id)
28
+ r = api_call(database_url(database_id), 200)
29
+ data = r.get(:params => params, :accept => "application/json")
30
+ data["backups"].collect{ |b| Backup.new(self, b) }
31
+ end
32
+
33
+ def start_backup(database_id, extension, part_count)
34
+ r = api_call(database_url(database_id), 201)
35
+ data = r.post(params.merge(:extension => extension, :part_count => part_count), :accept => "application/json")
36
+ Backup.new(self, data["backup"])
37
+ end
38
+
39
+ #SORTA-PRIVATE stuff:
40
+
41
+ def snapshots_url
42
+ URI.join(@base_url, "volumes/all/snapshots").to_s
43
+ end
44
+
45
+ def database_url(database_id)
46
+ URI.join(@base_url, "databases/#{database_id}/backups").to_s
47
+ end
48
+
49
+ def finish_backup(finished_url)
50
+ r = api_call(finished_url, 200)
51
+ r.put(params, :accept => "application/json")
52
+ end
53
+
54
+ def params
55
+ {:token => @token, :instance_id => @instance_id}
56
+ end
57
+
58
+ class InvalidCredentials < StandardError; end
59
+ class UnexpectedStatus < StandardError; end
60
+ class AlreadyFinished < StandardError; end
61
+ class NotFound < StandardError; end
62
+
63
+ def api_call(full_url, expects)
64
+ RestClient::Resource.new(full_url.to_s) do |response, request, raw|
65
+ case response.code
66
+ when 403
67
+ raise InvalidCredentials
68
+ when 404
69
+ raise NotFound
70
+ when 409
71
+ raise AlreadyFinished
72
+ when expects
73
+ JSON.parse(response)
74
+ else
75
+ raise UnexpectedStatus, "request to #{full_url} failed with #{response.code}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,29 @@
1
+ module EY
2
+ module InstanceAPIClient
3
+ class Snapshot
4
+ def initialize(attributes)
5
+ @attributes = attributes
6
+ end
7
+
8
+ def state
9
+ @attributes['state']
10
+ end
11
+
12
+ def progress
13
+ @attributes['progress']
14
+ end
15
+
16
+ def volume
17
+ @attributes['volume_type']
18
+ end
19
+
20
+ def id
21
+ @attributes['snapshot_id']
22
+ end
23
+
24
+ def created_at
25
+ Time.parse(@attributes['created_at'])
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module EY
2
+ module InstanceAPIClient
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,43 @@
1
+ # $:.shift(File.expand_path(__FILE__))
2
+ require 'json'
3
+ require 'rest-client'
4
+ require 'ey_instance_api_client/snapshot'
5
+ require 'ey_instance_api_client/backup'
6
+ require 'ey_instance_api_client/connection'
7
+ require 'ey_instance_api_client/config'
8
+
9
+ module EY
10
+ module InstanceAPIClient
11
+
12
+ class Client
13
+ def initialize(config = Config.default_config)
14
+ @backend = Connection.new(config.base_url, config.instance_id, config.token)
15
+ end
16
+ attr_reader :backend
17
+ def base_url
18
+ @backend.base_url
19
+ end
20
+ end
21
+
22
+ class Snapshots < Client
23
+ def list
24
+ @backend.list_snapshots
25
+ end
26
+
27
+ def request
28
+ @backend.request_snapshot
29
+ end
30
+ end
31
+
32
+ class Backups < Client
33
+ def list(database_id)
34
+ @backend.list_backups(database_id)
35
+ end
36
+
37
+ def start(database_id, extension, part_count)
38
+ @backend.start_backup(database_id, extension, part_count)
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,88 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe "Backups" do
4
+ before do
5
+ start_server("backup_base_config")
6
+ end
7
+
8
+ after do
9
+ stop_server
10
+ end
11
+
12
+ describe "with an invalid creds" do
13
+ it "returns 403 when the token is invalid" do
14
+ client = EY::InstanceAPIClient::Backups.new(EY::InstanceAPIClient::Config.new(base_url, "my-instance", "invalid-creds"))
15
+ lambda { client.list("doesntmatter") }.
16
+ should raise_error(EY::InstanceAPIClient::Connection::InvalidCredentials)
17
+ end
18
+ end
19
+
20
+ describe "starting a backup for non-existant database" do
21
+ it "return 404" do
22
+ client = EY::InstanceAPIClient::Backups.new(EY::InstanceAPIClient::Config.new(base_url, "my-instance", "token-for-my-instance"))
23
+ lambda { client.list("nonexistant") }.
24
+ should raise_error(EY::InstanceAPIClient::Connection::NotFound)
25
+ end
26
+ end
27
+
28
+ context "with an database that exists" do
29
+ before do
30
+ @database_id = "database-1"
31
+ @client = EY::InstanceAPIClient::Backups.new(EY::InstanceAPIClient::Config.new(base_url, "my-instance", "token-for-my-instance"))
32
+ end
33
+
34
+ describe "listing backups" do
35
+ it "Makes a request and Gets an empty list" do
36
+ list = @client.list(@database_id)
37
+ list.should == []
38
+ end
39
+
40
+ end
41
+
42
+ describe "starting a backup" do
43
+ before do
44
+ @backup = @client.start(@database_id, ".gz", 1)
45
+ end
46
+
47
+ it "returns the upload and finished url" do
48
+ @backup.should have(1).upload_urls
49
+ @backup.upload_urls.first.should =~ %r{^http://s3/PUT}
50
+ @backup.finish_url.should =~ %r{#{base_url}}
51
+ @backup.status.should == "pending"
52
+ end
53
+
54
+ it "should show started_at in the listing" do
55
+ list = @client.list(@database_id)
56
+ list.size.should == 1
57
+ backup = list.first
58
+ backup.status.should == "pending"
59
+ backup.started_at.should_not be_nil
60
+ backup.download_urls.should be_nil
61
+ backup.upload_urls.should be_nil
62
+ backup.finished_at.should be_nil
63
+ end
64
+
65
+ describe "finishing that backup" do
66
+ before do
67
+ @backup.finish!
68
+ end
69
+
70
+ it "should show finished_at in the listing" do
71
+ list = @client.list(@database_id)
72
+ list.size.should == 1
73
+ backup = list.first
74
+ backup.should have(1).download_urls
75
+ backup.download_urls.first.should =~ %r{^http://s3/GET}
76
+ backup.upload_urls.should be_nil
77
+ backup.started_at.should_not be_nil
78
+ backup.finished_at.should_not be_nil
79
+ end
80
+
81
+ it "should return 409 if you attempt to finish it again" do
82
+ lambda { @backup.finish! }.
83
+ should raise_error(EY::InstanceAPIClient::Connection::AlreadyFinished)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe "Config" do
4
+
5
+ describe "default_config" do
6
+ before(:each) do
7
+ YAML.stub!(:load_file).and_return do |path, *args|
8
+ if path =~ %r"/etc/engineyard/instance_api\.yml"
9
+ {
10
+ "base_url" => "http://localhost/",
11
+ "instance_id" => "my-instance",
12
+ "token" => "token"
13
+ }
14
+ end
15
+ end
16
+ EY::InstanceAPIClient::Connection.stub!(:new) do |*args|
17
+ @connection_called_with = args
18
+ end
19
+ end
20
+
21
+ it "Backups should load config from /etc/engineyard/instance_api.yml" do
22
+ EY::InstanceAPIClient::Backups.new
23
+ @connection_called_with.should == ["http://localhost/", "my-instance", "token"]
24
+ end
25
+
26
+ it "Snapshots should load config from /etc/engineyard/instance_api.yml" do
27
+ EY::InstanceAPIClient::Snapshots.new
28
+ @connection_called_with.should == ["http://localhost/", "my-instance", "token"]
29
+ end
30
+ end
31
+
32
+ it "ensures base_url ends in a slash" do
33
+ client = EY::InstanceAPIClient::Snapshots.new(EY::InstanceAPIClient::Config.new("http://localhost/end-point-without-a-slash", "some-instance", "some-creds"))
34
+ client.base_url.should == "http://localhost/end-point-without-a-slash/"
35
+ client = EY::InstanceAPIClient::Backups.new(EY::InstanceAPIClient::Config.new("http://localhost/end-point-without-a-slash", "some-instance", "some-creds"))
36
+ client.base_url.should == "http://localhost/end-point-without-a-slash/"
37
+ end
38
+
39
+ end
@@ -0,0 +1,82 @@
1
+
2
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../../../server/lib')
3
+ require 'ey_instance_api_server'
4
+ require 'ey_instance_api_server/backups/example_callback'
5
+
6
+ class MyCallback < EY::InstanceAPIServer::Backups::ExampleCallback
7
+ def initialize(base_url, s3_base_url, automatic_databases, real_s3)
8
+ super(base_url)
9
+ @s3_base_url = s3_base_url
10
+ @automatic_databases = automatic_databases
11
+ @real_s3 = real_s3
12
+ end
13
+
14
+ def download_url_for(backup_id, part)
15
+ if @real_s3
16
+ URI.join(@s3_base_url, "files/#{backup_id}.part#{part}").to_s
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def upload_url_for(backup_id, part)
23
+ if @real_s3
24
+ download_url_for(backup_id, part)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def backups_for(instance_id, database_id)
31
+ if @automatic_databases
32
+ add_database(instance_id, database_id)
33
+ end
34
+ super
35
+ end
36
+ end
37
+
38
+ base_url = ENV["BASE_URL"] || abort("Provide a base url")
39
+ automatic_databases = ENV["AUTO_DATABASES"] == "true"
40
+ real_s3 = ENV["REAL_S3"] == "true"
41
+
42
+ callback = MyCallback.new(URI.join(base_url, "api/").to_s, URI.join(base_url, "s3/").to_s, automatic_databases, real_s3)
43
+ callback.add_instance("my-instance")
44
+ callback.add_database("my-instance", "database-1")
45
+ EY::InstanceAPIServer.callback_module = callback
46
+
47
+ class S3Fake < Sinatra::Base
48
+ enable :raise_errors
49
+ disable :dump_errors
50
+ disable :show_exceptions
51
+
52
+ def files
53
+ @@files ||= {}
54
+ end
55
+
56
+ get "/files/:id" do |id|
57
+ puts "downloading file from #{id.inspect}"
58
+ files[id] || not_found
59
+ end
60
+
61
+ put "/files/:id" do |id|
62
+ unless request.content_type == "application/octet-stream"
63
+ raise "Incorrect content type: #{request.content_type}"
64
+ end
65
+ puts "uploading file to #{id.inspect}"
66
+ files[id] = request.body.read
67
+ end
68
+ end
69
+
70
+ map "/s3" do
71
+ run S3Fake
72
+ end
73
+
74
+ map "/api" do
75
+ run EY::InstanceAPIServer.app
76
+ end
77
+
78
+ map "/" do
79
+ run lambda {
80
+ Rack::Response.new("hello").finish
81
+ }
82
+ end
@@ -0,0 +1,45 @@
1
+
2
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../../../server/lib')
3
+ require 'ey_instance_api_server'
4
+ require 'ey_instance_api_server/snapshots/example_callback'
5
+
6
+ class MyCallback < EY::InstanceAPIServer::Snapshots::ExampleCallback
7
+ def initialize(base_url)
8
+ super(base_url)
9
+ end
10
+
11
+ def perform_all
12
+ @instances.each do |instance_id, instance|
13
+ instance[:volumes].each do |volume_id, volume|
14
+ volume[:snapshots].each do |snapshot_id, snapshot|
15
+ perform_snapshots_for(instance_id, volume_id, snapshot_id)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ base_url = ENV["BASE_URL"] || abort("Provide a base url")
24
+
25
+ callback = MyCallback.new(URI.join(base_url, "api/"))
26
+ callback.add_instance("my-instance")
27
+ callback.add_volume("my-instance", "volume-1", "db")
28
+ EY::InstanceAPIServer.callback_module = callback
29
+
30
+ map "/api/peform_all" do
31
+ run lambda {
32
+ callback.perform_all
33
+ Rack::Response.new("{}").finish
34
+ }
35
+ end
36
+
37
+ map "/api" do
38
+ run EY::InstanceAPIServer.app
39
+ end
40
+
41
+ map "/" do
42
+ run lambda {
43
+ Rack::Response.new("hello").finish
44
+ }
45
+ end
@@ -0,0 +1,69 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe "Snapshots" do
4
+ before do
5
+ start_server("snapshot_base_config")
6
+ end
7
+
8
+ after do
9
+ stop_server
10
+ end
11
+
12
+ describe "with an invalid creds" do
13
+ it "returns 403 when the token is invalid" do
14
+ client = EY::InstanceAPIClient::Snapshots.new(EY::InstanceAPIClient::Config.new(base_url, "my-instance", "invalid-creds"))
15
+ lambda { client.list }.
16
+ should raise_error(EY::InstanceAPIClient::Connection::InvalidCredentials)
17
+ end
18
+ end
19
+
20
+ context "with an instance that exists" do
21
+ before do
22
+ @instance_id = 'my-instance'
23
+ @volume_id = 'volume-1'
24
+ @client = EY::InstanceAPIClient::Snapshots.new(EY::InstanceAPIClient::Config.new(base_url, "my-instance", "token-for-my-instance"))
25
+ end
26
+
27
+ describe "listing snapshots" do
28
+ it "Makes a request and Gets an empty list" do
29
+ list = @client.list
30
+ list.should == []
31
+ end
32
+ end
33
+
34
+ describe "requesting a snapshot" do
35
+ before do
36
+ @client.request
37
+ end
38
+
39
+ it "should show a requested snapshot in the list" do
40
+ list = @client.list
41
+ list.size.should == 1
42
+ snapshot = list.first
43
+ snapshot.state.should == "requested"
44
+ snapshot.progress.should be_nil
45
+ snapshot.volume.should == 'db' #should be one of 'util', 'data', 'db'
46
+ snapshot.id.should_not be_nil
47
+ snapshot.created_at.should be_within(4).of(Time.now)
48
+ end
49
+
50
+ describe "when the snapshot is performed" do
51
+ before do
52
+ @client.backend.api_call(URI.join(base_url, "peform_all").to_s, 200).post({})
53
+ end
54
+
55
+ it "should show in the listing" do
56
+ list = @client.list
57
+ list.size.should == 1
58
+ snapshot = list.first
59
+ snapshot.state.should == "in progress"
60
+ snapshot.progress.should == "0%"
61
+ snapshot.volume.should == 'db' #should be one of 'util', 'data', 'db'
62
+ snapshot.id.should_not be_nil
63
+ snapshot.created_at.should be_within(4).of(Time.now)
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,32 @@
1
+ Bundler.require(:test)
2
+
3
+ require 'ey_instance_api_client'
4
+
5
+ module Helpers
6
+ def start_server(config)
7
+ config_ru = File.dirname(__FILE__) + "/fixtures/#{config}.ru"
8
+ @server = RealWeb.start_server(config_ru, Proc.new do |server|
9
+ ENV["BASE_URL"] = server_url_for(server.port)
10
+ end)
11
+ end
12
+
13
+ def stop_server
14
+ @server.stop
15
+ end
16
+
17
+ def server_url
18
+ server_url_for(@server.port)
19
+ end
20
+
21
+ def server_url_for(port)
22
+ "http://127.0.0.1:#{port}/"
23
+ end
24
+
25
+ def base_url
26
+ URI.join(server_url, "api/").to_s
27
+ end
28
+ end
29
+
30
+ RSpec.configure do |c|
31
+ c.include Helpers
32
+ end
metadata ADDED
@@ -0,0 +1,211 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ey_instance_api_client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Engine Yard
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-23 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rest-client
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rake
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rspec
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: ruby-debug
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :development
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: rcov
93
+ prerelease: false
94
+ requirement: &id006 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ type: :development
104
+ version_requirements: *id006
105
+ - !ruby/object:Gem::Dependency
106
+ name: realweb
107
+ prerelease: false
108
+ requirement: &id007 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - "="
112
+ - !ruby/object:Gem::Version
113
+ hash: 23
114
+ segments:
115
+ - 0
116
+ - 1
117
+ - 6
118
+ version: 0.1.6
119
+ type: :development
120
+ version_requirements: *id007
121
+ - !ruby/object:Gem::Dependency
122
+ name: sinatra
123
+ prerelease: false
124
+ requirement: &id008 !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ type: :development
134
+ version_requirements: *id008
135
+ - !ruby/object:Gem::Dependency
136
+ name: fog
137
+ prerelease: false
138
+ requirement: &id009 !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ type: :development
148
+ version_requirements: *id009
149
+ description: Used by backups and snapshots
150
+ email:
151
+ - gems@engineyard.com
152
+ executables: []
153
+
154
+ extensions: []
155
+
156
+ extra_rdoc_files: []
157
+
158
+ files:
159
+ - lib/ey_instance_api_client/backup.rb
160
+ - lib/ey_instance_api_client/config.rb
161
+ - lib/ey_instance_api_client/connection.rb
162
+ - lib/ey_instance_api_client/snapshot.rb
163
+ - lib/ey_instance_api_client/version.rb
164
+ - lib/ey_instance_api_client.rb
165
+ - spec/backup_client_spec.rb
166
+ - spec/config_spec.rb
167
+ - spec/fixtures/backup_base_config.ru
168
+ - spec/fixtures/snapshot_base_config.ru
169
+ - spec/snapshot_client_spec.rb
170
+ - spec/spec_helper.rb
171
+ has_rdoc: true
172
+ homepage: http://github.com/engineyard/ey_instance_api_client
173
+ licenses: []
174
+
175
+ post_install_message:
176
+ rdoc_options: []
177
+
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ none: false
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ hash: 3
186
+ segments:
187
+ - 0
188
+ version: "0"
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ hash: 3
195
+ segments:
196
+ - 0
197
+ version: "0"
198
+ requirements: []
199
+
200
+ rubyforge_project:
201
+ rubygems_version: 1.5.2
202
+ signing_key:
203
+ specification_version: 3
204
+ summary: Client libraries used to consume instance api exposed by AWSM.
205
+ test_files:
206
+ - spec/backup_client_spec.rb
207
+ - spec/config_spec.rb
208
+ - spec/fixtures/backup_base_config.ru
209
+ - spec/fixtures/snapshot_base_config.ru
210
+ - spec/snapshot_client_spec.rb
211
+ - spec/spec_helper.rb