-
Notifications
You must be signed in to change notification settings - Fork 4
/
util.py
780 lines (656 loc) · 32.8 KB
/
util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
# Copyright 2023 Consoli Solutions, LLC. All rights reserved.
#
# NOT BROADCOM SUPPORTED
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may also obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
:mod:`brcddb.util.util` - Utility functions for the brcddb libraries
Public Methods::
+-----------------------+---------------------------------------------------------------------------------------+
| Method | Description |
+=======================+=======================================================================================+
| ports_for_login | Returns a list of port objects associated with a list of login objects. |
+-----------------------+---------------------------------------------------------------------------------------+
| port_obj_for_wwn | Returns the port object for a switch port WWN. |
+-----------------------+---------------------------------------------------------------------------------------+
| sort_ports | Sorts a list of port objects by switch, then slot, then port number. |
+-----------------------+---------------------------------------------------------------------------------------+
| login_to_port_map | Creates a map of logins to the port where the login occured for |
| | build_login_port_map() |
+-----------------------+---------------------------------------------------------------------------------------+
| build_login_port_map | Creates a map of logins to the port where the login occured for each fabric and adds |
| | it to the fabric object |
+-----------------------+---------------------------------------------------------------------------------------+
| add_maps_groups | Adds the associated maps group to each object. Limited to port objects. Additional |
| | objects a future. |
+-----------------------+---------------------------------------------------------------------------------------+
| global_port_list | Looks through a list of fabrics for logins in a list of WWNs and returns a list of |
| | the associated port objects |
+-----------------------+---------------------------------------------------------------------------------------+
| has_alert | Determines if an alert has already been added to an object |
+-----------------------+---------------------------------------------------------------------------------------+
| parse_cli | Conditions each line read from the file of FOS commands into a list of dictionaries |
| | for use with send_zoning() |
+-----------------------+---------------------------------------------------------------------------------------+
| add_to_obj | Adds a key value pair to obj using '/' notation in the key. If the key already |
| | exists, it is overwritten. |
+-----------------------+---------------------------------------------------------------------------------------+
| get_from_obj | Returns the value associated with a key in / notation for a dict or brcddb.class |
| | object |
+-----------------------+---------------------------------------------------------------------------------------+
| zone_cli | Creates CLI commands for fabric zoning |
+-----------------------+---------------------------------------------------------------------------------------+
Version Control::
+-----------+---------------+-----------------------------------------------------------------------------------+
| Version | Last Edit | Description |
+===========+===============+===================================================================================+
| 4.0.0 | 04 Aug 2023 | Re-Launch |
+-----------+---------------+-----------------------------------------------------------------------------------+
"""
__author__ = 'Jack Consoli'
__copyright__ = 'Copyright 2023 Consoli Solutions, LLC'
__date__ = '04 August 2023'
__license__ = 'Apache License, Version 2.0'
__email__ = '[email protected]'
__maintainer__ = 'Jack Consoli'
__status__ = 'Released'
__version__ = '4.0.0'
import re
import datetime
import brcdapi.log as brcdapi_log
import brcdapi.gen_util as gen_util
import brcddb.classes.util as brcddb_class_util
import brcdapi.port as brcdapi_port
_DEBUG_FICON = False # Intended for lab use only. Few, if any, will use this to zone a FICON switch
_MAX_LINE_COUNT = 20 # Maximum number of lines before inserting a space when generating CLI
_MAX_MEM = 3 # Maximum number of members to add to a zone object in a single FOS command (CLI)
def ports_for_login(login_list):
"""Returns a list of port objects associated with a list of login objects.
:param login_list: list of login objects, brcddb.classes.login.LoginObj
:type login_list: list, tuple
:return port_list: List of port objects, PortObj, associated with the login objects in login_list
:rtype: list
"""
# If it's a SIM port, the WWN is in the name server but not 'neighbor' so check before tyring to append
return [login_obj.r_port_obj() for login_obj in login_list if login_obj.r_port_obj() is not None]
def port_obj_for_wwn(objx, wwn):
"""Returns the port object for a switch port WWN.
Programmers Tip: The need to know a port WWN is rare. Although the key for all other objects is the WWN, with
ports I used the port number because virtual ports do not have a WWN and may not have an index. Furthermore, the WWN
for the switch port is not prevalent. The only time I needed to associate a port object with a port WWN is with
E-Ports because the neighbor in that case is the port WWN of the port in the ISLed switch.
This method is extremely inefficient but since E-Port look up in this manner is infrequent, it's good enough. If you
find yourself in a situation where you need to look up a port object from a port WWN often, you should build a
table, similar to brcddb_project.build_xref(), for efficient look ups.
:param objx: A brcddb class object that has a method port_objects()
:type objx: ProjectObj, FabricObj, SwitchObj, ChassisObj
:param wwn: WWN of a switch port
:type wwn: str
:return: Port Object. None if not found
:rtype: brcddb.classes.port.PortObj, None
"""
for port_obj in objx.r_port_objects():
port_wwn = port_obj.r_get('wwn')
if isinstance(port_wwn, str) and port_wwn == wwn:
return port_obj
return None
def sp_port_sort(port_list):
"""Sorts a list of port objects by slot then port number. Deprecated."""
return brcdapi_port.sort_ports(port_list)
def sort_ports(port_obj_list):
"""Sorts a list of port objects by switch, then slot, then port number.
:param port_obj_list: list of PortObj objects - see PortObj - in brcddb.classes.port.PortObj
:type port_obj_list: list
:return return_list: Sorted list of port objects from obj_list
:rtype: list
"""
rl = list()
if len(port_obj_list) == 0:
return rl
proj_obj = port_obj_list[0].r_project_obj() # Assume the same project for all ports
# Use wd below to sort the port objects by the switch they belong to
wd = dict()
for port_obj in port_obj_list:
switch_obj = port_obj.r_switch_obj()
switch_key = switch_obj.r_get('brocade-fibrechannel-switch/fibrechannel-switch/user-friendly-name')
if switch_key is None:
switch_key = switch_obj.r_get('brocade-fabric/fabric-switch/switch-user-friendly-name')
if switch_key is None:
switch_key = ''
switch_key += '_' + switch_obj.r_obj_key()
switch_d = wd.get(switch_key)
if switch_d is None:
switch_d = dict(switch_obj=switch_obj, port_obj_l=list())
wd.update({switch_key: switch_d})
switch_d['port_obj_l'].append(port_obj)
# Sort the switch keys
switch_key_l = list(wd.keys())
switch_key_l.sort()
# Sort the ports on a per switch basis and add to the return list
for switch_d in [wd[k] for k in switch_key_l]:
switch_obj = switch_d['switch_obj']
rl.extend([switch_obj.r_port_obj(port) for port in \
brcdapi_port.sort_ports([port_obj.r_obj_key() for port_obj in switch_d['port_obj_l']])] )
return rl
def login_to_port_map(fab_obj):
"""Creates a map of logins to the port where the login occured for build_login_port_map()
:param fab_obj: Fabric Object
:type fab_obj: brcddb.classes.fabric.FabricObj
:return port_to_wwn_d: Dictionary - key: login WWN, value: port object
:rtype port_to_wwn_d: dict
:return base_l: List of NPIV base port logins
:rtype base_l: list
"""
base_l, port_to_wwn_d = list(), dict()
for port_obj in fab_obj.r_port_objects():
nl = list(port_obj.r_login_keys())
if len(nl) > 1:
base_l.append(nl[0])
for wwn in nl:
port_to_wwn_d.update({wwn: port_obj})
return port_to_wwn_d, base_l
def build_login_port_map(proj_obj):
"""Creates a map of logins to the port where the login occured for each fabric and adds it to the fabric object
:param proj_obj: Project Object
:type proj_obj: brcddb.classes.project.ProjectObj
"""
for fab_obj in proj_obj.r_fabric_objects():
fab_obj.s_base_logins(None) # None clears the base logins
fab_obj.s_port_map(None) # None clears the port map
port_map, base_logins = login_to_port_map(fab_obj) # Get a fresh base login and port map
fab_obj.s_port_map(port_map)
fab_obj.s_base_logins(base_logins)
# Case statements for add_maps_groups()
def _fc_port(switch_obj, group):
"""Adds the MAPS group to the port
:param switch_obj: Switch object
:type switch_obj: brcddb.classes.switch.SwitchObj
:param group: MAPS group
:type group: dict
"""
try:
name = group['name']
for port in gen_util.convert_to_list(group['members']['member']):
port_obj = switch_obj.r_port_obj(port)
if port_obj is not None:
port_obj.s_add_maps_fc_port_group(name)
except (TypeError, KeyError):
return
def _sfp(switch_obj, group):
"""Adds the MAPS group to the port
:param switch_obj: Switch object
:type switch_obj: brcddb.classes.switch.SwitchObj
:param group: MAPS group
:type group: dict
"""
try:
name = group['name']
for port in gen_util.convert_to_list(group['members']['member']):
port_obj = switch_obj.r_port_obj(port)
if port_obj is not None:
port_obj.s_add_maps_sfp_group(name)
except (TypeError, KeyError):
return
def _null(switch_obj, group):
"""MAPS groups not yet implemented
:param switch_obj: Switch object
:type switch_obj: brcddb.classes.switch.SwitchObj
:param group: MAPS group
:type group: dict
"""
if isinstance(group, dict) and group.get('name') is not None:
return
brcdapi_log.exception('Invalid MAPS group', echo=True)
# Case tables used by add_maps_groups()
_maps_group_type = {
'fc-port': _fc_port,
'sfp': _sfp,
'asic': _null,
'backend-port': _null,
'fan': _null,
'chassis': _null,
'device-pid': _null,
'power-supply': _null,
'temperature-sensor': _null,
'certificate': _null,
'switch': _null,
'flow': _null,
'circuit': _null,
'circuit-qos': _null,
'DP': _null,
'ethernet-port': _null,
'ge-port': _null,
'blade': _null,
'tunnel': _null,
'tunnel-qos': _null,
'wwn': _null,
}
def add_maps_groups(proj_obj):
"""Adds the associated maps group to each object. Limited to port objects. Additional objects a future.
:param proj_obj: Project Object
:type proj_obj: brcddb.classes.project.ProjectObj
"""
for switch_obj in proj_obj.r_switch_objects():
active_rule_list = gen_util.convert_to_list(gen_util.get_key_val(switch_obj.r_active_maps_policy(),
'rule-list/rule'))
for group in gen_util.convert_to_list(switch_obj.r_get('brocade-maps/group')):
switch_obj.s_add_group(group)
for rule in gen_util.convert_to_list(switch_obj.r_get('brocade-maps/rule')):
if rule.get('name') in active_rule_list:
switch_obj.s_add_rule(rule)
for group in switch_obj.r_active_group_objects():
try:
_maps_group_type[group['group-type']](switch_obj, group)
except KeyError: # Log it, but don't pester the operator
brcdapi_log.log('Unknown group type ' + str(group.get('group-type')))
except ValueError: # Log it and let the operator know but keep chugging
buf = 'Invalid MAPS group for switch ' + switch_obj.r_obj_key() + '. group-type: ' +\
str(group.get('group-type'))
brcdapi_log.exception(buf, echo=True)
def global_port_list(fabric_objects, wwn_list):
"""Looks through a list of fabrics for logins in a list of WWNs and returns a list of the associated port objects
:param fabric_objects: List of fabric objects (brcddb.classes.fabric.FabricObj)
:type fabric_objects: list, tuple
:param wwn_list: Login WWN or list of login WWNs to find the port objects for
:type wwn_list: None, str, list, tuple
:return: List of port objects (brcddb.classes.port.PortObj)
:rtype: list
"""
port_list = list()
for fab_obj in fabric_objects:
port_list.extend([fab_obj.r_port_obj(wwn) for wwn in gen_util.convert_to_list(wwn_list)
if fab_obj.r_port_obj(wwn) is not None])
return port_list
def has_alert(obj, al_num, key, p0, p1):
"""Determines if an alert has already been added to an object
:param obj: Object
:type obj: Any object in brcddb.classes
:param al_num: Alert number
:type al_num: int
:param key: Alert key
:type key: str
:param p0: Alert parameter p0
:type p0: str, None
:param p1: Alert parameter p1
:type p1: str, None
:return: True if alert already exists in object
:rtype: bool
"""
for alert_obj in obj.r_alert_objects():
if alert_obj.alert_num() == al_num and alert_obj.key() == key and alert_obj.p0() == p0 and alert_obj.p1() == p1:
return True
return False
##################################################################
#
# Method and tables to parse CLI
#
###################################################################
# Convert CLI commands to the c-type for brcddb.apps.zone
c_type_conv = dict(
aliadd='alias-add',
alicreate='alias-create',
alidelete='alias-delete',
aliremove='alias-remove',
cfgadd='cfg-add',
cfgclear='cfg-clear',
cfgcreate='cfg-create',
cfgdelete='cfg-delete',
# cfgdisable=None, # Not supported
cfgenable='cfg-enable',
cfgremove='cfg-remove',
cfgsave='cfg-save',
defzone='defzone',
zoneadd='zone-add',
zonecleanup='zone-cleanup',
zonecreate='zone-create',
zonedelete='zone-delete',
zoneobjectcopy='zone-object-copy',
# zoneobjectexpunge=None, # Not supported
zoneobjectrename='zone-object-rename', # Not supported
# zoneobjectreplace=None, # Not supported
zoneremove='zone-remove',
)
# It's not uncommon for customers with CLI zone scripts to have show commands in the script
skip_commands = ('alishow', 'cfgactvshow', 'cfgshow', 'cfgtransshow', 'configshow', 'zoneshow')
_state_cmd = 0
_state_operand = _state_cmd + 1
_state_principal = _state_operand + 1
_state_members = _state_principal + 1
def parse_cli(file_buf):
"""Conditions each line read from the file of FOS commands into a list of dictionaries for use with send_zoning()
WARNING: This is a quick and dirty method that only works on WWN and alias zones. It will not work with d,i
Ignores all extraneous white space, comments, and null lines. Each dict contains:
+--------+------------+-----------------------------------------------------------------------------------------+
| key | Value Type | Value Description |
+========+============+=========================================================================================+
| 'c' | str | Command |
+--------+------------+-----------------------------------------------------------------------------------------+
| 'o' | str | Operand |
+--------+------------+-----------------------------------------------------------------------------------------+
| 'p0' | list | Parameters. For all zone operations, these are the members. For peer zones, these are |
| | | the principal members. |
+--------+------------+-----------------------------------------------------------------------------------------+
| 'p1' | list | Similar to 'p0'. Only used for peer zones. These are the non-principal members |
+--------+------------+-----------------------------------------------------------------------------------------+
| 'peer' | bool | If true, zone is a peer zone. |
+--------+------------+-----------------------------------------------------------------------------------------+
In order to preserve the original line numbering, values in dict are None for blank lines
:param file_buf: List of lines (str) read from input file with FOS zone commands (CLI)
:type file_buf: list
:return: List of commands parsed into the aforementioned dictionary
:rtype: list
"""
cond_input = list()
for buf in file_buf:
mod_line = buf[:buf.find('#')] if buf.find('#') >= 0 else buf
if not _DEBUG_FICON:
# Replace double quotes and commas with a space, remove all double space, and trim
# DOES NOT WORK FOR d,i ZONES
mod_line = re.sub('\\s+', ' ', mod_line.replace(',', ' ').strip())
# remove all spaces within double quotes
temp_l = mod_line.split('"')
mod_line = ''
for i in range(len(temp_l)):
if i % 2 != 0: # The odd indices are what's inside double quotes
mod_line += re.sub('\\s+', '', temp_l[i])
else:
mod_line += temp_l[i]
temp_l = mod_line.split(' ') if len(mod_line) > 0 else list()
for i in range(len(temp_l)):
temp_l[i] = temp_l[i].replace('"', '')
# flag, below, is for malformed command lines
c, o, p0, p1, peer, flag, state = None, None, None, None, False, False, _state_cmd
for p_buf in temp_l:
if state == _state_cmd:
c = p_buf
state = _state_operand
elif state == _state_operand:
if '--peer' in p_buf:
peer = True
else:
o = p_buf
state = _state_members
elif state == _state_members:
if '-members' in p_buf:
if not peer:
flag = True
break
continue
elif '-principal' in p_buf:
if not peer:
flag = True
break
state = _state_principal
else:
p0 = p_buf.split(';')
elif state == _state_principal:
p1 = p_buf.split(';')
state = _state_members
if c is None:
cond_input.append(dict())
elif c in skip_commands:
cond_input.append(dict())
elif flag:
if c in c_type_conv:
# 'malformed' will be reported as an unsupported command, but with everything else in the user error
# message, that's good enough to let the user know what's going on
cond_input.append({'c-type': 'malformed', 'operand': o, 'p0': p0, 'p1': p1, 'peer': peer})
else:
if c in c_type_conv:
cond_input.append({'c-type': c_type_conv[c], 'operand': o, 'p0': p0, 'p1': p1, 'peer': peer})
else:
cond_input.append({'c-type': c + ': Unsupported', 'operand': o, 'p0': p0, 'p1': p1, 'peer': peer})
return cond_input
def add_to_obj(obj, k, v):
"""Adds a key value pair to obj using '/' notation in the key. If the key already exists, it is overwritten.
:param obj: Dictionary or brcddb.class object the key value pair is to be added to
:type obj: dict, ProjectObj, FabricObj, SwitchObj, AliasObj, ChassisObj, PortObj, AliasObj, ZoneObj, ZoneCfgObj
:param k: The key
:type k: str
:param v: Value associated with the key.
:type v: int, str, list, dict
"""
global error_asserted
if not isinstance(k, str):
brcdapi_log.exception('Invalid key. Expected type str, received type ' + str(type(k)), echo=True)
error_asserted = True
return
key_list = k.split('/')
if isinstance(obj, dict):
if len(key_list) == 1:
obj.update({k: v})
return
key = key_list.pop(0)
d = obj.get(key)
if d is None:
d = dict()
obj.update({key: d})
add_to_obj(d, '/'.join(key_list), v)
elif brcddb_class_util.get_simple_class_type(obj) is None:
brcdapi_log.exception('Invalid object type: ' + str(type(obj)) + '. k = ' + k + ', v type: ' + str(type(v)),
echo=True)
error_asserted = True
else:
key = key_list.pop(0)
if len(key_list) == 0:
obj.s_new_key(key, v, f=True)
return
r_obj = obj.r_get(key)
if r_obj is None:
r_obj = dict()
obj.s_new_key(key, r_obj)
add_to_obj(r_obj, '/'.join(key_list), v)
def get_from_obj(obj, k):
"""Returns the value associated with a key in / notation for a dict or brcddb.class object
:param obj: Dictionary the key is for
:type obj: dict
:param k: The key
:type k: str
:return: Value associated with the key. None is returned if the key was not found
:rtype: int, str, list, dict, None
"""
if isinstance(obj, dict):
return gen_util.get_from_obj(obj, k)
elif brcddb_class_util.get_simple_class_type(obj) is None:
brcdapi_log.exception('Invalid object type.', echo=True)
else:
return obj.r_get(k)
def zone_cli(fab_obj, filter_fab_obj=None):
"""Creates CLI commands for fabric zoning
:param fab_obj: Fabric object whose zoning information is to be converted to CLI
:type fab_obj: brcddb.classes.fabric.FabricObj
:param filter_fab_obj: Output does not include CLI for zones in this object. Useful for zone merging.
:type filter_fab_obj: brcddb.classes.fabric.FabricObj
:return: List of CLI commands
:rtype: list
"""
global _MAX_LINE_COUNT, _MAX_MEM
buf = fab_obj.r_obj_key() if filter_fab_obj is None else filter_fab_obj.r_obj_key()
rl = ['', '# Zone CLI commands for: ' + buf]
# Aliases
filter_l = list() if filter_fab_obj is None else [str(k) for k in filter_fab_obj.r_alias_keys()]
rl.extend(['', '# Aliases'])
line_count = 0
for obj in fab_obj.r_alias_objects():
if obj.r_obj_key() in filter_l:
continue
mem_l = obj.r_members()
buf_0 = ' "' + obj.r_obj_key() + '", '
buf = 'alicreate' + buf_0
while len(mem_l) > 0:
line_count = 0 if line_count >= _MAX_LINE_COUNT else line_count + 1
if line_count == 0:
rl.append('')
x = min(len(mem_l), _MAX_MEM)
rl.append(buf + '"' + ';'.join(mem_l[0:x]) + '"')
mem_l = mem_l[x:]
buf = 'aliadd'
# Zones
filter_l = list() if filter_fab_obj is None else [str(k) for k in filter_fab_obj.r_zone_keys()]
rl.extend(['', '# Zones'])
line_count = 0
for obj in fab_obj.r_zone_objects():
if obj.r_obj_key() in filter_l:
continue
# All the regular members first
mem_l = obj.r_members()
if len(mem_l) > 0:
buf = 'zonecreate --peerzone "' + obj.r_obj_key() + '" -members ' if obj.r_is_peer() else\
'zonecreate "' + obj.r_obj_key() + '", '
while len(mem_l) > 0:
line_count = 0 if line_count >= _MAX_LINE_COUNT else line_count + 1
if line_count == 0:
rl.append('')
x = min(len(mem_l), _MAX_MEM)
rl.append(buf + '"' + ';'.join(mem_l[0:x]) + '"')
mem_l = mem_l[x:]
buf = 'zoneadd --peerzone "' + obj.r_obj_key() + '" -members ' if obj.r_is_peer() else \
'zoneadd "' + obj.r_obj_key() + '", '
buf = 'zoneadd --peerzone "' + obj.r_obj_key() + '" -principal ' if obj.r_is_peer() else \
'zoneadd "' + obj.r_obj_key() + '", '
else:
buf = 'zonecreate --peerzone "' + obj.r_obj_key() + '" -principal ' if obj.r_is_peer() else \
'zonecreate "' + obj.r_obj_key() + '", '
# Now all the principal members
mem_l = obj.r_pmembers() # This will be empty if it's not a peer zone
while len(mem_l) > 0:
line_count = 0 if line_count >= _MAX_LINE_COUNT else line_count + 1
if line_count == 0:
rl.append('')
x = min(len(mem_l), _MAX_MEM)
rl.append(buf + '"' + ';'.join(mem_l[0:x]))
mem_l = mem_l[x:]
# Zone configurations
filter_l = list() if filter_fab_obj is None else [str(k) for k in filter_fab_obj.r_zonecfg_keys()]
filter_l.append('_effective_zone_cfg')
rl.extend(['', '# Zone configurations'])
line_count = 0
for obj in fab_obj.r_zonecfg_objects():
if obj.r_obj_key() in filter_l:
continue
buf_0 = ' "' + obj.r_obj_key() + '", '
buf = 'cfgcreate' + buf_0
mem_l = obj.r_members()
while len(mem_l) > 0:
line_count = 0 if line_count >= _MAX_LINE_COUNT else line_count + 1
if line_count == 0:
rl.append('')
x = min(len(mem_l), _MAX_MEM)
rl.append(buf + '"' + ';'.join(mem_l[0:x]) + '"')
mem_l = mem_l[x:]
buf = 'cfgadd' + buf_0
rl.append('')
return rl
_letter_to_num = dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10, k=11, l=12, m=13, n=14, o=15, p=16, q=17, r=18,
s=19, t=20, u=21, v=22, w=23, x=24, y=25, z=26) # Used in fos_to_dict()
def fos_to_dict(version_in, valid_check=True):
"""Converts a FOS version into a dictionary to be used for comparing for version numbers
+-----------+-------+-------------------------------------------------------------------------------+
| Key | Type |Description |
+===========+=======+===============================================================================+
| version | str | Same as version_in |
+-----------+-------+-------------------------------------------------------------------------------+
| major | int | In example 9.1.0b, this is 9 |
+-----------+-------+-------------------------------------------------------------------------------+
| feature | int | In example 9.1.0b, this is 1 |
+-----------+-------+-------------------------------------------------------------------------------+
| minor | int | In example 9.1.0b, this is 0 |
+-----------+-------+-------------------------------------------------------------------------------+
| bug | int | In example 9.1.0b, this is 2 (converted to a numeric for easier comparisons). |
| | | In example 9.1.0, this is 0. |
+-----------+-------+-------------------------------------------------------------------------------+
| patch | str | In example 9.1.0b, this is an empty str. In 9.1.0b_01, this is "_01" |
+-----------+-------+-------------------------------------------------------------------------------+
:param version_in: FOS version
:type version_in: str
:param valid_check: If True, creates an exception entry in the log if the version of FOS is not valid
:type valid_check: bool
:return: Dictionary as described above
:rtype dict
"""
global _letter_to_num
try:
version = version_in.lower()
if version[0] == 'v':
version = version[1:]
version_l = version.split('.')
if len(version_l[2]) > 1:
try:
bug = _letter_to_num[version_l[2][1:2]]
patch = version_l[2][2:] if len(version_l[2]) > 1 else ''
except KeyError:
bug = 0
patch = version_l[2][1:]
else:
bug = 0
patch = ''
return dict(version=str(version_in),
major=int(version_l[0]),
feature=int(version_l[1]),
minor=int(version_l[2][0:1]),
bug=bug,
patch=patch)
except (IndexError, TypeError, ValueError, AttributeError):
if valid_check:
brcdapi_log.exception(['Invalid FOS version: ' + str(version_in), 'Type: ' + str(type(version_in))],
echo=True)
return dict(version=str(version_in), major=0, feature=0, minor=0, bug=0, patch='')
###################################################################
#
# Depracated
#
###################################################################
non_decimal = gen_util.non_decimal
decimal = gen_util.decimal
zone_notes = gen_util.zone_notes
ishex = gen_util.ishex
valid_file_name = gen_util.valid_file_name
date_to_space = gen_util.date_to_space
multiplier = gen_util.multiplier
month_to_num = gen_util.month_to_num
num_to_month = gen_util.num_to_month
def remove_duplicate_space(buf):
return gen_util.remove_duplicate_space(buf)
def get_key_val(obj, keys):
return gen_util.get_key_val(obj, keys)
def sort_obj_num(obj_list, key, r=False, h=False):
return gen_util.sort_obj_num(obj_list, key, r, h)
def convert_to_list(obj):
return gen_util.convert_to_list(obj)
def remove_duplicates(obj_list):
return gen_util.remove_duplicates(obj_list)
def remove_none(obj_list):
return gen_util.remove_none(obj_list)
def is_wwn(wwn, full_check=True):
return gen_util.is_wwn(wwn, full_check)
def is_valid_zone_name(zone_name):
return gen_util.is_valid_zone_name(zone_name)
def slot_port(port):
return gen_util.slot_port(port)
def is_di(di):
return gen_util.is_di(di)
def remove_duplicate_space(buf):
return gen_util.remove_duplicate_space(buf)
def str_to_num(buf):
return gen_util.str_to_num(buf)
def paren_content(buf, p_remove=False):
return gen_util.paren_content(buf, p_remove)
def get_struct_from_obj(obj, k):
return gen_util.get_struct_from_obj(obj, k)
def resolve_multiplier(val):
return gen_util.resolve_multiplier(val)
def dBm_to_absolute(val, r=1):
return dBm_to_absolute(val, r)
def int_list_to_range(num_list):
return gen_util.int_list_to_range(num_list)
def date_to_epoch(date_time, fmt=0, utc=False):
return gen_util.date_to_epoch(date_time, fmt, utc)