Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relation parameter refactor #36

Merged
merged 8 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ for more!

Additional resources:

* [Tutorial to build a rock for a Flask application](https://documentation.ubuntu.com/rockcraft/en/latest/tutorial/flask/)
* [Tutorial to build a rock for a Flask application](https://documentation.ubuntu.com/rockcraft/en/latest/tutorial/flask.html)
* [Charmcraft `flask-framework` reference](https://juju.is/docs/sdk/charmcraft-extension-flask-framework)
* [Charmcraft `flask-framework` how to guides](https://juju.is/docs/sdk/build-a-paas-charm)
* [Rockcraft`flask-framework`
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ commands that need to be run in the root directory of the Flask application:
rockcraft pack

The `full Rockcraft tutorial
<https://documentation.ubuntu.com/rockcraft/en/latest/tutorial/flask/>`_ for
<https://documentation.ubuntu.com/rockcraft/en/latest/tutorial/flask.html>`_ for
creating an OCI image for a Flask application takes you from a plain Ubuntu
installation to a production ready OCI image for your Flask application.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""Initial migration

Revision ID: eca6177bd16a
Revises:
Revises:
Create Date: 2023-09-05 17:12:56.303534

"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""Initial migration

Revision ID: eca6177bd16a
Revises:
Revises:
Create Date: 2023-09-05 17:12:56.303534

"""
Expand Down
102 changes: 57 additions & 45 deletions src/paas_charm/charm_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import re
import typing
from dataclasses import dataclass, field
from typing import Optional
from typing import Optional, Type, TypeVar

from charms.data_platform_libs.v0.data_interfaces import DatabaseRequires
from pydantic import BaseModel, Extra, Field, ValidationError, ValidationInfo, field_validator
Expand All @@ -20,20 +20,6 @@
logger = logging.getLogger(__name__)


class ProxyConfig(BaseModel):
"""Configuration for network access through proxy.

Attributes:
http_proxy: The http proxy URL.
https_proxy: The https proxy URL.
no_proxy: Comma separated list of hostnames to bypass proxy.
"""

http_proxy: str | None = Field(default=None, pattern="https?://.+")
https_proxy: str | None = Field(default=None, pattern="https?://.+")
no_proxy: typing.Optional[str] = None


# too-many-instance-attributes is okay since we use a factory function to construct the CharmState
class CharmState: # pylint: disable=too-many-instance-attributes
"""Represents the state of the charm.
Expand Down Expand Up @@ -230,8 +216,6 @@ def build( # pylint: disable=too-many-arguments
) -> "IntegrationsState":
"""Initialize a new instance of the IntegrationsState class.

This functions will raise in the configuration is invalid.

Args:
redis_uri: The redis uri provided by the redis charm.
database_requirers: All database requirers object declared by the charm.
Expand All @@ -241,35 +225,14 @@ def build( # pylint: disable=too-many-arguments

Return:
The IntegrationsState instance created.

Raises:
CharmConfigInvalidError: If some parameter in invalid.
"""
if s3_connection_info:
try:
# s3_connection_info is not really a Dict[str, str] as stated in
# charms.data_platform_libs.v0.s3. It is really a
# Dict[str, str | list[str]].
# Ignoring as mypy does not work correctly with that information.
s3_parameters = S3Parameters(**s3_connection_info) # type: ignore[arg-type]
except ValidationError as exc:
error_message = build_validation_error_message(exc)
raise CharmConfigInvalidError(
f"Invalid S3 configuration: {error_message}"
) from exc
else:
s3_parameters = None

if saml_relation_data is not None:
try:
saml_parameters = SamlParameters(**saml_relation_data)
except ValidationError as exc:
error_message = build_validation_error_message(exc)
raise CharmConfigInvalidError(
f"Invalid Saml configuration: {error_message}"
) from exc
else:
saml_parameters = None
s3_parameters = typing.cast(
S3Parameters | None, generate_relation_parameters(s3_connection_info, S3Parameters)
)
saml_parameters = typing.cast(
SamlParameters | None,
generate_relation_parameters(saml_relation_data, SamlParameters, True),
)
alithethird marked this conversation as resolved.
Show resolved Hide resolved

# Workaround as the Redis library temporarily sends the port
# as None while the integration is being created.
Expand All @@ -289,6 +252,55 @@ def build( # pylint: disable=too-many-arguments
)


RelationParam = TypeVar("RelationParam", "SamlParameters", "S3Parameters")


def generate_relation_parameters(
relation_data: dict[str, str] | typing.MutableMapping[str, str] | None,
parameter_type: Type[RelationParam],
support_empty: bool = False,
) -> "RelationParam | None":
alithethird marked this conversation as resolved.
Show resolved Hide resolved
"""Generate relation parameter class from relation data.

Args:
relation_data: Relation data.
parameter_type: Parameter type to use.
support_empty: Support empty relation data.

Return:
Parameter instance created.

Raises:
CharmConfigInvalidError: If some parameter in invalid.
"""
if not support_empty and not relation_data:
return None
if relation_data is None:
return None

try:
return parameter_type.parse_obj(relation_data)
except ValidationError as exc:
error_message = build_validation_error_message(exc)
raise CharmConfigInvalidError(
f"Invalid {parameter_type.__name__} configuration: {error_message}"
) from exc


class ProxyConfig(BaseModel):
"""Configuration for network access through proxy.

Attributes:
http_proxy: The http proxy URL.
https_proxy: The https proxy URL.
no_proxy: Comma separated list of hostnames to bypass proxy.
"""

http_proxy: str | None = Field(default=None, pattern="https?://.+")
https_proxy: str | None = Field(default=None, pattern="https?://.+")
no_proxy: typing.Optional[str] = None


class S3Parameters(BaseModel):
"""Configuration for accessing S3 bucket.

Expand Down
2 changes: 1 addition & 1 deletion src/paas_charm/charm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def update_app_and_unit_status(self, status: ops.StatusBase) -> None:


def block_if_invalid_config(
method: typing.Callable[[C, E], None]
method: typing.Callable[[C, E], None],
) -> typing.Callable[[C, E], None]:
"""Create a decorator that puts the charm in blocked state if the config is wrong.

Expand Down
Loading