-
Notifications
You must be signed in to change notification settings - Fork 1
Add juju config and logic for creating traefik routes #3
Add juju config and logic for creating traefik routes #3
Conversation
rule: Optional[str] = None | ||
|
||
@property | ||
def is_valid(self) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a question about the attribute validation logic: Do you think it is better if we implement it via a descriptor class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The attribute validation logic is based on the traefik-route charm.
For simplicity of maintenance (and solving possible bugs), I would keep this part as in the "upstream" charm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I see that you are referring to this part: https://github.com/canonical/traefik-route-k8s-operator/blob/main/src/charm.py#L69-L108, right? Probably I don't understand the biz logic. But yeah, go ahead to keep this part if it is easy to maintain.
f"{name}=<{name.upper()}>" | ||
) | ||
|
||
elif obj != (stripped := obj.strip()): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe str.startswith
and str.endswith
?
Another thing is that:
Is this rule very important to us in the biz logic? If not, probably it would be better if we could skip verifying this by normalizing the attribute based on some rules (e.g. do not start or end with whitespaces) for users. We can normalize it when we set the attribute using the descriptor.
return f"Host(`{url_.hostname}`)" | ||
|
||
|
||
def _is_not_empty(config: str) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
Probably we can name it with a better function name, e.g. _is_access_rule_xxx
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using it for both access rules and root_url configs. Does _is_config_not_empty
sound better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, sure.
src/charm.py
Outdated
return self._config.render(model_name=model_name, unit_name=unit_name, app_name=app_name) | ||
|
||
@staticmethod | ||
def _generate_traefik_unit_config(config: RouteConfig) -> UnitConfig: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the logic about traefik unit config generation, merging, checking if it is ready, etc. is nothing to do with the charm itself. Do you think it is better we extract them into an individual class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could extract some of that logic into an individual class, but most of it is coupled with the charm, e.g. when it relies on charm relations, config or unit status, or uses charm's stored state to store info on config's validity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some comments, most of them are related to the code style and you can ignore them if you disagree.
What I fail to understand is what is this charm's relation to the traefik-route-k8s-operator
, it looks like it tries to serve a superset of its functionality. I also fail to see how the config is supposed to work.
rule: | ||
default: | ||
description: | | ||
A Traefik routing rule, see https://doc.traefik.io/traefik/routing/routers/ for | ||
an overview. | ||
|
||
The value of the field is going to be processed as a Jinja2 template, with the | ||
following globals available: | ||
- {{juju_model}} resolves to the model name of the downstream proxied | ||
application. | ||
- {{juju_application}} resolves to the application name of the downstream | ||
proxied application. | ||
- {{juju_unit}} resolves to the unit name of the downstream proxied unit; | ||
to avoid issues when used together with the Host directive or similar, | ||
the slash character between application name and unit index is replaced by a dash. | ||
|
||
For example, given a downstream unit called `prometheus/0` in the `cos` model, the following: | ||
|
||
Host(`foo.bar/{{juju_unit}}-{{juju_model}}`) | ||
|
||
would evaluate to: | ||
|
||
Host(`foo.bar/cos-prometheus-0`) | ||
|
||
If the host is omitted, but the root_url is provided, the charm will | ||
extract the hostname from the url and generate a Host rule for you. | ||
root_url=`http://{{juju_unit}}.bar.baz:80/qux` | ||
--> rule=Host(`{{juju_unit}}.bar.baz`) | ||
type: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why those are needed, shouldn't we get those from a relation??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rule
will be generated from root_url
if the first is not provided (with the globals coming from the relation), although if an admin wants to configure the rules differently, this config option provides that possibility. I'm trying to follow the logic of traefik-route-k8s here as the charm is tested against edge cases.
It's also a ground for non-charmed workloads as I imagine the rules will have to be supplied via config.
This charm is in a way a superset of traefik-route-k8s charm: following the discussion on ID006 spec, we decided to use traefik_route interface as the base for "ingress_auth" (see this diagram) |
Closing as the repo will be archived due to IAP redesign. |
This PR adds:
The further work will be to support generating rules for non-charmed workloads.
Testing Instructions
where
access_rules.json
is a file that contains the rules.The charm will get blocked unless you deploy any charm that supports ingress-per-unit relation, for example prometheus-k8s:
This is because the configurator charm requires some configs which come from that relation to set up the routes (model, unit names, host, port).
When the charm status becomes active, you should see the rendered rule in logs. If you scale up prometheus it should also get updated to include multiple units: