Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 0 additions & 20 deletions .github/workflows/promote.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ on:
jobs:
pull-request:
name: PR
uses: canonical/observability/.github/workflows/charm-pull-request.yaml@v0
uses: canonical/observability/.github/workflows/charm-pull-request.yaml@v1
secrets: inherit
5 changes: 3 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
name: Release Charm to Edge and Publish Libraries
name: Release Charm

on:
push:
branches:
- main
- track/**

jobs:
release:
uses: canonical/observability/.github/workflows/charm-release.yaml@v0
uses: canonical/observability/.github/workflows/charm-release.yaml@v1
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/tiobe-scan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ on:
jobs:
tics:
name: TiCs
uses: canonical/observability/.github/workflows/charm-tiobe-scan.yaml@main
uses: canonical/observability/.github/workflows/charm-tiobe-scan.yaml@v1
secrets: inherit
59 changes: 47 additions & 12 deletions charmcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
# Copyright 2021 Canonical Ltd.
# See LICENSE file for licensing details.

name: observability-libs
type: charm
bases:
- build-on:
- name: "ubuntu"
channel: "20.04"
run-on:
- name: "ubuntu"
channel: "20.04"
summary: Collection of Charm Libraries for the Observability charms.
description: |
A placeholder charm that contains helpful charm libraries curated by the
Canonical Observability charm team.

links:
website: https://charmhub.io/observability-libs
source: https://github.com/canonical/observability-libs
issues: https://github.com/canonical/observability-libs/issues

assumes:
- k8s-api

platforms:
[email protected]:amd64:

parts:
charm:
charm-binary-python-packages:
- httpx # https://github.com/pypa/setuptools_scm/issues/918
build-packages:
- git
source: .
plugin: uv
build-packages: [git]
build-snaps: [astral-uv]
override-build: |
craftctl default
git describe --always > $CRAFT_PART_INSTALL/version

containers:
placeholder:
resource: placeholder-image

resources:
placeholder-image:
type: oci-image
description: OCI image for placeholder
upstream-source: busybox

config:
options:
cpu:
description: |
K8s cpu resource limit, e.g. "1" or "500m". Default is unset (no limit).
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string
memory:
description: |
K8s memory resource limit, e.g. "1Gi". Default is unset (no limit).
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string
13 changes: 0 additions & 13 deletions config.yaml

This file was deleted.

22 changes: 0 additions & 22 deletions metadata.yaml

This file was deleted.

39 changes: 38 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
# Copyright 2025 Canonical Ltd.
# See LICENSE file for licensing details.
[project]
name = "observability-libs"
version = "0.0"
requires-python = "~=3.8"

dependencies = [
"ops",
"PyYAML",
"lightkube>=v0.15.4",
"tenacity",
]

[project.optional-dependencies]
dev = [
# Linting
"ruff",
"codespell",
# Static
"pyright",
# Unit
"pytest",
"coverage[toml]",
"ops[testing]",
"cryptography",
"jsonschema",
"tenacity",
# Integration
"juju<=3.3.0,>=3.0",
"websockets<14",
"lightkube",
"lightkube-models",
"pytest-operator",
]

# Testing tools configuration
[tool.coverage.run]
branch = true
Expand Down Expand Up @@ -28,9 +64,10 @@ convention = "google"

# Static analysis tools configuration
[tool.pyright]
extraPaths = ["lib"]
extraPaths = ["src", "lib"]
pythonVersion = "3.8"
pythonPlatform = "All"
exclude = ["tests/integration/tester-charm/*"]

[tool.pytest.ini_options]
minversion = "6.0"
Expand Down
7 changes: 0 additions & 7 deletions requirements.txt

This file was deleted.

6 changes: 5 additions & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import functools
import logging
import os
import shutil
from collections import defaultdict
from datetime import datetime
Expand Down Expand Up @@ -59,6 +60,9 @@ async def wrapper(*args, **kwargs):
@timed_memoizer
async def o11y_libs_charm(ops_test):
"""The charm used for integration testing."""
if charm_file := os.environ.get("CHARM_PATH"):
return Path(charm_file)

charm = await ops_test.build_charm(".")
return charm

Expand All @@ -73,7 +77,7 @@ async def tester_charm(ops_test: OpsTest) -> Path:
# Link to lib
dest_charmlib = Path(f"{TESTINGCHARM_PATH}/{CERTHANDLER_PATH}")
dest_charmlib.parent.mkdir(parents=True)
dest_charmlib.hardlink_to(CERTHANDLER_PATH)
dest_charmlib.hardlink_to(CERTHANDLER_PATH) # type: ignore

# fetch tls_certificates lib
fetch_tls_cmd = [
Expand Down
1 change: 1 addition & 0 deletions tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


def get_secret(ops_test: OpsTest, app_name: str, path: str) -> str:
assert ops_test.model_full_name
return subprocess.check_output(
[
"juju",
Expand Down
13 changes: 10 additions & 3 deletions tests/integration/test_cert_handler_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ async def test_cert_handler_v1(
tester_charm: Path,
):
"""Validate the integration between TesterCharm and self-signed-certificates using CertHandler v1."""
assert ops_test.model
assert ops_test.model_full_name
ca_app_name = "ca"
apps = [APP_NAME, ca_app_name]

Expand All @@ -37,7 +39,7 @@ async def test_cert_handler_v1(
ops_test.model.deploy(
"self-signed-certificates",
application_name=ca_app_name,
channel="beta",
channel="latest/beta",
trust=True,
),
ops_test.model.deploy(
Expand Down Expand Up @@ -74,13 +76,16 @@ async def test_cert_handler_v1(

@pytest.mark.abort_on_fail
async def test_secrets_does_not_change_after_refresh(ops_test: OpsTest, tester_charm: Path):
assert ops_test.model
paths = [KEY_PATH, CERT_PATH, CA_CERT_PATH]
secrets = {paths[0]: "", paths[1]: "", paths[2]: ""}

for path in paths:
secrets[path] = get_secret(ops_test, APP_NAME, path)

await ops_test.model.applications[APP_NAME].refresh(path=tester_charm)
application = ops_test.model.applications[APP_NAME]
assert application
await application.refresh(path=tester_charm)
await ops_test.model.wait_for_idle(
status="active", raise_on_error=False, timeout=600, idle_period=30
)
Expand All @@ -91,12 +96,14 @@ async def test_secrets_does_not_change_after_refresh(ops_test: OpsTest, tester_c

@pytest.mark.abort_on_fail
async def test_change_ssc_and_tester_still_have_certs(ops_test: OpsTest):
assert ops_test.model
assert ops_test.model_full_name
await ops_test.model.remove_application("ca", block_until_done=True)
await asyncio.gather(
ops_test.model.deploy(
"self-signed-certificates",
application_name="ca2",
channel="beta",
channel="latest/beta",
trust=True,
),
)
Expand Down
17 changes: 14 additions & 3 deletions tests/integration/test_compute_resources_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

logger = logging.getLogger(__name__)

METADATA = yaml.safe_load(Path("./metadata.yaml").read_text())
METADATA = yaml.safe_load(Path("./charmcraft.yaml").read_text())
app_name = METADATA["name"]
container_name = "placeholder"
resources = {"placeholder-image": METADATA["resources"]["placeholder-image"]["upstream-source"]}
Expand All @@ -28,19 +28,22 @@


def get_podspec(ops_test: OpsTest, app_name: str, container_name: str):
assert ops_test.model_name
client = Client()
pod = client.get(Pod, name=f"{app_name}-0", namespace=ops_test.model_name)
podspec = next(iter(filter(lambda ctr: ctr.name == container_name, pod.spec.containers))) # type: ignore
return podspec


async def test_setup_env(ops_test: OpsTest):
assert ops_test.model
await ops_test.model.set_config({"logging-config": "<root>=WARNING; unit=DEBUG"})


@pytest.mark.abort_on_fail
async def test_build_and_deploy(ops_test: OpsTest, o11y_libs_charm):
"""Build the charm-under-test and deploy it."""
assert ops_test.model
await ops_test.model.deploy(
o11y_libs_charm,
resources=resources,
Expand All @@ -56,15 +59,19 @@ async def test_build_and_deploy(ops_test: OpsTest, o11y_libs_charm):
async def test_default_resource_limits_applied(ops_test: OpsTest):
podspec = get_podspec(ops_test, app_name, container_name)
# TODO use `equals_canonically` when becomes available
assert podspec.resources
assert podspec.resources.limits is None
assert podspec.resources.requests is None


@pytest.mark.abort_on_fail
@pytest.mark.parametrize("cpu,memory", [("500m", "0.15Gi"), ("0.30000000000000004", "0.15G")])
async def test_resource_limits_match_config(ops_test: OpsTest, cpu, memory):
assert ops_test.model
custom_limits = {"cpu": cpu, "memory": memory}
await ops_test.model.applications[app_name].set_config(custom_limits)
application = ops_test.model.applications[app_name]
assert application
await application.set_config(custom_limits)
await ops_test.model.wait_for_idle(
status="active", timeout=resched_timeout, raise_on_error=False
)
Expand All @@ -76,9 +83,13 @@ async def test_resource_limits_match_config(ops_test: OpsTest, cpu, memory):

@pytest.mark.abort_on_fail
async def test_default_resource_limits_applied_after_resetting_config(ops_test: OpsTest):
await ops_test.model.applications[app_name].reset_config(["cpu", "memory"])
assert ops_test.model
application = ops_test.model.applications[app_name]
assert application
await application.reset_config(["cpu", "memory"])
await ops_test.model.wait_for_idle(status="active", timeout=resched_timeout)

podspec = get_podspec(ops_test, app_name, container_name)
assert podspec.resources
assert podspec.resources.limits is None
assert podspec.resources.requests is None
Loading
Loading