UCSAPI 0.0.6
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/History.txt +14 -0
- data/Manifest.txt +10 -0
- data/PostInstall.txt +1 -0
- data/Rakefile +30 -0
- data/lib/UCSAPI.rb +541 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_UCSAPI.rb +11 -0
- data/test/test_helper.rb +3 -0
- metadata +140 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/PostInstall.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
For more information on UCSAPI, see http://ciscoucs.rubyforge.org
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'hoe', '>= 2.1.0'
|
3
|
+
require 'hoe'
|
4
|
+
require 'fileutils'
|
5
|
+
require './lib/UCSAPI'
|
6
|
+
|
7
|
+
Hoe.plugin :newgem
|
8
|
+
# Hoe.plugin :website
|
9
|
+
# Hoe.plugin :cucumberfeatures
|
10
|
+
|
11
|
+
# Generate all the Rake tasks
|
12
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
13
|
+
$hoe = Hoe.spec 'UCSAPI' do
|
14
|
+
self.description = 'A simple ruby interface to the Cisco UCS XMLAPI'
|
15
|
+
self.url = 'http://ciscoucs.rubyforge.org'
|
16
|
+
self.developer 'Steve Chambers', 'stevie_chambers @nospam@ viewyonder.com'
|
17
|
+
self.post_install_message = 'PostInstall.txt'
|
18
|
+
self.rubyforge_name = 'ciscoucs'
|
19
|
+
self.extra_deps << ['rubygems-update']
|
20
|
+
self.extra_deps << ['rest-client']
|
21
|
+
self.readme_file = 'README.rdoc'
|
22
|
+
self.rubyforge_name = 'ciscoucs'
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'newgem/tasks'
|
26
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
27
|
+
|
28
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
29
|
+
# remove_task :default
|
30
|
+
# task :default => [:spec, :features]
|
data/lib/UCSAPI.rb
ADDED
@@ -0,0 +1,541 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
#= UCSAPI
|
5
|
+
#
|
6
|
+
#== What on earth do I do with this?
|
7
|
+
#The main UCSAPI module that you must _require_ into your Ruby script.
|
8
|
+
#If you _include_ the module in your classes, you can drop the UCSAPI:: prefix when using it.
|
9
|
+
#Here's a sample invocation that you could put at the top of your script
|
10
|
+
# require 'UCSAPI'
|
11
|
+
# include UCSAPI
|
12
|
+
# myucs = UCSM.new( :url => 'http://myucs', :inName => 'viewyonder', :inPassword => 'secret')
|
13
|
+
#
|
14
|
+
#== Unofficial, Unsupported simple interface to the UCSAPI
|
15
|
+
#
|
16
|
+
#This is a continual work in progress by stevie_chambers @nospam@ viewyonder.com
|
17
|
+
#to produce a simple interface to the powerful UCS XMLAPI.
|
18
|
+
#
|
19
|
+
#Things you can do with this UCSAPI code:
|
20
|
+
#* Get "raw" access to the XMLAPI methods like configResolveDn
|
21
|
+
#* Get friendly decorators to the raw methods, like "chassis" returning all chassis
|
22
|
+
#
|
23
|
+
#Future honorouable intentions:
|
24
|
+
#* Add more methods to get more objects, set configs, listen for events
|
25
|
+
#* Allow simple get/export of data in both raw and friendly formats (think interface stats and RRDtoo)
|
26
|
+
#* Add more backends that UCS, such as Nexus1000v and VMware.
|
27
|
+
#* Put a Rails front end on it so we have a GUI
|
28
|
+
#
|
29
|
+
#Author and Copyright (c) 2010 Steve Chambers
|
30
|
+
#http://viewyonder.com
|
31
|
+
#
|
32
|
+
#== License
|
33
|
+
#
|
34
|
+
#This work is licensed under the Creative Commons Attribution-ShareAlike license
|
35
|
+
#See it at: http://creativecommons.org/licenses/by-sa/3.0/
|
36
|
+
#
|
37
|
+
#You are free to share and remix as long as you
|
38
|
+
#* *Attribute* Steve Chambers and Cisco as the original authors
|
39
|
+
#* *Share* *Alike* by distributing derivative works under the same license terms.
|
40
|
+
#* *Notice* should be shown in reuse/distribution by linking to the license web page above
|
41
|
+
#
|
42
|
+
#These conditions can be waived if you get permission from Steve Chambers and Cisco.
|
43
|
+
#
|
44
|
+
|
45
|
+
module UCSAPI
|
46
|
+
require 'rubygems'
|
47
|
+
require 'rexml/document'
|
48
|
+
require 'rest_client'
|
49
|
+
require 'logger'
|
50
|
+
require 'ostruct'
|
51
|
+
VERSION = '0.0.6'
|
52
|
+
|
53
|
+
#At the moment this is one big class with lots of methods. Refactoring due later :)
|
54
|
+
class UCSM
|
55
|
+
|
56
|
+
#Allow public read-only access to the user OpenStruct which contains session details
|
57
|
+
attr_reader :user
|
58
|
+
|
59
|
+
#Set up the _logger_ and initialize the _user_ ostruct based on paramters in opts[]
|
60
|
+
#Example call:
|
61
|
+
# UCSM.new( :url => 'http://ucs/nuova', :inName => 'jbloggs', :inPassword => 'secret', :logging => 'info')
|
62
|
+
def initialize(opts={})
|
63
|
+
# FIXME: NEED TO ADD OPTION CHECKING INC SECURITY
|
64
|
+
@log = Logger.new(STDOUT)
|
65
|
+
@log.level = case opts[:logging]
|
66
|
+
when 'info'
|
67
|
+
Logger::INFO
|
68
|
+
else
|
69
|
+
Logger::ERROR
|
70
|
+
end
|
71
|
+
@log.progname = "CiscoUCS:UCSM"
|
72
|
+
@user = OpenStruct.new
|
73
|
+
@user.url = opts[:url]
|
74
|
+
@user.inName = opts[:inName] || opts[:name]
|
75
|
+
@user.inPassword = opts[:inPassword] || opts[:password]
|
76
|
+
@user.session = nil
|
77
|
+
@log.info("initialized")
|
78
|
+
end
|
79
|
+
|
80
|
+
#Build an send the <aaaLogin /> method to UCS
|
81
|
+
#Returns *user.session* which is an OpenStruct
|
82
|
+
#* Build the XMLAPI call from the opts parameters
|
83
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
84
|
+
#* Create a new OpenStruct from the response and store in @user
|
85
|
+
def login
|
86
|
+
@log.info("login @url=" + @user.url + ", @name=" + @user.inName + ", @password=" + @user.inPassword)
|
87
|
+
|
88
|
+
request = REXML::Document.new('<aaaLogin />')
|
89
|
+
request.root.add_attribute("inName",@user.inName)
|
90
|
+
request.root.add_attribute("inPassword",@user.inPassword)
|
91
|
+
|
92
|
+
response = dispatch(request)
|
93
|
+
|
94
|
+
attrs = Hash.new
|
95
|
+
response.attributes.each { | key, value | attrs[key]=value }
|
96
|
+
@user.session = OpenStruct.new(attrs)
|
97
|
+
|
98
|
+
if @user.session.response = "yes" and @user.session.outStatus = "success"
|
99
|
+
@log.info("login SUCCESS response = " + @user.session.to_s)
|
100
|
+
@user.session
|
101
|
+
else
|
102
|
+
@log.info("login FAIL response = " + @user.session.to_s)
|
103
|
+
@user.session
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
#Reuse an existing session, identified by the _@cookie_
|
108
|
+
#Returns *user.session* which is an OpenStruct
|
109
|
+
#* Build the XMLAPI call from the opts parameters
|
110
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
111
|
+
#* Create a new OpenStruct from the response and store in @user
|
112
|
+
def refresh
|
113
|
+
@log.info("@url=" + @user.url + ", @cookie=" + @user.session.outCookie)
|
114
|
+
|
115
|
+
request = REXML::Document.new('<aaaRefresh />')
|
116
|
+
request.root.add_attribute("inCookie",@user.session.outCookie)
|
117
|
+
|
118
|
+
response = dispatch(request)
|
119
|
+
|
120
|
+
attrs = Hash.new
|
121
|
+
response.attributes.each { | key, value | attrs[key]=value }
|
122
|
+
@user.session = OpenStruct.new(attrs)
|
123
|
+
|
124
|
+
if @user.session.response = "yes" and @user.session.outStatus = "success"
|
125
|
+
@log.info("refresh SUCCESS response = " + @user.session.to_s)
|
126
|
+
@user.session
|
127
|
+
else
|
128
|
+
@log.info("refresh FAIL response = " + @user.session.to_s)
|
129
|
+
@user.session
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#Logout / kill the UCS session with the _@cookie_
|
134
|
+
#Returns *user.session* which is an OpenStruct
|
135
|
+
#* Build the XMLAPI call from the opts parameters
|
136
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
137
|
+
#* Create a new OpenStruct from the response and store in @user
|
138
|
+
def logout
|
139
|
+
@log.info("logout @url=" + @user.url + ", @cookie=" + @user.session.outCookie)
|
140
|
+
|
141
|
+
request = REXML::Document.new('<aaaLogout />')
|
142
|
+
request.root.add_attribute("inCookie",@user.session.outCookie)
|
143
|
+
|
144
|
+
response = dispatch(request)
|
145
|
+
|
146
|
+
attrs = Hash.new
|
147
|
+
response.attributes.each { | key, value | attrs[key]=value }
|
148
|
+
@user.session = OpenStruct.new(attrs)
|
149
|
+
|
150
|
+
if @user.session.response = "yes" and @user.session.outStatus = "success"
|
151
|
+
@log.info("logout SUCCESS response = " + @user.session.to_s)
|
152
|
+
@user.session
|
153
|
+
else
|
154
|
+
@log.info("logout FAIL response = " + @user.session.to_s)
|
155
|
+
@user.session
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#Get an xml object containing API code, turn into text and HTTP POST it to _@user.url_
|
160
|
+
#Returns the root REXML::Element of the UCS XMLAPI response document
|
161
|
+
#* The caller will send a REXML object with the XMLAPI command in it
|
162
|
+
#* Send the XMLAPI call to UCS and catch any exceptions (log and quit if we do)
|
163
|
+
def dispatch(xml)
|
164
|
+
@log.info("UCSAPI::Session.dispatch sending " + xml.to_s)
|
165
|
+
|
166
|
+
# The RestClient.post method expects text, not a REXML object
|
167
|
+
post = xml.to_s
|
168
|
+
|
169
|
+
# FIXME: RestClient timeout is broken and default wait is 75s #dontaskmewhy
|
170
|
+
begin
|
171
|
+
response = RestClient.post @user.url, post, :content_type => 'text/xml'
|
172
|
+
rescue => e
|
173
|
+
@log.error "dispatch EXCEPTION " + e.class.to_s + " = " + e.to_s
|
174
|
+
exit
|
175
|
+
end
|
176
|
+
|
177
|
+
@log.info("dispatch received " + response.to_s)
|
178
|
+
REXML::Document.new(response).root
|
179
|
+
end
|
180
|
+
|
181
|
+
#Build an XMLAPI call to find an object via distinguished name
|
182
|
+
#Returns an *Array* of found objects
|
183
|
+
#* Build the XMLAPI call from the opts parameters
|
184
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
185
|
+
#If the response XML has objects under <outConfig> then
|
186
|
+
#* get each element and
|
187
|
+
#* build an OpenStruct with attributes from the XML attributes
|
188
|
+
#* add each OpenStruct to an array, which is returned to the method caller outConfig = response.root.elements[1]
|
189
|
+
def configResolveDn(opts={})
|
190
|
+
@log.info("configResolveDn started")
|
191
|
+
|
192
|
+
inHierarchical = opts[:inHierarchical] || "false"
|
193
|
+
if opts[:dn] then
|
194
|
+
request = REXML::Document.new('<configResolveDn />')
|
195
|
+
request.root.add_attribute("inHierarchical",inHierarchical)
|
196
|
+
request.root.add_attribute("dn",opts[:dn])
|
197
|
+
|
198
|
+
response = dispatch(request)
|
199
|
+
|
200
|
+
outConfig = response.root.elements[1]
|
201
|
+
if outConfig.has_elements? then
|
202
|
+
found = Array.new
|
203
|
+
outConfig.elements.each do |element|
|
204
|
+
attrs = Hash.new
|
205
|
+
attrs["classId"] = element.name
|
206
|
+
element.attributes.each { | key, value | attrs[key]=value }
|
207
|
+
found << OpenStruct.new(attrs)
|
208
|
+
end
|
209
|
+
|
210
|
+
@log.info "configResolveDn returning " + found.size.to_s + " objects"
|
211
|
+
else
|
212
|
+
@log.error "configResolveDn ERROR No items found for dn = " + opts[:dn]
|
213
|
+
end
|
214
|
+
else
|
215
|
+
@log.error "configResolveDn ERROR Please supply a :dn option like configResolveDn( :dn => 'sys/chassis-1' )" unless opts[:dn]
|
216
|
+
end
|
217
|
+
|
218
|
+
@log.info("configResolveDn ended")
|
219
|
+
found
|
220
|
+
end
|
221
|
+
|
222
|
+
#Build an XMLAPI call to find an object(s) via the class name
|
223
|
+
#Returns an *Array* of found objects
|
224
|
+
#* Build the XMLAPI call from the opts parameters
|
225
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
226
|
+
#If the response XML has objects under <outConfig> then
|
227
|
+
#* get each element and
|
228
|
+
#* build an OpenStruct with attributes from the XML attributes
|
229
|
+
#* add each OpenStruct to an array, which is returned to the method caller
|
230
|
+
def configResolveClass(opts={})
|
231
|
+
@log.info("configResolveClass started")
|
232
|
+
|
233
|
+
inHierarchical = opts[:inHierarchical] || "false"
|
234
|
+
if opts[:classId] then
|
235
|
+
request = REXML::Document.new('<configResolveClass />')
|
236
|
+
request.root.add_attribute("inHierarchical",inHierarchical)
|
237
|
+
request.root.add_attribute("classId",opts[:classId])
|
238
|
+
|
239
|
+
response = dispatch(request)
|
240
|
+
|
241
|
+
outConfig = response.root.elements[1]
|
242
|
+
if outConfig.has_elements? then
|
243
|
+
found = Array.new
|
244
|
+
outConfig.elements.each do |element|
|
245
|
+
attrs = Hash.new
|
246
|
+
attrs["classId"] = element.name
|
247
|
+
element.attributes.each { | key, value | attrs[key]=value }
|
248
|
+
found << OpenStruct.new(attrs)
|
249
|
+
end
|
250
|
+
|
251
|
+
@log.info "configResolveClass returning " + found.size.to_s + " objects"
|
252
|
+
else
|
253
|
+
@log.error "configResolveClass ERROR No items found for classId = " + opts[:classId]
|
254
|
+
end
|
255
|
+
else
|
256
|
+
@log.error "configResolveClass ERROR Please supply a :classId option like configResolveClass( :classId => 'equipmentChassis' )" unless opts[:classId]
|
257
|
+
end
|
258
|
+
|
259
|
+
@log.info("configResolveClass ended")
|
260
|
+
found
|
261
|
+
end
|
262
|
+
|
263
|
+
#Build an XMLAPI call to find objects of a specified class under a specified distinguished name
|
264
|
+
#Returns an *Array* of found objects
|
265
|
+
#* Build the XMLAPI call from the opts parameters
|
266
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
267
|
+
#If the response XML has objects under <outConfig> then
|
268
|
+
#* get each element and
|
269
|
+
#* build an OpenStruct with attributes from the XML attributes
|
270
|
+
#* add each OpenStruct to an array, which is returned to the method caller
|
271
|
+
def configResolveChildren(opts={})
|
272
|
+
@log.info("configResolveChildren started")
|
273
|
+
|
274
|
+
inHierarchical = opts[:inHierarchical] || "false"
|
275
|
+
request = REXML::Document.new('<configResolveChildren />')
|
276
|
+
request.root.add_attribute("inHierarchical",inHierarchical)
|
277
|
+
request.root.add_attribute("classId",opts[:classId])
|
278
|
+
request.root.add_attribute("inDn",opts[:inDn])
|
279
|
+
|
280
|
+
response = dispatch(request)
|
281
|
+
|
282
|
+
outConfig = response.root.elements[1]
|
283
|
+
if outConfig.has_elements? then
|
284
|
+
found = Array.new
|
285
|
+
outConfig.elements.each do |element|
|
286
|
+
attrs = Hash.new
|
287
|
+
attrs["classId"] = element.name
|
288
|
+
element.attributes.each { | key, value | attrs[key]=value }
|
289
|
+
found << OpenStruct.new(attrs)
|
290
|
+
end
|
291
|
+
@log.info "configResolveChildren returning " + found.size.to_s + " objects"
|
292
|
+
else
|
293
|
+
@log.error "configResolveChildren ERROR No items found for classId = " + opts[:classId]
|
294
|
+
end
|
295
|
+
|
296
|
+
@log.info("configResolveChildren ended")
|
297
|
+
found
|
298
|
+
end
|
299
|
+
|
300
|
+
#Build an XMLAPI call to find distinguished names in a specified class
|
301
|
+
#Returns an *Array* of found objects
|
302
|
+
#* Build the XMLAPI call from the opts parameters
|
303
|
+
#* Send the XMLAPI object to dispatch, get an XML object back
|
304
|
+
#If the response XML has objects under <outConfig> then
|
305
|
+
#* get each element and
|
306
|
+
#* build an OpenStruct with attributes from the XML attributes
|
307
|
+
#* add each OpenStruct to an array, which is returned to the method caller
|
308
|
+
def configScope(opts={})
|
309
|
+
@log.info("configScope started")
|
310
|
+
|
311
|
+
inHierarchical = opts[:inHierarchical] || "false"
|
312
|
+
inRecursive = opts[:inRecursive] || "false"
|
313
|
+
request = REXML::Document.new('<configScope />')
|
314
|
+
request.root.add_attribute("inHierarchical",inHierarchical)
|
315
|
+
request.root.add_attribute("inClass",opts[:inClass])
|
316
|
+
request.root.add_attribute("dn",opts[:dn])
|
317
|
+
|
318
|
+
response = dispatch(request)
|
319
|
+
|
320
|
+
outConfig = response.root.elements[1]
|
321
|
+
if outConfig.has_elements? then
|
322
|
+
found = Array.new
|
323
|
+
outConfig.elements.each do |element|
|
324
|
+
attrs = Hash.new
|
325
|
+
attrs["classId"] = element.name
|
326
|
+
element.attributes.each { | key, value | attrs[key]=value }
|
327
|
+
found << OpenStruct.new(attrs)
|
328
|
+
end
|
329
|
+
@log.info "configScope returning " + found.size.to_s + " objects"
|
330
|
+
else
|
331
|
+
@log.error "configScope ERROR No items found for classId = " + opts[:classId]
|
332
|
+
end
|
333
|
+
|
334
|
+
@log.info("configScope ended")
|
335
|
+
found
|
336
|
+
end
|
337
|
+
|
338
|
+
#Adapter pattern method to make finding fabric objects easier
|
339
|
+
#Returns an *Array* of found objects
|
340
|
+
#Logic is simple:
|
341
|
+
#* If you give us a dn, we get that and we're done
|
342
|
+
#* If you provide a text ID, we build a dn and get that
|
343
|
+
#* If you provide nothing, we get both fabrics
|
344
|
+
def fabric(opts={})
|
345
|
+
@log.info("fabric started")
|
346
|
+
|
347
|
+
found = Array.new
|
348
|
+
classId = 'networkElement'
|
349
|
+
|
350
|
+
if opts[:dn]
|
351
|
+
found = configResolveDn( :dn => opts[:dn] )
|
352
|
+
elsif opts[:id] then
|
353
|
+
dn = 'sys/switch-' + opts[:id]
|
354
|
+
@log.info("fabric find by dn = " + dn)
|
355
|
+
found = configResolveDn( :dn => dn)
|
356
|
+
else
|
357
|
+
@log.info("fabric find by class = " + classId)
|
358
|
+
found = configResolveClass( :classId => classId)
|
359
|
+
end
|
360
|
+
|
361
|
+
@log.info("fabric ended")
|
362
|
+
found
|
363
|
+
end
|
364
|
+
|
365
|
+
#Adapter pattern method to make finding chassis objects easier
|
366
|
+
#Returns an *Array* of found objects
|
367
|
+
#Logic is simple:
|
368
|
+
#* If you give us a dn, we get that and we're done
|
369
|
+
#* If you provide a numeric/text ID, we build a dn and get that
|
370
|
+
#* If you provide nothing, we get all chassis
|
371
|
+
def chassis(opts={})
|
372
|
+
@log.info("chassis started")
|
373
|
+
|
374
|
+
classId = 'equipmentChassis'
|
375
|
+
found = Array.new
|
376
|
+
|
377
|
+
if opts[:dn]
|
378
|
+
found = configResolveDn( :dn => opts[:dn] )
|
379
|
+
elsif opts[:id] then
|
380
|
+
dn = 'sys/chassis-' + opts[:id].to_s
|
381
|
+
found = configResolveDn( :dn => dn)
|
382
|
+
else
|
383
|
+
found = configResolveClass( :classId => classId)
|
384
|
+
end
|
385
|
+
|
386
|
+
@log.info("chassis ended")
|
387
|
+
found
|
388
|
+
end
|
389
|
+
|
390
|
+
#Adapter pattern method to make finding blades easier
|
391
|
+
#Returns an *Array* of found objects
|
392
|
+
#Logic is simple here:
|
393
|
+
#* You can just provide a dn, we just get that and we're done
|
394
|
+
#* If you provide only a :chassis, we get all blades in that chassis
|
395
|
+
#* If you provide a :chassis and a :blade it's like a full dn
|
396
|
+
#* If you provide nothing, we get all blades
|
397
|
+
def blade(opts={})
|
398
|
+
@log.info("blade started")
|
399
|
+
|
400
|
+
classId = 'computeBlade'
|
401
|
+
found = Array.new
|
402
|
+
|
403
|
+
if opts[:dn]
|
404
|
+
found = configResolveDn( :dn => opts[:dn] )
|
405
|
+
elsif opts[:chassis] then
|
406
|
+
chassis_dn = 'sys/chassis-' + opts[:chassis].to_s
|
407
|
+
if opts[:blade] then
|
408
|
+
dn = chassis_dn + '/blade-' + opts[:blade].to_s
|
409
|
+
found = configResolveDn( :dn => dn)
|
410
|
+
else
|
411
|
+
configResolveChildren( :classId => classId, :inDn => chassis_dn )
|
412
|
+
end
|
413
|
+
else
|
414
|
+
found = configResolveClass( :classId => classId)
|
415
|
+
end
|
416
|
+
|
417
|
+
@log.info("chassis ended")
|
418
|
+
found
|
419
|
+
end
|
420
|
+
|
421
|
+
#Adapter pattern method to make finding PSUs easier
|
422
|
+
#Returns an *Array* of found objects
|
423
|
+
#The logic works like this:
|
424
|
+
#* You can just provide a dn, we just get that and we're done
|
425
|
+
#* You can provide *either* a :chassis or a :fabric, but not both
|
426
|
+
#* If you only provide a :chassis we get all that :chassis's PSUs \
|
427
|
+
# or you can provide a :chassis and a :psu, which is like a full dn
|
428
|
+
#* If you only provide a :fabric we get all that :fabric's PSUs
|
429
|
+
# or you can provide a :fabric and a :psu, which is like a full dn
|
430
|
+
#* If you provide nothing, we get all PSUs
|
431
|
+
def psu(opts={})
|
432
|
+
@log.info("psu started")
|
433
|
+
|
434
|
+
classId = 'equipmentPsu'
|
435
|
+
|
436
|
+
if opts[:dn]
|
437
|
+
found = configResolveDn( :dn => opts[:dn] )
|
438
|
+
elsif opts[:chassis] and opts[:fabric]
|
439
|
+
@log.error("Only provide either :chassis => number OR :fabric => A|B")
|
440
|
+
elsif opts[:chassis] or opts[:fabric]
|
441
|
+
found = Array.new
|
442
|
+
if opts[:chassis]
|
443
|
+
chassis_dn = 'sys/chassis-' + opts[:chassis].to_s
|
444
|
+
if opts[:psu]
|
445
|
+
full_dn = chassis_dn + '/psu-' + opts[:psu].to_s
|
446
|
+
found = configResolveDn( :inDn => full_dn )
|
447
|
+
else
|
448
|
+
found = configResolveChildren( :classId => classId, :inDn => chassis_dn )
|
449
|
+
end
|
450
|
+
elsif opts[:fabric]
|
451
|
+
fabric_dn = 'sys/switch-' + opts[:fabric].to_s
|
452
|
+
if opts[:psu]
|
453
|
+
full_dn = fabric_dn + '/psu-' + opts[:psu].to_s
|
454
|
+
found = configResolveDn( :inDn => full_dn )
|
455
|
+
else
|
456
|
+
found = configResolveChildren( :classId => classId, :inDn => fabric_dn )
|
457
|
+
end
|
458
|
+
end
|
459
|
+
else
|
460
|
+
found = configResolveClass( :classId => classId)
|
461
|
+
end
|
462
|
+
|
463
|
+
@log.info("psu ended")
|
464
|
+
found
|
465
|
+
end
|
466
|
+
|
467
|
+
#Adapter pattern method to make finding Fans easier
|
468
|
+
#Returns an *Array* of found objects
|
469
|
+
#The logic works like this:
|
470
|
+
#* You can just provide a dn, we just get that and we're done
|
471
|
+
#* You can provide *either* a :chassis or a :fabric, but not both
|
472
|
+
#* If you provide a :chassis you have to provide a :module
|
473
|
+
#* If you provide no parameters, we get all fans
|
474
|
+
def fan(opts={})
|
475
|
+
@log.info("fan started")
|
476
|
+
|
477
|
+
classId = 'equipmentFan'
|
478
|
+
|
479
|
+
if opts[:dn]
|
480
|
+
found = configResolveDn( :dn => opts[:dn] )
|
481
|
+
elsif opts[:chassis] and opts[:fabric]
|
482
|
+
@log.error("Only provide either :chassis => number OR :fabric => A|B")
|
483
|
+
elsif opts[:chassis] or opts[:fabric]
|
484
|
+
found = Array.new
|
485
|
+
if opts[:chassis]
|
486
|
+
chassis_dn = 'sys/chassis-' + opts[:chassis].to_s
|
487
|
+
if opts[:module]
|
488
|
+
module_dn = chassis_dn + '/fan-module-' + opts[:module]
|
489
|
+
if opts[:fan]
|
490
|
+
full_dn = module_dn + '/fan-' + opts[:fan].to_s
|
491
|
+
found = configResolveDn( :inDn => full_dn )
|
492
|
+
else
|
493
|
+
found = configResolveChildren( :classId => classId, :inDn => module_dn )
|
494
|
+
end
|
495
|
+
else
|
496
|
+
@log.error "UCSM.fan Missing :module parameter"
|
497
|
+
end
|
498
|
+
elsif opts[:fabric]
|
499
|
+
fabric_dn = 'sys/switch-' + opts[:fabric].to_s
|
500
|
+
if opts[:fan]
|
501
|
+
full_dn = fabric_dn + '/fan-' + opts[:fan].to_s
|
502
|
+
found = configResolveDn( :inDn => full_dn )
|
503
|
+
else
|
504
|
+
found = configResolveChildren( :classId => classId, :inDn => fabric_dn )
|
505
|
+
end
|
506
|
+
end
|
507
|
+
else
|
508
|
+
found = configResolveClass( :classId => classId)
|
509
|
+
end
|
510
|
+
|
511
|
+
@log.info("fan ended")
|
512
|
+
found
|
513
|
+
end
|
514
|
+
|
515
|
+
def configResolveClasses
|
516
|
+
@log.error("Not implemented yet")
|
517
|
+
end
|
518
|
+
|
519
|
+
def configFindDnsByClassId
|
520
|
+
@log.error("Not implemented yet")
|
521
|
+
end
|
522
|
+
|
523
|
+
def configResolveParent
|
524
|
+
@log.error("Not implemented yet")
|
525
|
+
end
|
526
|
+
|
527
|
+
def help
|
528
|
+
@log.error("Not implemented yet")
|
529
|
+
end
|
530
|
+
|
531
|
+
def usage
|
532
|
+
@log.error("Not implemented yet")
|
533
|
+
end
|
534
|
+
|
535
|
+
def man
|
536
|
+
@log.error("Not implemented yet")
|
537
|
+
end
|
538
|
+
|
539
|
+
end
|
540
|
+
|
541
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/UCSAPI.rb'}"
|
9
|
+
puts "Loading UCSAPI gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_UCSAPI.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: UCSAPI
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Steve Chambers
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-01 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rubygems-update
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rest-client
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rubyforge
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 7
|
58
|
+
segments:
|
59
|
+
- 2
|
60
|
+
- 0
|
61
|
+
- 4
|
62
|
+
version: 2.0.4
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: hoe
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 19
|
74
|
+
segments:
|
75
|
+
- 2
|
76
|
+
- 6
|
77
|
+
- 2
|
78
|
+
version: 2.6.2
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
description: A simple ruby interface to the Cisco UCS XMLAPI
|
82
|
+
email:
|
83
|
+
- stevie_chambers @nospam@ viewyonder.com
|
84
|
+
executables: []
|
85
|
+
|
86
|
+
extensions: []
|
87
|
+
|
88
|
+
extra_rdoc_files:
|
89
|
+
- History.txt
|
90
|
+
- Manifest.txt
|
91
|
+
- PostInstall.txt
|
92
|
+
files:
|
93
|
+
- History.txt
|
94
|
+
- Manifest.txt
|
95
|
+
- PostInstall.txt
|
96
|
+
- Rakefile
|
97
|
+
- lib/UCSAPI.rb
|
98
|
+
- script/console
|
99
|
+
- script/destroy
|
100
|
+
- script/generate
|
101
|
+
- test/test_UCSAPI.rb
|
102
|
+
- test/test_helper.rb
|
103
|
+
has_rdoc: true
|
104
|
+
homepage: http://ciscoucs.rubyforge.org
|
105
|
+
licenses: []
|
106
|
+
|
107
|
+
post_install_message: PostInstall.txt
|
108
|
+
rdoc_options:
|
109
|
+
- --main
|
110
|
+
- README.rdoc
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
131
|
+
requirements: []
|
132
|
+
|
133
|
+
rubyforge_project: ciscoucs
|
134
|
+
rubygems_version: 1.3.7
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: Simple Ruby interface to the UCS XMLAPI
|
138
|
+
test_files:
|
139
|
+
- test/test_helper.rb
|
140
|
+
- test/test_UCSAPI.rb
|