Config: add stuff to handle just-try mode in ConfigurableObject class

This commit is contained in:
Benjamin Renard 2023-06-19 17:07:59 +02:00
parent 72877dd13e
commit f597164305
Signed by: bn8
GPG key ID: 3E2E1CE1907115BC
8 changed files with 135 additions and 76 deletions

View file

@ -1107,7 +1107,9 @@ class ConfigurableObject:
# Default options value # Default options value
# Important: all supported options MUST HAVE a default value defined # Important: all supported options MUST HAVE a default value defined
_defaults = {} _defaults = {
"just_try": None,
}
# Store options passed throuht __init__ method # Store options passed throuht __init__ method
_kwargs = {} _kwargs = {}
@ -1166,25 +1168,93 @@ class ConfigurableObject:
for option, default_value in default_values.items(): for option, default_value in default_values.items():
self.set_default(option, default_value) self.set_default(option, default_value)
def configure(self, comment=None, **kwargs): def configure(
"""Configure options on registered mylib.Config object""" self,
comment=None,
just_try=False,
just_try_default=False,
just_try_help="Just-try mode",
**kwargs,
):
"""
Configure options on registered mylib.Config object
:param comment: Configuration section comment (default: self._config_comment)
:param just_try: Add just-try mode option (default: False)
:param just_try_default: Default just-try mode option value (default: False)
:param just_try_help: Default just-try mode option help message (default: "Just-try mode")
:param kwargs: Other provided parameters are directly passed to Config.add_section() method
"""
assert self._config, ( assert self._config, (
"mylib.Config object not registered. Must be passed to __init__ as config keyword" "mylib.Config object not registered. Must be passed to __init__ as config keyword"
" argument." " argument."
) )
return self._config.add_section( section = self._config.add_section(
self._config_section, self._config_section,
comment=comment if comment else self._config_comment, comment=comment if comment else self._config_comment,
loaded_callback=self.initialize, loaded_callback=self.initialize,
**kwargs, **kwargs,
) )
if just_try:
self._defaults["just_try"] = just_try_default
section.add_option(
BooleanOption,
"just_try",
default=self._defaults["just_try"],
comment=just_try_help if just_try_help else "Just-try mode",
)
return section
def initialize(self, loaded_config=None): def initialize(self, loaded_config=None):
"""Configuration initialized hook""" """Configuration initialized hook"""
if loaded_config: if loaded_config:
self.config = loaded_config # pylint: disable=attribute-defined-outside-init self.config = loaded_config # pylint: disable=attribute-defined-outside-init
@property
def _just_try(self):
"""Check if just-try mode is enabled"""
# If "just_try" provided to constructor, use it value
if "just_try" in self._kwargs:
log.debug(
"Just-try mode is %s by value passed to constructor",
"enabled" if self._kwargs["just_try"] else "disabled",
)
return self._kwargs["just_try"]
# If options provided and just-try option exist and is enabled, just-try mode enabled
if (
self._options
and hasattr(self._options, f"{self._options_prefix}just_try")
and getattr(self._options, f"{self._options_prefix}just_try")
):
log.debug("Just-try mode for %s is enabled", __class__.__name__)
return True
# If options provided and a just_try option exist and is enabled, just-try mode enabled
if (
self._options
and hasattr(self._options, "just_try")
and getattr(self._options, "just_try")
):
log.debug("Just-try mode is globally enabled")
return True
# If Config provided, config section defined and just-try enabled in config, just-try mode
# enabled
if (
self._config
and self._config.defined(self._config_section, "just_try")
and self._config.get(self._config_section, "just_try")
):
log.debug("Just-try mode for %s is enabled in configuration", self._config_section)
return True
# If Config provided, use it's get_option() method to obtain a global just_try parameter
# value with a defaut to False, otherwise always false
return self._config.get_option("just_try", default=False) if self._config else False
class ConfigSectionAsDictWrapper: class ConfigSectionAsDictWrapper:
""" """

View file

@ -60,9 +60,12 @@ class EmailClient(
self.initialize() self.initialize()
# pylint: disable=arguments-differ,arguments-renamed # pylint: disable=arguments-differ,arguments-renamed
def configure(self, use_smtp=True, just_try=True, **kwargs): def configure(self, use_smtp=True, **kwargs):
"""Configure options on registered mylib.Config object""" """Configure options on registered mylib.Config object"""
section = super().configure(**kwargs) section = super().configure(
just_try_help=kwargs.pop("just_try_help", "Just-try mode: do not really send emails"),
**kwargs,
)
if use_smtp: if use_smtp:
section.add_option( section.add_option(
@ -132,14 +135,6 @@ class EmailClient(
comment="Catch all sent emails to this specified email address", comment="Catch all sent emails to this specified email address",
) )
if just_try:
section.add_option(
BooleanOption,
"just_try",
default=self._defaults["just_try"],
comment="Just-try mode: do not really send emails",
)
section.add_option( section.add_option(
StringOption, StringOption,
"templates_path", "templates_path",
@ -302,7 +297,7 @@ class EmailClient(
return msg return msg
def send( def send(
self, recipients, msg=None, subject=None, just_try=False, cc=None, bcc=None, **forge_args self, recipients, msg=None, subject=None, just_try=None, cc=None, bcc=None, **forge_args
): ):
""" """
Send an email Send an email
@ -350,7 +345,7 @@ class EmailClient(
] ]
) )
if just_try or self._get_option("just_try"): if just_try if just_try is not None else self._just_try:
log.debug( log.debug(
'Just-try mode: do not really send this email to %s (subject="%s")', 'Just-try mode: do not really send this email to %s (subject="%s")',
", ".join(recipients), ", ".join(recipients),

View file

@ -19,6 +19,7 @@ class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
"subject": "Report", "subject": "Report",
"loglevel": "WARNING", "loglevel": "WARNING",
"logformat": "%(asctime)s - %(levelname)s - %(message)s", "logformat": "%(asctime)s - %(levelname)s - %(message)s",
"just_try": False,
} }
content = [] content = []
@ -37,7 +38,10 @@ class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
def configure(self, **kwargs): # pylint: disable=arguments-differ def configure(self, **kwargs): # pylint: disable=arguments-differ
"""Configure options on registered mylib.Config object""" """Configure options on registered mylib.Config object"""
section = super().configure(**kwargs) section = super().configure(
just_try_help=kwargs.pop("just_try_help", "Just-try mode: do not really send report"),
**kwargs,
)
section.add_option(StringOption, "recipient", comment="Report recipient email address") section.add_option(StringOption, "recipient", comment="Report recipient email address")
section.add_option( section.add_option(
@ -97,7 +101,7 @@ class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
"""Add attachment payload""" """Add attachment payload"""
self._attachment_payloads.append(payload) self._attachment_payloads.append(payload)
def send(self, subject=None, rcpt_to=None, email_client=None, just_try=False): def send(self, subject=None, rcpt_to=None, email_client=None, just_try=None):
"""Send report using an EmailClient""" """Send report using an EmailClient"""
if rcpt_to is None: if rcpt_to is None:
rcpt_to = self._get_option("recipient") rcpt_to = self._get_option("recipient")
@ -124,7 +128,9 @@ class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
attachment_files=self._attachment_files, attachment_files=self._attachment_files,
attachment_payloads=self._attachment_payloads, attachment_payloads=self._attachment_payloads,
) )
if email_client.send(rcpt_to, msg=msg, just_try=just_try): if email_client.send(
rcpt_to, msg=msg, just_try=just_try if just_try is not None else self._just_try
):
log.debug("Report sent to %s", rcpt_to) log.debug("Report sent to %s", rcpt_to)
return True return True
log.error("Fail to send report to %s", rcpt_to) log.error("Fail to send report to %s", rcpt_to)

View file

@ -22,7 +22,7 @@ def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
"templates_path", "templates_path",
os.path.join(os.path.dirname(os.path.realpath(__file__)), "email_templates"), os.path.join(os.path.dirname(os.path.realpath(__file__)), "email_templates"),
) )
email_client.configure() email_client.configure(just_try=True)
# Options parser # Options parser
parser = config.get_arguments_parser(description=__doc__) parser = config.get_arguments_parser(description=__doc__)

View file

@ -240,23 +240,7 @@ def init_email_client(options, **kwargs):
from mylib.email import EmailClient # pylint: disable=import-outside-toplevel from mylib.email import EmailClient # pylint: disable=import-outside-toplevel
log.info("Initialize Email client") log.info("Initialize Email client")
return EmailClient( return EmailClient(options=options, initialize=True, **kwargs)
smtp_host=options.email_smtp_host,
smtp_port=options.email_smtp_port,
smtp_ssl=options.email_smtp_ssl,
smtp_tls=options.email_smtp_tls,
smtp_user=options.email_smtp_user,
smtp_password=options.email_smtp_password,
smtp_debug=options.email_smtp_debug,
sender_name=options.email_sender_name,
sender_email=options.email_sender_email,
catch_all_addr=options.email_catch_all,
just_try=options.just_try if hasattr(options, "just_try") else False,
encoding=options.email_encoding,
templates_path=options.email_templates_path,
initialize=True,
**kwargs,
)
def add_sftp_opts(parser): def add_sftp_opts(parser):

View file

@ -20,16 +20,21 @@ def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
report_opts = parser.add_argument_group("Report options") report_opts = parser.add_argument_group("Report options")
report_opts.add_argument( report_opts.add_argument(
"-t", "--to", action="store", type=str, dest="report_rcpt", help="Send report to this email" "-t",
"--to",
action="store",
type=str,
dest="report_recipient",
help="Send report to this email",
) )
options = parser.parse_args() options = parser.parse_args()
if not options.report_rcpt: if not options.report_recipient:
parser.error("You must specify a report recipient using -t/--to parameter") parser.error("You must specify a report recipient using -t/--to parameter")
# Initialize logs # Initialize logs
report = Report(rcpt_to=options.report_rcpt, subject="Test report") report = Report(options=options, subject="Test report")
init_logging(options, "Test Report", report=report) init_logging(options, "Test Report", report=report)
email_client = init_email_client(options) email_client = init_email_client(options)

View file

@ -43,7 +43,7 @@ def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
options.sftp_password = getpass.getpass("Please enter SFTP password: ") options.sftp_password = getpass.getpass("Please enter SFTP password: ")
log.info("Initialize Email client") log.info("Initialize Email client")
sftp = SFTPClient(options=options, just_try=options.just_try) sftp = SFTPClient(options=options)
sftp.connect() sftp.connect()
atexit.register(sftp.close) atexit.register(sftp.close)
@ -74,30 +74,31 @@ def main(argv=None): # pylint: disable=too-many-locals,too-many-statements
else os.path.basename(tmp_file) else os.path.basename(tmp_file)
) )
with tempfile.NamedTemporaryFile() as tmp_file2: if not sftp._just_try: # pylint: disable=protected-access
log.info("Retrieve test file to %s", tmp_file2.name) with tempfile.NamedTemporaryFile() as tmp_file2:
if not sftp.get_file(remote_filepath, tmp_file2.name): log.info("Retrieve test file to %s", tmp_file2.name)
log.error("Fail to retrieve test file") if not sftp.get_file(remote_filepath, tmp_file2.name):
else: log.error("Fail to retrieve test file")
with open(tmp_file2.name, "rb") as file_desc: else:
content = file_desc.read() with open(tmp_file2.name, "rb") as file_desc:
log.debug("Read content: %s", content) content = file_desc.read()
if test_content == content: log.debug("Read content: %s", content)
log.info("Content file retrieved match with uploaded one") if test_content == content:
else: log.info("Content file retrieved match with uploaded one")
log.error("Content file retrieved doest not match with uploaded one") else:
log.error("Content file retrieved doest not match with uploaded one")
try: try:
log.info("Remotly open test file %s", remote_filepath) log.info("Remotly open test file %s", remote_filepath)
file_desc = sftp.open_file(remote_filepath) file_desc = sftp.open_file(remote_filepath)
content = file_desc.read() content = file_desc.read()
log.debug("Read content: %s", content) log.debug("Read content: %s", content)
if test_content == content: if test_content == content:
log.info("Content of remote file match with uploaded one") log.info("Content of remote file match with uploaded one")
else: else:
log.error("Content of remote file doest not match with uploaded one") log.error("Content of remote file doest not match with uploaded one")
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
log.exception("An exception occurred remotly opening test file %s", remote_filepath) log.exception("An exception occurred remotly opening test file %s", remote_filepath)
if sftp.remove_file(remote_filepath): if sftp.remove_file(remote_filepath):
log.info("Test file removed on SFTP server") log.info("Test file removed on SFTP server")

View file

@ -40,9 +40,15 @@ class SFTPClient(ConfigurableObject):
initial_directory = None initial_directory = None
# pylint: disable=arguments-differ,arguments-renamed # pylint: disable=arguments-differ,arguments-renamed
def configure(self, just_try=True, **kwargs): def configure(self, **kwargs):
"""Configure options on registered mylib.Config object""" """Configure options on registered mylib.Config object"""
section = super().configure(**kwargs) section = super().configure(
just_try=kwargs.pop("just_try", True),
just_try_help=kwargs.pop(
"just_try_help", "Just-try mode: do not really make change on remote SFTP host"
),
**kwargs,
)
section.add_option( section.add_option(
StringOption, StringOption,
@ -80,14 +86,6 @@ class SFTPClient(ConfigurableObject):
comment="Auto add unknown host key", comment="Auto add unknown host key",
) )
if just_try:
section.add_option(
BooleanOption,
"just_try",
default=self._defaults["just_try"],
comment="Just-try mode: do not really make change on remote SFTP host",
)
return section return section
def initialize(self, loaded_config=None): def initialize(self, loaded_config=None):
@ -141,7 +139,7 @@ class SFTPClient(ConfigurableObject):
os.path.basename(filepath), os.path.basename(filepath),
) )
log.debug("Upload file '%s' to '%s'", filepath, remote_filepath) log.debug("Upload file '%s' to '%s'", filepath, remote_filepath)
if self._get_option("just_try"): if self._just_try:
log.debug( log.debug(
"Just-try mode: do not really upload file '%s' to '%s'", filepath, remote_filepath "Just-try mode: do not really upload file '%s' to '%s'", filepath, remote_filepath
) )
@ -153,7 +151,7 @@ class SFTPClient(ConfigurableObject):
"""Remove a file on SFTP server""" """Remove a file on SFTP server"""
self.connect() self.connect()
log.debug("Remove file '%s'", filepath) log.debug("Remove file '%s'", filepath)
if self._get_option("just_try"): if self._just_try:
log.debug("Just - try mode: do not really remove file '%s'", filepath) log.debug("Just - try mode: do not really remove file '%s'", filepath)
return True return True
return self.sftp_client.remove(filepath) is None return self.sftp_client.remove(filepath) is None