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):
|
||||||
|
if args['configpath']:
|
||||||
|
print(f'MKTX config path: {config_handler.usr_conf_data_path}')
|
||||||
|
else:
|
||||||
for entryname in config_handler.registered_entries():
|
for entryname in config_handler.registered_entries():
|
||||||
|
if args['entry_name'] and entryname != args['entry_name']:
|
||||||
|
continue
|
||||||
entry = config_handler.entry(entryname)
|
entry = config_handler.entry(entryname)
|
||||||
|
print(f'[{entryname}]')
|
||||||
print('[{}]'.format(entryname))
|
divider_fields = set(['username', 'use_ssl', 'dhcp'])
|
||||||
for field in entry._fields:
|
for field in entry._fields:
|
||||||
print(' {}: {}'.format(field, getattr(entry, field)))
|
if field == 'password':
|
||||||
|
print(f' {field}: {"*" * len(entry.password)}')
|
||||||
|
else:
|
||||||
|
if field in divider_fields:
|
||||||
print()
|
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)
|
|
||||||
config_handler.register_entry(entry_name = entry_name, entry_info = entry_info)
|
|
||||||
|
|
||||||
|
|
||||||
def edit_entry(self, args):
|
def edit_entry(self, args):
|
||||||
pass
|
editor = args['editor']
|
||||||
|
if not editor:
|
||||||
|
print(f'No editor to edit the following file with: {config_handler.usr_conf_data_path}')
|
||||||
|
subprocess.check_call([editor, config_handler.usr_conf_data_path])
|
||||||
|
|
||||||
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