right_flexiscale 0.1.0

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,39 @@
1
+ #
2
+ # Copyright (c) 2007 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,819 @@
1
+ #
2
+ # Copyright (c) 2008-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
+ require 'Flexiscale APIDriver'
25
+ require 'Flexiscale APIAddons'
26
+ require 'logger'
27
+
28
+ module Rightscale
29
+
30
+ class FlexiscaleError < RuntimeError
31
+ end
32
+
33
+ class FlexiscaleBenchmarkingBlock # :nodoc:
34
+ attr_accessor :service
35
+ def initialize
36
+ # Benchmark::Tms instance for service (Ec2, S3, or SQS) access benchmarking.
37
+ @service = Benchmark::Tms.new()
38
+ end
39
+ end
40
+
41
+ # Simple connection errors handler
42
+ class FlexiscaleConnectionHandler
43
+ # Number of times to retry the request after encountering the first error
44
+ HTTP_CONNECTION_RETRY_COUNT = 3
45
+ # Length of the post-error probationary period during which all requests will fail
46
+ HTTP_CONNECTION_RETRY_DELAY = 15
47
+
48
+ @@params = { :http_connection_retry_count => HTTP_CONNECTION_RETRY_COUNT,
49
+ :http_connection_retry_delay => HTTP_CONNECTION_RETRY_DELAY,
50
+ :exception => FlexiscaleError,
51
+ :retriable_errors => [ 'Timeout::Error',
52
+ 'Errno::ECONNREFUSED',
53
+ 'Errno::ETIMEDOUT',
54
+ 'OpenSSL::SSL::SSLError',
55
+ 'SocketError' ],
56
+ :relogin_on_errors => [ 'InvalidCredentials',
57
+ 'Your credentials are unsuitable or missing']
58
+ }
59
+ # Params accessor:
60
+ #
61
+ # Rightscale::FlexiscaleConnectionHandler.params[:http_connection_retry_count] = 5
62
+ # Rightscale::FlexiscaleConnectionHandler.params[:retriable_errors] << 'MyAwesomeExceptionClassName'
63
+ #
64
+ def self.params
65
+ @@params
66
+ end
67
+
68
+ private
69
+
70
+ @@errors = []
71
+
72
+ def self.reset_errors # :nodoc:
73
+ @@errors = []
74
+ end
75
+
76
+ def self.add_retriable_error(exception) # :nodoc:
77
+ @@errors << [Time.now.utc, exception]
78
+ end
79
+
80
+ def self.errors_count # :nodoc:
81
+ @@errors.size
82
+ end
83
+
84
+ def self.last_error # :nodoc:
85
+ @@errors.empty? ? nil : @@errors.last.last
86
+ end
87
+
88
+ def self.last_error_time # :nodoc:
89
+ @@errors.empty? ? nil : @@errors.last.first
90
+ end
91
+
92
+ # Error is assumed as retriable if it's class name is equal to error message or
93
+ # error message includes on of @@params[:retriable_errors] stamps
94
+ def self.is_error_retriable?(e) # :nodoc:
95
+ @@params[:retriable_errors].include?(e.class.name) ||
96
+ @@params[:retriable_errors].find { |partial_message| e.message[/#{partial_message}/] }
97
+ end
98
+
99
+ def self.is_relogin_error?(e) # :nodoc:
100
+ @@params[:relogin_on_errors].include?(e.class.name) ||
101
+ @@params[:relogin_on_errors].find { |partial_message| e.message[/#{partial_message}/] }
102
+ end
103
+
104
+ # Check the amount of connection errors and raise if it exceeds max value
105
+ def self.check_retries_and_raise_if_required # :nodoc:
106
+ if errors_count >= @@params[:http_connection_retry_count] &&
107
+ last_error_time + @@params[:http_connection_retry_delay] > Time.now
108
+ warning = ("Re-raising same error: #{last_error.message} " +
109
+ "-- error count: #{errors_count}, error age: #{Time.now.to_i - @@errors.first.first.to_i}")
110
+ #
111
+ yield(warning) if block_given?
112
+ #
113
+ exception = @@params[:exception] ? @@params[:exception].new(last_error.message) : last_error
114
+ raise exception
115
+ end
116
+ end
117
+
118
+ # Perform a retry on low level (connection) errors or raise on high level (flexiscale API)
119
+ def self.process_exception(e = nil) # :nodoc:
120
+ e ||= $!
121
+ if is_error_retriable?(e) || is_relogin_error?(e)
122
+ add_retriable_error(e)
123
+ yield(e, "#{self.last_error.class.name}: request failure count: #{self.errors_count}, exception: '#{e.message}'") if block_given?
124
+ elsif e.is_a?(Interrupt)
125
+ # raise Interrupt guys: Ctrl/C etc.
126
+ # PS I check for Interrupt after :retriable_errors check just because some of :retriable_errors list are also
127
+ # Interrupt guys (Timeouts for example). So we break only if the interrupt is not in :retriable_errors list.
128
+ raise e
129
+ else
130
+ # Convert SOAP::FaultError to Rightscale::FlexiscaleError
131
+ if e.is_a?(SOAP::FaultError)
132
+ e = FlexiscaleError.new(e.message)
133
+ # Create a backtrace stack from a scratch if it is abcent...
134
+ # It does not show the exact point of error but a stack of methods at least.
135
+ # (not sure why but SOAP::FaultError has backtrace empty, may be due to threads usage)
136
+ e.set_backtrace(caller(0)) unless e.backtrace && !e.backtrace.empty?
137
+ # log and raise error
138
+ end
139
+ yield(e, false) if block_given?
140
+ raise e
141
+ end
142
+ end
143
+ end
144
+
145
+ # = Rightscale::FlexiscaleApi -- RightScale Flexiscale interface
146
+ # The Rightscale::FlexiscaleApi class provides a complete interface to Flexiscale's
147
+ # Web service.
148
+ # For explanations of the semantics
149
+ # of each call, please refer to Flexiscale's documentation at
150
+ # https://api.flexiscale.com
151
+ #
152
+ # Examples:
153
+ #
154
+ # flexiscale = Rightscale::FlexiscaleApi.new(username, password)
155
+ #
156
+ # # get servers list
157
+ # servers = flexiscale.list_servers
158
+ #
159
+ # # OS images
160
+ # images = flexiscale.list_operating_system_images
161
+ #
162
+ # # create a new server
163
+ # image = flexiscale.list_operating_system_images.first
164
+ # package = flexiscale.list_packages.first
165
+ # vlan = flexiscale.list_vlans.first
166
+ # server_id = flexiscale.create_server('my_awesome_server', package[:fxs_id], 1, 1024, 20, image[:fxs_id], vlan[:fxs_id])
167
+ #
168
+ # # launch a server
169
+ # job_id = flexiscale.start_server('my_awesome_server')
170
+ #
171
+ # # reboot
172
+ # job_id = flexiscale.reboot_server('my_awesome_server')
173
+ #
174
+ # # stop and destroy server
175
+ # job_id = flexiscale.stop_server('my_awesome_server')
176
+ #
177
+ # if flexiscale.wait_for_jobs(job_id)
178
+ # flexiscale.destroy_server('my_awesome_server')
179
+ # end
180
+ #
181
+ # Error handling: all operations raise an Rightscale::FlexiscaleError in case
182
+ # of problems.
183
+ #
184
+ class FlexiscaleApi
185
+ attr_reader :params
186
+ attr_reader :logged_in
187
+ attr_reader :username
188
+ attr_reader :password
189
+ attr_reader :api
190
+ attr_reader :last_raw_response
191
+
192
+ @@bench = FlexiscaleBenchmarkingBlock.new
193
+ def self.bench_service # :nodoc:
194
+ @@bench.service
195
+ end
196
+
197
+ FLEXISCALE_WSDL = "https://api.flexiscale.com/current/Flexiscale.wsdl"
198
+
199
+ SERVER_STOP_SHUTDOWN = 1
200
+ SERVER_STOP_POWEROFF = 2
201
+
202
+ DEFAULT_HTTP_CONNECT_TIMEOUT = 60
203
+ DEFAULT_HTTP_RECEIVE_TIMEOUT = 300
204
+
205
+ # Create a new interface to Flexiscale API.
206
+ # If _username_ or/and _password_ are undefined then
207
+ # ENV['FLEXISCALE_USERNAME'] and ENV['FLEXISCALE_PASSWORD'] are used.
208
+ #
209
+ # - params: :raw_response - return SOAP objects as is
210
+ # :logger - logger object (STDOUT is used by default)
211
+ # :skip_logging - log nothing
212
+ #
213
+ # flexiscale = Rightscale::FlexiscaleApi.new(username, password)
214
+ # flexiscale.list_packages #=> [{:fxs_id => 12345,
215
+ # :name => "package"}]
216
+ #
217
+ # flexiscale = Rightscale::FlexiscaleApi.new(username, password, :raw_response=>true) #=>
218
+ # flexiscale.list_packages #=> [#<FlexiScale::Package:0xb78a1904
219
+ # @package_id = 12345,
220
+ # @package_name = "package">]
221
+ #
222
+ def initialize(username=nil, password=nil, params={})
223
+ @username = username || ENV['FLEXISCALE_USERNAME']
224
+ @password = password || ENV['FLEXISCALE_PASSWORD']
225
+ @params = params
226
+ # vars initialization
227
+ @params[:logger] ||= Logger.new(STDOUT)
228
+ @logged_in = false
229
+ @last_raw_response = nil
230
+ # create a new interface
231
+ @api = ::FlexiScale::FlexiScale.new
232
+ @api.wiredump_dev = STDERR if $DEBUG
233
+ # timeouts: 1 min for connection establishment and
234
+ # 5 min for wait_for_jobs
235
+ @api.options["protocol.http.connect_timeout"] = DEFAULT_HTTP_CONNECT_TIMEOUT
236
+ @api.options["protocol.http.receive_timeout"] = DEFAULT_HTTP_RECEIVE_TIMEOUT
237
+ # @api.options["protocol.http.send_timeout"]
238
+ end
239
+
240
+ def log(message, level=:info) # :nodoc:
241
+ unless @params[:skip_logging]
242
+ message = "#{self.class.name}: #{message}"
243
+ @params[:logger].__send__(level, message)
244
+ end
245
+ end
246
+
247
+ def log_error(e, level=:error) # :nodoc:
248
+ unless @params[:skip_logging]
249
+ trace = e.backtrace.join("\n")
250
+ message = "#{e.class.name}: #{e.message}\n#{trace}"
251
+ @params[:logger].__send__(level, message)
252
+ end
253
+ end
254
+
255
+ def internal_login(username=nil, password=nil) # :nodoc:
256
+ @username = username if username
257
+ @password = password if password
258
+ @logged_in = false
259
+ @api.login(@username, @password)
260
+ @logged_in = true
261
+ end
262
+
263
+ # Request Flexiscale.
264
+ # Performs a retry on login problems (timeouts etc).
265
+ # - params: :no_login - do not auto login
266
+ #
267
+ def perform_request(params={}, &block) # :nodoc:
268
+ loop do
269
+ result = nil
270
+ # Check retries count. And raise an exception if we run into permanent failure
271
+ # Block is called before exception to log an event.
272
+ FlexiscaleConnectionHandler.check_retries_and_raise_if_required do |warning|
273
+ log warning, :warn
274
+ end
275
+ # perform a request
276
+ begin
277
+ # login if required
278
+ if !params[:no_login] && !@logged_in
279
+ @@bench.service.add! do
280
+ internal_login
281
+ end
282
+ end
283
+ # call the block of code is passed
284
+ if block
285
+ @@bench.service.add! do
286
+ result = @last_raw_response = block.call
287
+ end
288
+ end
289
+ # reset errors list
290
+ FlexiscaleConnectionHandler.reset_errors
291
+ # convert a result to a handy format
292
+ if result.class.name[/^FlexiScale::/] && !@params[:raw_response]
293
+ result = result.to_handy_hash
294
+ end
295
+ return result
296
+
297
+ rescue Exception => exception
298
+ # Log the errors we got and increaze the errors count.
299
+ # +retriable_message+ is set when we get a low level connection error (and retry is to be performed).
300
+ # If +retriable_message+ is not set - the err is a high level one and it will be reraised as FlexiscaleError.
301
+ # Any case the block of code is used just to log an event.
302
+ FlexiscaleConnectionHandler.process_exception(exception) do |e, retriable_message|
303
+ log(retriable_message, :warn) if retriable_message
304
+ if FlexiscaleConnectionHandler.is_relogin_error?(e)
305
+ @logged_in = false
306
+ log('Internal logout performed.', :warn)
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
312
+
313
+ #----------------------------------------
314
+ # FLEXISCALE_API
315
+ #----------------------------------------
316
+
317
+ #----------------------------------------
318
+ # Miscellaneous
319
+ #----------------------------------------
320
+
321
+ # Loging into the API. Returns +true+ on success.
322
+ # If _username_ and/or _password_ are not specified then previously defined values are used.
323
+ #
324
+ # https://api.flexiscale.com/current/doc/login.html
325
+ def login(username=nil, password=nil)
326
+ @logged_in = false
327
+ @username = username if username
328
+ @password = password if password
329
+ # without a block perform_request just logs in
330
+ perform_request
331
+ true
332
+ end
333
+
334
+ # Logout of the API.
335
+ #
336
+ # https://api.flexiscale.com/current/doc/login.html
337
+ def logout
338
+ @logged_in = false
339
+ perform_request(:no_login=>true) do
340
+ @api.logout
341
+ end
342
+ end
343
+
344
+ # List packages. Returns an array of packages.
345
+ # _List_ is an array of ids.
346
+ #
347
+ # flexiscale.list_packages #=>
348
+ # [{:fxs_id => 12345,
349
+ # :name => "package"}]
350
+ #
351
+ # https://api.flexiscale.com/current/doc/list_packages.html
352
+ def list_packages(*list)
353
+ perform_request do
354
+ @api.listPackages(list.flatten)
355
+ end
356
+ end
357
+
358
+ #----------------------------------------
359
+ # Servers
360
+ #----------------------------------------
361
+
362
+ # List servers. Returns an array of servers.
363
+ # _List_ is an array of servers names.
364
+ #
365
+ # flexiscale.list_servers #=>
366
+ # [{:memory => 512,
367
+ # :processors => 1,
368
+ # :fxs_id => 1343,
369
+ # :image_id => 27,
370
+ # :image_name => "Ubuntu 8.04 LTS",
371
+ # :initial_password => "0000000000000000\n",
372
+ # :name => "my_awesome_server",
373
+ # :uptime => 0,
374
+ # :modified => false,
375
+ # :status => "stopped"
376
+ # :fxs_status => "5",
377
+ # :package_id => 12345,
378
+ # :disks => [2285],
379
+ # :disk_capacity => 20480,
380
+ # :ip_addresses => ["92.60.121.68"],
381
+ # :network_interfaces => [778]}, ... ]
382
+ #
383
+ # https://api.flexiscale.com/current/doc/list_servers.html
384
+ def list_servers(*list)
385
+ perform_request do
386
+ @api.listServers(list.flatten)
387
+ end
388
+ end
389
+
390
+ # Create a server. Returns a new +server_id+.
391
+ # (_Memory_ in MB, _disk_capacity_ in GB)
392
+ #
393
+ # flexiscale.create_server('my_awesome_server', 12345, 1, 512, 20, 27, 1552) #=> 1343
394
+ #
395
+ # https://api.flexiscale.com/current/doc/create_server.html
396
+ def create_server(server_name, package_id, processors, memory, disk_capacity, operating_system_image_id, vlan_id)
397
+ image = FlexiScale::OperatingSystemImage.new(operating_system_image_id)
398
+ server = FlexiScale::Server.new(nil, server_name, nil, package_id, processors, memory, image, disk_capacity)
399
+ vlan = FlexiScale::Vlan.new(vlan_id)
400
+ perform_request do
401
+ @api.createServer(server, vlan)
402
+ end
403
+ end
404
+
405
+ # Modify server params. Returns a modified server data.
406
+ # Note: a stop_start_server request will need to be sent after the modification
407
+ # have been made which will reboot the server and apply the changes
408
+ #
409
+ # flexiscale.modify_server(1343, 1, 1024) #=>
410
+ # {:memory => 1024,
411
+ # :processors => 1,
412
+ # :fxs_id => 1343,
413
+ # :image_id => 27,
414
+ # :image_name => "Ubuntu 8.04 LTS",
415
+ # :initial_password => "0000000000000000\n",
416
+ # :name => "my_awesome_server",
417
+ # :uptime => 0,
418
+ # :modified => false,
419
+ # :status => "stopped"
420
+ # :fxs_status => "5",
421
+ # :package_id => 12345,
422
+ # :disks => [2285],
423
+ # :disk_capacity => 20480,
424
+ # :ip_addresses => ["92.60.121.68"],
425
+ # :network_interfaces => [778]}
426
+ #
427
+ # https://api.flexiscale.com/current/doc/modify_server.html
428
+ def modify_server(server_id, processors, memory)
429
+ server = FlexiScale::Server.new(server_id, nil, nil, nil, processors, memory)
430
+ perform_request do
431
+ @api.modifyServer(server)
432
+ end
433
+ end
434
+
435
+ # Start a server.
436
+ # The response is returned as a integer which is the job number of the request,
437
+ # this can be looked up using _wait_for_jobs_ and _list_jobs_.
438
+ #
439
+ # flexiscale.start_server('my_awesome_server') #=> 11034
440
+ #
441
+ # https://api.flexiscale.com/current/doc/start_server.html
442
+ def start_server(server_name, notes='')
443
+ perform_request do
444
+ @api.startServer(server_name, notes)
445
+ end
446
+ end
447
+
448
+ # Reboot a server.
449
+ # The response is returned as a integer which is the job number of the request,
450
+ # this can be looked up using _wait_for_jobs_ and _list_jobs_.
451
+ #
452
+ # flexiscale.reboot_server('my_awesome_server') #=> 11035
453
+ #
454
+ # https://api.flexiscale.com/current/doc/reboot_server.html
455
+ def reboot_server(server_name, notes='')
456
+ perform_request do
457
+ @api.rebootServer(server_name, notes)
458
+ end
459
+ end
460
+
461
+ # Stop a server.
462
+ # The response is returned as a integer which is the job number of the request,
463
+ # this can be looked up using _wait_for_jobs_ and _list_jobs_.
464
+ #
465
+ # - method: (:shutdown || Rightscale::FlexiscaleApi::SERVER_STOP_SHUTDOWN) ||
466
+ # (:poweroff || Rightscale::FlexiscaleApi::SERVER_STOP_POWEROFF)
467
+ #
468
+ # flexiscale.stop_server('my_awesome_server') #=> 11036
469
+ #
470
+ # https://api.flexiscale.com/current/doc/stop_server.html
471
+ def stop_server(server_name, method=:shutdown, notes='')
472
+ perform_request do
473
+ case method.to_s
474
+ when 'shutdown', SERVER_STOP_SHUTDOWN.to_s then @api.stopServer(server_name, SERVER_STOP_SHUTDOWN, notes)
475
+ when 'poweroff', SERVER_STOP_POWEROFF.to_s then @api.stopServer(server_name, SERVER_STOP_POWEROFF, notes)
476
+ end
477
+ end
478
+ end
479
+
480
+ # Stop and Restart an existing server.
481
+ # The response is returned as a integer which is the job number of the request,
482
+ # this can be looked up using _wait_for_jobs_ and _list_jobs_.
483
+ #
484
+ # flexiscale.stop_start_server('my_awesome_server') #=> 11037
485
+ #
486
+ # https://api.flexiscale.com/current/doc/stop_start_server.html
487
+ def stop_start_server(server_name, notes='')
488
+ perform_request do
489
+ @api.stopStartServer(server_name, notes)
490
+ end
491
+ end
492
+
493
+ # Destroy a server. Returns +true+ if OK.
494
+ #
495
+ # flexiscale.destroy_server('my_awesome_server') #=> true
496
+ #
497
+ # https://api.flexiscale.com/current/doc/delete_server.html
498
+ def destroy_server(server_name)
499
+ perform_request do
500
+ @api.destroyServer(server_name)
501
+ end
502
+ true
503
+ end
504
+
505
+ #----------------------------------------
506
+ # Disk Management
507
+ #----------------------------------------
508
+
509
+ # List disks. Returns an array of disks.
510
+ # _List_ is an array of ids.
511
+ #
512
+ # flexiscale.list_disks #=>
513
+ # [{:capacity => 20,
514
+ # :server_id => 1322,
515
+ # :usage => 0.03,
516
+ # :name => "Server 1322 Operating System",
517
+ # :locked => 0,
518
+ # :package_id => 12345,
519
+ # :fxs_id => 2262}, ... ]
520
+ #
521
+ # https://api.flexiscale.com/current/doc/list_disks.html
522
+ def list_disks(*list)
523
+ perform_request do
524
+ @api.listDisks(list.flatten)
525
+ end
526
+ end
527
+
528
+ #----------------------------------------
529
+ # Jobs
530
+ #----------------------------------------
531
+
532
+ # List jobs. Returns an array of jobs.
533
+ # _List_ is an array of ids.
534
+ #
535
+ # flexiscale.list_jobs #=>
536
+ # [{:fxs_status => 2,
537
+ # :status => "completed",
538
+ # :started_at => Fri Jun 13 13:21:27 UTC 2008,
539
+ # :description => "start_virtual_server",
540
+ # :finished_at => Fri Jun 13 13:23:42 UTC 2008,
541
+ # :type_id => 1322,
542
+ # :notes => "kd-from-home-via-api",
543
+ # :fxs_id => 10928,
544
+ # :parent_job => 0}, ... ]
545
+ #
546
+ # https://api.flexiscale.com/current/doc/list_jobs.html
547
+ def list_jobs(*list)
548
+ perform_request do
549
+ @api.ListJobs(list.flatten)
550
+ end
551
+ end
552
+
553
+ # List running jobs. Returns an array of running jobs.
554
+ # _List_ is an array of ids.
555
+ #
556
+ # flexiscale.list_running_jobs #=> []
557
+ #
558
+ # https://api.flexiscale.com/current/doc/list_running_jobs.html
559
+ def list_running_jobs
560
+ perform_request do
561
+ @api.listRunningJobs
562
+ end
563
+ end
564
+
565
+ # Wait for jobs completion.
566
+ # The command returns a boolean value, if +true+ all jobs have been completed
567
+ # successfully, if +false+ one or more jobs failed.
568
+ # _List_ is an array of ids.
569
+ #
570
+ # flexiscale.wait_for_jobs(1132, 1133) #=> true
571
+ #
572
+ # For a long wait tasks you may need to increase
573
+ # @api.options["protocol.http.receive_timeout"]. The default value is
574
+ # DEFAULT_HTTP_RECEIVE_TIMEOUT
575
+ #
576
+ # https://api.flexiscale.com/current/doc/wait_for_jobs.html
577
+ def wait_for_jobs(*list)
578
+ perform_request do
579
+ @api.wait_for_jobs(list.flatten)
580
+ end
581
+ end
582
+
583
+ # List a filtered jobs. Returns an array of jobs.
584
+ # - order_by: :status || :job_id || :type_id || :started || :finished || :description || :parent_job
585
+ # - direction: :asc || :desc
586
+ #
587
+ # flexiscale.filter(100, :status, :desc ) #=>
588
+ # [{:fxs_status => 2,
589
+ # :status => "completed",
590
+ # :started_at => Fri Jun 13 13:21:27 UTC 2008,
591
+ # :description => "start_virtual_server",
592
+ # :finished_at => Fri Jun 13 13:23:42 UTC 2008,
593
+ # :type_id => 1322,
594
+ # :notes => "kd-from-home-via-api",
595
+ # :fxs_id => 10928,
596
+ # :parent_job => 0}, ... ]
597
+ #
598
+ # https://api.flexiscale.com/current/doc/filter_jobs.html
599
+ def filter_jobs(limit=50, order_by=:status, direction=:asc)
600
+ perform_request do
601
+ @api.filterJobs(limit, order_by.to_s, direction.to_s.upcase)
602
+ end
603
+ end
604
+
605
+ #----------------------------------------
606
+ # Operating Systems
607
+ #----------------------------------------
608
+
609
+ # List available operating system images.
610
+ #
611
+ # flexiscale.list_operating_system_images #=>
612
+ # [{:fxs_id=>1, :name=>"Centos 5"},
613
+ # {:fxs_id=>3, :name=>"Centos 4"},
614
+ # {:fxs_id=>4, :name=>"Windows Server 2003 Standard"},
615
+ # {:fxs_id=>6, :name=>"Debian 4.0 (Etch)"},
616
+ # {:fxs_id=>15, :name=>"Centos 5 64 Bit"},
617
+ # {:fxs_id=>16, :name=>"Ubuntu 6.06 LTS"},
618
+ # {:fxs_id=>17, :name=>"Windows Server 2003 Standard 64 Bit"},
619
+ # {:fxs_id=>18, :name=>"Debian 4.0 64 Bit (Etch)"},
620
+ # {:fxs_id=>27, :name=>"Ubuntu 8.04 LTS"}]
621
+ #
622
+ # https://api.flexiscale.com/current/doc/list_operating_system_images.html
623
+ def list_operating_system_images
624
+ perform_request do
625
+ @api.listOperatingSystemImages
626
+ end
627
+ end
628
+
629
+ #----------------------------------------
630
+ # Network Management
631
+ #----------------------------------------
632
+
633
+ # List network interfaces. Returns an array of nics.
634
+ # _List_ is an array of ids.
635
+ #
636
+ # flexiscale.list_network_interfaces #=>
637
+ # [{:server_id => 1322,
638
+ # :fxs_id => 749,
639
+ # :vlan_id => 552,
640
+ # :mac_address => "00:0f:4b:22:cb:0c"}, ... ]
641
+ #
642
+ # https://api.flexiscale.com/current/doc/list_nics.html
643
+ def list_network_interfaces(*list)
644
+ perform_request do
645
+ @api.listNetworkInterfaces(list.flatten)
646
+ end
647
+ end
648
+
649
+ # List vlans. Returns an array of vlans.
650
+ # _List_ is an array of ids.
651
+ #
652
+ # flexiscale.list_vlans #=>
653
+ # [{:fxs_id => 552,
654
+ # :name => "Cust15608VLAN1"}]
655
+ #
656
+ # https://api.flexiscale.com/current/doc/list_servers.html
657
+ def list_vlans(*list)
658
+ perform_request do
659
+ @api.listVlans(list.flatten)
660
+ end
661
+ end
662
+
663
+ # List IpBlocks. Returns an array of ip_blocks.
664
+ # _List_ is an array of ids.
665
+ #
666
+ # flexiscale.list_ip_blocks #=>
667
+ # [{:block_type => 29,
668
+ # :end_ip => "92.60.120.70",
669
+ # :fxs_id => 404,
670
+ # :customer_vlan_id => 552,
671
+ # :start_ip => "92.60.120.60"}]
672
+ #
673
+ # https://api.flexiscale.com/current/doc/list_ip_blocks.html
674
+ def list_ip_blocks(*list)
675
+ perform_request do
676
+ @api.listIpBlocks(list.flatten)
677
+ end
678
+ end
679
+
680
+ #----------------------------------------
681
+ # Billing Management
682
+ #----------------------------------------
683
+
684
+ # List debit items.
685
+ #
686
+ # - item_type: :virtual_server || :vlan || :disk_space
687
+ #
688
+ # flexiscale.list_debit_items(:virtual_server, 1322) #=>
689
+ # [{:description => "1 Hour of uptime for server kd test 1",
690
+ # :type_id => 1322,
691
+ # :item_value => 1.0,
692
+ # :item_cost => 0.05,
693
+ # :fxs_id => 738858,
694
+ # :debit_id => 415192,
695
+ # :timestamp => Fri Jun 13 16:45:04 +0400 2008,
696
+ # :item_type => "virtual_server"}]
697
+ #
698
+ # https://api.flexiscale.com/current/doc/list_debit_items.html
699
+ def list_debit_items(item_type, type_id, start_date=nil, end_date=nil)
700
+ perform_request do
701
+ @api.listDebitItems(item_type.to_s, type_id,
702
+ start_date && start_date.to_i, end_date && end_date.to_i)
703
+ end
704
+ end
705
+
706
+ # List debits.
707
+ #
708
+ # https://api.flexiscale.com/current/doc/list_debits.html
709
+ def list_debits(start_date=nil, end_date=nil)
710
+ perform_request do
711
+ @api.listDebits(start_date && start_date.to_i, end_date && end_date.to_i)
712
+ end
713
+ end
714
+
715
+ # List credits.
716
+ #
717
+ # https://api.flexiscale.com/current/doc/list_credits.html
718
+ def list_credits(start_date=nil, end_date=nil)
719
+ perform_request do
720
+ @api.listCredits(start_date && start_date.to_i, end_date && end_date.to_i)
721
+ end
722
+ end
723
+
724
+ #----------------------------------------
725
+ # Firewalls (flexiscale beta)
726
+ #----------------------------------------
727
+
728
+ # List firewalls.
729
+ #
730
+ # https://api.flexiscale.com/current/doc/list_firewalls.html
731
+ def list_firewalls(*list)
732
+ perform_request do
733
+ @api.listFirewalls(list.flatten)
734
+ end
735
+ end
736
+
737
+ # List firewall rulles.
738
+ # - direction: nil || :in || :out
739
+ #
740
+ # https://api.flexiscale.com/current/doc/list_firewall_rules.html
741
+ def list_firewall_rules(firewall_id, direction=nil)
742
+ perform_request do
743
+ @api.listFirewallRules(firewall_id, direction && direction.to_s.upcase)
744
+ end
745
+ end
746
+
747
+ # List firewall protocols.
748
+ #
749
+ # flexiscale.list_firewall_protocols #=>
750
+ # [{:fxs_id=>0, :name=>"Any"},
751
+ # {:fxs_id=>6, :name=>"TCP"},
752
+ # {:fxs_id=>17, :name=>"UDP"},
753
+ # {:fxs_id=>1, :name=>"ICMP"},
754
+ # {:fxs_id=>41, :name=>"GRE"},
755
+ # {:fxs_id=>50, :name=>"IPSEC-ESP"},
756
+ # {:fxs_id=>51, :name=>"IPSEC-AH"},
757
+ # {:fxs_id=>115, :name=>"L2TP"}]
758
+ #
759
+ # https://api.flexiscale.com/current/doc/list_firewall_protocols.html
760
+ def list_firewall_protocols
761
+ perform_request do
762
+ @api.listFirewallProtocols
763
+ end
764
+ end
765
+
766
+ # List ICMP protocols.
767
+ #
768
+ # flexiscale.list_icmp_protocols #=>
769
+ # [{:fxs_id=>0, :description=>"Echo Reply"},
770
+ # {:fxs_id=>8, :description=>"Echo"},
771
+ # {:fxs_id=>3, :description=>"Destination Unreachable"},
772
+ # {:fxs_id=>4, :description=>"Source Quench"},
773
+ # {:fxs_id=>5, :description=>"Redirect"},
774
+ # {:fxs_id=>6, :description=>"Alternate Host Address"},
775
+ # {:fxs_id=>9, :description=>"Router Advertisement"},
776
+ # {:fxs_id=>10, :description=>"Router Solicitation"},
777
+ # {:fxs_id=>11, :description=>"Time Exceeded"},
778
+ # {:fxs_id=>12, :description=>"Parameter Problem"},
779
+ # {:fxs_id=>13, :description=>"Timestamp"},
780
+ # {:fxs_id=>14, :description=>"Timestamp Reply"},
781
+ # {:fxs_id=>15, :description=>"Information Request"},
782
+ # {:fxs_id=>16, :description=>"Information Reply"},
783
+ # {:fxs_id=>17, :description=>"Address Mask Request"},
784
+ # {:fxs_id=>18, :description=>"Address Mask Reply"}]
785
+ #
786
+ # https://api.flexiscale.com/current/doc/list_icmp_protocols.html
787
+ def list_icmp_protocols
788
+ perform_request do
789
+ @api.listIcmpProtocols
790
+ end
791
+ end
792
+
793
+ # List firewall templates.
794
+ #
795
+ # flexiscale.list_firewall_templates #=>
796
+ # [{:fxs_id=>1, :name=>"Linux Web Server", :default_policy=>"REJECT"},
797
+ # {:fxs_id=>2, :name=>"Windows Web Server", :default_policy=>"REJECT"},
798
+ # {:fxs_id=>3, :name=>"Linux Email Server", :default_policy=>"REJECT"}]
799
+ #
800
+ # https://api.flexiscale.com/current/doc/list_firewall_templates.html
801
+ def list_firewall_templates(*list)
802
+ perform_request do
803
+ @api.listFirewallTemplates(list.flatten)
804
+ end
805
+ end
806
+
807
+ # List firewall template rules.
808
+ # - direction: nil || :in || :out
809
+ #
810
+ # https://api.flexiscale.com/current/doc/list_firewall_template_rules.html
811
+ def list_firewall_template_rules(firewall_template_id, direction=nil)
812
+ perform_request do
813
+ @api.listFirewallTemplateRules(firewall_template_id, direction && direction.to_s.upcase)
814
+ end
815
+ end
816
+
817
+ end
818
+
819
+ end