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

Set resource limits and requests for Tempo #24

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
15 changes: 13 additions & 2 deletions charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,19 @@ config:
Note that for a tempo deployment as a whole to be consistent, each role
(except the optional 'metrics-generator') needs to be assigned to at least one worker node. If this condition
is not met, the coordinator charm will set blocked status and the deployment will shut down.


cpu_limit:
description: |
K8s cpu resource limit, e.g. "1" or "500m". Default is unset (no limit). This value is used
for the "limits" portion of the resource requirements.
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string
memory_limit:
description: |
K8s memory resource limit, e.g. "1Gi". Default is unset (no limit). This value is used
for the "limits" portion of the resource requirements.
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string

# build info

bases:
Expand Down
9 changes: 6 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
ops>=2.15
cosl>=0.0.23
ops >= 2.15
cosl>=0.0.24

# Charm relation interfaces
pydantic>=2

# lib/charms/tempo_k8s/v1/charm_tracing.py
opentelemetry-exporter-otlp-proto-http==1.21.0
opentelemetry-exporter-otlp-proto-http==1.21.0

lightkube>=0.15.4
lightkube-models==1.24.1.4
8 changes: 7 additions & 1 deletion src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Integrate it with a `tempo-k8s` coordinator unit to start.
"""
import logging
from typing import Optional
from typing import Optional, Dict

from cosl.coordinated_workers.worker import CONFIG_FILE, Worker
from ops import CollectStatusEvent
Expand Down Expand Up @@ -59,6 +59,8 @@ def __init__(self, *args):
pebble_layer=self.generate_worker_layer,
endpoints={"cluster": "tempo-cluster"}, # type: ignore
readiness_check_endpoint=self.readiness_check_endpoint,
resources_requests=self.get_resources_requests,
container_name="tempo",
)
self.framework.observe(self.on.collect_unit_status, self._on_collect_status)

Expand Down Expand Up @@ -120,6 +122,10 @@ def _on_collect_status(self, e: CollectStatusEvent):
)
)

def get_resources_requests(self, _) -> Dict[str, str]:
"""Returns a dictionary for the "requests" portion of the resources requirements."""
return {"cpu": "50m", "memory": "200Mi"}


if __name__ == "__main__": # pragma: nocover
main(TempoWorkerK8SOperatorCharm)
17 changes: 15 additions & 2 deletions tests/scenario/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import pytest
from scenario import Context, ExecOutput
from ops import ActiveStatus
from unittest.mock import patch

from charm import TempoWorkerK8SOperatorCharm

Expand All @@ -18,8 +20,19 @@ def _urlopen_patch(url: str, resp, tls: bool = False):


@pytest.fixture
def ctx():
return Context(TempoWorkerK8SOperatorCharm)
def worker_charm():
with patch.multiple(
"cosl.coordinated_workers.worker.KubernetesComputeResourcesPatch",
_namespace="test-namespace",
_patch=lambda _: None,
get_status=lambda _: ActiveStatus(""),
):
yield TempoWorkerK8SOperatorCharm


@pytest.fixture
def ctx(worker_charm):
return Context(charm_type=worker_charm)


TEMPO_VERSION_EXEC_OUTPUT = ExecOutput(stdout="1.31")
87 changes: 84 additions & 3 deletions tests/scenario/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
from ops import BlockedStatus
from scenario import Context, State, Container, Relation, Mount

from charm import TempoWorkerK8SOperatorCharm
from tests.scenario.conftest import _urlopen_patch
import json
from unittest.mock import MagicMock

from cosl.coordinated_workers.interface import ClusterRequirer
from scenario import ExecOutput

from tests.scenario.conftest import TEMPO_VERSION_EXEC_OUTPUT
from tests.scenario.helpers import set_role


@pytest.fixture
def ctx():
return Context(TempoWorkerK8SOperatorCharm)
def ctx(worker_charm):
return Context(worker_charm)


@contextmanager
Expand Down Expand Up @@ -133,3 +140,77 @@ def test_status_check_ready(ctx, tmp_path):
state_out = ctx.run("update_status", state)
# THEN the charm sets waiting: Starting...
assert state_out.unit_status == ActiveStatus("(all roles) ready.")


@endpoint_ready
@patch.object(ClusterRequirer, "get_worker_config", MagicMock(return_value={"config": "config"}))
@patch(
"cosl.coordinated_workers.worker.KubernetesComputeResourcesPatch.get_status",
MagicMock(return_value=BlockedStatus("`juju trust` this application")),
)
def test_patch_k8s_failed(ctx):

tempo_container = Container(
"tempo",
can_connect=True,
exec_mock={
("/bin/tempo", "-version"): TEMPO_VERSION_EXEC_OUTPUT,
("update-ca-certificates", "--fresh"): ExecOutput(),
},
)
state_out = ctx.run(
"config_changed",
state=set_role(
State(
containers=[tempo_container],
relations=[
Relation(
"tempo-cluster",
remote_app_data={
"tempo_config": json.dumps({"alive": "beef"}),
},
)
],
),
"all",
),
)

assert state_out.unit_status == BlockedStatus("`juju trust` this application")


@endpoint_ready
@patch.object(ClusterRequirer, "get_worker_config", MagicMock(return_value={"config": "config"}))
@patch(
"cosl.coordinated_workers.worker.KubernetesComputeResourcesPatch.get_status",
MagicMock(return_value=WaitingStatus("")),
)
def test_patch_k8s_waiting(ctx):

tempo_container = Container(
"tempo",
can_connect=True,
exec_mock={
("/bin/tempo", "-version"): TEMPO_VERSION_EXEC_OUTPUT,
("update-ca-certificates", "--fresh"): ExecOutput(),
},
)
state_out = ctx.run(
"config_changed",
state=set_role(
State(
containers=[tempo_container],
relations=[
Relation(
"tempo-cluster",
remote_app_data={
"tempo_config": json.dumps({"alive": "beef"}),
},
)
],
),
"all",
),
)

assert state_out.unit_status == WaitingStatus("")
7 changes: 7 additions & 0 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@

ops.testing.SIMULATE_CAN_CONNECT = True

k8s_resource_multipatch = patch.multiple(
"cosl.coordinated_workers.worker.KubernetesComputeResourcesPatch",
_namespace="test-namespace",
_patch=lambda _: None,
)


@patch("cosl.coordinated_workers.worker.Worker.running_version", lambda *_: "1.2.3")
@patch("cosl.coordinated_workers.worker.Worker.restart", lambda *_: True)
@k8s_resource_multipatch
class TestCharm(unittest.TestCase):
def setUp(self, *unused):
self.harness = Harness(TempoWorkerK8SOperatorCharm)
Expand Down
Loading