ey_instance_api_server 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ require 'ey_instance_api_server/backups'
2
+ require 'ey_instance_api_server/snapshots'
3
+ require 'ey_instance_api_server/services'
4
+
5
+ module EY
6
+ module InstanceAPIServer
7
+
8
+ def self.services_url_for(app_name)
9
+ URI.join(base_url, "services/app/", app_name).to_s
10
+ end
11
+
12
+ def self.get_services_for(instance_id, app_name)
13
+ callback_module.get_services_for(instance_id, app_name)
14
+ end
15
+
16
+ def self.snapshots_base_url
17
+ URI.join(base_url, "volumes/all/snapshots").to_s
18
+ end
19
+
20
+ def self.snapshots_url_for_performing(instance_id, volume_id, snapshot_id, instance_token)
21
+ path = "volumes/#{volume_id}/snapshots/#{snapshot_id}/perform"+
22
+ "?instance_id=#{CGI.escape(instance_id.to_s)}"+
23
+ "&token=#{CGI.escape(instance_token.to_s)}"
24
+ URI.join(base_url, path).to_s
25
+ end
26
+
27
+ def self.request_snapshots_for(instance_id)
28
+ callback_module.request_snapshots_for(instance_id)
29
+ end
30
+
31
+ def self.perform_snapshot_for(instance_id, volume_id, snapshot_id)
32
+ callback_module.perform_snapshots_for(instance_id, volume_id, snapshot_id)
33
+ end
34
+
35
+ def self.list_snapshots_for(instance_id)
36
+ callback_module.list_snapshots_for(instance_id)
37
+ end
38
+
39
+ def self.snapshot_response(volume_id, snapshot_id, volume_type, created_at, state, progress)
40
+ {
41
+ "volume_id" => volume_id,
42
+ "volume_type" => volume_type,
43
+ "snapshot_id" => snapshot_id,
44
+ "created_at" => created_at,
45
+ "state" => state,
46
+ "progress" => progress,
47
+ }
48
+ end
49
+
50
+ def self.backups_url_for(database_id)
51
+ URI.join(base_url, "databases/#{database_id}/backups").to_s
52
+ end
53
+
54
+ def self.start_backup_for(instance_id, database_id, extension, part_count)
55
+ callback_module.start_backup_for(instance_id, database_id, extension, part_count)
56
+ end
57
+
58
+ def self.finish_backup_for(instance_id, database_id, backup_id)
59
+ callback_module.finish_backup_for(instance_id, database_id, backup_id)
60
+ end
61
+
62
+ def self.list_backups_for(instance_id, database_id)
63
+ callback_module.list_backups_for(instance_id, database_id)
64
+ end
65
+
66
+ def self.started_backup(backup_id, database_id, extension, upload_urls, started_at)
67
+ {
68
+ "started_at" => started_at.to_i,
69
+ "extension" => extension,
70
+ "upload_urls" => upload_urls,
71
+ 'finish_url' => "#{backups_url_for(database_id)}/#{backup_id}"
72
+ }
73
+ end
74
+
75
+ def self.pending_backup(backup_id, database_id, extension, started_at)
76
+ {
77
+ "started_at" => started_at.to_i,
78
+ "extension" => extension,
79
+ }
80
+ end
81
+
82
+ def self.finished_backup(backup_id, database_id, extension, download_urls, started_at, finished_at)
83
+ {
84
+ "started_at" => started_at.to_i,
85
+ "finished_at" => finished_at.to_i,
86
+ "extension" => extension,
87
+ "download_urls" => download_urls
88
+ }
89
+ end
90
+
91
+ def self.valid?(label, token)
92
+ token_for(label) == token
93
+ end
94
+
95
+ def self.token_for(label)
96
+ callback_module.token_for label
97
+ end
98
+
99
+ def self.base_url
100
+ base_url = callback_module.base_url
101
+ unless base_url.match(/\/$/)
102
+ base_url += '/'
103
+ end
104
+ base_url
105
+ end
106
+
107
+ def self.app
108
+ Rack::Builder.app do
109
+ map "/databases/" do
110
+ run Backups.app
111
+ end
112
+ map "/volumes/" do
113
+ run Snapshots.app
114
+ end
115
+ map "/services/" do
116
+ run Services.app
117
+ end
118
+ end
119
+ end
120
+
121
+ class << self; attr_accessor :callback_module end
122
+ end
123
+ end
@@ -0,0 +1,25 @@
1
+ module EY
2
+ module InstanceAPIServer
3
+ module Abstract
4
+ class ExampleCallback
5
+ def initialize(base_url)
6
+ @base_url = base_url.to_s
7
+ @instances = {}
8
+ end
9
+ attr_reader :base_url
10
+
11
+ def token_for(instance_id)
12
+ if @instances.include?(instance_id)
13
+ "token-for-#{instance_id}"
14
+ else
15
+ "invalid"
16
+ end
17
+ end
18
+
19
+ def add_instance(instance_id, value = {})
20
+ @instances[instance_id] = value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Backups
7
+ def self.app
8
+ Rackapp
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'ey_instance_api_server/backups/rackapp'
@@ -0,0 +1,70 @@
1
+ require 'ey_instance_api_server/abstract/example_callback'
2
+ module EY
3
+ module InstanceAPIServer
4
+ module Backups
5
+ class ExampleCallback < InstanceAPIServer::Abstract::ExampleCallback
6
+
7
+ def list_backups_for(instance_id, database_id)
8
+ if backups_hash = backups_for(instance_id, database_id)
9
+ backups = []
10
+ backups_hash.map do |backup_id,backup_hash|
11
+ extension = backup_hash[:extension]
12
+ if backup_hash[:complete]
13
+ download_urls = []
14
+ backup_hash[:part_count].times do |part|
15
+ download_urls << download_url_for(backup_id, part)
16
+ end
17
+ backups << EY::InstanceAPIServer.finished_backup(backup_id, database_id, extension, download_urls, Time.now - 1, Time.now)
18
+ else
19
+ backups << EY::InstanceAPIServer.pending_backup(backup_id, database_id, extension, Time.now)
20
+ end
21
+ end
22
+ backups
23
+ end
24
+ end
25
+
26
+ def start_backup_for(instance_id, database_id, extension, part_count)
27
+ if backups = backups_for(instance_id, database_id)
28
+ backup_id = backups.size.to_s
29
+ upload_urls = []
30
+ part_count = Integer(part_count)
31
+ part_count.times do |part|
32
+ upload_urls << upload_url_for(backup_id, part)
33
+ end
34
+ backup = EY::InstanceAPIServer.started_backup(backup_id, database_id, extension, upload_urls, Time.now)
35
+ backups[backup_id] = {
36
+ :extension => extension,
37
+ :part_count => part_count
38
+ }
39
+ backup
40
+ end
41
+ end
42
+
43
+ def upload_url_for(backup_id, part)
44
+ "http://s3/PUT/something/#{part}"
45
+ end
46
+
47
+ def finish_backup_for(instance_id, database_id, backup_id)
48
+ backups = backups_for(instance_id, database_id)
49
+ if backup_hash = backups[backup_id]
50
+ unless backup_hash[:complete]
51
+ backup_hash[:complete] = true
52
+ end
53
+ end
54
+ end
55
+
56
+ def download_url_for(backup_id, part)
57
+ "http://s3/GET/something/#{part}"
58
+ end
59
+
60
+ def backups_for(instance_id, database_id)
61
+ @instances[instance_id][database_id]
62
+ end
63
+
64
+ def add_database(instance_id, database_id)
65
+ @instances[instance_id][database_id] ||= {}
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,80 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Backups
7
+ class Rackapp < Sinatra::Base
8
+ enable :raise_errors
9
+ disable :dump_errors
10
+ disable :show_exceptions
11
+
12
+ before { content_type :json }
13
+
14
+ def validate!
15
+ unless valid?
16
+ halt 403, {}.to_json
17
+ end
18
+ end
19
+
20
+ def not_found
21
+ status 404
22
+ {}.to_json
23
+ end
24
+
25
+ get "/" do
26
+ {}.to_json
27
+ end
28
+
29
+ get "/:id/backups" do |database_id|
30
+ validate!
31
+ if backups = InstanceAPIServer.list_backups_for(instance_id, database_id)
32
+ backups_hash = backups.map do |backup|
33
+ backup.to_hash
34
+ end
35
+ {'backups' => backups_hash}.to_json
36
+ else
37
+ not_found
38
+ end
39
+ end
40
+
41
+ post "/:id/backups" do |database_id|
42
+ validate!
43
+ extension = params[:extension]
44
+ part_count = params[:part_count]
45
+ if backup = InstanceAPIServer.start_backup_for(instance_id, database_id, extension, part_count)
46
+ status 201
47
+ {'backup' => backup.to_hash}.to_json
48
+ else
49
+ not_found
50
+ end
51
+ end
52
+
53
+ put "/:database_id/backups/:id" do |database_id,backup_id|
54
+ validate!
55
+ if backup = InstanceAPIServer.finish_backup_for(instance_id, database_id, backup_id)
56
+ {}.to_json
57
+ else
58
+ status 409
59
+ {}.to_json
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def valid?
66
+ InstanceAPIServer.valid?(instance_id, token)
67
+ end
68
+
69
+ def instance_id
70
+ params['instance_id']
71
+ end
72
+
73
+ def token
74
+ params['token']
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
@@ -0,0 +1,14 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Services
7
+ def self.app
8
+ Rackapp
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'ey_instance_api_server/services/rackapp'
@@ -0,0 +1,14 @@
1
+ require 'ey_instance_api_server/abstract/example_callback'
2
+ module EY
3
+ module InstanceAPIServer
4
+ module Services
5
+ class ExampleCallback < InstanceAPIServer::Abstract::ExampleCallback
6
+
7
+ def get_services_for(instance_id, app_name)
8
+ @instances[instance_id] && @instances[instance_id][app_name]
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Services
7
+ class Rackapp < Sinatra::Base
8
+ enable :raise_errors
9
+ disable :dump_errors
10
+ disable :show_exceptions
11
+
12
+ before { content_type :json }
13
+
14
+ def validate!
15
+ unless valid?
16
+ halt 403, {}.to_json
17
+ end
18
+ end
19
+
20
+ def not_found
21
+ status 404
22
+ {}.to_json
23
+ end
24
+
25
+ get "/app/:app_name" do |app_name|
26
+ InstanceAPIServer.get_services_for(instance_id, app_name).to_json
27
+ end
28
+
29
+ private
30
+
31
+ def valid?
32
+ InstanceAPIServer.valid?(instance_id, token)
33
+ end
34
+
35
+ def instance_id
36
+ params['instance_id']
37
+ end
38
+
39
+ def token
40
+ params['token']
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,14 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Snapshots
7
+ def self.app
8
+ Rackapp
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'ey_instance_api_server/snapshots/rackapp'
@@ -0,0 +1,83 @@
1
+ require 'ey_instance_api_server/abstract/example_callback'
2
+ module EY
3
+ module InstanceAPIServer
4
+ module Snapshots
5
+ class ExampleCallback < InstanceAPIServer::Abstract::ExampleCallback
6
+ def initialize(*)
7
+ super
8
+ @snaplock_callbacks = []
9
+ Fog.mock!
10
+ end
11
+ attr_reader :snaplock_callbacks
12
+
13
+ def add_instance(instance_id, fog_instance = create_fog_instance)
14
+ super(instance_id, {:instance_fog => fog_instance})
15
+ end
16
+
17
+ def list_snapshots_for(instance_id)
18
+ volumes = @instances[instance_id][:volumes]
19
+ to_return = []
20
+ volumes.each do |vol_id, vol|
21
+ snapshots = vol[:snapshots]
22
+ snapshots.each do |snapshot_id, snapshot_info|
23
+ if snapshot_fog = snapshot_info[:snapshot_fog]
24
+ snapshot_fog.reload
25
+ to_return << EY::InstanceAPIServer.snapshot_response(vol_id, snapshot_id, vol[:volume_type], snapshot_info[:created_at], snapshot_fog.state, snapshot_fog.progress)
26
+ else
27
+ to_return << EY::InstanceAPIServer.snapshot_response(vol_id, snapshot_id, vol[:volume_type], snapshot_info[:created_at], "requested", nil)
28
+ end
29
+ end
30
+ end
31
+ to_return
32
+ end
33
+
34
+ def request_snapshots_for(instance_id)
35
+ volumes = @instances[instance_id][:volumes]
36
+ volumes.each do |vol_id, vol|
37
+ snapshots = vol[:snapshots]
38
+ volume_fog = vol[:volume_fog]
39
+ @@next_snapshot_id ||= 0
40
+ snapshot_id = (@@next_snapshot_id += 1).to_s
41
+ snapshots[snapshot_id] = {:created_at => Time.now}
42
+ @snaplock_callbacks << EY::InstanceAPIServer.snapshots_url_for_performing(instance_id, vol_id, snapshot_id, "token-for-#{instance_id}")
43
+ end
44
+ end
45
+
46
+ def perform_snapshots_for(instance_id, volume_id, snapshot_id)
47
+ if vol = volume_info(instance_id, volume_id)
48
+ snapshots = vol[:snapshots]
49
+ volume_fog = vol[:volume_fog]
50
+ if snapshot_info = snapshots[snapshot_id]
51
+ snapshot_fog = volume_fog.snapshots.create
52
+ snapshot_info[:snapshot_fog] = snapshot_fog
53
+ end
54
+ end
55
+ end
56
+
57
+ def volume_info(instance_id, volume_id)
58
+ @instances[instance_id] && @instances[instance_id][:volumes] && @instances[instance_id][:volumes][volume_id]
59
+ end
60
+
61
+ def add_volume(instance_id, volume_id, type)
62
+ instance_fog = @instances[instance_id][:instance_fog]
63
+ volume_fog = instance_fog.volumes.create(:size => 5, :device => 'dev/sdz123')
64
+ @instances[instance_id][:volumes] ||= {}
65
+ @instances[instance_id][:volumes][volume_id] ||= {:volume_fog => volume_fog, :volume_type => type, :snapshots => {}}
66
+ end
67
+
68
+ private
69
+
70
+ def create_fog_instance
71
+ Fog::AWS::Compute.new(
72
+ :aws_access_key_id => "fake",
73
+ :aws_secret_access_key => "fake"
74
+ ).servers.create(
75
+ :flavor_id => 'm1.large',
76
+ :image_id => 'ami-blah'
77
+ )
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,78 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module EY
5
+ module InstanceAPIServer
6
+ module Snapshots
7
+ class Rackapp < Sinatra::Base
8
+ enable :raise_errors
9
+ disable :dump_errors
10
+ disable :show_exceptions
11
+
12
+ before { content_type :json }
13
+
14
+ def validate!
15
+ unless valid?
16
+ halt 403, {}.to_json
17
+ end
18
+ end
19
+
20
+ def not_found
21
+ status 404
22
+ {}.to_json
23
+ end
24
+
25
+ get "/" do
26
+ {}.to_json
27
+ end
28
+
29
+ get "/all/snapshots" do
30
+ validate!
31
+ if snapshots = InstanceAPIServer.list_snapshots_for(instance_id)
32
+ snapshots_hash = snapshots.map do |snapshot|
33
+ snapshot.to_hash
34
+ end
35
+ {'snapshots' => snapshots_hash}.to_json
36
+ else
37
+ not_found
38
+ end
39
+ end
40
+
41
+ post "/all/snapshots" do
42
+ validate!
43
+ if snapshot = InstanceAPIServer.request_snapshots_for(instance_id)
44
+ status 201
45
+ {}.to_json
46
+ else
47
+ not_found
48
+ end
49
+ end
50
+
51
+ post "/:id/snapshots/:id/perform" do |volume_id, snapshot_id|
52
+ validate!
53
+ if snapshot = InstanceAPIServer.perform_snapshot_for(instance_id, volume_id, snapshot_id)
54
+ status 201
55
+ {}.to_json
56
+ else
57
+ not_found
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def valid?
64
+ InstanceAPIServer.valid?(instance_id, token)
65
+ end
66
+
67
+ def instance_id
68
+ params['instance_id']
69
+ end
70
+
71
+ def token
72
+ params['token']
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,5 @@
1
+ module EY
2
+ module InstanceAPIServer
3
+ VERSION = "0.1.5"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ey_instance_api_server
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 5
10
+ version: 0.1.5
11
+ platform: ruby
12
+ authors:
13
+ - Jacob Burkhart
14
+ - Tim Carey-Smith
15
+ - Martin Emde
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-11-01 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: json
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: sinatra
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 15
45
+ segments:
46
+ - 1
47
+ - 0
48
+ version: "1.0"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rake
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: rspec
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: ruby-debug
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id005
93
+ - !ruby/object:Gem::Dependency
94
+ name: rack-client
95
+ prerelease: false
96
+ requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ type: :development
106
+ version_requirements: *id006
107
+ - !ruby/object:Gem::Dependency
108
+ name: rcov
109
+ prerelease: false
110
+ requirement: &id007 !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ type: :development
120
+ version_requirements: *id007
121
+ - !ruby/object:Gem::Dependency
122
+ name: fog
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
+ description: Used by snapshots and services (was going to be used by backups)
136
+ email:
137
+ - cloud-engineering@engineyard.com
138
+ executables: []
139
+
140
+ extensions: []
141
+
142
+ extra_rdoc_files: []
143
+
144
+ files:
145
+ - lib/ey_instance_api_server/abstract/example_callback.rb
146
+ - lib/ey_instance_api_server/backups/example_callback.rb
147
+ - lib/ey_instance_api_server/backups/rackapp.rb
148
+ - lib/ey_instance_api_server/backups.rb
149
+ - lib/ey_instance_api_server/services/example_callback.rb
150
+ - lib/ey_instance_api_server/services/rackapp.rb
151
+ - lib/ey_instance_api_server/services.rb
152
+ - lib/ey_instance_api_server/snapshots/example_callback.rb
153
+ - lib/ey_instance_api_server/snapshots/rackapp.rb
154
+ - lib/ey_instance_api_server/snapshots.rb
155
+ - lib/ey_instance_api_server/version.rb
156
+ - lib/ey_instance_api_server.rb
157
+ homepage:
158
+ licenses: []
159
+
160
+ post_install_message:
161
+ rdoc_options: []
162
+
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ hash: 3
171
+ segments:
172
+ - 0
173
+ version: "0"
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ hash: 3
180
+ segments:
181
+ - 0
182
+ version: "0"
183
+ requirements: []
184
+
185
+ rubyforge_project:
186
+ rubygems_version: 1.8.10
187
+ signing_key:
188
+ specification_version: 3
189
+ summary: Server libraries used to expose the instance api in AWSM.
190
+ test_files: []
191
+