Skip to content

Commit

Permalink
Merge pull request #165 from baloise/feat/namespaceMaxLength
Browse files Browse the repository at this point in the history
feat(GitOpsConfig): add namespaceMaxLength
  • Loading branch information
christiansiegel authored Aug 4, 2021
2 parents c047e45 + 8f36965 commit 04be2c6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 9 deletions.
26 changes: 22 additions & 4 deletions gitopscli/gitops_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@

from gitopscli.gitops_exception import GitOpsException

_MAX_NAMESPACE_LENGTH = 63
_VARIABLE_REGEX = re.compile(r"\${(\w+)}")


@dataclass(frozen=True)
class GitOpsConfig:
class GitOpsConfig: # pylint: disable=too-many-instance-attributes
class Replacement:
@dataclass(frozen=True)
class PreviewContext:
Expand Down Expand Up @@ -61,6 +60,7 @@ def get_value(self, context: PreviewContext) -> str:
preview_target_repository: str
preview_target_branch: Optional[str]
preview_target_namespace_template: str
preview_target_max_namespace_length: int

replacements: Dict[str, List[Replacement]]

Expand Down Expand Up @@ -90,6 +90,10 @@ def __post_init__(self) -> None:
self.__assert_variables(
self.preview_target_namespace_template, {"APPLICATION_NAME", "PREVIEW_ID_HASH", "PREVIEW_ID"}
)
assert isinstance(
self.preview_target_max_namespace_length, int
), "preview_target_max_namespace_length of wrong type!"
assert self.preview_target_max_namespace_length >= 1, "preview_target_max_namespace_length is < 1!"
assert isinstance(self.replacements, dict), "replacements of wrong type!"
for file, replacements in self.replacements.items():
assert isinstance(file, str), f"replacement file '{file}' of wrong type!"
Expand All @@ -110,12 +114,12 @@ def get_preview_namespace(self, preview_id: str) -> str:
preview_namespace = preview_namespace.replace("${PREVIEW_ID_HASH}", self.create_preview_id_hash(preview_id))

current_length = len(preview_namespace) - len("${PREVIEW_ID}")
remaining_length = _MAX_NAMESPACE_LENGTH - current_length
remaining_length = self.preview_target_max_namespace_length - current_length

if remaining_length < 1:
preview_namespace = preview_namespace.replace("${PREVIEW_ID}", "")
raise GitOpsException(
f"Preview namespace is too long (max {_MAX_NAMESPACE_LENGTH} chars): "
f"Preview namespace is too long (max {self.preview_target_max_namespace_length} chars): "
f"{preview_namespace} ({len(preview_namespace)} chars)"
)

Expand Down Expand Up @@ -198,6 +202,12 @@ def __get_string_value_or_none(self, key: str) -> Optional[str]:
raise GitOpsException(f"Item '{key}' should be a string in GitOps config!")
return value

def __get_int_value_or_default(self, key: str, default: int) -> int:
value = self.__get_value_or_default(key, default)
if not isinstance(value, int):
raise GitOpsException(f"Item '{key}' should be an integer in GitOps config!")
return value

def __get_list_value(self, key: str) -> List[Any]:
value = self.__get_value(key)
if not isinstance(value, list):
Expand Down Expand Up @@ -268,6 +278,7 @@ def __parse_v0(self) -> GitOpsConfig:
preview_target_repository=preview_target_repository,
preview_target_branch=None, # use default branch
preview_target_namespace_template="${APPLICATION_NAME}-${PREVIEW_ID_HASH}-preview",
preview_target_max_namespace_length=63,
replacements=replacements,
)

Expand All @@ -292,13 +303,19 @@ def __parse_v1(self) -> GitOpsConfig:
preview_target_repository=config.preview_target_repository,
preview_target_branch=config.preview_target_branch,
preview_target_namespace_template=add_var_dollar(config.preview_target_namespace_template),
preview_target_max_namespace_length=63,
replacements=replacements,
)

def __parse_v2(self) -> GitOpsConfig:
preview_target_organisation = self.__get_string_value("previewConfig.target.organisation")
preview_target_repository = self.__get_string_value("previewConfig.target.repository")
preview_target_branch = self.__get_string_value_or_none("previewConfig.target.branch")
preview_target_max_namespace_length = self.__get_int_value_or_default(
"previewConfig.target.maxNamespaceLength", 53
)
if preview_target_max_namespace_length < 1:
raise GitOpsException("Value 'maxNamespaceLength' should be at least 1 in GitOps config!")

replacements: Dict[str, List[GitOpsConfig.Replacement]] = {}
for filename, file_replacements in self.__get_dict_value("previewConfig.replace").items():
Expand Down Expand Up @@ -344,5 +361,6 @@ def __parse_v2(self) -> GitOpsConfig:
preview_target_namespace_template=self.__get_string_value_or_default(
"previewConfig.target.namespace", "${APPLICATION_NAME}-${PREVIEW_ID}-${PREVIEW_ID_HASH}-preview",
),
preview_target_max_namespace_length=preview_target_max_namespace_length,
replacements=replacements,
)
2 changes: 2 additions & 0 deletions tests/commands/test_create_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def setUp(self):
preview_target_repository="PREVIEW_TARGET_REPO",
preview_target_branch=None,
preview_target_namespace_template="my-app-${PREVIEW_ID_HASH}-preview",
preview_target_max_namespace_length=50,
replacements={
"Chart.yaml": [GitOpsConfig.Replacement(path="name", value_template="${PREVIEW_NAMESPACE}"),],
"values.yaml": [
Expand Down Expand Up @@ -208,6 +209,7 @@ def test_create_new_preview_from_same_template_target_repo(self):
preview_target_repository=gitops_config.preview_target_repository,
preview_target_branch=gitops_config.preview_target_branch,
preview_target_namespace_template=gitops_config.preview_target_namespace_template,
preview_target_max_namespace_length=gitops_config.preview_target_max_namespace_length,
replacements=gitops_config.replacements,
)

Expand Down
1 change: 1 addition & 0 deletions tests/commands/test_delete_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def setUp(self):
preview_target_repository="PREVIEW_TARGET_REPO",
preview_target_branch="target-branch",
preview_target_namespace_template="APP-${PREVIEW_ID_HASH}-preview",
preview_target_max_namespace_length=50,
replacements={},
)

Expand Down
33 changes: 28 additions & 5 deletions tests/test_gitops_config_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def setUp(self):
"repository": "my-target-repo",
"branch": "my-target-branch",
"namespace": "${APPLICATION_NAME}-${PREVIEW_ID_HASH}-dev",
"maxNamespaceLength": 50,
},
"replace": {
"file_1.yaml": [
Expand Down Expand Up @@ -211,10 +212,10 @@ def test_preview_target_namespace_default(self):
config.preview_target_namespace_template, "${APPLICATION_NAME}-${PREVIEW_ID}-${PREVIEW_ID_HASH}-preview"
)
actual_namespace = config.get_preview_namespace(
"Very long preview ID. It will be cut to have max 63 chars of namespace in total!!"
"Very long preview ID. It will be cut to have max 'maxNamespaceLength' chars of namespace in total!!"
)
self.assertEqual(actual_namespace, "my-app-very-long-preview-id-it-will-be-cut-to-05d9825a-preview")
self.assertTrue(len(actual_namespace) <= 63)
self.assertEqual(actual_namespace, "my-app-very-long-preview-id-it-wi-c9fdf802-preview")
self.assertTrue(len(actual_namespace) <= 50)

def test_preview_target_namespace_not_a_string(self):
self.yaml["previewConfig"]["target"]["namespace"] = []
Expand All @@ -230,19 +231,41 @@ def test_preview_target_namespace_invalid_template(self):
def test_preview_target_namespace_too_long(self):
self.yaml["previewConfig"]["target"][
"namespace"
] = "veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long-${PREVIEW_ID}-${PREVIEW_ID_HASH}"
] = "veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long-${PREVIEW_ID}-${PREVIEW_ID_HASH}"
config = self.load()
with pytest.raises(GitOpsException) as ex:
config.get_preview_namespace("x")
self.assertEqual(
"Preview namespace is too long (max 63 chars): veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long--2d711642 (68 chars)",
"Preview namespace is too long (max 50 chars): veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long--2d711642 (55 chars)",
str(ex.value),
)

def test_preview_target_namespace_contains_invalid_variable(self):
self.yaml["previewConfig"]["target"]["namespace"] = "${FOO}-bar"
self.assert_load_error("GitOps config template '${FOO}-bar' contains invalid variable: FOO")

def test_preview_target_namespace_max_length(self):
self.yaml["previewConfig"]["target"]["maxNamespaceLength"] = 50
config = self.load()
self.assertEqual(config.preview_target_max_namespace_length, 50)

self.yaml["previewConfig"]["target"]["maxNamespaceLength"] = 256
config = self.load()
self.assertEqual(config.preview_target_max_namespace_length, 256)

def test_preview_target_namespace_max_length_default(self):
del self.yaml["previewConfig"]["target"]["maxNamespaceLength"]
config = self.load()
self.assertEqual(config.preview_target_max_namespace_length, 53)

def test_preview_target_namespace_max_length_not_an_integer(self):
self.yaml["previewConfig"]["target"]["maxNamespaceLength"] = "50"
self.assert_load_error("Item 'previewConfig.target.maxNamespaceLength' should be an integer in GitOps config!")

def test_preview_target_namespace_max_length_less_than_one(self):
self.yaml["previewConfig"]["target"]["maxNamespaceLength"] = 0
self.assert_load_error("Value 'maxNamespaceLength' should be at least 1 in GitOps config!")

def test_replacements(self):
config = self.load()
self.assertEqual(config.replacements.keys(), {"file_1.yaml", "file_2.yaml"})
Expand Down

0 comments on commit 04be2c6

Please sign in to comment.