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

Use hash and trim long Helm release names instead of only trimming #390

Merged
merged 34 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
00db2d3
Use fullnameOverride insted of nameOverride for the deployments
raminqaf Nov 20, 2023
a2101ee
Fix Kafka Resetter fullnameOverride value
raminqaf Nov 20, 2023
5ea5b7a
Fix Kafka Resetter fullnameOverride value
raminqaf Nov 20, 2023
9fdbfed
Use sha-1 hash to shorten clean up job release names
raminqaf Nov 21, 2023
76e1d03
Update files
raminqaf Nov 21, 2023
a211004
Change helm release name to sha-1 hashed strings
raminqaf Nov 21, 2023
9db707e
Improve helm release name creation
raminqaf Nov 21, 2023
2ad0c05
Improve tests
raminqaf Nov 21, 2023
fcec5eb
Improve tests
raminqaf Nov 21, 2023
c178617
fix helm name
raminqaf Dec 6, 2023
27d7782
Merge branch 'main' into feature/use-fullname-override
raminqaf Dec 6, 2023
6a77faa
add reviews
raminqaf Dec 8, 2023
cd5f65d
Fix tests
raminqaf Dec 8, 2023
eca8256
Merge v3
raminqaf Dec 8, 2023
7e8bb11
Merge branch 'v3' of github.com:bakdata/kpops into feature/use-fullna…
raminqaf Dec 8, 2023
ebbd5b0
fix title
raminqaf Dec 8, 2023
c3f6afa
add clean suffix to helm clean release name
raminqaf Dec 11, 2023
33a5d54
add tests
raminqaf Dec 12, 2023
8992d75
Update files
raminqaf Dec 12, 2023
b1344e5
merge v3
raminqaf Dec 12, 2023
db6e874
Add migration guide
raminqaf Dec 12, 2023
678ca56
Merge branch 'v3' of github.com:bakdata/kpops into feature/use-fullna…
raminqaf Dec 12, 2023
edc540f
Update files
raminqaf Dec 12, 2023
29e5cb5
Update files
raminqaf Dec 12, 2023
5d98313
Merge branch 'v3' of github.com:bakdata/kpops into feature/use-fullna…
raminqaf Dec 21, 2023
873553b
merge v3
raminqaf Dec 21, 2023
539efab
Merge branch 'v3' into feature/use-fullname-override
raminqaf Dec 21, 2023
64f46d3
Merge branch 'v3' into feature/use-fullname-override
raminqaf Dec 21, 2023
5fa0844
Merge branch 'v3' into feature/use-fullname-override
raminqaf Dec 22, 2023
e1fe2ec
Fix typo
raminqaf Dec 22, 2023
13935eb
add nameOverride
raminqaf Jan 2, 2024
e2d6394
Update files
raminqaf Jan 2, 2024
659f53a
Update files
raminqaf Jan 2, 2024
cddd344
Update files
raminqaf Jan 2, 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
12 changes: 6 additions & 6 deletions docs/docs/schema/pipeline.json
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,9 @@
"ProducerValues": {
"description": "Settings specific to producers.",
"properties": {
"nameOverride": {
"description": "Override name with this value",
"title": "Nameoverride",
"fullnameOverride": {
"description": "Overrides fully the release and chart name",
"title": "Fullnameoverride",
"type": "string"
},
"streams": {
Expand Down Expand Up @@ -749,9 +749,9 @@
"description": "Kubernetes Event-driven Autoscaling config",
"title": "Autoscaling"
},
"nameOverride": {
"description": "Override name with this value",
"title": "Nameoverride",
"fullnameOverride": {
"description": "Overrides fully the release and chart name",
"title": "Fullnameoverride",
"type": "string"
},
"streams": {
Expand Down
20 changes: 13 additions & 7 deletions kpops/component_handlers/helm_wrapper/utils.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import hashlib
import logging

log = logging.getLogger("HelmUtils")


ENCODING = "utf-8"
RELEASE_NAME_MAX_LEN = 52


def trim_release_name(name: str, suffix: str = "") -> str:
"""Trim Helm release name while preserving suffix.
def create_helm_release_name(name: str) -> str:
"""Shortens the long Helm release name.

Creates a 52 character long release name if the name length exceeds the Helm release character length.
It first trims the string and fetches the first 52 characters.
Then it replaces the last 6 characters with the SHA-1 encoded string (with "-") to avoid collision.

:param name: The release name including optional suffix
:param suffix: The release suffix to preserve
:return: Truncated release name.
:param: name: The Helm release name to be shortened.
:return: SHA-1 encoded String
"""
if len(name) > RELEASE_NAME_MAX_LEN:
new_name = name[: (RELEASE_NAME_MAX_LEN - len(suffix))] + suffix
exact_name = name[:RELEASE_NAME_MAX_LEN]
hash_name = hashlib.sha1(name.encode(ENCODING)).hexdigest()
new_name = exact_name[:-6] + "-" + hash_name[:4]
log.critical(
f"Invalid Helm release name '{name}'. Truncating to {RELEASE_NAME_MAX_LEN} characters: \n {name} --> {new_name}"
)
Expand Down
2 changes: 1 addition & 1 deletion kpops/component_handlers/kafka_connect/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class Config(CamelCaseConfig):
class KafkaConnectResetterValues(BaseModel):
connector_type: Literal["source", "sink"]
config: KafkaConnectResetterConfig
name_override: str
fullname_override: str

class Config(CamelCaseConfig):
pass
Expand Down
41 changes: 21 additions & 20 deletions kpops/components/base_components/kafka_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
HelmRepoConfig,
HelmUpgradeInstallFlags,
)
from kpops.component_handlers.helm_wrapper.utils import trim_release_name
from kpops.component_handlers.helm_wrapper.utils import create_helm_release_name
from kpops.components.base_components.kubernetes_app import (
KubernetesApp,
KubernetesAppConfig,
Expand Down Expand Up @@ -41,14 +41,14 @@ class KafkaAppConfig(KubernetesAppConfig):
"""Settings specific to Kafka Apps.

:param streams: Kafka streams config
:param name_override: Override name with this value, defaults to None
:param fullname_override: Overrides fully the release and chart name, defaults to None
"""

streams: KafkaStreamsConfig = Field(
default=..., description=describe_attr("streams", __doc__)
)
name_override: str | None = Field(
default=None, description=describe_attr("name_override", __doc__)
fullname_override: str | None = Field(
default=None, description=describe_attr("fullname_override", __doc__)
)


Expand Down Expand Up @@ -85,6 +85,12 @@ def clean_up_helm_chart(self) -> str:
"""Helm chart used to destroy and clean this component."""
raise NotImplementedError

@property
def clean_up_release_name(self) -> str:
suffix = "-clean"
# TODO: Should this be self.helm_release_name + suffix ?
return create_helm_release_name(self.full_name + suffix)

@override
def deploy(self, dry_run: bool) -> None:
if self.to:
Expand All @@ -109,28 +115,25 @@ def _run_clean_up_job(
:param values: The value YAML for the chart
:param dry_run: Dry run command
:param retain_clean_jobs: Whether to retain the cleanup job, defaults to False
:return:
"""
suffix = "-clean"
clean_up_release_name = trim_release_name(
self.helm_release_name + suffix, suffix
)
log.info(f"Uninstall old cleanup job for {clean_up_release_name}")
log.info(f"Uninstall old cleanup job for {self.clean_up_release_name}")

self.__uninstall_clean_up_job(clean_up_release_name, dry_run)
self.__uninstall_clean_up_job(self.clean_up_release_name, dry_run)

log.info(f"Init cleanup job for {clean_up_release_name}")
log.info(f"Init cleanup job for {self.clean_up_release_name}")

stdout = self.__install_clean_up_job(
clean_up_release_name, suffix, values, dry_run
self.clean_up_release_name, values, dry_run
)

if dry_run:
self.dry_run_handler.print_helm_diff(stdout, clean_up_release_name, log)
self.dry_run_handler.print_helm_diff(
stdout, self.clean_up_release_name, log
)

if not retain_clean_jobs:
log.info(f"Uninstall cleanup job for {clean_up_release_name}")
self.__uninstall_clean_up_job(clean_up_release_name, dry_run)
log.info(f"Uninstall cleanup job for {self.clean_up_release_name}")
self.__uninstall_clean_up_job(self.clean_up_release_name, dry_run)

def __uninstall_clean_up_job(self, release_name: str, dry_run: bool) -> None:
"""Uninstall clean up job.
Expand All @@ -143,7 +146,6 @@ def __uninstall_clean_up_job(self, release_name: str, dry_run: bool) -> None:
def __install_clean_up_job(
self,
release_name: str,
suffix: str,
values: dict,
dry_run: bool,
) -> str:
Expand All @@ -153,11 +155,10 @@ def __install_clean_up_job(
:param suffix: Suffix to add to the release name, e.g. "-clean"
:param values: The Helm values for the chart
:param dry_run: Whether to do a dry run of the command
:return: Install clean up job with helm, return the output of the installation
:return: Return the output of the installation
"""
clean_up_release_name = trim_release_name(release_name, suffix)
return self.helm.upgrade_install(
clean_up_release_name,
release_name,
self.clean_up_helm_chart,
dry_run,
self.namespace,
Expand Down
6 changes: 3 additions & 3 deletions kpops/components/base_components/kafka_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
HelmTemplateFlags,
HelmUpgradeInstallFlags,
)
from kpops.component_handlers.helm_wrapper.utils import trim_release_name
from kpops.component_handlers.helm_wrapper.utils import create_helm_release_name
from kpops.component_handlers.kafka_connect.model import (
KafkaConnectorConfig,
KafkaConnectorType,
Expand Down Expand Up @@ -106,7 +106,7 @@ def helm(self) -> Helm:
def _resetter_release_name(self) -> str:
suffix = "-clean"
clean_up_release_name = self.full_name + suffix
return trim_release_name(clean_up_release_name, suffix)
return create_helm_release_name(clean_up_release_name)

@property
def _resetter_helm_chart(self) -> str:
Expand Down Expand Up @@ -245,7 +245,7 @@ def _get_kafka_connect_resetter_values(
**kwargs,
),
connector_type=self._connector_type.value,
name_override=self.full_name,
fullname_override=self.full_name + "-clean",
).dict(),
**self.resetter_values,
}
Expand Down
3 changes: 2 additions & 1 deletion kpops/components/base_components/kubernetes_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
HelmTemplateFlags,
HelmUpgradeInstallFlags,
)
from kpops.component_handlers.helm_wrapper.utils import create_helm_release_name
from kpops.components.base_components.pipeline_component import PipelineComponent
from kpops.utils.colorify import magentaify
from kpops.utils.docstring import describe_attr
Expand Down Expand Up @@ -91,7 +92,7 @@ def dry_run_handler(self) -> DryRunHandler:
@property
def helm_release_name(self) -> str:
"""The name for the Helm release. Can be overridden."""
return self.full_name
return create_helm_release_name(self.full_name)

@property
def helm_chart(self) -> str:
Expand Down
6 changes: 3 additions & 3 deletions kpops/pipeline_generator/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ def validate_unique_names(self) -> None:
@staticmethod
def _populate_component_name(component: PipelineComponent) -> None: # TODO: remove
with suppress(
AttributeError # Some components like Kafka Connect do not have a name_override attribute
AttributeError # Some components like Kafka Connect do not have a fullname_override attribute
):
if (app := getattr(component, "app")) and app.name_override is None:
app.name_override = component.full_name
if (app := getattr(component, "app")) and app.fullname_override is None:
app.fullname_override = component.full_name


def create_env_components_index(
Expand Down
48 changes: 27 additions & 21 deletions tests/component_handlers/helm_wrapper/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
from kpops.component_handlers.helm_wrapper.utils import trim_release_name
import hashlib

from kpops.component_handlers.helm_wrapper.utils import (
create_helm_release_name,
)

def test_trim_release_name_with_suffix():
name = trim_release_name(
"example-component-name-too-long-fake-fakefakefakefakefake-clean",
suffix="-clean",

def test_helm_release_name_for_long_names():
long_release_name = "example-component-name-too-long-fake-fakefakefakefakefake"
actual_release_name = (
"example-component-name-too-long-fake-fakefakef-"
+ hashlib.sha1(long_release_name.encode("utf-8")).hexdigest()[:4]
)
assert name == "example-component-name-too-long-fake-fakefakef-clean"
assert len(name) == 52
expected_helm_release_name = create_helm_release_name(long_release_name)

assert expected_helm_release_name == actual_release_name
assert len(expected_helm_release_name) < 53


def test_trim_release_name_without_suffix():
name = trim_release_name(
"example-component-name-too-long-fake-fakefakefakefakefake"
def test_helm_release_name_for_install_and_clean_must_be_different():
long_release_name = "example-component-name-too-long-fake-fakefakefakefakefake"
long_clean_release_name = (
"example-component-name-too-long-fake-fakefakefakefakefake-clean"
)
assert name == "example-component-name-too-long-fake-fakefakefakefak"
assert len(name) == 52
expected_helm_release_name = create_helm_release_name(long_release_name)
expected_helm_clean_release_name = create_helm_release_name(long_clean_release_name)

assert expected_helm_release_name != expected_helm_clean_release_name

def test_no_trim_release_name():
assert (
trim_release_name("normal-name-with-no-need-of-trim-clean", suffix="-clean")
== "normal-name-with-no-need-of-trim-clean"
)
assert (
trim_release_name("normal-name-with-no-need-of-trim")
== "normal-name-with-no-need-of-trim"
)

def test_helm_release_name_for_short_names():
short_release_name = "example-component-name"
expected_helm_release_name = create_helm_release_name(short_release_name)
assert expected_helm_release_name == short_release_name
assert len(expected_helm_release_name) < 53
3 changes: 2 additions & 1 deletion tests/components/test_kafka_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
HelmRepoConfig,
HelmUpgradeInstallFlags,
)
from kpops.component_handlers.helm_wrapper.utils import create_helm_release_name
from kpops.components.base_components import KafkaApp

DEFAULTS_PATH = Path(__file__).parent / "resources"
Expand Down Expand Up @@ -93,7 +94,7 @@ def test_should_deploy_kafka_app(

print_helm_diff.assert_called_once()
helm_upgrade_install.assert_called_once_with(
"${pipeline_name}-example-name",
create_helm_release_name("${pipeline_name}-example-name"),
"test/test-chart",
True,
"test-namespace",
Expand Down
4 changes: 3 additions & 1 deletion tests/components/test_kafka_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
from kpops.cli.pipeline_config import PipelineConfig, TopicNameConfig
from kpops.component_handlers import ComponentHandlers
from kpops.component_handlers.helm_wrapper.model import HelmDiffConfig
from kpops.component_handlers.helm_wrapper.utils import create_helm_release_name
from kpops.component_handlers.kafka_connect.model import KafkaConnectorConfig
from kpops.components.base_components.kafka_connector import KafkaConnector

DEFAULTS_PATH = Path(__file__).parent / "resources"
CONNECTOR_NAME = "test-connector-with-long-name-0123456789abcdefghijklmnop"
CONNECTOR_FULL_NAME = "${pipeline_name}-" + CONNECTOR_NAME
CONNECTOR_CLEAN_FULL_NAME = "${pipeline_name}-test-connector-with-long-name-clean"
CONNECTOR_CLEAN_FULL_NAME = CONNECTOR_FULL_NAME + "-clean"
CONNECTOR_CLEAN_RELEASE_NAME = create_helm_release_name(CONNECTOR_CLEAN_FULL_NAME)
CONNECTOR_CLASS = "com.bakdata.connect.TestConnector"


Expand Down
Loading