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

Add logging relation katib-controller #195

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
2,750 changes: 2,750 additions & 0 deletions charms/katib-controller/lib/charms/loki_k8s/v1/loki_push_api.py

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions charms/katib-controller/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ requires:
k8s-service-info:
interface: k8s-service
limit: 1
logging:
DnPlas marked this conversation as resolved.
Show resolved Hide resolved
interface: loki_push_api
optional: true
2 changes: 2 additions & 0 deletions charms/katib-controller/requirements-integration.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ lightkube
pytest
pytest-operator
pyyaml
# This is required due to the abstraction of cos integration
charmed-kubeflow-chisme>=0.4.0
155 changes: 96 additions & 59 deletions charms/katib-controller/requirements-integration.txt
DnPlas marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -10,116 +10,139 @@ appnope==0.1.4
# via ipython
asttokens==2.4.0
# via stack-data
attrs==23.2.0
# via jsonschema
backcall==0.2.0
# via ipython
bcrypt==4.0.1
bcrypt==4.1.3
# via paramiko
cachetools==5.3.1
cachetools==5.3.3
# via google-auth
certifi==2023.7.22
certifi==2024.6.2
# via
# httpcore
# httpx
# kubernetes
# requests
cffi==1.15.1
cffi==1.16.0
# via
# cryptography
# pynacl
charset-normalizer==3.2.0
charmed-kubeflow-chisme==0.4.0
# via -r requirements-integration.in
charset-normalizer==3.3.2
# via requests
cryptography==41.0.3
cryptography==42.0.8
# via paramiko
decorator==5.1.1
# via
# ipdb
# ipython
exceptiongroup==1.1.3
deepdiff==6.2.1
# via charmed-kubeflow-chisme
exceptiongroup==1.2.1
# via
# anyio
# pytest
executing==1.2.0
executing==2.0.1
# via stack-data
google-auth==2.22.0
google-auth==2.30.0
# via kubernetes
h11==0.14.0
# via httpcore
httpcore==0.17.3
httpcore==1.0.5
# via httpx
httpx==0.24.1
httpx==0.27.0
# via lightkube
hvac==1.2.0
hvac==2.2.0
# via juju
idna==3.4
idna==3.7
# via
# anyio
# httpx
# requests
importlib-resources==6.4.0
# via jsonschema
iniconfig==2.0.0
# via pytest
ipdb==0.13.13
# via pytest-operator
ipython==8.12.2
ipython==8.12.3
# via ipdb
jedi==0.19.0
jedi==0.19.1
# via ipython
jinja2==3.1.2
# via pytest-operator
juju==3.2.2
jinja2==3.1.4
# via
# charmed-kubeflow-chisme
# pytest-operator
jsonschema==4.17.3
# via serialized-data-interface
juju==3.5.0.0
# via
# -r requirements-integration.in
# charmed-kubeflow-chisme
# pytest-operator
kubernetes==27.2.0
kubernetes==30.1.0
# via juju
lightkube==0.14.0
# via -r requirements-integration.in
lightkube-models==1.28.1.4
lightkube==0.15.3
# via
# -r requirements-integration.in
# charmed-kubeflow-chisme
lightkube-models==1.30.0.8
# via lightkube
macaroonbakery==1.3.1
macaroonbakery==1.3.4
# via juju
markupsafe==2.1.3
markupsafe==2.1.5
# via jinja2
matplotlib-inline==0.1.6
matplotlib-inline==0.1.7
# via ipython
mypy-extensions==1.0.0
# via typing-inspect
oauthlib==3.2.2
# via
# kubernetes
# requests-oauthlib
packaging==23.1
# via pytest
paramiko==2.12.0
ops==2.14.0
# via
# charmed-kubeflow-chisme
# serialized-data-interface
ordered-set==4.1.0
# via deepdiff
packaging==24.1
# via
# juju
# pytest
paramiko==3.4.0
# via juju
parso==0.8.3
parso==0.8.4
# via jedi
pexpect==4.8.0
pexpect==4.9.0
# via ipython
pickleshare==0.7.5
# via ipython
pluggy==1.3.0
pkgutil-resolve-name==1.3.10
# via jsonschema
pluggy==1.5.0
# via pytest
prompt-toolkit==3.0.39
prompt-toolkit==3.0.47
# via ipython
protobuf==3.20.3
protobuf==5.27.1
# via macaroonbakery
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
pyasn1==0.5.0
pyasn1==0.6.0
# via
# juju
# pyasn1-modules
# rsa
pyasn1-modules==0.3.0
pyasn1-modules==0.4.0
# via google-auth
pycparser==2.21
pycparser==2.22
# via cffi
pygments==2.16.1
pygments==2.18.0
# via ipython
pyhcl==0.4.5
# via hvac
pymacaroons==0.13.0
# via macaroonbakery
pynacl==1.5.0
Expand All @@ -131,76 +154,90 @@ pyrfc3339==1.1
# via
# juju
# macaroonbakery
pytest==7.4.2
pyrsistent==0.20.0
# via jsonschema
pytest==8.2.2
# via
# -r requirements-integration.in
# pytest-asyncio
# pytest-operator
pytest-asyncio==0.21.1
pytest-asyncio==0.21.2
# via pytest-operator
pytest-operator==0.29.0
pytest-operator==0.35.0
# via -r requirements-integration.in
python-dateutil==2.8.2
python-dateutil==2.9.0.post0
# via kubernetes
pytz==2023.3.post1
pytz==2024.1
# via pyrfc3339
pyyaml==6.0.1
# via
# -r requirements-integration.in
# juju
# kubernetes
# lightkube
# ops
# pytest-operator
requests==2.31.0
# serialized-data-interface
requests==2.32.3
# via
# hvac
# kubernetes
# macaroonbakery
# requests-oauthlib
requests-oauthlib==1.3.1
# serialized-data-interface
requests-oauthlib==2.0.0
# via kubernetes
rsa==4.9
# via google-auth
ruamel-yaml==0.18.6
# via charmed-kubeflow-chisme
ruamel-yaml-clib==0.2.8
# via ruamel-yaml
serialized-data-interface==0.7.0
# via charmed-kubeflow-chisme
six==1.16.0
# via
# asttokens
# google-auth
# kubernetes
# macaroonbakery
# paramiko
# pymacaroons
# python-dateutil
sniffio==1.3.0
sniffio==1.3.1
# via
# anyio
# httpcore
# httpx
stack-data==0.6.2
stack-data==0.6.3
# via ipython
tenacity==8.4.1
# via charmed-kubeflow-chisme
tomli==2.0.1
# via
# ipdb
# pytest
toposort==1.10
# via juju
traitlets==5.9.0
traitlets==5.14.3
# via
# ipython
# matplotlib-inline
typing-extensions==4.7.1
typing-extensions==4.12.2
# via
# anyio
# ipython
# typing-inspect
typing-inspect==0.9.0
# via juju
urllib3==1.26.16
urllib3==2.2.1
# via
# google-auth
# kubernetes
# requests
wcwidth==0.2.6
wcwidth==0.2.13
# via prompt-toolkit
websocket-client==1.6.2
# via kubernetes
websockets==8.1
websocket-client==1.8.0
# via
# kubernetes
# ops
websockets==12.0
# via juju
zipp==3.19.2
# via importlib-resources
2 changes: 1 addition & 1 deletion charms/katib-controller/requirements-unit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ charmed-kubeflow-chisme==0.2.1
# via -r requirements.in
charset-normalizer==3.3.2
# via requests
cosl==0.0.11
cosl==0.0.12
# via -r requirements.in
coverage==7.4.2
# via -r requirements-unit.in
Expand Down
2 changes: 1 addition & 1 deletion charms/katib-controller/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ charmed-kubeflow-chisme==0.2.1
# via -r requirements.in
charset-normalizer==3.3.2
# via requests
cosl==0.0.11
cosl==0.0.12
# via -r requirements.in
deepdiff==6.2.1
# via charmed-kubeflow-chisme
Expand Down
2 changes: 2 additions & 0 deletions charms/katib-controller/src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from charmed_kubeflow_chisme.components.leadership_gate_component import LeadershipGateComponent
from charmed_kubeflow_chisme.kubernetes import create_charm_default_labels
from charms.grafana_k8s.v0.grafana_dashboard import GrafanaDashboardProvider
from charms.loki_k8s.v1.loki_push_api import LogForwarder
from charms.observability_libs.v1.kubernetes_service_patch import KubernetesServicePatch
from charms.prometheus_k8s.v0.prometheus_scrape import MetricsEndpointProvider
from lightkube.models.core_v1 import ServicePort
Expand Down Expand Up @@ -203,6 +204,7 @@ def __init__(self, *args):
)

self.charm_reconciler.install_default_event_handlers()
self._logging = LogForwarder(charm=self)

def get_images(
self, default_images: Dict[str, str], custom_images: Dict[str, str]
Expand Down
38 changes: 38 additions & 0 deletions charms/katib-controller/tests/integration/test_charm.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import logging
from pathlib import Path

import lightkube
import pytest
import yaml
from charmed_kubeflow_chisme.testing import (
GRAFANA_AGENT_APP,
assert_alert_rules,
assert_logging,
assert_metrics_endpoint,
deploy_and_assert_grafana_agent,
get_alert_rules,
)
from lightkube.resources.core_v1 import ConfigMap
from pytest_operator.plugin import OpsTest

logger = logging.getLogger(__name__)

METADATA = yaml.safe_load(Path("./metadata.yaml").read_text())
CHARM_NAME = METADATA["name"]
KATIB_CONFIG = "katib-config"
Expand Down Expand Up @@ -60,6 +71,11 @@ async def test_build_and_deploy(self, ops_test: OpsTest):

await ops_test.model.wait_for_idle(apps=[CHARM_NAME], status="active", timeout=300)

# Deploying grafana-agent-k8s and add all relations
await deploy_and_assert_grafana_agent(
ops_test.model, CHARM_NAME, metrics=True, dashboard=True, logging=True
)

async def test_configmap_created(self, lightkube_client: lightkube.Client, ops_test: OpsTest):
"""Test configmaps contents with default coonfig."""
katib_config_cm = lightkube_client.get(
Expand Down Expand Up @@ -99,3 +115,25 @@ async def test_blocked_on_invalid_config(self, ops_test: OpsTest):
apps=[CHARM_NAME], status="blocked", raise_on_blocked=False, timeout=300
)
assert ops_test.model.applications[CHARM_NAME].units[0].workload_status == "blocked"

async def test_alert_rules(self, ops_test: OpsTest):
"""Test check charm alert rules and rules defined in relation data bag."""
app = ops_test.model.applications[CHARM_NAME]
alert_rules = get_alert_rules()
logger.info("found alert_rules: %s", alert_rules)
await assert_alert_rules(app, alert_rules)

async def test_metrics_enpoint(self, ops_test: OpsTest):
"""Test metrics_endpoints are defined in relation data bag and their accessibility.

This function gets all the metrics_endpoints from the relation data bag, checks if
they are available from the grafana-agent-k8s charm and finally compares them with the
ones provided to the function.
"""
app = ops_test.model.applications[CHARM_NAME]
await assert_metrics_endpoint(app, metrics_port=8080, metrics_path="/metrics")

async def test_logging(self, ops_test: OpsTest):
"""Test logging is defined in relation data bag."""
app = ops_test.model.applications[GRAFANA_AGENT_APP]
await assert_logging(app)
Loading
Loading