diff --git a/docs/user/app_feature_config_postprocessing.md b/docs/user/app_feature_config_postprocessing.md index 4ed33d08..6e041712 100644 --- a/docs/user/app_feature_config_postprocessing.md +++ b/docs/user/app_feature_config_postprocessing.md @@ -38,18 +38,18 @@ There are two different ways to customize the default behavior of `get_config_po The `render_secrets` function performs an extra Jinja rendering on top of an intended configuration, exposing new custom Jinja filters: -- `get_secret_by_secret_group_slug`: as the name suggests, it returns the secret_group value, for a secret type, from its `slug`. +- `get_secret_by_secret_group_name`: as the name suggests, it returns the secret_group value, for a secret type, from its `name`. !!! note Other default Django or Netutils filters are not available in this Jinja environment. Only `encrypt__type5` and `encrypt__type7` can be used together with the `get_secret` filters. Because this rendering is separated from the standard generation of the intended configuration, you must use the `{% raw %}` Jinja syntax to avoid being processed by the initial generation stage. -1. For example, an original template like this, `{% raw %}ppp pap sent-username {{ secrets_group["slug"] | get_secret_by_secret_group_slug("username")}}{% endraw %}` -2. Produces an intended configuration as `ppp pap sent-username {{ secrets_group["slug"] | get_secret_by_secret_group_slug("username") }}` +1. For example, an original template like this, `{% raw %}ppp pap sent-username {{ secrets_group["name"] | get_secret_by_secret_group_name("username")}}{% endraw %}` +2. Produces an intended configuration as `ppp pap sent-username {{ secrets_group["name"] | get_secret_by_secret_group_name("username") }}` 3. After the `render_secrets`, it becomes `ppp pap sent-username my_username`. -Notice that the `get_secret` filters take arguments. In the example, the `Secret_group` slug is passed, together with the type of the `Secret`. Check every signature for extra customization. +Notice that the `get_secret` filters take arguments. In the example, the `secret_group` name is passed, together with the type of the `Secret`. Check every signature for extra customization. !!! note Remember that to render these secrets, the user requesting it via UI or API, MUST have read permissions to Secrets Groups, Golden Config, and the specific Device object. @@ -64,7 +64,7 @@ This shows how Render the Secrets feature for a `Device`, for the default `Secre query ($device_id: ID!) { device(id: $device_id) { secrets_group { - slug + name } location { rel_my_secret_relationship_for_location { @@ -80,13 +80,13 @@ query ($device_id: ID!) { Using the default `secrets_group` FK in `Device`: ```jinja2 -{% raw %}{{ secrets_group["slug"] | get_secret_by_secret_group_slug("password") | default('no password') }}{% endraw %} +{% raw %}{{ secrets_group["name"] | get_secret_by_secret_group_name("password") | default('no password') }}{% endraw %} ``` Using the custom relationship at the `Location` level: ```jinja2 -{% raw %}{{ location["rel_my_secret_relationship_for_location"][0]["slug"] | get_secret_by_secret_group_slug("password") | default('no password') }}{% endraw %} +{% raw %}{{ location["rel_my_secret_relationship_for_location"][0]["name"] | get_secret_by_secret_group_name("password") | default('no password') }}{% endraw %} ``` This will end up rendering the secret, of type "password", for the corresponding `SecretGroup`. @@ -96,5 +96,5 @@ This will end up rendering the secret, of type "password", for the corresponding Obviously, the rendering process can find multiple challenges, that are managed, and properly explained to take corrective actions: ``` -Found an error rendering the configuration to push: Jinja encountered and UndefinedError: 'None' has no attribute 'slug', check the template for missing variable definitions. +Found an error rendering the configuration to push: Jinja encountered and UndefinedError: 'None' has no attribute 'name', check the template for missing variable definitions. ``` diff --git a/docs/user/app_feature_sotagg.md b/docs/user/app_feature_sotagg.md index d381dba5..8cb29722 100644 --- a/docs/user/app_feature_sotagg.md +++ b/docs/user/app_feature_sotagg.md @@ -92,17 +92,16 @@ query ($device_id: ID!) { } tags { name - slug } - device_role { + role { name } platform { name - network_driver manufacturer { name } + network_driver napalm_driver } location { diff --git a/docs/user/app_getting_started.md b/docs/user/app_getting_started.md index ef194657..c3d7ee19 100644 --- a/docs/user/app_getting_started.md +++ b/docs/user/app_getting_started.md @@ -153,7 +153,7 @@ The files within these folders can follow any naming pattern or nested folder st │ │ └── juniper_junos.yml ``` -The `YAML` files will contain all the attributes necessary to identify an object (for instance, a `ComplianceRule` is identified by the `feature_slug` and the `platform_slug` together) and the other attributes (the ones that are not used to identify the object). For example: +The `YAML` files will contain all the attributes necessary to identify an object (for instance, a `ComplianceRule` is identified by the `feature_slug` and the `platform_name` together) and the other attributes (the ones that are not used to identify the object). For example: `compliance_features` example: @@ -169,7 +169,7 @@ The `YAML` files will contain all the attributes necessary to identify an object ```yaml --- - feature_slug: "aaa" - platform_slug: "cisco_ios" + platform_name: "Cisco IOS" config_ordered: true match_config: | aaa @@ -184,7 +184,7 @@ The `YAML` files will contain all the attributes necessary to identify an object ```yaml --- -- platform_slug: "cisco_ios" +- platform_name: "Cisco IOS" name: "Build config" regex: '^Building\s+configuration.*\n' ``` @@ -194,7 +194,7 @@ The `YAML` files will contain all the attributes necessary to identify an object ```yaml --- - name: "username" - platform_slug: "cisco_ios" + platform_name: "Cisco IOS" description: "username" regex: '(username\s+\S+\spassword\s+5\s+)\S+(\s+role\s+\S+)' replace: '\1\2' @@ -213,7 +213,7 @@ CustomField data can be added using the `_custom_field_data` attribute, that tak ``` !!! note - For Foreign Key references to `ComplianceFeature` and `Platform` we use the keywords `feature_slug` and `platform_slug` respectively. + For Foreign Key references to `ComplianceFeature` and `Platform` we use the keywords `feature_slug` and `platform_name` respectively. 1. Add the Git repository that will be used to sync Git properties. diff --git a/docs/user/app_use_cases.md b/docs/user/app_use_cases.md index 2ef2d3d9..ca9789f3 100644 --- a/docs/user/app_use_cases.md +++ b/docs/user/app_use_cases.md @@ -56,7 +56,7 @@ To update existing settings click on one of the `Settings` name. |Intended Repositories |The Git Repository where your intended configuration state files will be found. | |Intended Path|A Jinja template which defines the path and name of intended configuration state files within the intended state repository. e.g. `{{obj.location.name}}/{{obj.name}}.intended_cfg`| |Jinja Repository |The Git Repository where your jinja templates will be found. | -|Jinja Path|A Jinja template which defines the path (within the repository) and name of the Jinja template file. e.g. `{{obj.platform.slug}}/{{obj.device_role.slug}}/main.j2`| +|Jinja Path|A Jinja template which defines the path (within the repository) and name of the Jinja template file. e.g. `{{obj.platform.name}}/{{obj.role.name}}/main.j2`| |Dynamic Group|The scope of devices on which Golden Config's jobs can operate. | |GraphQL Query|A query that is evaluated and used to render the config. The query must start with `query ($device_id: ID!)`.| @@ -78,31 +78,28 @@ Within the Detail view of a Golden Config Setting the section to denote the scop The below configurations of scope can either be removed or specified for pre 1.2 only, the same logic applies in 1.2 and onwards but via DynamicGroups. -Filtering to specific platforms, based on their slug. +Filtering to specific platforms, based on their name. ```json { "platform": [ - "cisco_ios", - "cisco_nxos", - "arista_eos", - "juniper_junos" + "Cisco IOS", + "Cisco NXOS", + "Arista EOS", + "Juniper Junos" ] } ``` -!!! note - The Platform slug is an important value, see the [FAQ](./app_faq.md) for further details. - Adding a "has_primary_ip" check. ```json { "platform": [ - "cisco_ios", - "cisco_nxos", - "arista_eos", - "juniper_junos" + "Cisco IOS", + "Cisco NXOS", + "Arista EOS", + "Juniper Junos" ], "has_primary_ip": "True" } diff --git a/nautobot_golden_config/datasources.py b/nautobot_golden_config/datasources.py index 16f805aa..93f91bcf 100644 --- a/nautobot_golden_config/datasources.py +++ b/nautobot_golden_config/datasources.py @@ -70,7 +70,7 @@ def refresh_git_gc_properties(repository_record, job_result, delete=False): # p "class": ComplianceRule, "id_keys": ( ("feature", "feature_slug"), - ("platform", "platform_slug"), + ("platform", "platform_name"), ), }, { @@ -78,7 +78,7 @@ def refresh_git_gc_properties(repository_record, job_result, delete=False): # p "class": ConfigRemove, "id_keys": ( ("name", "name"), - ("platform", "platform_slug"), + ("platform", "platform_name"), ), }, { @@ -86,7 +86,7 @@ def refresh_git_gc_properties(repository_record, job_result, delete=False): # p "class": ConfigReplace, "id_keys": ( ("name", "name"), - ("platform", "platform_slug"), + ("platform", "platform_name"), ), }, ) @@ -102,8 +102,8 @@ def refresh_git_gc_properties(repository_record, job_result, delete=False): # p def get_id_kwargs(gc_config_item_dict, id_keys, job_result): """Method to get the proper id kwargs and remove them from gc_config_item_dict.""" - # fk_slug_class_mapping contains a mapping of the FK attributes to the related model - fk_slug_class_mapping = {"feature": ComplianceFeature, "platform": Platform} + # fk_class_mapping contains a mapping of the FK attributes to the related model + fk_class_mapping = {"feature": ComplianceFeature, "platform": Platform} id_kwargs = {} for id_key in id_keys: @@ -111,12 +111,12 @@ def get_id_kwargs(gc_config_item_dict, id_keys, job_result): yaml_attr_name = id_key[1] # If the attribute is actually a FK reference, we need to resolve the related object - if actual_attr_name in fk_slug_class_mapping: + if actual_attr_name in fk_class_mapping: + _, field_name = yaml_attr_name.split("_") + kwargs = {field_name: gc_config_item_dict[yaml_attr_name]} try: - id_kwargs[actual_attr_name] = fk_slug_class_mapping[actual_attr_name].objects.get( - slug=gc_config_item_dict[yaml_attr_name] - ) - except fk_slug_class_mapping[actual_attr_name].DoesNotExist: + id_kwargs[actual_attr_name] = fk_class_mapping[actual_attr_name].objects.get(**kwargs) + except fk_class_mapping[actual_attr_name].DoesNotExist: job_result.log( ( f"Reference to {yaml_attr_name}: {gc_config_item_dict[yaml_attr_name]}", @@ -124,7 +124,7 @@ def get_id_kwargs(gc_config_item_dict, id_keys, job_result): ), level_choice=LogLevelChoices.LOG_WARNING, ) - raise MissingReference from fk_slug_class_mapping[actual_attr_name].DoesNotExist + raise MissingReference from fk_class_mapping[actual_attr_name].DoesNotExist else: id_kwargs[actual_attr_name] = gc_config_item_dict[yaml_attr_name] diff --git a/nautobot_golden_config/forms.py b/nautobot_golden_config/forms.py index 5a2d4eb5..f2ac6933 100644 --- a/nautobot_golden_config/forms.py +++ b/nautobot_golden_config/forms.py @@ -156,7 +156,7 @@ class ComplianceRuleFilterForm(NautobotFilterForm): q = forms.CharField(required=False, label="Search") platform = core_forms.DynamicModelMultipleChoiceField( - queryset=Platform.objects.all(), to_field_name="slug", required=False, null_option="None" + queryset=Platform.objects.all(), to_field_name="name", required=False, null_option="None" ) feature = core_forms.DynamicModelMultipleChoiceField( @@ -281,7 +281,7 @@ class ConfigReplaceFilterForm(NautobotFilterForm): model = models.ConfigReplace platform = core_forms.DynamicModelMultipleChoiceField( - queryset=Platform.objects.all(), to_field_name="slug", required=False, null_option="None" + queryset=Platform.objects.all(), to_field_name="name", required=False, null_option="None" ) name = core_forms.DynamicModelChoiceField( queryset=models.ConfigReplace.objects.all(), to_field_name="name", required=False diff --git a/nautobot_golden_config/tests/test_datasources.py b/nautobot_golden_config/tests/test_datasources.py index d8c98f09..1caeeefd 100644 --- a/nautobot_golden_config/tests/test_datasources.py +++ b/nautobot_golden_config/tests/test_datasources.py @@ -8,7 +8,6 @@ from nautobot_golden_config.datasources import get_id_kwargs, MissingReference -@unittest.skip("TODO: Fix datasources.get_id_kwargs to not use slugs") class GitPropertiesDatasourceTestCase(TestCase): """Test Git GC Properties datasource.""" @@ -54,20 +53,20 @@ def test_get_id_kwargs_3(self): def test_get_id_kwargs_4(self): """Test simple get_id_kwargs .""" - gc_config_item_dict = {"platform_slug": "invalid_platform"} + gc_config_item_dict = {"platform_name": "invalid_platform"} with self.assertRaises(MissingReference): get_id_kwargs( gc_config_item_dict, - (("platform", "platform_slug"),), + (("platform", "platform_name"),), self.job_result, ) def test_get_id_kwargs_5(self): """Test simple get_id_kwargs 5.""" - gc_config_item_dict = {"platform_slug": "example_platform"} + gc_config_item_dict = {"platform_name": "example_platform"} id_kwargs = get_id_kwargs( gc_config_item_dict, - (("platform", "platform_slug"),), + (("platform", "platform_name"),), self.job_result, ) self.assertEqual(id_kwargs, {"platform": self.platform}) diff --git a/nautobot_golden_config/tests/test_helpers.py b/nautobot_golden_config/tests/test_helpers.py index 4d3e2cbc..917299f7 100644 --- a/nautobot_golden_config/tests/test_helpers.py +++ b/nautobot_golden_config/tests/test_helpers.py @@ -1,6 +1,6 @@ """Unit tests for nautobot_golden_config helpers.""" import os -from unittest import mock, skip +from unittest import mock import jinja2 from django.contrib.auth import get_user_model @@ -12,7 +12,7 @@ from nautobot.users.models import ObjectPermission from nautobot_golden_config.utilities.config_postprocessing import ( - get_secret_by_secret_group_slug, + get_secret_by_secret_group_name, render_secrets, get_config_postprocessing, ) @@ -26,7 +26,6 @@ User = get_user_model() -@skip("TODO: Remove slugs and no-member") class GetSecretFilterTestCase(TestCase): """Test Get Secrets filters.""" @@ -35,18 +34,17 @@ def setUp(self): self.device = create_device() self.configs = GoldenConfig.objects.create(device=self.device) - self.secrets_group = SecretsGroup(name="Secrets Group 1", slug="secrets-group-1") + self.secrets_group = SecretsGroup(name="Secrets Group 1") self.secrets_group.validated_save() self.environment_secret = Secret.objects.create( name="Environment Variable Secret", - slug="env-var", provider="environment-variable", parameters={"variable": "NAUTOBOT_TEST_ENVIRONMENT_VARIABLE"}, ) SecretsGroupAssociation.objects.create( - group=self.secrets_group, + secrets_group=self.secrets_group, secret=self.environment_secret, access_type=SecretsGroupAccessTypeChoices.TYPE_GENERIC, secret_type=SecretsGroupSecretTypeChoices.TYPE_SECRET, @@ -68,39 +66,39 @@ def setUp(self): self.permission.validated_save() @mock.patch.dict(os.environ, {"NAUTOBOT_TEST_ENVIRONMENT_VARIABLE": "supersecretvalue"}) - def test_get_secret_by_secret_group_slug_superuser(self): + def test_get_secret_by_secret_group_name_superuser(self): """A super user admin should get the secret rendered.""" self.assertEqual( - get_secret_by_secret_group_slug( + get_secret_by_secret_group_name( self.user_admin, - self.secrets_group.slug, # pylint: disable=no-member + self.secrets_group.name, SecretsGroupSecretTypeChoices.TYPE_SECRET, ), "supersecretvalue", ) @mock.patch.dict(os.environ, {"NAUTOBOT_TEST_ENVIRONMENT_VARIABLE": "supersecretvalue"}) - def test_get_secret_by_secret_group_slug_user_without_permission(self): + def test_get_secret_by_secret_group_name_user_without_permission(self): """A normal user without permissions, should not get the secret rendered.""" self.assertEqual( - get_secret_by_secret_group_slug( + get_secret_by_secret_group_name( self.user_2, - self.secrets_group.slug, # pylint: disable=no-member + self.secrets_group.name, SecretsGroupSecretTypeChoices.TYPE_SECRET, ), - f"You have no permission to read this secret {self.secrets_group.slug}.", # pylint: disable=no-member + f"You have no permission to read this secret {self.secrets_group.name}.", ) @mock.patch.dict(os.environ, {"NAUTOBOT_TEST_ENVIRONMENT_VARIABLE": "supersecretvalue"}) - def test_get_secret_by_secret_group_slug_user_with_permission(self): + def test_get_secret_by_secret_group_name_user_with_permission(self): """A normal user with permissions, should get the secret rendered.""" self.permission.users.set([self.user_2]) self.permission.validated_save() self.assertEqual( - get_secret_by_secret_group_slug( + get_secret_by_secret_group_name( self.user_2, - self.secrets_group.slug, # pylint: disable=no-member + self.secrets_group.name, SecretsGroupSecretTypeChoices.TYPE_SECRET, ), "supersecretvalue", @@ -109,13 +107,13 @@ def test_get_secret_by_secret_group_slug_user_with_permission(self): @mock.patch.dict(os.environ, {"NAUTOBOT_TEST_ENVIRONMENT_VARIABLE": "supersecretvalue"}) @mock.patch( "nautobot_golden_config.utilities.config_postprocessing._get_device_agg_data", - mock.MagicMock(return_value={"group_slug": "secrets-group-1"}), + mock.MagicMock(return_value={"group_name": "Secrets Group 1"}), ) def test_get_secret_end_to_end(self): """This test will take an initial Jinja template and do the double rendering to demonstrate the end to end experience. """ - initial_template = "{% raw %}{{ group_slug | get_secret_by_secret_group_slug('secret') }}{% endraw %}" + initial_template = "{% raw %}{{ group_name | get_secret_by_secret_group_name('secret') }}{% endraw %}" # This simulates the first rendering to generate the Intended configuration jinja_env = jinja2.Environment(autoescape=True) @@ -123,7 +121,7 @@ def test_get_secret_end_to_end(self): intended_config = template.render({}) self.assertEqual( intended_config, - "{{ group_slug | get_secret_by_secret_group_slug('secret') }}", + "{{ group_name | get_secret_by_secret_group_name('secret') }}", ) mock_request = mock.Mock() diff --git a/nautobot_golden_config/tests/test_utilities/test_helpers.py b/nautobot_golden_config/tests/test_utilities/test_helpers.py index 4a17a80f..5f58e8a4 100644 --- a/nautobot_golden_config/tests/test_utilities/test_helpers.py +++ b/nautobot_golden_config/tests/test_utilities/test_helpers.py @@ -200,7 +200,6 @@ def test_get_job_filter_no_data_success(self): result = get_job_filter() self.assertEqual(result.count(), 2) - @unittest.skip("TODO: Fix get_job_filter using slugs") def test_get_job_filter_site_success(self): """Verify we get a single device returned when providing specific site.""" result = get_job_filter(data={"location": Location.objects.filter(name="Site 4")}) @@ -216,13 +215,13 @@ def test_get_job_filter_device_filter_success(self): result = get_job_filter(data={"device": Device.objects.filter(name="test_device")}) self.assertEqual(result.count(), 1) - @unittest.skip("TODO: Fix get_job_filter using slugs") + @unittest.skip("TODO: Fix tag to tags change") def test_get_job_filter_tag_success(self): """Verify we get a single device returned when providing tag filter that matches on device.""" result = get_job_filter(data={"tag": Tag.objects.filter(name="Orphaned")}) self.assertEqual(result.count(), 1) - @unittest.skip("TODO: Fix get_job_filter using slugs") + @unittest.skip("TODO: Fix tag to tags change") def test_get_job_filter_tag_success_and_logic(self): """Verify we get a single device returned when providing multiple tag filter that matches on device.""" device = Device.objects.get(name="orphan_device") @@ -238,13 +237,11 @@ def test_get_job_filter_tag_success_and_logic(self): self.assertEqual(device_2.tags.count(), 1) self.assertEqual(result.count(), 1) - @unittest.skip("TODO: Fix get_job_filter using slugs") def test_get_job_filter_status_success(self): """Verify we get a single device returned when providing status filter that matches on device.""" result = get_job_filter(data={"status": Status.objects.filter(name="Offline")}) self.assertEqual(result.count(), 1) - @unittest.skip("TODO: Fix get_job_filter using slugs") def test_get_job_filter_multiple_status_success(self): """Verify we get a0 devices returned matching multiple status'.""" result = get_job_filter(data={"status": Status.objects.filter(name__in=["Offline", "Failed"])}) @@ -268,13 +265,12 @@ def test_get_job_filter_base_queryset_raise(self): "The base queryset didn't find any devices. Please check the Golden Config Setting scope.", ) - @unittest.skip("TODO: Fix get_job_filter using slugs") def test_get_job_filter_filtered_devices_raise(self): """Verify we get raise for having providing site that doesn't have any devices in scope.""" location_type = LocationType.objects.create(name="New Location Type Site") Location.objects.create(name="New Site", status=Status.objects.get(name="Active"), location_type=location_type) with self.assertRaises(NornirNautobotException) as failure: - get_job_filter(data={"site": Location.objects.filter(name="New Site")}) + get_job_filter(data={"location": Location.objects.filter(name="New Site")}) self.assertEqual( failure.exception.args[0], "The provided job parameters didn't match any devices detected by the Golden Config scope. Please check the scope defined within Golden Config Settings or select the correct job parameters to correctly match devices.", diff --git a/nautobot_golden_config/utilities/config_postprocessing.py b/nautobot_golden_config/utilities/config_postprocessing.py index fb1ae091..9df3ccbb 100644 --- a/nautobot_golden_config/utilities/config_postprocessing.py +++ b/nautobot_golden_config/utilities/config_postprocessing.py @@ -19,18 +19,18 @@ from nautobot_golden_config.utilities.helper import get_device_to_settings_map -def get_secret_by_secret_group_slug( +def get_secret_by_secret_group_name( user: User, - secrets_group_slug: str, + secrets_group_name: str, secret_type: str, secret_access_type: Optional[str] = SecretsGroupAccessTypeChoices.TYPE_GENERIC, **kwargs, ) -> Optional[str]: - """Gets the secret from a Secret Group slug. To be used as a Jinja filter. + """Gets the secret from a Secret Group name. To be used as a Jinja filter. Args: user (User): User object that performs API call to render push template with secrets. - secrets_group_slug (str): Secrets Group slug. It needs to be part of the GraphQL query. + secrets_group_name (str): Secrets Group name. It needs to be part of the GraphQL query. secret_type (str): Type of secret, such as "username", "password", "token", "secret", or "key". secret_access_type (Optional[str], optional): Type of secret such as "Generic", "gNMI", "HTTP(S)". Defaults to "Generic". @@ -38,12 +38,12 @@ def get_secret_by_secret_group_slug( Optional[str] : Secret value. None if there is no match. An error string if there is an error. """ try: - secrets_group = SecretsGroup.objects.get(slug=secrets_group_slug) + secrets_group = SecretsGroup.objects.get(name=secrets_group_name) except ObjectDoesNotExist: - return f"{secrets_group_slug} doesn't exist." + return f"{secrets_group_name} doesn't exist." if not user.has_perm("extras.view_secretsgroup", secrets_group): - return f"You have no permission to read this secret {secrets_group_slug}." + return f"You have no permission to read this secret {secrets_group_name}." return secrets_group.get_secret_value( access_type=secret_access_type, @@ -69,7 +69,7 @@ def render_secrets(config_postprocessing: str, configs: models.GoldenConfig, req .. rubric:: Example Jinja render_secrets filters usage .. highlight:: jinja .. code-block:: jinja - ppp pap sent-username {{ secrets_group["slug"] | get_secret_by_secret_group_slug("password") | encrypt_type7 }} + ppp pap sent-username {{ secrets_group["name"] | get_secret_by_secret_group_name("password") | encrypt_type7 }} Returns: str : Return a string, with the rendered intended configuration with secrets, or an error message. @@ -85,7 +85,7 @@ def render_secrets(config_postprocessing: str, configs: models.GoldenConfig, req # This can only be done safely since the Jinja2 environment does not persist beyond this function. # If the code is changed to use the Nautobot Jinja2 environment, then the request's user must be passed # in via the template code. - jinja_env.filters["get_secret_by_secret_group_slug"] = partial(get_secret_by_secret_group_slug, request.user) + jinja_env.filters["get_secret_by_secret_group_name"] = partial(get_secret_by_secret_group_name, request.user) netutils_filters = jinja2_convenience_function() for template_name in [ diff --git a/nautobot_golden_config/utilities/helper.py b/nautobot_golden_config/utilities/helper.py index 0f2b3d1f..bd20f56d 100644 --- a/nautobot_golden_config/utilities/helper.py +++ b/nautobot_golden_config/utilities/helper.py @@ -23,11 +23,11 @@ "device_type", } -FIELDS_SLUG = {"tag", "status"} # TODO: Change slug where appropriate +FIELDS_NAME = {"tag", "status"} # TODO: Change tag to tags def get_job_filter(data=None): - """Helper function to return a the filterable list of OS's based on platform.slug and a specific custom value.""" + """Helper function to return a the filterable list of OS's based on platform.name and a specific custom value.""" if not data: data = {} query = {} @@ -35,12 +35,12 @@ def get_job_filter(data=None): # Translate instances from FIELDS set to list of primary keys for field in FIELDS_PK: if data.get(field): - query[f"{field}_id"] = data[field].values_list("pk", flat=True) + query[field] = data[field].values_list("pk", flat=True) - # Translate instances from FIELDS set to list of slugs - for field in FIELDS_SLUG: + # Translate instances from FIELDS set to list of names + for field in FIELDS_NAME: if data.get(field): - query[f"{field}"] = data[field].values_list("slug", flat=True) + query[field] = data[field].values_list("name", flat=True) # Handle case where object is from single device run all. if data.get("device") and isinstance(data["device"], Device):