Guillaume Boutry 2cc6bdfad6
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>
2025-02-13 17:53:39 +01:00

366 lines
9.5 KiB
Python

#!/usr/bin/env python3
# Copyright 2021 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test charms for unit tests."""
import os
import sys
import tempfile
from typing import (
TYPE_CHECKING,
)
if TYPE_CHECKING:
import ops.framework
from typing import (
List,
)
sys.path.append("tests/unit_tests/lib") # noqa
sys.path.append("src") # noqa
import ops_sunbeam.charm as sunbeam_charm
import ops_sunbeam.container_handlers as sunbeam_chandlers
CHARM_CONFIG = """
options:
debug:
default: True
description: Enable debug logging.
type: boolean
region:
default: RegionOne
description: Region
type: string
"""
INITIAL_CHARM_CONFIG = {"debug": "true", "region": "RegionOne"}
CHARM_METADATA = """
name: my-service
version: 3
bases:
- name: ubuntu
channel: 20.04/stable
tags:
- openstack
- identity
- misc
subordinate: false
"""
CHARM_METADATA_K8S = (
CHARM_METADATA
+ """
containers:
my-service:
resource: mysvc-image
mounts:
- storage: db
location: /var/lib/mysvc
storage:
logs:
type: filesystem
db:
type: filesystem
resources:
mysvc-image:
type: oci-image
"""
)
API_CHARM_METADATA = """
name: my-service
version: 3
bases:
- name: ubuntu
channel: 20.04/stable
tags:
- openstack
- identity
- misc
subordinate: false
requires:
database:
interface: mysql_client
limit: 1
ingress-internal:
interface: ingress
limit: 1
ingress-public:
interface: ingress
optional: true
limit: 1
amqp:
interface: rabbitmq
identity-service:
interface: keystone
identity-credentials:
interface: keystone-credentials
optional: true
limit: 1
ceph-access:
interface: cinder-ceph-key
optional: true
peers:
peers:
interface: mysvc-peer
containers:
my-service:
resource: mysvc-image
mounts:
- storage: db
location: /var/lib/mysvc
storage:
logs:
type: filesystem
db:
type: filesystem
resources:
mysvc-image:
type: oci-image
"""
class MyCharm(sunbeam_charm.OSBaseOperatorCharm):
"""Test charm for testing OSBaseOperatorCharm."""
service_name = "my-service"
def __init__(self, framework: "ops.framework.Framework") -> None:
"""Run constructor."""
self.seen_events = []
self.render_calls = []
self._template_dir = self._setup_templates()
super().__init__(framework)
def _log_event(self, event: "ops.framework.EventBase") -> None:
"""Log events."""
self.seen_events.append(type(event).__name__)
def _on_config_changed(self, event: "ops.framework.EventBase") -> None:
"""Log config changed event."""
self._log_event(event)
super()._on_config_changed(event)
def configure_charm(self, event: "ops.framework.EventBase") -> None:
"""Log configure_charm call."""
self._log_event(event)
super().configure_charm(event)
@property
def public_ingress_port(self) -> int:
"""Charms default port."""
return 789
def _setup_templates(self) -> str:
"""Run temp templates dir setup."""
tmpdir = tempfile.mkdtemp()
_template_dir = f"{tmpdir}/templates"
os.mkdir(_template_dir)
with open(f"{_template_dir}/my-service.conf.j2", "w") as f:
f.write("")
return _template_dir
@property
def template_dir(self) -> str:
"""Temp templates dir."""
return self._template_dir
TEMPLATE_CONTENTS = """
{{ wsgi_config.wsgi_admin_script }}
{{ database.database_password }}
{{ options.debug }}
{{ amqp.transport_url }}
{{ amqp.hostname }}
{{ identity_service.service_password }}
{{ peers.foo }}
"""
class MyCharmK8S(sunbeam_charm.OSBaseOperatorCharmK8S):
"""Test charm for k8s."""
service_name = "my-service"
def __init__(self, framework: "ops.framework.Framework") -> None:
"""Run constructor."""
self.seen_events = []
self.render_calls = []
self._template_dir = self._setup_templates()
super().__init__(framework)
def _log_event(self, event: "ops.framework.EventBase") -> None:
"""Log events."""
self.seen_events.append(type(event).__name__)
def _on_config_changed(self, event: "ops.framework.EventBase") -> None:
"""Log config changed event."""
self._log_event(event)
super()._on_config_changed(event)
def configure_charm(self, event: "ops.framework.EventBase") -> None:
"""Log configure_charm call."""
self._log_event(event)
super().configure_charm(event)
@property
def public_ingress_port(self) -> int:
"""Charms default port."""
return 789
def _setup_templates(self) -> str:
"""Run temp templates dir setup."""
tmpdir = tempfile.mkdtemp()
_template_dir = f"{tmpdir}/templates"
os.mkdir(_template_dir)
with open(f"{_template_dir}/my-service.conf.j2", "w") as f:
f.write("")
return _template_dir
def _on_service_pebble_ready(
self, event: "ops.framework.EventBase"
) -> None:
"""Log pebble ready event."""
self._log_event(event)
super()._on_service_pebble_ready(event)
class MyAPICharm(sunbeam_charm.OSBaseOperatorAPICharm):
"""Test charm for testing OSBaseOperatorAPICharm."""
service_name = "my-service"
wsgi_admin_script = "/bin/wsgi_admin"
wsgi_public_script = "/bin/wsgi_public"
def __init__(self, framework: "ops.framework.Framework") -> None:
"""Run constructor."""
self.seen_events = []
self.render_calls = []
self._template_dir = self._setup_templates()
super().__init__(framework)
def _setup_templates(self) -> str:
"""Run temp templates dir setup."""
tmpdir = tempfile.mkdtemp()
_template_dir = f"{tmpdir}/templates"
os.mkdir(_template_dir)
with open(f"{_template_dir}/my-service.conf.j2", "w") as f:
f.write(TEMPLATE_CONTENTS)
with open(f"{_template_dir}/wsgi-my-service.conf.j2", "w") as f:
f.write(TEMPLATE_CONTENTS)
return _template_dir
def _log_event(self, event: "ops.framework.EventBase") -> None:
"""Log events."""
self.seen_events.append(type(event).__name__)
def _on_service_pebble_ready(
self, event: "ops.framework.EventBase"
) -> None:
"""Log pebble ready event."""
self._log_event(event)
super()._on_service_pebble_ready(event)
def _on_config_changed(self, event: "ops.framework.EventBase") -> None:
"""Log config changed event."""
self._log_event(event)
super()._on_config_changed(event)
@property
def default_public_ingress_port(self) -> int:
"""Charms default port."""
return 789
@property
def template_dir(self) -> str:
"""Templates dir."""
return self._template_dir
@property
def healthcheck_http_url(self) -> str:
"""Healthcheck HTTP URL for the service."""
return f"http://localhost:{self.default_public_ingress_port}/v3"
@property
def healthcheck_http_timeout(self) -> str:
"""Healthcheck HTTP timeout for the service."""
return "5s"
class MultiSvcPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"""Test pebble handler for multi service charm."""
def get_layer(self) -> dict:
"""Glance API service pebble layer.
:returns: pebble layer configuration for glance api service
"""
return {
"summary": f"{self.service_name} layer",
"description": "pebble config layer for glance api service",
"services": {
f"{self.service_name}": {
"override": "replace",
"summary": f"{self.service_name} standalone",
"command": "/usr/bin/glance-api",
"startup": "disabled",
},
"apache forwarder": {
"override": "replace",
"summary": "apache",
"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",
},
},
},
}
class TestMultiSvcCharm(MyAPICharm):
"""Test class of multi service charm."""
def get_pebble_handlers(self) -> List[sunbeam_chandlers.PebbleHandler]:
"""Pebble handlers for the service."""
return [
MultiSvcPebbleHandler(
self,
self.service_name,
self.service_name,
self.container_configs,
self.template_dir,
self.configure_charm,
)
]