postgresql-charms-single-kernel 16.2.2__tar.gz → 16.3.1__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 (53) hide show
  1. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/PKG-INFO +16 -2
  2. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/pyproject.toml +26 -8
  3. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/charms/__init__.py +5 -0
  4. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/charms/abstract_charm.py +76 -0
  5. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/charms/k8s_charm.py +65 -0
  6. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/charms/vm_charm.py +58 -0
  7. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/config/enums.py +13 -0
  8. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/config/exceptions.py +75 -0
  9. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/config/literals.py +176 -0
  10. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/config/locales.py +527 -0
  11. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/config/statuses.py +47 -0
  12. {postgresql_charms_single_kernel-16.2.2/single_kernel_postgresql/events → postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/core}/__init__.py +1 -1
  13. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/core/config.py +266 -0
  14. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/core/peer_relation.py +398 -0
  15. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/core/relation_state.py +110 -0
  16. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/core/state.py +481 -0
  17. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/events/__init__.py +3 -0
  18. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/events/postgresql.py +230 -0
  19. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/lib/charms/data_platform_libs/v0/data_interfaces.py +5774 -0
  20. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/lib/charms/data_platform_libs/v1/data_models.py +361 -0
  21. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/__init__.py +8 -0
  22. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/base.py +44 -0
  23. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/cluster.py +151 -0
  24. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/config.py +295 -0
  25. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/k8s.py +161 -0
  26. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/patroni.py +894 -0
  27. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/managers/tls.py +100 -0
  28. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/utils/__init__.py +14 -1
  29. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/utils/arch.py +46 -0
  30. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/utils/postgresql.py +1 -1
  31. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/utils/secret.py +14 -0
  32. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/utils/status.py +32 -0
  33. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/__init__.py +12 -0
  34. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/base.py +245 -0
  35. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/k8s.py +212 -0
  36. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/paths/__init__.py +7 -0
  37. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/paths/base.py +84 -0
  38. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/paths/k8s.py +74 -0
  39. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/paths/vm.py +105 -0
  40. postgresql_charms_single_kernel-16.3.1/single_kernel_postgresql/workload/vm.py +225 -0
  41. postgresql_charms_single_kernel-16.2.2/single_kernel_postgresql/abstract_charm.py +0 -27
  42. postgresql_charms_single_kernel-16.2.2/single_kernel_postgresql/config/literals.py +0 -32
  43. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/LICENSE +0 -0
  44. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/README.md +0 -0
  45. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/__init__.py +0 -0
  46. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/charmcraft.yaml +0 -0
  47. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/compat/__init__.py +0 -0
  48. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/compat/postgresql.py +0 -0
  49. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/compat/pyproject.toml +0 -0
  50. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/config/__init__.py +0 -0
  51. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/config/pyproject.toml +0 -0
  52. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/events/tls_transfer.py +0 -0
  53. {postgresql_charms_single_kernel-16.2.2 → postgresql_charms_single_kernel-16.3.1}/single_kernel_postgresql/utils/filesystem.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: postgresql-charms-single-kernel
3
- Version: 16.2.2
3
+ Version: 16.3.1
4
4
  Summary: Shared and reusable code for PostgreSQL-related charms
5
5
  Author: Canonical Data Platform
6
6
  Author-email: Canonical Data Platform <data-platform@lists.launchpad.net>
@@ -210,11 +210,25 @@ Classifier: Development Status :: 3 - Alpha
210
210
  Classifier: Intended Audience :: Developers
211
211
  Classifier: Operating System :: POSIX :: Linux
212
212
  Requires-Dist: ops>=2.0.0
213
- Requires-Dist: psycopg2>=2.9.10
214
213
  Requires-Dist: tenacity>=9.0.0
214
+ Requires-Dist: psycopg2>=2.9.10 ; extra == 'db-driver'
215
215
  Requires-Dist: httpx ; python_full_version >= '3.12' and extra == 'postgresql'
216
+ Requires-Dist: data-platform-helpers>=0.1.7 ; python_full_version >= '3.12' and extra == 'postgresql'
217
+ Requires-Dist: charmlibs-pathops>=1.0.1 ; python_full_version >= '3.12' and extra == 'postgresql'
218
+ Requires-Dist: charmlibs-interfaces-tls-certificates>=1.8.3 ; python_full_version >= '3.12' and extra == 'postgresql'
219
+ Requires-Dist: charm-refresh ; python_full_version >= '3.12' and extra == 'postgresql'
220
+ Requires-Dist: requests ; python_full_version >= '3.12' and extra == 'postgresql'
221
+ Requires-Dist: tomli ; python_full_version >= '3.12' and extra == 'postgresql'
222
+ Requires-Dist: pydantic>=2.0 ; python_full_version >= '3.12' and extra == 'postgresql'
223
+ Requires-Dist: jinja2>=3.1.6 ; python_full_version >= '3.12' and extra == 'postgresql'
224
+ Requires-Dist: charmlibs-rollingops>=1.1.1 ; python_full_version >= '3.12' and extra == 'postgresql'
225
+ Requires-Dist: pysyncobj>=0.3.15 ; python_full_version >= '3.12' and extra == 'vm'
226
+ Requires-Dist: psutil>=7.2.2 ; python_full_version >= '3.12' and extra == 'vm'
227
+ Requires-Dist: charmlibs-snap>=1.0.1 ; python_full_version >= '3.12' and extra == 'vm'
216
228
  Requires-Python: >=3.8, <4.0
229
+ Provides-Extra: db-driver
217
230
  Provides-Extra: postgresql
231
+ Provides-Extra: vm
218
232
  Description-Content-Type: text/markdown
219
233
 
220
234
  # postgresql-single-kernel-library
@@ -4,7 +4,7 @@
4
4
  [project]
5
5
  name = "postgresql-charms-single-kernel"
6
6
  description = "Shared and reusable code for PostgreSQL-related charms"
7
- version = "16.2.2"
7
+ version = "16.3.1"
8
8
  readme = "README.md"
9
9
  license = {file = "LICENSE"}
10
10
  authors = [
@@ -18,12 +18,30 @@ classifiers = [
18
18
  requires-python = ">=3.8,<4.0"
19
19
  dependencies = [
20
20
  "ops>=2.0.0",
21
- "psycopg2>=2.9.10",
22
21
  "tenacity>=9.0.0",
23
22
  ]
24
23
 
25
24
  [project.optional-dependencies]
26
- postgresql = ["httpx; python_version >= '3.12'"]
25
+ postgresql = [
26
+ "httpx; python_version >= '3.12'",
27
+ "data-platform-helpers>=0.1.7; python_version >= '3.12'",
28
+ "charmlibs-pathops>=1.0.1; python_version >= '3.12'",
29
+ "charmlibs-interfaces-tls-certificates>=1.8.3; python_version >= '3.12'",
30
+ "charm-refresh; python_version >= '3.12'",
31
+ "requests; python_version >= '3.12'",
32
+ "tomli; python_version >= '3.12'",
33
+ "pydantic>=2.0; python_version >= '3.12'",
34
+ "jinja2 >=3.1.6; python_version >= '3.12'",
35
+ "charmlibs-rollingops>=1.1.1; python_version >= '3.12'",
36
+ ]
37
+ vm = [
38
+ "pysyncobj>=0.3.15; python_version >= '3.12'",
39
+ "psutil>=7.2.2; python_version >= '3.12'",
40
+ "charmlibs-snap>=1.0.1; python_version >= '3.12'",
41
+ ]
42
+ db-driver = [
43
+ "psycopg2>=2.9.10",
44
+ ]
27
45
 
28
46
  [build-system]
29
47
  requires = ["uv_build>=0.11.0,<0.12.0"]
@@ -35,15 +53,15 @@ module-root = ""
35
53
 
36
54
  [dependency-groups]
37
55
  format = [
38
- "ruff==0.15.14"
56
+ "ruff==0.15.20"
39
57
  ]
40
58
  lint = [
41
59
  "codespell==2.4.2",
42
- "ty==0.0.39"
60
+ "ty==0.0.55"
43
61
  ]
44
62
  unit = [
45
- "coverage[toml]==7.14.0",
46
- "pytest==9.0.3"
63
+ "coverage[toml]==7.14.3",
64
+ "pytest==9.1.1"
47
65
  ]
48
66
 
49
67
 
@@ -117,4 +135,4 @@ python = ".tox/lint/"
117
135
  python-version = "3.12"
118
136
 
119
137
  [tool.ty.src]
120
- exclude = ["tests"]
138
+ exclude = ["tests", "single_kernel_postgresql/lib"]
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2026 Canonical Ltd.
3
+ # See LICENSE file for licensing details.
4
+
5
+ """Charms Definitions."""
@@ -0,0 +1,76 @@
1
+ # Copyright 2025 Canonical Ltd.
2
+ # See LICENSE file for licensing details.
3
+ """Skeleton for the abstract charm."""
4
+
5
+ from abc import ABC, abstractmethod
6
+
7
+ from data_platform_helpers.advanced_statuses import StatusHandler
8
+ from ops.charm import CharmBase
9
+
10
+ from single_kernel_postgresql.core.state import CharmState
11
+ from single_kernel_postgresql.events.postgresql import PostgreSQLEventsHandler
12
+ from single_kernel_postgresql.managers.cluster import ClusterManager
13
+ from single_kernel_postgresql.managers.config import ConfigManager
14
+ from single_kernel_postgresql.managers.patroni import PatroniManager
15
+ from single_kernel_postgresql.managers.tls import TLSManager
16
+ from single_kernel_postgresql.workload.base import BaseWorkload
17
+
18
+ from ..config.enums import Substrates
19
+ from ..utils.postgresql import PostgreSQL
20
+
21
+
22
+ class AbstractPostgreSQLCharm(CharmBase, ABC):
23
+ """An abstract PostgreSQL charm."""
24
+
25
+ def __init__(self, *args):
26
+ super().__init__(*args)
27
+
28
+ # State
29
+ self.state = CharmState(charm=self, substrate=self.substrate)
30
+
31
+ # Managers
32
+ self.tls_manager = TLSManager(state=self.state, workload=self.workload)
33
+ self.patroni_manager = PatroniManager(state=self.state, workload=self.workload)
34
+ self.cluster_manager = ClusterManager(state=self.state, workload=self.workload)
35
+ self.config_manager = ConfigManager(state=self.state, workload=self.workload)
36
+
37
+ # Events Handler
38
+ self.postgresql_events_handler = PostgreSQLEventsHandler(
39
+ self,
40
+ self.workload,
41
+ self.state,
42
+ self.cluster_manager,
43
+ self.tls_manager,
44
+ self.config_manager,
45
+ self.patroni_manager,
46
+ )
47
+
48
+ # Status Handler
49
+ self.status_handler = StatusHandler(
50
+ self,
51
+ self.cluster_manager,
52
+ self.tls_manager,
53
+ self.config_manager,
54
+ self.patroni_manager,
55
+ )
56
+
57
+ # Postgresql Client
58
+ @property
59
+ @abstractmethod
60
+ def postgresql(self) -> PostgreSQL:
61
+ """Return a PostgreSQL client."""
62
+ pass
63
+
64
+ # Postgresql Workload
65
+ @property
66
+ @abstractmethod
67
+ def workload(self) -> BaseWorkload:
68
+ """Access current workload."""
69
+ pass
70
+
71
+ # Postgresql Substrate
72
+ @property
73
+ @abstractmethod
74
+ def substrate(self) -> Substrates:
75
+ """Access current substrate."""
76
+ pass
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Canonical Ltd.
3
+ # See LICENSE file for licensing details.
4
+
5
+ """PostgreSQL Kubernetes Charm."""
6
+
7
+ import logging
8
+
9
+ from single_kernel_postgresql.charms.abstract_charm import AbstractPostgreSQLCharm, PostgreSQL
10
+ from single_kernel_postgresql.config.enums import Substrates
11
+ from single_kernel_postgresql.config.literals import CONTAINER_NAME, SYSTEM_USERS, USER
12
+ from single_kernel_postgresql.managers.k8s import K8sManager
13
+ from single_kernel_postgresql.workload.base import BaseWorkload
14
+ from single_kernel_postgresql.workload.k8s import K8sWorkload
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class PostgreSQLK8sCharm(AbstractPostgreSQLCharm):
20
+ """PostgreSQL K8s Charm."""
21
+
22
+ def __init__(self, *args):
23
+ """Initialize the PostgreSQL Kubernetes Charm."""
24
+ super().__init__(*args)
25
+ assert isinstance(self.workload, K8sWorkload), ( # noqa: S101
26
+ "Workload must be an instance of K8sWorkload"
27
+ )
28
+ self.k8s_manager = K8sManager(self.state, self.workload)
29
+
30
+ @property
31
+ def postgresql(self) -> PostgreSQL:
32
+ """Return a PostgreSQL client."""
33
+ return PostgreSQL(
34
+ substrate=Substrates.K8S,
35
+ primary_host="localhost",
36
+ current_host="localhost",
37
+ user=USER,
38
+ # The password is hardcoded because this is an abstract charm and
39
+ # it meant to be used only in unit tests.
40
+ password="test-password", # noqa S106
41
+ database="test-database",
42
+ system_users=SYSTEM_USERS,
43
+ )
44
+
45
+ @property
46
+ def workload(self) -> BaseWorkload:
47
+ """Access current workload instance.
48
+
49
+ Returns the workload object.
50
+
51
+ Returns:
52
+ BaseWorkload: The K8sWorkload instance for this charm
53
+ """
54
+ return K8sWorkload(
55
+ charm_dir=self.charm_dir, container=self.unit.get_container(CONTAINER_NAME)
56
+ )
57
+
58
+ @property
59
+ def substrate(self) -> Substrates:
60
+ """Access current substrate type.
61
+
62
+ Returns:
63
+ Substrates: always Substrates.K8S for this charm
64
+ """
65
+ return Substrates.K8S
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Canonical Ltd.
3
+ # See LICENSE file for licensing details.
4
+
5
+ """PostgreSQL VM Charm."""
6
+
7
+ import logging
8
+
9
+ from single_kernel_postgresql.charms.abstract_charm import AbstractPostgreSQLCharm, PostgreSQL
10
+ from single_kernel_postgresql.config.enums import Substrates
11
+ from single_kernel_postgresql.config.literals import SYSTEM_USERS, USER
12
+ from single_kernel_postgresql.workload.base import BaseWorkload
13
+ from single_kernel_postgresql.workload.vm import VMWorkload
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class PostgreSQLVMCharm(AbstractPostgreSQLCharm):
19
+ """PostgreSQL VM Charm."""
20
+
21
+ def __init__(self, *args):
22
+ """Initialize the PostgreSQL VM Charm."""
23
+ super().__init__(*args)
24
+
25
+ @property
26
+ def postgresql(self) -> PostgreSQL:
27
+ """Return a PostgreSQL client."""
28
+ return PostgreSQL(
29
+ substrate=Substrates.VM,
30
+ primary_host="localhost",
31
+ current_host="localhost",
32
+ user=USER,
33
+ # The password is hardcoded because this is an abstract charm and
34
+ # it meant to be used only in unit tests.
35
+ password="test-password", # noqa S106
36
+ database="test-database",
37
+ system_users=SYSTEM_USERS,
38
+ )
39
+
40
+ @property
41
+ def workload(self) -> BaseWorkload:
42
+ """Access current workload instance.
43
+
44
+ Returns the workload object.
45
+
46
+ Returns:
47
+ BaseWorkload: The VMWorkload instance for this charm
48
+ """
49
+ return VMWorkload(charm_dir=self.charm_dir)
50
+
51
+ @property
52
+ def substrate(self) -> Substrates:
53
+ """Access current substrate type.
54
+
55
+ Returns:
56
+ Substrates: always Substrates.VM for this charm
57
+ """
58
+ return Substrates.VM
@@ -0,0 +1,13 @@
1
+ # Copyright 2025 Canonical Ltd.
2
+ # See LICENSE file for licensing details.
3
+
4
+ """PostgreSQL enums."""
5
+
6
+ from enum import Enum
7
+
8
+
9
+ class Substrates(str, Enum):
10
+ """Possible substrates."""
11
+
12
+ K8S = "k8s"
13
+ VM = "vm"
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Canonical Ltd.
3
+ # See LICENSE file for licensing details.
4
+
5
+ """Charm-specific exceptions."""
6
+
7
+ from single_kernel_postgresql.compat.postgresql import PostgreSQLBaseError
8
+
9
+
10
+ class PostgreSQLFileOperationError(PostgreSQLBaseError):
11
+ """Exception thrown when file operations related to PostgreSQL fail."""
12
+
13
+
14
+ class StorageUnavailableError(Exception):
15
+ """Cannot find storage mountpoint."""
16
+
17
+
18
+ class SettingSystemPasswordError(PostgreSQLBaseError):
19
+ """Exception thrown when setting the system password fails."""
20
+
21
+
22
+ class PostgreSQLCannotConnectError(Exception):
23
+ """Cannot run smoke check on connected Database."""
24
+
25
+
26
+ class TlsError(Exception):
27
+ """TLS implementation internal exception."""
28
+
29
+
30
+ class RaftPostgresqlNotUpError(Exception):
31
+ """Postgresql not yet started."""
32
+
33
+
34
+ class RaftPostgresqlStillUpError(Exception):
35
+ """Postgresql not yet down."""
36
+
37
+
38
+ class RaftNotPromotedError(Exception):
39
+ """Leader not yet set when reinitialising raft."""
40
+
41
+
42
+ class ClusterNotPromotedError(Exception):
43
+ """Raised when a cluster is not promoted."""
44
+
45
+
46
+ class NotReadyError(Exception):
47
+ """Raised when not all cluster members healthy or finished initial sync."""
48
+
49
+
50
+ class EndpointNotReadyError(Exception):
51
+ """Raised when an endpoint is not ready."""
52
+
53
+
54
+ class StandbyClusterAlreadyPromotedError(Exception):
55
+ """Raised when a standby cluster is already promoted."""
56
+
57
+
58
+ class RemoveRaftMemberFailedError(Exception):
59
+ """Raised when a remove raft member failed for some reason."""
60
+
61
+
62
+ class AddRaftMemberFailedError(Exception):
63
+ """Raised when adding raft member failed for some reason."""
64
+
65
+
66
+ class SwitchoverFailedError(Exception):
67
+ """Raised when a switchover failed for some reason."""
68
+
69
+
70
+ class SwitchoverNotSyncError(SwitchoverFailedError):
71
+ """Raised when a switchover failed because node is not sync."""
72
+
73
+
74
+ class UpdateSyncNodeCountError(Exception):
75
+ """Raised when updating synchronous_node_count failed for some reason."""
@@ -0,0 +1,176 @@
1
+ # Copyright 2025 Canonical Ltd.
2
+ # See LICENSE file for licensing details.
3
+ """Literal string for the different charms.
4
+
5
+ This module should contain the literals used in the charms (paths, relation names, etc).
6
+ """
7
+
8
+ from typing import Literal
9
+
10
+ # Permissions.
11
+ POSTGRESQL_STORAGE_PERMISSIONS = 0o700
12
+
13
+ # Relations
14
+ PEER_RELATION = "database-peers"
15
+ STATUS_PEERS_RELATION = "status-peers"
16
+
17
+ # Users.
18
+ BACKUP_USER = "backup"
19
+ MONITORING_USER = "monitoring"
20
+ REPLICATION_USER = "replication"
21
+ REWIND_USER = "rewind"
22
+ SNAP_USER = "_daemon_"
23
+ USER = "operator"
24
+ SYSTEM_USERS = [BACKUP_USER, MONITORING_USER, REPLICATION_USER, REWIND_USER, USER]
25
+
26
+ # Paths
27
+ ## VM Paths
28
+ BASE_SNAP_DIR = "/var/snap/charmed-postgresql"
29
+ SNAP_DATA = "current"
30
+ SNAP_COMMON = "common"
31
+ SNAP = "/snap/charmed-postgresql/current"
32
+ VM_LOGS_PATH = "var/log/postgresql"
33
+ VM_DATA_PATH = "var/lib/postgresql"
34
+ VM_ARCHIVE_PATH = "data/archive"
35
+ VM_DATA_LOGS_PATH = "data/logs"
36
+ VM_TEMP_PATH = "data/temp"
37
+
38
+ ## K8s Paths
39
+ K8S_DATA_PATH = "var/lib/pg/data"
40
+
41
+ ## Shared Paths
42
+ # NOTE: The paths don't have leading slahes since pathops
43
+ # will handle path concatenation otherwise it will use "/var/lib/postgresql"
44
+ # instead of using the root path or any other part defined by the / operator.
45
+ # e.g. snap_current / "/etc/postgresql" will result in "/etc/postgresql" instead of "/var/snap/postgresql/current/etc/postgresql"
46
+ POSTGRESQL_CONF_PATH = "etc/postgresql"
47
+ POSTGRESQL_CONF_FILE = "postgresql.conf"
48
+ ## Pgbackreest Paths
49
+ PGBACKREST_CONF_PATH = "etc/pgbackrest"
50
+ PGBACKREST_CONF_FILE = "pgbackrest.conf"
51
+
52
+ ## TLS Paths
53
+ TLS_CA_BUNDLE_FILE = "peer_ca_bundle.pem"
54
+
55
+ # Scopes
56
+ SCOPES = Literal["app", "unit"]
57
+ APP_SCOPE = "app"
58
+ UNIT_SCOPE = "unit"
59
+
60
+ # Patroni
61
+ ## Patroni Paths
62
+ PATRONI_CONF_PATH = "etc/patroni"
63
+ PATRONI_LOGS_PATH = "var/log/patroni"
64
+ ## Patroni states
65
+ STARTED_STATES = ["running", "streaming"]
66
+ RUNNING_STATES = [*STARTED_STATES, "starting"]
67
+ ## Patroni config
68
+ ORIGINAL_PATRONI_ON_FAILURE_CONDITION = "restart"
69
+
70
+
71
+ # Secrets
72
+ SECRET_KEY_OVERRIDES = {"ca": "cauth"}
73
+
74
+
75
+ # Password keys
76
+ REPLICATION_PASSWORD_KEY = "replication-password" # noqa: S105
77
+ REWIND_PASSWORD_KEY = "rewind-password" # noqa: S105
78
+ USER_PASSWORD_KEY = "operator-password" # noqa: S105
79
+ MONITORING_PASSWORD_KEY = "monitoring-password" # noqa: S105
80
+ RAFT_PASSWORD_KEY = "raft-password" # noqa: S105
81
+ PATRONI_PASSWORD_KEY = "patroni-password" # noqa: S105
82
+ SECRET_INTERNAL_LABEL = "internal-secret" # noqa: S105
83
+ SECRET_DELETED_LABEL = "None" # noqa: S105
84
+ SYSTEM_USERS_PASSWORD_CONFIG = "system-users" # noqa: S105
85
+
86
+ # K8s
87
+ ## K8s Services
88
+ K8S_POSTGRESQL_SERVICE_NAME = "postgresql"
89
+ K8S_PGBACK_REST_SERVER_SERVICE_NAME = "pgbackrest server"
90
+ K8S_LDAP_SYNC_SERVICE_NAME = "ldap-sync"
91
+ K8S_METRICS_SERVER_SERVICE_NAME = "metrics_server"
92
+ K8S_PGBACKREST_METRICS_SERVER_SERVICE_NAME = "pgbackrest_metrics_server"
93
+ K8S_ROTATE_LOGS_SERVICE_NAME = "rotate-logs"
94
+ ## K8s User and group
95
+ K8S_WORKLOAD_OS_GROUP = "postgres"
96
+ K8S_WORKLOAD_OS_USER = "postgres"
97
+
98
+
99
+ # File permissions as octal
100
+ # standard directory permissions
101
+ DIR_PERMISSIONS_READONLY = 0o750
102
+
103
+
104
+ # Container name for K8s deployments
105
+ CONTAINER_NAME = "postgresql"
106
+
107
+ API_REQUEST_TIMEOUT = 5
108
+
109
+
110
+ # --- Shared constants migrated from the charms ---
111
+
112
+ # Database
113
+ DATABASE = "database"
114
+ DATABASE_DEFAULT_NAME = "postgres"
115
+ DATABASE_PORT = "5432"
116
+
117
+ # Client relations
118
+ ALL_CLIENT_RELATIONS = [DATABASE]
119
+
120
+ # Async replication relations
121
+ REPLICATION_CONSUMER_RELATION = "replication"
122
+ REPLICATION_OFFER_RELATION = "replication-offer"
123
+
124
+ # TLS files
125
+ TLS_KEY_FILE = "key.pem"
126
+ TLS_CA_FILE = "ca.pem"
127
+ TLS_CERT_FILE = "cert.pem"
128
+
129
+ # Metrics ports (kept as str to match the K8s charm; VM adapts on flip)
130
+ METRICS_PORT = "9187"
131
+ PGBACKREST_METRICS_PORT = "9854"
132
+
133
+ # Secret/database mapping labels
134
+ USERNAME_MAPPING_LABEL = "custom-usernames"
135
+ DATABASE_MAPPING_LABEL = "prefix-databases"
136
+
137
+ # Overrides
138
+ BACKUP_TYPE_OVERRIDES = {"full": "full", "differential": "diff", "incremental": "incr"}
139
+ PLUGIN_OVERRIDES = {"audit": "pgaudit", "uuid_ossp": '"uuid-ossp"'}
140
+
141
+ # SPI extension modules
142
+ SPI_MODULE = ["refint", "autoinc", "insert_username", "moddatetime"]
143
+
144
+ # Tracing
145
+ TRACING_RELATION_NAME = "tracing"
146
+ TRACING_PROTOCOL = "otlp_http"
147
+
148
+ # Patroni
149
+ PATRONI_CLUSTER_STATUS_ENDPOINT = "cluster"
150
+
151
+ # pgBackRest
152
+ PGBACKREST_LOGROTATE_FILE = "/etc/logrotate.d/pgbackrest.logrotate"
153
+ # pgBackRest emits all error/warning output on stderr (the default is stdout) so error
154
+ # extraction stays consistent. Reference: https://pgbackrest.org/configuration.html#section-log
155
+ PGBACKREST_LOG_LEVEL_STDERR = "--log-level-stderr=warn"
156
+ # Archive timeout: unable to archive WAL files within the configured timeout period.
157
+ PGBACKREST_ARCHIVE_TIMEOUT_ERROR_CODE = 82
158
+
159
+ # Backup ID formats
160
+ BACKUP_ID_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
161
+ PGBACKREST_BACKUP_ID_FORMAT = "%Y%m%d-%H%M%S"
162
+
163
+ # Watcher relation (VM)
164
+ WATCHER_OFFER_RELATION = "watcher-offer"
165
+ WATCHER_RELATION = "watcher"
166
+ WATCHER_USER = "watcher"
167
+ WATCHER_PASSWORD_KEY = "watcher-password" # noqa: S105
168
+ WATCHER_SECRET_LABEL = "watcher-secret" # noqa: S105
169
+
170
+ # Raft
171
+ RAFT_PORT = 2222
172
+ RAFT_PARTNER_PREFIX = "partner_node_status_server_"
173
+
174
+ # VM services
175
+ VM_PATRONI_SERVICE_NAME = "snap.charmed-postgresql.patroni.service"
176
+ VM_PATRONI_SERVICE_DEFAULT_PATH = f"/etc/systemd/system/{VM_PATRONI_SERVICE_NAME}"