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