mirror of
				https://github.com/KevinMidboe/mktxp-no-cli.git
				synced 2025-10-29 17:50:23 +00:00 
			
		
		
		
	cli options
This commit is contained in:
		| @@ -84,7 +84,7 @@ class OSConfig(metaclass = ABCMeta): | |||||||
|             return OSXConfig() |             return OSXConfig() | ||||||
|         else: |         else: | ||||||
|             if not quiet: |             if not quiet: | ||||||
|                 print('Non-supported platform: {}'.format(sys.platform)) |                 print(f'Non-supported platform: {sys.platform}') | ||||||
|             return None |             return None | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
| @@ -136,7 +136,7 @@ class MKTXPConfigHandler: | |||||||
|  |  | ||||||
|     # MKTXP entries |     # MKTXP entries | ||||||
|     ############## |     ############## | ||||||
|     def register_entry(self, entry_name, entry_info, quiet = False): |     def register_entry(self, entry_name, entry_args, quiet = False): | ||||||
|         ''' Registers MKTXP conf entry |         ''' Registers MKTXP conf entry | ||||||
|         ''' |         ''' | ||||||
|         if entry_name in self.registered_entries(): |         if entry_name in self.registered_entries(): | ||||||
| @@ -144,8 +144,7 @@ class MKTXPConfigHandler: | |||||||
|                 print('"{0}": entry name already registered'.format(entry_name)) |                 print('"{0}": entry name already registered'.format(entry_name)) | ||||||
|             return False |             return False | ||||||
|         else: |         else: | ||||||
|             self.config[entry_name] = dict(entry_info._asdict()) |             self.config[entry_name] = entry_args | ||||||
|             print(f'adding entry: {self.config[entry_name]}') |  | ||||||
|             self.config.write() |             self.config.write() | ||||||
|             if not quiet: |             if not quiet: | ||||||
|                 print('Entry registered: {0}'.format(entry_name)) |                 print('Entry registered: {0}'.format(entry_name)) | ||||||
|   | |||||||
| @@ -13,8 +13,10 @@ | |||||||
| ## GNU General Public License for more details. | ## GNU General Public License for more details. | ||||||
|  |  | ||||||
| import sys | import sys | ||||||
|  | import subprocess | ||||||
| import pkg_resources | import pkg_resources | ||||||
| import mktxp.cli.checks.chk_pv | import mktxp.cli.checks.chk_pv | ||||||
|  | from mktxp.utils.utils import run_cmd | ||||||
| from mktxp.cli.options import MKTXPOptionsParser, MKTXPCommands | from mktxp.cli.options import MKTXPOptionsParser, MKTXPCommands | ||||||
| from mktxp.cli.config.config import config_handler, ConfigEntry | from mktxp.cli.config.config import config_handler, ConfigEntry | ||||||
| from mktxp.basep import MKTXPProcessor | from mktxp.basep import MKTXPProcessor | ||||||
| @@ -36,7 +38,7 @@ class MKTXPDispatcher: | |||||||
|             self.print_info() |             self.print_info() | ||||||
|  |  | ||||||
|         elif args['sub_cmd'] == MKTXPCommands.SHOW: |         elif args['sub_cmd'] == MKTXPCommands.SHOW: | ||||||
|             self.show_entries() |             self.show_entries(args) | ||||||
|  |  | ||||||
|         elif args['sub_cmd'] == MKTXPCommands.ADD: |         elif args['sub_cmd'] == MKTXPCommands.ADD: | ||||||
|             self.add_entry(args) |             self.add_entry(args) | ||||||
| @@ -61,40 +63,46 @@ class MKTXPDispatcher: | |||||||
|         ''' Prints MKTXP version info |         ''' Prints MKTXP version info | ||||||
|         ''' |         ''' | ||||||
|         version = pkg_resources.require("mktxp")[0].version |         version = pkg_resources.require("mktxp")[0].version | ||||||
|         print('Mikrotik RouterOS Prometheus Exporter version {}'.format(version)) |         print(f'Mikrotik RouterOS Prometheus Exporter version {version}') | ||||||
|  |  | ||||||
|     def print_info(self): |     def print_info(self): | ||||||
|         ''' Prints MKTXP general info |         ''' Prints MKTXP general info | ||||||
|         ''' |         ''' | ||||||
|         print('Mikrotik RouterOS Prometheus Exporter: {}'.format(self.option_parser.script_name)) |         print(f'{self.option_parser.script_name}: {self.option_parser.description}') | ||||||
|         print(self.option_parser.description) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     def show_entries(self): |     def show_entries(self, args): | ||||||
|         for entryname in config_handler.registered_entries(): |         if args['configpath']: | ||||||
|             entry = config_handler.entry(entryname) |             print(f'MKTX config path: {config_handler.usr_conf_data_path}') | ||||||
|  |         else: | ||||||
|             print('[{}]'.format(entryname)) |             for entryname in config_handler.registered_entries(): | ||||||
|             for field in entry._fields: |                 if args['entry_name'] and entryname != args['entry_name']: | ||||||
|                 print('    {}: {}'.format(field, getattr(entry, field))) |                     continue | ||||||
|             print() |                 entry = config_handler.entry(entryname) | ||||||
|  |                 print(f'[{entryname}]') | ||||||
|  |                 divider_fields = set(['username', 'use_ssl', 'dhcp']) | ||||||
|  |                 for field in entry._fields: | ||||||
|  |                     if field == 'password': | ||||||
|  |                         print(f'    {field}: {"*" * len(entry.password)}') | ||||||
|  |                     else: | ||||||
|  |                         if field in divider_fields: | ||||||
|  |                             print() | ||||||
|  |                         print(f'    {field}: {getattr(entry, field)}') | ||||||
|  |                 print('\n') | ||||||
|  |  | ||||||
|     def add_entry(self, args): |     def add_entry(self, args): | ||||||
|         args.pop('sub_cmd', None) |         entry_args = {key: value for key, value in args.items() if key not in set(['sub_cmd', 'entry_name'])} | ||||||
|         entry_name = args['entry_name'] |         config_handler.register_entry(entry_name = args['entry_name'], entry_args = entry_args) | ||||||
|         args.pop('entry_name', None) |  | ||||||
|  |  | ||||||
|         entry_info = ConfigEntry.MKTXPEntry(**args) |     def edit_entry(self, args):         | ||||||
|         config_handler.register_entry(entry_name = entry_name, entry_info = entry_info) |         editor = args['editor'] | ||||||
|  |         if not editor: | ||||||
|  |             print(f'No editor to edit the following file with: {config_handler.usr_conf_data_path}') | ||||||
|     def edit_entry(self, args): |         subprocess.check_call([editor, config_handler.usr_conf_data_path]) | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def delete_entry(self, args): |     def delete_entry(self, args): | ||||||
|         config_handler.unregister_entry(entry_name = args['entry_name']) |         config_handler.unregister_entry(entry_name = args['entry_name']) | ||||||
|          |          | ||||||
|  |  | ||||||
|     def start_export(self, args): |     def start_export(self, args): | ||||||
|         MKTXPProcessor.start() |         MKTXPProcessor.start() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
| import os | import os | ||||||
| from argparse import ArgumentParser, HelpFormatter | from argparse import ArgumentParser, HelpFormatter | ||||||
| from mktxp.cli.config.config import config_handler, MKTXPConfigKeys | from mktxp.cli.config.config import config_handler, MKTXPConfigKeys | ||||||
| from mktxp.utils.utils import FSHelper, UniquePartialMatchList | from mktxp.utils.utils import FSHelper, UniquePartialMatchList, run_cmd | ||||||
|  |  | ||||||
|  |  | ||||||
| class MKTXPCommands: | class MKTXPCommands: | ||||||
| @@ -29,13 +29,13 @@ class MKTXPCommands: | |||||||
|     @classmethod |     @classmethod | ||||||
|     def commands_meta(cls): |     def commands_meta(cls): | ||||||
|         return ''.join(('{', |         return ''.join(('{', | ||||||
|                         '{}, '.format(cls.INFO), |                         f'{cls.INFO}, ', | ||||||
|                         '{}'.format(cls.VERSION), |                         f'{cls.VERSION}, ', | ||||||
|                         '{}'.format(cls.SHOW), |                         f'{cls.SHOW}, ', | ||||||
|                         '{}'.format(cls.ADD), |                         f'{cls.ADD}, ', | ||||||
|                         '{}'.format(cls.EDIT), |                         f'{cls.EDIT}, ', | ||||||
|                         '{}'.format(cls.DELETE), |                         f'{cls.DELETE}, ', | ||||||
|                         '{}'.format(cls.START),                         |                         f'{cls.START}',                         | ||||||
|                         '}')) |                         '}')) | ||||||
|  |  | ||||||
| class MKTXPOptionsParser: | class MKTXPOptionsParser: | ||||||
| @@ -45,7 +45,8 @@ class MKTXPOptionsParser: | |||||||
|         self._script_name = 'MKTXP' |         self._script_name = 'MKTXP' | ||||||
|         self._description = \ |         self._description = \ | ||||||
|     ''' |     ''' | ||||||
|     Prometheus Exporter for Mikrotik RouterOS Devices |     Prometheus Exporter for Mikrotik RouterOS Devices. | ||||||
|  |  | ||||||
|     ''' |     ''' | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
| @@ -94,9 +95,13 @@ class MKTXPOptionsParser: | |||||||
|                                         formatter_class=MKTXPHelpFormatter) |                                         formatter_class=MKTXPHelpFormatter) | ||||||
|  |  | ||||||
|         # Show command |         # Show command | ||||||
|         subparsers.add_parser(MKTXPCommands.SHOW, |         show_parser = subparsers.add_parser(MKTXPCommands.SHOW, | ||||||
|                                         description = 'Displays MKTXP router entries', |                                         description = 'Displays MKTXP config router entries', | ||||||
|                                         formatter_class=MKTXPHelpFormatter) |                                         formatter_class=MKTXPHelpFormatter) | ||||||
|  |         self._add_entry_name(show_parser, registered_only = True, required = False, help = "Config entry name") | ||||||
|  |         show_parser.add_argument('-cp', '--configpath', dest='configpath', | ||||||
|  |                                         help = "Shows MKTXP config file path", | ||||||
|  |                                         action = 'store_true') | ||||||
|  |  | ||||||
|         # Add command |         # Add command | ||||||
|         add_parser = subparsers.add_parser(MKTXPCommands.ADD, |         add_parser = subparsers.add_parser(MKTXPCommands.ADD, | ||||||
| @@ -159,15 +164,14 @@ class MKTXPOptionsParser: | |||||||
|                 help = "Export CAPsMAN metrics", |                 help = "Export CAPsMAN metrics", | ||||||
|                 action = 'store_true') |                 action = 'store_true') | ||||||
|  |  | ||||||
| #'hostname', 'port', 'username', 'password', 'use_ssl', 'ssl_certificate', 'dhcp', 'dhcp_lease', 'pool', 'interface', 'monitor', 'route', 'wireless', and 'capsman' |  | ||||||
|  |  | ||||||
|         # Edit command |         # Edit command | ||||||
|         edit_parser = subparsers.add_parser(MKTXPCommands.EDIT, |         edit_parser = subparsers.add_parser(MKTXPCommands.EDIT, | ||||||
|                                         description = 'Edits an existing MKTXP router entry', |                                         description = 'Edits an existing MKTXP router entry', | ||||||
|                                         formatter_class=MKTXPHelpFormatter) |                                         formatter_class=MKTXPHelpFormatter) | ||||||
|         required_args_group = edit_parser.add_argument_group('Required Arguments') |         edit_parser.add_argument('-ed', '--editor', dest='editor', | ||||||
|         self._add_entry_name(required_args_group, registered_only = True, help = "Name of entry to edit")   |                 help = f"command line editor to use ({self._system_editor()} by default)", | ||||||
|  |                 default = self._system_editor(), | ||||||
|  |                 type = str)         | ||||||
|  |  | ||||||
|         # Delete command |         # Delete command | ||||||
|         delete_parser = subparsers.add_parser(MKTXPCommands.DELETE, |         delete_parser = subparsers.add_parser(MKTXPCommands.DELETE, | ||||||
| @@ -181,7 +185,6 @@ class MKTXPOptionsParser: | |||||||
|                                         description = 'Starts exporting Miktorik Router Metrics', |                                         description = 'Starts exporting Miktorik Router Metrics', | ||||||
|                                         formatter_class=MKTXPHelpFormatter) |                                         formatter_class=MKTXPHelpFormatter) | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Options checking |     # Options checking | ||||||
|     def _check_args(self, args, parser): |     def _check_args(self, args, parser): | ||||||
|         ''' Validation of supplied CLI arguments |         ''' Validation of supplied CLI arguments | ||||||
| @@ -189,13 +192,13 @@ class MKTXPOptionsParser: | |||||||
|         # check if there is a cmd to execute |         # check if there is a cmd to execute | ||||||
|         self._check_cmd_args(args, parser) |         self._check_cmd_args(args, parser) | ||||||
|  |  | ||||||
|         if args['sub_cmd'] in (MKTXPCommands.EDIT, MKTXPCommands.DELETE): |         if args['sub_cmd'] == MKTXPCommands.DELETE: | ||||||
|             # Registered Entry name could be a partial match, need to expand |             # Registered Entry name could be a partial match, need to expand | ||||||
|             args['entry_name'] = UniquePartialMatchList(config_handler.registered_entries()).find(args['entry_name']) |             args['entry_name'] = UniquePartialMatchList(config_handler.registered_entries()).find(args['entry_name']) | ||||||
|  |  | ||||||
|         if args['sub_cmd'] == MKTXPCommands.ADD: |         elif args['sub_cmd'] == MKTXPCommands.ADD: | ||||||
|             if args['entry_name'] in (config_handler.registered_entries()): |             if args['entry_name'] in (config_handler.registered_entries()): | ||||||
|                 print('"{0}": entry name already exists'.format(args['entry_name'])) |                 print(f"{args['entry_name']}: entry name already exists") | ||||||
|                 parser.exit() |                 parser.exit() | ||||||
|  |  | ||||||
|     def _check_cmd_args(self, args, parser): |     def _check_cmd_args(self, args, parser): | ||||||
| @@ -227,7 +230,7 @@ class MKTXPOptionsParser: | |||||||
|         ''' |         ''' | ||||||
|         path_arg = FSHelper.full_path(path_arg) |         path_arg = FSHelper.full_path(path_arg) | ||||||
|         if not (os.path.exists(path_arg) and os.path.isdir(path_arg)): |         if not (os.path.exists(path_arg) and os.path.isdir(path_arg)): | ||||||
|             parser.error('"{}" does not seem to be an existing directory path'.format(path_arg)) |             parser.error(f'"{path_arg}" does not seem to be an existing directory path') | ||||||
|         else: |         else: | ||||||
|             return path_arg |             return path_arg | ||||||
|  |  | ||||||
| @@ -237,16 +240,16 @@ class MKTXPOptionsParser: | |||||||
|         ''' |         ''' | ||||||
|         path_arg = FSHelper.full_path(path_arg) |         path_arg = FSHelper.full_path(path_arg) | ||||||
|         if not (os.path.exists(path_arg) and os.path.isfile(path_arg)): |         if not (os.path.exists(path_arg) and os.path.isfile(path_arg)): | ||||||
|             parser.error('"{}" does not seem to be an existing file path'.format(path_arg)) |             parser.error('"{path_arg}" does not seem to be an existing file path') | ||||||
|         else: |         else: | ||||||
|             return path_arg |             return path_arg | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _add_entry_name(parser, registered_only = False, help = 'MKTXP Entry name'): |     def _add_entry_name(parser, registered_only = False, required = True, help = 'MKTXP Entry name'): | ||||||
|         parser.add_argument('-en', '--entry-name', dest = 'entry_name', |         parser.add_argument('-en', '--entry-name', dest = 'entry_name', | ||||||
|             type = str, |             type = str, | ||||||
|             metavar = config_handler.registered_entries() if registered_only else None, |             metavar = config_handler.registered_entries() if registered_only else None, | ||||||
|             required = True, |             required = required, | ||||||
|             choices = UniquePartialMatchList(config_handler.registered_entries())if registered_only else None, |             choices = UniquePartialMatchList(config_handler.registered_entries())if registered_only else None, | ||||||
|             help = help) |             help = help) | ||||||
|  |  | ||||||
| @@ -255,6 +258,19 @@ class MKTXPOptionsParser: | |||||||
|         required_args_group = parser.add_argument_group('Required Arguments') |         required_args_group = parser.add_argument_group('Required Arguments') | ||||||
|         MKTXPOptionsParser._add_entry_name(required_args_group) |         MKTXPOptionsParser._add_entry_name(required_args_group) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def _system_editor(): | ||||||
|  |         editor = os.environ.get('EDITOR') | ||||||
|  |         if editor: | ||||||
|  |             return editor | ||||||
|  |  | ||||||
|  |         commands = ['which nano', 'which vi', 'which vim'] | ||||||
|  |         for command in commands: | ||||||
|  |             editor = run_cmd(command, quiet = True).rstrip() | ||||||
|  |             if editor: | ||||||
|  |                 break                                   | ||||||
|  |         return editor | ||||||
|  |  | ||||||
|  |  | ||||||
| class MKTXPHelpFormatter(HelpFormatter): | class MKTXPHelpFormatter(HelpFormatter): | ||||||
|     ''' Custom formatter for ArgumentParser |     ''' Custom formatter for ArgumentParser | ||||||
| @@ -284,4 +300,3 @@ class MKTXPHelpFormatter(HelpFormatter): | |||||||
|                 parts[-1] += ' %s'%args_string |                 parts[-1] += ' %s'%args_string | ||||||
|             return ', '.join(parts) |             return ', '.join(parts) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
|  |  | ||||||
| import ssl | import ssl | ||||||
| import socket | import socket | ||||||
|  | from datetime import datetime | ||||||
| from routeros_api import RouterOsApiPool | from routeros_api import RouterOsApiPool | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -28,7 +29,7 @@ class RouterAPIConnection: | |||||||
|         self.router_entry  = router_entry |         self.router_entry  = router_entry | ||||||
|          |          | ||||||
|         ctx = None |         ctx = None | ||||||
|         if not self.router_entry.ssl_certificate: |         if self.router_entry.use_ssl and not self.router_entry.ssl_certificate: | ||||||
|             ctx = ssl.create_default_context() |             ctx = ssl.create_default_context() | ||||||
|             ctx.set_ciphers('ADH:@SECLEVEL=0')        |             ctx.set_ciphers('ADH:@SECLEVEL=0')        | ||||||
|  |  | ||||||
| @@ -38,7 +39,7 @@ class RouterAPIConnection: | |||||||
|                 password = self.router_entry.password, |                 password = self.router_entry.password, | ||||||
|                 port = self.router_entry.port, |                 port = self.router_entry.port, | ||||||
|                 plaintext_login = True, |                 plaintext_login = True, | ||||||
|                 use_ssl = True, |                 use_ssl = self.router_entry.use_ssl, | ||||||
|                 ssl_context = ctx) |                 ssl_context = ctx) | ||||||
|          |          | ||||||
|         self.connection.socket_timeout = 2 |         self.connection.socket_timeout = 2 | ||||||
| @@ -58,12 +59,13 @@ class RouterAPIConnection: | |||||||
|     def connect(self): |     def connect(self): | ||||||
|         if self.is_connected(): |         if self.is_connected(): | ||||||
|             return |             return | ||||||
|  |         current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | ||||||
|         try: |         try: | ||||||
|             print('Connecting to router {0}@{1}'.format(self.router_name, self.router_entry.hostname)) |             print(f'Connecting to router {self.router_name}@{self.router_entry.hostname}') | ||||||
|             self.api = self.connection.get_api() |             self.api = self.connection.get_api() | ||||||
|             print('Connection to router {0}@{1} has been established'.format(self.router_name, self.router_entry.hostname)) |             print(f'{current_time} Connection to router {self.router_name}@{self.router_entry.hostname} has been established') | ||||||
|         except (socket.error, socket.timeout, Exception) as ex: |         except (socket.error, socket.timeout, Exception) as ex: | ||||||
|             print('Connection to router {0}@{1} has failed: {2}'.format(self.router_name, self.router_entry.hostname, ex)) |             print(f'{current_time} Connection to router {self.router_name}@{self.router_entry.hostname} has failed: {ex}') | ||||||
|             raise  |             raise  | ||||||
|  |  | ||||||
|     def router_api(self): |     def router_api(self): | ||||||
|   | |||||||
| @@ -39,14 +39,14 @@ def temp_dir(quiet = True): | |||||||
| class CmdProcessingError(Exception): | class CmdProcessingError(Exception): | ||||||
|     pass |     pass | ||||||
|  |  | ||||||
| def run_cmd(cmd, shell = False): | def run_cmd(cmd, shell = False, quiet = False): | ||||||
|     ''' Runs shell commands in a separate process |     ''' Runs shell commands in a separate process | ||||||
|     ''' |     ''' | ||||||
|     if not shell: |     if not shell: | ||||||
|         cmd = shlex.split(cmd) |         cmd = shlex.split(cmd) | ||||||
|     proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell = shell) |     proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell = shell) | ||||||
|     output = proc.communicate()[0].decode('utf-8') |     output = proc.communicate()[0].decode('utf-8') | ||||||
|     if proc.returncode != 0: |     if proc.returncode != 0 and not quiet: | ||||||
|         raise CmdProcessingError(output) |         raise CmdProcessingError(output) | ||||||
|     return output |     return output | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user