From 916f885ae433cf71166463af729ef2891dd1d557 Mon Sep 17 00:00:00 2001
From: Thl CMK <thl-cmk@outlook.com>
Date: Thu, 23 Feb 2023 22:03:01 +0100
Subject: [PATCH] adds -v/--default_cfg options

---
 pnp/configs/DEFAULT.cfg                 | 48 ++++++++++++++-----------
 pnp/configs/DEFAULT_REMOVE_INACTIVE.cfg | 24 +++++++++++++
 pnp/open-pnp.py                         | 42 +++++++++++++++-------
 pnp/open-pnp.toml                       |  1 +
 pnp/templates/status.html               |  2 +-
 5 files changed, 84 insertions(+), 33 deletions(-)
 create mode 100644 pnp/configs/DEFAULT_REMOVE_INACTIVE.cfg

diff --git a/pnp/configs/DEFAULT.cfg b/pnp/configs/DEFAULT.cfg
index 3643f1f..8aab374 100644
--- a/pnp/configs/DEFAULT.cfg
+++ b/pnp/configs/DEFAULT.cfg
@@ -1,24 +1,32 @@
 version 17.6
 
-event manager applet remove_inactive authorization bypass
-  description remove inactive firmware after reload, rest-config
-  event timer cron cron-entry "@reboot" maxrun 600 name REMOVE-INACTIVE
-  ! event timer countdown time 60 maxrun 600 name REMOVE-INACTIVE
-  action 0000.00 cli command "enable"
-  action 0000.10 syslog facility "EEM" msg "remove inactive images"
-  action 0000.15 cli command "terminal length 0"
-  action 0000.20 cli command "terminal width 0"
-  !
-  action 0010.00 syslog facility "EEM" msg "reset configuration (no reload) START"
-  action 0010.10 cli command "pnp service reset no-reload" pattern "\[yes/no\]"
-  action 0010.15 cli command "y"
-  action 0010.99 syslog facility "EEM" msg "reset configuration (no reload) DONE"
-  !
-  action 0020.00 syslog facility "EEM" msg "remove inactive images start"
-  action 0020.05 cli command "install remove inactive" pattern "\[y/n\]"
-  action 0020.10 cli command "y"
-  action 0020.99 syslog facility "EEM" msg "remove inactive images done"
-  !
-exit
+aaa new-model
+username admin privilege 15  algorithm-type scrypt secret admin
 
+aaa authentication login default local
+aaa authorization exec default local
+aaa authorization console
+
+crypto key generate rsa modulus 4096 label SSH-KEY
+ip ssh version 2
+ip ssh rsa keypair-name SSH-KEY
+
+interface gi0/0/0
+ no ip dhcp client client-id
+ ip address dhcp
+ no shutdown
+!
+interface vlan 1
+ ip address dhcp
+ no shutdown
+!
+line con 0
+  logging synchronous
+  width 0
+!
+line vty 0 15
+  logging synchronous
+  width 0
+  transport input ssh
+!
 end
diff --git a/pnp/configs/DEFAULT_REMOVE_INACTIVE.cfg b/pnp/configs/DEFAULT_REMOVE_INACTIVE.cfg
new file mode 100644
index 0000000..3643f1f
--- /dev/null
+++ b/pnp/configs/DEFAULT_REMOVE_INACTIVE.cfg
@@ -0,0 +1,24 @@
+version 17.6
+
+event manager applet remove_inactive authorization bypass
+  description remove inactive firmware after reload, rest-config
+  event timer cron cron-entry "@reboot" maxrun 600 name REMOVE-INACTIVE
+  ! event timer countdown time 60 maxrun 600 name REMOVE-INACTIVE
+  action 0000.00 cli command "enable"
+  action 0000.10 syslog facility "EEM" msg "remove inactive images"
+  action 0000.15 cli command "terminal length 0"
+  action 0000.20 cli command "terminal width 0"
+  !
+  action 0010.00 syslog facility "EEM" msg "reset configuration (no reload) START"
+  action 0010.10 cli command "pnp service reset no-reload" pattern "\[yes/no\]"
+  action 0010.15 cli command "y"
+  action 0010.99 syslog facility "EEM" msg "reset configuration (no reload) DONE"
+  !
+  action 0020.00 syslog facility "EEM" msg "remove inactive images start"
+  action 0020.05 cli command "install remove inactive" pattern "\[y/n\]"
+  action 0020.10 cli command "y"
+  action 0020.99 syslog facility "EEM" msg "remove inactive images done"
+  !
+exit
+
+end
diff --git a/pnp/open-pnp.py b/pnp/open-pnp.py
index b5c5667..33a9712 100755
--- a/pnp/open-pnp.py
+++ b/pnp/open-pnp.py
@@ -32,9 +32,12 @@
 #             cleanup: removed global variables
 # 2023-02-22: removed regex -> was not working with PID: ISR4451-X/K9
 #             added PNP_SERVER_VERSION
-#
+# 2023-02-23: added cli option -v/--version, --default_cfg
+
 # pip install flask xmltodict requests ifaddr tomli
 #
+# ToDo:
+#       add remove inactive job on IOS-XE devices if no space for image update
 
 # system libs
 import logging
@@ -57,13 +60,14 @@ from ifaddr import get_adapters
 from tomli import load as toml_load
 from tomli import TOMLDecodeError
 
-PNP_SERVER_VERSION = '20230222.v1.0.0'
+PNP_SERVER_VERSION = '20230223.v1.0.1'
 
 
 class Settings:
     def __init__(
             self,
             cli_args: Dict[str, any],
+            version: bool = False,
             cfg_file: Optional[str] = 'open-pnp.toml',
             image_data: Optional[str] = 'images.toml',
             bind_pnp_server: Optional[str] = '0.0.0.0',
@@ -75,10 +79,11 @@ class Settings:
             log_file: Optional[str] = 'log/pnp_debug.log',
             image_url: Optional[str] = '',
             config_url: Optional[str] = '',
-            default_cfg_file: Optional[str] = 'DEFAULT.cfg',
+            default_cfg: Optional[str] = 'DEFAULT.cfg',
     ):
         self.__settings = {
             'cfg_file': cfg_file,
+            'version': version,
             'image_data': image_data,
             'bind_pnp_server': bind_pnp_server,
             'port': port,
@@ -89,7 +94,7 @@ class Settings:
             'log_file': log_file,
             'image_url': image_url,
             'config_url': config_url,
-            'default_cfg_file': default_cfg_file,
+            'default_cfg_file': default_cfg,
         }
         self.__args = {}
         self.__set_cli_args(cli_args)
@@ -115,6 +120,10 @@ class Settings:
     def cfg_file(self) -> str:
         return self.__settings['cfg_file']
 
+    @property
+    def version(self) -> bool:
+        return self.__settings['version']
+
     @property
     def image_data(self) -> str:
         return self.__settings['image_data']
@@ -156,8 +165,8 @@ class Settings:
         return self.__settings['config_url']
 
     @property
-    def default_cfg_file(self) -> str:
-        return self.__settings['default_cfg_file']
+    def default_cfg(self) -> str:
+        return self.__settings['default_cfg']
 
 
 class SoftwareImage:
@@ -391,8 +400,7 @@ def parse_arguments() -> arg_Namespace:
         description='This is a basic implementation of the Cisco PnP protocol. It is intended to'
                     '\nroll out image updates and configurations for Cisco IOS/IOS-XE devices on day0.'
                     '\n'
-                    f'\nVersion: {PNP_SERVER_VERSION}'
-                    ', Written by: thl-cmk, for more information see: https://thl-cmk.hopto.org',
+                    f'\n{PNP_SERVER_VERSION} | Written by: thl-cmk, for more information see: https://thl-cmk.hopto.org',
         formatter_class=RawTextHelpFormatter,
         epilog='Usage: python open-pnp.py --config_url  http://192.168.10.133:8080/configs '
                '--image_url http://192.168.10.133:8080/images',
@@ -403,6 +411,8 @@ def parse_arguments() -> arg_Namespace:
                         help='TCP port to listen on. (default: 8080)')
     parser.add_argument('-r', '--status_refresh', type=int,
                         help='Time in seconds to refresh PnP server status page. (default: 60)')
+    parser.add_argument('-v', '--version', default=False, action='store_const', const=True,
+                        help='Print open-pnp-server version and exit')
     parser.add_argument('--config_file', type=str,
                         help='Path/name of open PnP server config file. (default: open-pnp.toml)')
     parser.add_argument('--config_url', type=str,
@@ -411,11 +421,13 @@ def parse_arguments() -> arg_Namespace:
                         help='File containing the image description. (default: images.toml)')
     parser.add_argument('--image_url', type=str,
                         help='Download URL for image files. I.e. http://192.168.10.133:8080/images')
-    parser.add_argument('--debug', default=False, action="store_const", const=True,
+    parser.add_argument('--debug', default=False, action='store_const', const=True,
                         help='Enable Debug output send to "log_file".')
+    parser.add_argument('--default_cfg', type=str,
+                        help='default config to use if no device specific config is found. (default: DEFAULT.cfg)')
     parser.add_argument('--log_file', type=str,
                         help='Path/name of the logfile. (default: log/pnp_debug.log, requires --debug) ')
-    parser.add_argument('--log_to_console', default=False, action="store_const", const=True,
+    parser.add_argument('--log_to_console', default=False, action='store_const', const=True,
                         help='Enable debug output send to stdout (requires --debug).')
     parser.add_argument('--time_format', type=str,
                         help='Format string to render time. (default: %%Y-%%m-%%dT%%H:%%M:%%S)')
@@ -503,7 +515,7 @@ def pnp_config_upgrade(udi: str, correlator: str) -> Optional[str]:
     cfg_file = f'{device.serial}.cfg'
     response = head(f'{SETTINGS.config_url}/{cfg_file}')
     if response.status_code != 200:  # SERIAL.cfg not found
-        cfg_file = SETTINGS.default_cfg_file
+        cfg_file = SETTINGS.default_cfg
         response = head(f'{SETTINGS.config_url}/{cfg_file}')
         if response.status_code != 200:  # DEFAULT.cfg also not found
             device.error_code = ERROR.ERROR_NO_CFG_FILE
@@ -797,6 +809,11 @@ if __name__ == '__main__':
     PNPFLOW = PnpFlow()
     SETTINGS = Settings(vars(parse_arguments()))
     SETTINGS.update(SETTINGS.cfg_file)
+
+    if SETTINGS.version:
+        print(PNP_SERVER_VERSION)
+        exit(0)
+
     IMAGES = Images(SETTINGS.image_data)
 
     devices: Dict[str, Device] = {}
@@ -835,6 +852,7 @@ if __name__ == '__main__':
     else:
         print(f'Status page running on : http://{SETTINGS.bind_pnp_server}:{SETTINGS.port}')
     print()
-    print(f'Writen by thl-cmk, see https://thl-cmk.hopto.org/gitlab/bits-and-bytes/cisco_day0_provision')
+    print(f'{PNP_SERVER_VERSION} | '
+          f'Written by thl-cmk, see https://thl-cmk.hopto.org/gitlab/bits-and-bytes/cisco_day0_provision')
     print()
     app.run(host=SETTINGS.bind_pnp_server, port=SETTINGS.port)
diff --git a/pnp/open-pnp.toml b/pnp/open-pnp.toml
index 2f0fcde..16d301f 100644
--- a/pnp/open-pnp.toml
+++ b/pnp/open-pnp.toml
@@ -11,3 +11,4 @@
 # image_data = "images.toml"
 # image_url = "http://192.168.10.133:8080/images"
 # config_url = "http://192.168.10.133:8080/configs"
+# default_cfg = "DEFAULT.cfg"
\ No newline at end of file
diff --git a/pnp/templates/status.html b/pnp/templates/status.html
index 9425757..5d43f80 100644
--- a/pnp/templates/status.html
+++ b/pnp/templates/status.html
@@ -214,7 +214,7 @@
         </div>
         <div class="footer">
             <footer>
-                <p>Version: {{pnp_server_version}} | Written by: <a href="mailto:thl-cmk@outlook.com?subject=About your PnP server“,">thl-cmk</a> | Date: 2022-12-10 | for more information see <a href="https://thl-cmk.hopto.org/gitlab/bits-and-bytes/cisco_day0_provision" target="_blank">Cisco Day0 provisioning</a></p>
+                <p>{{pnp_server_version}} | Written by: <a href="mailto:thl-cmk@outlook.com?subject=About your PnP server“,">thl-cmk</a> | for more information see <a href="https://thl-cmk.hopto.org/gitlab/bits-and-bytes/cisco_day0_provision" target="_blank">Cisco Day0 provisioning</a></p>
             </footer>
             <div class="reload_cfg">
                 <form class="reload_cfg" method="post" action="/buttons">
-- 
GitLab