From 0de74d7092af417f5966e8b590ca8a32bb60f268 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Mon, 18 Mar 2024 23:04:45 +0100 Subject: [PATCH 01/11] added optional label support --- broker/commands.py | 7 ++++++- broker/providers/ansible_tower.py | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/broker/commands.py b/broker/commands.py index 11a4338a..ef9d7e9c 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -189,6 +189,9 @@ def cli(version): @click.option("-b", "--background", is_flag=True, help="Run checkout in the background") @click.option("-n", "--nick", type=str, help="Use a nickname defined in your settings") @click.option("-c", "--count", type=int, help="Number of times broker repeats the checkout") +@click.option( + "--labels", type=str, help="List of strings (comma-separated) to be used as AAP labels" +) # fixme - this should be provider-agnostic @click.option( "--args-file", type=click.Path(exists=True), @@ -196,7 +199,7 @@ def cli(version): ) @provider_options @click.pass_context -def checkout(ctx, background, nick, count, args_file, **kwargs): +def checkout(ctx, background, nick, count, args_file, labels, **kwargs): """Checkout or "create" a Virtual Machine broker instance. COMMAND: broker checkout --workflow "workflow-name" --workflow_arg1 something @@ -210,6 +213,8 @@ def checkout(ctx, background, nick, count, args_file, **kwargs): broker_args["_count"] = count if args_file: broker_args["args_file"] = args_file + if labels: + broker_args["labels"] = labels.split(",") # if additional arguments were passed, include them in the broker args # strip leading -- characters broker_args.update( diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index 2f051b3a..5f144074 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -436,6 +436,24 @@ def _pull_extra_vars(extra_vars): compiled[key] = val return compiled + def _resolve_labels(self, labels, target): + """Fetch and return ids of the given labels. + + If label does not exist, create it under the same org as the target template. + """ + label_ids = [] + for label in labels: + if result := self.v2.labels.get(name=label).results: + label_ids.append(result[0].id) + else: + # label does not exist yet, creating + result = self.v2.labels.post( + {"name": label, "organization": target.summary_fields.organization.id} + ) + if result: + label_ids.append(result.id) + return label_ids + @cached_property def inventory(self): """Return the current tower inventory.""" @@ -536,7 +554,7 @@ def _get_fields_from_facts(facts): return host_inst @Provider.register_action("workflow", "job_template") - def execute(self, **kwargs): # noqa: PLR0912 - Possible TODO refactor + def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor """Execute workflow or job template in Ansible Tower. :param kwargs: workflow or job template name passed in a string @@ -572,6 +590,9 @@ def execute(self, **kwargs): # noqa: PLR0912 - Possible TODO refactor if inventory := kwargs.pop("inventory", None): payload["inventory"] = inventory logger.info(f"Using tower inventory: {self._translate_inventory(inventory)}") + if labels := kwargs.pop("labels", None): + payload["labels"] = self._resolve_labels(labels, target) + kwargs["_labels"] = ",".join(labels) elif self.inventory: payload["inventory"] = self.inventory logger.info(f"Using tower inventory: {self._translate_inventory(self.inventory)}") From b2473a6c380b04c297e5f5677f910731ba3bf748 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Tue, 19 Mar 2024 12:25:41 +0100 Subject: [PATCH 02/11] provider/container - support labels, skip envars as labels --- broker/commands.py | 9 +++++++-- broker/providers/ansible_tower.py | 8 +++++++- broker/providers/container.py | 8 +++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/broker/commands.py b/broker/commands.py index ef9d7e9c..2bf0d12f 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -190,8 +190,13 @@ def cli(version): @click.option("-n", "--nick", type=str, help="Use a nickname defined in your settings") @click.option("-c", "--count", type=int, help="Number of times broker repeats the checkout") @click.option( - "--labels", type=str, help="List of strings (comma-separated) to be used as AAP labels" -) # fixme - this should be provider-agnostic + "-l", + "--labels", + type=str, + help="A string representing the list" + " of k=v pairs (comma-separated) to be used as provider resource" + " labels (e.g. '-l k1=v1,k2=v2,k3=v3=z4').", +) @click.option( "--args-file", type=click.Path(exists=True), diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index 5f144074..c07966b5 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -592,7 +592,13 @@ def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor logger.info(f"Using tower inventory: {self._translate_inventory(inventory)}") if labels := kwargs.pop("labels", None): payload["labels"] = self._resolve_labels(labels, target) - kwargs["_labels"] = ",".join(labels) + # record labels also as extra vars - use key=value format + kwargs.update( + { + f"_broker_label_{label[0]}": "=".join(label[1:]) + for label in [kv_pair.split("=") for kv_pair in labels] + } + ) elif self.inventory: payload["inventory"] = self.inventory logger.info(f"Using tower inventory: {self._translate_inventory(self.inventory)}") diff --git a/broker/providers/container.py b/broker/providers/container.py index 218c4358..8a07f478 100644 --- a/broker/providers/container.py +++ b/broker/providers/container.py @@ -274,7 +274,13 @@ def run_container(self, container_host, **kwargs): if origin[1]: envars["JENKINS_URL"] = origin[1] kwargs["environment"] = envars - kwargs["labels"] = envars + # process eventual labels that were passed externally, split by "=" + kwargs["labels"] = { + f"broker.{label[0]}": "=".join(label[1:]) + for label in [kv_pair.split("=") for kv_pair in kwargs.get("labels", {})] + } + # append origin as labels too + kwargs["labels"].update({"broker.origin": origin[0], "broker.jenkins.url": origin[1]}) container_inst = self.runtime.create_container(container_host, **kwargs) container_inst.start() return container_inst From a9b5ed72c359fa25d942c329de41bd3bd3a783a2 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Tue, 19 Mar 2024 18:56:34 +0100 Subject: [PATCH 03/11] label formatting logic moved to commands.py --- broker/commands.py | 6 +++++- broker/providers/container.py | 5 ----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/broker/commands.py b/broker/commands.py index 2bf0d12f..4f18a735 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -219,7 +219,11 @@ def checkout(ctx, background, nick, count, args_file, labels, **kwargs): if args_file: broker_args["args_file"] = args_file if labels: - broker_args["labels"] = labels.split(",") + broker_args["labels"] = { + f"broker.{label[0]}": "=".join(label[1:]) + for label in [kv_pair.split("=") for kv_pair in labels.split(",")] + } + # if additional arguments were passed, include them in the broker args # strip leading -- characters broker_args.update( diff --git a/broker/providers/container.py b/broker/providers/container.py index 8a07f478..a418f4fb 100644 --- a/broker/providers/container.py +++ b/broker/providers/container.py @@ -275,11 +275,6 @@ def run_container(self, container_host, **kwargs): envars["JENKINS_URL"] = origin[1] kwargs["environment"] = envars # process eventual labels that were passed externally, split by "=" - kwargs["labels"] = { - f"broker.{label[0]}": "=".join(label[1:]) - for label in [kv_pair.split("=") for kv_pair in kwargs.get("labels", {})] - } - # append origin as labels too kwargs["labels"].update({"broker.origin": origin[0], "broker.jenkins.url": origin[1]}) container_inst = self.runtime.create_container(container_host, **kwargs) container_inst.start() From d03d7fbb895ee83f9700135c78b61db8554ca31e Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Wed, 3 Apr 2024 12:00:46 +0200 Subject: [PATCH 04/11] labels arg renamed to provider-labels --- broker/commands.py | 12 ++++++------ broker/providers/ansible_tower.py | 2 +- broker/providers/container.py | 11 ++++++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/broker/commands.py b/broker/commands.py index 4f18a735..730220b2 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -191,7 +191,7 @@ def cli(version): @click.option("-c", "--count", type=int, help="Number of times broker repeats the checkout") @click.option( "-l", - "--labels", + "--provider-labels", type=str, help="A string representing the list" " of k=v pairs (comma-separated) to be used as provider resource" @@ -204,7 +204,7 @@ def cli(version): ) @provider_options @click.pass_context -def checkout(ctx, background, nick, count, args_file, labels, **kwargs): +def checkout(ctx, background, nick, count, args_file, provider_labels, **kwargs): """Checkout or "create" a Virtual Machine broker instance. COMMAND: broker checkout --workflow "workflow-name" --workflow_arg1 something @@ -218,10 +218,10 @@ def checkout(ctx, background, nick, count, args_file, labels, **kwargs): broker_args["_count"] = count if args_file: broker_args["args_file"] = args_file - if labels: - broker_args["labels"] = { - f"broker.{label[0]}": "=".join(label[1:]) - for label in [kv_pair.split("=") for kv_pair in labels.split(",")] + if provider_labels: + broker_args["provider_labels"] = { + label[0]: "=".join(label[1:]) + for label in [kv_pair.split("=") for kv_pair in provider_labels.split(",")] } # if additional arguments were passed, include them in the broker args diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index c07966b5..fa7d8209 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -590,7 +590,7 @@ def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor if inventory := kwargs.pop("inventory", None): payload["inventory"] = inventory logger.info(f"Using tower inventory: {self._translate_inventory(inventory)}") - if labels := kwargs.pop("labels", None): + if labels := kwargs.pop("provider_labels", None): payload["labels"] = self._resolve_labels(labels, target) # record labels also as extra vars - use key=value format kwargs.update( diff --git a/broker/providers/container.py b/broker/providers/container.py index a418f4fb..6071003b 100644 --- a/broker/providers/container.py +++ b/broker/providers/container.py @@ -274,8 +274,17 @@ def run_container(self, container_host, **kwargs): if origin[1]: envars["JENKINS_URL"] = origin[1] kwargs["environment"] = envars + # prefix eventual label keys with 'broker.' to conform to the docker guidelines + # https://docs.docker.com/config/labels-custom-metadata/#key-format-recommendations + kwargs["provider_labels"] = { + f"broker.{label[0]}": label[1] for label in kwargs["provider_labels"].items() + } # process eventual labels that were passed externally, split by "=" - kwargs["labels"].update({"broker.origin": origin[0], "broker.jenkins.url": origin[1]}) + kwargs["provider_labels"].update( + {"broker.origin": origin[0], "broker.jenkins.url": origin[1]} + ) + # rename the dict key to the name of the arg recognized by provider + kwargs["labels"] = kwargs.pop("provider_labels") container_inst = self.runtime.create_container(container_host, **kwargs) container_inst.start() return container_inst From 81b337f5622219aaa061eb007e67dd0f1b7046df Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Wed, 3 Apr 2024 12:21:53 +0200 Subject: [PATCH 05/11] labels - AT provider - fix label value parsing --- broker/providers/ansible_tower.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index fa7d8209..5b9627bf 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -443,12 +443,13 @@ def _resolve_labels(self, labels, target): """ label_ids = [] for label in labels: - if result := self.v2.labels.get(name=label).results: + label_expanded = f"{label}={labels[label]}" if labels[label] else label + if result := self.v2.labels.get(name=label_expanded).results: label_ids.append(result[0].id) else: # label does not exist yet, creating result = self.v2.labels.post( - {"name": label, "organization": target.summary_fields.organization.id} + {"name": label_expanded, "organization": target.summary_fields.organization.id} ) if result: label_ids.append(result.id) @@ -594,10 +595,7 @@ def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor payload["labels"] = self._resolve_labels(labels, target) # record labels also as extra vars - use key=value format kwargs.update( - { - f"_broker_label_{label[0]}": "=".join(label[1:]) - for label in [kv_pair.split("=") for kv_pair in labels] - } + {f"_broker_label_{label[0]}": "=".join(label[1:]) for label in labels.items()} ) elif self.inventory: payload["inventory"] = self.inventory From 47a6c15006dc4072389a551eefc0735e13602581 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Thu, 18 Apr 2024 13:50:09 +0200 Subject: [PATCH 06/11] add provider_label support to execute command --- broker/commands.py | 33 ++++++++++++++++++++++++++----- broker/providers/ansible_tower.py | 3 ++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/broker/commands.py b/broker/commands.py index 730220b2..d4c73cfd 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -36,6 +36,14 @@ def wrapper(*args, **kwargs): return decorator +def parse_labels(provider_labels): + """Parse the provided label string and returns labels in a dict.""" + return { + label[0]: "=".join(label[1:]) + for label in [kv_pair.split("=") for kv_pair in provider_labels.split(",")] + } + + class ExceptionHandler(click.Group): """Wraps click group to catch and handle raised exceptions.""" @@ -219,10 +227,7 @@ def checkout(ctx, background, nick, count, args_file, provider_labels, **kwargs) if args_file: broker_args["args_file"] = args_file if provider_labels: - broker_args["provider_labels"] = { - label[0]: "=".join(label[1:]) - for label in [kv_pair.split("=") for kv_pair in provider_labels.split(",")] - } + broker_args["provider_labels"] = parse_labels(provider_labels) # if additional arguments were passed, include them in the broker args # strip leading -- characters @@ -305,6 +310,14 @@ def inventory(details, sync, filter): @click.option("--all", "all_", is_flag=True, help="Select all VMs") @click.option("--sequential", is_flag=True, help="Run extends sequentially") @click.option("--filter", type=str, help="Extend only what matches the specified filter") +@click.option( + "-l", + "--provider-labels", + type=str, + help="A string representing the list" + " of k=v pairs (comma-separated) to be used as provider resource" + " labels (e.g. '-l k1=v1,k2=v2,k3=v3=z4').", +) @provider_options def extend(vm, background, all_, sequential, filter, **kwargs): """Extend a host's lease time. @@ -336,9 +349,17 @@ def extend(vm, background, all_, sequential, filter, **kwargs): type=click.Path(exists=True), help="A json or yaml file mapping arguments to values", ) +@click.option( + "-l", + "--provider-labels", + type=str, + help="A string representing the list" + " of k=v pairs (comma-separated) to be used as provider resource" + " labels (e.g. '-l k1=v1,k2=v2,k3=v3=z4').", +) @provider_options @click.pass_context -def execute(ctx, background, nick, output_format, artifacts, args_file, **kwargs): +def execute(ctx, background, nick, output_format, artifacts, args_file, provider_labels, **kwargs): """Execute an arbitrary provider action. COMMAND: broker execute --workflow "workflow-name" --workflow_arg1 something @@ -352,6 +373,8 @@ def execute(ctx, background, nick, output_format, artifacts, args_file, **kwargs broker_args["artifacts"] = artifacts if args_file: broker_args["args_file"] = args_file + if provider_labels: + broker_args["provider_labels"] = parse_labels(provider_labels) # if additional arguments were passed, include them in the broker args # strip leading -- characters broker_args.update( diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index 5b9627bf..0d986668 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -653,7 +653,7 @@ def get_inventory(self, user=None): compiled_host_info = [self._compile_host_info(host) for host in hosts_bar] return compiled_host_info - def extend(self, target_vm, new_expire_time=None): + def extend(self, target_vm, new_expire_time=None, provider_labels=None): """Run the extend workflow with defaults args. :param target_vm: This should be a host object @@ -668,6 +668,7 @@ def extend(self, target_vm, new_expire_time=None): workflow=settings.ANSIBLETOWER.extend_workflow, target_vm=target_vm.name, new_expire_time=new_expire_time or settings.ANSIBLETOWER.get("new_expire_time"), + provider_labels=provider_labels, ) def provider_help( From fd95b193994c603af1aa284253650ffd1888a247 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Fri, 19 Apr 2024 13:14:20 +0200 Subject: [PATCH 07/11] fix provider_labels parsing for container provider --- broker/providers/container.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/broker/providers/container.py b/broker/providers/container.py index 6071003b..753d4f92 100644 --- a/broker/providers/container.py +++ b/broker/providers/container.py @@ -277,7 +277,7 @@ def run_container(self, container_host, **kwargs): # prefix eventual label keys with 'broker.' to conform to the docker guidelines # https://docs.docker.com/config/labels-custom-metadata/#key-format-recommendations kwargs["provider_labels"] = { - f"broker.{label[0]}": label[1] for label in kwargs["provider_labels"].items() + f"broker.{label[0]}": label[1] for label in kwargs.get("provider_labels", {}).items() } # process eventual labels that were passed externally, split by "=" kwargs["provider_labels"].update( From f82276eb795e00b776192713dc016adaa2ef1fb0 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Fri, 19 Apr 2024 20:30:15 +0200 Subject: [PATCH 08/11] provider_labels are nested for AT provider --- broker/providers/ansible_tower.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index 0d986668..fefe7a1a 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -594,8 +594,9 @@ def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor if labels := kwargs.pop("provider_labels", None): payload["labels"] = self._resolve_labels(labels, target) # record labels also as extra vars - use key=value format - kwargs.update( - {f"_broker_label_{label[0]}": "=".join(label[1:]) for label in labels.items()} + kwargs["provider_labels"] = kwargs.get("provider_labels", {}) + kwargs["provider_labels"].update( + {label[0]: "=".join(label[1:]) for label in labels.items()} ) elif self.inventory: payload["inventory"] = self.inventory From 7f0081840faa39e6135e7a9c589d37bd514c8cf1 Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Fri, 19 Apr 2024 19:22:26 +0200 Subject: [PATCH 09/11] append label asserts to test_container_e2e --- tests/functional/test_containers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/functional/test_containers.py b/tests/functional/test_containers.py index 027d99e4..4373863d 100644 --- a/tests/functional/test_containers.py +++ b/tests/functional/test_containers.py @@ -67,7 +67,7 @@ def test_containerhost_query(): def test_container_e2e(): - with Broker(container_host="ubi8:latest") as c_host: + with Broker(container_host="ubi8:latest", provider_labels={"l1": "v1", "l2": None}) as c_host: assert c_host._cont_inst.top()["Processes"] res = c_host.execute("hostname") assert res.stdout.strip() == c_host.hostname @@ -87,6 +87,9 @@ def test_container_e2e(): SETTINGS_PATH.read_bytes() == data ), "Local file is different from the received one (return_data=True)" assert data == Path(tmp.file.name).read_bytes(), "Received files do not match" + # assert labels + assert c_host._cont_inst.labels.get("broker.l1") == "v1" + assert c_host._cont_inst.labels.get("broker.l2") == "" # test the tail_file context manager tailed_file = f"{remote_dir}/tail_me.txt" c_host.execute(f"echo 'hello world' > {tailed_file}") From 0f62165533e86c82a267008fab13e1ae4f5135ff Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Fri, 19 Apr 2024 23:49:28 +0200 Subject: [PATCH 10/11] Add parsing of eventual settings.provider_labels for AT, Container providers --- broker/providers/ansible_tower.py | 19 ++++++++++++------- broker/providers/container.py | 5 +++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/broker/providers/ansible_tower.py b/broker/providers/ansible_tower.py index fefe7a1a..65052579 100644 --- a/broker/providers/ansible_tower.py +++ b/broker/providers/ansible_tower.py @@ -591,19 +591,24 @@ def execute(self, **kwargs): # noqa: PLR0912,PLR0915 - Possible TODO refactor if inventory := kwargs.pop("inventory", None): payload["inventory"] = inventory logger.info(f"Using tower inventory: {self._translate_inventory(inventory)}") - if labels := kwargs.pop("provider_labels", None): - payload["labels"] = self._resolve_labels(labels, target) - # record labels also as extra vars - use key=value format - kwargs["provider_labels"] = kwargs.get("provider_labels", {}) - kwargs["provider_labels"].update( - {label[0]: "=".join(label[1:]) for label in labels.items()} - ) + elif self.inventory: payload["inventory"] = self.inventory logger.info(f"Using tower inventory: {self._translate_inventory(self.inventory)}") else: logger.info("No inventory specified, Ansible Tower will use a default.") + # provider labels handling + + provider_labels = kwargs.get("provider_labels", {}) + # include eventual common labels, specified at each level of configuration + # typically imported from dynaconf env vars + provider_labels.update(settings.get("provider_labels", {})) + provider_labels.update(settings.ANSIBLETOWER.get("provider_labels", {})) + if provider_labels: + payload["labels"] = self._resolve_labels(provider_labels, target) + kwargs["provider_labels"] = provider_labels + # Save custom, non-workflow extra vars to a named variable. # The workflow can save these values to job artifacts / host facts. workflow_extra_vars = self._pull_extra_vars(target.extra_vars) diff --git a/broker/providers/container.py b/broker/providers/container.py index 753d4f92..ac61c994 100644 --- a/broker/providers/container.py +++ b/broker/providers/container.py @@ -274,6 +274,11 @@ def run_container(self, container_host, **kwargs): if origin[1]: envars["JENKINS_URL"] = origin[1] kwargs["environment"] = envars + + # process eventual provider labels for each setting level + kwargs["provider_labels"] = kwargs.get("provider_labels", {}) + kwargs["provider_labels"].update(settings.get("provider_labels", {})) + kwargs["provider_labels"].update(settings.CONTAINER.get("provider_labels", {})) # prefix eventual label keys with 'broker.' to conform to the docker guidelines # https://docs.docker.com/config/labels-custom-metadata/#key-format-recommendations kwargs["provider_labels"] = { From 6cbd7d6771e8ea4a78ef9a39994146fd10d7acbe Mon Sep 17 00:00:00 2001 From: Roman Plevka Date: Tue, 23 Apr 2024 15:29:37 +0200 Subject: [PATCH 11/11] add e2e provider_labels fn test for AA --- tests/functional/test_satlab.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/functional/test_satlab.py b/tests/functional/test_satlab.py index a2997915..e108a274 100644 --- a/tests/functional/test_satlab.py +++ b/tests/functional/test_satlab.py @@ -124,3 +124,17 @@ def test_tower_host_mp(): ) res = r_hosts[1].execute(f"ls /root") assert SETTINGS_PATH.name in res.stdout + + +def test_tower_provider_labels(): + """Assert labels being created on AAP and OSP metadata + being attached accordingly + """ + with Broker(workflow="deploy-rhel", provider_labels={"l1": "v1", "l2": ""}) as r_host: + # check provider labels in the resulting host object + assert r_host.provider_labels.get("l1") == "v1" + assert r_host.provider_labels.get("l2") == "" + # assert the AAP labels got created on the provider + aap_labels = [l.name for l in r_host._prov_inst.v2.labels.get().results] + assert "l1=v1" in aap_labels + assert "l2" in aap_labels