[Python-modules-commits] [napalm-fortios] 01/03: Imported Upstream version 0.1.1

Vincent Bernat bernat at moszumanska.debian.org
Tue Jun 7 15:00: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-fortios.

commit 6ba1a062cf785a73e22da0c162da834dd9f0a51c
Author: Vincent Bernat <bernat at debian.org>
Date:   Tue Jun 7 16:57:45 2016 +0200

    Imported Upstream version 0.1.1
---
 MANIFEST.in                                  |   1 +
 PKG-INFO                                     |  14 +
 napalm_fortios.egg-info/PKG-INFO             |  14 +
 napalm_fortios.egg-info/SOURCES.txt          |  10 +
 napalm_fortios.egg-info/dependency_links.txt |   1 +
 napalm_fortios.egg-info/requires.txt         |   2 +
 napalm_fortios.egg-info/top_level.txt        |   1 +
 napalm_fortios/__init__.py                   |  16 ++
 napalm_fortios/fortios.py                    | 412 +++++++++++++++++++++++++++
 requirements.txt                             |   2 +
 setup.cfg                                    |   5 +
 setup.py                                     |  29 ++
 12 files changed, 507 insertions(+)

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..f9bd145
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include requirements.txt
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..1ca1980
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,14 @@
+Metadata-Version: 1.1
+Name: napalm-fortios
+Version: 0.1.1
+Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
+Home-page: https://github.com/napalm-automation/napalm-fortios
+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_fortios.egg-info/PKG-INFO b/napalm_fortios.egg-info/PKG-INFO
new file mode 100644
index 0000000..1ca1980
--- /dev/null
+++ b/napalm_fortios.egg-info/PKG-INFO
@@ -0,0 +1,14 @@
+Metadata-Version: 1.1
+Name: napalm-fortios
+Version: 0.1.1
+Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
+Home-page: https://github.com/napalm-automation/napalm-fortios
+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_fortios.egg-info/SOURCES.txt b/napalm_fortios.egg-info/SOURCES.txt
new file mode 100644
index 0000000..0dfaff4
--- /dev/null
+++ b/napalm_fortios.egg-info/SOURCES.txt
@@ -0,0 +1,10 @@
+MANIFEST.in
+requirements.txt
+setup.py
+napalm_fortios/__init__.py
+napalm_fortios/fortios.py
+napalm_fortios.egg-info/PKG-INFO
+napalm_fortios.egg-info/SOURCES.txt
+napalm_fortios.egg-info/dependency_links.txt
+napalm_fortios.egg-info/requires.txt
+napalm_fortios.egg-info/top_level.txt
\ No newline at end of file
diff --git a/napalm_fortios.egg-info/dependency_links.txt b/napalm_fortios.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/napalm_fortios.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/napalm_fortios.egg-info/requires.txt b/napalm_fortios.egg-info/requires.txt
new file mode 100644
index 0000000..29a82cd
--- /dev/null
+++ b/napalm_fortios.egg-info/requires.txt
@@ -0,0 +1,2 @@
+napalm-base
+pyFG
diff --git a/napalm_fortios.egg-info/top_level.txt b/napalm_fortios.egg-info/top_level.txt
new file mode 100644
index 0000000..5b7a1e0
--- /dev/null
+++ b/napalm_fortios.egg-info/top_level.txt
@@ -0,0 +1 @@
+napalm_fortios
diff --git a/napalm_fortios/__init__.py b/napalm_fortios/__init__.py
new file mode 100644
index 0000000..a95ba2b
--- /dev/null
+++ b/napalm_fortios/__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_fortios package."""
+from fortios import FortiOSDriver
diff --git a/napalm_fortios/fortios.py b/napalm_fortios/fortios.py
new file mode 100644
index 0000000..cf47e63
--- /dev/null
+++ b/napalm_fortios/fortios.py
@@ -0,0 +1,412 @@
+# 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
+from pyFG.fortios import FortiOS, FortiConfig, logger
+from pyFG.exceptions import FailedCommit, CommandExecutionException
+from napalm_base.base import NetworkDriver
+from napalm_base.exceptions import ReplaceConfigException, MergeConfigException
+from napalm_base.utils.string_parsers import colon_separated_string_to_dict, convert_uptime_string_seconds
+
+
+class FortiOSDriver(NetworkDriver):
+    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
+        self.hostname = hostname
+        self.username = username
+        self.password = password
+
+        if optional_args is not None:
+            self.vdom = optional_args.get('fortios_vdom', None)
+        else:
+            self.vdom = None
+
+        self.device = FortiOS(hostname, username=username, password=password, timeout=timeout, vdom=self.vdom)
+        self.config_replace = False
+
+    def open(self):
+        self.device.open()
+
+    def close(self):
+        self.device.close()
+
+    def execute_command_with_vdom(self, command, vdom=None):
+        # If the user doesn't specify a particular vdom we use the default vdom for the object.
+        vdom = vdom or self.vdom
+
+        if vdom == 'global' and self.vdom is not None:
+            # If vdom is global we go to the global vdom, execute the commands and then back to the root.
+            # There is a catch, if the device doesn't have vdoms enabled we have to execute the command in the root
+            command = 'conf global\n{command}\nend'.format(command=command)
+
+            # We skip the lines telling us that we changed vdom
+            return self.device.execute_command(command)[1:-2]
+        elif vdom not in ['global', None]:
+            # If we have a vdom we change to the vdom, execute the commands and then exit back to the root
+            command = 'conf vdom\nedit {vdom}\n{command}\nend'.format(vdom=vdom, command=command)
+
+            # We skip the lines telling us that we changed vdom
+            return self.device.execute_command(command)[3:-2]
+        else:
+            # If there is no vdom we just execute the command
+            return self.device.execute_command(command)
+
+    def get_command_with_vdom(self, cmd, separator=':', auto=False, vdom=None):
+        output = self.execute_command_with_vdom(cmd, vdom)
+
+        if auto:
+            if ':' in output[0]:
+                separator = ':'
+            elif '\t' in output[0]:
+                separator = '\t'
+            else:
+                raise Exception('Unknown separator for block:\n{}'.format(output))
+
+        return colon_separated_string_to_dict('\n'.join(output), separator)
+
+    def _load_config(self, filename, config):
+        if filename is None:
+            configuration = config
+        else:
+            with open(filename) as f:
+                configuration = f.read()
+
+        self.device.load_config(in_candidate=True, config_text=configuration)
+
+    def load_replace_candidate(self, filename=None, config=None):
+        self.config_replace = True
+
+        self.device.candidate_config = FortiConfig('candidate')
+        self.device.running_config = FortiConfig('running')
+
+        self._load_config(filename, config)
+
+        self.device.load_config(empty_candidate=True)
+
+    def load_merge_candidate(self, filename=None, config=None):
+        self.config_replace = False
+
+        self.device.candidate_config = FortiConfig('candidate')
+        self.device.running_config = FortiConfig('running')
+
+        self._load_config(filename, config)
+
+        for block in self.device.candidate_config.get_block_names():
+            try:
+                self.device.load_config(path=block, empty_candidate=True)
+            except CommandExecutionException as e:
+                raise MergeConfigException(e.message)
+
+    def compare_config(self):
+        return self.device.compare_config()
+
+    def commit_config(self):
+        try:
+            self.execute_command_with_vdom('execute backup config flash commit_with_napalm')
+            self.device.commit()
+            self.discard_config()
+        except FailedCommit as e:
+            if self.config_replace:
+                raise ReplaceConfigException(e.message)
+            else:
+                raise MergeConfigException(e.message)
+
+    def discard_config(self):
+        self.device.candidate_config = FortiConfig('candidate')
+        self.device.load_config(in_candidate=True)
+
+    def rollback(self):
+        output = self.execute_command_with_vdom('fnsysctl ls -l data2/config', vdom=None)
+        rollback_file = output[-2].split()[-1]
+        rollback_config = self.execute_command_with_vdom(
+            'fnsysctl cat data2/config/{rollback_file}'.format(rollback_file))
+
+        self.device.load_config(empty_candidate=True)
+        self.load_replace_candidate(config=rollback_config)
+        self.device.candidate_config['vpn certificate local']['Fortinet_CA_SSLProxy'].del_param('private-key')
+        self.device.candidate_config['vpn certificate local']['Fortinet_CA_SSLProxy'].del_param('certificate')
+        self.device.candidate_config['vpn certificate local']['Fortinet_SSLProxy'].del_param('private-key')
+        self.device.candidate_config['vpn certificate local']['Fortinet_SSLProxy'].del_param('certificate')
+        self.device.commit()
+
+    def get_facts(self):
+        system_status = self.get_command_with_vdom('get system status', vdom='global')
+        performance_status = self.get_command_with_vdom('get system performance status', vdom='global')
+
+        interfaces = self.execute_command_with_vdom('get system interface | grep ==', vdom='global')
+        interface_list = [x.split()[2] for x in interfaces if x.strip() is not '']
+
+        domain = self.get_command_with_vdom('get system dns | grep domain', vdom='global')['domain']
+
+        return {
+            'vendor': unicode('Fortigate'),
+            'os_version': unicode(system_status['Version'].split(',')[0].split()[1]),
+            'uptime': convert_uptime_string_seconds(performance_status['Uptime']),
+            'serial_number': unicode(system_status['Serial-Number']),
+            'model': unicode(system_status['Version'].split(',')[0].split()[0]),
+            'hostname': unicode(system_status['Hostname']),
+            'fqdn': u'{}.{}'.format(system_status['Hostname'], domain),
+            'interface_list': interface_list
+        }
+
+    @staticmethod
+    def _get_tab_separated_interfaces(output):
+        interface_statistics = {
+            'is_up': ('up' in output['State'] and 'up' or 'down'),
+            'speed': output['Speed'],
+            'mac_adddress': output['Current_HWaddr']
+        }
+        return interface_statistics
+
+    @staticmethod
+    def _get_unsupported_interfaces():
+        return {
+            'is_up': None,
+            'is_enabled': None,
+            'description': None,
+            'last_flapped': None,
+            'mode': None,
+            'speed': None,
+            'mac_address': None
+        }
+
+    def get_interfaces(self):
+        cmd_data = self.execute_command_with_vdom('diagnose hardware deviceinfo nic', vdom='global')
+
+        interface_list = [x.replace('\t', '') for x in cmd_data if x.startswith('\t')]
+        interface_statistics = {}
+        for interface in interface_list:
+            if_data = self.execute_command_with_vdom(
+                'diagnose hardware deviceinfo nic {}'.format(interface), vdom='global')
+            parsed_data = {}
+            if interface.startswith('mgmt'):
+                for line in if_data:
+                    if line.startswith('Speed'):
+                        if line.split('\t')[-1].split(' ')[0].isdigit():
+                            parsed_data['speed'] = int(line.split('\t')[-1].split(' ')[0])
+                        else:
+                            parsed_data['speed'] = -1
+                    elif line.startswith('Link'):
+                        parsed_data['is_up'] = line.split('\t')[-1] is 'up'
+                    elif line.startswith('Current_HWaddr'):
+                        parsed_data['mac_address'] = unicode(line.split('\t')[-1])
+                parsed_data['is_enabled'] = True
+                parsed_data['description'] = u''
+                parsed_data['last_flapped'] = -1.0
+            else:
+                for line in if_data:
+                    if line.startswith('Admin'):
+                        parsed_data['is_enabled'] = line.split(':')[-1] is 'up'
+                    elif line.startswith('PHY Status'):
+                        parsed_data['is_up'] = line.split(':')[-1] is 'up'
+                    elif line.startswith('PHY Speed'):
+                        parsed_data['speed'] = int(line.split(':')[-1])
+                    elif line.startswith('Current_HWaddr'):
+                        parsed_data['mac_address'] = unicode(line.split(' ')[-1])
+                parsed_data['description'] = u''
+                parsed_data['last_flapped'] = -1.0
+            interface_statistics[interface] = parsed_data
+        return interface_statistics
+
+    @staticmethod
+    def _search_line_in_lines(search, lines):
+        for l in lines:
+            if search in l:
+                return l
+
+    def get_bgp_neighbors(self):
+
+        families = ['ipv4', 'ipv6']
+        terms = dict({'accepted_prefixes': 'accepted', 'sent_prefixes': 'announced'})
+        command_sum = 'get router info bgp sum'
+        command_detail = 'get router info bgp neighbor {}'
+        command_received = 'get router info bgp neighbors {} received-routes | grep prefixes '
+        peers = dict()
+
+        bgp_sum = self.execute_command_with_vdom(command_sum)
+
+        re_neigh = re.compile("^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
+        neighbors = {n.split()[0]: n.split()[1:] for n in bgp_sum if re.match(re_neigh, n)}
+
+        self.device.load_config('router bgp')
+
+        for neighbor, parameters in neighbors.iteritems():
+            logger.debug('NEW PEER')
+            neigh_conf = self.device.running_config['router bgp']['neighbor']['{}'.format(neighbor)]
+
+            neighbor_dict = peers.get(neighbor, dict())
+
+            if not neighbor_dict:
+                neighbor_dict['local_as'] = int(bgp_sum[0].split()[7])
+                neighbor_dict['remote_as'] = int(neigh_conf.get_param('remote-as'))
+                neighbor_dict['is_up'] = 'never' != parameters[7] or False
+                neighbor_dict['is_enabled'] = neigh_conf.get_param('shutdown') != 'enable' or False
+                neighbor_dict['description'] = u''
+                neighbor_dict['uptime'] = convert_uptime_string_seconds(parameters[7])
+                neighbor_dict['address_family'] = dict()
+                neighbor_dict['address_family']['ipv4'] = dict()
+                neighbor_dict['address_family']['ipv6'] = dict()
+
+            detail_output = [x.lower() for x in self.execute_command_with_vdom(command_detail.format(neighbor))]
+            m = re.search('remote router id (.+?)\n', '\n'.join(detail_output))
+            if m:
+                neighbor_dict['remote_id'] = unicode(m.group(1))
+            else:
+                raise Exception('cannot find remote router id for %s' % neighbor)
+
+            for family in families:
+                # find block
+                x = detail_output.index(' for address family: {} unicast'.format(family))
+                block = detail_output[x:]
+
+                for term, fortiname in terms.iteritems():
+                    text = self._search_line_in_lines('%s prefixes' % fortiname, block)
+                    t = [int(s) for s in text.split() if s.isdigit()][0]
+                    neighbor_dict['address_family'][family][term] = t
+
+                received = self.execute_command_with_vdom(
+                    command_received.format(neighbor))[0].split()
+                if len(received) > 0:
+                    neighbor_dict['address_family'][family]['received_prefixes'] = received[-1]
+                else:
+                    # Soft-reconfig is not enabled
+                    neighbor_dict['address_family'][family]['received_prefixes'] = 0
+            peers[neighbor] = neighbor_dict
+
+        return {
+            'global': {
+                'router_id': unicode(bgp_sum[0].split()[3]),
+                'peers': peers
+            }
+        }
+
+    def get_interfaces_counters(self):
+        cmd = self.execute_command_with_vdom('fnsysctl ifconfig', vdom=None)
+        if_name = None
+        interface_counters = dict()
+        for line in cmd:
+            data = line.split('\t')
+            if (data[0] == '' or data[0] == ' ') and len(data) == 1:
+                continue
+            elif data[0] != '':
+                if_name = data[0]
+                interface_counters[if_name] = dict()
+            elif (data[1].startswith('RX packets') or data[1].startswith('TX packets')) and if_name:
+                if_data = data[1].split(' ')
+                direction = if_data[0].lower()
+                interface_counters[if_name][direction + '_unicast_packets'] = int(if_data[1].split(':')[1])
+                interface_counters[if_name][direction + '_errors'] = int(if_data[2].split(':')[1])
+                interface_counters[if_name][direction + '_discards'] = int(if_data[2].split(':')[1])
+                interface_counters[if_name][direction + '_multicast_packets'] = -1
+                interface_counters[if_name][direction + '_broadcast_packets'] = -1
+            elif data[1].startswith('RX bytes'):
+                if_data = data[1].split(' ')
+                interface_counters[if_name]['rx_octets'] = int(if_data[1].split(':')[1])
+                try:
+                    interface_counters[if_name]['tx_octets'] = int(if_data[6].split(':')[1])
+                except IndexError:
+                    interface_counters[if_name]['tx_octets'] = int(if_data[7].split(':')[1])
+        return interface_counters
+
+    def get_lldp_neighbors(self):
+        return {}
+
+    def get_environment(self):
+
+        def parse_string(line):
+            return re.sub(' +', ' ', line.lower())
+
+        def search_disabled(line):
+            m = re.search("(.+?) (.+?) alarm=(.+?) \(scanning disabled\)", line)
+            return m.group(2)
+
+        def search_normal(line):
+            m = re.search("(.+?) (.+?) alarm=(.+?) value=(.+?) threshold_status=(.+?)", line)
+            return m
+
+        def get_fans(fan_lines):
+            output = dict()
+            for fan_line in fan_lines:
+                if 'disabled' in fan_line:
+                    name = search_disabled(fan_line)
+                    output[name] = dict(status=False)
+                    continue
+
+                m = search_normal(fan_line)
+                output[m.group(2)] = dict(status=True)
+            return output
+
+        def get_cpu(cpu_lines):
+            output = dict()
+            for l in cpu_lines:
+                m = re.search('(.+?) states: (.+?)% user (.+?)% system (.+?)% nice (.+?)% idle', l)
+                cpuname = m.group(1)
+                idle = m.group(5)
+                output[cpuname] = {
+                    '%usage': 100.0 - int(idle)
+                }
+            return output
+
+        def get_memory(memory_line):
+            total, used = int(memory_line[1]) >> 20, int(memory_line[2]) >> 20  # convert from byte to MB
+            return dict(available_ram=total, used_ram=used)
+
+        def get_temperature(temperature_lines, detail_block):
+            output = dict()
+            for temp_line in temperature_lines:
+                if 'disabled' in temp_line:
+                    sensor_name = search_disabled(temp_line)
+                    output[sensor_name] = {'is_alert': False, 'is_critical': False, 'temperature': 0.0}
+                    continue
+
+                m = search_normal(temp_line)
+                sensor_name, temp_value, status = m.group(2), m.group(4), int(m.group(5))
+                is_alert = True if status == 1 else False
+
+                # find block
+                fullline = self._search_line_in_lines(sensor_name, detail_block)
+                index_line = detail_block.index(fullline)
+                sensor_block = detail_block[index_line:]
+
+                v = int(self._search_line_in_lines('upper_non_recoverable', sensor_block).split('=')[1])
+
+                output[sensor_name] = dict(temperature=float(temp_value), is_alert=is_alert,
+                                           is_critical=True if v > temp_value else False)
+
+            return output
+
+        out = dict()
+
+        sensors_block = [parse_string(x) for x in self.execute_command_with_vdom('execute sensor detail', vdom='global') if x]
+
+        # temp
+        temp_lines = [x for x in sensors_block if any([True for y in ['dts', 'temp', 'adt7490'] if y in x])]
+        out['temperature'] = get_temperature(temp_lines, sensors_block)
+
+        # fans
+        out['fans'] = get_fans([x for x in sensors_block if 'fan' in x and 'temp' not in x])
+
+        # cpu
+        out['cpu'] = get_cpu(
+            [x for x in self.execute_command_with_vdom('get system performance status | grep CPU', vdom='global')[1:] if x])
+
+        # memory
+        memory_command = 'diag hard sys mem | grep Mem:'
+        t = [x for x in re.split('\s+', self.execute_command_with_vdom(memory_command, vdom='global')[0]) if x]
+        out['memory'] = get_memory(t)
+
+        # power, not implemented
+        sensors = [x.split()[1] for x in sensors_block if x.split()[0].isdigit()]
+        psus = {x for x in sensors if x.startswith('ps')}
+        out['power'] = {t: {'status': True, 'capacity': -1.0, 'output': -1.0} for t in psus}
+
+        return out
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..3b4589b
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+napalm_base
+pyFG
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..99be57b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,29 @@
+"""setup.py file."""
+
+import uuid
+
+from setuptools import setup, find_packages
+from pip.req import parse_requirements
+
+__author__ = 'David Barroso <dbarrosop at dravetech.com>'
+
+install_reqs = parse_requirements('requirements.txt', session=uuid.uuid1())
+reqs = [str(ir.req) for ir in install_reqs]
+
+setup(
+    name="napalm-fortios",
+    version="0.1.1",
+    packages=find_packages(),
+    author="David Barroso",
+    author_email="dbarrosop at dravetech.com",
+    description="Network Automation and Programmability Abstraction Layer with Multivendor support",
+    classifiers=[
+        'Topic :: Utilities',
+        'Programming Language :: Python',
+        'Operating System :: POSIX :: Linux',
+        'Operating System :: MacOS',
+    ],
+    url="https://github.com/napalm-automation/napalm-fortios",
+    include_package_data=True,
+    install_requires=reqs,
+)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/napalm-fortios.git



More information about the Python-modules-commits mailing list