mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 23:37:18 +00:00
restore behavior of the httploghandler
This commit is contained in:
parent
c83936d4d9
commit
7d7fd691b4
@ -20,6 +20,14 @@ ahriman.core.configuration.schema module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.configuration.shell\_interpolator module
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.configuration.shell_interpolator
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.core.configuration.validator module
|
ahriman.core.configuration.validator module
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
|
@ -84,6 +84,14 @@ ahriman.core.database.migrations.m009\_local\_source module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m010\_version\_based\_logs\_removal module
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m010_version_based_logs_removal
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ _shtab_ahriman_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
|
|||||||
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
|
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
|
||||||
_shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server')
|
_shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server')
|
||||||
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
|
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
|
||||||
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||||
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||||
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||||
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||||
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||||
_shtab_ahriman_service_shell_option_strings=('-h' '--help')
|
_shtab_ahriman_service_shell_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_shell_option_strings=('-h' '--help')
|
_shtab_ahriman_shell_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role')
|
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH AHRIMAN "1" "2023\-08\-13" "ahriman" "Generated Python Manual"
|
.TH AHRIMAN "1" "2023\-08\-19" "ahriman" "Generated Python Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -689,7 +689,7 @@ key server for key import
|
|||||||
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
|
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
|
||||||
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-generate\-salt | \-\-no\-generate\-salt]
|
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-generate\-salt | \-\-no\-generate\-salt]
|
||||||
[\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs] [\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib]
|
[\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs] [\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib]
|
||||||
\-\-packager PACKAGER \-\-repository REPOSITORY [\-\-sign\-key SIGN_KEY]
|
\-\-packager PACKAGER \-\-repository REPOSITORY [\-\-server SERVER] [\-\-sign\-key SIGN_KEY]
|
||||||
[\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
|
[\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
|
||||||
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
|
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
|
||||||
|
|
||||||
@ -732,6 +732,10 @@ packager name and email
|
|||||||
\fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
\fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
||||||
repository name
|
repository name
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-server\fR \fI\,SERVER\/\fR
|
||||||
|
server to be used for devtools. If none set, local files will be used
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-sign\-key\fR \fI\,SIGN_KEY\/\fR
|
\fB\-\-sign\-key\fR \fI\,SIGN_KEY\/\fR
|
||||||
sign key id
|
sign key id
|
||||||
|
@ -177,6 +177,7 @@ _shtab_ahriman_init_options=(
|
|||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email (default\: None)]:packager:"
|
||||||
"--repository[repository name (default\: None)]:repository:"
|
"--repository[repository name (default\: None)]:repository:"
|
||||||
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
"--web-port[port of the web service (default\: None)]:web_port:"
|
"--web-port[port of the web service (default\: None)]:web_port:"
|
||||||
@ -347,6 +348,7 @@ _shtab_ahriman_repo_init_options=(
|
|||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email (default\: None)]:packager:"
|
||||||
"--repository[repository name (default\: None)]:repository:"
|
"--repository[repository name (default\: None)]:repository:"
|
||||||
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
"--web-port[port of the web service (default\: None)]:web_port:"
|
"--web-port[port of the web service (default\: None)]:web_port:"
|
||||||
@ -390,6 +392,7 @@ _shtab_ahriman_repo_setup_options=(
|
|||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email (default\: None)]:packager:"
|
||||||
"--repository[repository name (default\: None)]:repository:"
|
"--repository[repository name (default\: None)]:repository:"
|
||||||
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
"--web-port[port of the web service (default\: None)]:web_port:"
|
"--web-port[port of the web service (default\: None)]:web_port:"
|
||||||
@ -482,6 +485,7 @@ _shtab_ahriman_service_setup_options=(
|
|||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email (default\: None)]:packager:"
|
||||||
"--repository[repository name (default\: None)]:repository:"
|
"--repository[repository name (default\: None)]:repository:"
|
||||||
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
"--web-port[port of the web service (default\: None)]:web_port:"
|
"--web-port[port of the web service (default\: None)]:web_port:"
|
||||||
@ -504,6 +508,7 @@ _shtab_ahriman_setup_options=(
|
|||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email (default\: None)]:packager:"
|
||||||
"--repository[repository name (default\: None)]:repository:"
|
"--repository[repository name (default\: None)]:repository:"
|
||||||
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
"--web-port[port of the web service (default\: None)]:web_port:"
|
"--web-port[port of the web service (default\: None)]:web_port:"
|
||||||
|
@ -66,9 +66,9 @@ class LogsOperations(Operations):
|
|||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into logs
|
insert into logs
|
||||||
(package_base, created, version, record)
|
(package_base, version, created, record)
|
||||||
values
|
values
|
||||||
(:package_base, :created, :version, :record)
|
(:package_base, :version, :created, :record)
|
||||||
""",
|
""",
|
||||||
{
|
{
|
||||||
"package_base": log_record_id.package_base,
|
"package_base": log_record_id.package_base,
|
||||||
|
@ -31,15 +31,17 @@ class HttpLogHandler(logging.Handler):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
reporter(Client): build status reporter instance
|
reporter(Client): build status reporter instance
|
||||||
|
suppress_errors(bool): suppress logging errors (e.g. if no web server available)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, *, report: bool) -> None:
|
def __init__(self, configuration: Configuration, *, report: bool, suppress_errors: bool) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
|
suppress_errors(bool): suppress logging errors (e.g. if no web server available)
|
||||||
"""
|
"""
|
||||||
# we don't really care about those parameters because they will be handled by the reporter
|
# we don't really care about those parameters because they will be handled by the reporter
|
||||||
logging.Handler.__init__(self)
|
logging.Handler.__init__(self)
|
||||||
@ -47,6 +49,7 @@ class HttpLogHandler(logging.Handler):
|
|||||||
# client has to be imported here because of circular imports
|
# client has to be imported here because of circular imports
|
||||||
from ahriman.core.status.client import Client
|
from ahriman.core.status.client import Client
|
||||||
self.reporter = Client.load(configuration, report=report)
|
self.reporter = Client.load(configuration, report=report)
|
||||||
|
self.suppress_errors = suppress_errors
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, configuration: Configuration, *, report: bool) -> Self:
|
def load(cls, configuration: Configuration, *, report: bool) -> Self:
|
||||||
@ -65,7 +68,8 @@ class HttpLogHandler(logging.Handler):
|
|||||||
if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None:
|
if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None:
|
||||||
return handler # there is already registered instance
|
return handler # there is already registered instance
|
||||||
|
|
||||||
handler = cls(configuration, report=report)
|
suppress_errors = configuration.getboolean("settings", "suppress_http_log_errors", fallback=False)
|
||||||
|
handler = cls(configuration, report=report, suppress_errors=suppress_errors)
|
||||||
root.addHandler(handler)
|
root.addHandler(handler)
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
@ -81,4 +85,9 @@ class HttpLogHandler(logging.Handler):
|
|||||||
if log_record_id is None:
|
if log_record_id is None:
|
||||||
return # in case if no package base supplied we need just skip log message
|
return # in case if no package base supplied we need just skip log message
|
||||||
|
|
||||||
|
try:
|
||||||
self.reporter.package_logs(log_record_id, record)
|
self.reporter.package_logs(log_record_id, record)
|
||||||
|
except Exception:
|
||||||
|
if self.suppress_errors:
|
||||||
|
return
|
||||||
|
self.handleError(record)
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import requests
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.report.report import Report
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.core.status.web_client import WebClient
|
from ahriman.core.status.web_client import WebClient
|
||||||
@ -77,43 +79,41 @@ class RemoteCall(Report):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True in case if remote process is alive and False otherwise
|
bool: True in case if remote process is alive and False otherwise
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
response = self.client.make_request("GET", f"/api/v1/service/process/{process_id}")
|
response = self.client.make_request("GET", f"/api/v1/service/process/{process_id}")
|
||||||
if response is None:
|
except requests.RequestException as e:
|
||||||
|
if e.response is not None and e.response.status_code == 404:
|
||||||
return False
|
return False
|
||||||
|
raise
|
||||||
|
|
||||||
response_json = response.json()
|
response_json = response.json()
|
||||||
is_alive: bool = response_json["is_alive"]
|
is_alive: bool = response_json["is_alive"]
|
||||||
|
|
||||||
return is_alive
|
return is_alive
|
||||||
|
|
||||||
def remote_update(self) -> str | None:
|
def remote_update(self) -> str:
|
||||||
"""
|
"""
|
||||||
call remote server for update
|
call remote server for update
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str | None: remote process id on success and ``None`` otherwise
|
str: remote process id
|
||||||
"""
|
"""
|
||||||
response = self.client.make_request("POST", "/api/v1/service/update", json={
|
response = self.client.make_request("POST", "/api/v1/service/update", json={
|
||||||
"aur": self.update_aur,
|
"aur": self.update_aur,
|
||||||
"local": self.update_local,
|
"local": self.update_local,
|
||||||
"manual": self.update_manual,
|
"manual": self.update_manual,
|
||||||
})
|
})
|
||||||
if response is None:
|
|
||||||
return None # request terminated with error
|
|
||||||
|
|
||||||
response_json = response.json()
|
response_json = response.json()
|
||||||
|
|
||||||
process_id: str = response_json["process_id"]
|
process_id: str = response_json["process_id"]
|
||||||
return process_id
|
return process_id
|
||||||
|
|
||||||
def remote_wait(self, process_id: str | None) -> None:
|
def remote_wait(self, process_id: str) -> None:
|
||||||
"""
|
"""
|
||||||
wait for remote process termination
|
wait for remote process termination
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
process_id(str | None): remote process id
|
process_id(str): remote process id
|
||||||
"""
|
"""
|
||||||
if process_id is None:
|
|
||||||
return # nothing to track
|
|
||||||
|
|
||||||
waiter = Waiter(self.wait_timeout)
|
waiter = Waiter(self.wait_timeout)
|
||||||
waiter.wait(self.is_process_alive, process_id)
|
waiter.wait(self.is_process_alive, process_id)
|
||||||
|
@ -21,7 +21,6 @@ import contextlib
|
|||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from collections.abc import Generator
|
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any, IO, Literal
|
from typing import Any, IO, Literal
|
||||||
from urllib.parse import quote_plus as urlencode
|
from urllib.parse import quote_plus as urlencode
|
||||||
@ -129,32 +128,6 @@ class WebClient(Client, LazyLogging):
|
|||||||
address = f"http://{host}:{port}"
|
address = f"http://{host}:{port}"
|
||||||
return address, False
|
return address, False
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def __get_session(self, session: requests.Session | None = None) -> Generator[requests.Session, None, None]:
|
|
||||||
"""
|
|
||||||
execute request and handle exceptions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
session(requests.Session | None, optional): session to be used or stored instance property otherwise
|
|
||||||
(Default value = None)
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
requests.Session: session for requests
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if session is not None:
|
|
||||||
yield session # use session from arguments
|
|
||||||
else:
|
|
||||||
yield self.session # use instance generated session
|
|
||||||
except requests.RequestException as e:
|
|
||||||
if self.suppress_errors:
|
|
||||||
return
|
|
||||||
self.logger.exception("could not perform http request: %s", exception_response_text(e))
|
|
||||||
except Exception:
|
|
||||||
if self.suppress_errors:
|
|
||||||
return
|
|
||||||
self.logger.exception("could not perform http request")
|
|
||||||
|
|
||||||
def _create_session(self, *, use_unix_socket: bool) -> requests.Session:
|
def _create_session(self, *, use_unix_socket: bool) -> requests.Session:
|
||||||
"""
|
"""
|
||||||
generate new request session
|
generate new request session
|
||||||
@ -191,13 +164,15 @@ class WebClient(Client, LazyLogging):
|
|||||||
"username": self.user.username,
|
"username": self.user.username,
|
||||||
"password": self.user.password
|
"password": self.user.password
|
||||||
}
|
}
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
self.make_request("POST", self._login_url, json=payload, session=session)
|
self.make_request("POST", self._login_url, json=payload, session=session)
|
||||||
|
|
||||||
def make_request(self, method: Literal["DELETE", "GET", "POST"], url: str, *,
|
def make_request(self, method: Literal["DELETE", "GET", "POST"], url: str, *,
|
||||||
params: list[tuple[str, str]] | None = None,
|
params: list[tuple[str, str]] | None = None,
|
||||||
json: dict[str, Any] | None = None,
|
json: dict[str, Any] | None = None,
|
||||||
files: dict[str, MultipartType] | None = None,
|
files: dict[str, MultipartType] | None = None,
|
||||||
session: requests.Session | None = None) -> requests.Response | None:
|
session: requests.Session | None = None,
|
||||||
|
suppress_errors: bool | None = None) -> requests.Response:
|
||||||
"""
|
"""
|
||||||
perform request with specified parameters
|
perform request with specified parameters
|
||||||
|
|
||||||
@ -208,17 +183,30 @@ class WebClient(Client, LazyLogging):
|
|||||||
json(dict[str, Any] | None, optional): request json parameters (Default value = None)
|
json(dict[str, Any] | None, optional): request json parameters (Default value = None)
|
||||||
files(dict[str, MultipartType] | None, optional): multipart upload (Default value = None)
|
files(dict[str, MultipartType] | None, optional): multipart upload (Default value = None)
|
||||||
session(requests.Session | None, optional): session object if any (Default value = None)
|
session(requests.Session | None, optional): session object if any (Default value = None)
|
||||||
|
suppress_errors(bool | None, optional): suppress logging errors (e.g. if no web server available). If none
|
||||||
|
set, the instance-wide value will be used (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
requests.Response | None: response object or None in case of errors
|
requests.Response: response object
|
||||||
"""
|
"""
|
||||||
with self.__get_session(session) as _session:
|
# defaults
|
||||||
response = _session.request(method, f"{self.address}{url}", params=params, json=json, files=files)
|
if suppress_errors is None:
|
||||||
|
suppress_errors = self.suppress_errors
|
||||||
|
if session is None:
|
||||||
|
session = self.session
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = session.request(method, f"{self.address}{url}", params=params, json=json, files=files)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response
|
return response
|
||||||
|
except requests.RequestException as e:
|
||||||
# noinspection PyUnreachableCode
|
if not suppress_errors:
|
||||||
return None
|
self.logger.exception("could not perform http request: %s", exception_response_text(e))
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
if not suppress_errors:
|
||||||
|
self.logger.exception("could not perform http request")
|
||||||
|
raise
|
||||||
|
|
||||||
def package_add(self, package: Package, status: BuildStatusEnum) -> None:
|
def package_add(self, package: Package, status: BuildStatusEnum) -> None:
|
||||||
"""
|
"""
|
||||||
@ -232,6 +220,7 @@ class WebClient(Client, LazyLogging):
|
|||||||
"status": status.value,
|
"status": status.value,
|
||||||
"package": package.view()
|
"package": package.view()
|
||||||
}
|
}
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
self.make_request("POST", self._package_url(package.base), json=payload)
|
self.make_request("POST", self._package_url(package.base), json=payload)
|
||||||
|
|
||||||
def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
|
def package_get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
|
||||||
@ -244,16 +233,17 @@ class WebClient(Client, LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
||||||
"""
|
"""
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
response = self.make_request("GET", self._package_url(package_base or ""))
|
response = self.make_request("GET", self._package_url(package_base or ""))
|
||||||
if response is None:
|
|
||||||
return []
|
|
||||||
|
|
||||||
response_json = response.json()
|
response_json = response.json()
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(Package.from_json(package["package"]), BuildStatus.from_json(package["status"]))
|
(Package.from_json(package["package"]), BuildStatus.from_json(package["status"]))
|
||||||
for package in response_json
|
for package in response_json
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
def package_logs(self, log_record_id: LogRecordId, record: logging.LogRecord) -> None:
|
def package_logs(self, log_record_id: LogRecordId, record: logging.LogRecord) -> None:
|
||||||
"""
|
"""
|
||||||
post log record
|
post log record
|
||||||
@ -267,7 +257,11 @@ class WebClient(Client, LazyLogging):
|
|||||||
"message": record.getMessage(),
|
"message": record.getMessage(),
|
||||||
"version": log_record_id.version,
|
"version": log_record_id.version,
|
||||||
}
|
}
|
||||||
self.make_request("POST", self._logs_url(log_record_id.package_base), json=payload)
|
|
||||||
|
# this is special case, because we would like to do not suppress exception here
|
||||||
|
# in case of exception raised it will be handled by upstream HttpLogHandler
|
||||||
|
# In the other hand, we force to suppress all http logs here to avoid cyclic reporting
|
||||||
|
self.make_request("POST", self._logs_url(log_record_id.package_base), json=payload, suppress_errors=True)
|
||||||
|
|
||||||
def package_remove(self, package_base: str) -> None:
|
def package_remove(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
@ -276,6 +270,7 @@ class WebClient(Client, LazyLogging):
|
|||||||
Args:
|
Args:
|
||||||
package_base(str): basename to remove
|
package_base(str): basename to remove
|
||||||
"""
|
"""
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
self.make_request("DELETE", self._package_url(package_base))
|
self.make_request("DELETE", self._package_url(package_base))
|
||||||
|
|
||||||
def package_update(self, package_base: str, status: BuildStatusEnum) -> None:
|
def package_update(self, package_base: str, status: BuildStatusEnum) -> None:
|
||||||
@ -287,6 +282,7 @@ class WebClient(Client, LazyLogging):
|
|||||||
status(BuildStatusEnum): current package build status
|
status(BuildStatusEnum): current package build status
|
||||||
"""
|
"""
|
||||||
payload = {"status": status.value}
|
payload = {"status": status.value}
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
self.make_request("POST", self._package_url(package_base), json=payload)
|
self.make_request("POST", self._package_url(package_base), json=payload)
|
||||||
|
|
||||||
def status_get(self) -> InternalStatus:
|
def status_get(self) -> InternalStatus:
|
||||||
@ -296,13 +292,14 @@ class WebClient(Client, LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
InternalStatus: current internal (web) service status
|
InternalStatus: current internal (web) service status
|
||||||
"""
|
"""
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
response = self.make_request("GET", self._status_url)
|
response = self.make_request("GET", self._status_url)
|
||||||
if response is None:
|
|
||||||
return InternalStatus(status=BuildStatus())
|
|
||||||
|
|
||||||
response_json = response.json()
|
response_json = response.json()
|
||||||
|
|
||||||
return InternalStatus.from_json(response_json)
|
return InternalStatus.from_json(response_json)
|
||||||
|
|
||||||
|
return InternalStatus(status=BuildStatus())
|
||||||
|
|
||||||
def status_update(self, status: BuildStatusEnum) -> None:
|
def status_update(self, status: BuildStatusEnum) -> None:
|
||||||
"""
|
"""
|
||||||
update ahriman status itself
|
update ahriman status itself
|
||||||
@ -311,4 +308,5 @@ class WebClient(Client, LazyLogging):
|
|||||||
status(BuildStatusEnum): current ahriman status
|
status(BuildStatusEnum): current ahriman status
|
||||||
"""
|
"""
|
||||||
payload = {"status": status.value}
|
payload = {"status": status.value}
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
self.make_request("POST", self._status_url, json=payload)
|
self.make_request("POST", self._status_url, json=payload)
|
||||||
|
@ -43,18 +43,46 @@ def test_emit(configuration: Configuration, log_record: logging.LogRecord, packa
|
|||||||
log_record_id = log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version)
|
log_record_id = log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version)
|
||||||
log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs")
|
log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs")
|
||||||
|
|
||||||
handler = HttpLogHandler(configuration, report=False)
|
handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
|
||||||
|
|
||||||
handler.emit(log_record)
|
handler.emit(log_record)
|
||||||
log_mock.assert_called_once_with(log_record_id, log_record)
|
log_mock.assert_called_once_with(log_record_id, log_record)
|
||||||
|
|
||||||
|
|
||||||
|
def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must call handle error on exception
|
||||||
|
"""
|
||||||
|
log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version)
|
||||||
|
mocker.patch("ahriman.core.status.client.Client.package_logs", side_effect=Exception())
|
||||||
|
handle_error_mock = mocker.patch("logging.Handler.handleError")
|
||||||
|
handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
|
||||||
|
|
||||||
|
handler.emit(log_record)
|
||||||
|
handle_error_mock.assert_called_once_with(log_record)
|
||||||
|
|
||||||
|
|
||||||
|
def test_emit_suppress_failed(configuration: Configuration, log_record: logging.LogRecord, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must not call handle error on exception if suppress flag is set
|
||||||
|
"""
|
||||||
|
log_record.package_id = LogRecordId(package_ahriman.base, package_ahriman.version)
|
||||||
|
mocker.patch("ahriman.core.status.client.Client.package_logs", side_effect=Exception())
|
||||||
|
handle_error_mock = mocker.patch("logging.Handler.handleError")
|
||||||
|
handler = HttpLogHandler(configuration, report=False, suppress_errors=True)
|
||||||
|
|
||||||
|
handler.emit(log_record)
|
||||||
|
handle_error_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_emit_skip(configuration: Configuration, log_record: logging.LogRecord, mocker: MockerFixture) -> None:
|
def test_emit_skip(configuration: Configuration, log_record: logging.LogRecord, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must skip log record posting if no package base set
|
must skip log record posting if no package base set
|
||||||
"""
|
"""
|
||||||
log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs")
|
log_mock = mocker.patch("ahriman.core.status.client.Client.package_logs")
|
||||||
handler = HttpLogHandler(configuration, report=False)
|
handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
|
||||||
|
|
||||||
handler.emit(log_record)
|
handler.emit(log_record)
|
||||||
log_mock.assert_not_called()
|
log_mock.assert_not_called()
|
||||||
|
@ -37,10 +37,37 @@ def test_is_process_alive_unknown(remote_call: RemoteCall, mocker: MockerFixture
|
|||||||
"""
|
"""
|
||||||
must correctly define if process is unknown
|
must correctly define if process is unknown
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.status.web_client.WebClient.make_request", return_value=None)
|
response = requests.Response()
|
||||||
|
response.status_code = 404
|
||||||
|
mocker.patch("ahriman.core.status.web_client.WebClient.make_request",
|
||||||
|
side_effect=requests.RequestException(response=response))
|
||||||
|
|
||||||
assert not remote_call.is_process_alive("id")
|
assert not remote_call.is_process_alive("id")
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_process_alive_error(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must reraise exception on process request
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.status.web_client.WebClient.make_request", side_effect=Exception)
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
remote_call.is_process_alive("id")
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_process_alive_http_error(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must reraise http exception on process request
|
||||||
|
"""
|
||||||
|
response = requests.Response()
|
||||||
|
response.status_code = 500
|
||||||
|
mocker.patch("ahriman.core.status.web_client.WebClient.make_request",
|
||||||
|
side_effect=requests.RequestException(response=response))
|
||||||
|
|
||||||
|
with pytest.raises(requests.RequestException):
|
||||||
|
remote_call.is_process_alive("id")
|
||||||
|
|
||||||
|
|
||||||
def test_remote_update(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
def test_remote_update(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must call remote server for update process
|
must call remote server for update process
|
||||||
@ -59,14 +86,6 @@ def test_remote_update(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def test_remote_update_failed(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must return empty process id in case of errors
|
|
||||||
"""
|
|
||||||
mocker.patch("ahriman.core.status.web_client.WebClient.make_request", return_value=None)
|
|
||||||
assert remote_call.generate([], Result()) is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_remote_wait(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
def test_remote_wait(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must wait for remote process to success
|
must wait for remote process to success
|
||||||
@ -74,12 +93,3 @@ def test_remote_wait(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
|||||||
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
||||||
remote_call.remote_wait("id")
|
remote_call.remote_wait("id")
|
||||||
wait_mock.assert_called_once_with(pytest.helpers.anyvar(int), "id")
|
wait_mock.assert_called_once_with(pytest.helpers.anyvar(int), "id")
|
||||||
|
|
||||||
|
|
||||||
def test_remote_wait_skip(remote_call: RemoteCall, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must skip wait if process id is unknown
|
|
||||||
"""
|
|
||||||
wait_mock = mocker.patch("ahriman.models.waiter.Waiter.wait")
|
|
||||||
remote_call.remote_wait(None)
|
|
||||||
wait_mock.assert_not_called()
|
|
||||||
|
@ -163,7 +163,8 @@ def test_make_request_failed(web_client: WebClient, mocker: MockerFixture) -> No
|
|||||||
must make HTTP request
|
must make HTTP request
|
||||||
"""
|
"""
|
||||||
mocker.patch("requests.Session.request", side_effect=Exception())
|
mocker.patch("requests.Session.request", side_effect=Exception())
|
||||||
assert web_client.make_request("GET", "url") is None
|
with pytest.raises(Exception):
|
||||||
|
web_client.make_request("GET", "url")
|
||||||
|
|
||||||
|
|
||||||
def test_package_add(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None:
|
def test_package_add(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
@ -296,6 +297,7 @@ def test_package_logs_failed(web_client: WebClient, log_record: logging.LogRecor
|
|||||||
"""
|
"""
|
||||||
mocker.patch("requests.Session.request", side_effect=Exception())
|
mocker.patch("requests.Session.request", side_effect=Exception())
|
||||||
log_record.package_base = package_ahriman.base
|
log_record.package_base = package_ahriman.base
|
||||||
|
with pytest.raises(Exception):
|
||||||
web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record)
|
web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record)
|
||||||
|
|
||||||
|
|
||||||
@ -306,6 +308,7 @@ def test_package_logs_failed_http_error(web_client: WebClient, log_record: loggi
|
|||||||
"""
|
"""
|
||||||
mocker.patch("requests.Session.request", side_effect=requests.exceptions.HTTPError())
|
mocker.patch("requests.Session.request", side_effect=requests.exceptions.HTTPError())
|
||||||
log_record.package_base = package_ahriman.base
|
log_record.package_base = package_ahriman.base
|
||||||
|
with pytest.raises(Exception):
|
||||||
web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record)
|
web_client.package_logs(LogRecordId(package_ahriman.base, package_ahriman.version), log_record)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user