ey_instance_api_client 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|