You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

stop.py 5.9 kB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # Copyright 2019 Huawei Technologies Co., Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # ============================================================================
  15. """Stop mindinsight service."""
  16. import os
  17. import sys
  18. import argparse
  19. import signal
  20. import getpass
  21. import psutil
  22. from mindinsight.conf import settings
  23. from mindinsight.utils.command import BaseCommand
  24. from mindinsight.utils.hook import HookUtils
  25. class PortAction(argparse.Action):
  26. """Port action class definition."""
  27. MIN_PORT = 1
  28. MAX_PORT = 65535
  29. def __call__(self, parser, namespace, values, option_string=None):
  30. """
  31. Inherited __call__ method from argparse.Action.
  32. Args:
  33. parser (ArgumentParser): Passed-in argument parser.
  34. namespace (Namespace): Namespace object to hold arguments.
  35. values (object): Argument values with type depending on argument definition.
  36. option_string (str): Optional string for specific argument name. Default: None.
  37. """
  38. port = values
  39. if not self.MIN_PORT <= port <= self.MAX_PORT:
  40. parser.error(f'{option_string} should be chosen from {self.MIN_PORT} to {self.MAX_PORT}')
  41. setattr(namespace, self.dest, port)
  42. class Command(BaseCommand):
  43. """Stop command."""
  44. name = 'stop'
  45. description = 'stop mindinsight service'
  46. cmd_regex = 'mindinsight.backend.application:APP'
  47. access_log_path = os.path.join('gunicorn', 'access.{}.log'.format(settings.PORT))
  48. def add_arguments(self, parser):
  49. """
  50. Add arguments to parser.
  51. Args:
  52. parser (ArgumentParser): Specify parser to which arguments are added.
  53. """
  54. parser.add_argument(
  55. '--port',
  56. type=int,
  57. action=PortAction,
  58. help="""
  59. Custom port ranging from %s to %s. Default value is %s
  60. """ % (PortAction.MIN_PORT, PortAction.MAX_PORT, settings.PORT))
  61. def update_settings(self, args):
  62. """
  63. Update settings.
  64. Args:
  65. args (Namespace): parsed arguments to hold customized parameters.
  66. """
  67. if args.port is None:
  68. args.port = settings.PORT
  69. pid, workspace = self.get_process(args.port)
  70. settings.config_workspace(workspace)
  71. setattr(args, 'pid', pid)
  72. def run(self, args):
  73. """
  74. Run to stop.
  75. Args:
  76. args (Namespace): Parsed arguments to hold customized parameters.
  77. """
  78. port, pid = args.port, args.pid
  79. if not pid:
  80. msg = f'No mindinsight service started by current user found for port {port}'
  81. self.console.error(msg)
  82. sys.exit(1)
  83. self.logfile.info('Stop mindinsight with port %s and pid %s.', port, pid)
  84. process = psutil.Process(pid)
  85. processes_to_kill = [process]
  86. # Set recursive to True to kill grand children processes.
  87. for child in process.children(recursive=True):
  88. processes_to_kill.append(child)
  89. for proc in processes_to_kill:
  90. self.logfile.info('Stopping mindinsight process %s.', proc.pid)
  91. try:
  92. proc.send_signal(signal.SIGKILL)
  93. except psutil.Error as ex:
  94. self.logfile.warning("Stop process %s failed. Detail: %s.", proc.pid, str(ex))
  95. for hook in HookUtils.instance().hooks():
  96. hook.on_shutdown(self.logfile)
  97. self.console.info('Stop mindinsight service successfully')
  98. def get_process(self, port):
  99. """
  100. Get mindinsight process
  101. Args:
  102. port (int): Specified port for mindinsight process.
  103. Returns:
  104. tuple, return mindinsight process pid and workspace.
  105. """
  106. pid, workspace = 0, settings.WORKSPACE
  107. user = getpass.getuser()
  108. connections = psutil.net_connections()
  109. for connection in connections:
  110. if connection.status != 'LISTEN':
  111. continue
  112. if connection.laddr.port != port:
  113. continue
  114. try:
  115. process = psutil.Process(connection.pid)
  116. except psutil.NoSuchProcess:
  117. continue
  118. cmds = process.cmdline()
  119. if ' '.join(cmds).find(self.cmd_regex) == -1:
  120. continue
  121. if user != process.username():
  122. continue
  123. gunicorn_master_process = process
  124. # The gunicorn master process might have grand children (eg forked by process pool).
  125. while True:
  126. parent_process = gunicorn_master_process.parent()
  127. if parent_process is None or parent_process.pid == 1:
  128. break
  129. parent_cmd = parent_process.cmdline()
  130. if ' '.join(parent_cmd).find(self.cmd_regex) == -1:
  131. break
  132. gunicorn_master_process = parent_process
  133. pid = gunicorn_master_process.pid
  134. for open_file in process.open_files():
  135. if open_file.path.endswith(self.access_log_path):
  136. log_base_dir = open_file.path[:-len(self.access_log_path)]
  137. workspace = os.path.realpath(os.path.join(log_base_dir, os.pardir))
  138. break
  139. break
  140. return pid, workspace