acirb 1.0.4h
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/acirb/aaa.rb +1477 -0
- data/lib/acirb/ac.rb +133 -0
- data/lib/acirb/action.rb +533 -0
- data/lib/acirb/actrl.rb +1269 -0
- data/lib/acirb/actrlcap.rb +37 -0
- data/lib/acirb/adcom.rb +421 -0
- data/lib/acirb/aib.rb +85 -0
- data/lib/acirb/arp.rb +309 -0
- data/lib/acirb/bfd.rb +245 -0
- data/lib/acirb/bgp.rb +1109 -0
- data/lib/acirb/callhome.rb +373 -0
- data/lib/acirb/cap.rb +101 -0
- data/lib/acirb/cdp.rb +325 -0
- data/lib/acirb/cnw.rb +101 -0
- data/lib/acirb/comm.rb +2981 -0
- data/lib/acirb/comp.rb +3285 -0
- data/lib/acirb/compat.rb +613 -0
- data/lib/acirb/condition.rb +213 -0
- data/lib/acirb/config.rb +261 -0
- data/lib/acirb/coop.rb +709 -0
- data/lib/acirb/copp.rb +645 -0
- data/lib/acirb/ctrlr.rb +37 -0
- data/lib/acirb/ctx.rb +101 -0
- data/lib/acirb/datetime.rb +389 -0
- data/lib/acirb/dbg.rb +1397 -0
- data/lib/acirb/dbgac.rb +757 -0
- data/lib/acirb/dbgexp.rb +661 -0
- data/lib/acirb/dhcp.rb +1141 -0
- data/lib/acirb/dhcptlv.rb +133 -0
- data/lib/acirb/dhcptlvpol.rb +133 -0
- data/lib/acirb/dlgt.rb +21 -0
- data/lib/acirb/dns.rb +293 -0
- data/lib/acirb/draw.rb +37 -0
- data/lib/acirb/edr.rb +85 -0
- data/lib/acirb/eigrp.rb +789 -0
- data/lib/acirb/ep.rb +69 -0
- data/lib/acirb/epm.rb +133 -0
- data/lib/acirb/eptrk.rb +117 -0
- data/lib/acirb/eqpt.rb +6405 -0
- data/lib/acirb/eqptcap.rb +197 -0
- data/lib/acirb/eqptcapacity.rb +4069 -0
- data/lib/acirb/eqptdiag.rb +181 -0
- data/lib/acirb/eqptdiagp.rb +981 -0
- data/lib/acirb/ethpm.rb +309 -0
- data/lib/acirb/event.rb +197 -0
- data/lib/acirb/extnw.rb +181 -0
- data/lib/acirb/fabric.rb +6693 -0
- data/lib/acirb/fault.rb +821 -0
- data/lib/acirb/file.rb +149 -0
- data/lib/acirb/firmware.rb +645 -0
- data/lib/acirb/fmcast.rb +101 -0
- data/lib/acirb/frmwrk.rb +277 -0
- data/lib/acirb/fsm.rb +21 -0
- data/lib/acirb/fv.rb +6901 -0
- data/lib/acirb/fvcap.rb +37 -0
- data/lib/acirb/fvns.rb +533 -0
- data/lib/acirb/fvtopo.rb +85 -0
- data/lib/acirb/geo.rb +133 -0
- data/lib/acirb/glean.rb +85 -0
- data/lib/acirb/ha.rb +21 -0
- data/lib/acirb/health.rb +341 -0
- data/lib/acirb/hvs.rb +357 -0
- data/lib/acirb/icmp.rb +69 -0
- data/lib/acirb/icmpv4.rb +69 -0
- data/lib/acirb/icmpv6.rb +85 -0
- data/lib/acirb/ident.rb +693 -0
- data/lib/acirb/igmp.rb +69 -0
- data/lib/acirb/igmpsnoop.rb +293 -0
- data/lib/acirb/im.rb +117 -0
- data/lib/acirb/imginstall.rb +21 -0
- data/lib/acirb/infra.rb +3893 -0
- data/lib/acirb/ip.rb +389 -0
- data/lib/acirb/ipmcsnoop.rb +293 -0
- data/lib/acirb/ipv4.rb +133 -0
- data/lib/acirb/ipv6.rb +149 -0
- data/lib/acirb/isis.rb +1653 -0
- data/lib/acirb/isistlv.rb +133 -0
- data/lib/acirb/l1.rb +741 -0
- data/lib/acirb/l1cap.rb +37 -0
- data/lib/acirb/l2.rb +2437 -0
- data/lib/acirb/l2cap.rb +37 -0
- data/lib/acirb/l2ext.rb +309 -0
- data/lib/acirb/l3.rb +613 -0
- data/lib/acirb/l3cap.rb +37 -0
- data/lib/acirb/l3ext.rb +949 -0
- data/lib/acirb/l3vm.rb +53 -0
- data/lib/acirb/l4.rb +53 -0
- data/lib/acirb/lacp.rb +293 -0
- data/lib/acirb/lbp.rb +37 -0
- data/lib/acirb/leqpt.rb +117 -0
- data/lib/acirb/lldp.rb +469 -0
- data/lib/acirb/lldptlv.rb +133 -0
- data/lib/acirb/lldptlvpol.rb +133 -0
- data/lib/acirb/maint.rb +549 -0
- data/lib/acirb/mcast.rb +53 -0
- data/lib/acirb/mcp.rb +245 -0
- data/lib/acirb/memory.rb +293 -0
- data/lib/acirb/mgmt.rb +805 -0
- data/lib/acirb/mldsnoop.rb +261 -0
- data/lib/acirb/mo.rb +53 -0
- data/lib/acirb/mock.rb +69 -0
- data/lib/acirb/mon.rb +645 -0
- data/lib/acirb/monitor.rb +149 -0
- data/lib/acirb/naming.rb +37 -0
- data/lib/acirb/nd.rb +405 -0
- data/lib/acirb/nw.rb +629 -0
- data/lib/acirb/nws.rb +117 -0
- data/lib/acirb/oam.rb +53 -0
- data/lib/acirb/observer.rb +69 -0
- data/lib/acirb/opflex.rb +2693 -0
- data/lib/acirb/os.rb +37 -0
- data/lib/acirb/ospf.rb +1317 -0
- data/lib/acirb/ospfv3.rb +501 -0
- data/lib/acirb/pc.rb +181 -0
- data/lib/acirb/pcons.rb +677 -0
- data/lib/acirb/phys.rb +37 -0
- data/lib/acirb/ping.rb +101 -0
- data/lib/acirb/pki.rb +245 -0
- data/lib/acirb/pol.rb +1413 -0
- data/lib/acirb/policer.rb +37 -0
- data/lib/acirb/pool.rb +101 -0
- data/lib/acirb/pres.rb +309 -0
- data/lib/acirb/proc.rb +2085 -0
- data/lib/acirb/psu.rb +69 -0
- data/lib/acirb/qos.rb +453 -0
- data/lib/acirb/qosm.rb +645 -0
- data/lib/acirb/qosp.rb +181 -0
- data/lib/acirb/rbqm.rb +149 -0
- data/lib/acirb/regress.rb +21 -0
- data/lib/acirb/reln.rb +421 -0
- data/lib/acirb/repl.rb +69 -0
- data/lib/acirb/res.rb +197 -0
- data/lib/acirb/rib.rb +149 -0
- data/lib/acirb/rmon.rb +165 -0
- data/lib/acirb/rpm.rb +21 -0
- data/lib/acirb/rtcom.rb +53 -0
- data/lib/acirb/rtctrl.rb +949 -0
- data/lib/acirb/rtextcom.rb +69 -0
- data/lib/acirb/rtflt.rb +53 -0
- data/lib/acirb/rtleak.rb +101 -0
- data/lib/acirb/rtmap.rb +517 -0
- data/lib/acirb/rtpfx.rb +85 -0
- data/lib/acirb/rtregcom.rb +69 -0
- data/lib/acirb/rtsum.rb +21 -0
- data/lib/acirb/rule.rb +69 -0
- data/lib/acirb/satm.rb +101 -0
- data/lib/acirb/snmp.rb +549 -0
- data/lib/acirb/span.rb +1349 -0
- data/lib/acirb/stats.rb +501 -0
- data/lib/acirb/statstore.rb +69 -0
- data/lib/acirb/stormctrl.rb +53 -0
- data/lib/acirb/stp.rb +453 -0
- data/lib/acirb/sts.rb +725 -0
- data/lib/acirb/svccore.rb +133 -0
- data/lib/acirb/svi.rb +53 -0
- data/lib/acirb/synthetic.rb +709 -0
- data/lib/acirb/sysdebug.rb +293 -0
- data/lib/acirb/sysfile.rb +69 -0
- data/lib/acirb/syshist.rb +69 -0
- data/lib/acirb/syslog.rb +229 -0
- data/lib/acirb/sysmgr.rb +69 -0
- data/lib/acirb/sysmgrp.rb +37 -0
- data/lib/acirb/tag.rb +197 -0
- data/lib/acirb/task.rb +53 -0
- data/lib/acirb/test.rb +53 -0
- data/lib/acirb/testinfralab.rb +133 -0
- data/lib/acirb/tlv.rb +165 -0
- data/lib/acirb/top.rb +261 -0
- data/lib/acirb/topoctrl.rb +149 -0
- data/lib/acirb/traceroute.rb +181 -0
- data/lib/acirb/traceroutep.rb +197 -0
- data/lib/acirb/trig.rb +485 -0
- data/lib/acirb/troubleshoot.rb +133 -0
- data/lib/acirb/tunnel.rb +181 -0
- data/lib/acirb/uribv4.rb +133 -0
- data/lib/acirb/uribv6.rb +101 -0
- data/lib/acirb/vlan.rb +85 -0
- data/lib/acirb/vlanmgr.rb +37 -0
- data/lib/acirb/vmm.rb +805 -0
- data/lib/acirb/vns.rb +6853 -0
- data/lib/acirb/vpc.rb +229 -0
- data/lib/acirb/vsvc.rb +69 -0
- data/lib/acirb/vtap.rb +37 -0
- data/lib/acirb/vxlan.rb +69 -0
- data/lib/acirb/vz.rb +2325 -0
- data/lib/acirb.rb +12 -0
- data/lib/autoloadmap.rb +6372 -0
- data/lib/events.rb +27 -0
- data/lib/loader.rb +85 -0
- data/lib/logging.rb +22 -0
- data/lib/lookup.rb +6377 -0
- data/lib/mo.rb +203 -0
- data/lib/naming.rb +124 -0
- data/lib/query.rb +69 -0
- data/lib/restclient.rb +198 -0
- data/lib/version.rb +3 -0
- metadata +301 -0
data/lib/mo.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'restclient'
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
# rubocop:disable ClassLength
|
6
|
+
module ACIrb
|
7
|
+
# A generic managed object class
|
8
|
+
class MO
|
9
|
+
# Class variable properties
|
10
|
+
class << self
|
11
|
+
# for class variables
|
12
|
+
attr_reader :prefix, :class_name, :child_classes, :props,
|
13
|
+
:naming_props, :prefixes, :ruby_class, :containers
|
14
|
+
end
|
15
|
+
|
16
|
+
# for instance variables
|
17
|
+
attr_reader :children, :attributes
|
18
|
+
attr_accessor :parent
|
19
|
+
|
20
|
+
def prefixes
|
21
|
+
self.class.prefixes
|
22
|
+
end
|
23
|
+
|
24
|
+
def child_classes
|
25
|
+
self.class.child_classes
|
26
|
+
end
|
27
|
+
|
28
|
+
def containers
|
29
|
+
self.class.containers
|
30
|
+
end
|
31
|
+
|
32
|
+
def naming_props
|
33
|
+
self.class.naming_props
|
34
|
+
end
|
35
|
+
|
36
|
+
def props
|
37
|
+
self.class.props
|
38
|
+
end
|
39
|
+
|
40
|
+
def class_name
|
41
|
+
self.class.class_name
|
42
|
+
end
|
43
|
+
|
44
|
+
def ruby_class
|
45
|
+
self.class.ruby_class
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(create_parent, create_attr = {})
|
49
|
+
@attributes = {}
|
50
|
+
props.each do |prop|
|
51
|
+
@attributes[prop.to_s] = ''
|
52
|
+
end
|
53
|
+
@children = []
|
54
|
+
|
55
|
+
if create_parent.nil?
|
56
|
+
@parent = nil
|
57
|
+
else
|
58
|
+
@parent = create_parent
|
59
|
+
@parent.add_child(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
# for performance reasons, do not use set_prop here
|
63
|
+
# and build the dn string after all attributes are set
|
64
|
+
create_attr.each do |k, v|
|
65
|
+
@attributes[k.to_s] = v
|
66
|
+
end
|
67
|
+
@attributes['dn'] = build_dn
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_child(child)
|
71
|
+
unless child.containers.include?(ruby_class)
|
72
|
+
fail child.class.to_s + ' cannot be child of ' + self.class.to_s
|
73
|
+
end
|
74
|
+
@children.each do |mo|
|
75
|
+
return nil if mo.dn == child.dn
|
76
|
+
end
|
77
|
+
@children.push(child)
|
78
|
+
child.parent = self
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_prop(key, val)
|
82
|
+
key = key.to_s
|
83
|
+
val = val.to_s
|
84
|
+
return if key == 'dn' || key == 'rn'
|
85
|
+
@attributes[key] = val
|
86
|
+
if naming_props.include? key
|
87
|
+
dn_str = build_dn
|
88
|
+
@attributes['dn'] = dn_str
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def root
|
93
|
+
p = self
|
94
|
+
p = p.parent until p.parent.nil?
|
95
|
+
p
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_xml
|
99
|
+
# TODO: Use nokogiri here
|
100
|
+
# https://github.com/sparklemotion/nokogiri/wiki/Cheat-sheet
|
101
|
+
x = REXML::Element.new mo_type.to_s
|
102
|
+
@attributes.each do |key, value|
|
103
|
+
x.attributes[key.to_s] = value if value.to_s != ''
|
104
|
+
end
|
105
|
+
@children.each do |child|
|
106
|
+
x.add_element(child.to_xml)
|
107
|
+
end
|
108
|
+
x
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_hash
|
112
|
+
h = {}
|
113
|
+
h[mo_type.to_s] = {}
|
114
|
+
h[mo_type.to_s]['attributes'] = @attributes
|
115
|
+
h[mo_type.to_s]['attributes']['dn'] = dn
|
116
|
+
h[mo_type.to_s]['children'] = [] if children.length > 0
|
117
|
+
@children.each do |child|
|
118
|
+
h[mo_type.to_s]['children'].push(child.to_hash)
|
119
|
+
end
|
120
|
+
h
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_json
|
124
|
+
JSON.dump(to_hash)
|
125
|
+
end
|
126
|
+
|
127
|
+
def create(restclient)
|
128
|
+
@attributes['status'] = 'created,modified'
|
129
|
+
restclient.post(data: self,
|
130
|
+
url: "/api/mo/#{dn}.#{restclient.format}")
|
131
|
+
end
|
132
|
+
|
133
|
+
def destroy(restclient)
|
134
|
+
@attributes['status'] = 'deleted'
|
135
|
+
restclient.post(data: self,
|
136
|
+
url: "/api/mo/#{dn}.#{restclient.format}")
|
137
|
+
end
|
138
|
+
|
139
|
+
def exists(restclient, recurse = false)
|
140
|
+
options = {}
|
141
|
+
options[:subtree] = 'full' if recurse
|
142
|
+
if restclient.lookupByDn(dn, options)
|
143
|
+
if recurse == true
|
144
|
+
children.each do |child|
|
145
|
+
unless child.exists(restclient, recurse = true)
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
return true
|
151
|
+
else
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def build_dn
|
157
|
+
if @parent.nil?
|
158
|
+
return rn
|
159
|
+
else
|
160
|
+
parent_dn = '' << @parent.dn
|
161
|
+
if parent_dn == ''
|
162
|
+
return rn
|
163
|
+
else
|
164
|
+
parent_dn << '/'
|
165
|
+
parent_dn << rn
|
166
|
+
return parent_dn
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def mo_type
|
172
|
+
self.class.class_name.delete('.')
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_s
|
176
|
+
def hash_to_table(h)
|
177
|
+
len = h.keys.map(&:length).max
|
178
|
+
ret = []
|
179
|
+
h.each do |k, v|
|
180
|
+
ret.push(('%' + len.to_s + 's: %s') % [k.to_s, v.to_s])
|
181
|
+
end
|
182
|
+
ret
|
183
|
+
end
|
184
|
+
header_table = hash_to_table(
|
185
|
+
'Class' => class_name,
|
186
|
+
)
|
187
|
+
attribute_table = hash_to_table(attributes)
|
188
|
+
header_table.push(attribute_table)
|
189
|
+
header_table.join("\n")
|
190
|
+
end
|
191
|
+
|
192
|
+
def method_missing(name, *args, &block)
|
193
|
+
lookup_name = name.to_s
|
194
|
+
return @attributes[lookup_name] if @attributes.include? lookup_name
|
195
|
+
child_matches = []
|
196
|
+
@children.each do |child|
|
197
|
+
child_matches.push(child) if child.class.prefix.sub('-', '') == lookup_name
|
198
|
+
end
|
199
|
+
return child_matches if child_matches.length > 0
|
200
|
+
super
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
data/lib/naming.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module ACIrb
|
2
|
+
class Naming
|
3
|
+
def self.split_outside_brackets(dn_str, splitChar)
|
4
|
+
depth = 0
|
5
|
+
place = 0
|
6
|
+
last_split = 0
|
7
|
+
pieces = []
|
8
|
+
while place < dn_str.length
|
9
|
+
c = dn_str[place]
|
10
|
+
if c == '['
|
11
|
+
depth += 1
|
12
|
+
elsif c == ']'
|
13
|
+
depth -= 1
|
14
|
+
end
|
15
|
+
if depth == 0 && c == splitChar && place != 0
|
16
|
+
pieces.push(dn_str[last_split..place])
|
17
|
+
last_split = place + 1
|
18
|
+
end
|
19
|
+
place += 1
|
20
|
+
end
|
21
|
+
pieces.push(dn_str[last_split..place - 1]) if place != last_split
|
22
|
+
|
23
|
+
pieces
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.strip_last_delimiter(str, delim)
|
27
|
+
if str[-1] == delim
|
28
|
+
return str[0..-2]
|
29
|
+
else
|
30
|
+
return str
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.strip_outer_brackets(str)
|
35
|
+
if str[0] == '[' && str[-1] == ']'
|
36
|
+
return str[1..-2]
|
37
|
+
else
|
38
|
+
return str
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.split_dn_str(dn_str)
|
43
|
+
rns = []
|
44
|
+
split_outside_brackets(dn_str, '/').each do |rn|
|
45
|
+
rns.push(strip_last_delimiter(rn, '/'))
|
46
|
+
end
|
47
|
+
rns
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.split_rn_str(rn_str, delims)
|
51
|
+
rn_pieces = []
|
52
|
+
delims.each_with_index do |(delim, _has_prop), index|
|
53
|
+
begin_delim = rn_str.split(delim)
|
54
|
+
|
55
|
+
if index == delims.length - 1
|
56
|
+
name_prop = begin_delim[1]
|
57
|
+
else
|
58
|
+
rn_str = begin_delim[1]
|
59
|
+
end_delim = rn_str.split(delims[index + 1][0])
|
60
|
+
name_prop = end_delim[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
rn_pieces.push(delim)
|
64
|
+
rn_pieces.push(name_prop)
|
65
|
+
end
|
66
|
+
rn_pieces
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.get_mo_from_dn(dn_str)
|
70
|
+
rns = split_dn_str(dn_str)
|
71
|
+
mo = ACIrb::TopRoot.new(nil)
|
72
|
+
rns.each do |rn|
|
73
|
+
mo = get_mo_from_rn(mo, rn)
|
74
|
+
end
|
75
|
+
mo
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.get_mo_from_rn(parent_mo, rn_str)
|
79
|
+
mo = get_class_from_child_prefix(parent_mo, rn_str).new(parent_mo)
|
80
|
+
return mo if mo.naming_props.length == 0
|
81
|
+
rn_pieces = split_rn_str(rn_str, mo.prefixes)
|
82
|
+
rn_values = rn_pieces.values_at(*(1..rn_pieces.length - 1).step(2))
|
83
|
+
mo.naming_props.each_with_index do |prop_name, index|
|
84
|
+
prop_val = rn_values[index]
|
85
|
+
mo.set_prop(prop_name.to_s, strip_outer_brackets(prop_val))
|
86
|
+
end
|
87
|
+
mo
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.match_prefix_in_list(rn_str, prefix_list)
|
91
|
+
matches = false
|
92
|
+
prefix_match = ''
|
93
|
+
prefix_list.each do |prefix|
|
94
|
+
if rn_str.start_with?(prefix)
|
95
|
+
matches = true
|
96
|
+
prefix_match = prefix
|
97
|
+
break
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
return prefix_match if matches
|
102
|
+
|
103
|
+
return nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.get_class_from_child_prefix(parent_mo, rn_str)
|
107
|
+
prefix_to_class = {}
|
108
|
+
parent_mo.child_classes.each do |c|
|
109
|
+
cls = ACIrb.const_get(c)
|
110
|
+
prefix_to_class[cls.prefix] = cls
|
111
|
+
end
|
112
|
+
|
113
|
+
lpm = prefix_to_class.keys.sort_by { |x| -1 * x.length }
|
114
|
+
prefix_match = match_prefix_in_list(rn_str, lpm)
|
115
|
+
|
116
|
+
if prefix_match
|
117
|
+
return prefix_to_class[prefix_match]
|
118
|
+
else
|
119
|
+
fail 'Unknown child prefix ' + rn_str + ' in container class ' +
|
120
|
+
parent_mo.class.to_s
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/query.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'restclient'
|
2
|
+
|
3
|
+
# rubocop:disable ClassLength
|
4
|
+
# rubocop:disable FormatString
|
5
|
+
module ACIrb
|
6
|
+
# Generic Query Interface
|
7
|
+
class Query
|
8
|
+
attr_accessor :subtree, :class_filter, :query_target, :subtree_class_filter,
|
9
|
+
:prop_filter, :subtree_prop_filter, :subtree_include,
|
10
|
+
:page_size, :include_prop, :subscribe, :sort_order
|
11
|
+
|
12
|
+
def make_options
|
13
|
+
query_params = []
|
14
|
+
|
15
|
+
query_params.push('rsp-subtree=%s' % @subtree) \
|
16
|
+
if @subtree
|
17
|
+
query_params.push('target-subtree-class=%s' % @class_filter) \
|
18
|
+
if @class_filter
|
19
|
+
query_params.push('query-target=%s' % @query_target) \
|
20
|
+
if @query_target
|
21
|
+
query_params.push('rsp-subtree-class=%s' % @subtree_class_filter) \
|
22
|
+
if @subtree_class_filter
|
23
|
+
query_params.push('query-target-filter=%s' % @prop_filter) \
|
24
|
+
if @prop_filter
|
25
|
+
query_params.push('rsp-subtree-filter=%s' % @subtree_prop_filter) \
|
26
|
+
if @subtree_prop_filter
|
27
|
+
query_params.push('rsp-subtree-include=%s' % @subtree_include) \
|
28
|
+
if @subtree_include
|
29
|
+
query_params.push('page-size=%s' % @page_size) \
|
30
|
+
if @page_size
|
31
|
+
query_params.push('order-by=%s' % @sort_order) \
|
32
|
+
if @sort_order
|
33
|
+
query_params.push('rsp-prop-include=%s' % @include_prop) \
|
34
|
+
if @include_prop
|
35
|
+
query_params.push('subscription=yes') \
|
36
|
+
if @subscribe
|
37
|
+
|
38
|
+
if query_params.length > 0
|
39
|
+
'?' + query_params.join('&')
|
40
|
+
else
|
41
|
+
''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Dn Query
|
47
|
+
class DnQuery < Query
|
48
|
+
attr_accessor :dn
|
49
|
+
def initialize(dn)
|
50
|
+
@dn = dn
|
51
|
+
end
|
52
|
+
|
53
|
+
def uri(format)
|
54
|
+
'/api/mo/%s.%s%s' % [@dn, format, make_options]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Class Query
|
59
|
+
class ClassQuery < Query
|
60
|
+
attr_accessor :cls
|
61
|
+
def initialize(cls)
|
62
|
+
@cls = cls
|
63
|
+
end
|
64
|
+
|
65
|
+
def uri(format)
|
66
|
+
'/api/class/%s.%s%s' % [@cls, format, make_options]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/restclient.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'httpclient'
|
2
|
+
require 'openssl'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'json'
|
5
|
+
# require 'uri'
|
6
|
+
|
7
|
+
# rubocop:disable ClassLength
|
8
|
+
module ACIrb
|
9
|
+
# REST client end point implementation
|
10
|
+
|
11
|
+
class RestClient
|
12
|
+
attr_accessor :format, :user, :password, :baseurl, :debug, :refresh_time
|
13
|
+
attr_reader :auth_cookie
|
14
|
+
# Desc: initialize a rest client
|
15
|
+
# Returns: does not return anything, but will raise an exception
|
16
|
+
# if authentication fails
|
17
|
+
# Parameters: accepts a hash of options:
|
18
|
+
# url : string. URL of APIC
|
19
|
+
# user : string. User ID for authentication
|
20
|
+
# password : string. Password for authentication
|
21
|
+
# debug : true or false. Flag for enabling verbose REST output
|
22
|
+
# format : 'xml' or 'json'. Defaults to xml
|
23
|
+
# verify : true or false. verify the SSL certificate. Defaults to disabled
|
24
|
+
def initialize(options = {})
|
25
|
+
uri = URI.parse(options[:url])
|
26
|
+
@baseurl = '%s://%s' % [uri.scheme, uri.host]
|
27
|
+
@format = options[:format] ? options[:format] : 'xml'
|
28
|
+
|
29
|
+
@user = options[:user]
|
30
|
+
@password = options[:password]
|
31
|
+
|
32
|
+
@client = HTTPClient.new
|
33
|
+
|
34
|
+
@client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE \
|
35
|
+
unless options[:verify] && uri.scheme == 'https'
|
36
|
+
|
37
|
+
@debug = options[:debug]
|
38
|
+
|
39
|
+
@auth_cookie = ''
|
40
|
+
|
41
|
+
authenticate if @user && @password
|
42
|
+
end
|
43
|
+
|
44
|
+
# Desc: authenticates the REST session with the APIC and receives an
|
45
|
+
# auth_cookie/token
|
46
|
+
# Returns: does not return anything, but will raise an exception if
|
47
|
+
# authentication fails
|
48
|
+
# Parameters: does not accept any parameters
|
49
|
+
def authenticate
|
50
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
51
|
+
xml.aaaUser(name: @user, pwd: @password)
|
52
|
+
end
|
53
|
+
post_url = URI.encode(@baseurl.to_s + '/api/mo/aaaLogin.xml')
|
54
|
+
puts 'POST REQUEST', post_url if @debug
|
55
|
+
puts 'POST BODY', builder.to_xml if @debug
|
56
|
+
response = @client.post(post_url, body: builder.to_xml)
|
57
|
+
puts 'POST RESPONSE: ', response.body if @debug
|
58
|
+
doc = Nokogiri::XML(response.body)
|
59
|
+
fail 'Authentication error(%s): %s' % [doc.at_css('error')['code'], doc.at_css('error')['text']] \
|
60
|
+
if doc.at_css('error')
|
61
|
+
@auth_cookie = doc.at_css('aaaLogin')['token']
|
62
|
+
@refresh_time = doc.at_css('aaaLogin')['refreshTimeoutSeconds']
|
63
|
+
end
|
64
|
+
|
65
|
+
def refresh_session
|
66
|
+
get_url = URI.encode(@baseurl.to_s + '/api/mo/aaaRefresh.xml')
|
67
|
+
puts 'GET REQUEST', get_url if @debug
|
68
|
+
response = @client.get(get_url)
|
69
|
+
puts 'GET RESPONSE: ', response.body if @debug
|
70
|
+
doc = Nokogiri::XML(response.body)
|
71
|
+
fail 'Authentication error(%s): %s' % [doc.at_css('error')['code'], doc.at_css('error')['text']] \
|
72
|
+
if doc.at_css('error')
|
73
|
+
@auth_cookie = doc.at_css('aaaLogin')['token']
|
74
|
+
@refresh_time = doc.at_css('aaaLogin')['refreshTimeoutSeconds']
|
75
|
+
end
|
76
|
+
|
77
|
+
# Desc: Perform a Net::HTTP::Post to the REST interface with the
|
78
|
+
# parameters provided
|
79
|
+
# Returns: an array of managed object containing the parsed result
|
80
|
+
# Parameters: a single hash array is accepted, with the following keys:
|
81
|
+
# data : This is a string containing the data to be posted. This
|
82
|
+
# should be well formed XML that the APIC REST interface can interpret.
|
83
|
+
# No validation is done
|
84
|
+
# url : this is the path to the REST interface method being
|
85
|
+
# utilized, typicalliy /api/mo/.xml
|
86
|
+
|
87
|
+
def post(options)
|
88
|
+
post_url = URI.encode(@baseurl.to_s + options[:url].to_s)
|
89
|
+
|
90
|
+
data = options[:data]
|
91
|
+
if @format == 'xml'
|
92
|
+
data = data.to_xml
|
93
|
+
elsif @format == 'json'
|
94
|
+
data = data.to_json
|
95
|
+
end
|
96
|
+
|
97
|
+
puts 'POST REQUEST', post_url if @debug
|
98
|
+
puts 'POST BODY', data if @debug
|
99
|
+
response = @client.post(post_url, body: data)
|
100
|
+
puts 'POST RESPONSE: ', response.body if @debug
|
101
|
+
|
102
|
+
parse_response(response)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Desc: Perform a Net::HTTP::Get to the REST interface with the
|
106
|
+
# parameters provided
|
107
|
+
# Returns: an array of managed object containing the parsed result
|
108
|
+
# Parameters: a single hash array is accepted, with the following keys:
|
109
|
+
# url : this is the path to the REST interface method being utilized,
|
110
|
+
# typicalliy /api/mo/.xml with some parameters
|
111
|
+
|
112
|
+
def get(options)
|
113
|
+
get_url = URI.encode(@baseurl.to_s + options[:url].to_s)
|
114
|
+
|
115
|
+
puts 'GET REQUEST', get_url if @debug
|
116
|
+
response = @client.get(get_url)
|
117
|
+
puts 'GET RESPONSE: ', response.body if @debug
|
118
|
+
|
119
|
+
parse_response(response)
|
120
|
+
end
|
121
|
+
|
122
|
+
def parse_error(doc)
|
123
|
+
if format == 'xml'
|
124
|
+
fail 'Error response from APIC (%s): "%s"' % \
|
125
|
+
[doc.at_css('error')['code'], doc.at_css('error')['text']] \
|
126
|
+
if doc.at_css('error')
|
127
|
+
elsif format == 'json'
|
128
|
+
fail 'Error response from APIC (%s): "%s"' % \
|
129
|
+
[doc['imdata'][0]['error']['attributes']['code'].to_s, \
|
130
|
+
doc['imdata'][0]['error']['attributes']['text'].to_s] \
|
131
|
+
if doc['imdata'].length > 0 && doc['imdata'][0].include?('error')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse_response(response)
|
136
|
+
if format == 'xml'
|
137
|
+
xml_data = response.body
|
138
|
+
doc = Nokogiri::XML(xml_data)
|
139
|
+
|
140
|
+
parse_error(doc)
|
141
|
+
|
142
|
+
mos = []
|
143
|
+
doc.root.elements.each do |xml_obj|
|
144
|
+
mo = ACIrb::Loader.load_xml(xml_obj)
|
145
|
+
mos.push(mo)
|
146
|
+
end
|
147
|
+
|
148
|
+
return mos
|
149
|
+
|
150
|
+
elsif format == 'json'
|
151
|
+
json_data = response.body
|
152
|
+
doc = JSON.parse(json_data)
|
153
|
+
|
154
|
+
parse_error(doc)
|
155
|
+
|
156
|
+
mos = []
|
157
|
+
doc['imdata'].each do |json_obj|
|
158
|
+
mo = ACIrb::Loader.load_json(json_obj)
|
159
|
+
mos.push(mo)
|
160
|
+
end
|
161
|
+
|
162
|
+
return mos
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def query(query)
|
167
|
+
query_uri = query.uri(@format)
|
168
|
+
get(url: query_uri)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Desc: A helper function that will lookup a given DN via the
|
172
|
+
# APIC REST interface
|
173
|
+
# Returns: Returns Mo for match if one exists, otherwise nil
|
174
|
+
# Parameters:
|
175
|
+
# dn : string. the distinguished name to query
|
176
|
+
# options : hash. set query parameters
|
177
|
+
|
178
|
+
def lookupByDn(dn, options = {})
|
179
|
+
subtree = options[:subtree]
|
180
|
+
dn_query = ACIrb::DnQuery.new(dn)
|
181
|
+
dn_query.subtree = subtree
|
182
|
+
|
183
|
+
mos = query(dn_query)
|
184
|
+
if mos.length == 1
|
185
|
+
return mos[0]
|
186
|
+
else
|
187
|
+
return nil
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def lookupByClass(cls, options = {})
|
192
|
+
subtree = options[:subtree]
|
193
|
+
cls_query = ACIrb::ClassQuery.new(cls)
|
194
|
+
cls_query.subtree = subtree
|
195
|
+
query(cls_query)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
data/lib/version.rb
ADDED