Skip to content

Commit 71268a6

Browse files
authored
Merge pull request #70 from Yelp/gcoll_COREML-2591_fix_issues_with_long_label_names
[COREML-2591] Fix issue with long label names in k8s
2 parents b528539 + 66818c0 commit 71268a6

File tree

3 files changed

+47
-7
lines changed

3 files changed

+47
-7
lines changed

service_configuration_lib/spark_config.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
import functools
23
import hashlib
34
import itertools
@@ -34,6 +35,7 @@
3435
DEFAULT_EXECUTOR_CORES = 2
3536
DEFAULT_EXECUTOR_INSTANCES = 2
3637
DEFAULT_EXECUTOR_MEMORY = '4g'
38+
DEFAULT_K8S_LABEL_LENGTH = 63
3739

3840

3941
NON_CONFIGURABLE_SPARK_OPTS = {
@@ -446,6 +448,12 @@ def _get_k8s_spark_env(
446448
volumes: Optional[List[Mapping[str, str]]],
447449
paasta_pool: str,
448450
) -> Dict[str, str]:
451+
# RFC 1123: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
452+
# technically only paasta instance can be longer than 63 chars. But we apply the normalization regardless.
453+
# NOTE: this affects only k8s labels, not the pod names.
454+
_paasta_cluster = _get_k8s_resource_name_limit_size_with_hash(paasta_cluster)
455+
_paasta_service = _get_k8s_resource_name_limit_size_with_hash(paasta_service)
456+
_paasta_instance = _get_k8s_resource_name_limit_size_with_hash(paasta_instance)
449457
spark_env = {
450458
'spark.master': f'k8s://https://k8s.{paasta_cluster}.paasta:6443',
451459
'spark.executorEnv.PAASTA_SERVICE': paasta_service,
@@ -460,19 +468,37 @@ def _get_k8s_spark_env(
460468
'spark.kubernetes.authenticate.clientKeyFile': f'{K8S_AUTH_FOLDER}/{paasta_cluster}-client.key',
461469
'spark.kubernetes.authenticate.clientCertFile': f'{K8S_AUTH_FOLDER}/{paasta_cluster}-client.crt',
462470
'spark.kubernetes.container.image.pullPolicy': 'Always',
463-
'spark.kubernetes.executor.label.yelp.com/paasta_service': paasta_service,
464-
'spark.kubernetes.executor.label.yelp.com/paasta_instance': paasta_instance,
465-
'spark.kubernetes.executor.label.yelp.com/paasta_cluster': paasta_cluster,
466-
'spark.kubernetes.executor.label.paasta.yelp.com/service': paasta_service,
467-
'spark.kubernetes.executor.label.paasta.yelp.com/instance': paasta_instance,
468-
'spark.kubernetes.executor.label.paasta.yelp.com/cluster': paasta_cluster,
471+
'spark.kubernetes.executor.label.yelp.com/paasta_service': _paasta_service,
472+
'spark.kubernetes.executor.label.yelp.com/paasta_instance': _paasta_instance,
473+
'spark.kubernetes.executor.label.yelp.com/paasta_cluster': _paasta_cluster,
474+
'spark.kubernetes.executor.label.paasta.yelp.com/service': _paasta_service,
475+
'spark.kubernetes.executor.label.paasta.yelp.com/instance': _paasta_instance,
476+
'spark.kubernetes.executor.label.paasta.yelp.com/cluster': _paasta_cluster,
469477
'spark.kubernetes.node.selector.yelp.com/pool': paasta_pool,
470478
'spark.kubernetes.executor.label.yelp.com/pool': paasta_pool,
471479
**_get_k8s_docker_volumes_conf(volumes),
472480
}
473481
return spark_env
474482

475483

484+
def _get_k8s_resource_name_limit_size_with_hash(name: str, limit: int = 63, suffix: int = 4) -> str:
485+
""" Returns `name` unchanged if it's length does not exceed the `limit`.
486+
Otherwise, returns truncated `name` with it's hash of size `suffix`
487+
appended.
488+
489+
base32 encoding is chosen as it satisfies the common requirement in
490+
various k8s names to be alphanumeric.
491+
492+
NOTE: This function is the same as paasta/paasta_tools/kubernetes_tools.py
493+
"""
494+
if len(name) > limit:
495+
digest = hashlib.md5(name.encode()).digest()
496+
hash = base64.b32encode(digest).decode().replace('=', '').lower()
497+
return f'{name[:(limit-suffix-1)]}-{hash[:suffix]}'
498+
else:
499+
return name
500+
501+
476502
def stringify_spark_env(spark_env: Mapping[str, str]) -> str:
477503
return ' '.join([f'--conf {k}={v}' for k, v in spark_env.items()])
478504

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name='service-configuration-lib',
20-
version='2.5.8',
20+
version='2.6.0',
2121
provides=['service_configuration_lib'],
2222
description='Start, stop, and inspect Yelp SOA services',
2323
url='https://github.com/Yelp/service_configuration_lib',

tests/spark_config_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,3 +1137,17 @@ def test_send_and_calculate_resources_cost(
11371137
mock_clusterman_metrics.util.costs.estimate_cost_per_hour.assert_called_once_with(
11381138
cluster='test-cluster', pool='test-pool', cpus=10, mem=2048,
11391139
)
1140+
1141+
1142+
@pytest.mark.parametrize(
1143+
'instance_name,expected_instance_label',
1144+
(
1145+
('my_job.do_something', 'my_job.do_something'),
1146+
(
1147+
f"my_job.{'a'* 100}",
1148+
'my_job.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-6xhe',
1149+
),
1150+
),
1151+
)
1152+
def test_get_k8s_resource_name_limit_size_with_hash(instance_name, expected_instance_label):
1153+
assert expected_instance_label == spark_config._get_k8s_resource_name_limit_size_with_hash(instance_name)

0 commit comments

Comments
 (0)