Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit c563ec08 authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

changed config files to toml format

parent ea41b546
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,9 @@ pnp/log/
# python virtual environment
.venv
# vscode stuff
.vscode
# pycharm
.idea
......
PYTHONPATH=vars
\ No newline at end of file
2023-01-26: reorg platforms.py and images.py in images.json
reorg settings.py in open-pnp.ini
remove imports for platforms.py/images.py/settings.py
add reload data function
\ No newline at end of file
add reload data function
changed open-pnp.ini/images.json to toml (better to handle)
\ No newline at end of file
# Plug and Play (PnP) server for IOS XE based devices
# Plug and Play (PnP) server for IOS/IOS-XE based devices
# Introduction
This is a basic implementation of the Cisco Plug and Play protocol, to fully automate the day0 provisioning of Cisco IOS-XE devices.
This is a basic implementation of the Cisco Plug and Play protocol, to fully automate the day0 provisioning of Cisco IOS/IOS-XE devices.
### Acknowledgment
This project is based on https://github.com/oliverl-21/Open-PnP-Server
......@@ -10,21 +10,23 @@ This project is based on https://github.com/oliverl-21/Open-PnP-Server
## Prerequisites
- Your devices need to be PnP capable. This is true for most IOS-XE devices like ISR routers, Catalyst 9k Switches,
ASR routers and so on.
- a HTTP server to store the images and config files
- Your devices need to be PnP capable. This is true for most IOS/IOS-XE devices like ISR routers, Catalyst 9k Switches, ASR routers and so on.
- an HTTP server to store the images and config files
- a DHCP server to provide IP configuration and option 43 to the new devices (or DNS)
- an python 3.x environment to run this PnP server
- a python 3.x environment to run this PnP server
## How to use
---
### IOS-XE Images
Place the IOS-XE images on an HTTP server where the new devices can download them. If you use this PnP server to provide the `images` place them in the images' subdirectory. For the images I would recommend using a _real_ HTTP server.
### IOS/IOS-XE Images
Place the IOS/IOS-XE images on an HTTP server where the new devices can download them. If you use this PnP server to
provide the images place them in the `images` subdirectory. For the images I would recommend using a _real_ HTTP server.
---
### Configuration files
Create for each device a configuration file named SERIALNUMBER.cfg. i.e.: [`FCZ094210DS.cfg`](pnp/configs/FGL223590FL.cfg). Place the configuration files also on your HTTP server, so the new devices can download them. In case the PnP server should deliver the configuration files, copy them in the `configs` subdirectory.
Create for each device a configuration file named SERIALNUMBER.cfg. i.e.: [`FCZ094210DS.cfg`](/pnp/configs/FGL223590FL.cfg).
Place the configuration files also on your HTTP server, so the new devices can download them. In case the PnP server
should deliver the configuration files, copy them in the `configs` subdirectory.
**Hint**: you can use different HTTP servers for the images and the configuration files
......@@ -41,27 +43,30 @@ on Linux
# go to the pnp subproject
~/: cd cisco_day0_provision/pnp
# create a python virtual environment (optional)
~/cisco_day0_provision/pnp$ python3.8 -m venv .venv
# create a python virtual environment
~/cisco_day0_provision/pnp$ python3 -m venv .venv
# activate the environment
~/cisco_day0_provision/pnp$ source .venv/bin/activate
# update pip (oprional)
# update pip (optional)
(.venv) :~/cisco_day0_provision/pnp$ pip3 install -U pip
# install the required pyton packages
(.venv) :~/cisco_day0_provision/pnp$pip3 install -r requirements.txt
(.venv) :~/cisco_day0_provision/pnp$pip3 install flask xmltodict requests ifaddr tomli
# run the pnp server
(.venv) :~/cisco_day0_provision/pnp$ python3.8 open-pnp.py
(.venv) :~/cisco_day0_provision/pnp$ python3 open-pnp.py
Running PnP server. Stop with ctrl+c
Bind to IP-address : ::
Bind to IP-address : 0.0.0.0
Listen on port : 8080
Image file(s) base URL : http://192.168.10.133:8080/images
Config file(s) base URL : http://192.168.10.133:8080/configs
The PnP server is running on the following URL(s)
http://192.168.10.133:8080
```
on Windows
......@@ -71,10 +76,7 @@ c:\>cd cisco_day0_provision\pnp
c:\cisco_day0_provision\pnp>python -m venv .venv
c:\cisco_day0_provision\pnp>.venv\Scripts\activate.bat
(.venv)c:\cisco_day0_provision\pnp>pip install flask
(.venv)c:\cisco_day0_provision\pnp>pip install xmltodict
(.venv)c:\cisco_day0_provision\pnp>pip install requests
(.venv)c:\cisco_day0_provision\pnp>pip install python-dotenv
(.venv)c:\cisco_day0_provision\pnp>pip install flask xmltodict requests ifaddr tomli
(.venv)c:\cisco_day0_provision\pnp>python open-pnp.py
......@@ -84,6 +86,9 @@ Listen on port : 8080
Image file(s) base URL : http://192.168.10.133:8080/images
Config file(s) base URL : http://192.168.10.133:8080/configs
The PnP server is running on the following URL(s)
http://192.168.10.133:8080
```
You can check if the PnP server is running by opening a web browser and accessing the status page of the pnp server
......@@ -97,64 +102,63 @@ You can check if the PnP server is running by opening a web browser and accessin
to use the PnP server you need to configure the server by modifying the following files
- [**_settings.py_**](/pnp/open-pnp.ini)
- [**_images.py_**](/pnp/images.json)
- [**_settings.toml_**](/pnp/open-pnp.toml)
- [**_images.toml_**](/pnp/images.toml)
**NOTE:** after changing the PnP server configuration you need to restart the PnP server.
**NOTE**: after changing the PnP server configuration you need to restart the PnP server.
**NOTE:** both files need to be in valid [TOML](https://toml.io/en/) format.
---
#### Global variables in [**open-pnp.ini_**](/pnp/open-pnp.ini)
#### Global settings [**open-pnp.toml**](/pnp/open-pnp.toml)
```
[settings]
# BIND_PNP_SERVER = '0.0.0.0'
# BIND_PNP_SERVER = "0.0.0.0"
# PORT = 8080
# TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
# TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
# STATUS_REFRESH = 60
# DEBUG = False
# LOG_TO_FILE = True
# LOG_FILE = 'log/pnp_debug.log'
IMAGE_BASE_URL = 'http://192.168.10.133:8080/images'
CONFIG_BASE_URL = 'http://192.168.10.133:8080/configs'
# IMAGE_DATA = 'images.json'
# DEBUG = false
# LOG_TO_FILE = true
# LOG_FILE = "log/pnp_debug.log"
# IMAGE_DATA = "images.toml"
IMAGE_BASE_URL = "http://192.168.10.133:8080/images"
CONFIG_BASE_URL = "http://192.168.10.133:8080/configs"
```
- **BIND_PNP_SERVER**: the IP-address of your open-pnp server box. (Use `'::'` for IPv6)
- **BIND_PNP_SERVER**: the IP-address of your open-pnp server box. (Use `"::"` for IPv6)
- **PORT**: the TCP port the server should listen on (remember for port 80 the server needs to run as root)
- **TIME_FORMAT**: the time format used in the status page
- **STATUS_REFRESH**: the interval in seconds the status page will automatically reload
- **DEBUG**: enable debug output with `DEBUG = True`. Can be `True` or `False`.
- **DEBUG**: enable debug output with `DEBUG = true`. Can be `true` or `false`.
- **LOG_FILE**: path/name of the log file
- **LOG_TO_FILE**: write log output to file. Can be `True` or `False`.
- **LOG_TO_FILE**: write log output to file. Can be `true` or `false`.
- **IMAGE_DATA**: the file containing the data of your IOS/IOS-XE images
- **IMAGE_BASE_URL**: the base URL for your images
- **CONFIG_BASE_URL**: the base URL for your configuration files
- **IMAGE_DATA**: the file containing the data of your IOS/IOS-XE images
**Note**: you need to uncomment (remove `# `) the lines if you change the values.
---
#### _IMAGES_ dictionary in [**_images.json_**](/images.json)
#### _IMAGES_ file [**_images.toml_**](/pnp/images.toml)
Each entry in the _IMAGES_ dictionary contains
- the **name** of the image file as key
Each entry in the _IMAGES_ file contains
- the **name** of the image file as section title
- the IOS/IOS-XE **version** of the image
- the **md5** checksum of the image file
- the **size** of the image file in bytes
- a list of **models** where that image should be used
```
"c1000-universalk9-mz.152-7.E7.bin": {
"version": "15.2(7)E7",
"md5": "1e6f508499c36434f7035b83a4018390",
"size": 16499712,
"models": ["C1000-8T-2G-L", "C1000-24P-4G-L", "C1000-24T-4G-L", "C1000-24T-4X-L", "C1000-48P-4G-L", "C1000-48T-4X-L"]
}
["c1000-universalk9-mz.152-7.E7.bin"]
version = "15.2(7)E7"
md5 = "1e6f508499c36434f7035b83a4018390"
size = 16499712
models = ["C1000-8T-2G-L", "C1000-24P-4G-L", "C1000-24T-4G-L", "C1000-24T-4X-L", "C1000-48P-4G-L", "C1000-48T-4X-L"]
```
**NOTE:** By default _open-pnp_ expects the image data in _images.json_. You can change this with the key _IMAGE_DATA_ in _settings.ini_.
**NOTE:** this file needs to be in valid json format.
---
### PnP server discovery
The IOS-XE device can discover a PnP server via DHCP option 43 or using DNS lookup for the hostname _pnpserver.your.domain_. Replaced _your.domain_ by the DNS domain the device receives via DHCP. With DHCP, the DHCP server needs to send the vendor option 43.
......
{
"your_image_name.bin": {
"version": "0.0.0",
"md5": "fdb9c92bae37f9130d0ee6761afe2919",
"size": 9999999999,
"models": []
},
"cat9k_iosxe.17.06.01.SPA.bin": {
"version": "17.6.1",
"md5": "fdb9c92bae37f9130d0ee6761afe2919",
"size": 1,
"models": ["C9500-24Q", "C9300-24P"]
},
"asr1000-universalk9.17.05.01a.SPA.bin": {
"version": "17.5.1a",
"md5": "0e4b1fc1448f8ee289634a41f75dc215",
"size": 1,
"models": ["ASR1001-HX"]
},
"c1000-universalk9-mz.152-7.E7.bin": {
"version": "15.2(7)E7",
"md5": "1e6f508499c36434f7035b83a4018390",
"size": 16499712,
"models": ["C1000-8T-2G-L", "C1000-24P-4G-L", "C1000-24T-4G-L", "C1000-24T-4X-L", "C1000-48P-4G-L", "C1000-48T-4X-L"]
},
"c1100-universalk9.16.12.01a.SPA.bin": {
"version": "16.12.1a",
"md5": "045d73625025b4f77c65c7800b7faa2b",
"size": 541469788,
"models": []
},
"c1100-universalk9.17.01.01.SPA.bin": {
"version": "17.1.1",
"md5": "62e79c54994b82fc862c2ca043dcd543",
"size": 573996288,
"models": []
},
"c1100-universalk9.17.02.03.SPA.bin": {
"version": "17.2.3",
"md5": "4986d253b333d21b1b80c76f6d2267ca",
"size": 589675224,
"models": []
},
"c1100-universalk9.17.03.05.SPA.bin": {
"version": "17.3.5",
"md5": "64aa0df0806f7f962d66d325ff917e4a",
"size": 604409868,
"models": []
},
"c1100-universalk9.17.04.02.SPA.bin": {
"version": "17.4.2",
"md5": "40b7ec81c4e4cdc8b3683a3938ae8361",
"size": 651402492,
"models": []
},
"c1100-universalk9.17.05.01a.SPA.bin": {
"version": "17.5.1a",
"md5": "85d86916e33d27ae9867eec822206b97",
"size": 674793716,
"models": []
},
"c1100-universalk9.17.06.03a.SPA.bin": {
"version": "17.6.3a",
"md5": "2501b21b6fa3f71ea6acd7d59bcc8423",
"size": 706422748,
"models": []
},
"c1100-universalk9.17.06.04.SPA.bin": {
"version": "17.6.4",
"md5": "2caa962f5ed0ecc52f99b90c733c54de",
"size": 706565772,
"models": ["C1117-4PMLTEEAWE"]
},
"c1100-universalk9.17.07.02.SPA.bin": {
"version": "17.7.2",
"md5": "b824743e09cfa2644ccb442ef3e48cd2",
"size": 727305300,
"models": []
},
"c1100-universalk9.17.08.01a.SPA.bin": {
"version": "17.8.1a",
"md5": "8997c56cb03b5dcb08f12bf82fe23988",
"size": 758605624,
"models": []
},
"c1100-universalk9.17.09.01a.SPA.bin": {
"version": "17.9.1a",
"md5": "b3efb230d869fa6e77a98b4130c89585",
"size": 684976080,
"models": []
},
"c3560cx-universalk9-mz.152-7.E7.bin": {
"version": "15.2(7)E7",
"md5": "1c4c0597d355a0926c3d7198c1167cae",
"size": 22967296,
"models": ["WS-C3560CX-12PD-S"]
}
}
\ No newline at end of file
["cat9k_iosxe.17.06.01.SPA.bin"]
version = "17.6.1"
md5 = "fdb9c92bae37f9130d0ee6761afe2919"
size = 1
models = ["C9500-24Q", "C9300-24P"]
["asr1000-universalk9.17.05.01a.SPA.bin"]
version = "17.5.1a"
md5 = "0e4b1fc1448f8ee289634a41f75dc215"
size = 1
models = ["ASR1001-HX"]
["c1000-universalk9-mz.152-7.E7.bin"]
version = "15.2(7)E7"
md5 = "1e6f508499c36434f7035b83a4018390"
size = 16499712
models = ["C1000-8T-2G-L", "C1000-24P-4G-L", "C1000-24T-4G-L", "C1000-24T-4X-L", "C1000-48P-4G-L", "C1000-48T-4X-L"]
["c1100-universalk9.16.12.01a.SPA.bin"]
version = "16.12.1a"
md5 = "045d73625025b4f77c65c7800b7faa2b"
size = 541469788
models = []
["c1100-universalk9.17.06.04.SPA.bin"]
version = "17.6.4"
md5 = "2caa962f5ed0ecc52f99b90c733c54de"
size = 706565772
models = ["C1117-4PMLTEEAWE"]
["c1100-universalk9.17.09.01a.SPA.bin"]
version = "17.9.1a"
md5 = "b3efb230d869fa6e77a98b4130c89585"
size = 684976080
models = []
["c3560cx-universalk9-mz.152-7.E7.bin"]
version = "15.2(7)E7"
md5 = "1c4c0597d355a0926c3d7198c1167cae"
size = 22967296
models = ["WS-C3560CX-12PD-S"]
[settings]
# BIND_PNP_SERVER = '0.0.0.0'
# BIND_PNP_SERVER = '::'
# PORT = 8080
# TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
STATUS_REFRESH = 10
# DEBUG = True
# LOG_TO_FILE = True
# LOG_FILE = 'log/pnp_debug.log'
IMAGE_BASE_URL = 'http://192.168.10.133:8080/images'
CONFIG_BASE_URL = 'http://192.168.10.133:8080/configs'
# IMAGE_DATA = 'images.json'
\ No newline at end of file
......@@ -19,40 +19,39 @@
# 20-12-15: renamed ./vars/vars.py to ./vars/settings.py
# stop on import error for images.py and platforms.py
# removed extending path variable to ./vars
# changed open-pnp.ini/images.json to toml (better to handle)
#
# pip install flask xmltodict requests ifaddr tomli
# pip install python-dotenv # for vscode
import logging
from logging.handlers import RotatingFileHandler
from re import compile as re_compile
from flask import Flask, request, send_from_directory, render_template, Response, redirect, cli
from pathlib import Path
from xmltodict import parse as xml_parse
from time import strftime
from typing import Optional, List, Dict, Any
import logging
from logging.handlers import RotatingFileHandler
from requests import head
from json import load as json_load
from json.decoder import JSONDecodeError
from configparser import ConfigParser
try:
from netifaces import interfaces, ifaddresses, AF_INET, AF_INET6
_netifaces = True
except ModuleNotFoundError:
_netifaces = False
pass
# devine global variables
IMAGE_DATA = None # 'images.json'
BIND_PNP_SERVER = None # '0.0.0.0'
PORT = None # 8080
TIME_FORMAT = None # '%Y-%m-%dT%H:%M:%S'
STATUS_REFRESH = None # 60
DEBUG = None # False
LOG_TO_FILE = None # True
LOG_FILE = None # 'log/pnp_debug.log'
IMAGE_BASE_URL = None # ''
CONFIG_BASE_URL = None # ''
IMAGES = None # {}
from flask import Flask, request, send_from_directory, render_template, Response, redirect, cli
from xmltodict import parse as xml_parse
from ifaddr import get_adapters
from tomli import load as toml_load
from tomli import TOMLDecodeError
# define global variables
CFG_FILE = 'open-pnp.toml'
IMAGE_DATA: Optional[str] = None # 'images.toml'
BIND_PNP_SERVER: Optional[str] = None # '0.0.0.0'
PORT: Optional[int] = None # 8080
TIME_FORMAT: Optional[str] = None # '%Y-%m-%dT%H:%M:%S'
STATUS_REFRESH: Optional[int] = None # 60
DEBUG: Optional[bool] = None # False
LOG_TO_FILE: Optional[bool] = None # True
LOG_FILE: Optional[str] = None # 'log/pnp_debug.log'
IMAGES: Optional[Dict[str, any]] = None # {}
IMAGE_BASE_URL: Optional[str] = None # ''
CONFIG_BASE_URL: Optional[str] = None # ''
class SoftwareImage:
......@@ -62,6 +61,7 @@ class SoftwareImage:
self.md5: str = md5
self.size: int = size
class ErrorCodes:
__readable = {
0: 'No error',
......@@ -160,6 +160,7 @@ class Device:
self.image: str = ''
self.destination_name: str = ''
self.destination_free: Optional[int] = None
self.status: str = ''
self.__pnp_flow: int = PNPFLOW.NEW
self.pnp_flow_readable: str = PNPFLOW.readable(PNPFLOW.NEW)
self.target_image: Optional[SoftwareImage] = None
......@@ -171,7 +172,7 @@ class Device:
self.error_count: int = 0
self.error_message = ''
self.__hard_error: bool = False
self.__status: str = ''
self.__status_class: str = ''
@property
def pnp_flow(self) -> int:
......@@ -182,7 +183,7 @@ class Device:
self.__pnp_flow = pnp_flow
self.pnp_flow_readable = PNPFLOW.readable(pnp_flow)
if pnp_flow == PNPFLOW.FINISHED:
self.__status = 'finished'
self.__status_class = 'finished'
@property
def refresh_data(self) -> bool:
......@@ -204,7 +205,7 @@ class Device:
def error_code(self, error_code: int):
self.__error_code = error_code
self.error_code_readable = ERROR.readable(error_code)
self.__status = 'warning'
self.__status_class = 'warning'
@property
def hard_error(self) -> bool:
......@@ -213,15 +214,15 @@ class Device:
@hard_error.setter
def hard_error(self, hard_error: bool):
self.__hard_error = hard_error
self.__status = 'error'
self.__status_class = 'error'
@property
def status(self) -> str:
return self.__status
def status_class(self) -> str:
return self.__status_class
@status.setter
def status(self, status: str):
self.__status = status
@status_class.setter
def status_class(self, status_class: str):
self.__status_class = status_class
app = Flask(__name__, template_folder='./templates')
......@@ -281,35 +282,51 @@ def load_data():
global IMAGE_BASE_URL
global CONFIG_BASE_URL
config = ConfigParser()
config.read('open-pnp.ini')
IMAGE_DATA = config['settings'].get('IMAGE_DATA', 'images.json')
BIND_PNP_SERVER = config['settings'].get('BIND_PNP_SERVER', '0.0.0.0')
TIME_FORMAT = config['settings'].get('TIME_FORMAT', '%Y-%m-%dT%H:%M:%S')
LOG_FILE = config['settings'].get('LOG_FILE', 'log/pnp_debug.log')
IMAGE_BASE_URL = config['settings'].get('IMAGE_BASE_URL', '').rstrip('/')
CONFIG_BASE_URL = config['settings'].get('CONFIG_BASE_URL', '').rstrip('/')
#
PORT = config['settings'].get('PORT', '8080')
STATUS_REFRESH = config['settings'].get('STATUS_REFRESH', '60')
#
PORT = int(PORT) if PORT.isdigit() else 8080
STATUS_REFRESH = int(STATUS_REFRESH) if STATUS_REFRESH.isdigit() else 60
#
DEBUG = True if config['settings'].get('DEBUG', 'False') == 'True' else False
LOG_TO_FILE = True if config['settings'].get('LOG_TO_FILE', 'True') == 'True' else False
settings = {
'BIND_PNP_SERVER': '0.0.0.0',
'CONFIG_BASE_URL': '',
'DEBUG': False,
'IMAGE_BASE_URL': '',
'IMAGE_DATA': 'images.toml',
'LOG_FILE': 'log/pnp_debug.log',
'LOG_TO_FILE': True,
'PORT': 8080,
'STATUS_REFRESH': 60,
'TIME_FORMAT': '%Y-%m-%dT%H:%M:%S'
}
try:
with open(IMAGE_DATA, 'r') as f:
IMAGES = json_load(f)
with open(CFG_FILE, 'rb') as f:
settings.update(toml_load(f))
except FileNotFoundError as e:
print(f'ERROR: Data file {CFG_FILE} not found! ({e})')
exit(1)
except TOMLDecodeError as e:
print(f'ERROR: Data file {CFG_FILE} is not valid toml! ({e})')
exit(2)
BIND_PNP_SERVER = settings.get('BIND_PNP_SERVER')
PORT = settings.get('PORT')
TIME_FORMAT = settings.get('TIME_FORMAT')
STATUS_REFRESH = settings.get('STATUS_REFRESH')
DEBUG = settings.get('DEBUG')
LOG_TO_FILE = settings.get('LOG_TO_FILE')
LOG_FILE = settings.get('LOG_FILE')
IMAGE_DATA = settings.get('IMAGE_DATA')
IMAGE_BASE_URL = settings.get('IMAGE_BASE_URL').rstrip('/')
CONFIG_BASE_URL = settings.get('CONFIG_BASE_URL').rstrip('/')
try:
with open(IMAGE_DATA, 'rb') as f:
IMAGES = toml_load(f)
except FileNotFoundError as e:
print(f'ERROR: Data file {IMAGE_DATA} not found! ({e})')
exit(1)
except JSONDecodeError as e:
print(f'ERROR: Data file {IMAGE_DATA} is not valid json! ({e})')
except TOMLDecodeError as e:
print(f'ERROR: Data file {IMAGE_DATA} is not valid toml! ({e})')
exit(2)
def pnp_device_info(udi: str, correlator: str, info_type: str) -> str:
# info_type can be one of:
# image, hardware, filesystem, udi, profile, all
......@@ -350,7 +367,7 @@ def pnp_backoff(udi: str, correlator: str, minutes: Optional[int] = 1) -> str:
# will not be used as we remove PNP via EEM. PNP terminate is missing a "write mem"
def pnp_backoff_terminate(udi: str, correlator: str) -> str:
device = devices[udi]
device.status = f'finished'
# device.status_class = f'finished'
device.pnp_flow = PNPFLOW.FINISHED
device.current_job = 'urn:cisco:pnp:backoff-terminate'
jinja_context = {
......@@ -448,7 +465,7 @@ def create_new_device(udi: str, src_add: str):
size=image_data['size']
)
if not device.target_image:
device.error_code = ERROR.ERROR_NO_IMAGE
device.error_code = ERROR.ERROR_NO_PLATFORM
device.hard_error = True
......@@ -486,17 +503,11 @@ def check_update(udi: str):
def get_local_ip_addresses() -> List[str]:
_addresses = []
for iface_name in interfaces():
try:
for _address in ifaddresses(iface_name).setdefault(AF_INET):
_addresses.append(_address['addr'])
except TypeError:
pass
try:
for _address in ifaddresses(iface_name).setdefault(AF_INET6):
_addresses.append(_address['addr'])
except TypeError: # if no ip address in interface ifaddresses(iface_name) comes back with None
pass
adapters = get_adapters()
for adapter in adapters:
if adapter.nice_name not in ['lo']:
for ip in adapter.ips:
_addresses.append(ip.ip)
return _addresses
......@@ -570,15 +581,15 @@ def pnp_work_request():
device.last_contact = strftime(TIME_FORMAT)
device.ip_address = src_add
if device.hard_error:
return Response(pnp_backoff(udi, correlator, 59), mimetype='text/xml')
return Response(pnp_backoff(udi, correlator, 10), mimetype='text/xml')
pass
if device.backoff:
if DEBUG:
log_info('BACKOFF')
# backoff more and more on errors, max error_count = 11 -> 5 * 11 = 55
# error_count == 12 -> like hard_error
minutes = min((device.error_count * 5), 57) + 2
if minutes > 57:
minutes = device.error_count + 1
if minutes > 10:
device.hard_error = True
return Response(pnp_backoff(udi, correlator, minutes), mimetype='text/xml')
if device.pnp_flow == PNPFLOW.NEW:
......@@ -604,7 +615,7 @@ def pnp_work_request():
log_info('PNPFLOW.CONFIG_DOWN')
return Response(pnp_backoff_terminate(udi, correlator), mimetype='text/xml')
if DEBUG:
log_info(f'Other PNP_FLOW: {device.pnp_flow}')
log_info(f'Other PNP_FLOW: {PNPFLOW.readable(device.pnp_flow)}')
return Response('', 200)
else:
if DEBUG:
......@@ -699,13 +710,13 @@ if __name__ == '__main__':
print(f'Image file(s) base URL : {IMAGE_BASE_URL}')
print(f'Config file(s) base URL : {CONFIG_BASE_URL}')
print()
if _netifaces:
print('The PnP server is running on the following URL(s)')
if BIND_PNP_SERVER in ['0.0.0.0', '::']:
addresses = get_local_ip_addresses()
for address in addresses:
print(f' http://{address}:{PORT}')
else:
print(f'Status page running on : http://{BIND_PNP_SERVER}:{PORT}')
print()
print('The PnP server is running on the following URL(s)')
if BIND_PNP_SERVER in ['0.0.0.0', '::']:
addresses = get_local_ip_addresses()
for address in addresses:
print(f' http://{address}:{PORT}')
else:
print(f'Status page running on : http://{BIND_PNP_SERVER}:{PORT}')
print()
print()
app.run(host=BIND_PNP_SERVER, port=PORT)
# [settings]
# BIND_PNP_SERVER = "0.0.0.0"
# BIND_PNP_SERVER = "::"
# PORT = 8080
# TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
STATUS_REFRESH = 10
# DEBUG = false
# LOG_TO_FILE = true
# LOG_FILE = "log/pnp_debug.log"
# IMAGE_DATA = "images.json"
IMAGE_BASE_URL = "http://192.168.10.133:8080/images"
CONFIG_BASE_URL = "http://192.168.10.133:8080/configs"
certifi==2022.12.7
charset-normalizer==2.1.1
charset-normalizer==3.0.1
click==8.1.3
Flask==2.2.2
idna==3.4
importlib-metadata==5.1.0
importlib-metadata==6.0.0
ipaddr==2.2.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
netifaces==0.11.0
python-dotenv==0.21.0
requests==2.28.1
urllib3==1.26.13
MarkupSafe==2.1.2
pkg_resources==0.0.0
requests==2.28.2
typing_extensions==4.4.0
urllib3==1.26.14
Werkzeug==2.2.2
xmltodict==0.13.0
zipp==3.11.0
......@@ -3,8 +3,6 @@
<request xmlns="urn:cisco:pnp:backoff" correlator="{{ correlator }}">
<backoff>
<reason>backoffNow</reason>
<!-- <defaultMinutes>{{ minutes }}</defaultMinutes>-->
<!-- <terminate/>-->
<callbackAfter>
<seconds>{{ seconds }}</seconds>
<minutes>{{ minutes }}</minutes>
......
......@@ -4,6 +4,7 @@
<meta http-equiv="refresh" content="{{ refresh }}">
<style>
body {background-color: rgb(141, 133, 133);}
h1 { text-align: center;}
table { border-spacing: 0; width: 100%}
tr:nth-child(even) { background-color: #D6EEEE; }
th {
......@@ -26,8 +27,6 @@
background-color: #7cfc00;
}
input { width: 70px; }
</style>
</head>
<body>
......@@ -76,7 +75,7 @@
<input type="submit" value="Remove" name="{{ device.udi }}"/>
</form>
</td>
<td class="{{ device.status}}">{{ device.serial }}</td>
<td class="{{ device.status_class }}">{{ device.serial }}</td>
<td>{{ device.platform }}</td>
<td>{{ device.hw_rev }}</td>
<td>{{ device.ip_address }}</td>
......
......@@ -7,6 +7,7 @@
body {
background-color: rgb(141, 133, 133);
}
h1 { text-align: center;}
table {
border-spacing: 0;
......@@ -92,7 +93,7 @@
<input type="submit" value="Remove" name="{{ device.udi }}" />
</form>
</td>
<td class="{{ device.status}}"><a href="{{ config_base_url }}/{{ device.serial }}.cfg" target="_blank">{{
<td class="{{ device.status_class }}"><a href="{{ config_base_url }}/{{ device.serial }}.cfg" target="_blank">{{
device.serial }}</a></td>
<td>{{ device.platform }}</td>
<td>{{ device.hw_rev }}</td>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment