diff options
| author | omnom62 <omnom62@outlook.com> | 2026-03-02 21:20:30 +1000 |
|---|---|---|
| committer | omnom62 <omnom62@outlook.com> | 2026-03-02 21:20:30 +1000 |
| commit | 7952a8645124ef160c2759a2dae9e9cb32eac1a9 (patch) | |
| tree | a01436ff4f4af14d7386715e9e7c613f05d5ac2c /plugins/module_utils | |
| download | rest.vyos-7952a8645124ef160c2759a2dae9e9cb32eac1a9.tar.gz rest.vyos-7952a8645124ef160c2759a2dae9e9cb32eac1a9.zip | |
first commit
Diffstat (limited to 'plugins/module_utils')
| -rw-r--r-- | plugins/module_utils/utils.py | 40 | ||||
| -rw-r--r-- | plugins/module_utils/vyos.py | 177 |
2 files changed, 217 insertions, 0 deletions
diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py new file mode 100644 index 0000000..f256247 --- /dev/null +++ b/plugins/module_utils/utils.py @@ -0,0 +1,40 @@ +def normalize_to_list(value): + """ + Normalize VyOS REST return values to list. + + Handles: + dict -> keys + list -> same + str -> [value] + None -> [] + """ + if isinstance(value, dict): + return list(value.keys()) + + if isinstance(value, list): + return value + + if isinstance(value, str): + return [value] + + return [] + + +def normalize_to_dict(value): + """ + Normalize VyOS REST return values to dict. + + list -> {item: {}} + str -> {value: {}} + dict -> same + """ + if isinstance(value, dict): + return value + + if isinstance(value, list): + return {v: {} for v in value} + + if isinstance(value, str): + return {value: {}} + + return {}
\ No newline at end of file diff --git a/plugins/module_utils/vyos.py b/plugins/module_utils/vyos.py new file mode 100644 index 0000000..aa17a9f --- /dev/null +++ b/plugins/module_utils/vyos.py @@ -0,0 +1,177 @@ +from ansible.module_utils.connection import Connection +import json + + +class VyOSModule: + + def __init__(self, module): + + self.module = module + + if not module._socket_path: + module.fail_json(msg="Connection must be httpapi") + + self.connection = Connection(module._socket_path) + + self.existing = {} + self.commands = [] + + # + # LOW LEVEL transport + # + def _send(self, path, op=None, path_list=None, commands=None): + + payload = {} + + if op: + payload["op"] = op + + if path_list: + payload["path"] = path_list + + if commands: + payload["commands"] = commands + + response = self.connection.send_request( + path=path, + method="POST", + data=payload + ) + + if not response: + self.module.fail_json(msg="Empty response from device") + + if not response.get("success"): + self.module.fail_json(msg="VyOS error", response=response) + + return response.get("data", {}) + + # + # Fetch config + # + def get_config(self, path_list): + + self.existing = self._send( + path="/retrieve", + op="showConfig", + path_list=path_list + ) + + return self.existing + + # + # Add command + # + def add_command(self, cmd): + + self.commands.append(cmd) + + # + # Diff + # + def get_diff(self): + + diff = [] + + existing_servers = [] + + # + # Extract existing servers safely + # + if isinstance(self.existing, dict): + server_block = self.existing.get("server", {}) + if isinstance(server_block, dict): + existing_servers = list(server_block.keys()) + + # + # Compare commands vs existing state + # + for cmd in self.commands: + + op = cmd.get("op") + path = cmd.get("path", []) + + if not path: + continue + + server = path[-1] + + if op == "set": + if server not in existing_servers: + diff.append(cmd) + + elif op == "delete": + if server in existing_servers: + diff.append(cmd) + + return diff + # + # Apply config + # + def apply_config(self, diff): + + if not diff: + self.module.exit_json( + changed=False, + msg="Already configured" + ) + + response = self._send( + path="/configure", + commands=diff + ) + + self.module.exit_json( + changed=True, + commands=diff, + response=response + ) + + # + # Apply commands + # + def apply_commands(self, commands): + + if not commands: + self.module.exit_json( + changed=False, + commands=[], + msg="Already configured" + ) + + # convert tuples to dicts for API + payload_commands = [] + for cmd in commands: + if isinstance(cmd, tuple): + op, path = cmd + payload_commands.append({"op": op, "path": path}) + elif isinstance(cmd, dict): + payload_commands.append(cmd) + else: + self.module.fail_json(msg=f"Invalid command type: {cmd}") + + response = self._send( + path="/configure", + commands=payload_commands + ) + + self.module.exit_json( + changed=True, + commands=commands, + response=response + ) + # + # Delete config + # + def delete_config(self, cmds): + + response = self._send( + path="/configure", + commands=cmds + ) + + self.module.exit_json( + changed=True, + commands=cmds, + response=response + )
\ No newline at end of file |
