Commit 433346ff authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Common - Tools - Rest Conf

- Packed code into RestConfServerApp class
- Separated Config settings to Config.py
parent ff5a7ad6
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import os, secrets


RESTCONF_PREFIX  = os.environ.get('RESTCONF_PREFIX',  '/restconf'     )
YANG_SEARCH_PATH = os.environ.get('YANG_SEARCH_PATH', './yang'        )
STARTUP_FILE     = os.environ.get('STARTUP_FILE',     './startup.json')
SECRET_KEY       = os.environ.get('SECRET_KEY',       secrets.token_hex(64))
+95 −0
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import json, logging, time
from flask import Flask, request
from flask_restful import Api
from .Config import RESTCONF_PREFIX, SECRET_KEY, STARTUP_FILE, YANG_SEARCH_PATH
from .Dispatch import RestConfDispatch
from .HostMeta import HostMeta
from .YangHandler import YangHandler
from .YangModelDiscoverer import YangModuleDiscoverer


logging.basicConfig(
    level=logging.INFO,
    format='[Worker-%(process)d][%(asctime)s] %(levelname)s:%(name)s:%(message)s',
)


LOGGER = logging.getLogger(__name__)


def log_request(response):
    timestamp = time.strftime('[%Y-%b-%d %H:%M]')
    LOGGER.info(
        '%s %s %s %s %s', timestamp, request.remote_addr, request.method,
        request.full_path, response.status
    )
    return response


class RestConfServerApplication:
    def __init__(self) -> None:
        self._ymd = YangModuleDiscoverer(YANG_SEARCH_PATH)
        self._yang_module_names = self._ymd.run(do_log_order=True)

        with open(STARTUP_FILE, mode='r', encoding='UTF-8') as fp:
            self._yang_startup_data = json.loads(fp.read())

        self._yang_handler = YangHandler(
            YANG_SEARCH_PATH, self._yang_module_names, self._yang_startup_data
        )

        self._app = Flask(__name__)
        self._app.config['SECRET_KEY'] = SECRET_KEY
        self._app.after_request(log_request)
        self._api = Api(self._app, prefix=RESTCONF_PREFIX)

    def get_startup_data(self) -> None:
        return self._yang_startup_data

    def register_host_meta(self) -> None:
        self._api.add_resource(
            HostMeta,
            '/.well-known/host-meta',
            resource_class_args=(RESTCONF_PREFIX,)
        )

    def register_restconf(self) -> None:
        self._api.add_resource(
            RestConfDispatch,
            '/data',
            '/data/',
            '/data/<path:subpath>',
            '/data/<path:subpath>/',
            resource_class_args=(self._yang_handler,)
        )

    def register_endpoints(self) -> None:
        self.register_host_meta()
        self.register_restconf()

    def get_flask_app(self) -> Flask:
        return self._app

    def get_flask_api(self) -> Api:
        return self._api

    def dump_configuration(self) -> None:
        LOGGER.info('Available RESTCONF paths:')
        restconf_paths = self._yang_handler.get_schema_paths()
        for restconf_path in sorted(restconf_paths):
            LOGGER.info('- {:s}'.format(str(restconf_path)))
+8 −64
Original line number Diff line number Diff line
@@ -13,19 +13,8 @@
# limitations under the License.


import json, logging, os, secrets, time
from flask import Flask, request
from flask_restful import Api
from .Dispatch import RestConfDispatch
from .HostMeta import HostMeta
from .YangHandler import YangHandler
from .YangModelDiscoverer import YangModuleDiscoverer


RESTCONF_PREFIX  = os.environ.get('RESTCONF_PREFIX',  '/restconf'     )
YANG_SEARCH_PATH = os.environ.get('YANG_SEARCH_PATH', './yang'        )
STARTUP_FILE     = os.environ.get('STARTUP_FILE',     './startup.json')
SECRET_KEY       = os.environ.get('SECRET_KEY',       secrets.token_hex(64))
import logging
from .RestConfServerApplication import RestConfServerApplication


logging.basicConfig(
@@ -34,56 +23,11 @@ logging.basicConfig(
)
LOGGER = logging.getLogger(__name__)

LOGGER.info('Starting...')
rcs_app = RestConfServerApplication()
LOGGER.info('All connectors registered')

def log_request(response):
    timestamp = time.strftime('[%Y-%b-%d %H:%M]')
    LOGGER.info(
        '%s %s %s %s %s', timestamp, request.remote_addr, request.method,
        request.full_path, response.status
    )
    return response


ymd = YangModuleDiscoverer(YANG_SEARCH_PATH)
YANG_MODULE_NAMES = ymd.run(do_log_order=True)

with open(STARTUP_FILE, mode='r', encoding='UTF-8') as fp:
    YANG_STARTUP_DATA = json.loads(fp.read())



ymd = YangModuleDiscoverer(YANG_SEARCH_PATH)
YANG_MODULE_NAMES = ymd.run(do_log_order=True)


with open(STARTUP_FILE, mode='r', encoding='UTF-8') as fp:
    YANG_STARTUP_DATA = json.loads(fp.read())


yang_handler = YangHandler(
    YANG_SEARCH_PATH, YANG_MODULE_NAMES, YANG_STARTUP_DATA
)
restconf_paths = yang_handler.get_schema_paths()

app = Flask(__name__)
app.config['SECRET_KEY'] = SECRET_KEY
app.after_request(log_request)

api = Api(app)
api.add_resource(
    HostMeta,
    '/.well-known/host-meta',
    resource_class_args=(RESTCONF_PREFIX,)
)
api.add_resource(
    RestConfDispatch,
    RESTCONF_PREFIX + '/data',
    RESTCONF_PREFIX + '/data/',
    RESTCONF_PREFIX + '/data/<path:subpath>',
    RESTCONF_PREFIX + '/data/<path:subpath>/',
    resource_class_args=(yang_handler,)
)
rcs_app.dump_configuration()
app = rcs_app.get_flask_app()

LOGGER.info('Available RESTCONF paths:')
for restconf_path in sorted(restconf_paths):
    LOGGER.info('- {:s}'.format(str(restconf_path)))
LOGGER.info('Initialization completed!')