You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
6.6 KiB
156 lines
6.6 KiB
# Lint as: python2, python3
|
|
# Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""This module provides utility functions to help managing servers in server
|
|
database (defined in global config section AUTOTEST_SERVER_DB).
|
|
|
|
After a role is added or removed from a server, certain services may need to
|
|
be restarted. For example, scheduler needs to be restarted after a drone is
|
|
added to a primary server. This module includes functions to check if actions
|
|
are required to be executed and what actions to executed on which servers.
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import subprocess
|
|
import sys
|
|
|
|
import common
|
|
|
|
from autotest_lib.frontend.server import models as server_models
|
|
from autotest_lib.site_utils import server_manager_utils
|
|
from autotest_lib.site_utils.lib import infra
|
|
|
|
|
|
# Actions that must be executed for server management action to be effective.
|
|
# Each action is a tuple:
|
|
# (the role of which the command should be executed, the command)
|
|
RESTART_SCHEDULER = (server_models.ServerRole.ROLE.SCHEDULER,
|
|
'sudo service scheduler restart')
|
|
RESTART_HOST_SCHEDULER = (server_models.ServerRole.ROLE.HOST_SCHEDULER,
|
|
'sudo service host-scheduler restart')
|
|
RELOAD_APACHE = (server_models.ServerRole.ROLE.SCHEDULER,
|
|
'sudo service apache reload')
|
|
|
|
STOP_SCHEDULER = (server_models.ServerRole.ROLE.SCHEDULER,
|
|
'sudo service scheduler stop')
|
|
STOP_HOST_SCHEDULER = (server_models.ServerRole.ROLE.HOST_SCHEDULER,
|
|
'sudo service host-scheduler stop')
|
|
|
|
# Dictionary of actions needed for a role to be enabled. Key is the role, and
|
|
# value is a list of action. All these actions should be applied after the role
|
|
# is added to the server, or the server's status is changed to primary.
|
|
ACTIONS_AFTER_ROLE_APPLIED = {
|
|
server_models.ServerRole.ROLE.SCHEDULER: [RESTART_SCHEDULER],
|
|
server_models.ServerRole.ROLE.HOST_SCHEDULER: [RESTART_HOST_SCHEDULER],
|
|
server_models.ServerRole.ROLE.DRONE: [RESTART_SCHEDULER],
|
|
server_models.ServerRole.ROLE.DATABASE:
|
|
[RESTART_SCHEDULER, RESTART_HOST_SCHEDULER, RELOAD_APACHE],
|
|
server_models.ServerRole.ROLE.DEVSERVER: [RESTART_SCHEDULER],
|
|
}
|
|
|
|
# Dictionary of actions needed for a role to be disabled. Key is the role, and
|
|
# value is a list of action.
|
|
# Action should be taken before role is deleted from a server, or the server's
|
|
# status is changed to primary.
|
|
ACTIONS_BEFORE_ROLE_REMOVED = {
|
|
server_models.ServerRole.ROLE.SCHEDULER: [STOP_SCHEDULER],
|
|
server_models.ServerRole.ROLE.HOST_SCHEDULER: [STOP_HOST_SCHEDULER],
|
|
server_models.ServerRole.ROLE.DATABASE:
|
|
[STOP_SCHEDULER, STOP_HOST_SCHEDULER],
|
|
}
|
|
# Action should be taken after role is deleted from a server, or the server's
|
|
# status is changed to primary.
|
|
ACTIONS_AFTER_ROLE_REMOVED = {
|
|
server_models.ServerRole.ROLE.DRONE: [RESTART_SCHEDULER],
|
|
server_models.ServerRole.ROLE.DEVSERVER: [RESTART_SCHEDULER],
|
|
}
|
|
|
|
|
|
def apply(action):
|
|
"""Apply an given action.
|
|
|
|
It usually involves ssh to the server with specific role and run the
|
|
command, e.g., ssh to scheduler server and restart scheduler.
|
|
|
|
@param action: A tuple of (the role of which the command should be executed,
|
|
the command)
|
|
@raise ServerActionError: If the action can't be applied due to database
|
|
issue.
|
|
@param subprocess.CalledProcessError: If command is failed to be
|
|
executed.
|
|
"""
|
|
role = action[0]
|
|
command = action[1]
|
|
# Find the servers with role
|
|
servers = server_manager_utils.get_servers(
|
|
role=role, status=server_models.Server.STATUS.PRIMARY)
|
|
if not servers:
|
|
print('WARNING! Action %s failed to be applied. No '
|
|
'server with given role %s was found.' % (action, role),
|
|
file=sys.stderr)
|
|
return
|
|
|
|
for server in servers:
|
|
print('Run command `%s` on server %s' % (command, server.hostname))
|
|
try:
|
|
infra.execute_command(server.hostname, command)
|
|
except subprocess.CalledProcessError as e:
|
|
print('Failed to check server %s, error: %s' %
|
|
(server.hostname, e), file=sys.stderr)
|
|
|
|
|
|
def try_execute(server, roles, enable, post_change,
|
|
prev_status=server_models.Server.STATUS.REPAIR_REQUIRED,
|
|
do_action=False):
|
|
"""Try to execute actions for given role changes of the server.
|
|
|
|
@param server: Server that has the role changes.
|
|
@param roles: A list of roles changed.
|
|
@param enable: Set to True if the roles are enabled, i.e., added to server.
|
|
If it's False, the roles are removed from the server.
|
|
@param post_change: Set to True if to apply actions should be applied after
|
|
the role changes, otherwise, set to False.
|
|
@param prev_status: The previous status after the status change if any. This
|
|
is to help to decide if actions should be executed,
|
|
since actions should be applied if the server's status
|
|
is changed from primary to other status. Default to
|
|
repair_required.
|
|
@param do_action: Set to True to execute actions, otherwise, post a warning.
|
|
"""
|
|
if not server_manager_utils.use_server_db():
|
|
return
|
|
# This check is to prevent actions to be applied to server not in primary
|
|
# role or server database is not enabled. Note that no action is needed
|
|
# before a server is changed to primary status. If that assumption is
|
|
# no longer valid, this method needs to be updated accordingly.
|
|
if (server.status != server_models.Server.STATUS.PRIMARY and
|
|
prev_status != server_models.Server.STATUS.PRIMARY):
|
|
return
|
|
|
|
possible_actions = {}
|
|
if enable:
|
|
if post_change:
|
|
possible_actions = ACTIONS_AFTER_ROLE_APPLIED
|
|
else:
|
|
if post_change:
|
|
possible_actions = ACTIONS_AFTER_ROLE_REMOVED
|
|
else:
|
|
possible_actions = ACTIONS_BEFORE_ROLE_REMOVED
|
|
|
|
all_actions = []
|
|
for role in roles:
|
|
all_actions.extend(possible_actions.get(role, []))
|
|
for action in set(all_actions):
|
|
if do_action:
|
|
apply(action)
|
|
else:
|
|
message = ('WARNING! Action %s is skipped. Please manually '
|
|
'execute the action to make your change effective.' %
|
|
str(action))
|
|
print(message, file=sys.stderr)
|