diff --git a/src/charm_types.py b/src/charm_types.py index fe11c11..a72e717 100644 --- a/src/charm_types.py +++ b/src/charm_types.py @@ -44,39 +44,6 @@ class DatasourcePostgreSQL(BaseModel): db: str = Field(min_length=1, description="Database name") uri: str = Field(min_length=1, description="Database connection URI") - @classmethod - def from_relation(cls, model: ops.Model, relation: ops.Relation) -> "DatasourcePostgreSQL": - """Create a DatasourcePostgreSQL from a relation. - - Args: - relation: The relation to get the data from. - model: The model to get the secret from. - - Returns: - A DatasourcePostgreSQL instance. - """ - relation_data = relation.data[relation.app] - user = relation_data.get("username", "") - password = relation_data.get("password", "") - secret_user = relation_data.get("secret-user", "") - if user == "" and secret_user != "": # nosec - secret = model.get_secret(id=secret_user) - secret_fields = ops.Secret.get_content(secret) - user = secret_fields["username"] - password = secret_fields["password"] - host, port = relation_data.get("endpoints", ":").split(":") - db = relation_data.get("database", "") - uri = f"postgres://{user}:{password}@{host}:{port}/{db}" - - return DatasourcePostgreSQL( - user=user, - password=password, - host=host, - port=port, - db=db, - uri=uri, - ) - class CharmConfig(BaseModel): """A named tuple representing an IRC configuration. diff --git a/src/database_observer.py b/src/database_observer.py index 84589c9..528c761 100644 --- a/src/database_observer.py +++ b/src/database_observer.py @@ -56,10 +56,40 @@ def get_db(self) -> typing.Optional[DatasourcePostgreSQL]: Returns: DatasourcePostgreSQL: The datasource model. """ - # not using get_relation due this issue - # https://github.com/canonical/operator/issues/1153 - if not self.model.relations.get(self.database.relation_name): + relation_data = list( + self.database.fetch_relation_data( + fields=["uris", "endpoints", "username", "password", "database"] + ).values() + ) + + if not relation_data: + return None + + # There can be only one database integrated at a time + # with the same interface name. See: metadata.yaml + data = relation_data[0] + + # Check that the relation data is well formed according to the following json_schema: + # https://github.com/canonical/charm-relation-interfaces/blob/main/interfaces/mysql_client/v0/schemas/provider.json + if not all(data.get(key) for key in ("endpoints", "username", "password")): return None - relation = self.model.get_relation(self.relation_name) - return DatasourcePostgreSQL.from_relation(self.model, relation) + database_name = data.get("database", self.database.database) + endpoint = data["endpoints"].split(",")[0] + user = data["username"] + password = data["password"] + host, port = endpoint.split(":") + + if "uris" in data: + uri = data["uris"].split(",")[0] + else: + uri = f"postgres://{user}:{password}@{endpoint}/{database_name}" + + return DatasourcePostgreSQL( + user=user, + password=password, + host=host, + port=port, + db=database_name, + uri=uri, + ) diff --git a/tests/unit/test_database_observer.py b/tests/unit/test_database_observer.py index a4aecf8..45c119b 100644 --- a/tests/unit/test_database_observer.py +++ b/tests/unit/test_database_observer.py @@ -96,7 +96,28 @@ def test_get_db_when_no_relation_data(): """ harness = Harness(ObservedCharm, meta=REQUIRER_METADATA) harness.begin() - harness.add_relation("database", "database-provider") + harness.add_relation("database", "database-provider", app_data={}) + + assert harness.charm.database.get_db() is None + + +def test_get_db_when_invalid_relation_data(): + """ + arrange: set up a charm and a database relation with invalid databag. + act:. + assert: it raises a validation error. + """ + harness = Harness(ObservedCharm, meta=REQUIRER_METADATA) + harness.begin() + harness.add_relation( + "database", + "database-provider", + app_data={ + "database": "ircbridge", + "endpoints": "postgresql-k8s-primary.local:5432", + "password": "", + "username": "", + }, + ) - with pytest.raises(ValidationError): - harness.charm.database.get_db() # pylint: disable=pointless-statement + assert harness.charm.database.get_db() is None