deltacloud-client 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/COPYING +502 -0
  2. data/Rakefile +39 -0
  3. data/credentials.yml +2 -0
  4. data/init.rb +19 -0
  5. data/lib/dcloud/base_model.rb +80 -0
  6. data/lib/dcloud/flavor.rb +43 -0
  7. data/lib/dcloud/image.rb +46 -0
  8. data/lib/dcloud/instance.rb +97 -0
  9. data/lib/dcloud/realm.rb +47 -0
  10. data/lib/dcloud/state.rb +30 -0
  11. data/lib/dcloud/storage_snapshot.rb +50 -0
  12. data/lib/dcloud/storage_volume.rb +53 -0
  13. data/lib/dcloud/transition.rb +35 -0
  14. data/lib/deltacloud.rb +356 -0
  15. data/specs/data/images/img1.yml +3 -0
  16. data/specs/data/images/img2.yml +3 -0
  17. data/specs/data/images/img3.yml +3 -0
  18. data/specs/data/instances/inst1.yml +8 -0
  19. data/specs/data/instances/inst2.yml +8 -0
  20. data/specs/data/storage_snapshots/snap1.yml +4 -0
  21. data/specs/data/storage_snapshots/snap2.yml +4 -0
  22. data/specs/data/storage_snapshots/snap3.yml +4 -0
  23. data/specs/data/storage_volumes/vol1.yml +6 -0
  24. data/specs/data/storage_volumes/vol2.yml +6 -0
  25. data/specs/data/storage_volumes/vol3.yml +6 -0
  26. data/specs/fixtures/images/img1.yml +3 -0
  27. data/specs/fixtures/images/img2.yml +3 -0
  28. data/specs/fixtures/images/img3.yml +3 -0
  29. data/specs/fixtures/instances/inst1.yml +8 -0
  30. data/specs/fixtures/instances/inst2.yml +8 -0
  31. data/specs/fixtures/storage_snapshots/snap1.yml +4 -0
  32. data/specs/fixtures/storage_snapshots/snap2.yml +4 -0
  33. data/specs/fixtures/storage_snapshots/snap3.yml +4 -0
  34. data/specs/fixtures/storage_volumes/vol1.yml +6 -0
  35. data/specs/fixtures/storage_volumes/vol2.yml +6 -0
  36. data/specs/fixtures/storage_volumes/vol3.yml +6 -0
  37. data/specs/flavors_spec.rb +67 -0
  38. data/specs/images_spec.rb +104 -0
  39. data/specs/initialization_spec.rb +59 -0
  40. data/specs/instance_states_spec.rb +77 -0
  41. data/specs/instances_spec.rb +171 -0
  42. data/specs/realms_spec.rb +65 -0
  43. data/specs/shared/resources.rb +29 -0
  44. data/specs/spec_helper.rb +54 -0
  45. data/specs/storage_snapshot_spec.rb +76 -0
  46. data/specs/storage_volume_spec.rb +86 -0
  47. metadata +108 -0
@@ -0,0 +1,53 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'dcloud/base_model'
19
+
20
+ module DCloud
21
+ class StorageVolume < BaseModel
22
+
23
+ xml_tag_name :storage_volume
24
+
25
+ attribute :created
26
+ attribute :state
27
+ attribute :capacity
28
+ attribute :device
29
+ attribute :instance
30
+
31
+ def initialize(client, uri, xml=nil)
32
+ super( client, uri, xml )
33
+ end
34
+
35
+ def load_payload(xml=nil)
36
+ super(xml)
37
+ unless xml.nil?
38
+ @created = xml.text( 'created' )
39
+ @state = xml.text( 'state' )
40
+ @capacity = xml.text( 'capacity' ).to_f
41
+ @device = xml.text( 'device' )
42
+ instances = xml.get_elements( 'instance' )
43
+ if ( ! instances.empty? )
44
+ instance = instances.first
45
+ instance_href = instance.attributes['href']
46
+ if ( instance_href )
47
+ @instance = Instance.new( @client, instance_href )
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+
19
+ module DCloud
20
+ class Transition
21
+
22
+ attr_accessor :to
23
+ attr_accessor :action
24
+
25
+ def initialize(to, action)
26
+ @to = to
27
+ @action = action
28
+ end
29
+
30
+ def auto?()
31
+ @action.nil?
32
+ end
33
+
34
+ end
35
+ end
data/lib/deltacloud.rb ADDED
@@ -0,0 +1,356 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'rest_client'
19
+ require 'rexml/document'
20
+ require 'logger'
21
+ require 'dcloud/flavor'
22
+ require 'dcloud/realm'
23
+ require 'dcloud/image'
24
+ require 'dcloud/instance'
25
+ require 'dcloud/storage_volume'
26
+ require 'dcloud/storage_snapshot'
27
+ require 'dcloud/state'
28
+ require 'dcloud/transition'
29
+ require 'base64'
30
+
31
+ module RestClient
32
+ class Response
33
+ def body
34
+ self.to_s
35
+ end
36
+ end
37
+ end
38
+
39
+ class DeltaCloud
40
+
41
+ attr_accessor :logger
42
+ attr_reader :api_uri
43
+ attr_reader :entry_points
44
+ attr_reader :driver_name
45
+
46
+ def self.driver_name(url)
47
+ DeltaCloud.new( nil, nil, url) do |client|
48
+ return client.driver_name
49
+ end
50
+ end
51
+
52
+ def initialize(name, password, api_uri, &block)
53
+ @logger = Logger.new( STDERR )
54
+ @name = name
55
+ @password = password
56
+ @api_uri = URI.parse( api_uri )
57
+ @entry_points = {}
58
+ discover_entry_points
59
+ connect( &block )
60
+ self
61
+ end
62
+
63
+
64
+ def connect(&block)
65
+ @http = RestClient::Resource.new( api_uri.to_s , :accept => 'application/xml' )
66
+ discover_entry_points
67
+ block.call( self ) if block
68
+ self
69
+ end
70
+
71
+ def api_host
72
+ @api_uri.host
73
+ end
74
+
75
+ def api_port
76
+ @api_uri.port
77
+ end
78
+
79
+ def api_path
80
+ @api_uri.path
81
+ end
82
+
83
+ def flavors(opts={})
84
+ flavors = []
85
+ request(entry_points[:flavors], :get, opts) do |response|
86
+ doc = REXML::Document.new( response )
87
+ doc.get_elements( 'flavors/flavor' ).each do |flavor|
88
+ uri = flavor.attributes['href']
89
+ flavors << DCloud::Flavor.new( self, uri, flavor )
90
+ end
91
+ end
92
+ flavors
93
+ end
94
+
95
+ def flavor(id)
96
+ request( entry_points[:flavors], :get, {:id=>id } ) do |response|
97
+ doc = REXML::Document.new( response.body )
98
+ doc.get_elements( '/flavor' ).each do |flavor|
99
+ uri = flavor.attributes['href']
100
+ return DCloud::Flavor.new( self, uri, flavor )
101
+ end
102
+ end
103
+ end
104
+
105
+ def fetch_flavor(uri)
106
+ xml = fetch_resource( :flavor, uri )
107
+ return DCloud::Flavor.new( self, uri, xml ) if xml
108
+ nil
109
+ end
110
+
111
+ def fetch_resource(type, uri)
112
+ request( uri ) do |response|
113
+ doc = REXML::Document.new( response.body )
114
+ if ( doc.root && ( doc.root.name == type.to_s.gsub( /_/, '-' ) ) )
115
+ return doc.root
116
+ end
117
+ end
118
+ nil
119
+ end
120
+
121
+ def instance_states
122
+ states = []
123
+ request( entry_points[:instance_states] ) do |response|
124
+ doc = REXML::Document.new( response.body )
125
+ doc.get_elements( 'states/state' ).each do |state_elem|
126
+ state = DCloud::State.new( state_elem.attributes['name'] )
127
+ state_elem.get_elements( 'transition' ).each do |transition_elem|
128
+ state.transitions << DCloud::Transition.new(
129
+ transition_elem.attributes['to'],
130
+ transition_elem.attributes['action']
131
+ )
132
+ end
133
+ states << state
134
+ end
135
+ end
136
+ states
137
+ end
138
+
139
+ def instance_state(name)
140
+ found = instance_states.find{|e| e.name.to_s == name.to_s}
141
+ found
142
+ end
143
+
144
+ def realms(opts={})
145
+ realms = []
146
+ request( entry_points[:realms], :get, opts ) do |response|
147
+ doc = REXML::Document.new( response.body )
148
+ doc.get_elements( 'realms/realm' ).each do |realm|
149
+ uri = realm.attributes['href']
150
+ realms << DCloud::Realm.new( self, uri, realm )
151
+ end
152
+ end
153
+ realms
154
+ end
155
+
156
+ def realm(id)
157
+ request( entry_points[:realms], :get, {:id=>id } ) do |response|
158
+ doc = REXML::Document.new( response.body )
159
+ doc.get_elements( 'realm' ).each do |realm|
160
+ uri = realm.attributes['href']
161
+ return DCloud::Realm.new( self, uri, realm )
162
+ end
163
+ end
164
+ nil
165
+ end
166
+
167
+ def fetch_realm(uri)
168
+ xml = fetch_resource( :realm, uri )
169
+ return DCloud::Realm.new( self, uri, xml ) if xml
170
+ nil
171
+ end
172
+
173
+ def images(opts={})
174
+ images = []
175
+ request_path = entry_points[:images]
176
+ request( request_path, :get, opts ) do |response|
177
+ doc = REXML::Document.new( response.body )
178
+ doc.get_elements( 'images/image' ).each do |image|
179
+ uri = image.attributes['href']
180
+ images << DCloud::Image.new( self, uri, image )
181
+ end
182
+ end
183
+ images
184
+ end
185
+
186
+ def image(id)
187
+ request( entry_points[:images], :get, {:id=>id } ) do |response|
188
+ doc = REXML::Document.new( response.body )
189
+ doc.get_elements( 'image' ).each do |instance|
190
+ uri = instance.attributes['href']
191
+ return DCloud::Image.new( self, uri, instance )
192
+ end
193
+ end
194
+ nil
195
+ end
196
+
197
+ def instances
198
+ instances = []
199
+ request( entry_points[:instances] ) do |response|
200
+ doc = REXML::Document.new( response.body )
201
+ doc.get_elements( 'instances/instance' ).each do |instance|
202
+ uri = instance.attributes['href']
203
+ instances << DCloud::Instance.new( self, uri, instance )
204
+ end
205
+ end
206
+ instances
207
+ end
208
+
209
+ def instance(id)
210
+ request( entry_points[:instances], :get, {:id=>id } ) do |response|
211
+ doc = REXML::Document.new( response.body )
212
+ doc.get_elements( 'instance' ).each do |instance|
213
+ uri = instance.attributes['href']
214
+ return DCloud::Instance.new( self, uri, instance )
215
+ end
216
+ end
217
+ nil
218
+ end
219
+
220
+ def post_instance(uri)
221
+ request( uri, :post ) do |response|
222
+ return true
223
+ end
224
+ return false
225
+ end
226
+
227
+ def fetch_instance(uri)
228
+ xml = fetch_resource( :instance, uri )
229
+ return DCloud::Instance.new( self, uri, xml ) if xml
230
+ nil
231
+ end
232
+
233
+ def create_instance(image_id, opts={})
234
+ name = opts[:name]
235
+ realm_id = opts[:realm]
236
+ flavor_id = opts[:flavor]
237
+
238
+ params = {}
239
+ ( params[:realm_id] = realm_id ) if realm_id
240
+ ( params[:flavor_id] = flavor_id ) if flavor_id
241
+ ( params[:name] = name ) if name
242
+
243
+ params[:image_id] = image_id
244
+ request( entry_points[:instances], :post, {}, params ) do |response|
245
+ doc = REXML::Document.new( response.body )
246
+ instance = doc.root
247
+ uri = instance.attributes['href']
248
+ return DCloud::Instance.new( self, uri, instance )
249
+ end
250
+ end
251
+
252
+ def storage_volumes
253
+ storage_volumes = []
254
+ request( entry_points[:storage_volumes] ) do |response|
255
+ doc = REXML::Document.new( response.body )
256
+ doc.get_elements( 'storage-volumes/storage-volume' ).each do |instance|
257
+ uri = instance.attributes['href']
258
+ storage_volumes << DCloud::StorageVolume.new( self, uri, instance )
259
+ end
260
+ end
261
+ storage_volumes
262
+ end
263
+
264
+ def storage_volume(id)
265
+ request( entry_points[:storage_volumes], :get, {:id=>id } ) do |response|
266
+ doc = REXML::Document.new( response.body )
267
+ doc.get_elements( 'storage-volume' ).each do |storage_volume|
268
+ uri = storage_volume.attributes['href']
269
+ return DCloud::StorageVolume.new( self, uri, storage_volume )
270
+ end
271
+ end
272
+ nil
273
+ end
274
+
275
+ def fetch_storage_volume(uri)
276
+ xml = fetch_resource( :storage_volume, uri )
277
+ return DCloud::StorageVolume.new( self, uri, xml ) if xml
278
+ nil
279
+ end
280
+
281
+ def storage_snapshots()
282
+ storage_snapshots = []
283
+ request( entry_points[:storage_snapshots] ) do |response|
284
+ doc = REXML::Document.new( response.body )
285
+ doc.get_elements( 'storage-snapshots/storage-snapshot' ).each do |instance|
286
+ uri = instance.attributes['href']
287
+ storage_snapshots << DCloud::StorageSnapshot.new( self, uri, instance )
288
+ end
289
+ end
290
+ storage_snapshots
291
+ end
292
+
293
+ def storage_snapshot(id)
294
+ request( entry_points[:storage_snapshots], :get, {:id=>id } ) do |response|
295
+ doc = REXML::Document.new( response.body )
296
+ doc.get_elements( 'storage-snapshot' ).each do |storage_snapshot|
297
+ uri = storage_snapshot.attributes['href']
298
+ return DCloud::StorageSnapshot.new( self, uri, storage_snapshot )
299
+ end
300
+ end
301
+ nil
302
+ end
303
+
304
+ def fetch_storage_snapshot(uri)
305
+ xml = fetch_resource( :storage_snapshot, uri )
306
+ return DCloud::StorageSnapshot.new( self, uri, xml ) if xml
307
+ nil
308
+ end
309
+
310
+ def fetch_image(uri)
311
+ xml = fetch_resource( :image, uri )
312
+ return DCloud::Image.new( self, uri, xml ) if xml
313
+ nil
314
+ end
315
+
316
+ private
317
+
318
+ attr_reader :http
319
+
320
+ def discover_entry_points
321
+ request(api_uri.to_s) do |response|
322
+ doc = REXML::Document.new( response.body )
323
+ @driver_name = doc.root.attributes['driver']
324
+ doc.get_elements( 'api/link' ).each do |link|
325
+ rel = link.attributes['rel']
326
+ uri = link.attributes['href']
327
+ @entry_points[rel.to_sym] = uri
328
+ end
329
+ end
330
+ end
331
+
332
+ def request(path='', method=:get, query_args={}, form_data={}, &block)
333
+ if ( path =~ /^http/ )
334
+ request_path = path
335
+ else
336
+ request_path = "#{api_uri.to_s}#{path}"
337
+ end
338
+ if query_args[:id]
339
+ request_path += "/#{query_args[:id]}"
340
+ query_args.delete(:id)
341
+ end
342
+ query_string = URI.escape(query_args.collect{|k,v| "#{k}=#{v}"}.join('&'))
343
+ request_path += "?#{query_string}" unless query_string==''
344
+ headers = {
345
+ :authorization => "Basic "+Base64.encode64("#{@name}:#{@password}"),
346
+ :accept => "application/xml"
347
+ }
348
+ logger << "Request [#{method.to_s.upcase}] #{request_path}]\n"
349
+ if method.eql?(:get)
350
+ RestClient.send(method, request_path, headers, &block)
351
+ else
352
+ RestClient.send(method, request_path, form_data, headers, &block)
353
+ end
354
+ end
355
+
356
+ end
@@ -0,0 +1,3 @@
1
+ :description: Fedora 10
2
+ :owner_id: fedoraproject
3
+ :architecture: x86_64