• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lint as: python2, python3
2# Copyright 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This module provides utility functions to help managing servers in server
7database (defined in global config section AUTOTEST_SERVER_DB).
8
9After a role is added or removed from a server, certain services may need to
10be restarted. For example, scheduler needs to be restarted after a drone is
11added to a primary server. This module includes functions to check if actions
12are required to be executed and what actions to executed on which servers.
13"""
14
15from __future__ import absolute_import
16from __future__ import division
17from __future__ import print_function
18
19import subprocess
20import sys
21
22import common
23
24from autotest_lib.frontend.server import models as server_models
25from autotest_lib.site_utils import server_manager_utils
26from autotest_lib.site_utils.lib import infra
27
28
29# Actions that must be executed for server management action to be effective.
30# Each action is a tuple:
31# (the role of which the command should be executed, the command)
32RESTART_SCHEDULER = (server_models.ServerRole.ROLE.SCHEDULER,
33                     'sudo service scheduler restart')
34RESTART_HOST_SCHEDULER = (server_models.ServerRole.ROLE.HOST_SCHEDULER,
35                          'sudo service host-scheduler restart')
36RELOAD_APACHE = (server_models.ServerRole.ROLE.SCHEDULER,
37                 'sudo service apache reload')
38
39STOP_SCHEDULER = (server_models.ServerRole.ROLE.SCHEDULER,
40                  'sudo service scheduler stop')
41STOP_HOST_SCHEDULER = (server_models.ServerRole.ROLE.HOST_SCHEDULER,
42                       'sudo service host-scheduler stop')
43
44# Dictionary of actions needed for a role to be enabled. Key is the role, and
45# value is a list of action. All these actions should be applied after the role
46# is added to the server, or the server's status is changed to primary.
47ACTIONS_AFTER_ROLE_APPLIED = {
48        server_models.ServerRole.ROLE.SCHEDULER: [RESTART_SCHEDULER],
49        server_models.ServerRole.ROLE.HOST_SCHEDULER: [RESTART_HOST_SCHEDULER],
50        server_models.ServerRole.ROLE.DRONE: [RESTART_SCHEDULER],
51        server_models.ServerRole.ROLE.DATABASE:
52                [RESTART_SCHEDULER, RESTART_HOST_SCHEDULER, RELOAD_APACHE],
53        server_models.ServerRole.ROLE.DEVSERVER: [RESTART_SCHEDULER],
54        }
55
56# Dictionary of actions needed for a role to be disabled. Key is the role, and
57# value is a list of action.
58# Action should be taken before role is deleted from a server, or the server's
59# status is changed to primary.
60ACTIONS_BEFORE_ROLE_REMOVED = {
61        server_models.ServerRole.ROLE.SCHEDULER: [STOP_SCHEDULER],
62        server_models.ServerRole.ROLE.HOST_SCHEDULER: [STOP_HOST_SCHEDULER],
63        server_models.ServerRole.ROLE.DATABASE:
64                [STOP_SCHEDULER, STOP_HOST_SCHEDULER],
65        }
66# Action should be taken after role is deleted from a server, or the server's
67# status is changed to primary.
68ACTIONS_AFTER_ROLE_REMOVED = {
69        server_models.ServerRole.ROLE.DRONE: [RESTART_SCHEDULER],
70        server_models.ServerRole.ROLE.DEVSERVER: [RESTART_SCHEDULER],
71        }
72
73
74def apply(action):
75    """Apply an given action.
76
77    It usually involves ssh to the server with specific role and run the
78    command, e.g., ssh to scheduler server and restart scheduler.
79
80    @param action: A tuple of (the role of which the command should be executed,
81                   the command)
82    @raise ServerActionError: If the action can't be applied due to database
83                              issue.
84    @param subprocess.CalledProcessError: If command is failed to be
85                                          executed.
86    """
87    role = action[0]
88    command = action[1]
89    # Find the servers with role
90    servers = server_manager_utils.get_servers(
91            role=role, status=server_models.Server.STATUS.PRIMARY)
92    if not servers:
93        print('WARNING! Action %s failed to be applied. No '
94              'server with given role %s was found.' % (action, role),
95              file=sys.stderr)
96        return
97
98    for server in servers:
99        print('Run command `%s` on server %s' % (command, server.hostname))
100        try:
101            infra.execute_command(server.hostname, command)
102        except subprocess.CalledProcessError as e:
103            print('Failed to check server %s, error: %s' %
104                  (server.hostname, e), file=sys.stderr)
105
106
107def try_execute(server, roles, enable, post_change,
108                prev_status=server_models.Server.STATUS.REPAIR_REQUIRED,
109                do_action=False):
110    """Try to execute actions for given role changes of the server.
111
112    @param server: Server that has the role changes.
113    @param roles: A list of roles changed.
114    @param enable: Set to True if the roles are enabled, i.e., added to server.
115                   If it's False, the roles are removed from the server.
116    @param post_change: Set to True if to apply actions should be applied after
117                        the role changes, otherwise, set to False.
118    @param prev_status: The previous status after the status change if any. This
119                        is to help to decide if actions should be executed,
120                        since actions should be applied if the server's status
121                        is changed from primary to other status. Default to
122                        repair_required.
123    @param do_action: Set to True to execute actions, otherwise, post a warning.
124    """
125    if not server_manager_utils.use_server_db():
126        return
127    # This check is to prevent actions to be applied to server not in primary
128    # role or server database is not enabled. Note that no action is needed
129    # before a server is changed to primary status. If that assumption is
130    # no longer valid, this method needs to be updated accordingly.
131    if (server.status != server_models.Server.STATUS.PRIMARY and
132        prev_status != server_models.Server.STATUS.PRIMARY):
133        return
134
135    possible_actions = {}
136    if enable:
137        if post_change:
138            possible_actions = ACTIONS_AFTER_ROLE_APPLIED
139    else:
140        if post_change:
141            possible_actions = ACTIONS_AFTER_ROLE_REMOVED
142        else:
143            possible_actions = ACTIONS_BEFORE_ROLE_REMOVED
144
145    all_actions = []
146    for role in roles:
147        all_actions.extend(possible_actions.get(role, []))
148    for action in set(all_actions):
149        if do_action:
150            apply(action)
151        else:
152            message = ('WARNING! Action %s is skipped. Please manually '
153                       'execute the action to make your change effective.' %
154                       str(action))
155            print(message, file=sys.stderr)
156