diff --git a/mindinsight/backend/application.py b/mindinsight/backend/application.py index dc16c5dcb088eca099b34c3b4a16a7dda3d57659..cdeeca7197d45566f19eeaac12237895cb938276 100644 --- a/mindinsight/backend/application.py +++ b/mindinsight/backend/application.py @@ -107,7 +107,7 @@ def before_request(): def create_app(): """Set flask APP config, and start the data manager.""" - static_url_path = "/static" + static_url_path = settings.URL_PATH_PREFIX + "/static" static_folder_path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.pardir, 'ui', 'dist', 'static')) app = Flask(__name__, static_url_path=static_url_path, static_folder=static_folder_path) diff --git a/mindinsight/backend/datavisual/static_resource_api.py b/mindinsight/backend/datavisual/static_resource_api.py index a8d3574ab128dcaf591a68a053c084df134e8a76..38cc62e4696f702fcd5be7c4fec4f8dc1400dd9b 100644 --- a/mindinsight/backend/datavisual/static_resource_api.py +++ b/mindinsight/backend/datavisual/static_resource_api.py @@ -20,20 +20,18 @@ from flask import current_app from flask import send_from_directory from flask import Blueprint +from mindinsight.conf import settings -APP_PATH = os.path.realpath(os.path.dirname(sys.argv[0])) -BLUEPRINT = Blueprint("static_resource", __name__) + +BLUEPRINT = Blueprint("static_resource", __name__, url_prefix=settings.URL_PATH_PREFIX) @BLUEPRINT.route("/", methods=["GET"]) def index(): """Interface to return static index.html.""" - return send_from_directory(get_index_resource_dir(), "index.html") - - -def get_index_resource_dir(): - """Interface to return index.html resource directory.""" - return os.path.realpath(os.path.join(APP_PATH, current_app.static_folder, os.pardir)) + app_path = os.path.realpath(os.path.dirname(sys.argv[0])) + index_resource_dir = os.path.realpath(os.path.join(app_path, current_app.static_folder, os.pardir)) + return send_from_directory(index_resource_dir, "index.html") def init_module(app): diff --git a/mindinsight/backend/datavisual/task_manager_api.py b/mindinsight/backend/datavisual/task_manager_api.py index 024b7907edf162fcc53b42619955abd89c4b75ad..c07f231e2ccecdaaaa355e79b43fb3e9db5b4179 100644 --- a/mindinsight/backend/datavisual/task_manager_api.py +++ b/mindinsight/backend/datavisual/task_manager_api.py @@ -34,7 +34,7 @@ from mindinsight.datavisual.processors.train_task_manager import TrainTaskManage from mindinsight.datavisual.data_transform.data_manager import DATA_MANAGER -BLUEPRINT = Blueprint("task_manager", __name__, url_prefix=settings.URL_PREFIX) +BLUEPRINT = Blueprint("task_manager", __name__, url_prefix=settings.URL_PATH_PREFIX+settings.API_PREFIX) @BLUEPRINT.route("/datavisual/single-job", methods=["GET"]) diff --git a/mindinsight/backend/datavisual/train_visual_api.py b/mindinsight/backend/datavisual/train_visual_api.py index 91871ae3a90282dbe01db9d110a0fc838de1f24d..a868a443c817c402a689b20195737d12c7706bd9 100644 --- a/mindinsight/backend/datavisual/train_visual_api.py +++ b/mindinsight/backend/datavisual/train_visual_api.py @@ -31,7 +31,7 @@ from mindinsight.datavisual.processors.graph_processor import GraphProcessor from mindinsight.datavisual.data_transform.data_manager import DATA_MANAGER -BLUEPRINT = Blueprint("train_visual", __name__, url_prefix=settings.URL_PREFIX) +BLUEPRINT = Blueprint("train_visual", __name__, url_prefix=settings.URL_PATH_PREFIX+settings.API_PREFIX) @BLUEPRINT.route("/datavisual/image/metadata", methods=["GET"]) diff --git a/mindinsight/backend/lineagemgr/lineage_api.py b/mindinsight/backend/lineagemgr/lineage_api.py index 7b4846adad20208b188b6c1b8e32ccfd56dc9f8f..8d8547d03c7ae8db916a4fbf8b91b65c1b8ad6af 100644 --- a/mindinsight/backend/lineagemgr/lineage_api.py +++ b/mindinsight/backend/lineagemgr/lineage_api.py @@ -25,7 +25,7 @@ from mindinsight.lineagemgr.api.model import general_filter_summary_lineage, gen from mindinsight.utils.exceptions import MindInsightException, ParamValueError from mindinsight.lineagemgr.cache_item_updater import update_lineage_object -BLUEPRINT = Blueprint("lineage", __name__, url_prefix=settings.URL_PREFIX.rstrip("/")) +BLUEPRINT = Blueprint("lineage", __name__, url_prefix=settings.URL_PATH_PREFIX+settings.API_PREFIX) @BLUEPRINT.route("/lineagemgr/lineages", methods=["POST"]) diff --git a/mindinsight/backend/profiler/profile_api.py b/mindinsight/backend/profiler/profile_api.py index 40bbbd59073c53b6beec8716bc3d8837b8b6be5b..887cf4f2c8f6f1db95329fc05e0b4a4eef786e5f 100644 --- a/mindinsight/backend/profiler/profile_api.py +++ b/mindinsight/backend/profiler/profile_api.py @@ -41,7 +41,7 @@ from mindinsight.profiler.common.validator.validate_path import validate_and_nor from mindinsight.profiler.proposer.compose_proposer import ComposeProposal from mindinsight.utils.exceptions import ParamValueError -BLUEPRINT = Blueprint("profile", __name__, url_prefix=settings.URL_PREFIX) +BLUEPRINT = Blueprint("profile", __name__, url_prefix=settings.URL_PATH_PREFIX+settings.API_PREFIX) @BLUEPRINT.route("/profile/ops/search", methods=["POST"]) diff --git a/mindinsight/backend/run.py b/mindinsight/backend/run.py index 627aa5d3443f90b28e8f21c562952497210f0971..23831b72f51bdbde5cebd5438f5b6e4fe3b5995c 100644 --- a/mindinsight/backend/run.py +++ b/mindinsight/backend/run.py @@ -252,7 +252,7 @@ def start(): else: state_result = _check_server_start_stat(errorlog_abspath, log_size) # print gunicorn start state to stdout - console.info('Web address: http://%s:%s', settings.HOST, settings.PORT) + console.info('Web address: http://%s:%s%s', settings.HOST, settings.PORT, settings.URL_PATH_PREFIX) for line in state_result["prompt_message"]: console.info(line) diff --git a/mindinsight/conf/constants.py b/mindinsight/conf/constants.py index 66e09a39c62643b0b9a760e099fdc2b3aefe3202..5677b73f217021925f5c6e1740771f3e7a8967f1 100644 --- a/mindinsight/conf/constants.py +++ b/mindinsight/conf/constants.py @@ -41,8 +41,8 @@ ENABLE_CORS = False SUPPORT_REQUEST_METHODS = {'POST', 'GET', 'PUT', 'DELETE'} -# url prefix should not end with slash, correct format is /v1/url -URL_PREFIX = '/v1/mindinsight' +# api prefix should not end with slash, correct format is /v1/url +API_PREFIX = '/v1/mindinsight' #################################### # Datavisual default settings. diff --git a/mindinsight/conf/defaults.py b/mindinsight/conf/defaults.py index ec3054bdd227fd490b9028928673091b09764f71..b554869ebc42ddc9136213a6a9359b946469ee31 100644 --- a/mindinsight/conf/defaults.py +++ b/mindinsight/conf/defaults.py @@ -24,6 +24,7 @@ WORKSPACE = os.path.join(os.environ['HOME'], 'mindinsight') # Web default settings. #################################### PORT = 8080 +URL_PATH_PREFIX = '' #################################### # Datavisual default settings. diff --git a/mindinsight/scripts/start.py b/mindinsight/scripts/start.py index e959d5bd0ac11c70877b330f19ba295b1ba8139c..77a847c67e0e51153dc22c23a51173a8eae8a621 100644 --- a/mindinsight/scripts/start.py +++ b/mindinsight/scripts/start.py @@ -16,6 +16,7 @@ import os import sys +import re import argparse from importlib import import_module @@ -118,6 +119,28 @@ class PortAction(argparse.Action): setattr(namespace, self.dest, port) +class UrlPathPrefixAction(argparse.Action): + """Url Path prefix action class definition.""" + + REGEX = r'^(\/[a-zA-Z0-9-\-\.]+)+$' + + def __call__(self, parser, namespace, values, option_string=None): + """ + Inherited __call__ method from argparse.Action. + + Args: + parser (ArgumentParser): Passed-in argument parser. + namespace (Namespace): Namespace object to hold arguments. + values (object): Argument values with type depending on argument definition. + option_string (str): Optional string for specific argument name. Default: None. + """ + prefix = values + if not re.match(self.REGEX, prefix): + parser.error(f'{option_string} value is invalid url path prefix') + + setattr(namespace, self.dest, prefix) + + class Command(BaseCommand): """ Start mindinsight service. @@ -158,6 +181,14 @@ class Command(BaseCommand): Custom port ranging from %s to %s. Default value is %s. """ % (PortAction.MIN_PORT, PortAction.MAX_PORT, settings.PORT)) + parser.add_argument( + '--url-path-prefix', + type=str, + action=UrlPathPrefixAction, + help=""" + Custom path prefix for web page address. Default value is ''. + """) + for hook in HookUtils.instance().hooks(): hook.register_startup_arguments(parser) diff --git a/mindinsight/ui/src/services/fetcher.js b/mindinsight/ui/src/services/fetcher.js index e5569cf6e11648d02e7b3fe4e9736de5a7083c6a..69bdc1ca389b117e9b7b47a5a370971b2478b112 100644 --- a/mindinsight/ui/src/services/fetcher.js +++ b/mindinsight/ui/src/services/fetcher.js @@ -20,7 +20,7 @@ import axios from 'axios'; import Vue from 'vue'; export {default} from 'axios'; -export const basePath = location.origin; +export const basePath = location.origin + location.pathname; axios.defaults.timeout = 30000; axios.defaults.baseURL = basePath; diff --git a/tests/ut/backend/datavisual/conftest.py b/tests/ut/backend/datavisual/conftest.py index a75c248d5879eebe95e80ab4aa20d1c0870fddcf..974f8c22da0ec6403ecfafe71658d165ef89208d 100644 --- a/tests/ut/backend/datavisual/conftest.py +++ b/tests/ut/backend/datavisual/conftest.py @@ -21,7 +21,7 @@ import pytest from flask import Response from mindinsight.backend import datavisual -from mindinsight.datavisual import utils +from mindinsight.datavisual.utils import tools @pytest.fixture @@ -31,12 +31,10 @@ def client(): mock_data_manager.start_load_data = Mock() datavisual.DATA_MANAGER = mock_data_manager - packages = ["mindinsight.backend.raw_dataset", - "mindinsight.backend.train_dataset", - "mindinsight.backend.data_visual"] + packages = ["mindinsight.backend.data_visual"] mock_obj = Mock(return_value=packages) - utils.find_app_package = mock_obj + tools.find_app_package = mock_obj from mindinsight.backend.application import APP APP.response_class = Response