ey_instance_api_client 0.1.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.
- data/lib/ey_instance_api_client/backup.rb +56 -0
- data/lib/ey_instance_api_client/config.rb +28 -0
- data/lib/ey_instance_api_client/connection.rb +81 -0
- data/lib/ey_instance_api_client/snapshot.rb +29 -0
- data/lib/ey_instance_api_client/version.rb +5 -0
- data/lib/ey_instance_api_client.rb +43 -0
- data/spec/backup_client_spec.rb +88 -0
- data/spec/config_spec.rb +39 -0
- data/spec/fixtures/backup_base_config.ru +82 -0
- data/spec/fixtures/snapshot_base_config.ru +45 -0
- data/spec/snapshot_client_spec.rb +69 -0
- data/spec/spec_helper.rb +32 -0
- metadata +211 -0
@@ -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,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
|
data/spec/config_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|