Skip to content

Commit

Permalink
feat!: check for scheduled update jobs (#106)
Browse files Browse the repository at this point in the history
Co-authored-by: Alp Eren Kose <alperenkose@gmail.com>
  • Loading branch information
FoSix and alperenkose committed Sep 12, 2023
1 parent 24acbdb commit 4b303f9
Show file tree
Hide file tree
Showing 12 changed files with 890 additions and 132 deletions.
70 changes: 70 additions & 0 deletions docs/panos-upgrade-assurance/api/check_firewall.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,76 @@ __Returns__
* [`CheckStatus.ERROR`](/panos/docs/panos-upgrade-assurance/api/utils#class-checkstatus) when the certificate's
properties (installed or required) are not supported.

### `CheckFirewall._calculate_schedule_time_diff`

```python
def _calculate_schedule_time_diff(now_dt: datetime, schedule_type: str,
schedule: dict) -> (int, str)
```

A method that calculates the time distance between two `datetime` objects.

:::note
This method is used only by [`CheckFirewall.check_scheduled_updates()`](#checkfirewallcheck_scheduled_updates) method and it expects some information
to be already available.
:::

__Parameters__


- __now_dt__ (`datetime`): A `datetime` object representing the current moment in time. Ideally this should be the device's local
time, taken from the management plane clock.
- __schedule_type__ (`str`): A schedule type returned by PanOS, can be one of: `every-*`, `hourly`, `daily`, `weekly`,
`real-time`.
- __schedule__ (`dict`): Value of the `recurring` key in the API response, see
[`FirewallProxy.get_update_schedules()`](/panos/docs/panos-upgrade-assurance/api/firewall_proxy#firewallproxyget_update_schedules)
documentation for details. Both formats (locally configured and pushed from a Panorama template) are supported.

__Raises__


- `MalformedResponseException`: Thrown then the `schedule_type` is not recognizable.

__Returns__


`tuple(int, str)`: A tuple containing the calculated time difference (in minutes) and human-readable description.

### `CheckFirewall.check_scheduled_updates`

```python
def check_scheduled_updates(test_window: int = 60) -> CheckResult
```

Check if any Dynamic Update job is scheduled to run within the specified time window.

When device is configured via Panorama, this includes schedules set up in Templates. It does not however include schedules
configured in `Panorama/Device Deployment/Dynamic Updates/Schedules`.

__Parameters__


- __test_window__ (`int, optional`): (defaults to 60 minutes). A time window in minutes to look for an update job occurrence.
Has to be a value between `60` and `10080` (1 week equivalent). The time window is calculated based on the device's
local time (taken from the management plane).

__Raises__


- `MalformedResponseException`: Thrown in case API response does not meet expectations.

__Returns__


`CheckResult`: Object of [`CheckResult`](/panos/docs/panos-upgrade-assurance/api/utils#class-checkresult) class taking value of:

* [`CheckStatus.SUCCESS`](/panos/docs/panos-upgrade-assurance/api/utils#class-checkstatus) when there is no update job
planned within the test window.
* [`CheckStatus.FAIL`](/panos/docs/panos-upgrade-assurance/api/utils#class-checkstatus) otherwise, `CheckResult.reason`
field contains information about the planned jobs with next occurrence time provided if possible.
* [`CheckStatus.ERROR`](/panos/docs/panos-upgrade-assurance/api/utils#class-checkstatus) when the `test_window` parameter
does not meet criteria.

### `CheckFirewall.check_non_finished_jobs`

```python
Expand Down
4 changes: 4 additions & 0 deletions docs/panos-upgrade-assurance/api/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ Parent class for all exceptions coming from [Utils](/panos/docs/panos-upgrade-as

Used when a command run on a device does not return the `success` status.

## class `GetXpathConfigFailedException`

Used when XAPI does not return a `success` state when running a `get` operation.

## class `MalformedResponseException`

A generic exception class used when a response does not meet the expected standards.
Expand Down
113 changes: 86 additions & 27 deletions docs/panos-upgrade-assurance/api/firewall_proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Execute a command on node, parse, and return response.

This is just a wrapper around the
[`Firewall.op()`](https://pan-os-python.readthedocs.io/en/latest/module-firewall.html#panos.firewall.Firewall.op) method.
It additionally does basic error handling and tries to extract the actual device
response.
It additionally does basic error handling and tries to extract the actual device response.

__Parameters__

Expand All @@ -57,6 +56,36 @@ __Returns__

`dict, xml.etree.ElementTree.Element`: The actual command output. A type is defined by the `return_xml` parameter.

### `FirewallProxy.get_parser`

```python
def get_parser(xml_path: str,
return_xml: Optional[bool] = False) -> Union[dict, ET.Element]
```

Execute a configuration get command on a node, parse and return response.

This is a wrapper around the
[`pan.xapi.get()` method](https://github.com/kevinsteves/pan-python/blob/master/doc/pan.xapi.rst#getxpathnone)
from the [`pan-python` package](https://pypi.org/project/pan-python/).
It does a basic error handling and tries to extract the actual response.

__Parameters__


- __xml_path__ (`str`): An XPATH pointing to the config to be retrieved.
- __return_xml__ (`bool`): (defaults to `False`) When set to `True`, the return data is an [`XML object`](https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element)
instead of a Python dictionary.

__Raises__


- `GetXpathConfigFailedException`: This exception is raised when XPATH is not provided or does not exist.

__Returns__

`dict, xml.etree.ElementTree.Element`: The actual command output. A type is defined by the `return_xml` parameter.

### `FirewallProxy.is_pending_changes`

```python
Expand Down Expand Up @@ -854,7 +883,7 @@ __Returns__
### `FirewallProxy.get_mp_clock`

```python
def get_mp_clock() -> dict
def get_mp_clock() -> datetime
```

Get the clock information from management plane.
Expand All @@ -864,18 +893,7 @@ The actual API command is `show clock`.
__Returns__


`dict`: The clock information represented as a dictionary.

```python showLineNumbers title="Sample output"
{
'time': '00:41:36',
'tz': 'PDT',
'day': '19',
'month': 'Apr',
'year': '2023',
'day_of_week': 'Wed'
}
```
`datetime`: The clock information represented as a `datetime` object.

### `FirewallProxy.get_dp_clock`

Expand All @@ -890,18 +908,7 @@ The actual API command is `show clock more`.
__Returns__


`dict`: The clock information represented as a dictionary.

```python showLineNumbers title="Sample output"
{
'time': '00:41:36',
'tz': 'PDT',
'day': '19',
'month': 'Apr',
'year': '2023',
'day_of_week': 'Wed'
}
```
`datetime`: The clock information represented as a `datetime` object.

### `FirewallProxy.get_certificates`

Expand Down Expand Up @@ -956,6 +963,58 @@ __Returns__
}
```

### `FirewallProxy.get_update_schedules`

```python
def get_update_schedules() -> dict
```

Get schedules for all dynamic updates.

This method gets scheduled dynamic updates on a device. This includes the ones pushed from Panorama,
but it does not include the ones configured via `Panorama/Device Deployment/Dynamic Updates/Schedules`.

The actual XMLAPI command run here is `config/get` with XPATH set to
`/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/update-schedule`.

__Returns__


`dict`: All dynamic updates schedules, key is the entity type to update, like: threats, wildfire, etc.

```python showLineNumbers title="Sample output, showing values coming from Panorama"
{'@ptpl': 'lab',
'@src': 'tpl',
'anti-virus': {'@ptpl': 'lab',
'@src': 'tpl',
'recurring': {'@ptpl': 'lab',
'@src': 'tpl',
'hourly': {'@ptpl': 'lab',
'@src': 'tpl',
'action': {'`text`': 'download-and-install',
'@ptpl': 'lab',
'@src': 'tpl'},
'at': {'`text`': '0',
'@ptpl': 'lab',
'@src': 'tpl'}}}},
'global-protect-clientless-vpn': {'@ptpl': 'lab',
'@src': 'tpl',
'recurring': {'@ptpl': 'lab',
'@src': 'tpl',
'weekly': {'@ptpl': 'lab',
'@src': 'tpl',
'action': {'`text`': 'download-only',
'@ptpl': 'lab',
'@src': 'tpl'},
'at': {'`text`': '20:00',
'@ptpl': 'lab',
'@src': 'tpl'},
'day-of-week': {'`text`': 'wednesday',
'@ptpl': 'lab',
'@src': 'tpl'}}}}
}
```

### `FirewallProxy.get_jobs`

```python
Expand Down
54 changes: 54 additions & 0 deletions docs/panos-upgrade-assurance/configuration_details.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ checks_configuration = [
}
},
{'content_version': {'version': '8634-7678'}},
{'dynamic_updates': {'test_window': 120}},
{"expired_licenses": {"skip_licenses": ["Threat Prevention"]}},
{'free_disk_space': {'image_version': '10.1.6-h6'}},
{'ha': {'skip_config_sync': True}},
Expand Down Expand Up @@ -309,6 +310,8 @@ checks_configuration:
hash_method: "sha1"
- content_version:
version: "8634-7678"
- dynamic_updates:
test_window: 120
- expired_licenses:
skip_licenses:
- "Threat Prevention"
Expand Down Expand Up @@ -522,6 +525,57 @@ checks_configuration:
```


### `dynamic_updates`

Check if any Dynamic Update job is scheduled to run within the specified time window.

:::note
This includes schedules pushed from Panorama via a template, but does not include the ones configured
in `Panorama/Device Deployment/Dynamic Updates/Schedules`.
:::

**Method:** [`CheckFirewall.check_scheduled_updates()`](/panos/docs/panos-upgrade-assurance/api/check_firewall#checkfirewallcheck_scheduled_updates)

**Configuration parameters**

paramter | description
--- | ---
`test_window` | (optional) time window in minutes to look for an update job occurrence

**Sample configuration**

```mdx-code-block
<Tabs>
<TabItem value="python" label="Python" default>
```

```python showLineNumbers
checks_configuration = [
{
'dynamic_updates': {
'test_window': 120
}
}
]
```

```mdx-code-block
</TabItem>
<TabItem value="ansible" label="YAML" default>
```

```yaml showLineNumbers
checks_configuration:
- dynamic_updates:
test_window: 120
```

```mdx-code-block
</TabItem>
</Tabs>
```


### `free_disk_space`

Checks if there is enough free space on the `/opt/panrepo` volume to download a PanOS image before an upgrade.
Expand Down
3 changes: 3 additions & 0 deletions examples/low_level_methods/run_low_level_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from panos.panorama import Panorama
from argparse import ArgumentParser
from getpass import getpass
from pprint import pprint

if __name__ == "__main__":
argparser = ArgumentParser(
Expand Down Expand Up @@ -117,6 +118,8 @@

print(f"\n certificates: {firewall.get_certificates()}")

print(f"\n dynamic schedules: {firewall.get_update_schedules()}")

print(f"\n jobs: {firewall.get_jobs()}")


Expand Down
1 change: 1 addition & 0 deletions examples/readiness_checks/run_readiness_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
}
}
},
{"dynamic_updates": {"test_window": 500}},
# checks below require additional configuration
{
"session_exist": {
Expand Down
Loading

0 comments on commit 4b303f9

Please sign in to comment.