#!/usr/bin/env python3 from bundlewrap.repo import Repository from os.path import realpath, dirname import json import os import subprocess from dataclasses import dataclass from typing import Optional, List bw = Repository(dirname(dirname(realpath(__file__)))) VAULT=bw.vault.decrypt('encrypt$gAAAAABpLgX_xxb5NmNCl3cgHM0JL65GT6PHVXO5gwly7IkmWoEgkCDSuAcSAkNFB8Tb4RdnTdpzVQEUL1XppTKVto_O7_b11GjATiyQYiSfiQ8KZkTKLvk=').value BW_TAG = "bw" BUNDLEWRAP_FIELD_LABEL = "bundlewrap node id" @dataclass class OpResult: stdout: str stderr: str returncode: int def main(): for node in bw.nodes_in_group('routeros'): upsert_node_item( node_name=node.name, node_uuid=node.metadata.get('id'), username=node.username, password=node.password, url=f'http://{node.hostname}', ) def run_op(args): proc = subprocess.run( ["op", "--vault", VAULT] + args, env=os.environ.copy(), capture_output=True, text=True, ) if proc.returncode != 0: raise RuntimeError( f"op {' '.join(args)} failed with code {proc.returncode}:\n" f"STDOUT:\n{proc.stdout}\n\nSTDERR:\n{proc.stderr}" ) return OpResult(stdout=proc.stdout, stderr=proc.stderr, returncode=proc.returncode) def op_item_list_bw(): out = run_op([ "item", "list", "--tags", BW_TAG, "--format", "json", ]) stdout = out.stdout.strip() return json.loads(stdout) if stdout else [] def op_item_get(item_id): args = ["item", "get", item_id, "--format", "json"] return json.loads(run_op(args).stdout) def op_item_create(title, node_uuid, username, password, url): print(f"creating {title}") return json.loads(run_op([ "item", "create", "--category", "LOGIN", "--title", title, "--tags", BW_TAG, "--url", url, "--format", "json", f"username={username}", f"password={password}", f"{BUNDLEWRAP_FIELD_LABEL}[text]={node_uuid}", ]).stdout) def op_item_edit(item_id, title, username, password, url): print(f"updating {title}") return json.loads(run_op([ "item", "edit", item_id, "--title", title, "--url", url, "--format", "json", f"username={username}", f"password={password}", ]).stdout) def find_node_item_id(node_uuid): for summary in op_item_list_bw(): item_id = summary.get("id") if not item_id: continue item = op_item_get(item_id) for field in item.get("fields") or []: label = field.get("label") value = field.get("value") if label == BUNDLEWRAP_FIELD_LABEL and value == node_uuid: return item_id return None def upsert_node_item(node_name, node_uuid, username, password, url): if item_id := find_node_item_id(node_uuid): return op_item_edit( item_id=item_id, title=node_name, username=username, password=password, url=url, ) else: return op_item_create( title=node_name, node_uuid=node_uuid, username=username, password=password, url=url, ) if __name__ == "__main__": main()