Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add user endpoint for managing user groups permissions #409

Merged
merged 21 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions plugins/lookup/lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ def get_endpoint(nautobot, term):
"""

endpoint_map = {
"admin-users": {"endpoint": nautobot.users.users},
"admin-groups": {"endpoint": nautobot.users.groups},
"admin-permissions": {"endpoint": nautobot.users.permissions},
"aggregates": {"endpoint": nautobot.ipam.aggregates},
"circuit-terminations": {"endpoint": nautobot.circuits.circuit_terminations},
"circuit-types": {"endpoint": nautobot.circuits.circuit_types},
Expand Down
64 changes: 64 additions & 0 deletions plugins/module_utils/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Jeff Kala (@jeffkala)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import (
NautobotModule,
ENDPOINT_NAME_MAPPING,
)


NB_USERS = "users"
NB_ADMIN_GROUP = "groups"
NB_OBJECT_PERMISSION = "permissions"


class NautobotUsersModule(NautobotModule):
def run(self):
"""
This function should have all necessary code for endpoints within the application
to create/update/delete the endpoint objects
Supported endpoints:
- users
- groups
- permissions
"""
# Used to dynamically set key when returning results
endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint]

self.result = {"changed": False}

application = self._find_app(self.endpoint)
nb_app = getattr(self.nb, application)
nb_endpoint = getattr(nb_app, self.endpoint)
user_query_params = self.module.params.get("query_params")

data = self.data

# Used for msg output
if data.get("username"):
name = data["username"]
elif data.get("name"):
name = data["name"]
else:
name = data.get("id")

object_query_params = self._build_query_params(endpoint_name, data, user_query_params)
self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name)

if self.state == "present":
self._ensure_object_exists(nb_endpoint, endpoint_name, name, data)
elif self.state == "absent":
self._ensure_object_absent(endpoint_name, name)

try:
serialized_object = self.nb_object.serialize()
except AttributeError:
serialized_object = self.nb_object

self.result.update({endpoint_name: serialized_object})

self.module.exit_json(**self.result)
15 changes: 14 additions & 1 deletion plugins/module_utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
plugins=[],
secrets=[],
tenancy=["tenants", "tenant_groups"],
users=["users", "groups", "permissions"],
virtualization=["cluster_groups", "cluster_types", "clusters", "virtual_machines"],
)

Expand All @@ -109,6 +110,7 @@
device_type="model",
export_targets="name",
group="name",
groups="name",
installed_device="name",
import_targets="name",
location="name",
Expand Down Expand Up @@ -139,6 +141,7 @@
tenant="name",
tenant_group="name",
time_zone="timezone",
user="username",
virtual_chassis="name",
virtual_machine="name",
vlan="name",
Expand Down Expand Up @@ -168,6 +171,7 @@
"device_type": "device_types",
"export_targets": "route_targets",
"group": "tenant_groups",
"groups": "groups",
"import_targets": "route_targets",
"installed_device": "devices",
"interface": "interfaces",
Expand Down Expand Up @@ -211,6 +215,7 @@
"termination_a": "interfaces",
"termination_b": "interfaces",
"untagged_vlan": "vlans",
"users": "users",
"virtual_chassis": "virtual_chassis",
"virtual_machine": "virtual_machines",
"vlan": "vlans",
Expand Down Expand Up @@ -242,6 +247,7 @@
"device_redundancy_groups": "device_redundancy_group",
"front_ports": "front_port",
"front_port_templates": "front_port_template",
"groups": "group",
"interfaces": "interface",
"interface_templates": "interface_template",
"inventory_items": "inventory_item",
Expand All @@ -251,6 +257,7 @@
"location_types": "location_type",
"manufacturers": "manufacturer",
"namespaces": "namespace",
"permissions": "permission",
"platforms": "platform",
"power_feeds": "power_feed",
"power_outlets": "power_outlet",
Expand All @@ -274,6 +281,7 @@
"teams": "team",
"tenants": "tenant",
"tenant_groups": "tenant_group",
"users": "user",
"virtual_chassis": "virtual_chassis",
"virtual_machines": "virtual_machine",
"vlans": "vlan",
Expand Down Expand Up @@ -315,6 +323,8 @@
"device_type": set(["model"]),
"front_port": set(["name", "device", "rear_port"]),
"front_port_template": set(["name", "device_type", "rear_port_template"]),
"group": set(["name"]),
"groups": set(["name"]),
"installed_device": set(["name"]),
"interface": set(["name", "device", "virtual_machine"]),
"interface_template": set(["name", "device_type"]),
Expand All @@ -332,6 +342,7 @@
"nat_inside": set(["namespace", "address"]),
"parent_rack_group": set(["name"]),
"parent_tenant_group": set(["name"]),
"permission": set(["name"]),
"platform": set(["name"]),
"power_feed": set(["name", "power_panel"]),
"power_outlet": set(["name", "device"]),
Expand Down Expand Up @@ -361,6 +372,7 @@
"tenant_group": set(["name"]),
"termination_a": set(["name", "device", "virtual_machine"]),
"termination_b": set(["name", "device", "virtual_machine"]),
"user": set(["username"]),
"untagged_vlan": set(["group", "name", "location", "vid", "vlan_group", "tenant"]),
"virtual_chassis": set(["name", "device"]),
"virtual_machine": set(["name", "cluster"]),
Expand Down Expand Up @@ -685,7 +697,8 @@ def _get_query_param_id(self, match, data):
result = self._nb_endpoint_get(nb_endpoint, query_params, match)

if result:
return result.id
# Inherited django models(admin groups) that are not overloaded are integers, force the integer to string.
return str(result.id)
else:
return data

Expand Down
92 changes: 92 additions & 0 deletions plugins/modules/admin_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Jeff Kala (@jeffkala)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type


DOCUMENTATION = r"""
---
module: admin_group
short_description: Create, update or delete admin groups within Nautobot
description:
- Creates, updates or removes admin groups from Nautobot
notes:
- This should be ran with connection C(local) and hosts C(localhost)
author:
- Jeff Kala (@jeffkala)
version_added: "5.3.0"
extends_documentation_fragment:
- networktocode.nautobot.fragments.base
options:
name:
description:
- The name of the group
required: true
type: str
"""

EXAMPLES = r"""
- name: "Test Nautobot modules"
connection: local
hosts: localhost
gather_facts: False

tasks:
- name: Create admin group within Nautobot
networktocode.nautobot.admin_group:
url: http://nautobot.local
token: thisIsMyToken
name: read_only_group
state: present

- name: Delete admin group
networktocode.nautobot.user:
url: http://nautobot.local
token: thisIsMyToken
name: read_only_group
state: absent
"""

RETURN = r"""
admin_group:
description: Serialized object as created or already existent within Nautobot
returned: success (when I(state=present))
type: dict
msg:
description: Message indicating failure or info about what has been achieved
returned: always
type: str
"""

from ansible_collections.networktocode.nautobot.plugins.module_utils.utils import NAUTOBOT_ARG_SPEC
from ansible_collections.networktocode.nautobot.plugins.module_utils.users import (
NautobotUsersModule,
NB_ADMIN_GROUP,
)
from ansible.module_utils.basic import AnsibleModule
from copy import deepcopy


def main():
"""
Main entry point for module execution
"""
argument_spec = deepcopy(NAUTOBOT_ARG_SPEC)
argument_spec.update(
dict(
name=dict(required=True, type="str"),
)
)

module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

nb_groups = NautobotUsersModule(module, NB_ADMIN_GROUP)
nb_groups.run()


if __name__ == "__main__": # pragma: no cover
main()
Loading