class ShowNtpAssociationsSchema(MetaParser): """Schema for show ntp associations""" schema = { 'peer': { Any(): { 'local_mode': { Any(): { 'remote': str, 'configured': bool, Optional('refid'): str, Optional('local_mode'): str, Optional('stratum'): int, Optional('receive_time'): Or(str, int), Optional('poll'): int, Optional('reach'): int, Optional('delay'): float, Optional('offset'): float, Optional('jitter'): float, 'mode': str, }, } }, }, 'clock_state': { 'system_status': { 'clock_state': str, Optional('clock_stratum'): int, Optional('associations_address'): str, Optional('root_delay'): float, Optional('clock_offset'): float, Optional('clock_refid'): str, Optional('associations_local_mode'): str, } }, 'vrf': { Any(): { 'address': { Any(): { 'type': { Any(): { 'address': str, 'type': str, 'vrf': str, } }, 'isconfigured': { Any(): { 'address': str, 'isconfigured': bool, } } } } } } }
class ShowMacAddressTableLearningSchema(MetaParser): """Schema for show mac address-table learning""" schema = { 'vlans': { Any(): { 'mac_learning': bool, 'vlan': Or(int, str) } } }
class ShowMacAddressTableAgingTimeSchema(MetaParser): """Schema for show mac address-table aging-time""" schema = { 'mac_aging_time': int, Optional('vlans'): { Any(): { 'mac_aging_time': int, 'vlan': Or(int, str) } } }
class ShowMPLSVLLSchema(MetaParser): """Schema for show mpls vll {vll}""" schema = { 'vll': { Any(): { 'vcid': int, 'vll_index': int, 'local': { 'type': str, 'interface': str, Optional('vlan_id'): int, Optional('inner_vlan_id'): int, Optional('outer_vlan_id'): int, 'state': str, Optional('mct_state'): str, Optional('ifl_id'): str, 'vc_type': str, 'mtu': int, 'cos': str, Optional('extended_counters'): bool, Optional('counters'): bool }, 'peer': { 'ip': str, 'state': str, Optional('reason'): str, 'vc_type': str, 'mtu': int, 'local_label': Or(int, str), 'remote_label': Or(int, str), 'local_group_id': Or(int, str), 'remote_group_id': Or(int, str), Optional('tunnel_lsp'): { 'name': str, Optional('tunnel_interface'): str }, 'lsps_assigned': str } } } }
class ShowLslibProducerAllLscacheLinksDetailSchema(MetaParser): """Schema for show lslib producer all lscache links detail""" schema = { 'link': { int: { 'protocol': str, 'identifier': str, Or('local_node_descriptor', 'remote_node_descriptor'): { Optional('as_number'): int, Optional('bgp_identifier'): str, Optional('area_id'): str, Optional('router_id'): str, Optional('iso_node_id'): str, }, 'link_descriptor': { Optional('link_id'): str, Optional('local_intf_address'): str, Optional('neighbor_intf_address'): str, Optional('multi_topology'): str, }, 'internal_flag': str, 'action': str, 'merged_link_attr': { Optional('metric'): int, Optional('admin_group'): str, Optional('max_link_bw'): int, Optional('max_reserv_link_bw'): int, Optional('max_unreserv_link_bw'): list, Optional('te_default_metric'): int, Optional('link_protection_type'): str, Optional('mpls_proto_mask'): str, Optional('opaque_link_attr'): str, Optional('link_name'): str, Optional('adj_sid'): list, Optional('lan_adj_sid'): list, Optional('srlg'): list, Optional('extended_admin_group'): str, Optional('link_delay'): int, Optional('min_delay'): int, Optional('max_delay'): int, Optional('delay_variation'): int, Optional('link_loss'): str, Optional('residual_bw'): int, Optional('available_bw'): int, Optional('utilized_bw'): int, Optional('asla'): { Optional('sabm'): str, Optional('te_default_metric'): int, }, }, }, }, }
class ShowBootSystemSchema(MetaParser): """Schema for show boot system""" schema = { 'boot_variable': str, Optional('manual_boot_variable'): str, Optional('is_manual_boot'): bool, Optional('baud'): int, Optional('ipxe_timeout'): Or(int, str), Optional('bootmode'): str, Optional('is_boot_mode'): bool, Optional('enable_break'): bool, Optional('config_file'): str, }
class ShowInterfacesBriefSchema(MetaParser): """Schema for show interfaces brief wide""" schema = { 'interfaces': { Any(): { 'link': str, 'state': str, 'speed': str, 'tag': str, 'mac': str, 'description': Or(str, None) } } }
class ShowOpticSchema(MetaParser): """Schema for show interfaces brief wide""" schema = { 'interfaces': { Any(): { 'temperature': { 'value': Or(float, str), Optional('alarm'): str }, 'tx': { 'value': Or(float, str), Optional('alarm'): str }, 'rx': { 'value': Or(float, str), Optional('alarm'): str }, 'tx_bias_current': { 'value': Or(float, str), Optional('alarm'): str } } } }
raise Exception("Cannot recover the device '{d}'\nCannot run clean".\ format(d=device.name)) else: log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) @clean_schema({ Optional('console_activity_pattern'): str, Optional('console_breakboot_char'): str, Optional('grub_activity_pattern'): str, Optional('grub_breakboot_char'): str, Optional('break_count'): int, Optional('timeout'): int, Optional('golden_image'): Or(list, { 'system': str, Optional('kickstart'): str }), Optional('tftp_boot'): { 'image': list, 'ip_address': list, 'subnet_mask': str, 'gateway': str, 'tftp_server': str }, Optional('recovery_password'): str, Optional('clear_line'): bool, Optional('powercycler'): bool, Optional('powercycler_delay'): int, Optional('reconnect_delay'): int, Optional('post_recovery_configuration'): str, })
class ShowRouteSchema(MetaParser): """Schema for * show route """ schema = { 'vrf': { 'default': { 'address_family': { 'ipv4': { Optional(Or('routes', 'tunneled_routes')): { Any(): { 'candidate_default': bool, Optional('subnet'): str, 'route': str, Optional('active'): bool, Optional('date'): str, Optional('route_preference'): int, Optional('metric'): int, Optional('source_protocol'): str, Optional('source_protocol_codes'): str, Optional('next_hop'): { Optional('outgoing_interface_name'): { Any(): { # context_name for interface if there is no next_hop Optional('outgoing_interface_name'): str }, }, Optional('next_hop_list'): { Any(): { # index Optional('index'): int, Optional('next_hop'): str, Optional('outgoing_interface_name'): str }, }, }, }, }, }, }, }, }, } """ Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2 E1 - OSPF external type 1, E2 - OSPF external type 2, V - VPN i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2 ia - IS-IS, * - candidate default, U - per-user static route o - ODR, P - periodic downloaded static route, + - replicated route SI - Static InterVRF """ source_protocol_dict = { 'O': 'ospf', 'IA': 'ospf', 'N1': 'ospf', 'N2': 'ospf', 'E1': 'ospf', 'E2': 'ospf', 'o': 'odr', 'i': 'isis', 'su': 'isis', 'L1': 'isis', 'L2': 'isis', 'ia': 'isis', 'D': 'eigrp', 'EX': 'eigrp', 'S': 'static', 'E': 'egp', 'M': 'mobile', 'L': 'local', 'C': 'connected', 'B': 'bgp', 'U': 'per-user static route', 'R': 'rip', 'I': 'igrp', '+': 'replicated route', 'V': 'VPN', 'P': 'periodic downloaded static route', 'SI': 'Static InterVRF', }
class ShowLoggingSchema(MetaParser): '''Schema for: * 'show logging' * 'show logging | include {include}' * 'show logging | exclude {exclude}' ''' schema = { Optional('logs'): list, Optional('syslog_logging'): { Any(): { # enabled 'counters': { 'messages_dropped': int, 'messages_rate_limited': int, 'flushes': int, 'overruns': int, 'xml': str, # 'disabled' 'filtering': str, # 'disabled' } } }, Optional('message_discriminator'): { Optional(Any()): { # 'Active'|'Inactive' Optional('md_name'): { Optional(Any()): { # 'C' Optional('severity_group'): { 'flag': str, # 'includes'|'drops' 'str': str, # '5' }, Optional('facility'): { 'flag': str, # 'includes'|'drops' 'regexp_str': str, # 'SYS' }, Optional('mnemonics'): { 'flag': str, # 'include'|'drops' 'regexp_str': str, # 'UPDOWN' }, Optional('msg_body'): { 'flag': str, # 'include'|'drops' 'regexp_str': str, # link }, Optional('rate_limit_not_to_exceed'): { 'rate_limit': int, # 100 } } } } }, Optional('logging'): { 'console': { 'status': str, # 'enabled'|'disabled' Optional('level'): str, Optional('messages_logged'): int, Optional('xml'): str, Optional('filtering'): str, }, 'monitor': { 'status': str, # 'enabled'|'disabled' Optional('level'): str, Optional('messages_logged'): int, Optional('xml'): str, Optional('filtering'): str, Optional('discriminator'): str, Optional('messages_rate_limited'): int, Optional('messages_dropped_by_md'): int, Optional('logging_to'): { Any(): { # '10.4.29.222' Or('vty', 'tty'): int, } } }, 'buffer': { 'status': str, # 'enabled'|'disabled' Optional('level'): str, Optional('messages_logged'): int, 'xml': str, # 'enabled'|'disabled' Optional('xml_buffer_count'): int, 'filtering': str, # 'enabled'|'disabled' Optional('buffer_count'): int, Optional('discriminator'): str, Optional('messages_rate_limited'): int, Optional('messages_dropped_by_md'): int }, 'exception': { Optional('status'): str, # 'enabled'|'disabled' Optional('size_bytes'): int, # 4096 }, 'persistent': { Optional('status'): str, # 'enabled'|'disabled' Optional('url'): str, Optional('disk_space_bytes'): int, Optional('file_size_bytes'): int, Optional('batch_size_bytes'): int, # threshold capacity 5 alert , immediate , protected , notify Optional('logging_threshold'): int, Optional('threshold_percent'): int, Optional('threshold_alert'): str, Optional('immediate_write'): str, Optional('notify'): str, Optional('protected'): str }, Optional('file'): { Optional('status'): str, # 'enabled'|'disabled' Optional('file_name'): str, Optional('max_size'): int, Optional('min_size'): int, Optional('level'): str, Optional('messages_logged'): int, }, Optional('count_and_time_stamp_logging_messages'): str, # 'enabled'|'disabled' 'trap': { Optional('status'): str, # 'enabled'|'disabled' Optional('level'): str, # 'informational' Optional('message_lines_logged'): int, # 70 Optional("logging_source_interface"): { Any(): { # Loopback0 Optional("vrf"): str # Mgmt-intf } }, Optional('logging_to'): { Any(): { # '10.4.29.222' 'protocol': str, # 'tcp'|'udp'|'unknown' 'port': int, # 1470 'audit': str, # 'disabled'|'enabled' 'link': str, # 'up'|'down' 'message_lines_logged': int, 'message_lines_rate_limited': int, 'message_lines_dropped_by_md': int, 'xml': str, # 'enabled'|'disabled' 'sequence_number': str, # 'enabled'|'disabled' 'filtering': str, # 'enabled'|'disabled' Optional('vrf'): str, Optional('logging_source_interface'): { Any(): str, # 'Vlan200': <vrf> }, } } } }, Optional('filter_modules'): { Any(): { # url 'cli_args': str, 'invalid': bool, # True|False } }, Optional('tls_profiles'): { Any(): { # 'tls-profile-name 'ciphersuites': list, # rsa-aes-cbc-sha2 ecdhe-rsa-aes-cbc-sha2 'trustpoint': str, # tls-trustpoint 'tls_version': str # TLSv1.1 | TLSv1.2 | Default } }, Optional('log_buffer_bytes'): int, # 32000 }
def validate_clean(clean_file, testbed_file, lint=True): """ Validates the clean yaml using device abstraction to collect the proper schemas Args: clean_file (str/dict): clean datafile testbed_file (str/dict): testbed datafile lint (bool, optional): Do yaml linting on the clean_file Returns: { 'warnings' ['Warning example', ...], 'exceptions: [ValueError, ...] } """ warnings = [] exceptions = [] validation_results = {'warnings': warnings, 'exceptions': exceptions} if lint: lint_messages = do_lint(clean_file) for message in lint_messages: # we want to use the str representation not the object warnings.append(str(message)) # these sections are not true stages and therefore cant be loaded sections_to_ignore = [ 'images', 'order' ] base_schema = { Optional('clean_devices'): list, 'cleaners': { Any(): { 'module': str, Optional('devices'): list, Optional('platforms'): list, Optional('groups'): list, Any(): Any() } }, 'devices': { } } try: # Load yaml without parsing markup # Mock the use validate to prevent calling functions like # translate_host or import_from_name with patch.object(PyatsUse, 'validate') as mockvalid: # return data on Use.validate mockvalid.side_effect = lambda *x, **y: x[1] loaded_tb = testbed_loader(testbed_file, locations={}, markupprocessor=TestbedMarkupProcessor( reference=True, callable=False, env_var=False, include_file=False, ask=False, encode=False)) except Exception: exceptions.append( Exception("Could not load the testbed file. Use " "'pyats validate testbed <file>' to validate " "the testbed file.") ) loaded_tb = testbed_loader({}) loader = Loader(enable_extensions=True, markupprocessor=MarkupProcessor(reference=True, callable=False, env_var=False, include_file=False, ask=False, encode=False)) try: clean_dict = loader.load(clean_file, locations={}) except Exception as e: exceptions.append(e) return validation_results loader = Loader(enable_extensions=True, markupprocessor=MarkupProcessor(reference=True, callable=False, env_var=False, include_file=False, ask=False, encode=False)) try: clean_dict = loader.load(clean_file, locations={}) except Exception as e: exceptions.append(e) return validation_results try: clean_json = load_clean_json() except Exception as e: exceptions.append(e) from genie.libs.clean.recovery import recovery_processor for dev in clean_dict.get('devices', {}): schema = base_schema.setdefault('devices', {}).setdefault(dev, {}) schema.update({Optional('order'): list}) schema.update({Optional('device_recovery'): dict}) schema.update({Optional('images'): Or(list, dict)}) clean_data = clean_dict["devices"][dev] try: dev = loaded_tb.devices[dev] except KeyError as e: warnings.append( "The device {dev} specified in the clean yaml does " "not exist in the testbed.".format(dev=e)) # cant validate schema so allow anything under dev schema.update({Any(): Any()}) continue except Exception as e: exceptions.append(e) schema.update({Any(): Any()}) continue # update stages with image if clean_data.get('images'): setattr(dev, 'clean', clean_data) try: # Get abstracted ImageHandler class abstract = Lookup.from_device(dev, packages={'clean': clean}) ImageHandler = abstract.clean.stages.image_handler.ImageHandler image_handler = ImageHandler(dev, dev.clean['images']) initialize_clean_sections(image_handler, clean_data['order']) except Exception as e: # If the device does not have custom.abstraction defined # then we cannot load the correct stages to test the # correct schema. Skip this device. exceptions.append(Exception(dev.name+': '+str(e))) schema.update({Any(): Any()}) continue for section in clean_data: # ignore sections that aren't true stages if section in sections_to_ignore: continue if section == 'device_recovery': schema.update({'device_recovery': recovery_processor.schema}) continue clean_data[section].pop('change_order_if_fail', None) clean_data[section].pop('change_order_if_pass', None) # when no data is provided under stage, change None to dict # this is needed for schema validation if clean_data[section] is None: clean_data[section] = {} # Load it up so we can grab the schema from the stage # If source isnt provided then check if it is inside the clean json try: if 'source' not in clean_data: task = get_clean_function(section, clean_json, dev) else: task = load_class(clean_data, dev) except Exception as e: # Stage cannot be found. Allow any schema to prevent schema error # and skip this stage exceptions.append(str(e)) schema.update({section: Any()}) continue # Add the stage schema to the base schema if hasattr(task, 'schema'): schema.update({task.__name__: task.schema}) try: Schema(base_schema).validate(clean_dict) except Exception as e: exceptions.append(pretty_schema_exception(e)) return validation_results
class ShowLoggingSchema(MetaParser): '''Schema for: * 'show logging' * 'show logging | include {include}' * 'show logging | exclude {exclude}' ''' schema={ Optional('logs'): list, Optional('syslog_logging'): { Any(): { # enabled 'counters': { 'messages_dropped': int, 'messages_rate_limited': int, 'flushes': int, 'overruns': int, 'xml': str, # 'disabled' 'filtering': str, # 'disabled' } } }, Optional('message_discriminator'): { Optional(Any()): { # 'Active'|'Inactive' Optional('md_name'): { Optional(Any()): { # 'C' Optional('severity_group'): { 'flag': str, # 'includes'|'drops' 'str': str, # '5' }, Optional('facility'): { 'flag': str, # 'includes'|'drops' 'regexp_str': str, # 'SYS' }, Optional('mnemonics'): { 'flag': str, # 'include'|'drops' 'regexp_str': str, # 'UPDOWN' }, Optional('msg_body'): { 'flag': str, # 'include'|'drops' 'regexp_str': str, # link }, Optional('rate_limit_not_to_exceed'): { 'rate_limit': int, # 100 } } } } }, Optional('logging'): { 'console': { 'status': str, # 'enabled'|'disabled' Optional('level'): str, Optional('messages_logged'): int, Optional('xml'): str, Optional('filtering'): str, }, 'monitor': { 'status': str, # 'enabled'|'disabled' 'level': str, 'messages_logged': int, 'xml': str, 'filtering': str, Optional('discriminator'): str, Optional('messages_rate_limited'): int, Optional('messages_dropped_by_md'): int, Optional('logging_to'): { Any(): { # '10.4.29.222' Or('vty','tty'): int, } } }, 'buffer': { 'status': str, # 'enabled'|'disabled' 'level': str, 'messages_logged': int, 'xml': str, # 'enabled'|'disabled' Optional('xml_buffer_count'): int, 'filtering': str, # 'enabled'|'disabled' Optional('buffer_count'): int, Optional('discriminator'): str, Optional('messages_rate_limited'): int, Optional('messages_dropped_by_md'): int }, 'exception': { Optional('status'): str, # 'enabled'|'disabled' 'size_bytes': int, # 4096 }, 'persistent': { Optional('status'): str, # 'enabled'|'disabled' Optional('url'): str, Optional('disk_space_bytes'): int, Optional('file_size_bytes'): int, Optional('batch_size_bytes'): int, }, Optional('file'): { Optional('status'): str, # 'enabled'|'disabled' Optional('file_name'): str, Optional('max_size'): int, Optional('min_size'): int, Optional('level'): str, Optional('messages_logged'): int, }, Optional('count_and_time_stamp_logging_messages'): str, # 'enabled'|'disabled' 'trap': { Optional('status'): str, # 'enabled'|'disabled' 'level': str, # 'informational' 'message_lines_logged': int, # 70 Optional('logging_to'): { Any(): { # '10.4.29.222' 'protocol': str, # 'tcp'|'udp'|'unknown' 'port': int, # 1470 'audit': str, # 'disabled'|'enabled' 'link': str, # 'up'|'down' 'message_lines_logged': int, 'message_lines_rate_limited': int, 'message_lines_dropped_by_md': int, 'xml': str, # 'enabled'|'disabled' 'sequence_number': str, # 'enabled'|'disabled' 'filtering': str, # 'enabled'|'disabled' Optional('logging_source_interface'): { Any(): str, # 'Vlan200': <vrf> } } } } }, Optional('filter_modules'): { Any(): { # url 'cli_args': str, 'invalid': bool, # True|False } }, Optional('log_buffer_bytes'): int, # 32000 }
class ShowAccessListsSchema(MetaParser): """Schema for show access-lists show access-lists <acl> show ip access-lists show ip access-lists <acl> show ipv6 access-list show ipv6 access-list <acl>""" schema = { Any():{ 'name': str, 'type': str, Optional('per_user'): bool, Optional('aces'): { Any(): { 'name': str, 'matches': { Optional('l2'): { 'eth': { 'destination_mac_address': str, 'source_mac_address': str, Optional('ether_type'): str, Optional('cos'): int, Optional('vlan'): int, Optional('protocol_family'): str, Optional('lsap'): str, } }, Optional('l3'): { Any(): { # protocols Optional('dscp'): str, Optional('ttl'): int, Optional('ttl_operator'): str, 'protocol': str, Optional('precedence'): str, Optional('precedence_code'): int, Optional('destination_network'): { Any(): { 'destination_network': str, } }, 'source_network': { Any(): { 'source_network': str, } } }, }, Optional('l4'): { Any(): { # protocols Optional('type'): int, Optional('code'): int, Optional('acknowledgement_number'): int, Optional('data_offset'): int, Optional('reserved'): int, Optional('flags'): str, Optional('window_size'): int, Optional('urgent_pointer'): int, Optional('options'): int, Optional('options_name'): str, Optional('established'): bool, Optional('source_port'): { Optional('range'): { 'lower_port': int, 'upper_port': int, }, Optional('operator'): { 'operator': str, 'port': str, } }, Optional('destination_port'): { Optional('range'): { 'lower_port': int, 'upper_port': int, }, Optional('operator'): { 'operator': str, 'port': int, } }, Optional('msg_type'): str, } }, }, 'actions': { 'forwarding': str, Optional('logging'): str, }, Optional('statistics'): { 'matched_packets': Or(int,str) } } } } }
def validate_clean(clean_dict, testbed_dict): """ Validates the clean yaml using device abstraction to collect the proper schemas Args: clean_dict (dict): clean datafile testbed_dict (dict): testbed datafile Returns: { 'warnings' ['Warning example', ...], 'exceptions: [ValueError, ...] } """ warnings = [] exceptions = [] validation_results = {'warnings': warnings, 'exceptions': exceptions} # these sections are not true stages and therefore cant be loaded sections_to_ignore = [ 'images', 'order' ] base_schema = { 'cleaners': { Any(): { 'module': str, Optional('devices'): list, Optional('platforms'): list, Optional('groups'): list, Any(): Any() } }, 'devices': { } } try: loaded_tb = testbed_loader(testbed_dict) except Exception: exceptions.append( Exception("Could not load the testbed file. Use " "'pyats validate testbed <file>' to validate " "the testbed file.") ) clean_json = load_clean_json() from genie.libs.clean.stages.recovery import recovery_processor for dev in clean_dict.get('devices', {}): schema = base_schema.setdefault('devices', {}).setdefault(dev, {}) schema.update({Optional('order'): list}) schema.update({Optional('device_recovery'): dict}) schema.update({Optional('images'): Or(list, dict)}) clean_data = clean_dict["devices"][dev] try: dev = loaded_tb.devices[dev] except KeyError as e: warnings.append( "The device {dev} specified in the clean yaml does " "not exist in the testbed.".format(dev=e)) # cant validate schema so allow anything under dev schema.update({Any(): Any()}) continue # update stages with image if clean_data.get('images'): setattr(dev, 'clean', clean_data) # Get abstracted ImageHandler class abstract = Lookup.from_device(dev, packages={'clean': clean}) ImageHandler = abstract.clean.stages.image_handler.ImageHandler # Image handler image_handler = ImageHandler(dev, dev.clean['images']) initialize_clean_sections(image_handler, clean_data['order']) for section in clean_data: # ignore sections that aren't true stages if section in sections_to_ignore: continue if section == 'device_recovery': schema.update({'device_recovery': recovery_processor.schema}) continue # when no data is provided under stage, change None to dict # this is needed for schema validation if clean_data[section] is None: clean_data[section] = {} # Load it up so we can grab the schema from the stage # If source isnt provided then check if it is inside the clean json if 'source' not in clean_data: task = get_clean_function(section, clean_json, dev) else: task = load_class(clean_data, dev) # Add the stage schema to the base schema if hasattr(task, 'schema'): schema.update({task.__name__: task.schema}) try: Schema(base_schema).validate(clean_dict) except Exception as e: exceptions.append(pretty_schema_exception(e)) return validation_results
log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) if tftp_boot: section.parameters['common_data']['device_tftp_booted'] = True @clean_schema({ Optional('console_activity_pattern'): str, Optional('break_count'): int, Optional('timeout'): int, Optional('golden_image'): Or(list, { 'system': str, Optional('kickstart'): str }), Optional('tftp_boot'): { 'image': list, 'ip_address': list, 'subnet_mask': str, 'gateway': str, 'tftp_server': str }, Optional('recovery_password'): str, Optional('clear_line'): bool, Optional('powercycler'): bool, Optional('powercycler_delay'):
class ShowStackPowerSchema(MetaParser): """Schema for * show stack-power * show stack-power budgeting * show stack-power detail """ schema = { 'power_stack': { Any(): { 'mode': str, 'topology': str, 'total_power': int, 'reserved_power': int, 'allocated_power': int, Optional('unused_power'): int, Optional('available_power'): int, 'switch_num': int, 'power_supply_num': int, Optional('power_stack_detail'): { 'stack_mode': str, 'stack_topology': str, 'switch': { Any(): { 'power_budget': int, 'power_allocated': int, 'low_port_priority_value': int, 'high_port_priority_value': int, 'switch_priority_value': int, 'port_1_status': str, 'port_2_status': str, 'neighbor_on_port_1': str, 'neighbor_on_port_2': str, }, }, }, Optional('switches'): { Any(): { 'power_supply_a': Or(int, float), 'power_supply_b': Or(int, float), 'power_budget': Or(int, float), 'allocated_power': Or(int, float), 'available_power': Or(int, float), 'consumed_power_sys': Or(int, float), 'consumed_power_poe': Or(int, float), }, }, }, }, Optional('totals'): { 'total_allocated_power': Or(int, float), 'total_available_power': Or(int, float), 'total_consumed_power_sys': Or(int, float), 'total_consumed_power_poe': Or(int, float), }, }