jamesn-softlayer-ruby 0.6.3.0 → 0.7.0.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.
- 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
|