Skip to content

Commit

Permalink
Apply suggestions from review
Browse files Browse the repository at this point in the history
  • Loading branch information
weiiwang01 committed Sep 20, 2024
1 parent cbb37b4 commit 0e7e3fc
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 134 deletions.
2 changes: 1 addition & 1 deletion examples/django/charm/charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ config:
This configuration is similar to `django-secret-key`, but instead accepts a Juju user secret ID.
The secret should contain a single key, "value", which maps to the actual Django secret key.
To create the secret, run the following command:
`juju add-secret my-django-secret-key value=secret-string && juju grant-secret my-django-secret-key django-k8s`,
`juju add-secret my-django-secret-key value=<secret-string> && juju grant-secret my-django-secret-key django-k8s`,
and use the outputted secret ID to configure this option.
type: secret
webserver-keepalive:
Expand Down
2 changes: 1 addition & 1 deletion examples/fastapi/charm/charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ config:
This configuration is similar to `app-secret-key`, but instead accepts a Juju user secret ID.
The secret should contain a single key, "value", which maps to the actual secret key.
To create the secret, run the following command:
`juju add-secret my-secret-key value=secret-string && juju grant-secret my-secret-key fastapi-k8s`,
`juju add-secret my-secret-key value=<secret-string> && juju grant-secret my-secret-key fastapi-k8s`,
and use the outputted secret ID to configure this option.
user-defined-config:
type: string
Expand Down
2 changes: 1 addition & 1 deletion examples/flask/charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ config:
This configuration is similar to `flask-secret-key`, but instead accepts a Juju user secret ID.
The secret should contain a single key, "value", which maps to the actual Flask secret key.
To create the secret, run the following command:
`juju add-secret my-flask-secret-key value=secret-string && juju grant-secret my-flask-secret-key flask-k8s`,
`juju add-secret my-flask-secret-key value=<secret-string> && juju grant-secret my-flask-secret-key flask-k8s`,
and use the outputted secret ID to configure this option.
type: secret
flask-session-cookie-secure:
Expand Down
2 changes: 1 addition & 1 deletion examples/go/charm/charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ config:
This configuration is similar to `app-secret-key`, but instead accepts a Juju user secret ID.
The secret should contain a single key, "value", which maps to the actual secret key.
To create the secret, run the following command:
`juju add-secret my-secret-key value=secret-string && juju grant-secret my-secret-key go-k8s`,
`juju add-secret my-secret-key value=<secret-string> && juju grant-secret my-secret-key go-k8s`,
and use the outputted secret ID to configure this option.
user-defined-config:
type: string
Expand Down
59 changes: 23 additions & 36 deletions paas_app_charmer/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ def __init__(self, framework: ops.Framework, framework_name: str) -> None:
self._on_secret_storage_relation_changed,
)
self.framework.observe(self.on.update_status, self._on_update_status)
if ops.JujuVersion.from_environ().has_secrets:
self.framework.observe(self.on.secret_changed, self._on_secret_changed)
self.framework.observe(self.on.secret_changed, self._on_secret_changed)
for database, database_requirer in self._database_requirers.items():
self.framework.observe(
database_requirer.on.database_created,
Expand Down Expand Up @@ -188,21 +187,13 @@ def _container(self) -> Container:
return self.unit.get_container(self._workload_config.container_name)

@block_if_invalid_config
def _on_config_changed(self, _event: ops.EventBase) -> None:
"""Configure the application pebble service layer.
Args:
_event: the config-changed event that triggers this callback function.
"""
def _on_config_changed(self, _: ops.EventBase) -> None:
"""Configure the application pebble service layer."""
self.restart()

@block_if_invalid_config
def _on_secret_changed(self, _event: ops.EventBase) -> None:
"""Configure the application Pebble service layer.
Args:
_event: the secret-changed event that triggers this callback function.
"""
def _on_secret_changed(self, _: ops.EventBase) -> None:
"""Configure the application Pebble service layer."""
self.restart()

@block_if_invalid_config
Expand All @@ -223,12 +214,8 @@ def _on_rotate_secret_key_action(self, event: ops.ActionEvent) -> None:
self.restart()

@block_if_invalid_config
def _on_secret_storage_relation_changed(self, _event: ops.RelationEvent) -> None:
"""Handle the secret-storage-relation-changed event.
Args:
_event: the action event that triggers this callback.
"""
def _on_secret_storage_relation_changed(self, _: ops.RelationEvent) -> None:
"""Handle the secret-storage-relation-changed event."""
self.restart()

def update_app_and_unit_status(self, status: ops.StatusBase) -> None:
Expand Down Expand Up @@ -371,67 +358,67 @@ def _on_update_status(self, _: ops.HookEvent) -> None:
self.restart()

@block_if_invalid_config
def _on_mysql_database_database_created(self, _event: DatabaseRequiresEvent) -> None:
def _on_mysql_database_database_created(self, _: DatabaseRequiresEvent) -> None:
"""Handle mysql's database-created event."""
self.restart()

@block_if_invalid_config
def _on_mysql_database_endpoints_changed(self, _event: DatabaseRequiresEvent) -> None:
def _on_mysql_database_endpoints_changed(self, _: DatabaseRequiresEvent) -> None:
"""Handle mysql's endpoints-changed event."""
self.restart()

@block_if_invalid_config
def _on_mysql_database_relation_broken(self, _event: ops.RelationBrokenEvent) -> None:
def _on_mysql_database_relation_broken(self, _: ops.RelationBrokenEvent) -> None:
"""Handle mysql's relation-broken event."""
self.restart()

@block_if_invalid_config
def _on_postgresql_database_database_created(self, _event: DatabaseRequiresEvent) -> None:
def _on_postgresql_database_database_created(self, _: DatabaseRequiresEvent) -> None:
"""Handle postgresql's database-created event."""
self.restart()

@block_if_invalid_config
def _on_postgresql_database_endpoints_changed(self, _event: DatabaseRequiresEvent) -> None:
def _on_postgresql_database_endpoints_changed(self, _: DatabaseRequiresEvent) -> None:
"""Handle mysql's endpoints-changed event."""
self.restart()

@block_if_invalid_config
def _on_postgresql_database_relation_broken(self, _event: ops.RelationBrokenEvent) -> None:
def _on_postgresql_database_relation_broken(self, _: ops.RelationBrokenEvent) -> None:
"""Handle postgresql's relation-broken event."""
self.restart()

@block_if_invalid_config
def _on_mongodb_database_database_created(self, _event: DatabaseRequiresEvent) -> None:
def _on_mongodb_database_database_created(self, _: DatabaseRequiresEvent) -> None:
"""Handle mongodb's database-created event."""
self.restart()

@block_if_invalid_config
def _on_mongodb_database_endpoints_changed(self, _event: DatabaseRequiresEvent) -> None:
def _on_mongodb_database_endpoints_changed(self, _: DatabaseRequiresEvent) -> None:
"""Handle mysql's endpoints-changed event."""
self.restart()

@block_if_invalid_config
def _on_mongodb_database_relation_broken(self, _event: ops.RelationBrokenEvent) -> None:
def _on_mongodb_database_relation_broken(self, _: ops.RelationBrokenEvent) -> None:
"""Handle postgresql's relation-broken event."""
self.restart()

@block_if_invalid_config
def _on_redis_relation_updated(self, _event: DatabaseRequiresEvent) -> None:
def _on_redis_relation_updated(self, _: DatabaseRequiresEvent) -> None:
"""Handle redis's database-created event."""
self.restart()

@block_if_invalid_config
def _on_s3_credential_changed(self, _event: ops.HookEvent) -> None:
def _on_s3_credential_changed(self, _: ops.HookEvent) -> None:
"""Handle s3 credentials-changed event."""
self.restart()

@block_if_invalid_config
def _on_s3_credential_gone(self, _event: ops.HookEvent) -> None:
def _on_s3_credential_gone(self, _: ops.HookEvent) -> None:
"""Handle s3 credentials-gone event."""
self.restart()

@block_if_invalid_config
def _on_saml_data_available(self, _event: ops.HookEvent) -> None:
def _on_saml_data_available(self, _: ops.HookEvent) -> None:
"""Handle saml data available event."""
self.restart()

Expand All @@ -451,16 +438,16 @@ def _on_pebble_ready(self, _: ops.PebbleReadyEvent) -> None:
self.restart()

@block_if_invalid_config
def _on_rabbitmq_connected(self, _event: ops.HookEvent) -> None:
def _on_rabbitmq_connected(self, _: ops.HookEvent) -> None:
"""Handle rabbitmq connected event."""
self.restart()

@block_if_invalid_config
def _on_rabbitmq_ready(self, _event: ops.HookEvent) -> None:
def _on_rabbitmq_ready(self, _: ops.HookEvent) -> None:
"""Handle rabbitmq ready event."""
self.restart()

@block_if_invalid_config
def _on_rabbitmq_departed(self, _event: ops.HookEvent) -> None:
def _on_rabbitmq_departed(self, _: ops.HookEvent) -> None:
"""Handle rabbitmq departed event."""
self.restart()
29 changes: 6 additions & 23 deletions paas_app_charmer/django/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,31 @@
import typing

import ops
from pydantic import BaseModel, Extra, Field, model_validator, validator
from pydantic import ConfigDict, Field, validator

from paas_app_charmer._gunicorn.charm import GunicornBase
from paas_app_charmer.framework import FrameworkConfig

logger = logging.getLogger(__name__)


class DjangoConfig(BaseModel, extra=Extra.ignore):
class DjangoConfig(FrameworkConfig):
"""Represent Django builtin configuration values.
Attrs:
debug: whether Django debug mode is enabled.
secret_key: a secret key that will be used for security related needs by your
Django application.
allowed_hosts: a list of host/domain names that this Django site can serve.
model_config: Pydantic model configuration.
"""

debug: bool | None = Field(alias="django-debug", default=None)
secret_key: str | None = Field(alias="django-secret-key", default=None, min_length=1)
allowed_hosts: str | None = Field(alias="django-allowed-hosts", default=[])

model_config = ConfigDict(extra="ignore")

@validator("allowed_hosts")
@classmethod
def allowed_hosts_to_list(cls, value: str | None) -> typing.List[str]:
Expand All @@ -44,27 +48,6 @@ def allowed_hosts_to_list(cls, value: str | None) -> typing.List[str]:
return []
return [h.strip() for h in value.split(",")]

@model_validator(mode="before")
@classmethod
def secret_key_id(cls, data: dict[str, str | int | bool | dict[str, str] | None]) -> dict:
"""Read the new *-secret-key-id style configuration.
Args:
data: model input.
Returns:
modified input with *-secret-key replaced by the secret content of *-secret-key-id.
Raises:
ValueError: if the *-secret-key-id is invalid.
"""
if "django-secret-key-id" in data and data["django-secret-key-id"]:
secret_value = typing.cast(dict[str, str], data["django-secret-key-id"])
if "value" not in secret_value:
raise ValueError("django-secret-key-id missing 'value' key in the secret content")
data["django-secret-key"] = secret_value["value"]
return data


class Charm(GunicornBase):
"""Django Charm service.
Expand Down
27 changes: 5 additions & 22 deletions paas_app_charmer/fastapi/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import typing

import ops
from pydantic import BaseModel, Extra, Field, model_validator
from pydantic import ConfigDict, Field

from paas_app_charmer.app import App, WorkloadConfig
from paas_app_charmer.charm import PaasCharm
from paas_app_charmer.framework import FrameworkConfig


class FastAPIConfig(BaseModel, extra=Extra.ignore):
class FastAPIConfig(FrameworkConfig):
"""Represent FastAPI builtin configuration values.
Attrs:
Expand All @@ -25,6 +26,7 @@ class FastAPIConfig(BaseModel, extra=Extra.ignore):
metrics_path: path where the metrics are collected
app_secret_key: a secret key that will be used for securely signing the session cookie
and can be used for any other security related needs by your Flask application.
model_config: Pydantic model configuration.
"""

uvicorn_port: int = Field(alias="webserver-port", default=8080, gt=0)
Expand All @@ -37,26 +39,7 @@ class FastAPIConfig(BaseModel, extra=Extra.ignore):
metrics_path: str | None = Field(alias="metrics-path", default=None, min_length=1)
app_secret_key: str | None = Field(alias="app-secret-key", default=None, min_length=1)

@model_validator(mode="before")
@classmethod
def secret_key_id(cls, data: dict[str, str | int | bool | dict[str, str] | None]) -> dict:
"""Read the new *-secret-key-id style configuration.
Args:
data: model input.
Returns:
modified input with *-secret-key replaced by the secret content of *-secret-key-id.
Raises:
ValueError: if the *-secret-key-id is invalid.
"""
if "app-secret-key-id" in data and data["app-secret-key-id"]:
secret_value = typing.cast(dict[str, str], data["app-secret-key-id"])
if "value" not in secret_value:
raise ValueError("app-secret-key-id missing 'value' key in the secret content")
data["app-secret-key"] = secret_value["value"]
return data
model_config = ConfigDict(extra="ignore")


class Charm(PaasCharm):
Expand Down
29 changes: 5 additions & 24 deletions paas_app_charmer/flask/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
"""Flask Charm service."""
import logging
import pathlib
import typing

import ops
from pydantic import BaseModel, Extra, Field, field_validator, model_validator
from pydantic import ConfigDict, Field, field_validator

from paas_app_charmer._gunicorn.charm import GunicornBase
from paas_app_charmer.framework import FrameworkConfig

logger = logging.getLogger(__name__)


class FlaskConfig(BaseModel, extra=Extra.ignore):
class FlaskConfig(FrameworkConfig):
"""Represent Flask builtin configuration values.
Attrs:
Expand All @@ -29,6 +29,7 @@ class FlaskConfig(BaseModel, extra=Extra.ignore):
session_cookie_secure: set the secure attribute in the Flask application cookies.
preferred_url_scheme: use this scheme for generating external URLs when not in a request
context in the Flask application.
model_config: Pydantic model configuration.
"""

env: str | None = Field(alias="flask-env", default=None, min_length=1)
Expand All @@ -44,6 +45,7 @@ class FlaskConfig(BaseModel, extra=Extra.ignore):
preferred_url_scheme: str | None = Field(
alias="flask-preferred-url-scheme", default=None, pattern="(?i)^(HTTP|HTTPS)$"
)
model_config = ConfigDict(extra="ignore")

@field_validator("preferred_url_scheme")
@staticmethod
Expand All @@ -58,27 +60,6 @@ def to_upper(value: str) -> str:
"""
return value.upper()

@model_validator(mode="before")
@classmethod
def secret_key_id(cls, data: dict[str, str | int | bool | dict[str, str] | None]) -> dict:
"""Read the new *-secret-key-id style configuration.
Args:
data: model input.
Returns:
modified input with *-secret-key replaced by the secret content of *-secret-key-id.
Raises:
ValueError: if the *-secret-key-id is invalid.
"""
if "flask-secret-key-id" in data and data["flask-secret-key-id"]:
secret_value = typing.cast(dict[str, str], data["flask-secret-key-id"])
if "value" not in secret_value:
raise ValueError("flask-secret-key-id missing 'value' key in the secret content")
data["flask-secret-key"] = secret_value["value"]
return data


class Charm(GunicornBase):
"""Flask Charm service.
Expand Down
Loading

0 comments on commit 0e7e3fc

Please sign in to comment.