paas-charm 2.0.dev0__tar.gz → 2.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/PKG-INFO +5 -5
  2. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/pyproject.toml +24 -24
  3. paas_charm-2.0.dev1/src/paas_charm/__init__.py +13 -0
  4. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/_gunicorn/charm.py +1 -3
  5. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/_gunicorn/webserver.py +4 -8
  6. paas_charm-2.0.dev1/src/paas_charm/_gunicorn/workload_config.py +62 -0
  7. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/app.py +7 -22
  8. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/charm.py +115 -311
  9. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/charm_state.py +19 -30
  10. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/django/charm.py +1 -1
  11. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/expressjs/charm.py +9 -7
  12. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/charm.py +11 -10
  13. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/flask/charm.py +1 -1
  14. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/framework.py +8 -14
  15. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/go/charm.py +12 -10
  16. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/observability.py +19 -23
  17. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/paas_config.py +49 -1
  18. paas_charm-2.0.dev1/src/paas_charm/peers.py +60 -0
  19. paas_charm-2.0.dev1/src/paas_charm/secret_key.py +86 -0
  20. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/springboot/charm.py +45 -36
  21. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm.egg-info/PKG-INFO +5 -5
  22. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm.egg-info/SOURCES.txt +2 -3
  23. paas_charm-2.0.dev1/src/paas_charm.egg-info/requires.txt +6 -0
  24. paas_charm-2.0.dev0/src/paas_charm/__init__.py +0 -60
  25. paas_charm-2.0.dev0/src/paas_charm/_gunicorn/workload_config.py +0 -52
  26. paas_charm-2.0.dev0/src/paas_charm/openfga.py +0 -9
  27. paas_charm-2.0.dev0/src/paas_charm/redis.py +0 -63
  28. paas_charm-2.0.dev0/src/paas_charm/secret_storage.py +0 -169
  29. paas_charm-2.0.dev0/src/paas_charm.egg-info/requires.txt +0 -6
  30. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/README.md +0 -0
  31. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/setup.cfg +0 -0
  32. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/__init__.py +0 -0
  33. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/django/__init__.py +0 -0
  34. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/django/charm.py +0 -0
  35. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/fastapi/__init__.py +0 -0
  36. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/fastapi/charm.py +0 -0
  37. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/flask/__init__.py +0 -0
  38. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/flask/charm.py +0 -0
  39. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/go/__init__.py +0 -0
  40. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_app_charmer/go/charm.py +0 -0
  41. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/_gunicorn/__init__.py +0 -0
  42. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/_gunicorn/wsgi_app.py +0 -0
  43. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/charm_utils.py +0 -0
  44. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/database_migration.py +0 -0
  45. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/databases.py +0 -0
  46. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/django/__init__.py +0 -0
  47. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/django/cos/grafana_dashboards/django.json +0 -0
  48. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/django/cos/loki_alert_rules/.gitkeep +0 -0
  49. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/django/cos/prometheus_alert_rules/django.rule +0 -0
  50. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/exceptions.py +0 -0
  51. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/expressjs/__init__.py +0 -0
  52. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/expressjs/cos/grafana_dashboards/expressjs.json +0 -0
  53. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/expressjs/cos/loki_alert_rules/.gitkeep +0 -0
  54. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/expressjs/cos/prometheus_alert_rules/.gitkeep +0 -0
  55. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/__init__.py +0 -0
  56. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/app.py +0 -0
  57. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/cos/grafana_dashboards/fastapi.json +0 -0
  58. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/cos/loki_alert_rules/.gitkeep +0 -0
  59. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/fastapi/cos/prometheus_alert_rules/.gitkeep +0 -0
  60. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/flask/__init__.py +0 -0
  61. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/flask/cos/grafana_dashboards/flask.json +0 -0
  62. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/flask/cos/loki_alert_rules/.gitkeep +0 -0
  63. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/flask/cos/prometheus_alert_rules/flask.rule +0 -0
  64. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/go/__init__.py +0 -0
  65. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/go/cos/grafana_dashboards/go.json +0 -0
  66. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/go/cos/loki_alert_rules/.gitkeep +0 -0
  67. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/go/cos/prometheus_alert_rules/.gitkeep +0 -0
  68. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/http_proxy.py +0 -0
  69. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/oauth.py +0 -0
  70. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/rabbitmq.py +0 -0
  71. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/s3.py +0 -0
  72. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/saml.py +0 -0
  73. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/springboot/__init__.py +0 -0
  74. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/springboot/cos/grafana_dashboards/spring_boot.json +0 -0
  75. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/springboot/cos/loki_alert_rules/.gitkeep +0 -0
  76. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/springboot/cos/prometheus_alert_rules/.gitkeep +0 -0
  77. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/templates/_gunicorn_json_logging.py +0 -0
  78. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/templates/fastapi/uvicorn-log-config.json +0 -0
  79. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/templates/fastapi/uvicorn_log_handler.py +0 -0
  80. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/templates/gunicorn.conf.py.j2 +0 -0
  81. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/tracing.py +0 -0
  82. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/utils.py +0 -0
  83. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm/valkey.py +0 -0
  84. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm.egg-info/dependency_links.txt +0 -0
  85. {paas_charm-2.0.dev0 → paas_charm-2.0.dev1}/src/paas_charm.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paas-charm
3
- Version: 2.0.dev0
3
+ Version: 2.0.dev1
4
4
  Summary: Companion library for 12-factor app support in Charmcraft & Rockcraft.
5
5
  Author-email: Canonical IS DevOps team <is-devops-team@canonical.com>
6
6
  Project-URL: Repository, https://github.com/canonical/paas-charm
@@ -11,12 +11,12 @@ Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: cosl==1.9.1
15
- Requires-Dist: dpcharmlibs-interfaces==1.0.2
14
+ Requires-Dist: cosl==1.10.3
15
+ Requires-Dist: dpcharmlibs-interfaces==1.2.0
16
16
  Requires-Dist: Jinja2==3.1.6
17
17
  Requires-Dist: jsonschema==4.26.0
18
- Requires-Dist: ops==3.7.1
19
- Requires-Dist: pydantic==2.13.4
18
+ Requires-Dist: ops==3.8.2
19
+ Requires-Dist: pydantic[email]==2.13.5
20
20
 
21
21
  # PaaS Charm
22
22
 
@@ -2,7 +2,7 @@
2
2
  # See LICENSE file for licensing details.
3
3
  [project]
4
4
  name = "paas-charm"
5
- version = "2.0.dev0"
5
+ version = "2.0.dev1"
6
6
  description = "Companion library for 12-factor app support in Charmcraft & Rockcraft."
7
7
  readme = "README.md"
8
8
  authors = [
@@ -17,12 +17,12 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3",
18
18
  ]
19
19
  dependencies = [
20
- "cosl==1.9.1",
21
- "dpcharmlibs-interfaces==1.0.2",
20
+ "cosl==1.10.3",
21
+ "dpcharmlibs-interfaces==1.2.0",
22
22
  "Jinja2==3.1.6",
23
23
  "jsonschema==4.26.0",
24
- "ops==3.7.1",
25
- "pydantic==2.13.4",
24
+ "ops==3.8.2",
25
+ "pydantic[email]==2.13.5",
26
26
  ]
27
27
 
28
28
  [project.urls]
@@ -37,7 +37,7 @@ where = ["src"]
37
37
 
38
38
  [tool.uv.sources]
39
39
  # opcli is published only from the charm-ci git repository, not PyPI.
40
- opcli = { git = "https://github.com/canonical/charm-ci.git", branch = "main" }
40
+ opcli = { git = "https://github.com/canonical/charm-ci.git", tag = "v1.0.1" }
41
41
 
42
42
  [tool.setuptools.package-data]
43
43
  paas_charm = ["**/cos/**", "**/cos/**/.**", "**/*.j2", "**/templates/**/*.py", "**/templates/**/*.json"]
@@ -134,13 +134,13 @@ line-length = 99
134
134
 
135
135
  [dependency-groups]
136
136
  unit = [
137
- "cosl==1.9.1",
138
- "coverage[toml]==7.14.1",
139
- "gunicorn==26.0.0",
140
- "opentelemetry-api==1.42.1",
141
- "opentelemetry-sdk==1.42.1",
142
- "ops[testing]==3.7.1",
143
- "pydantic[email]==2.13.4",
137
+ "cosl==1.10.3",
138
+ "coverage[toml]==7.16.0",
139
+ "gunicorn==26.2.0",
140
+ "opentelemetry-api==1.44.0",
141
+ "opentelemetry-sdk==1.44.0",
142
+ "ops[testing]==3.8.2",
143
+ "pydantic[email]==2.13.5",
144
144
  "pytest==9.1.1",
145
145
  ]
146
146
  lint = [
@@ -158,8 +158,7 @@ lint = [
158
158
  "pydocstyle",
159
159
  "pylint",
160
160
  "pyproject-flake8",
161
- "pytest_operator",
162
- "snowballstemmer<3.0.0",
161
+ "snowballstemmer<3.1.2",
163
162
  "types-PyYAML",
164
163
  "types-requests",
165
164
  ]
@@ -168,15 +167,16 @@ static = [
168
167
  ]
169
168
  integration-tests = [
170
169
  "pytest>=9.1.1",
171
- "aiohttp==3.11.7",
172
- "cosl==1.9.1",
170
+ "aiohttp==3.14.3",
171
+ "cosl==1.10.3",
173
172
  "saml-test-helper @ git+https://github.com/canonical/saml-test-idp.git",
174
- "jubilant==1.7.0",
175
- "juju==3.6.1.2",
176
- "minio==7.2.14",
177
- "ops==3.7.1",
178
- "tenacity==9.0.0",
179
- "playwright==1.61.0",
180
- "lightkube==0.21.0",
173
+ "jubilant==1.13.0",
174
+ "juju==3.6.1.3",
175
+ "minio==7.2.20",
176
+ "ops==3.8.2",
177
+ "tenacity==9.1.4",
178
+ "playwright==1.62.0",
179
+ "lightkube==1.0.1",
180
+ "pytest-jubilant>=2,<3",
181
181
  "opcli"
182
182
  ]
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2025 Canonical Ltd.
4
+ # See LICENSE file for licensing details.
5
+
6
+ """Module __init__."""
7
+
8
+ import charms.data_platform_libs.v0.data_interfaces # noqa: F401
9
+ import charms.grafana_k8s.v0.grafana_dashboard # noqa: F401
10
+ import charms.loki_k8s.v1.loki_push_api # noqa: F401
11
+ import charms.observability_libs.v0.juju_topology # noqa: F401
12
+ import charms.prometheus_k8s.v0.prometheus_scrape # noqa: F401
13
+ import charms.traefik_k8s.v2.ingress # noqa: F401
@@ -13,7 +13,6 @@ from paas_charm._gunicorn.wsgi_app import WsgiApp
13
13
  from paas_charm.app import App, WorkloadConfig
14
14
  from paas_charm.charm import PaasCharm
15
15
  from paas_charm.exceptions import CharmConfigInvalidError
16
- from paas_charm.paas_config import read_paas_config
17
16
 
18
17
  logger = logging.getLogger(__name__)
19
18
 
@@ -24,13 +23,12 @@ class GunicornBase(PaasCharm):
24
23
  @property
25
24
  def _workload_config(self) -> WorkloadConfig:
26
25
  """Return a WorkloadConfig instance."""
27
- paas_config = read_paas_config()
28
26
  return create_workload_config(
29
27
  framework_name=self._framework_name,
30
28
  unit_name=self.unit.name,
31
29
  state_dir=self._state_dir,
32
30
  tracing_enabled=bool(self._tracing and self._tracing.is_ready()),
33
- logging_format=paas_config.framework_logging_format,
31
+ paas_config=self._paas_config,
34
32
  )
35
33
 
36
34
  def create_webserver_config(self) -> WebserverConfig:
@@ -17,8 +17,8 @@ import ops
17
17
  from ops.pebble import ExecError, PathError
18
18
 
19
19
  from paas_charm._gunicorn.workload_config import (
20
- APPLICATION_ERROR_LOG_FILE_FMT,
21
- APPLICATION_LOG_FILE_FMT,
20
+ APPLICATION_ERROR_LOG_FILE,
21
+ APPLICATION_LOG_FILE,
22
22
  STATSD_HOST,
23
23
  )
24
24
  from paas_charm.app import WorkloadConfig
@@ -157,12 +157,8 @@ class GunicornWebserver: # pylint: disable=too-few-public-methods
157
157
  access_log = "-"
158
158
  error_log = "-"
159
159
  else:
160
- access_log = str(
161
- APPLICATION_LOG_FILE_FMT.format(framework=self._workload_config.framework)
162
- )
163
- error_log = str(
164
- APPLICATION_ERROR_LOG_FILE_FMT.format(framework=self._workload_config.framework)
165
- )
160
+ access_log = str(APPLICATION_LOG_FILE)
161
+ error_log = str(APPLICATION_ERROR_LOG_FILE)
166
162
 
167
163
  jinja_environment = jinja2.Environment(
168
164
  loader=jinja2.PackageLoader("paas_charm", "templates"), autoescape=True
@@ -0,0 +1,62 @@
1
+ # Copyright 2025 Canonical Ltd.
2
+ # See LICENSE file for licensing details.
3
+
4
+ """This module defines the WorloadConfig class which represents configuration for the workload."""
5
+
6
+ import pathlib
7
+
8
+ from paas_charm.app import WorkloadConfig
9
+ from paas_charm.paas_config import PaasConfig
10
+
11
+ STATSD_HOST = "localhost:9125"
12
+ APPLICATION_LOG_FILE = "/var/log/app/access.log"
13
+ APPLICATION_ERROR_LOG_FILE = "/var/log/app/error.log"
14
+ GUNICORN_CONFIG_DIR = "/var/lib/gunicorn"
15
+
16
+
17
+ def create_workload_config(
18
+ framework_name: str,
19
+ unit_name: str,
20
+ state_dir: pathlib.Path,
21
+ paas_config: PaasConfig | None = None,
22
+ tracing_enabled: bool = False,
23
+ ) -> WorkloadConfig:
24
+ """Create an WorkloadConfig for Gunicorn.
25
+
26
+ Args:
27
+ framework_name: framework name.
28
+ unit_name: name of the app unit.
29
+ state_dir: state folder directory.
30
+ paas_config: PaasConfig instance. Uses the schema defaults when omitted.
31
+ tracing_enabled: if True, tracing is enabled.
32
+
33
+ Returns:
34
+ new WorkloadConfig
35
+ """
36
+ paas_config = paas_config or PaasConfig()
37
+ application_port = paas_config.application_port(default_port=8000)
38
+ metrics_port, metrics_path = paas_config.metrics_endpoint(
39
+ default_port=9102, default_path="/metrics"
40
+ )
41
+ # For Gunicorn, base_dir holds the (mutable) gunicorn.conf.py, kept separate from app_dir
42
+ # (the application source directory) so the two can have different lifecycles/ownership.
43
+ base_dir = pathlib.Path(GUNICORN_CONFIG_DIR)
44
+ app_dir = pathlib.Path("/app")
45
+ return WorkloadConfig(
46
+ framework=framework_name,
47
+ container_name="app",
48
+ port=application_port,
49
+ base_dir=base_dir,
50
+ app_dir=app_dir,
51
+ state_dir=state_dir,
52
+ service_name=framework_name,
53
+ log_files=[
54
+ pathlib.Path(APPLICATION_LOG_FILE),
55
+ pathlib.Path(APPLICATION_ERROR_LOG_FILE),
56
+ ],
57
+ metrics_path=metrics_path,
58
+ metrics_port=metrics_port,
59
+ unit_name=unit_name,
60
+ tracing_enabled=tracing_enabled,
61
+ logging_format=paas_config.framework_logging_format,
62
+ )
@@ -27,7 +27,6 @@ if TYPE_CHECKING:
27
27
  from paas_charm.databases import PaaSDatabaseRelationData
28
28
  from paas_charm.oauth import PaaSOAuthRelationData
29
29
  from paas_charm.rabbitmq import PaaSRabbitMQRelationData
30
- from paas_charm.redis import PaaSRedisRelationData
31
30
  from paas_charm.s3 import PaaSS3RelationData
32
31
  from paas_charm.saml import PaaSSAMLRelationData
33
32
  from paas_charm.tracing import PaaSTracingRelationData
@@ -54,8 +53,8 @@ class WorkloadConfig: # pylint: disable=too-many-instance-attributes
54
53
  state_dir: the directory in the application container to store states information.
55
54
  service_name: the WSGI application pebble service name.
56
55
  log_files: list of files to monitor.
57
- metrics_target: target to scrape for metrics.
58
56
  metrics_path: path to scrape for metrics.
57
+ metrics_port: port on which the application exposes metrics.
59
58
  unit_name: Name of the unit. Needed to know if schedulers should run here.
60
59
  tracing_enabled: True if tracing should be enabled.
61
60
  logging_format: Structured logging format to use; ``LoggingFormat.NONE`` for default.
@@ -71,8 +70,8 @@ class WorkloadConfig: # pylint: disable=too-many-instance-attributes
71
70
  state_dir: pathlib.Path
72
71
  service_name: str
73
72
  log_files: List[pathlib.Path]
74
- metrics_target: str | None = None
75
73
  metrics_path: str | None = "/metrics"
74
+ metrics_port: int = 8080
76
75
  unit_name: str
77
76
  tracing_enabled: bool = False
78
77
  logging_format: LoggingFormat = LoggingFormat.NONE
@@ -152,21 +151,6 @@ def generate_rabbitmq_env(
152
151
  return envvars
153
152
 
154
153
 
155
- def generate_redis_env(relation_data: "PaaSRedisRelationData | None" = None) -> dict[str, str]:
156
- """Generate environment variable from Redis relation data.
157
-
158
- Args:
159
- relation_data: The charm Redis integration relation data.
160
-
161
- Returns:
162
- Redis environment mappings if Redis relation data is available, empty
163
- dictionary otherwise.
164
- """
165
- if not relation_data:
166
- return {}
167
- return _db_url_to_env_variables("REDIS", str(relation_data.url))
168
-
169
-
170
154
  def generate_valkey_env(
171
155
  relation_data: ValkeyResponseModel | None = None,
172
156
  ) -> dict[str, str]:
@@ -392,7 +376,6 @@ class App: # pylint: disable=too-many-instance-attributes
392
376
  generate_db_env: Maps database connection information to environment variables.
393
377
  generate_openfga_env: Maps OpenFGA connection information to environment variables.
394
378
  generate_rabbitmq_env: Maps RabbitMQ connection information to environment variables.
395
- generate_redis_env: Maps Redis connection information to environment variables.
396
379
  generate_valkey_env: Maps Valkey connection information to environment variables.
397
380
  generate_s3_env: Maps S3 connection information to environment variables.
398
381
  generate_saml_env: Maps SAML connection information to environment variables.
@@ -405,7 +388,6 @@ class App: # pylint: disable=too-many-instance-attributes
405
388
  generate_db_env = staticmethod(generate_db_env)
406
389
  generate_openfga_env = staticmethod(generate_openfga_env)
407
390
  generate_rabbitmq_env = staticmethod(generate_rabbitmq_env)
408
- generate_redis_env = staticmethod(generate_redis_env)
409
391
  generate_valkey_env = staticmethod(generate_valkey_env)
410
392
  generate_s3_env = staticmethod(generate_s3_env)
411
393
  generate_saml_env = staticmethod(generate_saml_env)
@@ -421,7 +403,7 @@ class App: # pylint: disable=too-many-instance-attributes
421
403
  charm_state: CharmState,
422
404
  workload_config: WorkloadConfig,
423
405
  database_migration: DatabaseMigration,
424
- framework_config_prefix: str = "APP_",
406
+ framework_config_prefix: str = "",
425
407
  configuration_prefix: str = "APP_",
426
408
  integrations_prefix: str = "",
427
409
  ):
@@ -499,6 +481,10 @@ class App: # pylint: disable=too-many-instance-attributes
499
481
  for k, v in framework_config.items()
500
482
  }
501
483
  )
484
+ env[f"{framework_config_prefix}METRICS_PORT"] = str(self._workload_config.metrics_port)
485
+ env[f"{framework_config_prefix}METRICS_PATH"] = (
486
+ self._workload_config.metrics_path or "/metrics"
487
+ )
502
488
 
503
489
  if self._charm_state.base_url:
504
490
  env[f"{prefix}BASE_URL"] = self._charm_state.base_url
@@ -528,7 +514,6 @@ class App: # pylint: disable=too-many-instance-attributes
528
514
  env.update(
529
515
  self.generate_rabbitmq_env(relation_data=self._charm_state.integrations.rabbitmq)
530
516
  )
531
- env.update(self.generate_redis_env(relation_data=self._charm_state.integrations.redis))
532
517
  env.update(self.generate_valkey_env(relation_data=self._charm_state.integrations.valkey))
533
518
  env.update(self.generate_s3_env(relation_data=self._charm_state.integrations.s3))
534
519
  for (