Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

RabbitMQ integration #39

Merged
merged 42 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1b4f63f
WIP mongodb integration
javierdelapuente Aug 30, 2024
83a5e90
fail a bit faster
javierdelapuente Sep 2, 2024
0edbb73
Let's see if it works
javierdelapuente Sep 2, 2024
ff5ea46
comment nestasyncio
javierdelapuente Sep 2, 2024
699800d
integrate with full name
javierdelapuente Sep 2, 2024
29b6e10
put name
javierdelapuente Sep 2, 2024
e110dde
switch cli client to its original controller
javierdelapuente Sep 3, 2024
0e5b384
try lxd + not lxd
javierdelapuente Sep 3, 2024
1dc37bb
fix linting
javierdelapuente Sep 3, 2024
5469072
remove tmate. more messages
javierdelapuente Sep 3, 2024
962ad62
add ops_test fixture
javierdelapuente Sep 3, 2024
d2bcc37
do not switch controller
javierdelapuente Sep 3, 2024
a3b9c87
fix error
javierdelapuente Sep 3, 2024
4a24365
Add some logs
javierdelapuente Sep 3, 2024
474fc19
update name to destroy relation
javierdelapuente Sep 3, 2024
47f1997
Starting to clean the relation and the charm
javierdelapuente Sep 4, 2024
ef932b1
remove unnecesasry logging
javierdelapuente Sep 4, 2024
fe2a38e
improve comments
javierdelapuente Sep 4, 2024
8c4565b
Some more cleaning
javierdelapuente Sep 4, 2024
93c511e
remove unneded logs and listing of offers
javierdelapuente Sep 4, 2024
df8f391
rename relation from amqp to rabbitmq
javierdelapuente Sep 5, 2024
41f553e
remove extra fetch-libs
javierdelapuente Sep 5, 2024
df0dd91
improve variables in tests
javierdelapuente Sep 5, 2024
4a3d71c
rename goneaway with departed
javierdelapuente Sep 6, 2024
7f99365
Use amqp uri instead of our own struct
javierdelapuente Sep 6, 2024
0a70624
Revert to previous comments for missing charm libraries
javierdelapuente Sep 6, 2024
9d266ce
get rabbitmq connection from individual parts and frmo uri to check e…
javierdelapuente Sep 6, 2024
dd27db8
add comment for lint exception
javierdelapuente Sep 6, 2024
f96d19b
Merge branch 'main' into rabbitmq-integration
javierdelapuente Sep 10, 2024
0c2b00e
add trivy ignore
javierdelapuente Sep 10, 2024
33b6cf0
Merge remote-tracking branch 'origin/rabbitmq-integration' into rabbi…
javierdelapuente Sep 10, 2024
1ea32b5
Launch actions
javierdelapuente Sep 10, 2024
18d9876
test remove first trivy
javierdelapuente Sep 10, 2024
9b1c752
remove CVE-2024-24790 and comment CVE-2023-45288
javierdelapuente Sep 10, 2024
45249eb
remove CVE-2023-45288. comment CVE-2022-40897
javierdelapuente Sep 10, 2024
90c453d
lets see CVE-2024-6345
javierdelapuente Sep 10, 2024
6358f71
put the necessary ignores in trivvy
javierdelapuente Sep 10, 2024
bd1933f
do not use self hosted runners temporarily
javierdelapuente Sep 11, 2024
8d8b04e
do not use self hosted runners
javierdelapuente Sep 11, 2024
172b820
Add typing hints to get rabbitmq connections
javierdelapuente Sep 11, 2024
f266001
Code suggestions
javierdelapuente Sep 11, 2024
8fbcc59
close rabbitmq connections on teardown
javierdelapuente Sep 11, 2024
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 .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ jobs:
uses: canonical/operator-workflows/.github/workflows/test.yaml@main
secrets: inherit
with:
self-hosted-runner: true
self-hosted-runner: false
self-hosted-runner-label: "edge"
6 changes: 2 additions & 4 deletions .trivyignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# stdlib golang: net/netip: Unexpected behavior from Is methods for IPv4-mapped IPv6 addresses
CVE-2024-24790
# CVE usr/bin/pebble (gobinary)
CVE-2023-45288
# ignore CVE introduced by python3-gunicorn
CVE-2022-40897

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.

Check notice on line 2 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2022-40897 not present anymore, can be safely removed.
# pypa/setuptools: Remote code execution via download
CVE-2024-6345

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.

Check notice on line 4 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-6345 not present anymore, can be safely removed.
# pebble: Calling Decoder.Decode on a message which contains deeply nested structures can cause a panic due to stack exhaustion
CVE-2024-34156

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.3/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.5/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-django-app-73af8619bafa0333df8a895574fa338225d6dab2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-fastapi-app-c87a504dd282a887ea91436e44f2971c1f261f21-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-db-flask-6b21db403f3005f016e12a9216efff7b51800af4-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-test-flask-f3b3727b2f45b2594143f92db96bf0e0f2836799-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.

Check notice on line 6 in .trivyignore

View workflow job for this annotation

GitHub Actions / integration-tests (3.4/stable) / Scan Image (ghcr.io-canonical-go-app-4247271c185d273bc85588566c4612eb538114c2-_0.1_amd64.tar)

CVE-2024-34156 not present anymore, can be safely removed.
5 changes: 5 additions & 0 deletions examples/flask/charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ requires:
interface: saml
optional: True
limit: 1
rabbitmq:
interface: rabbitmq
optional: True
limit: 1

resources:
flask-app-image:
description: flask application image.
Expand Down
62 changes: 62 additions & 0 deletions examples/flask/test_rock/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import boto3
import botocore.config
import pika
import psycopg
import pymongo
import pymongo.database
Expand Down Expand Up @@ -73,6 +74,35 @@ def get_redis_database() -> redis.Redis | None:
return g.redis_db


def get_rabbitmq_connection() -> pika.BlockingConnection | None:
"""Get rabbitmq connection."""
if "rabbitmq" not in g:
if "RABBITMQ_HOSTNAME" in os.environ:
username = os.environ["RABBITMQ_USERNAME"]
password = os.environ["RABBITMQ_PASSWORD"]
hostname = os.environ["RABBITMQ_HOSTNAME"]
vhost = os.environ["RABBITMQ_VHOST"]
port = os.environ["RABBITMQ_PORT"]
credentials = pika.PlainCredentials(username, password)
parameters = pika.ConnectionParameters(hostname, port, vhost, credentials)
g.rabbitmq = pika.BlockingConnection(parameters)
javierdelapuente marked this conversation as resolved.
Show resolved Hide resolved
else:
return None
return g.rabbitmq


def get_rabbitmq_connection_from_uri() -> pika.BlockingConnection | None:
"""Get rabbitmq connection from uri."""
if "rabbitmq_from_uri" not in g:
if "RABBITMQ_CONNECT_STRING" in os.environ:
uri = os.environ["RABBITMQ_CONNECT_STRING"]
parameters = pika.URLParameters(uri)
g.rabbitmq_from_uri = pika.BlockingConnection(parameters)
javierdelapuente marked this conversation as resolved.
Show resolved Hide resolved
else:
return None
return g.rabbitmq_from_uri


def get_boto3_client():
if "boto3_client" not in g:
if "S3_ACCESS_KEY" in os.environ:
Expand Down Expand Up @@ -113,6 +143,12 @@ def teardown_database(_):
boto3_client = g.pop("boto3_client", None)
if boto3_client is not None:
boto3_client.close()
rabbitmq = g.pop("rabbitmq", None)
if rabbitmq is not None:
rabbitmq.close()
rabbitmq_from_uri = g.pop("rabbitmq_from_uri", None)
if rabbitmq_from_uri is not None:
rabbitmq_from_uri.close()


@app.route("/")
Expand Down Expand Up @@ -187,6 +223,32 @@ def redis_status():
return "FAIL"


@app.route("/rabbitmq/send")
def rabbitmq_send():
"""Send a message to "charm" queue."""
if connection := get_rabbitmq_connection():
channel = connection.channel()
channel.queue_declare(queue="charm")
channel.basic_publish(exchange="", routing_key="charm", body="SUCCESS")
return "SUCCESS"
return "FAIL"


@app.route("/rabbitmq/receive")
def rabbitmq_receive():
"""Receive a message from "charm" queue in blocking form."""
if connection := get_rabbitmq_connection_from_uri():
channel = connection.channel()
method_frame, _header_frame, body = channel.basic_get("charm")
if method_frame:
channel.basic_ack(method_frame.delivery_tag)
if body == b"SUCCESS":
return "SUCCESS"
return "FAIL. INCORRECT MESSAGE."
return "FAIL. NO MESSAGE."
return "FAIL. NO CONNECTION."


@app.route("/env")
def get_env():
"""Return environment variables"""
Expand Down
1 change: 1 addition & 0 deletions examples/flask/test_rock/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ psycopg[binary]
pymongo
redis[hiredis]
boto3
pika
81 changes: 60 additions & 21 deletions paas_app_charmer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,10 @@ def map_integrations_to_env(integrations: IntegrationsState, prefix: str = "") -
"""
env = {}
if integrations.redis_uri:
redis_envvars = _db_url_to_env_variables("redis", integrations.redis_uri)
redis_envvars = _db_url_to_env_variables("REDIS", integrations.redis_uri)
env.update(redis_envvars)
for interface_name, uri in integrations.databases_uris.items():
interface_envvars = _db_url_to_env_variables(interface_name, uri)
interface_envvars = _db_url_to_env_variables(interface_name.upper(), uri)
env.update(interface_envvars)

if integrations.s3_parameters:
Expand Down Expand Up @@ -259,46 +259,85 @@ def map_integrations_to_env(integrations: IntegrationsState, prefix: str = "") -
if v is not None
)

if integrations.rabbitmq_uri:
rabbitmq_envvars = _rabbitmq_uri_to_env_variables("RABBITMQ", integrations.rabbitmq_uri)
env.update(rabbitmq_envvars)

return {prefix + k: v for k, v in env.items()}


def _db_url_to_env_variables(base_name: str, url: str) -> dict[str, str]:
def _db_url_to_env_variables(prefix: str, url: str) -> dict[str, str]:
"""Convert a database url to environment variables.

Args:
base_name: name of the database.
prefix: prefix for the environment variables
url: url of the database

Return:
All environment variables, that is, the connection string,
all components as returned from urllib.parse and the
database name extracted from the path
"""
prefix = prefix + "_DB"
envvars = _url_env_vars(prefix, url)
parsed_url = urllib.parse.urlparse(url)

# database name is usually parsed this way.
db_name = parsed_url.path.removeprefix("/") if parsed_url.path else None
if db_name is not None:
envvars[f"{prefix}_NAME"] = db_name
return envvars


def _rabbitmq_uri_to_env_variables(prefix: str, url: str) -> dict[str, str]:
"""Convert a rabbitmq uri to environment variables.

Args:
prefix: prefix for the environment variables
url: url of rabbitmq

Return:
All environment variables, that is, the connection string,
all components as returned from urllib.parse and the
rabbitmq vhost extracted from the path
"""
envvars = _url_env_vars(prefix, url)
parsed_url = urllib.parse.urlparse(url)
if len(parsed_url.path) > 1:
envvars[f"{prefix}_VHOST"] = urllib.parse.unquote(parsed_url.path.split("/")[1])
return envvars


def _url_env_vars(prefix: str, url: str) -> dict[str, str]:
"""Convert a url to environment variables using parts from urllib.parse.urlparse.

Args:
prefix: prefix for the environment variables
url: url of the database

Return:
All environment variables, that is, the connection string and
all components as returned from urllib.parse
"""
if not url:
return {}

base_name = base_name.upper()
envvars: dict[str, str | None] = {}
envvars[f"{base_name}_DB_CONNECT_STRING"] = url
envvars[f"{prefix}_CONNECT_STRING"] = url

parsed_url = urllib.parse.urlparse(url)

# All components of urlparse, using the same convention for default values.
# See: https://docs.python.org/3/library/urllib.parse.html#url-parsing
envvars[f"{base_name}_DB_SCHEME"] = parsed_url.scheme
envvars[f"{base_name}_DB_NETLOC"] = parsed_url.netloc
envvars[f"{base_name}_DB_PATH"] = parsed_url.path
envvars[f"{base_name}_DB_PARAMS"] = parsed_url.params
envvars[f"{base_name}_DB_QUERY"] = parsed_url.query
envvars[f"{base_name}_DB_FRAGMENT"] = parsed_url.fragment
envvars[f"{base_name}_DB_USERNAME"] = parsed_url.username
envvars[f"{base_name}_DB_PASSWORD"] = parsed_url.password
envvars[f"{base_name}_DB_HOSTNAME"] = parsed_url.hostname
envvars[f"{base_name}_DB_PORT"] = str(parsed_url.port) if parsed_url.port is not None else None

# database name is usually parsed this way.
envvars[f"{base_name}_DB_NAME"] = (
parsed_url.path.removeprefix("/") if parsed_url.path else None
)
envvars[f"{prefix}_SCHEME"] = parsed_url.scheme
envvars[f"{prefix}_NETLOC"] = parsed_url.netloc
envvars[f"{prefix}_PATH"] = parsed_url.path
envvars[f"{prefix}_PARAMS"] = parsed_url.params
envvars[f"{prefix}_QUERY"] = parsed_url.query
envvars[f"{prefix}_FRAGMENT"] = parsed_url.fragment
envvars[f"{prefix}_USERNAME"] = parsed_url.username
envvars[f"{prefix}_PASSWORD"] = parsed_url.password
envvars[f"{prefix}_HOSTNAME"] = parsed_url.hostname
envvars[f"{prefix}_PORT"] = str(parsed_url.port) if parsed_url.port is not None else None

return {k: v for k, v in envvars.items() if v is not None}
37 changes: 36 additions & 1 deletion paas_app_charmer/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from paas_app_charmer.databases import make_database_requirers
from paas_app_charmer.exceptions import CharmConfigInvalidError
from paas_app_charmer.observability import Observability
from paas_app_charmer.rabbitmq import RabbitMQRequires
from paas_app_charmer.secret_storage import KeySecretStorage
from paas_app_charmer.utils import build_validation_error_message

Expand Down Expand Up @@ -101,6 +102,20 @@ def __init__(self, framework: ops.Framework, framework_name: str) -> None:
else:
self._saml = None

self._rabbitmq: RabbitMQRequires | None
if "rabbitmq" in requires and requires["rabbitmq"].interface_name == "rabbitmq":
self._rabbitmq = RabbitMQRequires(
self,
"rabbitmq",
username=self.app.name,
vhost="/",
)
self.framework.observe(self._rabbitmq.on.connected, self._on_rabbitmq_connected)
self.framework.observe(self._rabbitmq.on.ready, self._on_rabbitmq_ready)
self.framework.observe(self._rabbitmq.on.departed, self._on_rabbitmq_departed)
else:
self._rabbitmq = None

self._database_migration = DatabaseMigration(
container=self.unit.get_container(self._workload_config.container_name),
state_dir=self._workload_config.state_dir,
Expand Down Expand Up @@ -245,7 +260,8 @@ def is_ready(self) -> bool:

return True

def _missing_required_integrations(self, charm_state: CharmState) -> list[str]:
# Pending to refactor all integrations
def _missing_required_integrations(self, charm_state: CharmState) -> list[str]: # noqa: C901
"""Get list of missing integrations that are required.

Args:
Expand All @@ -272,6 +288,9 @@ def _missing_required_integrations(self, charm_state: CharmState) -> list[str]:
if self._saml and not charm_state.integrations.saml_parameters:
if not requires["saml"].optional:
missing_integrations.append("saml")
if self._rabbitmq and not charm_state.integrations.rabbitmq_uri:
if not requires["rabbitmq"].optional:
missing_integrations.append("rabbitmq")
return missing_integrations

def restart(self) -> None:
Expand Down Expand Up @@ -319,6 +338,7 @@ def _create_charm_state(self) -> CharmState:
redis_uri=self._redis.url if self._redis is not None else None,
s3_connection_info=self._s3.get_s3_connection_info() if self._s3 else None,
saml_relation_data=saml_relation_data,
rabbitmq_uri=self._rabbitmq.rabbitmq_uri() if self._rabbitmq else None,
base_url=self._base_url,
)

Expand Down Expand Up @@ -418,3 +438,18 @@ def _on_ingress_ready(self, _: ops.HookEvent) -> None:
def _on_pebble_ready(self, _: ops.PebbleReadyEvent) -> None:
"""Handle the pebble-ready event."""
self.restart()

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

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

@block_if_invalid_config
def _on_rabbitmq_departed(self, _event: ops.HookEvent) -> None:
"""Handle rabbitmq departed event."""
self.restart()
11 changes: 10 additions & 1 deletion paas_app_charmer/charm_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def from_charm( # pylint: disable=too-many-arguments
redis_uri: str | None = None,
s3_connection_info: dict[str, str] | None = None,
saml_relation_data: typing.MutableMapping[str, str] | None = None,
rabbitmq_uri: str | None = None,
base_url: str | None = None,
) -> "CharmState":
"""Initialize a new instance of the CharmState class from the associated charm.
Expand All @@ -101,6 +102,7 @@ def from_charm( # pylint: disable=too-many-arguments
redis_uri: The redis uri provided by the redis charm.
s3_connection_info: Connection info from S3 lib.
saml_relation_data: Relation data from the SAML app.
rabbitmq_uri: RabbitMQ uri.
base_url: Base URL for the service.

Return:
Expand All @@ -120,6 +122,7 @@ def from_charm( # pylint: disable=too-many-arguments
database_requirers=database_requirers,
s3_connection_info=s3_connection_info,
saml_relation_data=saml_relation_data,
rabbitmq_uri=rabbitmq_uri,
)
return cls(
framework=framework,
Expand Down Expand Up @@ -205,20 +208,24 @@ class IntegrationsState:
databases_uris: Map from interface_name to the database uri.
s3_parameters: S3 parameters.
saml_parameters: SAML parameters.
rabbitmq_uri: RabbitMQ uri.
"""

redis_uri: str | None = None
databases_uris: dict[str, str] = field(default_factory=dict)
s3_parameters: "S3Parameters | None" = None
saml_parameters: "SamlParameters | None" = None
rabbitmq_uri: str | None = None

# This dataclass combines all the integrations, so it is reasonable that they stay together.
@classmethod
def build(
def build( # pylint: disable=too-many-arguments
javierdelapuente marked this conversation as resolved.
Show resolved Hide resolved
cls,
redis_uri: str | None,
database_requirers: dict[str, DatabaseRequires],
s3_connection_info: dict[str, str] | None,
saml_relation_data: typing.MutableMapping[str, str] | None = None,
rabbitmq_uri: str | None = None,
) -> "IntegrationsState":
"""Initialize a new instance of the IntegrationsState class.

Expand All @@ -229,6 +236,7 @@ def build(
database_requirers: All database requirers object declared by the charm.
s3_connection_info: S3 connection info from S3 lib.
saml_relation_data: Saml relation data from saml lib.
rabbitmq_uri: RabbitMQ uri.

Return:
The IntegrationsState instance created.
Expand Down Expand Up @@ -276,6 +284,7 @@ def build(
},
s3_parameters=s3_parameters,
saml_parameters=saml_parameters,
rabbitmq_uri=rabbitmq_uri,
)


Expand Down
Loading
Loading