right_slicehost 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 2009-20-02
2
+
3
+ * Initial release
4
+
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/right_slicehost.rb
6
+ lib/slicehost_base.rb
7
+ lib/benchmark_fix.rb
8
+ lib/support.rb
9
+ test/test_right_slicehost.rb
10
+ test/_test_helper.rb
11
+ test/_test_credentials.rb
@@ -0,0 +1,47 @@
1
+ = RightScale Slicehost API Ruby Gem
2
+
3
+ Published by RightScale, Inc. under the MIT License.
4
+ For information about RightScale, see http://www.rightscale.com
5
+
6
+ == DESCRIPTION:
7
+
8
+ The RightScale Slicehost gem has been designed to provide a robust interface to Slicehost's existing API.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ - Full programmatic access to the Slicehost API.
13
+ - Complete error handling: all operations check for errors and report complete
14
+ error information by raising a SlicehostError.
15
+ - Persistent HTTP connections with robust network-level retry layer using
16
+ Rightscale::HttpConnection. This includes socket timeouts and retries.
17
+ - Robust HTTP-level retry layer. Certain (user-adjustable) HTTP errors
18
+ returned by Slicehost are classified as temporary errors.
19
+ These errors are automaticallly retried using exponentially increasing intervals.
20
+ The number of retries is user-configurable.
21
+
22
+ == INSTALL:
23
+
24
+ sudo gem install right_slicehost
25
+
26
+ == LICENSE:
27
+
28
+ Copyright (c) 2007-2009 RightScale, Inc.
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining
31
+ a copy of this software and associated documentation files (the
32
+ 'Software'), to deal in the Software without restriction, including
33
+ without limitation the rights to use, copy, modify, merge, publish,
34
+ distribute, sublicense, and/or sell copies of the Software, and to
35
+ permit persons to whom the Software is furnished to do so, subject to
36
+ the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be
39
+ included in all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
42
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require "rake/testtask"
4
+ require 'rcov/rcovtask'
5
+ $: << File.dirname(__FILE__)
6
+ require './lib/right_slicehost.rb'
7
+
8
+ # Suppress Hoe's self-inclusion as a dependency for our Gem. This also keeps
9
+ # Rake & rubyforge out of the dependency list. Users must manually install
10
+ # these gems to run tests, etc.
11
+ # TRB 2/20/09: also do this for the extra_dev_deps array present in newer hoes.
12
+ # Older versions of RubyGems will try to install developer-dependencies as
13
+ # required runtime dependencies....
14
+ class Hoe
15
+ def extra_deps
16
+ @extra_deps.reject do |x|
17
+ Array(x).first == 'hoe'
18
+ end
19
+ end
20
+ def extra_dev_deps
21
+ @extra_dev_deps.reject do |x|
22
+ Array(x).first == 'hoe'
23
+ end
24
+ end
25
+ end
26
+
27
+ Hoe.new('right_slicehost', RightSlicehost::VERSION) do |p|
28
+ p.rubyforge_name = 'rightscale'
29
+ p.author = 'RightScale, Inc.'
30
+ p.email = 'rubygems@rightscale.com'
31
+ p.summary = 'Interface classes for the Slicehost API'
32
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
33
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
34
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
35
+ p.remote_rdoc_dir = "/right_slicehost_gem_doc"
36
+ p.extra_deps = [['right_http_connection','>= 1.2.4']]
37
+ end
@@ -0,0 +1,39 @@
1
+ #
2
+ # Copyright (c) 2007-2009 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ #
24
+
25
+
26
+ # A hack because there's a bug in add! in Benchmark::Tms
27
+ module Benchmark #:nodoc:
28
+ class Tms #:nodoc:
29
+ def add!(&blk)
30
+ t = Benchmark::measure(&blk)
31
+ @utime = utime + t.utime
32
+ @stime = stime + t.stime
33
+ @cutime = cutime + t.cutime
34
+ @cstime = cstime + t.cstime
35
+ @real = real + t.real
36
+ self
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,601 @@
1
+ #
2
+ # Copyright (c) 2007-2009 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'cgi'
24
+ require 'benchmark'
25
+ require 'md5'
26
+ require 'rubygems'
27
+ require "rexml/document"
28
+ require 'right_http_connection'
29
+
30
+ $:.unshift(File.dirname(__FILE__))
31
+ require 'benchmark_fix'
32
+ require 'support'
33
+ require 'slicehost_base'
34
+
35
+
36
+ module RightSlicehost
37
+ MAJOR = 0
38
+ MINOR = 1
39
+ TINY = 0
40
+ VERSION = [MAJOR, MINOR, TINY].join('.')
41
+ end
42
+
43
+ module Rightscale
44
+
45
+ # # Slices:
46
+ #
47
+ # sl = Rightscale::Slicehost.new('12345...uvwxyz')
48
+ #
49
+ # sl.list_images #=>
50
+ # [{:sls_id=>2, :name=>"CentOS 5.2"},
51
+ # {:sls_id=>3, :name=>"Gentoo 2008.0"},
52
+ # {:sls_id=>4, :name=>"Debian 4.0 (etch)"},
53
+ # {:sls_id=>5, :name=>"Fedora 9"},
54
+ # {:sls_id=>9, :name=>"Arch 2007.08"},
55
+ # {:sls_id=>10, :name=>"Ubuntu 8.04.1 LTS (hardy)"},
56
+ # {:sls_id=>11, :name=>"Ubuntu 8.10 (intrepid)"}]
57
+ #
58
+ # sl.list_flavors #=>
59
+ # [{:sls_id=>1, :name=>"256 slice", :price=>2000, :ram=>256},
60
+ # {:sls_id=>2, :name=>"512 slice", :price=>3800, :ram=>512},
61
+ # {:sls_id=>3, :name=>"1GB slice", :price=>7000, :ram=>1024},
62
+ # {:sls_id=>4, :name=>"2GB slice", :price=>13000, :ram=>2048},
63
+ # {:sls_id=>5, :name=>"4GB slice", :price=>25000, :ram=>4096},
64
+ # {:sls_id=>6, :name=>"8GB slice", :price=>45000, :ram=>8192},
65
+ # {:sls_id=>7, :name=>"15.5GB slice", :price=>80000, :ram=>15872}]
66
+ #
67
+ # sl.create_slice(:flavor_id=>1 , :image_id=>2, :name=>'my-slice' ) #=>
68
+ # {:flavor_sls_id=>1,
69
+ # :addresses=>["173.45.224.125"],
70
+ # :bw_in=>0.0,
71
+ # :sls_id=>26831,
72
+ # :name=>"my-slice",
73
+ # :status=>"build",
74
+ # :bw_out=>0.0,
75
+ # :ip_address=>"173.45.224.125",
76
+ # :progress=>0,
77
+ # :image_sls_id=>2,
78
+ # :root_password=>"my-slicen57"}
79
+ #
80
+ # sl.rebuild_slice(26831, :image_id => 3) #=> true
81
+ #
82
+ # sl.reboot_slice(26832, :hard) #=> true
83
+ #
84
+ # sl.delete_slice(26832) #=> true
85
+ #
86
+ # # DNS:
87
+ #
88
+ # sl.list_zones #=>
89
+ # [ {:origin=>"a1.my-domain.com.", :ttl=>300, :sls_id=>45486, :active=>true},
90
+ # {:origin=>"a2.my-domain.com.", :ttl=>300, :sls_id=>45485, :active=>true},
91
+ # {:origin=>"a3.my-domain.com.", :ttl=>300, :sls_id=>45487, :active=>false}, ... ]
92
+ #
93
+ # sl.list_records #=>
94
+ # [ { :sls_id=>"348257",
95
+ # :zone_id=>45687,
96
+ # :data=>"woo-hoo.my-domain.com",
97
+ # :aux=>"0",
98
+ # :name=>"wooooohooooo",
99
+ # :ttl=>86400,
100
+ # :active=>true,
101
+ # :record_type=>"CNAME"}, ... ]
102
+ #
103
+ class Slicehost
104
+ include RightSlicehostInterface
105
+
106
+ def initialize(slicehost_password=nil, params={})
107
+ slicehost_password ||= ENV['SLICEHOST_PASSWORD']
108
+ init slicehost_password, params
109
+ end
110
+
111
+ def build_path(path, sls_id=nil, action=nil) # :nodoc:
112
+ path = path.to_s
113
+ unless (sls_id || action)
114
+ path += '.xml'
115
+ else
116
+ path += "/#{sls_id}#{action ? '' : '.xml'}" if sls_id
117
+ path += "/#{action}.xml" if action
118
+ end
119
+ path
120
+ end
121
+
122
+ def build_xml(name, params) # :nodoc:
123
+ xml_params = params.to_a.map do |key,value|
124
+ key = key.to_s.gsub('_','-')
125
+ "<#{key}>#{CGI.escape(value.to_s)}</#{key}>"
126
+ end.join("\n")
127
+
128
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
129
+ "<#{name.to_s}>\n" +
130
+ "#{xml_params}\n" +
131
+ "</#{name.to_s}>\n"
132
+ end
133
+
134
+ #------------------------------------------------------------
135
+ # Images
136
+ #------------------------------------------------------------
137
+
138
+ # List images.
139
+ #
140
+ # sl.list_images #=>
141
+ # [{:sls_id=>2, :name=>"CentOS 5.2"},
142
+ # {:sls_id=>3, :name=>"Gentoo 2008.0"},
143
+ # {:sls_id=>4, :name=>"Debian 4.0 (etch)"},
144
+ # {:sls_id=>5, :name=>"Fedora 9"},
145
+ # {:sls_id=>9, :name=>"Arch 2007.08"},
146
+ # {:sls_id=>10, :name=>"Ubuntu 8.04.1 LTS (hardy)"},
147
+ # {:sls_id=>11, :name=>"Ubuntu 8.10 (intrepid)"}]
148
+ #
149
+ # sl.list_images(9) #=> {:sls_id=>9, :name=>"Arch 2007.08"}
150
+ #
151
+ def list_images(sls_id=nil)
152
+ req = generate_request(Net::HTTP::Get, build_path(:images, sls_id))
153
+ result = request_cache_or_info(:list_images, req, ImagesParser, sls_id.nil?)
154
+ sls_id ? result.first : result
155
+ rescue
156
+ on_exception
157
+ end
158
+
159
+ #------------------------------------------------------------
160
+ # Flavors
161
+ #------------------------------------------------------------
162
+
163
+ # List flavors.
164
+ #
165
+ # sl.list_flavors #=>
166
+ # [{:sls_id=>1, :name=>"256 slice", :price=>2000, :ram=>256},
167
+ # {:sls_id=>2, :name=>"512 slice", :price=>3800, :ram=>512},
168
+ # {:sls_id=>3, :name=>"1GB slice", :price=>7000, :ram=>1024},
169
+ # {:sls_id=>4, :name=>"2GB slice", :price=>13000, :ram=>2048},
170
+ # {:sls_id=>5, :name=>"4GB slice", :price=>25000, :ram=>4096},
171
+ # {:sls_id=>6, :name=>"8GB slice", :price=>45000, :ram=>8192},
172
+ # {:sls_id=>7, :name=>"15.5GB slice", :price=>80000, :ram=>15872}]
173
+ #
174
+ # sl.list_flavors(6) #=> {:sls_id=>6, :name=>"8GB slice", :price=>45000, :ram=>8192}
175
+ #
176
+ def list_flavors(sls_id=nil)
177
+ req = generate_request(Net::HTTP::Get, build_path(:flavors, sls_id))
178
+ result = request_cache_or_info(:list_flavors, req, FlavorsParser, sls_id.nil?)
179
+ sls_id ? result.first : result
180
+ rescue
181
+ on_exception
182
+ end
183
+
184
+ #------------------------------------------------------------
185
+ # Backups
186
+ #------------------------------------------------------------
187
+
188
+ # List backups.
189
+ #
190
+ # sl.list_backups #=>
191
+ # [{:sls_id=>"5-6507",
192
+ # :slice_sls_id=>26831,
193
+ # :name=>"backup 1",
194
+ # :date=>Wed Dec 10 00:43:20 UTC 2008}, ...]
195
+ #
196
+ # sl.list_backups("5-6507") #=>
197
+ # {:sls_id=>"5-6507",
198
+ # :slice_sls_id=>26831,
199
+ # :name=>"backup 1",
200
+ # :date=>Wed Dec 10 00:43:20 UTC 2008}
201
+ #
202
+ #
203
+ #
204
+ def list_backups(sls_id=nil)
205
+ req = generate_request(Net::HTTP::Get, build_path(:backups, sls_id))
206
+ result = request_cache_or_info(:list_backups, req, BackupsParser, sls_id.nil?)
207
+ sls_id ? result.first : result
208
+ rescue
209
+ on_exception
210
+ end
211
+
212
+ #------------------------------------------------------------
213
+ # Slices
214
+ #------------------------------------------------------------
215
+
216
+ # List slices.
217
+ #
218
+ # sl.list_slices #=>
219
+ # [{:bw_in=>0.05,
220
+ # :sls_id=>26706,
221
+ # :bw_out=>0.0,
222
+ # :ip_address=>"173.45.233.125",
223
+ # :progress=>100,
224
+ # :status=>"active",
225
+ # :name=>"slice26706",
226
+ # :image_sls_id=>11,
227
+ # :flavor_sls_id=>1,
228
+ # :addresses=>["173.45.233.125"]}, ...]
229
+ #
230
+ def list_slices(sls_id=nil)
231
+ # GET /slices.xml
232
+ req = generate_request(Net::HTTP::Get, build_path(:slices, sls_id))
233
+ result = request_cache_or_info(:list_slices, req, SlicesParser, sls_id.nil?)
234
+ sls_id ? result.first : result
235
+ rescue
236
+ on_exception
237
+ end
238
+
239
+ # Create a new slice.
240
+ #
241
+ # sl.create_slice(:flavor_id=>1 , :image_id=>2, :name=>'my-slice' ) #=>
242
+ # {:flavor_sls_id=>1,
243
+ # :addresses=>["173.45.224.125"],
244
+ # :bw_in=>0.0,
245
+ # :sls_id=>26831,
246
+ # :name=>"my-slice",
247
+ # :status=>"build",
248
+ # :bw_out=>0.0,
249
+ # :ip_address=>"173.45.224.125",
250
+ # :progress=>0,
251
+ # :image_sls_id=>2,
252
+ # :root_password=>"my-slicen57"}
253
+ #
254
+ def create_slice(params={})
255
+ # POST /slices.xml
256
+ req = generate_request(Net::HTTP::Post, build_path(:slices))
257
+ req[:request].body = build_xml(:slice, params)
258
+ request_info(req, SlicesParser.new(:logger => @logger)).first
259
+ end
260
+
261
+ # Update a slice.
262
+ #
263
+ # sl.update_slice(26831, :name => 'my-awesome-slice') #=> true
264
+ #
265
+ def update_slice(sls_id, params={})
266
+ # PUT /slices/id.xml
267
+ req = generate_request(Net::HTTP::Put, build_path(:slices, sls_id))
268
+ req[:request].body = build_xml(:slice, params)
269
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
270
+ end
271
+
272
+ # Rebuild a slice.
273
+ #
274
+ # sl.rebuild_slice(26831, :image_id => 3) #=> true
275
+ #
276
+ def rebuild_slice(sls_id, params)
277
+ # PUT /slices/id/rebuild.xml?params
278
+ req = generate_request(Net::HTTP::Put, build_path(:slices, sls_id, :rebuild), params)
279
+ request_info(req, RightHttp2xxParser.new)
280
+ rescue
281
+ on_exception
282
+ end
283
+
284
+ # Reboot a slice (soft reboot is by default).
285
+ #
286
+ # sl.reboot_slice(26831) #=> true
287
+ # sl.reboot_slice(26832, :hard) #=> true
288
+ #
289
+ def reboot_slice(sls_id, hard_reboot = false)
290
+ # PUT /slices/id/reboot.xml
291
+ action = hard_reboot ? :hard_reboot : :reboot
292
+ req = generate_request(Net::HTTP::Put, build_path(:slices, sls_id, action))
293
+ request_info(req, RightHttp2xxParser.new)
294
+ rescue
295
+ on_exception
296
+ end
297
+
298
+ # Delete a slice.
299
+ #
300
+ # sl.delete_slice(26831) #=> true
301
+ #
302
+ def delete_slice(sls_id)
303
+ # DELETE /slices/id.xml
304
+ req = generate_request(Net::HTTP::Delete, build_path(:slices, sls_id))
305
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
306
+ end
307
+
308
+
309
+ #------------------------------------------------------------
310
+ # Zones
311
+ #------------------------------------------------------------
312
+
313
+ # List DNS Zones.
314
+ #
315
+ # # bunch of zones
316
+ # sl.list_zones #=>
317
+ # [ {:origin=>"a1.my-domain.com.", :ttl=>300, :sls_id=>45486, :active=>true},
318
+ # {:origin=>"a2.my-domain.com.", :ttl=>300, :sls_id=>45485, :active=>true},
319
+ # {:origin=>"a3.my-domain.com.", :ttl=>300, :sls_id=>45487, :active=>false} ]
320
+ #
321
+ # # single zone
322
+ # sl.list_zones(45486) #=>
323
+ # {:origin=>"a1.my-domain.com.", :ttl=>300, :sls_id=>45486, :active=>true}
324
+ #
325
+ def list_zones(sls_id=nil)
326
+ # GET /zones.xml
327
+ # GET /zones/id.xml
328
+ req = generate_request(Net::HTTP::Get, build_path(:zones, sls_id))
329
+ result = request_cache_or_info(:list_zones, req, ZonesParser, sls_id.nil?)
330
+ sls_id ? result.first : result
331
+ rescue
332
+ on_exception
333
+ end
334
+
335
+ # Create a new zone.
336
+ #
337
+ # sl.create_zone(:origin => 'a4.my_domain.ru', :ttl => 111, :active => false) #=>
338
+ # { :origin=>"a4.my-domain.com.",
339
+ # :ttl=>111,
340
+ # :sls_id=>45689,
341
+ # :active=>false}
342
+ #
343
+ def create_zone(params={})
344
+ params[:active] = (params[:active] ? 'Y' : 'N') unless params[:active].nil?
345
+ # POST /zones.xml
346
+ req = generate_request(Net::HTTP::Post, build_path(:zones))
347
+ req[:request].body = build_xml(:zone, params)
348
+ request_info(req, ZonesParser.new(:logger => @logger)).first
349
+ end
350
+
351
+ # Update a zone.
352
+ #
353
+ # sl.update_zone(45486, :acive => false, :ttl => 333) #=> true
354
+ #
355
+ def update_zone(sls_id, params={})
356
+ params[:active] = (params[:active] ? 'Y' : 'N') unless params[:active].nil?
357
+ # PUT /zones/id.xml
358
+ req = generate_request(Net::HTTP::Put, build_path(:zones, sls_id))
359
+ req[:request].body = build_xml(:zone, params)
360
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
361
+ end
362
+
363
+ # Delete a zone.
364
+ #
365
+ # sl.delete_zone(45486) #=> true
366
+ #
367
+ def delete_zone(sls_id)
368
+ # DELETE /zones/id.xml
369
+ req = generate_request(Net::HTTP::Delete, build_path(:zones, sls_id))
370
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
371
+ end
372
+
373
+ #------------------------------------------------------------
374
+ # Records
375
+ #------------------------------------------------------------
376
+
377
+ # List DNS Records
378
+ #
379
+ # sl.list_records #=>
380
+ # [ { :sls_id=>"348257",
381
+ # :zone_id=>45687,
382
+ # :data=>"woo-hoo.my-domain.com",
383
+ # :aux=>"0",
384
+ # :name=>"wooooohooooo",
385
+ # :ttl=>86400,
386
+ # :active=>true,
387
+ # :record_type=>"CNAME"}, ... ]
388
+ #
389
+ def list_records(sls_id=nil)
390
+ # GET /records.xml
391
+ # GET /records/id.xml
392
+ req = generate_request(Net::HTTP::Get, build_path(:records, sls_id))
393
+ result = request_cache_or_info(:list_records, req, RecordsParser, sls_id.nil?)
394
+ sls_id ? result.first : result
395
+ rescue
396
+ on_exception
397
+ end
398
+
399
+ # Create a new record.
400
+ #
401
+ # sl.create_record(:zone_id => 45687, :data=>"woo-hoo.my-domain.com", :name=>"wooooohooooo", :data=>"woo-hoo.my-domain.com") #=>
402
+ # [ { :sls_id=>348257,
403
+ # :zone_id=>45687,
404
+ # :data=>"woo-hoo.my-domain.com",
405
+ # :aux=>"0",
406
+ # :name=>"wooooohooooo",
407
+ # :ttl=>86400,
408
+ # :active=>true,
409
+ # :record_type=>"CNAME"}, ... ]
410
+ #
411
+ def create_record(params={})
412
+ params[:active] = (params[:active] ? 'Y' : 'N') unless params[:active].nil?
413
+ # POST /records.xml
414
+ req = generate_request(Net::HTTP::Post, build_path(:records))
415
+ req[:request].body = build_xml(:record, params)
416
+ request_info(req, RecordsParser.new(:logger => @logger)).first
417
+ end
418
+
419
+ # Update a record.
420
+ #
421
+ # sl.update_record(348257, :ttl => 777, :data=>"oops.my-domain.com") #=> true
422
+ #
423
+ def update_record(sls_id, params={})
424
+ params[:active] = (params[:active] ? 'Y' : 'N') unless params[:active].nil?
425
+ # PUT /zones/id.xml
426
+ req = generate_request(Net::HTTP::Put, build_path(:records, sls_id))
427
+ req[:request].body = build_xml(:record, params)
428
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
429
+ end
430
+
431
+ # Delete a record.
432
+ #
433
+ # sl.delete_record(348257) #=> true
434
+ #
435
+ def delete_record(sls_id)
436
+ # DELETE /records/id.xml
437
+ req = generate_request(Net::HTTP::Delete, build_path(:records, sls_id))
438
+ request_info(req, RightHttp2xxParser.new(:logger => @logger))
439
+ end
440
+
441
+ #------------------------------------------------------------
442
+ # Parsers
443
+ #------------------------------------------------------------
444
+
445
+ #------------------------------------------------------------
446
+ # Images
447
+ #------------------------------------------------------------
448
+
449
+ class ImagesParser < RightSlicehostParser #:nodoc:
450
+ def tagstart(name, attributes)
451
+ @item = {} if name == 'image'
452
+ end
453
+ def tagend(name)
454
+ case name
455
+ when 'id' then @item[:sls_id] = @text.to_i
456
+ when 'name' then @item[:name] = @text
457
+ when 'image' then @result << @item
458
+ end
459
+ end
460
+ def reset
461
+ @result = []
462
+ end
463
+ end
464
+
465
+ #------------------------------------------------------------
466
+ # Flavors
467
+ #------------------------------------------------------------
468
+
469
+ class FlavorsParser < RightSlicehostParser #:nodoc:
470
+ def tagstart(name, attributes)
471
+ @item = {} if name == 'flavor'
472
+ end
473
+ def tagend(name)
474
+ case name
475
+ when 'id' then @item[:sls_id] = @text.to_i
476
+ when 'name' then @item[:name] = @text
477
+ when 'price' then @item[:price] = @text.to_i
478
+ when 'ram' then @item[:ram] = @text.to_i
479
+ when 'flavor' then @result << @item
480
+ end
481
+ end
482
+ def reset
483
+ @result = []
484
+ end
485
+ end
486
+
487
+ #------------------------------------------------------------
488
+ # Backups
489
+ #------------------------------------------------------------
490
+
491
+ class BackupsParser < RightSlicehostParser #:nodoc:
492
+ def tagstart(name, attributes)
493
+ @item = {} if name == 'backup'
494
+ end
495
+ def tagend(name)
496
+ case name
497
+ when 'id' then @item[:sls_id] = @text
498
+ when 'name' then @item[:name] = @text
499
+ when 'slice_id' then @item[:slice_sls_id] = @text.to_i
500
+ when 'date' then @item[:date] = Time.parse(@text)
501
+ when 'backup' then @result << @item
502
+ end
503
+ end
504
+ def reset
505
+ @result = []
506
+ end
507
+ end
508
+
509
+ #------------------------------------------------------------
510
+ # Slices
511
+ #------------------------------------------------------------
512
+
513
+ class SlicesParser < RightSlicehostParser #:nodoc:
514
+ def tagstart(name, attributes)
515
+ @item = {} if name == 'slice'
516
+ @addresses = [] if name == 'addresses'
517
+ end
518
+ def tagend(name)
519
+ case name
520
+ when 'id' then @item[:sls_id] = @text.to_i
521
+ when 'name' then @item[:name] = @text
522
+ when 'image-id' then @item[:image_sls_id] = @text.to_i
523
+ when 'flavor-id' then @item[:flavor_sls_id] = @text.to_i
524
+ when 'slice-id' then @item[:slice_sls_id] = @text.to_i
525
+ when 'backup-id' then @item[:backup_sls_id] = @text.to_i
526
+ when 'status' then @item[:status] = @text
527
+ when 'progress' then @item[:progress] = @text.to_i
528
+ when 'bw-in' then @item[:bw_in] = @text.to_f
529
+ when 'bw-out' then @item[:bw_out] = @text.to_f
530
+ when 'ip-address' then @item[:ip_address] = @text
531
+ when 'root-password' then @item[:root_password] = @text
532
+ when 'address' then @addresses << @text
533
+ when 'addresses' then @item[:addresses] = @addresses
534
+ when 'slice' then @result << @item
535
+ end
536
+ end
537
+ def reset
538
+ @result = []
539
+ end
540
+ end
541
+
542
+ #------------------------------------------------------------
543
+ # Zones
544
+ #------------------------------------------------------------
545
+
546
+ class ZonesParser < RightSlicehostParser #:nodoc:
547
+ def tagstart(name, attributes)
548
+ @item = {} if name == 'zone'
549
+ end
550
+ def tagend(name)
551
+ case name
552
+ when 'id' then @item[:sls_id] = @text.to_i
553
+ when 'origin' then @item[:origin] = @text
554
+ when 'ttl' then @item[:ttl] = @text.to_i
555
+ when 'active' then @item[:active] = @text == 'Y'
556
+ when 'zone' then @result << @item
557
+ end
558
+ end
559
+ def reset
560
+ @result = []
561
+ end
562
+ end
563
+
564
+ #------------------------------------------------------------
565
+ # Records
566
+ #------------------------------------------------------------
567
+
568
+ class RecordsParser < RightSlicehostParser #:nodoc:
569
+ def tagstart(name, attributes)
570
+ @item = {} if name == 'record'
571
+ end
572
+ def tagend(name)
573
+ case name
574
+ when 'id' then @item[:sls_id] = @text.to_i
575
+ when 'record-type' then @item[:record_type] = @text
576
+ when 'zone-id' then @item[:zone_id] = @text.to_i
577
+ when 'name' then @item[:name] = @text
578
+ when 'data' then @item[:data] = @text
579
+ when 'ttl' then @item[:ttl] = @text.to_i
580
+ when 'active' then @item[:active] = @text == 'Y'
581
+ when 'aux' then @item[:aux] = @text
582
+ when 'record' then @result << @item
583
+ end
584
+ end
585
+ def reset
586
+ @result = []
587
+ end
588
+ end
589
+
590
+ #------------------------------------------------------------
591
+ # HTTP 2xx
592
+ #------------------------------------------------------------
593
+
594
+ class RightHttp2xxParser < RightSlicehostParser # :nodoc:
595
+ def parse(response)
596
+ @result = response.is_a?(Net::HTTPSuccess)
597
+ end
598
+ end
599
+
600
+ end
601
+ end