Skip to content

Commit c7a54da

Browse files
authored
Merge branch 'main' into upgrade-jupyterhub-helm-chart
2 parents ee3e582 + 70ef140 commit c7a54da

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

src/_nebari/stages/infrastructure/__init__.py

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,12 @@ class NodeGroup(schema.Base):
4949
def validate_taint_strings(cls, taints: list[Any]):
5050
if taints is None:
5151
return taints
52-
53-
TAINT_STR_REGEX = re.compile(r"(\w+)=(\w+):(\w+)")
5452
return_value = []
5553
for taint in taints:
5654
if not isinstance(taint, str):
5755
return_value.append(taint)
5856
else:
59-
match = TAINT_STR_REGEX.match(taint)
60-
if not match:
61-
raise ValueError(f"Invalid taint string: {taint}")
62-
key, taints, effect = match.groups()
63-
parsed_taint = schema.Taint(key=key, value=taints, effect=effect)
57+
parsed_taint = schema.Taint.from_string(taint)
6458
return_value.append(parsed_taint)
6559

6660
return return_value
@@ -73,7 +67,6 @@ def validate_taint_strings(cls, taints: list[Any]):
7367

7468

7569
def set_missing_taints_to_default_taints(node_groups: NodeGroup) -> NodeGroup:
76-
7770
for node_group_name, node_group in node_groups.items():
7871
if node_group.taints is None:
7972
if node_group_name == "general":
@@ -239,21 +232,6 @@ def construct_aws_ami_type(
239232

240233
return "AL2_x86_64"
241234

242-
@field_validator("node_taints", mode="before")
243-
def convert_taints(cls, value: Optional[List[schema.Taint]]):
244-
return [
245-
dict(
246-
key=taint.key,
247-
value=taint.value,
248-
effect={
249-
schema.TaintEffectEnum.NoSchedule: "NO_SCHEDULE",
250-
schema.TaintEffectEnum.PreferNoSchedule: "PREFER_NO_SCHEDULE",
251-
schema.TaintEffectEnum.NoExecute: "NO_EXECUTE",
252-
}[taint.effect],
253-
)
254-
for taint in value
255-
]
256-
257235

258236
class AWSInputVars(schema.Base):
259237
name: str
@@ -656,7 +634,7 @@ def _check_input(cls, data: Any) -> Any:
656634
or available_kms_keys[key_id[0]].Arn != data["eks_kms_arn"]
657635
):
658636
raise ValueError(
659-
f"Amazon Web Services KMS Key with ARN {data['eks_kms_arn']} not one of available/enabled keys={ [v.Arn for v in available_kms_keys.values() if v.KeyManager == 'CUSTOMER' and v.KeySpec == 'SYMMETRIC_DEFAULT']}"
637+
f"Amazon Web Services KMS Key with ARN {data['eks_kms_arn']} not one of available/enabled keys={[v.Arn for v in available_kms_keys.values() if v.KeyManager == 'CUSTOMER' and v.KeySpec == 'SYMMETRIC_DEFAULT']}"
660638
)
661639
key_id = key_id[0]
662640
# Raise error if key is not a customer managed key

src/nebari/schema.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import enum
2-
from typing import Annotated
2+
import re
3+
from typing import Annotated, ClassVar
34

45
import pydantic
56
from pydantic import ConfigDict, Field, StringConstraints, field_validator
@@ -117,10 +118,32 @@ def to_yaml(cls, representer, node):
117118
return representer.represent_str(node.value)
118119

119120

121+
TAINT_KEY_REGEX = r"([a-zA-Z0-9][-a-zA-Z0-9_.]{0,251}[a-zA-Z0-9]?(?:/[a-zA-Z0-9][-a-zA-Z0-9_.]{0,251}[a-zA-Z0-9]?)?)"
122+
TAINT_VALUE_REGEX = r"([a-zA-Z0-9][-a-zA-Z0-9_.]{0,61}[a-zA-Z0-9]?)?"
123+
TAINT_STR_REGEX = rf"^{TAINT_KEY_REGEX}(?:={TAINT_VALUE_REGEX})?:({'|'.join([taint_effect.value for taint_effect in TaintEffectEnum])})$"
124+
125+
120126
class Taint(Base):
121-
key: str
122-
value: str
127+
# Taint constraints listed at https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#taint
128+
key: Annotated[str, StringConstraints(pattern=TAINT_KEY_REGEX)]
129+
value: Annotated[None | str, StringConstraints(pattern=TAINT_VALUE_REGEX)]
123130
effect: TaintEffectEnum
131+
_TAINT_REGEX_PATTERN: ClassVar[re.Pattern] = re.compile(TAINT_STR_REGEX)
132+
133+
@classmethod
134+
def from_string(cls, taint_string: str):
135+
"""
136+
Given a taint string, parse it into the Taint object.
137+
"""
138+
match = cls._TAINT_REGEX_PATTERN.match(taint_string)
139+
if not match:
140+
raise ValueError(f"Invalid taint string: {taint_string}")
141+
key, value, effect = match.groups()
142+
return Taint(
143+
key=key,
144+
value=value,
145+
effect=effect,
146+
)
124147

125148

126149
provider_enum_name_map: dict[ProviderEnum, str] = {

tests/tests_unit/test_stages.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import pytest
55

6+
from _nebari.stages.infrastructure import NodeGroup
67
from _nebari.stages.terraform_state import TerraformStateStage
78
from _nebari.utils import yaml
89
from _nebari.version import __version__
@@ -115,3 +116,32 @@ def test_check_immutable_fields_change_dict_any(
115116

116117
# This should not raise an exception
117118
terraform_state_stage.check_immutable_fields()
119+
120+
121+
@pytest.mark.parametrize(
122+
"taints,keys,values,effects",
123+
[
124+
(["key1=value1:NoSchedule"], ["key1"], ["value1"], ["NoSchedule"]),
125+
(["key1=value1:PreferNoSchedule"], ["key1"], ["value1"], ["PreferNoSchedule"]),
126+
(["key1=value1:NoExecute"], ["key1"], ["value1"], ["NoExecute"]),
127+
(
128+
["dedicated=special-user:NoSchedule"],
129+
["dedicated"],
130+
["special-user"],
131+
["NoSchedule"],
132+
),
133+
(["dedicated:NoSchedule"], ["dedicated"], [None], ["NoSchedule"]),
134+
(
135+
["key1=value1:NoExecute", "key2=value2:NoExecute"],
136+
["key1", "key2"],
137+
["value1", "value2"],
138+
["NoExecute", "NoExecute"],
139+
),
140+
],
141+
)
142+
def test_node_group_taints(taints, keys, values, effects):
143+
ng = NodeGroup(instance="t3.medium", min_nodes=1, max_nodes=1, taints=taints)
144+
145+
assert [t.key for t in ng.taints] == keys
146+
assert [t.value for t in ng.taints] == values
147+
assert [t.effect for t in ng.taints] == effects

0 commit comments

Comments
 (0)