diff --git a/charms/glance-k8s/src/charm.py b/charms/glance-k8s/src/charm.py index fc40daf6..139fe075 100755 --- a/charms/glance-k8s/src/charm.py +++ b/charms/glance-k8s/src/charm.py @@ -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): diff --git a/charms/openstack-images-sync-k8s/src/charm.py b/charms/openstack-images-sync-k8s/src/charm.py index bb6589ed..80bcf777 100755 --- a/charms/openstack-images-sync-k8s/src/charm.py +++ b/charms/openstack-images-sync-k8s/src/charm.py @@ -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): diff --git a/ops-sunbeam/ops_sunbeam/container_handlers.py b/ops-sunbeam/ops_sunbeam/container_handlers.py index 85a67799..ddb2c619 100644 --- a/ops-sunbeam/ops_sunbeam/container_handlers.py +++ b/ops-sunbeam/ops_sunbeam/container_handlers.py @@ -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", + }, }, }, } diff --git a/ops-sunbeam/tests/unit_tests/test_charms.py b/ops-sunbeam/tests/unit_tests/test_charms.py index bae71217..e351eac9 100644 --- a/ops-sunbeam/tests/unit_tests/test_charms.py +++ b/ops-sunbeam/tests/unit_tests/test_charms.py @@ -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", + }, }, }, }