ey_instance_api_server 0.1.5

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