Manage apache2 process directly

Apache2 supports the signal USR1 to restart all its children and reload
configuration.
Apache2ctl cannot receive USR1 signal directly to this effect, therefore
manage the apache2 directly, configuring all the environment variables
from apache2ctl.

Closes-Bug: #2097259
Change-Id: I55741645b09d5de0f25970b16e4d5fdfa3c58a9d
Signed-off-by: Guillaume Boutry <guillaume.boutry@canonical.com>
This commit is contained in:
Guillaume Boutry 2025-02-13 15:31:33 +01:00
parent fba9eac56a
commit 2cc6bdfad6
No known key found for this signature in database
GPG Key ID: 0DD77DC1796E98CD
4 changed files with 115 additions and 8 deletions
charms
glance-k8s/src
openstack-images-sync-k8s/src
ops-sunbeam
ops_sunbeam
tests/unit_tests

@ -24,6 +24,8 @@ This charm provide Glance services as part of an OpenStack deployment
import json
import logging
import re
import signal
import typing
from typing import (
Callable,
List,
@ -74,7 +76,7 @@ STORAGE_NAME = "local-repository"
class GlanceAPIPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"""Handler for glance api container."""
def get_layer(self) -> dict:
def get_layer(self) -> ops.pebble.LayerDict:
"""Glance API service pebble layer.
:returns: pebble layer configuration for glance api service
@ -86,6 +88,7 @@ class GlanceAPIPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
f"{self.service_name}": {
"override": "replace",
"summary": f"{self.service_name} standalone",
"startup": "disabled",
"command": (
"/usr/bin/glance-api "
"--config-file /etc/glance/glance-api.conf"
@ -96,7 +99,16 @@ class GlanceAPIPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"apache forwarder": {
"override": "replace",
"summary": "apache",
"command": "/usr/sbin/apache2ctl -DFOREGROUND",
"command": "/usr/sbin/apache2 -DFOREGROUND -DNO_DETACH",
"startup": "disabled",
"environment": {
"APACHE_RUN_DIR": "/var/run/apache2",
"APACHE_PID_FILE": "/var/run/apache2/apache2.pid",
"APACHE_LOCK_DIR": "/var/lock/apache2",
"APACHE_RUN_USER": "www-data",
"APACHE_RUN_GROUP": "www-data",
"APACHE_LOG_DIR": "/var/log/apache2",
},
},
},
}
@ -110,6 +122,16 @@ class GlanceAPIPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
self.execute(["a2enmod", "proxy_http"], exception_on_error=True)
return super().init_service(context)
@property
def _restart_methods(
self,
) -> typing.Mapping[str, Callable[[ops.Container, str], None]]:
return {
"apache forwarder": lambda container, service_name: container.send_signal(
signal.SIGUSR1, service_name
)
}
@sunbeam_tracing.trace_type
class GlanceStorageRelationHandler(sunbeam_rhandlers.CephClientHandler):

@ -22,6 +22,8 @@ This charm deploys the openstack images sync service on Kubernetes.
import logging
import os
import signal
import typing
from typing import (
TYPE_CHECKING,
)
@ -107,9 +109,14 @@ class OpenstackImagesSyncPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
self.charm.service_user,
self.charm.service_group,
),
sunbeam_chandlers.ContainerDir(
"/var/run/apache2",
"root",
"root",
),
]
def get_layer(self) -> dict:
def get_layer(self) -> ops.pebble.LayerDict:
"""Openstack Images Sync service pebble layer.
:returns: pebble layer configuration for openstack images sync service
@ -135,7 +142,16 @@ class OpenstackImagesSyncPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"http-mirror": {
"override": "replace",
"summary": "apache",
"command": "/usr/sbin/apache2ctl -DFOREGROUND",
"command": "/usr/sbin/apache2 -DFOREGROUND -DNO_DETACH",
"startup": "disabled",
"environment": {
"APACHE_RUN_DIR": "/var/run/apache2",
"APACHE_PID_FILE": "/var/run/apache2/apache2.pid",
"APACHE_LOCK_DIR": "/var/lock/apache2",
"APACHE_RUN_USER": "www-data",
"APACHE_RUN_GROUP": "www-data",
"APACHE_LOG_DIR": "/var/log/apache2",
},
},
},
}
@ -149,6 +165,16 @@ class OpenstackImagesSyncPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
self.execute(["a2dissite", "000-default"], exception_on_error=True)
return super().init_service(context)
@property
def _restart_methods(
self,
) -> typing.Mapping[str, typing.Callable[[ops.Container, str], None]]:
return {
"http-mirror": lambda container, service_name: container.send_signal(
signal.SIGUSR1, service_name
)
}
@sunbeam_tracing.trace_sunbeam_charm
class OpenstackImagesSyncK8SCharm(sunbeam_charm.OSBaseOperatorAPICharm):

@ -21,6 +21,7 @@ in the container.
import collections
import logging
import signal
import typing
from collections.abc import (
Callable,
@ -316,7 +317,26 @@ class PebbleHandler(ops.framework.Object):
self.status.set(ActiveStatus(""))
def start_all(self, restart: bool = True) -> None:
@staticmethod
def _restart_service(container: ops.Container, service_name: str) -> None:
"""Restart service in container.
:param container: Container to restart service in.
:param service_name: Service to restart.
"""
container.restart(service_name)
@property
def _restart_methods(
self,
) -> typing.Mapping[str, Callable[[ops.Container, str], None]]:
"""Mapping of service names to restart methods."""
return {}
def start_all(
self,
restart: bool = True,
) -> None:
"""Start services in container.
:param restart: Whether to stop services before starting them.
@ -341,7 +361,9 @@ class PebbleHandler(ops.framework.Object):
logger.debug(
f"Restarting {service_name} in {self.container_name}"
)
container.restart(service_name)
self._restart_methods.get(service_name, self._restart_service)(
container, service_name
)
self._reset_files_changed()
def stop_all(self) -> None:
@ -425,6 +447,27 @@ class WSGIPebbleHandler(PebbleHandler):
)
self.wsgi_service_name = wsgi_service_name
@staticmethod
def _restart_wsgi_service(
container: ops.Container, service_name: str
) -> None:
"""Restart WSGI service in container.
WSGI services can be gracefully restarted by sending SIGUSR1 to the
service.
:param container: Container to restart service in.
:param service_name: Service to restart.
"""
container.send_signal(signal.SIGUSR1, service_name)
@property
def _restart_methods(
self,
) -> typing.Mapping[str, Callable[[ops.Container, str], None]]:
"""Mapping of service names to restart methods."""
return {self.wsgi_service_name: self._restart_wsgi_service}
def start_wsgi(self, restart: bool = True) -> None:
"""Check and start services in container.
@ -459,8 +502,16 @@ class WSGIPebbleHandler(PebbleHandler):
f"{self.wsgi_service_name}": {
"override": "replace",
"summary": f"{self.service_name} wsgi",
"command": "/usr/sbin/apache2ctl -DFOREGROUND",
"command": "/usr/sbin/apache2 -DFOREGROUND -DNO_DETACH",
"startup": "disabled",
"environment": {
"APACHE_RUN_DIR": "/var/run/apache2",
"APACHE_PID_FILE": "/var/run/apache2/apache2.pid",
"APACHE_LOCK_DIR": "/var/lock/apache2",
"APACHE_RUN_USER": "www-data",
"APACHE_RUN_GROUP": "www-data",
"APACHE_LOG_DIR": "/var/log/apache2",
},
},
},
}

@ -333,8 +333,16 @@ class MultiSvcPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"apache forwarder": {
"override": "replace",
"summary": "apache",
"command": "/usr/sbin/apache2ctl -DFOREGROUND",
"command": "/usr/sbin/apache2 -DFOREGROUND",
"startup": "disabled",
"environment": {
"APACHE_RUN_DIR": "/var/run/apache2",
"APACHE_PID_FILE": "/var/run/apache2/apache2.pid",
"APACHE_LOCK_DIR": "/var/lock/apache2",
"APACHE_RUN_USER": "www-data",
"APACHE_RUN_GROUP": "www-data",
"APACHE_LOG_DIR": "/var/log/apache2",
},
},
},
}