Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(panos-upgrade-assurance): upgrade assurance modules introduction #437

Closed
wants to merge 14 commits into from
Closed

feat(panos-upgrade-assurance): upgrade assurance modules introduction #437

wants to merge 14 commits into from

Conversation

FoSix
Copy link
Contributor

@FoSix FoSix commented May 23, 2023

Description

Introducing Ansible modules that wrap the PanOS Upgrade Assurance package.

Motivation and Context

The PanOS Upgrade Assurance package is just a set of libs that have to be wrapped with some code. One way of doing this are Ansible modules. This PR introduces 4 modules:

  • panos_readiness_checks - runs readiness checks on a device
  • panos_state_snapshot - take a snapshot of a device's state
  • panos_snapshot_report - produces a report from a comparison of two snapshot in a form of a dictionary
  • panos_active_in_ha - a helper module to quickly verify if a given node in an HA pair is active or passive.

Since the package itself is based on pan-os-python, these modules follow the provider block standard used widely in this collection.

How Has This Been Tested?

Already used on production as local modules.

Screenshots (if appropriate)

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes if appropriate.
  • All new and existing tests passed.

@jamesholland-uk jamesholland-uk requested a review from shinmog May 23, 2023 13:36
@adambaumeister
Copy link
Collaborator

@shinmog thoughts on this one? Is there anything else you need the team to look at?

@thomaschristory
Copy link

Hello,

When will this be merged into main ?

Copy link
Collaborator

@shinmog shinmog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Universal feedback for the modules.

  • All version_added values inside DOCUMENTATION blocks need to be updated, as multiple Ansible collection versions have been released since this PR was opened (sorry for the late feedback).
  • Remove get_firewall_proxy_object() from all of the modules, and instead create the FirewallProxy from helper.device after invoking helper.get_pandevice_parent. helper.get_pandevice_parent() does other useful things such as minimum pan-os-python versions, minimum PAN-OS versions, python libraries, and all kinds of things. Most importantly, having get_firewall_proxy_object() like this that directly accesses authentication credentials like this duplicates the authentication credential retrieval that we need to move away from as a collection. These days, authentication credentials for Ansible collections comes from environment variables, which I think are configured in the inventory file..? Anyways, use the helper object to deal with authentication credentials is the point.
  • If you guys decide that, yes, you do in fact want to keep the panos_upgrade_assurance code separate as opposed to just adding it directly in ./plugins/module_utils/ somewhere or in pan-os-python itself, you're going to need to 1) mandate that releases of panos_upgrade_assurance follow semver standards, just like pan-os-python does, and 2) add a new version checking hook for the version of panos_upgrade_assurance to the helper object. To not break backwards compatibility for people who won't be using the code, the version check should default to None and not worry about if panos_upgrade_assurance is an installed library or not. If the version number is defined, then make sure that panos_upgrade_assurance is present, and that the version is at least what is defined (refer to the version checking for pandevice / pan-os-python within the ./plugins/module_utils/panos.py for the current helper logic and build off of that).
  • The ./tests/sanity/ignore* files have all been changed in recent versions, so you'll have to redo the new ignores for the files that are present.
  • The CI has changed a lot since this PR was opened, so other things may need to be changed to satisfy all the new requirements collections must follow. So just a heads up that there may be CI failures on syntax, and those have to be fixed.

Comment on lines +48 to +49
- A list of checks that should be run against a device. For the details on currently supported checks please refer to
L(package's documentation,https://pan.dev/panos/docs/panos-upgrade-assurance/configuration-details/#readiness-checks).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's reasons like this why having the upgrade assurance stuff as completely separate from this collection is problematic.

It's a bad user experience to read documentation to be referred to other documentation for potential values. And the waters get even muddier when a user's installed version of the upgrade assurance stuff is out of sync with what is live, and the values have changed.

These are not insurmountable issues, but you'll need to be ready for when it inevitably happens.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, but panos-upgrade-assurance is not for Ansible only, XSOAR can use it as well. Or just some pure Python script. Maybe more reasonable would be to keep it as part of the pan-os-python package?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok. Separate it is, then! So you'll want to add a new parameter to ./plugins/module_utils/panos.py > get_connection() that allows you to do version checking against panos_upgrade_assurance.version the same as happens for both PAN-OS itself and pan-os-python / pandevice. Please have the logic of this new check look like this:

if self.min_panos_upgrade_assurance is not None:
    try:
        import panos_upgrade_assurance
    except ImportError:
        module.fail_json(msg='Missing required library "panos_upgrade_assurance".', syspath=sys.path)
    # This code assumes both panos_upgrade_assurance.version and self.min_panos_upgrade_assurance
    # are a tuple of 3 ints.  If panos_upgrade_assurance.version is a string, then you'll have
    # to turn it into a 3 element tuple of ints to do the comparison.
    if panos_upgrade_assurance.version < self.min_panos_upgrade_assurance:
        module.fail_json(msg=MIN_VERSION_ERROR.format(
            "panos_upgrade_assurance",
            _vstr(panos_upgrade_assurance.version),
            _vstr(self.min_panos_upgrade_assurance),
        ))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shinmog I am thinking we can use a super call in the FirewallProxy class to get the best of both worlds. Subclassing FirewallProxy makes life easy so what I'm thinking is something like (psuedocode here)

firewall = helper.get_pandevice_parent().device
firewall_proxy = FirewallProxy(firewall)

# ... in assurance library ...

Class FirewallProxy(Firewall):
    def __init__(self, firewall_object: Optional[Firewall] = None, *args, **kwargs):
        """
        """
        if firewall_object:
            super(FirewallProxy, self).__init__(
                api_key=firewall_object.xapi.api_key,
                api_password=firewall_object.xapi.api_password,
                api_username=firewall_object.xapi.api_username,
                serial=firewall_object.xapi.serial,
                *args,
                **kwargs
            )
        else:
            super(FirewallProxy, self).__init__()

Can you see any reason this wouldn't work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finally FirewallProxy has both options, so it can take the api-* parameters or an existing device object. Changes will be introduced in upgrade assurance with this pr.

This way we can leave the upgrade assurance as a standalone package and still use the helper class inside Ansible modules.

If someone has any objections, please leave a comment in the upgrade assurance PR.

poetry.lock Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file. The existance of a poetry.lock file breaks the CI and prevents us from testing against multiple Ansible versions.

pyproject.toml Outdated
Comment on lines 13 to 16
python = "^3.8.1"
pan-python = "^0.17.0"
pan-os-python = "^1.8.0"
xmltodict = "^0.12.0"
xmltodict = "^0.13.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these two changes necessary for the upgrade assurance stuff?

Copy link
Contributor Author

@FoSix FoSix Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a reason why this was introduced, but it was so long ago....

I've tested it again and we can skip it so probably the issues got resolved along the way (actually the python = "^3.8.1" requirement came from the fact that we used a recent version of flake8, version 6 and up).

@shinmog
Copy link
Collaborator

shinmog commented Sep 12, 2023

Just to be clear, this PR needs to be rebased against current develop so that the new CI can run all the new requirements RedHat has in place.

@shinmog
Copy link
Collaborator

shinmog commented Oct 18, 2023

Few more issues:

  • There are multiple changes to files outside the scope of this PR (aka - panos_query_rules.py, for example, which is causing a merge conflict). Please undo the changes to unrelated files.
  • It seems the upgrade assurance stuff is specific to firewall. If Panorama is not supported, then please 1) add a note to the notes section saying Panorama is not supported and 2) pass in the desired error message
    as the panorama_error flag to the helper.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FoSix I think we should avoid touching files non-related to the PR

Copy link
Contributor Author

@FoSix FoSix Oct 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alperenkose those file were modified by black, not by me. If I wouldn't fix them, the CI would fail. I don't think I had an option here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frankly speaking, I do not know how this work, but for example the module_utils/panos.py is missing a trailing new line causing sanity checks to fail. Did the linting rules change? Maybe. But in the end, I'm the one that have to introduce that change, even though it's not directly related to my code.

or we can stop here, do a separate PR, fix all the things that do not pass a sanity test - wait for review - merge - rebase this PR - run sanity.... but I'm affraid by this time something else would change and the PR would never get merged

@@ -1323,6 +1348,7 @@ def get_connection(
required_one_of=None,
min_pandevice_version=None,
min_panos_version=None,
min_panos_upgrade_assurance_version=None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add this in the "Arguments:" section in method docstring.

firewall = FirewallProxy(firewall=helper.get_pandevice_parent(module))

is_active = CheckFirewall(firewall).check_is_ha_active(
skip_config_sync=module.params["skip_config_sync"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have added another parameter ignore_non_functional to this method but we can leave it for a separate PR.

from panos_upgrade_assurance.firewall_proxy import FirewallProxy
from panos_upgrade_assurance.check_firewall import CheckFirewall
except ImportError:
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we have the PUA_AVAILABLE logic here as in the panos_snapshot_report.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it's in the helper class, panos_snapshot_report does not use the helper class, so the logic had to be moved to the module directly

from panos_upgrade_assurance.check_firewall import CheckFirewall
from panos_upgrade_assurance.firewall_proxy import FirewallProxy
except ImportError:
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we have the PUA_AVAILABLE logic here as in the panos_snapshot_report.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a new file for version 2.16 - ignore-2.16.txt we need to update that as well

@FoSix
Copy link
Contributor Author

FoSix commented Oct 27, 2023

I'm closing this PR in favour of a new one, made from a branch, not a fork, with an up to date code (passing sanity tests at least partially)

all the suggestions from this PR were taken into consideration (unless irrelevant)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants