feat: add healh-check like endpoint, support of healthcheck in docker compose

This commit is contained in:
Evgenii Alekseev 2023-12-21 17:49:35 +02:00
parent 290e6e7670
commit 48344f759d
13 changed files with 193 additions and 4 deletions

View File

@ -25,6 +25,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:
@ -46,8 +51,6 @@ services:
worker: worker:
image: arcan1s/ahriman:edge image: arcan1s/ahriman:edge
depends_on:
- backend
privileged: true privileged: true
environment: environment:
@ -63,6 +66,10 @@ services:
volume: volume:
nocopy: true nocopy: true
depends_on:
backend:
condition: service_healthy
command: repo-daemon --dry-run command: repo-daemon --dry-run
configs: configs:

View File

@ -25,6 +25,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:

View File

@ -25,6 +25,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:
@ -67,6 +72,11 @@ services:
secrets: secrets:
- password - password
healthcheck:
test: curl --fail --silent --output /dev/null http://worker:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
configs: configs:

View File

@ -33,6 +33,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:

View File

@ -26,6 +26,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:

View File

@ -25,6 +25,11 @@ services:
volume: volume:
nocopy: true nocopy: true
healthcheck:
test: curl --fail --silent --output /dev/null http://backend:8080/api/v1/info
interval: 10s
start_period: 30s
command: web command: web
frontend: frontend:

View File

@ -24,6 +24,7 @@ from ahriman.web.schemas.changes_schema import ChangesSchema
from ahriman.web.schemas.counters_schema import CountersSchema from ahriman.web.schemas.counters_schema import CountersSchema
from ahriman.web.schemas.error_schema import ErrorSchema from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.file_schema import FileSchema from ahriman.web.schemas.file_schema import FileSchema
from ahriman.web.schemas.info_schema import InfoSchema
from ahriman.web.schemas.internal_status_schema import InternalStatusSchema from ahriman.web.schemas.internal_status_schema import InternalStatusSchema
from ahriman.web.schemas.log_schema import LogSchema from ahriman.web.schemas.log_schema import LogSchema
from ahriman.web.schemas.login_schema import LoginSchema from ahriman.web.schemas.login_schema import LoginSchema

View File

@ -0,0 +1,40 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from marshmallow import Schema, fields
from ahriman import __version__
from ahriman.web.schemas.repository_id_schema import RepositoryIdSchema
class InfoSchema(Schema):
"""
response service information schema
"""
auth = fields.Boolean(dump_default=False, required=True, metadata={
"description": "Whether authentication is enabled or not",
})
repositories = fields.Nested(RepositoryIdSchema(many=True), required=True, metadata={
"description": "List of loaded repositories",
})
version = fields.String(required=True, metadata={
"description": "Service version",
"example": __version__,
})

View File

@ -37,6 +37,6 @@ class InternalStatusSchema(RepositoryIdSchema):
"description": "Repository status as stored by web service", "description": "Repository status as stored by web service",
}) })
version = fields.String(required=True, metadata={ version = fields.String(required=True, metadata={
"description": "Repository version", "description": "Service version",
"example": __version__, "example": __version__,
}) })

View File

@ -0,0 +1,70 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import aiohttp_apispec # type: ignore[import-untyped]
from aiohttp.web import Response, json_response
from ahriman import __version__
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas import AuthSchema, ErrorSchema, InfoSchema
from ahriman.web.views.base import BaseView
class InfoView(BaseView):
"""
web service information view
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
"""
GET_PERMISSION = UserAccess.Unauthorized
ROUTES = ["/api/v1/info"]
@aiohttp_apispec.docs(
tags=["Status"],
summary="Service information",
description="Perform basic service health check and returns its information",
responses={
200: {"description": "Success response", "schema": InfoSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def get(self) -> Response:
"""
get service information
Returns:
Response: 200 with service information object
"""
response = {
"auth": self.validator.enabled,
"repositories": [
repository_id.view()
for repository_id in sorted(self.services)
],
"version": __version__,
}
return json_response(response)

View File

@ -0,0 +1 @@
# schema testing goes in view class tests

View File

@ -0,0 +1,40 @@
import pytest
from aiohttp.test_utils import TestClient
from ahriman import __version__
from ahriman.models.repository_id import RepositoryId
from ahriman.models.user_access import UserAccess
from ahriman.web.views.v1.status.info import InfoView
async def test_get_permission() -> None:
"""
must return correct permission for the request
"""
for method in ("GET",):
request = pytest.helpers.request("", "", method)
assert await InfoView.get_permission(request) == UserAccess.Unauthorized
def test_routes() -> None:
"""
must return correct routes
"""
assert InfoView.ROUTES == ["/api/v1/info"]
async def test_get(client: TestClient, repository_id: RepositoryId) -> None:
"""
must return service information
"""
response_schema = pytest.helpers.schema_response(InfoView.get)
response = await client.get(f"/api/v1/info")
assert response.ok
json = await response.json()
assert not response_schema.validate(json)
assert json["repositories"] == [repository_id.view()]
assert not json["auth"]
assert json["version"] == __version__

View File

@ -25,7 +25,7 @@ def test_routes() -> None:
async def test_get(client: TestClient, repository_id: RepositoryId) -> None: async def test_get(client: TestClient, repository_id: RepositoryId) -> None:
""" """
must return status for specific package must return list of available repositories
""" """
response_schema = pytest.helpers.schema_response(RepositoriesView.get) response_schema = pytest.helpers.schema_response(RepositoriesView.get)