blob: 76e96f31c1088cbea66ff01838f5e6ed375ad0d9 [file] [log] [blame]
Dan Shi784df0c2014-11-26 10:11:15 -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 functions to manage servers in server database
Dan Shi56f1ba72014-12-03 19:16:53 -08006(defined in global config section AUTOTEST_SERVER_DB).
Dan Shi784df0c2014-11-26 10:11:15 -08007
8create(hostname, role=None, note=None)
9 Create a server with given role, with status backup.
10
11delete(hostname)
12 Delete a server from the database. If the server is in primary status, its
13 roles will be replaced by a backup server first.
14
15modify(hostname, role=None, status=None, note=None, delete=False,
16 attribute=None, value=None)
17 Modify a server's role, status, note, or attribute:
18 1. Add role to a server. If the server is in primary status, proper actions
19 like service restart will be executed to enable the role.
20 2. Delete a role from a server. If the server is in primary status, proper
21 actions like service restart will be executed to disable the role.
22 3. Change status of a server. If the server is changed from or to primary
23 status, proper actions like service restart will be executed to enable
24 or disable each role of the server.
25 4. Change note of a server. Note is a field you can add description about
26 the server.
27 5. Change/delete attribute of a server. Attribute can be used to store
28 information about a server. For example, the max_processes count for a
29 drone.
30
31"""
32
Dan Shi784df0c2014-11-26 10:11:15 -080033
34import datetime
35
36import common
37
Dan Shi784df0c2014-11-26 10:11:15 -080038from autotest_lib.frontend.server import models as server_models
Dan Shi56f1ba72014-12-03 19:16:53 -080039from autotest_lib.site_utils import server_manager_actions
40from autotest_lib.site_utils import server_manager_utils
Dan Shi784df0c2014-11-26 10:11:15 -080041
42
Dan Shi56f1ba72014-12-03 19:16:53 -080043def _add_role(server, role, action):
Dan Shi784df0c2014-11-26 10:11:15 -080044 """Add a role to the server.
45
46 @param server: An object of server_models.Server.
47 @param role: Role to be added to the server.
Dan Shi56f1ba72014-12-03 19:16:53 -080048 @param action: Execute actions after role or status is changed. Default to
49 False.
Dan Shi784df0c2014-11-26 10:11:15 -080050
51 @raise ServerActionError: If role is failed to be added.
52 """
53 server_models.validate(role=role)
Dan Shi56f1ba72014-12-03 19:16:53 -080054 if role in server.get_role_names():
55 raise server_manager_utils.ServerActionError(
56 'Server %s already has role %s.' % (server.hostname, role))
57
58 # Verify server
59 if not server_manager_utils.check_server(server.hostname, role):
60 raise server_manager_utils.ServerActionError(
61 'Server %s is not ready for role %s.' % (server.hostname, role))
Dan Shi784df0c2014-11-26 10:11:15 -080062
63 if (role in server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE and
64 server.status == server_models.Server.STATUS.PRIMARY):
65 servers = server_models.Server.objects.filter(
66 roles__role=role, status=server_models.Server.STATUS.PRIMARY)
67 if len(servers) >= 1:
Dan Shi56f1ba72014-12-03 19:16:53 -080068 raise server_manager_utils.ServerActionError(
69 'Role %s must be unique. Server %s already has role %s.' %
70 (role, servers[0].hostname, role))
71
Dan Shi784df0c2014-11-26 10:11:15 -080072 server_models.ServerRole.objects.create(server=server, role=role)
73
Dan Shi56f1ba72014-12-03 19:16:53 -080074 # If needed, apply actions to enable the role for the server.
75 server_manager_actions.try_execute(server, [role], enable=True,
76 post_change=True, do_action=action)
77
Dan Shi784df0c2014-11-26 10:11:15 -080078 print 'Role %s is added to server %s.' % (role, server.hostname)
79
80
Dan Shi60cf6a92015-01-29 17:22:49 -080081def _delete_role(server, role, action=False):
Dan Shi784df0c2014-11-26 10:11:15 -080082 """Delete a role from the server.
83
84 @param server: An object of server_models.Server.
85 @param role: Role to be deleted from the server.
Dan Shi56f1ba72014-12-03 19:16:53 -080086 @param action: Execute actions after role or status is changed. Default to
87 False.
Dan Shi784df0c2014-11-26 10:11:15 -080088
89 @raise ServerActionError: If role is failed to be deleted.
90 """
91 server_models.validate(role=role)
Dan Shi56f1ba72014-12-03 19:16:53 -080092 if role not in server.get_role_names():
93 raise server_manager_utils.ServerActionError(
94 'Server %s does not have role %s.' % (server.hostname, role))
Dan Shi784df0c2014-11-26 10:11:15 -080095
96 if server.status == server_models.Server.STATUS.PRIMARY:
Dan Shi56f1ba72014-12-03 19:16:53 -080097 server_manager_utils.warn_missing_role(role, server)
98
99 # Apply actions to disable the role for the server before the role is
100 # removed from the server.
101 server_manager_actions.try_execute(server, [role], enable=False,
102 post_change=False, do_action=action)
103
104 print 'Deleting role %s from server %s...' % (role, server.hostname)
105 server.roles.get(role=role).delete()
106
107 # Apply actions to disable the role for the server after the role is
108 # removed from the server.
109 server_manager_actions.try_execute(server, [role], enable=False,
110 post_change=True, do_action=action)
111
112 # If the server is in status primary and has no role, change its status to
113 # backup.
114 if (not server.get_role_names() and
115 server.status == server_models.Server.STATUS.PRIMARY):
116 print ('Server %s has no role, change its status from primary to backup'
117 % server.hostname)
118 server.status = server_models.Server.STATUS.BACKUP
119 server.save()
Dan Shi784df0c2014-11-26 10:11:15 -0800120
121 print 'Role %s is deleted from server %s.' % (role, server.hostname)
122
123
Dan Shi56f1ba72014-12-03 19:16:53 -0800124def _change_status(server, status, action):
Dan Shi784df0c2014-11-26 10:11:15 -0800125 """Change the status of the server.
126
127 @param server: An object of server_models.Server.
128 @param status: New status of the server.
Dan Shi56f1ba72014-12-03 19:16:53 -0800129 @param action: Execute actions after role or status is changed. Default to
130 False.
Dan Shi784df0c2014-11-26 10:11:15 -0800131
132 @raise ServerActionError: If status is failed to be changed.
133 """
134 server_models.validate(status=status)
135 if server.status == status:
Dan Shi56f1ba72014-12-03 19:16:53 -0800136 raise server_manager_utils.ServerActionError(
137 'Server %s already has status of %s.' %
138 (server.hostname, status))
Dan Shi784df0c2014-11-26 10:11:15 -0800139 if (not server.roles.all() and
Dan Shi56f1ba72014-12-03 19:16:53 -0800140 status == server_models.Server.STATUS.PRIMARY):
141 raise server_manager_utils.ServerActionError(
142 'Server %s has no role associated. Server must have a role to '
143 'be in status primary.' % server.hostname)
Dan Shi784df0c2014-11-26 10:11:15 -0800144
Dan Shi56f1ba72014-12-03 19:16:53 -0800145 # Abort the action if the server's status will be changed to primary and
146 # the Autotest instance already has another server running an unique role.
147 # For example, a scheduler server is already running, and a backup server
148 # with role scheduler should not be changed to status primary.
Dan Shi784df0c2014-11-26 10:11:15 -0800149 unique_roles = server.roles.filter(
150 role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE)
151 if unique_roles and status == server_models.Server.STATUS.PRIMARY:
152 for role in unique_roles:
153 servers = server_models.Server.objects.filter(
154 roles__role=role.role,
155 status=server_models.Server.STATUS.PRIMARY)
156 if len(servers) == 1:
Dan Shi56f1ba72014-12-03 19:16:53 -0800157 raise server_manager_utils.ServerActionError(
158 'Role %s must be unique. Server %s already has the '
159 'role.' % (role.role, servers[0].hostname))
160
161 # Post a warning if the server's status will be changed from primary to
162 # other value and the server is running a unique role across database, e.g.
163 # scheduler.
164 if server.status == server_models.Server.STATUS.PRIMARY:
165 for role in server.get_role_names():
166 server_manager_utils.warn_missing_role(role, server)
167
168 enable = status == server_models.Server.STATUS.PRIMARY
169 server_manager_actions.try_execute(server, server.get_role_names(),
170 enable=enable, post_change=False,
171 do_action=action)
172
173 prev_status = server.status
Dan Shi784df0c2014-11-26 10:11:15 -0800174 server.status = status
175 server.save()
176
Dan Shi56f1ba72014-12-03 19:16:53 -0800177 # Apply actions to enable/disable roles of the server after the status is
178 # changed.
179 server_manager_actions.try_execute(server, server.get_role_names(),
180 enable=enable, post_change=True,
181 prev_status=prev_status,
182 do_action=action)
183
Dan Shi784df0c2014-11-26 10:11:15 -0800184 print ('Status of server %s is changed from %s to %s. Affected roles: %s' %
Dan Shi56f1ba72014-12-03 19:16:53 -0800185 (server.hostname, prev_status, status,
186 ', '.join(server.get_role_names())))
Dan Shi784df0c2014-11-26 10:11:15 -0800187
188
Dan Shi56f1ba72014-12-03 19:16:53 -0800189@server_manager_utils.verify_server(exist=False)
Dan Shi784df0c2014-11-26 10:11:15 -0800190def create(hostname, role=None, note=None):
191 """Create a new server.
192
193 The status of new server will always be backup, user need to call
194 atest server modify hostname --status primary
195 to set the server's status to primary.
196
197 @param hostname: hostname of the server.
198 @param role: role of the new server, default to None.
199 @param note: notes about the server, default to None.
200
201 @return: A Server object that contains the server information.
202 """
203 server_models.validate(hostname=hostname, role=role)
204 server = server_models.Server.objects.create(
205 hostname=hostname, status=server_models.Server.STATUS.BACKUP,
206 note=note, date_created=datetime.datetime.now())
207 server_models.ServerRole.objects.create(server=server, role=role)
208 return server
209
210
Dan Shi56f1ba72014-12-03 19:16:53 -0800211@server_manager_utils.verify_server()
Dan Shi784df0c2014-11-26 10:11:15 -0800212def delete(hostname, server=None):
213 """Delete given server from server database.
214
215 @param hostname: hostname of the server to be deleted.
216 @param server: Server object from database query, this argument should be
217 injected by the verify_server_exists decorator.
218
219 @raise ServerActionError: If delete server action failed, e.g., server is
220 not found in database or server is primary but no backup is found.
221 """
222 print 'Deleting server %s from server database.' % hostname
223
Dan Shi56f1ba72014-12-03 19:16:53 -0800224 if (server_manager_utils.use_server_db() and
225 server.status == server_models.Server.STATUS.PRIMARY):
Dan Shi784df0c2014-11-26 10:11:15 -0800226 print ('Server %s is in status primary, need to disable its '
227 'current roles first.' % hostname)
228 for role in server.roles.all():
229 _delete_role(server, role.role)
230
231 server.delete()
232 print 'Server %s is deleted from server database.' % hostname
233
234
Dan Shi56f1ba72014-12-03 19:16:53 -0800235@server_manager_utils.verify_server()
Dan Shi784df0c2014-11-26 10:11:15 -0800236def modify(hostname, role=None, status=None, delete=False, note=None,
Dan Shi56f1ba72014-12-03 19:16:53 -0800237 attribute=None, value=None, action=False, server=None):
Dan Shi784df0c2014-11-26 10:11:15 -0800238 """Modify given server with specified actions.
239
240 @param hostname: hostname of the server to be modified.
241 @param role: Role to be added to the server.
242 @param status: Modify server status.
243 @param delete: True to delete given role from the server, default to False.
244 @param note: Note of the server.
245 @param attribute: Name of an attribute of the server.
246 @param value: Value of an attribute of the server.
Dan Shi56f1ba72014-12-03 19:16:53 -0800247 @param action: Execute actions after role or status is changed. Default to
248 False.
Dan Shi784df0c2014-11-26 10:11:15 -0800249 @param server: Server object from database query, this argument should be
250 injected by the verify_server_exists decorator.
251
252 @raise InvalidDataError: If the operation failed with any wrong value of
253 the arguments.
254 @raise ServerActionError: If any operation failed.
255 """
256 if role:
257 if not delete:
Dan Shi56f1ba72014-12-03 19:16:53 -0800258 _add_role(server, role, action)
Dan Shi784df0c2014-11-26 10:11:15 -0800259 else:
Dan Shi56f1ba72014-12-03 19:16:53 -0800260 _delete_role(server, role, action)
Dan Shi784df0c2014-11-26 10:11:15 -0800261
262 if status:
Dan Shi56f1ba72014-12-03 19:16:53 -0800263 _change_status(server, status, action)
Dan Shi784df0c2014-11-26 10:11:15 -0800264
265 if note is not None:
266 server.note = note
267 server.save()
268
269 if attribute and value:
Dan Shi56f1ba72014-12-03 19:16:53 -0800270 server_manager_utils.change_attribute(server, attribute, value)
Dan Shi784df0c2014-11-26 10:11:15 -0800271 elif attribute and delete:
Dan Shi56f1ba72014-12-03 19:16:53 -0800272 server_manager_utils.delete_attribute(server, attribute)
Dan Shi784df0c2014-11-26 10:11:15 -0800273
274 return server