jamesn-softlayer-ruby 0.6.3.0 → 0.7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +10 -0
- data/lib/softlayer.rb +16 -305
- data/lib/softlayer/baseclass.rb +247 -0
- data/lib/softlayer/util.rb +89 -0
- data/sample/cdnlayerupload.rb +68 -0
- data/sample/resultlimit.rb +6 -3
- metadata +5 -2
data/Changes
CHANGED
@@ -1,4 +1,14 @@
|
|
1
1
|
|
2
|
+
Changes since 0.6.3
|
3
|
+
|
4
|
+
|
5
|
+
Added a CDNLayer sample
|
6
|
+
Refactor slapiCall and realCall to clean up a bit of a mess, fix method parameter handling, and cleans up header handling. There's a bit of an api change here.
|
7
|
+
Clean up initParamater handling (so that it actually works again)
|
8
|
+
Allow the base class to be replaced with another.
|
9
|
+
Split softlayer.rb into three files, one containing just the base class, another containing
|
10
|
+
the header and exception classes.
|
11
|
+
|
2
12
|
Change since 0.6.1
|
3
13
|
|
4
14
|
Silenced the name space warning (I think this is a bug in soap4r)
|
data/lib/softlayer.rb
CHANGED
@@ -37,16 +37,23 @@ gem 'soap4r'
|
|
37
37
|
require 'soap/header/simplehandler'
|
38
38
|
require 'soap/wsdlDriver'
|
39
39
|
|
40
|
+
require 'softlayer/baseclass'
|
41
|
+
require 'softlayer/util'
|
42
|
+
|
40
43
|
|
41
44
|
module SoftLayer
|
42
45
|
|
46
|
+
DEFAULTBASE=SoftLayer::BaseClass
|
47
|
+
|
43
48
|
# Declare SLAPI clases. Args take class names in two forms:
|
44
49
|
# +soap+:: Service names in SOAP format (example: SoftLayer_Account)
|
45
50
|
# +ruby+:: Class names in Ruby format (example: SoftLayer::Account)
|
51
|
+
# +base+:: A substitute base class (otherwise SoftLayer::Base)
|
46
52
|
# Creates the class, and retrieves and caches the endpoint WSDL.
|
47
53
|
def SoftLayer::declareClasses(args)
|
48
54
|
classes = args[:ruby]
|
49
55
|
services = args[:soap]
|
56
|
+
base = args[:base]
|
50
57
|
|
51
58
|
unless (services.nil? || services.empty?)
|
52
59
|
services.each do |s|
|
@@ -56,7 +63,7 @@ module SoftLayer
|
|
56
63
|
end
|
57
64
|
|
58
65
|
classes.each do |cstr|
|
59
|
-
k = SoftLayer::ClassFactory(:class => cstr)
|
66
|
+
k = SoftLayer::ClassFactory(:class => cstr, :base => base)
|
60
67
|
k.cacheWSDL
|
61
68
|
end
|
62
69
|
end
|
@@ -65,338 +72,42 @@ module SoftLayer
|
|
65
72
|
# Args:
|
66
73
|
# +class+:: The name of the class to create in Ruby format.
|
67
74
|
# +parent+:: The parent namespace to add the class to (this should be somewere in SoftLayer; optional).
|
75
|
+
# +base+:: A substitute base class (otherwise SoftLayer::Base)
|
68
76
|
# This recursively walks up +class+ creating them as needed, so SoftLayer::Dns::Domain will create
|
69
77
|
# classes for Dns and Domain (even though the Dns class will never be used).
|
70
78
|
def SoftLayer::ClassFactory(args)
|
71
79
|
cname = args[:class]
|
72
80
|
parent = args[:parent] unless args[:parent].nil?
|
81
|
+
base = args[:base]
|
82
|
+
base = DEFAULTBASE if base.nil?
|
73
83
|
|
74
84
|
cary = cname.split('::')
|
75
85
|
parent = const_get(cary.shift) if parent.nil? # This should always be SoftLayer, but maybe not...
|
76
86
|
cur = cary.shift
|
77
87
|
newclass = nil
|
78
88
|
unless parent.const_defined?(cur)
|
79
|
-
newclass = SoftLayer::makeSLAPIKlass(:class => cur, :parent => parent)
|
89
|
+
newclass = SoftLayer::makeSLAPIKlass(:class => cur, :parent => parent, :base => base)
|
80
90
|
else
|
81
91
|
newclass = parent.const_get(cur)
|
82
92
|
end
|
83
93
|
return newclass if cary.empty?
|
84
94
|
|
85
95
|
left = cary.join('::')
|
86
|
-
k = SoftLayer::ClassFactory(:class => left, :parent => newclass)
|
96
|
+
k = SoftLayer::ClassFactory(:class => left, :parent => newclass, :base => base)
|
87
97
|
return k
|
88
98
|
end
|
89
99
|
|
90
100
|
# This really creates the class.
|
91
101
|
# +class+:: The name of the class to create in Ruby format.
|
92
102
|
# +parent+:: The parent namespace to add the class to (this should be somewhere in SoftLayer, not optional).
|
103
|
+
# +base+:: A substitute base class (otherwise SoftLayer::Base)
|
93
104
|
def SoftLayer::makeSLAPIKlass(args)
|
94
105
|
cname = args[:class]
|
95
106
|
parent = args[:parent]
|
107
|
+
base = args[:base]
|
96
108
|
realKlassName = "#{cname}"
|
97
|
-
klass = Class.new
|
98
|
-
|
99
|
-
end
|
109
|
+
klass = Class.new base do ; end
|
100
110
|
parent.const_set realKlassName, klass
|
101
111
|
return klass
|
102
112
|
end
|
103
|
-
|
104
|
-
# A class to old Paramaters.
|
105
|
-
class Param < SOAP::Header::SimpleHandler
|
106
|
-
def initialize(tag, out)
|
107
|
-
@out = out
|
108
|
-
super(XSD::QName.new(nil, tag))
|
109
|
-
end
|
110
|
-
|
111
|
-
def on_simple_outbound
|
112
|
-
@out
|
113
|
-
end
|
114
|
-
|
115
|
-
def [](k)
|
116
|
-
return @out[k]
|
117
|
-
end
|
118
|
-
|
119
|
-
def []=(k,v)
|
120
|
-
@out[k]=v
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# A class to hold the object mask.
|
125
|
-
class ObjectMask < SOAP::Header::SimpleHandler
|
126
|
-
|
127
|
-
def initialize(tag, out)
|
128
|
-
@out = out
|
129
|
-
super(XSD::QName.new(nil, tag))
|
130
|
-
end
|
131
|
-
|
132
|
-
def on_simple_outbound
|
133
|
-
{ 'mask' => @out }
|
134
|
-
end
|
135
|
-
|
136
|
-
def [](k)
|
137
|
-
@out[k]
|
138
|
-
end
|
139
|
-
|
140
|
-
def []=(k,v)
|
141
|
-
@out[k]=v
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
class ResultLimit < SOAP::Header::SimpleHandler
|
146
|
-
attr_accessor :limit, :offset
|
147
|
-
|
148
|
-
# limit should be an array of two elements; limit and offset.
|
149
|
-
def initialize(tag, limit)
|
150
|
-
@limit = limit[0]
|
151
|
-
@offset = limit[1]
|
152
|
-
super(XSD::QName.new(nil, tag))
|
153
|
-
end
|
154
|
-
|
155
|
-
def on_simple_outbound
|
156
|
-
{ 'limit' => @limit, 'offset' => @offset }
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
|
161
|
-
# An Exception proxy class
|
162
|
-
# This doesn't do anything yet, but it probably
|
163
|
-
# will at some point.
|
164
|
-
class Exception < RuntimeError
|
165
|
-
|
166
|
-
def initialize(args)
|
167
|
-
e = args[:exception]
|
168
|
-
message = args[:message] unless args[:message].nil?
|
169
|
-
message = e.message unless e.nil?
|
170
|
-
super(message)
|
171
|
-
|
172
|
-
@realException = e unless e.nil?
|
173
|
-
@realException = self if @realException.nil?
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# The Base class for our generated class.
|
178
|
-
class BaseClass
|
179
|
-
|
180
|
-
WSDLBASE='http://api.service.softlayer.com/soap/v3'
|
181
|
-
WSDLPARAM='?wsdl'
|
182
|
-
|
183
|
-
@@wsdl = { }
|
184
|
-
@@apiUser = nil
|
185
|
-
@@apiKey = nil
|
186
|
-
|
187
|
-
# The initializer.
|
188
|
-
# Arguments:
|
189
|
-
# +user+:: The API User
|
190
|
-
# +key+:: The API Key
|
191
|
-
# +initParams+:: This object's initParam (just the key)
|
192
|
-
# +debug+:: Enable debug after driver creation. (IO handler)
|
193
|
-
#
|
194
|
-
# +user+ and +key+ are optional. The first time they're presented
|
195
|
-
# they're saved to class variables and reused later as necessary. Supplying
|
196
|
-
# +user+ and +key+ later does not overwrite the class variables. +initParams+ is
|
197
|
-
# required where the api requires it.
|
198
|
-
def initialize(args)
|
199
|
-
@apiUser = args[:user] unless args[:user].nil?
|
200
|
-
@apiKey = args[:key] unless args[:key].nil?
|
201
|
-
@initParam = args[:initParam]
|
202
|
-
|
203
|
-
@@apiUser = args[:user] unless (args[:user].nil? || !@@apiUser.nil?)
|
204
|
-
@@apiKey = args[:key] unless (args[:key].nil? || !@@apiKey.nil?)
|
205
|
-
@apiUser = @@apiUser unless (@@apiUser.nil? || !@apiUser.nil?)
|
206
|
-
@apiKey = @@apiKey unless (@@apiKey.nil? || !@apiKey.nil?)
|
207
|
-
@authHeader = Param.new('authenticate', {'username' => @apiUser, 'apiKey' => @apiKey})
|
208
|
-
|
209
|
-
self.class.cacheWSDL
|
210
|
-
@slapi = @@wsdl[self.soapClass].create_rpc_driver unless @@wsdl[self.soapClass].nil?
|
211
|
-
raise SoftLayer::Exception.new(:message => 'WSDL endpoint not available.') if @slapi.nil?
|
212
|
-
|
213
|
-
self.debug=args[:debug] unless args[:debug].nil?
|
214
|
-
end
|
215
|
-
|
216
|
-
# Return this object's matching SLAPI SOAP Class.
|
217
|
-
def soapClass
|
218
|
-
return self.class.to_s.gsub(/::/, '_')
|
219
|
-
end
|
220
|
-
|
221
|
-
# This returns key values from this Service's associated Type (retrieved using #getObject).
|
222
|
-
def [](key)
|
223
|
-
@slapiObject = self.getObject if @slapiobject.nil?
|
224
|
-
return @slapiObject[key.to_s]
|
225
|
-
end
|
226
|
-
|
227
|
-
def setObject(obj)
|
228
|
-
@slapiObject = obj
|
229
|
-
end
|
230
|
-
|
231
|
-
# Set the object mask which ia passed as a hash of optional hashes (otherwise the hash elements should have a nil value).
|
232
|
-
# Using the example from the wiki:
|
233
|
-
# <SoftLayer_AccountObjectMask xsi:type="v3:SoftLayer_AccountObjectMask">
|
234
|
-
# <mask xsi:type="slt:SoftLayer_Account" xmlns:slt="http://api.service.softlayer.com/soap/v3/SLTypes/">
|
235
|
-
# <domains>
|
236
|
-
# <resourceRecords />
|
237
|
-
# </domains>
|
238
|
-
# <openTickets>
|
239
|
-
# <assignedUser />
|
240
|
-
# <attachedHardware />
|
241
|
-
# <updates />
|
242
|
-
# </openTickets>
|
243
|
-
# <userCount />
|
244
|
-
# </mask>
|
245
|
-
# </SoftLayer_AccountObjectMask>
|
246
|
-
#
|
247
|
-
# { 'domains' => { 'resourceRecords' => nil }, 'openTicket' => { 'assignedUser' => nil, 'attachedHardware' => nil, 'updates' => nil },
|
248
|
-
# userCount => nil }
|
249
|
-
# Changing this resets the cached object used by #[]
|
250
|
-
def objectMask=(mask)
|
251
|
-
if mask.class == ObjectMask
|
252
|
-
@objectMask = mask
|
253
|
-
else
|
254
|
-
@objectMask = ObjectMask.new("#{self.soapClass}ObjectMask", mask)
|
255
|
-
end
|
256
|
-
@slapiObject = nil
|
257
|
-
end
|
258
|
-
|
259
|
-
def objectMask
|
260
|
-
return @objectMask
|
261
|
-
end
|
262
|
-
|
263
|
-
# Set an object wide result set (or clear it)
|
264
|
-
# arg can be one of three things:
|
265
|
-
# * nil clears the resultLimit
|
266
|
-
# * A Result Limit array of two elements range and offset.
|
267
|
-
# * An existing ResultLimit object
|
268
|
-
def resultLimit=(arg)
|
269
|
-
case arg.class
|
270
|
-
when NilClass
|
271
|
-
@resultLimit = nil
|
272
|
-
when Array
|
273
|
-
@resultLimit = ResultLimit.new('resultLimit',arg)
|
274
|
-
when ResultLimit
|
275
|
-
@resultLimit = arg
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def resultLimit
|
280
|
-
return @resultLimit
|
281
|
-
end
|
282
|
-
|
283
|
-
|
284
|
-
# Make a direct api call. Paramaters are a hash where the key is passed to ParamHeader as the tag, and the value
|
285
|
-
# is passed as the tag content, unless it's a magic paramater.
|
286
|
-
# Magic Paramaters:
|
287
|
-
# +initParam+:: Initialization paramater for this call (just the key), therwise @initParam is used.
|
288
|
-
# +limit+:: A Result Limit array of two elements range and offset. If @resultLimit is set it's used
|
289
|
-
# if +limit+ is not and if neither is set, no limit is applied.
|
290
|
-
#
|
291
|
-
# If a block is provided, the limit's range (or fewer) elements will yield to the block until the dataset
|
292
|
-
# is exhausted. If no limit is provided with the block a limit of [1,0] is assumed initially.
|
293
|
-
# Aliased to #method_missing.
|
294
|
-
def slapiCall(method, args = { }, &block)
|
295
|
-
|
296
|
-
initParam = args[:initParam] unless args[:initParam].nil?
|
297
|
-
args.delete(:initParam) unless args[:initParam].nil?
|
298
|
-
initParam = Param.new("#{self.soapClass}InitParameters", { 'id' => initParam }) unless initParam.nil?
|
299
|
-
initParam = @initParam if initParam.nil?
|
300
|
-
resultLimit = ResultLimit.new('resultLimit', args[:limit]) unless args[:limit].nil?
|
301
|
-
args.delete(:limit) unless args[:limit].nil?
|
302
|
-
resultLimit = @resultLimit if resultLimit.nil?
|
303
|
-
|
304
|
-
@slapi.headerhandler << @authHeader unless @slapi.headerhandler.include?(@authHeader)
|
305
|
-
paramHeaders = []
|
306
|
-
unless args.nil?
|
307
|
-
args.each do |k,v|
|
308
|
-
p = Param.new(k.to_s,v)
|
309
|
-
paramHeaders.push(p)
|
310
|
-
@slapi.headerhandler << p
|
311
|
-
end
|
312
|
-
end
|
313
|
-
@slapi.headerhandler << initParam unless @slapi.headerhandler.include?(@authHeader)
|
314
|
-
@slapi.headerhandler << @objectMask unless @objectMask.nil?
|
315
|
-
@slapi.headerhandler << resultLimit unless resultLimit.nil?
|
316
|
-
|
317
|
-
if block_given?
|
318
|
-
go=true
|
319
|
-
resultLimit = ResultLimit.new('resultLimit', [1,0]) if resultLimit.nil? # this is broken.
|
320
|
-
@slapi.headerhandler << resultLimit unless @slapi.headerhandler.include?(resultLimit)
|
321
|
-
while(go) do
|
322
|
-
res = realCall(method.to_s)
|
323
|
-
yield(res) unless (res.nil? || (res.respond_to?(:empty) && res.empty?))
|
324
|
-
go = false if res.nil?
|
325
|
-
go = false if (res.respond_to?(:size) && (res.size < resultLimit.limit))
|
326
|
-
resultLimit.offset=resultLimit.offset + resultLimit.limit
|
327
|
-
end
|
328
|
-
headerClean(resultLimit,paramHeaders)
|
329
|
-
return true
|
330
|
-
else
|
331
|
-
res = realCall(method.to_s)
|
332
|
-
headerClean(resultLimit,paramHeaders)
|
333
|
-
return res
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
# Alias the above slapiCall to #method_missing.
|
338
|
-
alias_method :method_missing, :slapiCall
|
339
|
-
# Alias slapiCall to #call specifically because of it's special paramter list.
|
340
|
-
alias_method :call, :slapiCall
|
341
|
-
|
342
|
-
# Enable (or disable) debug. (paramater is the IO handler to write to)
|
343
|
-
def debug=(dev)
|
344
|
-
@slapi.wiredump_dev=(dev)
|
345
|
-
end
|
346
|
-
|
347
|
-
# Get the WSDL, parse it, and save it to a Class level hash.
|
348
|
-
# Returns false of we couldn't parse the WSDL.
|
349
|
-
def self.cacheWSDL
|
350
|
-
return unless @@wsdl[self.soapClass].nil?
|
351
|
-
|
352
|
-
begin
|
353
|
-
# XXX: Silence soap4r's bogus use of Kernel#warn
|
354
|
-
v = $VERBOSE
|
355
|
-
$VERBOSE=nil
|
356
|
-
@@wsdl[self.soapClass] = SOAP::WSDLDriverFactory.new(self.wsdlUrl)
|
357
|
-
$VERBOSE = v
|
358
|
-
return true
|
359
|
-
rescue => e
|
360
|
-
return SoftLayer::Exception.new(:exception => e)
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
# Return this Class's WSDL.
|
365
|
-
def self.wsdl
|
366
|
-
return @@wsdl[self.soapClass]
|
367
|
-
end
|
368
|
-
|
369
|
-
# Return this Class's WSDL URL.
|
370
|
-
def self.wsdlUrl
|
371
|
-
return URI.parse("#{WSDLBASE}/#{self.soapClass}#{WSDLPARAM}")
|
372
|
-
end
|
373
|
-
|
374
|
-
# Returns this Class's SOAP Class.
|
375
|
-
def self.soapClass
|
376
|
-
self.name.to_s.gsub(/::/, '_')
|
377
|
-
end
|
378
|
-
|
379
|
-
private
|
380
|
-
|
381
|
-
# Clean the headers out of the driver.
|
382
|
-
def headerClean(rl,ha)
|
383
|
-
@slapi.headerhandler.delete(rl)
|
384
|
-
ha.each { |h| @slapi.headerhandler.delete(h) }
|
385
|
-
end
|
386
|
-
|
387
|
-
# This really calls the soap method.
|
388
|
-
# This catches all exceptions, creates a copy of our exception proxy class
|
389
|
-
# and copies the message. This insures exceptions make it up to user code
|
390
|
-
# as opposed to soap4r's tendancy to just exit when there's a soap exception.
|
391
|
-
# todo: Add header processing/clean up.
|
392
|
-
def realCall(m)
|
393
|
-
begin
|
394
|
-
return @slapi.call(m)
|
395
|
-
rescue => e
|
396
|
-
re = SoftLayer::Exception.new(:exception => e)
|
397
|
-
raise re
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
end
|
402
113
|
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# baseclass
|
3
|
+
#
|
4
|
+
# Author:: James Nuckolls
|
5
|
+
# Copyright:: Copyright (c) 2009 SoftLayer. All rights reserved.
|
6
|
+
#
|
7
|
+
#= Description
|
8
|
+
#
|
9
|
+
#= ToDo
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rubygems' rescue LoadError
|
13
|
+
gem 'soap4r'
|
14
|
+
require 'soap/wsdlDriver'
|
15
|
+
|
16
|
+
require 'softlayer'
|
17
|
+
require 'softlayer/util'
|
18
|
+
|
19
|
+
|
20
|
+
module SoftLayer
|
21
|
+
# The Base class for our generated class.
|
22
|
+
class BaseClass
|
23
|
+
attr_reader :slapi, :initParam
|
24
|
+
|
25
|
+
WSDLBASE='http://api.service.softlayer.com/soap/v3'
|
26
|
+
WSDLPARAM='?wsdl'
|
27
|
+
|
28
|
+
@@wsdl = { }
|
29
|
+
@@apiUser = nil
|
30
|
+
@@apiKey = nil
|
31
|
+
|
32
|
+
# The initializer.
|
33
|
+
# Arguments:
|
34
|
+
# +user+:: The API User
|
35
|
+
# +key+:: The API Key
|
36
|
+
# +initParams+:: This object's initParam (just the key)
|
37
|
+
# +debug+:: Enable debug after driver creation. (IO handler)
|
38
|
+
#
|
39
|
+
# +user+ and +key+ are optional. The first time they're presented
|
40
|
+
# they're saved to class variables and reused later as necessary. Supplying
|
41
|
+
# +user+ and +key+ later does not overwrite the class variables. +initParams+ is
|
42
|
+
# required where the api requires it.
|
43
|
+
def initialize(args)
|
44
|
+
@apiUser = args[:user] unless args[:user].nil?
|
45
|
+
@apiKey = args[:key] unless args[:key].nil?
|
46
|
+
@initParam = args[:initParam]
|
47
|
+
@initParam = Param.new("#{self.soapClass}InitParameters", { 'id' => args[:initParam] }) unless args[:initParam].nil?
|
48
|
+
|
49
|
+
@@apiUser = args[:user] unless (args[:user].nil? || !@@apiUser.nil?)
|
50
|
+
@@apiKey = args[:key] unless (args[:key].nil? || !@@apiKey.nil?)
|
51
|
+
@apiUser = @@apiUser unless (@@apiUser.nil? || !@apiUser.nil?)
|
52
|
+
@apiKey = @@apiKey unless (@@apiKey.nil? || !@apiKey.nil?)
|
53
|
+
@authHeader = Param.new('authenticate', {'username' => @apiUser, 'apiKey' => @apiKey})
|
54
|
+
|
55
|
+
self.class.cacheWSDL
|
56
|
+
@slapi = @@wsdl[self.soapClass].create_rpc_driver unless @@wsdl[self.soapClass].nil?
|
57
|
+
raise SoftLayer::Exception.new(:message => 'WSDL endpoint not available.') if @slapi.nil?
|
58
|
+
|
59
|
+
self.debug=args[:debug] unless args[:debug].nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return this object's matching SLAPI SOAP Class.
|
63
|
+
def soapClass
|
64
|
+
return self.class.to_s.gsub(/::/, '_')
|
65
|
+
end
|
66
|
+
|
67
|
+
# This returns key values from this Service's associated Type (retrieved using #getObject).
|
68
|
+
def [](key)
|
69
|
+
@slapiObject = self.getObject if @slapiobject.nil?
|
70
|
+
return @slapiObject[key.to_s]
|
71
|
+
end
|
72
|
+
|
73
|
+
def setObject(obj)
|
74
|
+
@slapiObject = obj
|
75
|
+
end
|
76
|
+
|
77
|
+
# Set the object mask which ia passed as a hash of optional hashes (otherwise the hash elements should have a nil value).
|
78
|
+
# Using the example from the wiki:
|
79
|
+
# <SoftLayer_AccountObjectMask xsi:type="v3:SoftLayer_AccountObjectMask">
|
80
|
+
# <mask xsi:type="slt:SoftLayer_Account" xmlns:slt="http://api.service.softlayer.com/soap/v3/SLTypes/">
|
81
|
+
# <domains>
|
82
|
+
# <resourceRecords />
|
83
|
+
# </domains>
|
84
|
+
# <openTickets>
|
85
|
+
# <assignedUser />
|
86
|
+
# <attachedHardware />
|
87
|
+
# <updates />
|
88
|
+
# </openTickets>
|
89
|
+
# <userCount />
|
90
|
+
# </mask>
|
91
|
+
# </SoftLayer_AccountObjectMask>
|
92
|
+
#
|
93
|
+
# { 'domains' => { 'resourceRecords' => nil }, 'openTicket' => { 'assignedUser' => nil, 'attachedHardware' => nil, 'updates' => nil },
|
94
|
+
# userCount => nil }
|
95
|
+
# Changing this resets the cached object used by #[]
|
96
|
+
def objectMask=(mask)
|
97
|
+
if mask.class == ObjectMask
|
98
|
+
@objectMask = mask
|
99
|
+
else
|
100
|
+
@objectMask = ObjectMask.new("#{self.soapClass}ObjectMask", mask)
|
101
|
+
end
|
102
|
+
@slapiObject = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def objectMask
|
106
|
+
return @objectMask
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set an object wide result set (or clear it)
|
110
|
+
# arg can be one of three things:
|
111
|
+
# * nil clears the resultLimit
|
112
|
+
# * A Result Limit array of two elements range and offset.
|
113
|
+
# * An existing ResultLimit object
|
114
|
+
def resultLimit=(arg)
|
115
|
+
case arg.class
|
116
|
+
when NilClass
|
117
|
+
@resultLimit = nil
|
118
|
+
when Array
|
119
|
+
@resultLimit = ResultLimit.new('resultLimit',arg)
|
120
|
+
when ResultLimit
|
121
|
+
@resultLimit = arg
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def resultLimit
|
126
|
+
return @resultLimit
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Make a direct api call. The values of the paramaters are passed to the method
|
131
|
+
# (the keys generally are not), unless it's a magic paramater.
|
132
|
+
# Magic Paramaters:
|
133
|
+
# +initParam+:: Initialization paramater for this call (just the key), therwise @initParam is used.
|
134
|
+
# +limit+:: A Result Limit array of two elements range and offset. If @resultLimit is set it's used \
|
135
|
+
# if +limit+ is not and if neither is set, no limit is applied.
|
136
|
+
# +header+:: Extra headers to pass to the method in an array.
|
137
|
+
#
|
138
|
+
# If a block is provided, the limit's range (or fewer) elements will yield to the block until the dataset
|
139
|
+
# is exhausted. If no limit is provided with the block a limit of [1,0] is assumed initially (sorta).
|
140
|
+
# Aliased to #method_missing.
|
141
|
+
def slapiCall(method, args = {}, &block)
|
142
|
+
initParam = args[:initParam] unless args[:initParam].nil?
|
143
|
+
args.delete(:initParam) unless args[:initParam].nil?
|
144
|
+
initParam = Param.new("#{self.soapClass}InitParameters", { 'id' => initParam }) unless initParam.nil?
|
145
|
+
initParam = @initParam if initParam.nil?
|
146
|
+
resultLimit = ResultLimit.new('resultLimit', args[:limit]) unless args[:limit].nil?
|
147
|
+
args.delete(:limit) unless args[:limit].nil?
|
148
|
+
resultLimit = @resultLimit if resultLimit.nil?
|
149
|
+
unroll = true if resultLimit.nil? && block_given?
|
150
|
+
resultLimit = ResultLimit.new('resultLimit', [5,0]) if resultLimit.nil? && block_given?
|
151
|
+
headers = args[:header]
|
152
|
+
args.delete(:header) unless args[:header].nil?
|
153
|
+
|
154
|
+
headers = [] if headers.nil?
|
155
|
+
headers << initParam unless @slapi.headerhandler.include?(initParam)
|
156
|
+
headers << @objectMask unless @objectMask.nil?
|
157
|
+
headers << resultLimit unless resultLimit.nil?
|
158
|
+
argshash = { :method => method, :headers => headers, :args => args }
|
159
|
+
argshash[:yield] = true if block_given?
|
160
|
+
catch :done do
|
161
|
+
while true do
|
162
|
+
res = realCall(argshash)
|
163
|
+
return res unless block_given?
|
164
|
+
return res if res.nil?
|
165
|
+
res.each { |e| yield(e) } if unroll && res.respond_to?(:each)
|
166
|
+
yield(res) unless unroll || (res.respond_to?(:empty) && res.empty?)
|
167
|
+
throw :done if (res.respond_to?(:size) && (res.size < resultLimit.limit))
|
168
|
+
resultLimit.offset=resultLimit.offset + resultLimit.limit
|
169
|
+
end
|
170
|
+
end
|
171
|
+
headerClean(headers) if argshash[:yield]
|
172
|
+
end
|
173
|
+
|
174
|
+
# Alias the above slapiCall to #method_missing.
|
175
|
+
alias_method :method_missing, :slapiCall
|
176
|
+
# Alias slapiCall to #call specifically because of it's special paramter list.
|
177
|
+
alias_method :call, :slapiCall
|
178
|
+
|
179
|
+
# Enable (or disable) debug. (paramater is the IO handler to write to)
|
180
|
+
def debug=(dev)
|
181
|
+
@slapi.wiredump_dev=(dev)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get the WSDL, parse it, and save it to a Class level hash.
|
185
|
+
# Returns false of we couldn't parse the WSDL.
|
186
|
+
def self.cacheWSDL
|
187
|
+
return unless @@wsdl[self.soapClass].nil?
|
188
|
+
|
189
|
+
begin
|
190
|
+
# XXX: Silence soap4r's bogus use of Kernel#warn
|
191
|
+
v = $VERBOSE
|
192
|
+
$VERBOSE=nil
|
193
|
+
@@wsdl[self.soapClass] = SOAP::WSDLDriverFactory.new(self.wsdlUrl)
|
194
|
+
$VERBOSE = v
|
195
|
+
return true
|
196
|
+
rescue => e
|
197
|
+
return SoftLayer::Exception.new(:exception => e)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Return this Class's WSDL.
|
202
|
+
def self.wsdl
|
203
|
+
return @@wsdl[self.soapClass]
|
204
|
+
end
|
205
|
+
|
206
|
+
# Return this Class's WSDL URL.
|
207
|
+
def self.wsdlUrl
|
208
|
+
return URI.parse("#{WSDLBASE}/#{self.soapClass}#{WSDLPARAM}")
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns this Class's SOAP Class.
|
212
|
+
def self.soapClass
|
213
|
+
self.name.to_s.gsub(/::/, '_')
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
# Clean the headers out of the driver.
|
219
|
+
def headerClean(ha)
|
220
|
+
ha.each { |h| @slapi.headerhandler.delete(h) }
|
221
|
+
end
|
222
|
+
|
223
|
+
# This really calls the soap method.
|
224
|
+
# This catches all exceptions, creates a copy of our exception proxy class
|
225
|
+
# and copies the message. This insures exceptions make it up to user code
|
226
|
+
# as opposed to soap4r's tendancy to just exit when there's a soap exception.
|
227
|
+
# todo: Add header processing/clean up.
|
228
|
+
def realCall(args)
|
229
|
+
m = args[:method]
|
230
|
+
h = args[:headers]
|
231
|
+
a = args[:args]
|
232
|
+
y = args[:yield]
|
233
|
+
@slapi.headerhandler << @authHeader unless @slapi.headerhandler.include?(@authHeader)
|
234
|
+
h.each {|e| @slapi.headerhandler << e }
|
235
|
+
args = []
|
236
|
+
a.each { |k,v| args.push(v) }
|
237
|
+
begin
|
238
|
+
return @slapi.call(m.to_s, *args)
|
239
|
+
rescue => e
|
240
|
+
re = SoftLayer::Exception.new(:exception => e)
|
241
|
+
raise re
|
242
|
+
ensure
|
243
|
+
headerClean(h) unless y
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# util
|
3
|
+
#
|
4
|
+
# Author:: James Nuckolls
|
5
|
+
# Copyright:: Copyright (c) 2009 SoftLayer. All rights reserved.
|
6
|
+
#
|
7
|
+
#= Description
|
8
|
+
#
|
9
|
+
#= ToDo
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rubygems' rescue LoadError
|
13
|
+
gem 'soap4r'
|
14
|
+
require 'soap/header/simplehandler'
|
15
|
+
|
16
|
+
|
17
|
+
module SoftLayer
|
18
|
+
# A class to old Paramaters.
|
19
|
+
class Param < SOAP::Header::SimpleHandler
|
20
|
+
def initialize(tag, out)
|
21
|
+
@out = out
|
22
|
+
super(XSD::QName.new(nil, tag))
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_simple_outbound
|
26
|
+
@out
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](k)
|
30
|
+
return @out[k]
|
31
|
+
end
|
32
|
+
|
33
|
+
def []=(k,v)
|
34
|
+
@out[k]=v
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A class to hold the object mask.
|
39
|
+
class ObjectMask < SOAP::Header::SimpleHandler
|
40
|
+
|
41
|
+
def initialize(tag, out)
|
42
|
+
@out = out
|
43
|
+
super(XSD::QName.new(nil, tag))
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_simple_outbound
|
47
|
+
{ 'mask' => @out }
|
48
|
+
end
|
49
|
+
|
50
|
+
def [](k)
|
51
|
+
@out[k]
|
52
|
+
end
|
53
|
+
|
54
|
+
def []=(k,v)
|
55
|
+
@out[k]=v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ResultLimit < SOAP::Header::SimpleHandler
|
60
|
+
attr_accessor :limit, :offset
|
61
|
+
|
62
|
+
# limit should be an array of two elements; limit and offset.
|
63
|
+
def initialize(tag, limit)
|
64
|
+
@limit = limit[0]
|
65
|
+
@offset = limit[1]
|
66
|
+
super(XSD::QName.new(nil, tag))
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_simple_outbound
|
70
|
+
{ 'limit' => @limit, 'offset' => @offset }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# An Exception proxy class
|
76
|
+
# Not every exception soap4r returns decends from RuntimeError.
|
77
|
+
class Exception < RuntimeError
|
78
|
+
|
79
|
+
def initialize(args)
|
80
|
+
e = args[:exception]
|
81
|
+
message = args[:message] unless args[:message].nil?
|
82
|
+
message = e.message unless e.nil?
|
83
|
+
super(message)
|
84
|
+
|
85
|
+
@realException = e unless e.nil?
|
86
|
+
@realException = self if @realException.nil?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# cdnlayerupload
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009, James Nuckolls. All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
# * Neither "James Nuckolls" nor the names of any contributors may
|
15
|
+
# be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
22
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
#
|
30
|
+
#= Description
|
31
|
+
# Retrieves the current Account's BillingItems using an objectMask and outputs a report of the
|
32
|
+
# current (not-canceled) items.
|
33
|
+
#= ToDo
|
34
|
+
#
|
35
|
+
|
36
|
+
require 'rubygems' rescue LoadError
|
37
|
+
require 'ftools'
|
38
|
+
require 'pp'
|
39
|
+
require 'softlayer'
|
40
|
+
|
41
|
+
AUTH_USER = ARGV[0]
|
42
|
+
AUTH_KEY = ARGV[4]
|
43
|
+
ACCT_ID = ARGV[1]
|
44
|
+
CDN_ACCT = ARGV[2]
|
45
|
+
INFILE = ARGV[3]
|
46
|
+
|
47
|
+
SLAPICLASSES = [ 'SoftLayer::Account', 'SoftLayer::Network::ContentDelivery::Account' ]
|
48
|
+
SoftLayer::declareClasses(:ruby => SLAPICLASSES)
|
49
|
+
account = SoftLayer::Account.new(:user => AUTH_USER, :key => AUTH_KEY, :initParam => ACCT_ID)
|
50
|
+
account.objectMask={'cdnAccountName' => nil}
|
51
|
+
cdnacct = nil
|
52
|
+
|
53
|
+
# Get the accout number by matching the name that was in ARGV[2]
|
54
|
+
account.getCdnAccounts.each do |c|
|
55
|
+
# pp c
|
56
|
+
cdnacct = SoftLayer::Network::ContentDelivery::Account.new(:initParam => c['id']) if c['cdnAccountName'] == CDN_ACCT
|
57
|
+
end
|
58
|
+
|
59
|
+
cdnacct.getPopNames
|
60
|
+
|
61
|
+
fname = File.basename(INFILE)
|
62
|
+
# base64 encode the file
|
63
|
+
b64 = [IO.read(INFILE)].pack("m")
|
64
|
+
# cdnacct.debug=STDOUT
|
65
|
+
ret = cdnacct.uploadStream(:source => { 'data' => b64, 'filename' => fname}, :target => "/media/http/test")
|
66
|
+
pp ret
|
67
|
+
|
68
|
+
|
data/sample/resultlimit.rb
CHANGED
@@ -46,6 +46,7 @@ SoftLayer::declareClasses(:ruby => SLAPICLASSES)
|
|
46
46
|
range = 5
|
47
47
|
offset = 0
|
48
48
|
account = SoftLayer::Account.new(:user => AUTH_USER, :key => AUTH_KEY, :initParam => ACCT_ID)
|
49
|
+
|
49
50
|
# account.debug=STDOUT
|
50
51
|
bia = account.getAllBillingItems(:limit => [range,offset])
|
51
52
|
pp bia
|
@@ -61,11 +62,13 @@ account.getAllBillingItems(:limit => [range,offset]) do |bi|
|
|
61
62
|
offset = range + offset
|
62
63
|
end
|
63
64
|
|
64
|
-
range =
|
65
|
+
range = 1
|
65
66
|
offset = 0
|
66
|
-
|
67
|
-
account.getInvoices(:limit => [range,offset]) do |bi|
|
67
|
+
account.getInvoices do |bi|
|
68
68
|
pp bi
|
69
69
|
puts "================== #{offset}"
|
70
70
|
offset = offset + range
|
71
71
|
end
|
72
|
+
|
73
|
+
exit 0
|
74
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jamesn-softlayer-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Nuckolls
|
@@ -9,7 +9,7 @@ autorequire: softlayer
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-27 22:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -34,10 +34,13 @@ extra_rdoc_files:
|
|
34
34
|
- Changes
|
35
35
|
files:
|
36
36
|
- lib/softlayer.rb
|
37
|
+
- lib/softlayer/baseclass.rb
|
38
|
+
- lib/softlayer/util.rb
|
37
39
|
- sample/nascapacity.rb
|
38
40
|
- sample/billingreport.rb
|
39
41
|
- sample/objectmask.rb
|
40
42
|
- sample/resultlimit.rb
|
43
|
+
- sample/cdnlayerupload.rb
|
41
44
|
- README
|
42
45
|
- LICENSE
|
43
46
|
- Changes
|