From fe3be7e3e90b033cedc4ef23b529f8acbd20370e Mon Sep 17 00:00:00 2001 From: Johan Marcusson Date: Wed, 20 Sep 2023 09:54:26 +0200 Subject: [PATCH] Use field masks from flask_restx marshal to do "partial object fetching" using X-Fields header instead of custom query params, hopefully a bit more standard and more flexible Example use curl -H "X-Fields: available_variables{interfaces},hostname" to only retreive hostname and variables regarding interfaces --- src/cnaas_nms/api/device.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cnaas_nms/api/device.py b/src/cnaas_nms/api/device.py index d3a0df8a..7de7d721 100644 --- a/src/cnaas_nms/api/device.py +++ b/src/cnaas_nms/api/device.py @@ -3,7 +3,7 @@ from typing import List, Optional from flask import make_response, request -from flask_restx import Namespace, Resource, fields +from flask_restx import Namespace, Resource, fields, marshal from pydantic import ValidationError from sqlalchemy import func from sqlalchemy.exc import IntegrityError @@ -171,6 +171,15 @@ }, ) +device_generate_config_model = device_api.model( + "generate_config", + { + "hostname": fields.String, + "generated_config": fields.String, + "available_variables": fields.Raw, + }, +) + stackmember_model = device_api.model( "stackmember", { @@ -844,14 +853,11 @@ def post(self): return resp -class DeviceConfigApi(Resource): +class DeviceGenerateConfigApi(Resource): @jwt_required - @device_api.param("variables_only", "Only return available variables") - @device_api.param("interface_variables_only", "Only return available interface variables") - @device_api.param("config_only", "Only return full generated config") + @device_api.doc(model=device_generate_config_model) def get(self, hostname: str): """Get device configuration""" - args = request.args result = empty_result() result["data"] = {"config": None} if not Device.valid_hostname(hostname): @@ -860,19 +866,13 @@ def get(self, hostname: str): try: config, template_vars = cnaas_nms.devicehandler.sync_devices.generate_only(hostname) template_vars["host"] = hostname - result["data"]["config"] = { + data = { "hostname": hostname, "generated_config": config, "available_variables": template_vars, } - if "variables_only" in args and args["variables_only"]: - del result["data"]["config"]["generated_config"] - elif "interface_variables_only" in args and args["interface_variables_only"]: - del result["data"]["config"]["generated_config"] - interface_variables = result["data"]["config"]["available_variables"]["interfaces"] - result["data"]["config"]["available_variables"] = {"interfaces": interface_variables} - elif "config_only" in args and args["config_only"]: - del result["data"]["config"]["available_variables"] + + result["data"]["config"] = marshal(data, device_generate_config_model, mask=request.headers.get("X-Fields")) except Exception as e: logger.exception(f"Exception while generating config for device {hostname}") @@ -1207,7 +1207,7 @@ def post(self): # Devices device_api.add_resource(DeviceByIdApi, "/") device_api.add_resource(DeviceByHostnameApi, "/") -device_api.add_resource(DeviceConfigApi, "//generate_config") +device_api.add_resource(DeviceGenerateConfigApi, "//generate_config") device_api.add_resource(DeviceRunningConfigApi, "//running_config") device_api.add_resource(DevicePreviousConfigApi, "//previous_config") device_api.add_resource(DeviceApplyConfigApi, "//apply_config")