Beispiel #1
0
    def get_layered_subinterface(self, mode, add=True):
        """Instantiate a regular subinterface type from this AbstractSubinterface

        Converts an abstract subinterface to a real subinterface by offering it a mode.

        Args:
            mode (str): Mode of the subinterface ('layer3' or 'layer2')
            add (bool): Add the newly instantiated subinterface to the base interface object

        Returns:
            Subinterface: A :class:`pandevice.network.Layer3Subinterface` or
            :class:`pandevice.network.Layer2Subinterface` instance, depending on the mode argument

        """
        if self.parent is not None:
            if mode == "layer3":
                subintclass = Layer3Subinterface
            elif mode == "layer2":
                subintclass = Layer2Subinterface
            else:
                raise err.PanDeviceError(
                    "Unknown layer passed to subinterface factory: %s" % mode)
            layered_subinterface = self.parent.find(self.name, subintclass)
            # Verify tag is correct
            if layered_subinterface is not None:
                if layered_subinterface.tag != self.tag:
                    layered_subinterface.tag = self.tag
            else:
                if add:
                    layered_subinterface = self.parent.add(
                        subintclass(self.name, tag=self.tag))
                else:
                    return
            return layered_subinterface
Beispiel #2
0
 def set_zone(self,
              zone_name,
              mode=None,
              refresh=False,
              update=False,
              running_config=False):
     raise err.PanDeviceError(
         "Unable to set zone on abstract subinterface because layer must be known to set zone"
     )
 def _interface_name(self, interface):
     if issubclass(interface.__class__, basestring):
         return interface
     elif issubclass(interface.__class__, Interface):
         return interface.name
     else:
         raise err.PanDeviceError(
             "interface argument must be of type str or Interface",
             pan_device=self)
Beispiel #4
0
 def set_shared_policy_synced(self, sync_status):
     if sync_status == "In Sync":
         self.shared_policy_synced = True
     elif sync_status == "Out of Sync":
         self.shared_policy_synced = False
     elif not sync_status:
         self.shared_policy_synced = None
     else:
         raise err.PanDeviceError("Unknown shared policy status: %s" % str(sync_status))
    def refresh_interfaces(self):
        self.xapi.op('show interface "all"', cmd_xml=True)
        pconf = PanConfig(self.xapi.element_root)
        response = pconf.python()
        hw = {}
        interfaces = {}
        # Check if there is a response and result
        try:
            response = response['response']['result']
        except KeyError as e:
            raise err.PanDeviceError(
                "Error reading response while refreshing interfaces",
                pan_device=self)
        if response:
            self._logger.debug("Refresh interfaces result: %s" % response)
            # Create a hw dict with all the 'hw' info
            hw_result = response.get('hw', {})
            if hw_result is None:
                return
            hw_result = hw_result.get('entry', [])
            for hw_entry in hw_result:
                hw[hw_entry['name']] = hw_entry

            if_result = response.get('ifnet', {})
            if if_result is None:
                return
            if_result = if_result.get('entry', [])
            for entry in if_result:
                try:
                    router = entry['fwd'].split(":", 1)[1]
                except IndexError:
                    router = entry['fwd']
                interface = Interface(name=entry['name'],
                                      zone=entry['zone'],
                                      router=router,
                                      subnets=[entry['ip']],
                                      state=hw.get(entry['name'],
                                                   {}).get('state'))
                interfaces[entry['name']] = interface
        else:
            raise err.PanDeviceError("Could not refresh interfaces",
                                     pan_device=self)
        self.interfaces = interfaces
Beispiel #6
0
def interface(name, *args, **kwargs):
    """Interface object factory

    Creates an interface object of type determined by the name of the interface.

    Args:
        name (str): Name of the interface to create (eg. ethernet1/1.5)
        mode (str): Mode of the interface.
            Possible values: layer3, layer2, virtual-wire, tap, ha, aggregate-group.
            Default: None

    Keyword Args:
        tag (int): Tag for the interface, aka vlan id

    Returns:
        Interface: An instantiated subclass of :class:`pandevice.network.Interface`

    """
    name = str(name)
    if name.startswith("ethernet") and name.find(".") == -1:
        return EthernetInterface(name, *args, **kwargs)
    elif name.startswith("ae") and name.find(".") == -1:
        return AggregateInterface(name, *args, **kwargs)
    elif name.startswith("ethernet") or name.startswith("ae"):
        # Subinterface
        # Get mode from args
        args = list(args)
        if len(args) > 0:
            mode = args[0]
            del args[0]
        else:
            mode = kwargs.pop("mode", None)
        # Get tag from kwargs
        tag = kwargs.get("tag", None)
        if tag is None:
            # Determine tag from name
            tag = name.split(".")[-1]
            kwargs["tag"] = tag
        if mode == "layer3":
            return Layer3Subinterface(name, *args, **kwargs)
        elif mode == "layer2":
            return Layer2Subinterface(name, *args, **kwargs)
        else:
            return AbstractSubinterface(name, *args, **kwargs)
    elif name.startswith("vlan"):
        return VlanInterface(name, *args, **kwargs)
    elif name.startswith("loopback"):
        return LoopbackInterface(name, *args, **kwargs)
    elif name.startswith("tunnel"):
        return TunnelInterface(name, *args, **kwargs)
    else:
        raise err.PanDeviceError(
            "Can't identify interface type from name: %s" % name)
Beispiel #7
0
 def show_system_resources(self):
     self.xapi.op(cmd="show system resources", cmd_xml=True)
     result = self.xapi.xml_root()
     regex = re.compile(r"load average: ([\d.]+).* ([\d.]+)%id.*Mem:.*?([\d.]+)k total.*?([\d]+)k free", re.DOTALL)
     match = regex.search(result)
     if match:
         """
         return cpu, mem_free, load
         """
         return {
             'load': Decimal(match.group(1)),
             'cpu': 100 - Decimal(match.group(2)),
             'mem_total': int(match.group(3)),
             'mem_free': int(match.group(4)),
         }
     else:
         raise err.PanDeviceError("Problem parsing show system resources",
                                  pan_device=self)
Beispiel #8
0
    def _xpath(self):
        xpath = pandevice.XPATH_INTERFACES + "/%s" % (self.type, )

        if self.type == "ethernet":
            if self.parent:
                xpath += "/entry[@name='%s']/%s/units/entry[@name='%s']" \
                         % (self.parent.name,
                            self.parent.mode,
                            self.name)
                root = ET.Element("entry", {"name": self.name})
                settings = root
            else:
                match = re.search(r"(ethernet\d/\d{1,3})\.\d{1,4}", self.name)
                if match:
                    xpath += "/entry[@name='%s']/%s/units/entry[@name='%s']"\
                             % (match.group(1), self.mode, self.name)
                    root = ET.Element("entry", {"name": self.name})
                    settings = root
                else:
                    xpath += "/entry[@name='%s']" % (self.name, )
                    root = ET.Element("entry", {"name": self.name})
                    settings = ET.SubElement(root, self.mode)
        elif self.type == "vlan":
            xpath += "/units/entry[@name='%s']" % (self.name, )
            root = ET.Element("entry", {"name": self.name})
            settings = root
        else:
            raise err.PanDeviceError("Unknown interface type: %s" % self.type)

        # For Layer 3 interfaces, apply any subnet configuration
        if self.mode == "layer3" and self.subnets:
            node = ET.SubElement(settings, "ip")
            for subnet in self.subnets:
                ET.SubElement(node, "entry", {"name": subnet})

        # If there is a tag, apply it in the XML
        if self.tag:
            node = ET.SubElement(settings, "tag")
            node.text = self.tag

        return xpath, root
    def system_info(self, all_info=False):
        """Get system information

        Returns:
            system information like version, platform, etc.
        """

        self.xapi.op(cmd="<show><system><info></info></system></show>")
        pconf = PanConfig(self.xapi.element_result)
        system_info = pconf.python()
        self._logger.debug("Systeminfo: %s" % system_info)
        if not system_info:
            error_msg = 'Cannot detect device type, unable to get system info'
            self._logger.error(error_msg)
            raise err.PanDeviceError(error_msg, pan_device=self)

        if not all_info:
            version = system_info['result']['system']['sw-version']
            model = system_info['result']['system']['model']
            serial = system_info['result']['system']['serial']
            return version, model, serial
        else:
            return system_info['result']
Beispiel #10
0
 def __init__(self, *args, **kwargs):
     if type(self) == PhysicalInterface:
         raise err.PanDeviceError(
             "Do not instantiate class. Please use a subclass.")
     super(PhysicalInterface, self).__init__(*args, **kwargs)
Beispiel #11
0
 def __init__(self, *args, **kwargs):
     if type(self) == NTPServer:
         raise err.PanDeviceError(
             "Do not instantiate class. Please use a subclass.")
     super(NTPServer, self).__init__(*args, **kwargs)
Beispiel #12
0
    def refresh_devices(self,
                        devices=(),
                        only_connected=False,
                        expand_vsys=True,
                        include_device_groups=True,
                        add=False,
                        running_config=False):
        """Refresh device groups and devices using config and operational commands

        Uses operational command in addition to configuration to gather as much information
        as possible about Panorama connected devices. The operational commands used are
        'show devices all/connected' and 'show devicegroups'.

        Information gathered about each device includes:

        - management IP address (can be different from hostname)
        - serial
        - version
        - high availability peer releationships
        - panorama connection status
        - device-group sync status

        Args:
            devices (list): Limit refresh to these serial numbers
            only_connected (bool): Ignore devices that are not 'connected' to Panorama (Default: False)
            expand_vsys (bool): Instantiate a Firewall object for every Vsys (Default: True)
            include_device_groups (bool): Instantiate :class:`pandevice.panorama.DeviceGroup` objects with Firewall
                objects added to them.
            add (bool): Add the new tree of instantiated DeviceGroup and Firewall objects to the Panorama config tree.
                Warning: This removes all current DeviceGroup and Firewall objects from the configuration tree, and all
                their children, so it is typically done before building a configuration tree. (Default: False)
            running_config (bool): Refresh devices from the running configuration (Default: False)

        Returns:
            list: If 'include_device_groups' is True, returns a list containing new DeviceGroup instances which
            contain new Firewall instances. Any Firewall that is not in a device-group is in the list with the
            DeviceGroup instances.
            If 'include_device_groups' is False, returns a list containing new Firewall instances.

        """
        logger.debug(self.hostname + ": refresh_devices called")
        try:
            # Test if devices is iterable
            test_iterable = iter(devices)
        except TypeError:
            # This probably means a single device was passed in, not an iterable.
            # Convert to an iterable with a single item.
            devices = (devices, )
        # Remove None from list of devices
        devices = [x for x in devices if x is not None]
        # Get the list of managed devices
        if only_connected:
            cmd = "show devices connected"
        else:
            cmd = "show devices all"
        devices_xml = self.op(cmd)
        devices_xml = devices_xml.find("result/devices")

        # Filter to only requested devices
        if devices:
            filtered_devices_xml = ET.Element("devices")
            for serial, vsys in [(d.serial, d.vsys) for d in devices]:
                if serial is None:
                    continue
                entry = devices_xml.find("entry[@name='%s']" % serial)
                if entry is None:
                    raise err.PanDeviceError(
                        "Can't find device with serial %s attached to Panorama at %s"
                        % (serial, self.hostname))
                multi_vsys = yesno(entry.findtext("multi-vsys"))
                # Create entry if needed
                if filtered_devices_xml.find(
                        "entry[@name='%s']" % serial) is None:
                    entry_copy = deepcopy(entry)
                    # If multivsys firewall with vsys defined, erase all vsys in filtered
                    if multi_vsys and vsys != "shared" and vsys is not None:
                        entry_copy.remove(entry_copy.find("vsys"))
                        ET.SubElement(entry_copy, "vsys")
                    filtered_devices_xml.append(entry_copy)
                # Get specific vsys
                if vsys != "shared" and vsys is not None:
                    vsys_entry = entry.find("vsys/entry[@name='%s']" % vsys)
                    if vsys_entry is None:
                        raise err.PanDeviceError(
                            "Can't find device with serial %s and"
                            " vsys %s attached to Panorama at %s" %
                            (serial, vsys, self.hostname))
                    vsys_section = filtered_devices_xml.find(
                        "entry[@name='%s']/vsys" % serial)
                    vsys_section.append(vsys_entry)
            devices_xml = filtered_devices_xml

        # Manipulate devices_xml so each vsys is a separate device
        if expand_vsys:
            original_devices_xml = deepcopy(devices_xml)
            devices_xml = ET.Element("devices")
            for entry in original_devices_xml:
                serial = entry.findtext("serial")
                for vsys_entry in entry.findall("vsys/entry"):
                    new_vsys_device = deepcopy(entry)
                    new_vsys_device.set("name", serial)
                    ET.SubElement(new_vsys_device,
                                  "vsysid").text = vsys_entry.get("name")
                    ET.SubElement(
                        new_vsys_device,
                        "vsysname").text = vsys_entry.findtext("display-name")
                    devices_xml.append(new_vsys_device)

        # Create firewall instances
        firewall_instances = firewall.Firewall.refreshall_from_xml(
            devices_xml, refresh_children=not expand_vsys)

        if not include_device_groups:
            if add:
                self.removeall(firewall.Firewall)
                self.extend(firewall_instances)
            return firewall_instances

        # Create device-groups

        # Get the list of device groups from configuration XML
        api_action = self.xapi.show if running_config else self.xapi.get
        devicegroup_configxml = api_action(
            "/config/devices/entry[@name='localhost.localdomain']/device-group"
        )
        devicegroup_configxml = devicegroup_configxml.find(
            "result/device-group")

        # Get the list of device groups from operational commands
        devicegroup_opxml = self.op("show devicegroups")
        devicegroup_opxml = devicegroup_opxml.find("result/devicegroups")

        # Combine the config XML and operational command XML to get a complete picture
        # of the device groups
        pandevice.xml_combine(devicegroup_opxml, devicegroup_configxml)

        devicegroup_instances = DeviceGroup.refreshall_from_xml(
            devicegroup_opxml, refresh_children=False)

        for dg in devicegroup_instances:
            dg_serials = [
                entry.get("name") for entry in devicegroup_opxml.findall(
                    "entry[@name='%s']/devices/entry" % dg.name)
            ]
            # Find firewall with each serial
            for dg_serial in dg_serials:
                all_dg_vsys = [
                    entry.get("name") for entry in devicegroup_opxml.findall(
                        "entry[@name='%s']/devices/entry[@name='%s']/vsys/entry"
                        % (dg.name, dg_serial))
                ]
                # Collect the firewall serial entry to get current status information
                fw_entry = devicegroup_opxml.find(
                    "entry[@name='%s']/devices/entry[@name='%s']" %
                    (dg.name, dg_serial))
                if not all_dg_vsys:
                    # This is a single-context firewall, assume vsys1
                    all_dg_vsys = ["vsys1"]
                for dg_vsys in all_dg_vsys:
                    fw = next((x for x in firewall_instances
                               if x.serial == dg_serial and x.vsys == dg_vsys),
                              None)
                    if fw is None:
                        # It's possible for device-groups to reference a serial/vsys that doesn't exist
                        # In this case, create the FW instance
                        if not only_connected:
                            fw = firewall.Firewall(serial=dg_serial,
                                                   vsys=dg_vsys)
                            dg.add(fw)
                    else:
                        # Move the firewall to the device-group
                        dg.add(fw)
                        firewall_instances.remove(fw)
                        fw.state.connected = yesno(
                            fw_entry.findtext("connected"))
                        fw.state.unsupported_version = yesno(
                            fw_entry.findtext("unsupported-version"))
                        fw.state.set_shared_policy_synced(
                            fw_entry.findtext("shared-policy-status"))

        if add:
            for dg in devicegroup_instances:
                found_dg = self.find(dg.name, DeviceGroup)
                if found_dg is not None:
                    # Move the firewalls to the existing devicegroup
                    found_dg.removeall(firewall.Firewall)
                    found_dg.extend(dg.children)
                else:
                    # Devicegroup doesn't exist, add it
                    self.add(dg)
            # Add firewalls that are not in devicegroups
            self.removeall(firewall.Firewall)
            self.extend(firewall_instances)

        return firewall_instances + devicegroup_instances
Beispiel #13
0
 def xpath_panorama(self):
     raise err.PanDeviceError("Attempt to modify Panorama configuration on non-Panorama device")
    def syncreboot(self, interval=5.0, timeout=600):
        """Block until reboot completes and return version of device"""

        import httplib

        # Validate interval and convert it to float
        if interval is not None:
            try:
                interval = float(interval)
                if interval < 0:
                    raise ValueError
            except ValueError:
                raise err.PanDeviceError("Invalid interval: %s" % interval)

        self._logger.debug("Syncing reboot...")

        # Record start time to gauge timeout
        start_time = time.time()
        attempts = 0
        is_rebooting = False

        time.sleep(interval)
        while True:
            try:
                # Try to get the device version (ie. test to see if firewall is up)
                attempts += 1
                version = self.refresh_version()
            except (pan.xapi.PanXapiError, err.PanDeviceXapiError) as e:
                # Connection errors (URLError) are ok
                # Invalid cred errors are ok because FW auth system takes longer to start up
                # Other errors should be raised
                if not e.msg.startswith("URLError:") and not e.msg.startswith(
                        "Invalid credentials."):
                    # Error not related to connection issue.  Raise it.
                    raise e
                else:
                    # Connection issue.  The firewall is currently rebooting.
                    is_rebooting = True
                    self._logger.debug("Connection attempted: %s" % str(e))
                    self._logger.debug(
                        "Device is not available yet. Connection attempts: %s"
                        % str(attempts))
            except httplib.BadStatusLine as e:
                # Connection issue.  The firewall is currently rebooting.
                is_rebooting = True
                self._logger.debug("Connection attempted: %s" % str(e))
                self._logger.debug(
                    "Device is not available yet. Connection attempts: %s" %
                    str(attempts))
            else:
                # No exception... connection succeeded and device is up!
                # This could mean reboot hasn't started yet, so check that we had
                # a connection error prior to this success.
                if is_rebooting:
                    self._logger.debug("Device is up! Running version %s" %
                                       version)
                    return version
                else:
                    self._logger.debug(
                        "Device is up, but it probably hasn't started rebooting yet."
                    )

            # Check to see if we hit timeout
            if (self.timeout is not None and self.timeout != 0
                    and time.time() > start_time + self.timeout):
                raise err.PanDeviceError(
                    "Timeout waiting for device to reboot")

            # Sleep and try again
            self._logger.debug("Sleep %.2f seconds", interval)
            time.sleep(interval)
    def syncjob(self, response, interval=0.5):
        """Block until job completes and return result

        response: XML response tag from firewall when job is created

        :returns True if job completed successfully, False if not
        """
        if interval is not None:
            try:
                interval = float(interval)
                if interval < 0:
                    raise ValueError
            except ValueError:
                raise err.PanDeviceError('Invalid interval: %s' % interval)

        job = response.find('./result/job')
        if job is None:
            return False
        job = job.text

        self._logger.debug('Syncing job: %s', job)

        cmd = 'show jobs id "%s"' % job
        start_time = time.time()

        while True:
            try:
                self.xapi.op(cmd=cmd, cmd_xml=True)
            except pan.xapi.PanXapiError as msg:
                raise pan.xapi.PanXapiError('commit %s: %s' % (cmd, msg))

            path = './result/job/status'
            status = self.xapi.element_root.find(path)
            if status is None:
                raise pan.xapi.PanXapiError('No status element in ' +
                                            "'%s' response" % cmd)
            if status.text == 'FIN':
                pconf = PanConfig(self.xapi.element_result)
                response = pconf.python()
                job = response['result']
                if job is None:
                    return
                job = job['job']
                success = True if job['result'] == "OK" else False
                messages = job['details']['line']
                if issubclass(messages.__class__, basestring):
                    messages = [messages]
                # Create the results dict
                result = {
                    'success': success,
                    'result': job['result'],
                    'jobid': job['id'],
                    'user': job['user'],
                    'warnings': job['warnings'],
                    'starttime': job['tenq'],
                    'endtime': job['tfin'],
                    'messages': messages,
                }
                return result

            self._logger.debug('Job %s status %s', job, status.text)

            if (self.timeout is not None and self.timeout != 0
                    and time.time() > start_time + self.timeout):
                raise pan.xapi.PanXapiError('Timeout waiting for ' +
                                            'job %s completion' % job)

            self._logger.debug('Sleep %.2f seconds', interval)
            time.sleep(interval)
    def refresh_devices_from_panorama(self, devices=()):
        try:
            # Test if devices is iterable
            test_iterable = iter(devices)
        except TypeError:
            # This probably means a single device was passed in, not an iterable.
            # Convert to an iterable with a single item.
            devices = (devices, )
        stats_by_ip = {}
        stats_by_host = {}
        devicegroup_stats_by_serial = {}
        template_stats_by_serial = {}
        # Get the list of managed devices
        self.xapi.op("show devices all", cmd_xml=True)
        pconf = PanConfig(self.xapi.element_root)
        response = pconf.python()
        try:
            for device in response['response']['result']['devices']['entry']:
                stats_by_ip[device['ip-address']] = device
                stats_by_host[device['ip-address']] = device
                stats_by_host[device['hostname']] = device
            # Populate the device objects with some of the data
            for device in devices:
                try:
                    device.serial = stats_by_host[device.hostname]['serial']
                    device.connected_to_panorama = stats_by_host[
                        device.hostname]['connected']
                except KeyError as e:
                    raise err.PanDeviceError(
                        "Can't determine serial for "
                        "device",
                        pan_device=device)
        # Ignore errors because it means there are no devices
        except KeyError:
            return {}

        # Get the list of device groups
        self.xapi.op("show devicegroups", cmd_xml=True)
        dg_element = self.xapi.element_result
        for dg in dg_element.findall("./devicegroups/entry"):
            for device in dg.findall("./devices/entry"):
                pconf = PanConfig(config=device)
                stats = pconf.python()
                # Save device stats
                stats = stats['entry']
                # Save device serial
                serial = stats['serial']
                # Save device ip-address
                ip = stats['ip-address']
                # Save device's device-group
                dg_name = dg.get('name')
                # Save the device-group to the device's stats
                stats['devicegroup'] = dg_name
                devicegroup_stats_by_serial[serial] = stats
                stats_by_ip[ip]['devicegroup'] = dg_name

        # Set the device-group for each device
        for device in devices:
            if device.serial is not None:
                stats = devicegroup_stats_by_serial.get(device.serial)
                if stats is not None:
                    device.devicegroup = stats['devicegroup']
                    sync_status = stats['shared-policy-status']
                    device.dg_in_sync = True if sync_status == "In Sync" else False

        return stats_by_ip