[Python-modules-commits] [napalm-junos] 01/04: Imported Upstream version 0.2.1
Vincent Bernat
bernat at moszumanska.debian.org
Fri May 27 17:52:13 UTC 2016
This is an automated email from the git hooks/post-receive script.
bernat pushed a commit to branch master
in repository napalm-junos.
commit ee17345f8877a416c303b007683f824df9f79148
Author: Vincent Bernat <bernat at debian.org>
Date: Fri May 27 19:29:07 2016 +0200
Imported Upstream version 0.2.1
---
MANIFEST.in | 4 +
PKG-INFO | 14 +
napalm_junos.egg-info/PKG-INFO | 14 +
napalm_junos.egg-info/SOURCES.txt | 19 +
napalm_junos.egg-info/dependency_links.txt | 1 +
napalm_junos.egg-info/requires.txt | 2 +
napalm_junos.egg-info/top_level.txt | 1 +
napalm_junos/__init__.py | 16 +
napalm_junos/junos.py | 1183 ++++++++++++++++++++++++++++
napalm_junos/templates/delete_ntp_peers.j2 | 7 +
napalm_junos/templates/delete_probes.j2 | 11 +
napalm_junos/templates/schedule_probes.j2 | 0
napalm_junos/templates/set_hostname.j2 | 3 +
napalm_junos/templates/set_ntp_peers.j2 | 7 +
napalm_junos/templates/set_probes.j2 | 25 +
napalm_junos/utils/__init__.py | 1 +
napalm_junos/utils/junos_views.py | 7 +
napalm_junos/utils/junos_views.yml | 550 +++++++++++++
requirements.txt | 2 +
setup.cfg | 5 +
setup.py | 29 +
21 files changed, 1901 insertions(+)
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..566e0a0
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,4 @@
+include requirements.txt
+include napalm_junos/utils/*.yml
+include napalm_junos/templates/*.j2
+include napalm_junos/utils/textfsm_templates/*.tpl
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..c66b72d
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,14 @@
+Metadata-Version: 1.1
+Name: napalm-junos
+Version: 0.2.1
+Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
+Home-page: https://github.com/napalm-automation/napalm-junos
+Author: David Barroso
+Author-email: dbarrosop at dravetech.com
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
+Classifier: Topic :: Utilities
+Classifier: Programming Language :: Python
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: MacOS
diff --git a/napalm_junos.egg-info/PKG-INFO b/napalm_junos.egg-info/PKG-INFO
new file mode 100644
index 0000000..c66b72d
--- /dev/null
+++ b/napalm_junos.egg-info/PKG-INFO
@@ -0,0 +1,14 @@
+Metadata-Version: 1.1
+Name: napalm-junos
+Version: 0.2.1
+Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
+Home-page: https://github.com/napalm-automation/napalm-junos
+Author: David Barroso
+Author-email: dbarrosop at dravetech.com
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
+Classifier: Topic :: Utilities
+Classifier: Programming Language :: Python
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: MacOS
diff --git a/napalm_junos.egg-info/SOURCES.txt b/napalm_junos.egg-info/SOURCES.txt
new file mode 100644
index 0000000..8062c9d
--- /dev/null
+++ b/napalm_junos.egg-info/SOURCES.txt
@@ -0,0 +1,19 @@
+MANIFEST.in
+requirements.txt
+setup.py
+napalm_junos/__init__.py
+napalm_junos/junos.py
+napalm_junos.egg-info/PKG-INFO
+napalm_junos.egg-info/SOURCES.txt
+napalm_junos.egg-info/dependency_links.txt
+napalm_junos.egg-info/requires.txt
+napalm_junos.egg-info/top_level.txt
+napalm_junos/templates/delete_ntp_peers.j2
+napalm_junos/templates/delete_probes.j2
+napalm_junos/templates/schedule_probes.j2
+napalm_junos/templates/set_hostname.j2
+napalm_junos/templates/set_ntp_peers.j2
+napalm_junos/templates/set_probes.j2
+napalm_junos/utils/__init__.py
+napalm_junos/utils/junos_views.py
+napalm_junos/utils/junos_views.yml
\ No newline at end of file
diff --git a/napalm_junos.egg-info/dependency_links.txt b/napalm_junos.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/napalm_junos.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/napalm_junos.egg-info/requires.txt b/napalm_junos.egg-info/requires.txt
new file mode 100644
index 0000000..9baf4f6
--- /dev/null
+++ b/napalm_junos.egg-info/requires.txt
@@ -0,0 +1,2 @@
+napalm-base
+junos-eznc
diff --git a/napalm_junos.egg-info/top_level.txt b/napalm_junos.egg-info/top_level.txt
new file mode 100644
index 0000000..d5d0407
--- /dev/null
+++ b/napalm_junos.egg-info/top_level.txt
@@ -0,0 +1 @@
+napalm_junos
diff --git a/napalm_junos/__init__.py b/napalm_junos/__init__.py
new file mode 100644
index 0000000..d6e7728
--- /dev/null
+++ b/napalm_junos/__init__.py
@@ -0,0 +1,16 @@
+# Copyright 2016 Dravetech AB. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may 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.
+
+"""napalm_iosxr package."""
+from junos import JunOSDriver
diff --git a/napalm_junos/junos.py b/napalm_junos/junos.py
new file mode 100644
index 0000000..e6d291c
--- /dev/null
+++ b/napalm_junos/junos.py
@@ -0,0 +1,1183 @@
+# Copyright 2015 Spotify AB. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may 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.
+
+import re
+import collections
+from lxml.builder import E
+
+from napalm_junos.utils import junos_views
+from napalm_base.base import NetworkDriver
+
+from jnpr.junos import Device
+from jnpr.junos.utils.config import Config
+from jnpr.junos.exception import ConfigLoadError, ConnectTimeoutError
+from napalm_base.exceptions import ConnectionException, ReplaceConfigException, MergeConfigException,\
+ CommandErrorException
+
+from napalm_base.utils import string_parsers
+
+
+class JunOSDriver(NetworkDriver):
+
+ def __init__(self, hostname, username, password, timeout=60, optional_args=None):
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+ self.timeout = timeout
+ self.config_replace = False
+ self.locked = False
+
+ if optional_args is None:
+ optional_args = {}
+ self.port = optional_args.get('port', 22)
+ self.config_lock = optional_args.get('config_lock', True)
+
+ self.device = Device(hostname, user=username, password=password, port=self.port)
+
+ def open(self):
+ try:
+ self.device.open()
+ except ConnectTimeoutError as cte:
+ raise ConnectionException(cte.message)
+ self.device.timeout = self.timeout
+ self.device.bind(cu=Config)
+ if self.config_lock:
+ self.lock()
+
+ def close(self):
+ if self.config_lock:
+ self.unlock()
+ self.device.close()
+
+ def lock(self):
+ if not self.locked:
+ self.device.cu.lock()
+ self.locked = True
+
+ def unlock(self):
+ if self.locked:
+ self.device.cu.unlock()
+ self.locked = False
+
+ def _load_candidate(self, filename, config, overwrite):
+ if filename is None:
+ configuration = config
+ else:
+ with open(filename) as f:
+ configuration = f.read()
+
+ if not self.config_lock:
+ # if not locked during connection time
+ # will try to lock it if not already aquired
+ self.lock()
+ # and the device will be locked till first commit/rollback
+
+ try:
+ self.device.cu.load(configuration, format='text', overwrite=overwrite)
+ except ConfigLoadError as e:
+ if self.config_replace:
+ raise ReplaceConfigException(e.message)
+ else:
+ raise MergeConfigException(e.message)
+
+ def load_replace_candidate(self, filename=None, config=None):
+ self.config_replace = True
+ self._load_candidate(filename, config, True)
+
+ def load_merge_candidate(self, filename=None, config=None):
+ self.config_replace = False
+ self._load_candidate(filename, config, False)
+
+ def compare_config(self):
+ diff = self.device.cu.diff()
+
+ if diff is None:
+ return ''
+ else:
+ return diff.strip()
+
+ def commit_config(self):
+ self.device.cu.commit()
+ if not self.config_lock:
+ self.unlock()
+
+ def discard_config(self):
+ self.device.cu.rollback(rb_id=0)
+ if not self.config_lock:
+ self.unlock()
+
+ def rollback(self):
+ self.device.cu.rollback(rb_id=1)
+ self.commit_config()
+
+
+ # perhaps both should be moved in napalm_base.helpers at some point
+ @staticmethod
+ def _find_txt(xml_tree, path, default = ''):
+ try:
+ return xml_tree.find(path).text.strip()
+ except Exception:
+ return default
+
+
+ @staticmethod
+ def _convert(to, who, default = u''):
+ if who is None:
+ return default
+ try:
+ return to(who)
+ except:
+ return default
+
+
+ def get_facts(self):
+
+ output = self.device.facts
+
+ uptime = 0
+ if 'RE0' in output:
+ uptime = output['RE0']['up_time']
+
+ interfaces = junos_views.junos_iface_table(self.device)
+ interfaces.get()
+ interface_list = interfaces.keys()
+
+ return {
+ 'vendor': u'Juniper',
+ 'model': unicode(output['model']),
+ 'serial_number': unicode(output['serialnumber']),
+ 'os_version': unicode(output['version']),
+ 'hostname': unicode(output['hostname']),
+ 'fqdn': unicode(output['fqdn']),
+ 'uptime': string_parsers.convert_uptime_string_seconds(uptime),
+ 'interface_list': interface_list
+ }
+
+ def get_interfaces(self):
+
+ # init result dict
+ result = {}
+
+ interfaces = junos_views.junos_iface_table(self.device)
+ interfaces.get()
+
+ # convert all the tuples to our pre-defined dict structure
+ for iface in interfaces.keys():
+ result[iface] = {
+ 'is_up': interfaces[iface]['is_up'],
+ 'is_enabled': interfaces[iface]['is_enabled'],
+ 'description': (interfaces[iface]['description'] or u''),
+ 'last_flapped': float((interfaces[iface]['last_flapped'] or -1)),
+ 'mac_address': unicode((interfaces[iface]['mac_address'] or '')),
+ 'speed': -1
+ }
+ # result[iface]['last_flapped'] = float(result[iface]['last_flapped'])
+
+ match = re.search(r'(\d+)(\w*)', interfaces[iface]['speed'] or u'')
+ if match is None:
+ continue
+ speed_value = self._convert(int, match.group(1), -1)
+ if speed_value == -1:
+ continue
+ speed_unit = match.group(2)
+ if speed_unit.lower() == 'gbps':
+ speed_value *= 1000
+ result[iface]['speed'] = speed_value
+
+ return result
+
+ def get_interfaces_counters(self):
+ query = junos_views.junos_iface_counter_table(self.device)
+ query.get()
+ interface_counters = dict()
+ for interface, counters in query.items():
+ interface_counters[interface] = {k: v if v is not None else -1 for k, v in counters}
+ return interface_counters
+
+ def get_environment(self):
+ environment = junos_views.junos_enviroment_table(self.device)
+ routing_engine = junos_views.junos_routing_engine_table(self.device)
+ temperature_thresholds = junos_views.junos_temperature_thresholds(self.device)
+ environment.get()
+ routing_engine.get()
+ temperature_thresholds.get()
+ environment_data = dict()
+
+ for sensor_object, object_data in environment.items():
+ structured_object_data = {k: v for k, v in object_data}
+
+ if structured_object_data['class'] == 'Power':
+ # Create a dict for the 'power' key
+ try:
+ environment_data['power'][sensor_object] = dict()
+ except KeyError:
+ environment_data['power'] = dict()
+ environment_data['power'][sensor_object] = dict()
+
+ # Set these values to -1, because Junos does not provide them
+ environment_data['power'][sensor_object]['capacity'] = -1.0
+ environment_data['power'][sensor_object]['output'] = -1.0
+
+ if structured_object_data['class'] == 'Fans':
+ # Create a dict for the 'fans' key
+ try:
+ environment_data['fans'][sensor_object] = dict()
+ except KeyError:
+ environment_data['fans'] = dict()
+ environment_data['fans'][sensor_object] = dict()
+
+ if structured_object_data['status'] == 'OK' and structured_object_data['class'] == 'Power':
+ # If status is Failed, Absent or Testing, set status to False.
+ environment_data['power'][sensor_object]['status'] = True
+
+ elif structured_object_data['status'] != 'OK' and structured_object_data['class'] == 'Power':
+ environment_data['power'][sensor_object]['status'] = False
+
+ elif structured_object_data['status'] == 'OK' and structured_object_data['class'] == 'Fans':
+ # If status is Failed, Absent or Testing, set status to False.
+ environment_data['fans'][sensor_object]['status'] = True
+
+ elif structured_object_data['status'] != 'OK' and structured_object_data['class'] == 'Fans':
+ environment_data['fans'][sensor_object]['status'] = False
+
+ for temperature_object, temperature_data in temperature_thresholds.items():
+ structured_temperature_data = {k: v for k, v in temperature_data}
+ if structured_object_data['class'] == 'Temp':
+ # Create a dict for the 'temperature' key
+ try:
+ environment_data['temperature'][sensor_object] = dict()
+ except KeyError:
+ environment_data['temperature'] = dict()
+ environment_data['temperature'][sensor_object] = dict()
+
+ environment_data['temperature'][sensor_object]['temperature'] = float(structured_object_data['temperature'])
+ # Set a default value (False) to the key is_critical and is_alert
+ environment_data['temperature'][sensor_object]['is_alert'] = False
+ environment_data['temperature'][sensor_object]['is_critical'] = False
+ # Check if the working temperature is equal to or higher than alerting threshold
+ if structured_temperature_data['red-alarm'] <= structured_object_data['temperature']:
+ environment_data['temperature'][sensor_object]['is_critical'] = True
+ environment_data['temperature'][sensor_object]['is_alert'] = True
+ elif structured_temperature_data['yellow-alarm'] <= structured_object_data['temperature']:
+ environment_data['temperature'][sensor_object]['is_alert'] = True
+
+ for routing_engine_object, routing_engine_data in routing_engine.items():
+ structured_routing_engine_data = {k: v for k, v in routing_engine_data}
+ # Create dicts for 'cpu' and 'memory'.
+ try:
+ environment_data['cpu'][routing_engine_object] = dict()
+ environment_data['memory'] = dict()
+ except KeyError:
+ environment_data['cpu'] = dict()
+ environment_data['cpu'][routing_engine_object] = dict()
+ environment_data['memory'] = dict()
+ # Calculate the CPU usage by using the CPU idle value.
+ environment_data['cpu'][routing_engine_object]['%usage'] = 100.0 - structured_routing_engine_data['cpu-idle']
+ try:
+ environment_data['memory']['available_ram'] = int(structured_routing_engine_data['memory-dram-size'])
+ except ValueError:
+ environment_data['memory']['available_ram'] = int(''.join(i for i in structured_routing_engine_data['memory-dram-size'] if i.isdigit()))
+ # Junos gives us RAM in %, so calculation has to be made.
+ # Sadly, bacause of this, results are not 100% accurate to the truth.
+ environment_data['memory']['used_ram'] = (environment_data['memory']['available_ram'] / 100 * structured_routing_engine_data['memory-buffer-utilization'])
+
+ return environment_data
+
+ @staticmethod
+ def _get_address_family(table):
+ """
+ Function to derive address family from a junos table name
+ :params table: The name of the routing table
+ :returns: address family
+ """
+ address_family_mapping = {
+ 'inet': 'ipv4',
+ 'inet6': 'ipv6'
+ }
+ family = table.split('.')[-2]
+ return address_family_mapping[family]
+
+ def _parse_route_stats(self, neighbor):
+ data = {}
+ if not neighbor['is_up']:
+ pass
+ elif isinstance(neighbor['tables'], list):
+ for idx, table in enumerate(neighbor['tables']):
+ family = self._get_address_family(table)
+ data[family] = {}
+ data[family]['received_prefixes'] = neighbor['received_prefixes'][idx]
+ data[family]['accepted_prefixes'] = neighbor['accepted_prefixes'][idx]
+ data[family]['sent_prefixes'] = neighbor['sent_prefixes'][idx]
+ else:
+ family = self._get_address_family(neighbor['tables'])
+ data[family] = {}
+ data[family]['received_prefixes'] = neighbor['received_prefixes']
+ data[family]['accepted_prefixes'] = neighbor['accepted_prefixes']
+ data[family]['sent_prefixes'] = neighbor['sent_prefixes']
+ return data
+
+ @staticmethod
+ def _parse_value(value):
+ if isinstance(value, basestring):
+ return unicode(value)
+ elif value is None:
+ return u''
+ else:
+ return value
+
+ def get_bgp_neighbors(self):
+ instances = junos_views.junos_route_instance_table(self.device)
+ uptime_table = junos_views.junos_bgp_uptime_table(self.device)
+ bgp_neighbors = junos_views.junos_bgp_table(self.device)
+ keys =['local_as', 'remote_as', 'is_up', 'is_enabled', 'description', 'remote_id']
+ bgp_neighbor_data = {}
+ for instance, instance_data in instances.get().items():
+ if instance.startswith('__'):
+ # junos internal instances
+ continue
+ instance_name = "global" if instance == 'master' else instance
+ bgp_neighbor_data[instance_name] = {'peers': {}}
+ for neighbor, data in bgp_neighbors.get(instance=instance).items():
+ neighbor_data = {k: v for k, v in data}
+ peer_ip = neighbor.split('+')[0]
+ if 'router_id' not in bgp_neighbor_data[instance_name]:
+ # we only need to set this once
+ bgp_neighbor_data[instance_name]['router_id'] = unicode(neighbor_data['local_id'])
+ peer = {key:self._parse_value(value) for key, value in neighbor_data.iteritems() if key in keys}
+ peer['address_family'] = self._parse_route_stats(neighbor_data)
+ bgp_neighbor_data[instance_name]['peers'][peer_ip] = peer
+ for neighbor, uptime in uptime_table.get(instance=instance).items():
+ bgp_neighbor_data[instance_name]['peers'][neighbor]['uptime'] = uptime[0][1]
+ for key in bgp_neighbor_data.keys():
+ if not bgp_neighbor_data[key]['peers']:
+ del bgp_neighbor_data[key]
+ return bgp_neighbor_data
+
+ def get_lldp_neighbors(self):
+ lldp = junos_views.junos_lldp_table(self.device)
+ lldp.get()
+
+ result = lldp.items()
+
+ neighbors = dict()
+ for neigh in result:
+ if neigh[0] not in neighbors.keys():
+ neighbors[neigh[0]] = list()
+ neighbors[neigh[0]].append({x[0]: unicode(x[1]) for x in neigh[1]})
+
+ return neighbors
+
+
+ def get_lldp_neighbors_detail(self, interface=''):
+
+ lldp_neighbors = dict()
+
+ lldp_table = junos_views.junos_lldp_neighbors_detail_table(self.device)
+ lldp_table.get()
+ interfaces = lldp_table.get().keys()
+
+ old_junos = self._convert(int, self.device.facts.get('version', '0.0').split('.')[0], '0') < 13
+
+ lldp_table.GET_RPC = 'get-lldp-interface-neighbors'
+ if old_junos:
+ lldp_table.GET_RPC = 'get-lldp-interface-neighbors-information'
+
+ for interface in interfaces:
+ if old_junos:
+ lldp_table.get(interface_name=interface)
+ else:
+ lldp_table.get(interface_device=interface)
+ for item in lldp_table:
+ if interface not in lldp_neighbors.keys():
+ lldp_neighbors[interface] = list()
+ lldp_neighbors[interface].append({
+ 'parent_interface' : item.parent_interface,
+ 'remote_port' : item.remote_port,
+ 'remote_chassis_id' : item.remote_chassis_id,
+ 'remote_port' : item.remote_port,
+ 'remote_port_description' : item.remote_port_description,
+ 'remote_system_name' : item.remote_system_name,
+ 'remote_system_description' : item.remote_system_description,
+ 'remote_system_capab' : item.remote_system_capab,
+ 'remote_system_enable_capab': item.remote_system_enable_capab
+ })
+
+ return lldp_neighbors
+
+
+ def cli(self, commands = None):
+
+ cli_output = dict()
+
+ if type(commands) is not list:
+ raise TypeError('Please enter a valid list of commands!')
+
+ for command in commands:
+ try:
+ cli_output[unicode(command)] = unicode(self.device.cli(command))
+ except Exception as e:
+ cli_output[unicode(command)] = 'Unable to execute command "{cmd}": {err}'.format(
+ cmd = command,
+ err = e
+ )
+ raise CommandErrorException(str(cli_output))
+
+ return cli_output
+
+
+ def get_bgp_config(self, group='', neighbor=''):
+
+ def update_dict(d, u): # for deep dictionary update
+ for k, v in u.iteritems():
+ if isinstance(d, collections.Mapping):
+ if isinstance(v, collections.Mapping):
+ r = update_dict(d.get(k, {}), v)
+ d[k] = r
+ else:
+ d[k] = u[k]
+ else:
+ d = {k: u[k]}
+ return d
+
+ def build_prefix_limit(**args):
+
+ """
+ This helper will transform the lements of a dictionary into nested dictionaries:
+ Example:
+
+ {
+ 'inet_unicast_limit': 500,
+ 'inet_unicast_teardown_threshold': 95,
+ 'inet_unicast_teardown_timeout': 5
+ }
+
+ becomes:
+
+ {
+ 'inet': {
+ 'unicast': {
+ 'limit': 500,
+ 'teardown': {
+ 'threshold': 95,
+ 'timeout': 5
+ }
+ }
+ }
+ }
+
+ """
+
+ prefix_limit = dict()
+
+ for key, value in args.iteritems():
+ key_levels = key.split('_')
+ length = len(key_levels)-1
+ temp_dict = {
+ key_levels[length]: value
+ }
+ for index in reversed(range(length)):
+ level = key_levels[index]
+ temp_dict = {level: temp_dict}
+ update_dict(prefix_limit, temp_dict)
+
+ return prefix_limit
+
+ _COMMON_FIELDS_DATATYPE_ = {
+ 'description': unicode,
+ 'local_address': unicode,
+ 'local_as': int,
+ 'remote_as': int,
+ 'import_policy': unicode,
+ 'export_policy': unicode,
+ 'inet_unicast_limit_prefix_limit': int,
+ 'inet_unicast_teardown_threshold_prefix_limit': int,
+ 'inet_unicast_teardown_timeout_prefix_limit': int,
+ 'inet_unicast_novalidate_prefix_limit': int,
+ 'inet_flow_limit_prefix_limit': int,
+ 'inet_flow_teardown_threshold_prefix_limit': int,
+ 'inet_flow_teardown_timeout_prefix_limit': int,
+ 'inet_flow_novalidate_prefix_limit': unicode,
+ 'inet6_unicast_limit_prefix_limit': int,
+ 'inet6_unicast_teardown_threshold_prefix_limit': int,
+ 'inet6_unicast_teardown_timeout_prefix_limit': int,
+ 'inet6_unicast_novalidate_prefix_limit': int,
+ 'inet6_flow_limit_prefix_limit': int,
+ 'inet6_flow_teardown_threshold_prefix_limit': int,
+ 'inet6_flow_teardown_timeout_prefix_limit': int,
+ 'inet6_flow_novalidate_prefix_limit': unicode,
+ }
+
+ _PEER_FIELDS_DATATYPE_MAP_ = {
+ 'group': unicode,
+ 'authentication_key': unicode,
+ 'route_reflector_client': bool,
+ 'nhs': bool
+ }
+ _PEER_FIELDS_DATATYPE_MAP_.update(
+ _COMMON_FIELDS_DATATYPE_
+ )
+
+ _GROUP_FIELDS_DATATYPE_MAP_ = {
+ 'type': unicode,
+ 'apply_groups': list,
+ 'remove_private_as': bool,
+ 'multipath': bool,
+ 'multihop_ttl': int
+ }
+ _GROUP_FIELDS_DATATYPE_MAP_.update(
+ _COMMON_FIELDS_DATATYPE_
+ )
+
+ _DATATYPE_DEFAULT_ = {
+ unicode: u'',
+ int: 0,
+ bool: False,
+ list: []
+ }
+
+ bgp_config = dict()
+
+ if group:
+ bgp = junos_views.junos_bgp_config_group_table(self.device)
+ bgp.get(group = group)
+ else:
+ bgp = junos_views.junos_bgp_config_table(self.device)
+ bgp.get()
+ neighbor = '' # if no group is set, no neighbor should be set either
+ bgp_items = bgp.items()
+
+ peers = junos_views.junos_bgp_config_peers_table(self.device)
+ peers.get() # unfortunately cannot add filters for group name of neighbor address
+ peers_items = peers.items()
+
+ bgp_neighbors = dict()
+
+ for bgp_group_neighbor in peers_items:
+ bgp_peer_address = bgp_group_neighbor[0]
+ if neighbor and bgp_peer_address != neighbor:
+ continue # if filters applied, jump over all other neighbors
+ bgp_group_details = bgp_group_neighbor[1]
+ bgp_peer_details = {
+ field: _DATATYPE_DEFAULT_.get(datatype) \
+ for field, datatype in _PEER_FIELDS_DATATYPE_MAP_.iteritems() \
+ if '_prefix_limit' not in field
+ }
+ for elem in bgp_group_details:
+ if not('_prefix_limit' not in elem[0] and elem[1] is not None):
+ continue
+ datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0])
+ default = _DATATYPE_DEFAULT_.get(datatype)
+ key = elem[0]
+ value = elem[1]
+ if key in ['export_policy', 'import_policy']:
+ if isinstance(value, list):
+ value = ' '.join(value)
+ bgp_peer_details.update({
+ key: self._convert(datatype, value, default)
+ })
+ prefix_limit_fields = dict()
+ for elem in bgp_group_details:
+ if '_prefix_limit' in elem[0] and elem[1] is not None:
+ datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0])
+ default = _DATATYPE_DEFAULT_.get(datatype)
+ prefix_limit_fields.update({
+ elem[0].replace('_prefix_limit', ''): self._convert(datatype, elem[1], default)
+ })
+ bgp_peer_details['prefix_limit'] = build_prefix_limit(**prefix_limit_fields)
+ # and all these things only because PyEZ cannto convert to a specifc datatype when retrieving config...
+ group = bgp_peer_details.pop('group')
+ if group not in bgp_neighbors.keys():
+ bgp_neighbors[group] = dict()
+ bgp_neighbors[group][bgp_peer_address] = bgp_peer_details
+ if neighbor and bgp_peer_address == neighbor:
+ break # found the desired neighbor
+
+ for bgp_group in bgp_items:
+ bgp_group_name = bgp_group[0]
+ bgp_group_details = bgp_group[1]
+ bgp_config[bgp_group_name] = {
+ field: _DATATYPE_DEFAULT_.get(datatype) \
+ for field, datatype in _GROUP_FIELDS_DATATYPE_MAP_.iteritems() \
+ if '_prefix_limit' not in field
+ }
+ for elem in bgp_group_details:
+ if not('_prefix_limit' not in elem[0] and elem[1] is not None):
+ continue
+ datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0])
+ default = _DATATYPE_DEFAULT_.get(datatype)
+ key = elem[0]
+ value = elem[1]
+ if key in ['export_policy', 'import_policy']:
+ if isinstance(value, list):
+ value = ' '.join(value)
+ bgp_config[bgp_group_name].update({
+ key: self._convert(datatype, value, default)
+ })
+ prefix_limit_fields = dict()
+ for elem in bgp_group_details:
+ if '_prefix_limit' in elem[0] and elem[1] is not None:
+ datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0])
+ default = _DATATYPE_DEFAULT_.get(datatype)
+ prefix_limit_fields.update({
+ elem[0].replace('_prefix_limit', ''): self._convert(datatype, elem[1], default)
+ })
+ bgp_config[bgp_group_name]['prefix_limit'] = build_prefix_limit(**prefix_limit_fields)
+ bgp_config[bgp_group_name]['neighbors'] = bgp_neighbors.get(bgp_group_name, {})
+
+ return bgp_config
+
+ def get_bgp_neighbors_detail(self, neighbor_address = ''):
+
+ bgp_neighbors = dict()
+
+ bgp_neighbors_table = junos_views.junos_bgp_neighbors_table(self.device)
+
+ bgp_neighbors_table.get(
+ neighbor_address = neighbor_address
+ )
+ bgp_neighbors_items = bgp_neighbors_table.items()
+
+ default_neighbor_details = {
+ 'up' : False,
+ 'local_as' : 0,
+ 'remote_as' : 0,
+ 'local_address' : u'',
+ 'routing_table' : u'',
+ 'local_address_configured' : False,
+ 'local_port' : 0,
+ 'remote_address' : u'',
+ 'remote_port' : 0,
+ 'multihop' : False,
+ 'multipath' : False,
+ 'remove_private_as' : False,
+ 'import_policy' : u'',
+ 'export_policy' : u'',
+ 'input_messages' : 0,
+ 'output_messages' : 0,
+ 'input_updates' : 0,
+ 'output_updates' : 0,
+ 'messages_queued_out' : 0,
+ 'connection_state' : u'',
+ 'previous_connection_state' : u'',
+ 'last_event' : u'',
+ 'suppress_4byte_as' : False,
+ 'local_as_prepend' : False,
+ 'holdtime' : 0,
+ 'configured_holdtime' : 0,
+ 'keepalive' : 0,
+ 'configured_keepalive' : 0,
+ 'active_prefix_count' : 0,
+ 'received_prefix_count' : 0,
+ 'accepted_prefix_count' : 0,
+ 'suppressed_prefix_count' : 0,
+ 'advertise_prefix_count' : 0,
+ 'flap_count' : 0
+ }
+
+ _OPTION_KEY_MAP_ = {
+ 'RemovePrivateAS': 'remove_private_as',
+ 'Multipath' : 'multipath',
+ 'Multihop' : 'multihop',
+ 'AddressFamily' : 'local_address_configured'
+ # 'AuthKey' : 'authentication_key_set'
+ # but other vendors do not specify if auth key is set
+ # other options:
+ # Preference, HoldTime, Ttl, LogUpDown, Refresh
+ }
+
+ for bgp_neighbor in bgp_neighbors_items:
+ remote_as = int(bgp_neighbor[0])
+ if remote_as not in bgp_neighbors.keys():
+ bgp_neighbors[remote_as] = list()
+ neighbor_details = default_neighbor_details.copy()
+ neighbor_details.update(
+ {elem[0]: elem[1] for elem in bgp_neighbor[1] if elem[1] is not None}
+ )
+ options = neighbor_details.pop('options', '')
+ if isinstance(options, str):
+ options_list = options.split()
+ for option in options_list:
+ key = _OPTION_KEY_MAP_.get(option)
+ if key is None:
+ continue
+ neighbor_details[key] = True
+ four_byte_as = neighbor_details.pop('4byte_as', 0)
+ local_address = neighbor_details.pop('local_address', '')
+ local_details = local_address.split('+')
+ neighbor_details['local_address'] = unicode(local_details[0])
+ if len(local_details) == 2:
+ neighbor_details['local_port']= int(local_details[1])
+ else:
+ neighbor_details['local_port']=179
+ neighbor_details['suppress_4byte_as'] = (remote_as != four_byte_as)
+ peer_address = neighbor_details.pop('peer_address', '')
+ remote_details = peer_address.split('+')
+ neighbor_details['remote_address'] = unicode(remote_details[0])
+ if len(remote_details) == 2:
+ neighbor_details['remote_port'] = int(remote_details[1])
+ else:
+ neighbor_details['remote_port'] = 179
+ bgp_neighbors[remote_as].append(neighbor_details)
+
+ return bgp_neighbors
+
+
+ def get_arp_table(self):
+
+ # could use ArpTable
+ # from jnpr.junos.op.phyport import ArpTable
+ # and simply use it
+ # but
+ # we need:
+ # - filters
+ # - group by VLAN ID
+ # - hostname & TTE fields as well
+
+ arp_table = list()
+
+ arp_table_raw = junos_views.junos_arp_table(self.device)
+ arp_table_raw.get()
+ arp_table_items = arp_table_raw.items()
+
+ for arp_table_entry in arp_table_items:
+ arp_entry = {
+ elem[0]: elem[1] for elem in arp_table_entry[1]
+ }
+ tte = arp_entry.pop('tte')
+ arp_entry['age'] = tte
+ # must compute age based on TTE
+ arp_table.append(arp_entry)
+
+ return arp_table
+
+ def get_ntp_peers(self):
+
+ ntp_table = junos_views.junos_ntp_peers_config_table(self.device)
+ ntp_table.get()
+
+ ntp_peers = ntp_table.items()
+
+ if not ntp_peers:
+ return {}
+
+ return {unicode(peer[0]):{} for peer in ntp_peers}
+
+ def get_ntp_stats(self):
+
+ # NTP Peers does not have XML RPC defined
+ # thus we need to retrieve raw text and parse...
+ # :(
+
+ ntp_stats = list()
+
+ REGEX = (
+ '^\s?(\+|\*|x|-)?([a-zA-Z0-9\.+-:]+)'
+ '\s+([a-zA-Z0-9\.]+)\s+([0-9]{1,2})'
+ '\s+(-|u)\s+([0-9h-]+)\s+([0-9]+)'
+ '\s+([0-9]+)\s+([0-9\.]+)\s+([0-9\.-]+)'
+ '\s+([0-9\.]+)\s?$'
+ )
+
+ ntp_assoc_output = self.device.cli('show ntp associations no-resolve')
+ ntp_assoc_output_lines = ntp_assoc_output.splitlines()
+
+ for ntp_assoc_output_line in ntp_assoc_output_lines[3:]: #except last line
+ line_search = re.search(REGEX, ntp_assoc_output_line, re.I)
+ if not line_search:
+ continue # pattern not found
+ line_groups = line_search.groups()
+ try:
+ ntp_stats.append({
+ 'remote' : unicode(line_groups[1]),
+ 'synchronized' : (line_groups[0] == '*'),
+ 'referenceid' : unicode(line_groups[2]),
+ 'stratum' : int(line_groups[3]),
+ 'type' : unicode(line_groups[4]),
+ 'when' : unicode(line_groups[5]),
+ 'hostpoll' : int(line_groups[6]),
+ 'reachability' : int(line_groups[7]),
+ 'delay' : float(line_groups[8]),
+ 'offset' : float(line_groups[9]),
+ 'jitter' : float(line_groups[10])
+ })
+ except Exception:
+ continue # jump to next line
+
+ return ntp_stats
+
+ def get_interfaces_ip(self):
+
+ interfaces_ip = dict()
+
+ interface_table = junos_views.junos_ip_interfaces_table(self.device)
+ interface_table.get()
+ interface_table_items = interface_table.items()
+
+ _FAMILY_VMAP_ = {
+ 'inet' : u'ipv4',
+ 'inet6' : u'ipv6'
+ # can add more mappings
+ }
+
+ for interface_details in interface_table_items:
+ try:
+ ip_address = interface_details[0]
+ address = unicode(ip_address.split('/')[0])
+ prefix = self._convert(int, ip_address.split('/')[-1], 0)
+ interface = unicode(interface_details[1][0][1])
+ family_raw = interface_details[1][1][1]
+ family = _FAMILY_VMAP_.get(family_raw)
+ if not family:
+ continue
+ if interface not in interfaces_ip.keys():
+ interfaces_ip[interface] = dict()
+ if family not in interfaces_ip[interface].keys():
... 1055 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/napalm-junos.git
More information about the Python-modules-commits
mailing list