|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- # Copyright 2019 Huawei Technologies Co., Ltd
- #
- # 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.
- # ============================================================================
- """Start mindinsight service."""
-
- import argparse
- import os
- import re
- import sys
- import socket
- from importlib import import_module
-
- import psutil
-
- from mindinsight.conf import settings
- from mindinsight.utils.command import BaseCommand
- from mindinsight.utils.exceptions import PortNotAvailableError
- from mindinsight.utils.hook import HookUtils
- from mindinsight.utils.hook import init
-
-
- class ConfigAction(argparse.Action):
- """Config action class definition."""
-
- 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.
- """
- config = values
- if not config:
- setattr(namespace, self.dest, config)
-
- # python:full.path.for.config.module
- if config.startswith('python:'):
- config = config[len('python:'):]
- try:
- import_module(config)
- except ModuleNotFoundError:
- parser.error(f'{option_string} {config} not exists')
-
- config = f'python:{config}'
- else:
- # file:/full/path/for/config/module.py
- if config.startswith('file:'):
- config = config[len('file:'):]
-
- if config.startswith('~'):
- config = os.path.realpath(os.path.expanduser(config))
-
- if not config.startswith('/'):
- config = os.path.realpath(os.path.join(os.getcwd(), config))
-
- if not os.path.exists(config):
- parser.error(f'{option_string} {config} not exists')
-
- if not os.access(config, os.R_OK):
- parser.error(f'{option_string} {config} not accessible')
-
- config = f'file:{config}'
-
- setattr(namespace, self.dest, config)
-
-
- class WorkspaceAction(argparse.Action):
- """Workspace action class definition."""
-
- 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.
- """
- workspace = os.path.realpath(values)
- setattr(namespace, self.dest, workspace)
-
-
- class PortAction(argparse.Action):
- """Port action class definition."""
-
- MIN_PORT = 1
- MAX_PORT = 65535
-
- OPEN_PORT_LIMIT = 1024
-
- 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.
- """
- port = values
- if not self.MIN_PORT <= port <= self.MAX_PORT:
- parser.error(f'{option_string} should be chosen from {self.MIN_PORT} to {self.MAX_PORT}')
-
- setattr(namespace, self.dest, port)
-
-
- class UrlPathPrefixAction(argparse.Action):
- """Url Path prefix action class definition."""
-
- INVALID_SEGMENTS = ('.', '..')
- 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
- segments = prefix.split('/')
- for index, segment in enumerate(segments):
- if not segment and index in (0, len(segments) - 1):
- continue
- if segment in self.INVALID_SEGMENTS or not re.match(self.REGEX, segment):
- parser.error(f'{option_string} value is invalid url path prefix')
-
- setattr(namespace, self.dest, prefix)
-
-
- class Command(BaseCommand):
- """
- Start mindinsight service.
- """
-
- name = 'start'
- description = 'startup mindinsight service'
-
- def add_arguments(self, parser):
- """
- Add arguments to parser.
-
- Args:
- parser (ArgumentParser): Specify parser to which arguments are added.
- """
- parser.add_argument(
- '--config',
- type=str,
- action=ConfigAction,
- help="""
- Specify path for user config module or file of the form python:path.to.config.module
- or file:/path/to/config.py
- """)
-
- parser.add_argument(
- '--workspace',
- type=str,
- action=WorkspaceAction,
- help="""
- Specify path for user workspace. Default is %s.
- """ % settings.WORKSPACE)
-
- parser.add_argument(
- '--port',
- type=int,
- action=PortAction,
- help="""
- 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 URL path prefix for web page address. URL path prefix
- consists of segments separated by slashes. Each segment supports
- alphabets / digits / underscores / dashes / dots, but not single
- dot or double dots. Default value is ''.
- """)
-
- for hook in HookUtils.instance().hooks():
- hook.register_startup_arguments(parser)
-
- def update_settings(self, args):
- """
- Update settings.
-
- Args:
- args (Namespace): parsed arguments to hold customized parameters.
- """
- kwargs = {}
- for key, value in args.__dict__.items():
- if value is not None:
- kwargs[key] = value
-
- init(**kwargs)
-
- def run(self, args):
- """
- Execute for start command.
-
- Args:
- args (Namespace): Parsed arguments to hold customized parameters.
- """
- for key, value in args.__dict__.items():
- if value is not None:
- self.logfile.info('%s = %s', key, value)
-
- try:
- self.check_port()
- self.check_debugger_port()
- except PortNotAvailableError as error:
- self.console.error(error.message)
- self.logfile.error(error.message)
- sys.exit(1)
-
- self.console.info('Workspace: %s', os.path.realpath(settings.WORKSPACE))
-
- run_module = import_module('mindinsight.backend.run')
- run_module.start()
-
- self.logfile.info('Start mindinsight done.')
-
- def check_port(self):
- """Check port."""
- if os.getuid() != 0 and settings.PORT < PortAction.OPEN_PORT_LIMIT:
- raise PortNotAvailableError(
- f'Port {settings.PORT} below {PortAction.OPEN_PORT_LIMIT} is not allowed by current user.')
-
- connections = psutil.net_connections()
- for connection in connections:
- if connection.status != 'LISTEN':
- continue
- if connection.laddr.port == settings.PORT:
- raise PortNotAvailableError(f'Port {settings.PORT} is no available for MindInsight')
-
-
- def check_debugger_port(self):
- """Check if the debugger_port is available"""
- if not settings.ENABLE_DEBUGGER:
- return
- ip = settings.HOST
- port = settings.DEBUGGER_PORT
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect((ip, int(port)))
- s.shutdown(2)
- raise PortNotAvailableError(f'Debugger-port {ip}:{port} is not available for MindInsight')
- except socket.error:
- return
|