diff options
-rwxr-xr-x | src/services/vyos-http-api-server | 79 |
1 files changed, 56 insertions, 23 deletions
diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server index 206d3176d..31430170a 100755 --- a/src/services/vyos-http-api-server +++ b/src/services/vyos-http-api-server @@ -1,6 +1,6 @@ #!/usr/share/vyos-http-api-tools/bin/python3 # -# Copyright (C) 2019-2021 VyOS maintainers and contributors +# Copyright (C) 2019-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -125,6 +125,15 @@ class ConfigureListModel(ApiModel): } } +class BaseConfigSectionModel(BasePathModel): + section: Dict + +class ConfigSectionModel(ApiModel, BaseConfigSectionModel): + pass + +class ConfigSectionListModel(ApiModel): + commands: List[BaseConfigSectionModel] + class RetrieveModel(ApiModel): op: StrictStr path: List[StrictStr] @@ -350,6 +359,13 @@ class MultipartRequest(Request): if 'value' in c and not isinstance(c['value'], str): self.form_err = (400, f"Malformed command '{c}': 'value' field must be a string") + if endpoint in ('/configure-section'): + if 'section' not in c: + self.form_err = (400, + f"Malformed command '{c}': missing 'section' field") + elif not isinstance(c['section'], dict): + self.form_err = (400, + f"Malformed command '{c}': 'section' field must be JSON of dict") if 'key' not in forms and 'key' not in merge: self.form_err = (401, "Valid API key is required") @@ -394,7 +410,8 @@ app.router.route_class = MultipartRoute async def validation_exception_handler(request, exc): return error(400, str(exc.errors()[0])) -def _configure_op(data: Union[ConfigureModel, ConfigureListModel], +def _configure_op(data: Union[ConfigureModel, ConfigureListModel, + ConfigSectionModel, ConfigSectionListModel], request: Request): session = app.state.vyos_session env = session.get_session_env() @@ -421,27 +438,37 @@ def _configure_op(data: Union[ConfigureModel, ConfigureListModel], op = c.op path = c.path - if c.value: - value = c.value - else: - value = "" - - # For vyos.configsession calls that have no separate value arguments, - # and for type checking too - cfg_path = " ".join(path + [value]).strip() - - if op == 'set': - # XXX: it would be nice to do a strict check for "path already exists", - # but there's probably no way to do that - session.set(path, value=value) - elif op == 'delete': - if app.state.vyos_strict and not config.exists(cfg_path): - raise ConfigSessionError(f"Cannot delete [{cfg_path}]: path/value does not exist") - session.delete(path, value=value) - elif op == 'comment': - session.comment(path, value=value) - else: - raise ConfigSessionError(f"'{op}' is not a valid operation") + if isinstance(c, BaseConfigureModel): + if c.value: + value = c.value + else: + value = "" + # For vyos.configsession calls that have no separate value arguments, + # and for type checking too + cfg_path = " ".join(path + [value]).strip() + + elif isinstance(c, BaseConfigSectionModel): + section = c.section + + if isinstance(c, BaseConfigureModel): + if op == 'set': + session.set(path, value=value) + elif op == 'delete': + if app.state.vyos_strict and not config.exists(cfg_path): + raise ConfigSessionError(f"Cannot delete [{cfg_path}]: path/value does not exist") + session.delete(path, value=value) + elif op == 'comment': + session.comment(path, value=value) + else: + raise ConfigSessionError(f"'{op}' is not a valid operation") + + elif isinstance(c, BaseConfigSectionModel): + if op == 'set': + session.set_section(path, section) + elif op == 'load': + session.load_section(path, section) + else: + raise ConfigSessionError(f"'{op}' is not a valid operation") # end for session.commit() logger.info(f"Configuration modified via HTTP API using key '{app.state.vyos_id}'") @@ -472,6 +499,12 @@ async def configure_op(data: Union[ConfigureModel, request: Request): return _configure_op(data, request) +@app.post('/configure-section') +async def configure_section_op(data: Union[ConfigSectionModel, + ConfigSectionListModel], + request: Request): + return _configure_op(data, request) + @app.post("/retrieve") async def retrieve_op(data: RetrieveModel): session = app.state.vyos_session |