UCSAPI 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|