-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Manifest toSection with Strimzi KafkaTopic (#545)
Closes #537
- Loading branch information
Showing
17 changed files
with
567 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
kafka_brokers: "http://k8kafka-cp-kafka-headless.kpops.svc.cluster.local:9092" | ||
pipeline_base_dir: tests/pipeline | ||
strimzi_topic: | ||
label: | ||
strimzi.io/cluster: my-cluster |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Any | ||
|
||
from pydantic import ConfigDict, Field, model_validator | ||
|
||
from kpops.api.exception import ValidationError | ||
from kpops.components.common.topic import KafkaTopic | ||
from kpops.config import get_config | ||
from kpops.manifests.kubernetes import KubernetesManifest, ObjectMeta | ||
from kpops.utils.docstring import describe_attr | ||
from kpops.utils.pydantic import CamelCaseConfigModel | ||
|
||
if TYPE_CHECKING: | ||
try: | ||
from typing import Self # pyright: ignore[reportAttributeAccessIssue] | ||
except ImportError: | ||
from typing_extensions import Self | ||
|
||
|
||
class TopicSpec(CamelCaseConfigModel): | ||
"""Specification of a Kafka topic. | ||
:param partitions: The number of partitions the topic should have. This cannot be decreased after topic creation. It can be increased after topic creation, but it is important to understand the consequences that has, especially for topics with semantic partitioning. When absent this will default to the broker configuration for `num.partitions`. | ||
:param replicas: The number of replicas the topic should have. When absent this will default to the broker configuration for `default.replication.factor`. | ||
:param config: The topic configuration. Topic config reference: https://docs.confluent.io/platform/current/installation/configuration/topic-configs.html | ||
""" | ||
|
||
partitions: int = Field( | ||
default=1, ge=1, description=describe_attr("partitions", __doc__) | ||
) | ||
replicas: int = Field( | ||
default=1, ge=1, le=32767, description=describe_attr("replicas", __doc__) | ||
) | ||
config: dict[str, Any] | None = Field( | ||
default=None, description=describe_attr("config", __doc__) | ||
) | ||
|
||
model_config = ConfigDict(extra="allow") | ||
|
||
@model_validator(mode="before") | ||
@classmethod | ||
def set_defaults_if_none(cls, values: Any) -> Any: | ||
if values.get("partitions") is None: | ||
values["partitions"] = 1 | ||
if values.get("replicas") is None: | ||
values["replicas"] = 1 | ||
return values | ||
|
||
|
||
class StrimziKafkaTopic(KubernetesManifest): | ||
"""Represents a Strimzi Kafka Topic CRD. | ||
CRD definition: https://github.com/strimzi/strimzi-kafka-operator/blob/main/install/cluster-operator/043-Crd-kafkatopic.yaml | ||
example: https://github.com/strimzi/strimzi-kafka-operator/blob/main/examples/topic/kafka-topic.yaml | ||
""" | ||
|
||
api_version: str = "kafka.strimzi.io/v1beta2" | ||
kind: str = "KafkaTopic" | ||
metadata: ObjectMeta | ||
spec: TopicSpec | ||
status: dict[str, Any] | None = None | ||
|
||
@classmethod | ||
def from_topic(cls, topic: KafkaTopic) -> Self: | ||
strimzi_topic = get_config().strimzi_topic | ||
if not strimzi_topic: | ||
msg = "When manifesting KafkaTopic you must define 'strimzi_topic.resource_label' in the config.yaml" | ||
raise ValidationError(msg) | ||
cluster_domain, cluster_name = strimzi_topic.cluster_labels | ||
|
||
metadata = ObjectMeta.model_validate( | ||
{ | ||
"name": topic.name, | ||
"labels": {cluster_domain: cluster_name}, | ||
} | ||
) | ||
spec = TopicSpec.model_validate( | ||
{ | ||
"partitions": topic.config.partitions_count, | ||
"replicas": topic.config.replication_factor, | ||
"config": topic.config.configs, | ||
} | ||
) | ||
return cls( | ||
metadata=metadata, | ||
spec=spec, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
from unittest.mock import MagicMock | ||
|
||
import pytest | ||
from pydantic import ValidationError as PydanticValidationError | ||
from pytest_mock import MockerFixture | ||
|
||
from kpops.api.exception import ValidationError | ||
from kpops.components.common.topic import KafkaTopic, TopicConfig | ||
from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic, TopicSpec | ||
|
||
|
||
@pytest.fixture | ||
def kafka_topic() -> KafkaTopic: | ||
return KafkaTopic( | ||
name="test-topic", | ||
config=TopicConfig.model_validate( | ||
{ | ||
"partitions_count": 3, | ||
"replication_factor": 2, | ||
"configs": {"cleanup.policy": "compact"}, | ||
}, | ||
), | ||
) | ||
|
||
|
||
def test_topic_spec_defaults(): | ||
spec = TopicSpec() | ||
assert spec.partitions == 1 | ||
assert spec.replicas == 1 | ||
assert spec.config is None | ||
|
||
|
||
def test_topic_spec_custom_values(): | ||
spec = TopicSpec(partitions=3, replicas=2, config={"retention.ms": "60000"}) | ||
assert spec.partitions == 3 | ||
assert spec.replicas == 2 | ||
assert spec.config == {"retention.ms": "60000"} | ||
|
||
|
||
def test_topic_spec_validation(): | ||
with pytest.raises(PydanticValidationError): | ||
TopicSpec(partitions=0) # Less than 1, should raise validation error | ||
|
||
with pytest.raises(PydanticValidationError): | ||
TopicSpec(replicas=40000) # Exceeds max value, should raise validation error | ||
|
||
|
||
def test_strimzi_kafka_topic_from_topic(kafka_topic: KafkaTopic, mocker: MockerFixture): | ||
mock_config = MagicMock() | ||
mock_config.strimzi_topic.cluster_labels = ("bakdata.com/cluster", "my-cluster") | ||
mocker.patch( | ||
"kpops.manifests.strimzi.kafka_topic.get_config", return_value=mock_config | ||
) | ||
|
||
strimzi_topic = StrimziKafkaTopic.from_topic(kafka_topic) | ||
|
||
# Check metadata | ||
assert strimzi_topic.metadata.name == kafka_topic.name | ||
assert strimzi_topic.metadata.labels == {"bakdata.com/cluster": "my-cluster"} | ||
|
||
# Check spec | ||
assert strimzi_topic.spec.partitions == kafka_topic.config.partitions_count | ||
assert strimzi_topic.spec.replicas == kafka_topic.config.replication_factor | ||
assert strimzi_topic.spec.config == kafka_topic.config.configs | ||
|
||
|
||
def test_strimzi_kafka_topic_missing_config(kafka_topic, mocker): | ||
mock_config = MagicMock() | ||
mock_config.strimzi_topic = None | ||
mocker.patch( | ||
"kpops.manifests.strimzi.kafka_topic.get_config", return_value=mock_config | ||
) | ||
|
||
with pytest.raises( | ||
ValidationError, match="must define 'strimzi_topic.resource_label'" | ||
): | ||
StrimziKafkaTopic.from_topic(kafka_topic) |
Oops, something went wrong.