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

[DPE-3737] Add a zookeeper_client interface #144

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0a209fd
feat (interface): Add a zookeeper_client interface
Batalex Mar 15, 2024
7ab69b0
Merge branch 'main' into feat/DPE-3737
Batalex Mar 15, 2024
cca873c
feat (schema): Add json schemas
Batalex Mar 15, 2024
f6b98ff
Merge remote-tracking branch 'origin/feat/DPE-3737' into feat/DPE-3737
Batalex Mar 15, 2024
059770b
docs (schema): Improve wording in title and description
Batalex Mar 19, 2024
2893147
docs (interface): Add kafka and zookeeper in charms.yaml
Batalex Mar 19, 2024
ba07bb2
fix: Wording for consistency
Batalex Mar 22, 2024
07d3db3
fix: Rebuild zk json schema
Batalex Mar 22, 2024
07e0d40
WIP: Add minimal provider test
Batalex Apr 25, 2024
912b1b9
tests: Add simple zk interface tests
Batalex Apr 26, 2024
a2fffdd
WIP: Try removing pydantic v2 in zk client interface
Batalex Apr 26, 2024
529e16c
fix (tests): Add requested_secrets to remote app data
Batalex Apr 29, 2024
f2cdcdb
feat: Rename interface to former name
Batalex Apr 29, 2024
1664cef
feat: Add extra-user-roles to requirer schema
Batalex Apr 29, 2024
94a8e2d
Revert "WIP: Try removing pydantic v2 in zk client interface"
Batalex May 2, 2024
8c4e01c
feat: Remove chroot from endpoints value
Batalex May 2, 2024
1876a71
chore: Remove old schema dir
Batalex May 2, 2024
ca2f1f3
Update zookeeper charms list
Batalex May 2, 2024
32b63bf
Merge remote-tracking branch 'upstream/main' into feat/DPE-3737
Batalex May 2, 2024
9b7d5e2
fix: Rename charms.yaml to interface.yaml
Batalex Sep 4, 2024
7d95713
fix: Add missing fields in zk interfaces.yaml
Batalex Sep 4, 2024
0563817
tests: Add zookeeper provider tests
Batalex Sep 5, 2024
cd17bfd
fix: Remove tests & add kyuubi to zookeeper requirers
Batalex Sep 6, 2024
354fac0
Merge branch 'main' into feat/DPE-3737
Batalex Sep 6, 2024
4124021
chore: Remove __init__.py from interfaces root folder
Batalex Sep 6, 2024
31afb08
fix: Add secret_user description field
Batalex Sep 6, 2024
c8704aa
fix: Remove mtls secret field from zookeeper requirer
Batalex Sep 9, 2024
92b7846
Merge branch 'main' into feat/DPE-3737
Batalex Jan 9, 2025
8687e85
refactor: Remove unused Endpoint model
Batalex Jan 20, 2025
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
82 changes: 82 additions & 0 deletions docs/json_schemas/zookeeper/v0/provider.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"$defs": {
"BaseModel": {
"properties": {},
"title": "BaseModel",
"type": "object"
},
"ZooKeeperProviderAppData": {
"properties": {
"database": {
"description": "The parent chroot zNode granted to the requirer",
"examples": [
"/myappB"
],
"title": "zNode",
"type": "string"
},
"endpoints": {
"description": "A comma-seperated list of ZooKeeper server and ports",
"examples": [
"10.141.78.133:2181,10.141.78.50:2181,10.141.78.45:2181"
],
"title": "ZooKeeper endpoints",
"type": "string"
},
"secret-user": {
"description": "",
"examples": [
"secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub6vubg2s77p3nio0"
],
"title": "Credentials Secret Name",
"type": "string"
},
"secret-tls": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The name of the TLS secret to use. Leaving this empty will configure a client with TLS disabled.",
"examples": [
"secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub7fubg2s77p3niog"
],
"title": "TLS Secret Name"
}
},
"required": [
"database",
"endpoints",
"secret-user"
],
"title": "ZooKeeperProviderAppData",
"type": "object"
}
},
"description": "The schema for the provider side of this interface.",
"properties": {
"unit": {
"anyOf": [
{
"$ref": "#/$defs/BaseModel"
},
{
"type": "null"
}
],
"default": null
},
"app": {
"$ref": "#/$defs/ZooKeeperProviderAppData"
}
},
"required": [
"app"
],
"title": "ProviderSchema",
"type": "object"
}
97 changes: 97 additions & 0 deletions docs/json_schemas/zookeeper/v0/requirer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"$defs": {
"BaseModel": {
"properties": {},
"title": "BaseModel",
"type": "object"
},
"ZooKeeperRequirerAppData": {
"properties": {
"database": {
"description": "The parent chroot zNode requested by the requirer",
"examples": [
"/myappA"
],
"title": "zNode",
"type": "string"
},
"extra-user-roles": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "ACL string representation for the parent chroot",
"examples": [
"cdrwa"
],
"title": "User roles"
},
"requested-secrets": {
"description": "Any provider field which should be transfered as Juju Secret",
"examples": [
[
"username",
"password",
"tls-ca",
"uris"
]
],
"items": {
"type": "string"
},
"title": "Requested secrets",
"type": "array"
},
"secret-mtls": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name of the mTLS secret to use. Leaving this empty will configure the provider to not use mTLS.",
"examples": [
"secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub7fubg2s77p3niog"
],
"title": "mTLS Secret Name"
}
},
"required": [
"database",
"requested-secrets",
"secret-mtls"
],
"title": "ZooKeeperRequirerAppData",
"type": "object"
}
},
"description": "The schema for the requirer side of this interface.",
"properties": {
"unit": {
"anyOf": [
{
"$ref": "#/$defs/BaseModel"
},
{
"type": "null"
}
],
"default": null
},
"app": {
"$ref": "#/$defs/ZooKeeperRequirerAppData"
}
},
"required": [
"app"
],
"title": "RequirerSchema",
"type": "object"
}
59 changes: 59 additions & 0 deletions interfaces/zookeeper/v0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# `zookeeper`

## Usage

This relation interface describes the expected behavior of any charm claiming to be able to interface with a Zookeeper cluster.

## Direction

```mermaid
flowchart TD
Requirer -- database, \nrequested-secrets --> Provider
Provider -- database, \nendpoints, \nsecret-user --> Requirer
```

## Behavior

Both the Requirer and the Provider need to adhere to criteria to be considered compatible with the interface.

### Provider

- Is expected to create an application user inside the database cluster when the requirer provides the `database` field.
- Is expected to provide credentials (`username` and `password`) in a Juju Secret whenever the Requirer supplies the `database` field.
- Is expected to expose the Juju Secrets URI to the credentials through the `secret-user` field of the data bag.
- Is expected to provide the `endpoints` field with a comma-separated list of server uris and zNode.
- Is expected to provide the `database` field with the zNode that was actually created.
- Is expected to provide the `version` field whenever database charm wants to communicate its database version.
- Is expected to provide the CA chain in the `tls-ca` field of a Juju Secret, whenever the provider has TLS enabled (such as using the [TLS Certificates Operator](https://github.com/canonical/tls-certificates-operator)).
- Is expected to share the TLS Juju Secret URI through the `secret-tls` field of the databag.
- If the Requirer asks for additional secrets (via `requested-secrets`, see below) other than those stored in the `user` and `tls` secrets, Provider is expected to define a `secret-extra` field holding the URI of the Juju Secret containing all additional secret fields.
- If the Requirer both requested the `tls-ca` and provided `secret-mtls`, the Provider should use enable mTLS.

### Requirer

- Is expected to provide `requested-secrets`, which is a list of field names that are not to be exposed on the relation databag, but handled within Juju Secrets. It should be JSON parsable array of strings, and correspond to valid Juju Secret keys (i.e. alphanumerical characters with a potential '-' (dash) character). Secret fields must contain `username` and `password` (and `tls-ca` in case TLS is enabled).
- Is expected to provide a zNode in the `database` field.
- Is expected to have unique credentials for each relation. Therefore, different instances of the same Charm (juju applications) will have different relations with different credentials.
- Is expected to have different relations names on Requirer with the same interface name if Requirer needs access to multiple database charms.
- Is expected to allow multiple different Juju applications to access the same zNode.
- Is expected to tolerate that the Provider may ignore the `database` field in some cases and instead use the zNode received.
- Can optionally provide the `extra-user-roles` field specifying a ACL string for the client application.
- Can optionally provide the mTLS Juju Secret Uri through the `secret-mtls` field of the databag

## Relation Data

[\[Pydantic Schema\]](./schema.py)


```yaml
provider:
app:
database: /myappB
endpoints: 10.141.78.133:2181,10.141.78.50:2181,10.141.78.45:2181
secret-user: secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub6vubg2s77p3nio0
secret-tls: secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub7fubg2s77p3niog
requirer:
app:
database: myappA
requested-secrets: ["username", "password", "tls-ca", "uris"]
```
17 changes: 17 additions & 0 deletions interfaces/zookeeper/v0/interface.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: zookeeper
version: 0
status: draft

providers:
- name: zookeeper
url: https://github.com/canonical/zookeeper-operator
- name: zookeeper-k8s
url: https://github.com/canonical/zookeeper-k8s-operator

requirers:
- name: kafka
url: https://github.com/canonical/kafka-operator
- name: kafka-k8s
url: https://github.com/canonical/kafka-k8s-operator
- name: kyuubi-k8s-operator
url: https://github.com/canonical/kyuubi-k8s-operator
101 changes: 101 additions & 0 deletions interfaces/zookeeper/v0/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""This file defines the schemas for the provider and requirer sides of the zookeeper_client interface.

It must expose two interfaces.schema_base.DataBagSchema subclasses called:
- ProviderSchema
- RequirerSchema
"""

from typing import Annotated, TypeAlias

from interface_tester.schema_base import DataBagSchema
from pydantic import (
BaseModel,
Field,
IPvAnyAddress,
conint,
)


class Endpoint(BaseModel):
Batalex marked this conversation as resolved.
Show resolved Hide resolved
ip: IPvAnyAddress
port: conint(ge=0, le=65535) | None

def __init__(self, value: str) -> None:
ip, _, port = value.partition(":")
if not port:
port = None
super().__init__(ip=ip, port=port)


Endpoints: TypeAlias = str


class ZooKeeperProviderAppData(BaseModel):
database: str = Field(
description="The parent chroot zNode granted to the requirer",
examples=["/myappB"],
title="zNode",
)

endpoints: Endpoints = Field(
description="A comma-seperated list of ZooKeeper server and ports",
examples=["10.141.78.133:2181,10.141.78.50:2181,10.141.78.45:2181"],
title="ZooKeeper endpoints",
)

secret_user: str = Field(
alias="secret-user",
description="",
Batalex marked this conversation as resolved.
Show resolved Hide resolved
examples=["secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub6vubg2s77p3nio0"],
title="Credentials Secret Name",
)

secret_tls: str | None = Field(
None,
alias="secret-tls",
description="The name of the TLS secret to use. Leaving this empty will configure a client with TLS disabled.",
examples=["secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub7fubg2s77p3niog"],
title="TLS Secret Name",
)


class ZooKeeperRequirerAppData(BaseModel):
database: str = Field(
description="The parent chroot zNode requested by the requirer",
examples=["/myappA"],
title="zNode",
)

extra_user_roles: str | None = Field(
None,
alias="extra-user-roles",
description="ACL string representation for the parent chroot",
examples=["cdrwa"],
title="User roles",
)

requested_secrets: list[str] = Field(
alias="requested-secrets",
description="Any provider field which should be transfered as Juju Secret",
examples=[["username", "password", "tls-ca", "uris"]],
title="Requested secrets",
)

secret_mtls: str | None = Field(
alias="secret-mtls",
description="The name of the mTLS secret to use. Leaving this empty will configure the provider to not use mTLS.",
examples=["secret://59060ecc-0495-4a80-8006-5f1fc13fd783/cjqub7fubg2s77p3niog"],
title="mTLS Secret Name",
)
Batalex marked this conversation as resolved.
Show resolved Hide resolved


class ProviderSchema(DataBagSchema):
"""The schema for the provider side of this interface."""

app: ZooKeeperProviderAppData


class RequirerSchema(DataBagSchema):
"""The schema for the requirer side of this interface."""

app: ZooKeeperRequirerAppData
Loading