Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
47 changes: 43 additions & 4 deletions core/tests/test_controller_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def test_download_collection_failure(mock_download_failure):
def test_create_project_builds_payload_and_waits(mock_wait, mock_post, mock_session):
instance = MagicMock(organization_id=7, credentials={"project": 123})
pattern = MagicMock(
collection_name="my_namespace.my_collection",
collection_version_uri="https://hub/artifacts/collection-1.0.0.tar.gz",
pattern_name="test_pattern",
collection_version="1.0.0",
pattern_definition={
"aap_resources": {
"controller_project": {"name": "proj", "scm_type": "git"},
Expand All @@ -166,6 +169,7 @@ def test_create_project_builds_payload_and_waits(mock_wait, mock_post, mock_sess
assert pid == 55
payload = mock_post.call_args.args[2]
print("payload", payload)
assert payload["name"] == "proj my_namespace.my_collection.test_pattern 436aa34f"
assert payload["organization"] == 7
assert payload["scm_type"] == "archive"
assert payload["scm_url"] == "https://hub/artifacts/collection-1.0.0.tar.gz"
Expand All @@ -178,8 +182,27 @@ def test_create_project_builds_payload_and_waits(mock_wait, mock_post, mock_sess
@pytest.mark.parametrize(
"ee_def,expected_pull",
[
({"name": "ee1", "image_name": "ns/repo:tag"}, ""),
({"name": "ee1", "image_name": "ns/repo:tag", "pull": "always"}, "always"),
(
{
"name": "ee1",
"collection_name": "collection.example",
"collection_version": "2.0.0",
"pattern_name": "test",
"image_name": "ns/repo:tag",
},
"",
),
(
{
"name": "ee1",
"collection_name": "collection.example",
"collection_version": "2.0.0",
"pattern_name": "test",
"image_name": "ns/repo:tag",
"pull": "always",
},
"always",
),
],
)
def test_create_execution_environment_pull(
Expand All @@ -190,6 +213,7 @@ def test_create_execution_environment_pull(
mock_post.return_value = {"id": 99}
_ = create_execution_environment(mock_session, instance, pattern_def)
payload = mock_post.call_args.args[2]
assert payload["name"] == "ee1 collection.example.test 74d0f2c7"
assert payload["image"] == "aap.example.com/ns/repo:tag"
assert payload["pull"] == expected_pull

Expand All @@ -198,7 +222,12 @@ def test_create_execution_environment_pull(
@patch("core.utils.controller.helpers.post")
def test_create_labels(mock_post, MockControllerLabel, mock_session):
instance = MagicMock(organization_id=1)
pattern_def = {"aap_resources": {"controller_labels": ["L1", "L2"]}}
pattern_def = {
"collection_name": "my_test_namespace.my_test_collection",
"pattern_name": "tester",
"collection_version": "1.0.0",
"aap_resources": {"controller_labels": ["L1", "L2"]},
}

mock_post.side_effect = [
{"id": 10},
Expand All @@ -216,14 +245,20 @@ def test_create_labels(mock_post, MockControllerLabel, mock_session):
assert labels == [label1, label2]
# Ensure proper payloads used
first_payload = mock_post.call_args_list[0].args[2]
assert first_payload == {"name": "L1", "organization": 1}
assert first_payload == {
"name": "L1 my_test_namespace.my_test_collection.tester 5202431b",
"organization": 1,
}


@patch("core.utils.controller.helpers.post")
def test_create_job_templates_payload_and_survey(mock_post, mock_session):
instance = MagicMock(organization_id=5)
pattern_def = {
"name": "mypat",
"collection_name": "tester_namespace.test_collection",
"pattern_name": "demo_pattern",
"collection_version": "3.0.0",
"aap_resources": {
"controller_job_templates": [
{
Expand Down Expand Up @@ -261,6 +296,10 @@ def test_create_job_templates_payload_and_survey(mock_post, mock_session):

# Verify payload fields for a JT
first_jt_payload = mock_post.call_args_list[0].args[2]
assert (
first_jt_payload["name"]
== "jt1 tester_namespace.test_collection.demo_pattern dc5a3002"
)
assert first_jt_payload["organization"] == 5
assert first_jt_payload["project"] == 10
assert first_jt_payload["execution_environment"] == 20
Expand Down
58 changes: 56 additions & 2 deletions core/utils/controller/helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import contextlib
import hashlib
import logging
import os
import random
Expand Down Expand Up @@ -51,6 +52,22 @@ def build_collection_uri(collection_name: str, version: str) -> str:
return urljoin(f"{settings.AAP_URL}/", f"{path}/{filename}")


def aap_resource_info_hash(
resource_name: str,
collection_name: str,
pattern_name: str,
version: str,
organization_id: int,
) -> str:
"""
Generates a unique name for a resource.
"""
hash = hashlib.sha256(
f"{collection_name}.{pattern_name}.{version}.{organization_id}".encode()
).hexdigest()[:8]
return f"{resource_name} {collection_name}.{pattern_name} {hash}"


@contextlib.contextmanager
def download_collection(collection_name: str, version: str) -> Iterator[str]:
"""
Expand Down Expand Up @@ -96,6 +113,14 @@ def create_project(
The created project ID.
"""
project_def = pattern.pattern_definition["aap_resources"]["controller_project"]
# Add unique name to the project definition
project_def["name"] = aap_resource_info_hash(
project_def["name"],
pattern.collection_name,
pattern.pattern_name,
pattern.collection_version,
instance.organization_id,
)
project_def.update(
{
"organization": instance.organization_id,
Expand Down Expand Up @@ -123,6 +148,14 @@ def create_execution_environment(
"""
ee_def = pattern_def["aap_resources"]["controller_execution_environment"]
image_name = ee_def.pop("image_name")
# Add unique name to the ee definition
ee_def["name"] = aap_resource_info_hash(
ee_def["name"],
ee_def["collection_name"],
ee_def["pattern_name"],
ee_def["collection_version"],
instance.organization_id,
)
ee_def.update(
{
"organization": instance.organization_id,
Expand All @@ -138,7 +171,9 @@ def create_execution_environment(


def create_labels(
session: requests.Session, instance: PatternInstance, pattern_def: Dict[str, Any]
session: requests.Session,
instance: PatternInstance,
pattern_def: Dict[str, Any],
) -> List[ControllerLabel]:
"""
Creates controller labels and returns model instances.
Expand All @@ -149,8 +184,19 @@ def create_labels(
List of ControllerLabel model instances.
"""
labels = []

for name in pattern_def["aap_resources"]["controller_labels"]:
label_def = {"name": name, "organization": instance.organization_id}
# Add unique name to the label definition
label_def = {
"name": aap_resource_info_hash(
name,
pattern_def["collection_name"],
pattern_def["pattern_name"],
pattern_def["collection_version"],
instance.organization_id,
)
}
label_def.update({"organization": instance.organization_id})
logger.debug(f"Creating label with definition: {label_def}")

results = post(session, "/api/controller/v2/labels/", label_def)
Expand Down Expand Up @@ -186,6 +232,14 @@ def create_job_templates(

jt_payload = {
**jt,
# Add unique name to the job template definition
"name": aap_resource_info_hash(
jt["name"],
pattern_def["collection_name"],
pattern_def["pattern_name"],
pattern_def["collection_version"],
instance.organization_id,
),
"organization": instance.organization_id,
"project": project_id,
"execution_environment": ee_id,
Expand Down