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.
272 lines
11 KiB
272 lines
11 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 functions to manage servers in server database
|
|
(defined in global config section AUTOTEST_SERVER_DB).
|
|
|
|
create(hostname, role=None, note=None)
|
|
Create a server with given role, with status primary.
|
|
|
|
delete(hostname)
|
|
Delete a server from the database.
|
|
|
|
modify(hostname, role=None, status=None, note=None, delete=False,
|
|
attribute=None, value=None)
|
|
Modify a server's role, status, note, or attribute:
|
|
1. Add role to a server. If the server is in primary status, proper actions
|
|
like service restart will be executed to enable the role.
|
|
2. Delete a role from a server. If the server is in primary status, proper
|
|
actions like service restart will be executed to disable the role.
|
|
3. Change status of a server. If the server is changed from or to primary
|
|
status, proper actions like service restart will be executed to enable
|
|
or disable each role of the server.
|
|
4. Change note of a server. Note is a field you can add description about
|
|
the server.
|
|
5. Change/delete attribute of a server. Attribute can be used to store
|
|
information about a server. For example, the max_processes count for a
|
|
drone.
|
|
|
|
"""
|
|
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import datetime
|
|
|
|
import common
|
|
|
|
from autotest_lib.frontend.server import models as server_models
|
|
from autotest_lib.site_utils import server_manager_actions
|
|
from autotest_lib.site_utils import server_manager_utils
|
|
|
|
|
|
def _add_role(server, role, action):
|
|
"""Add a role to the server.
|
|
|
|
@param server: An object of server_models.Server.
|
|
@param role: Role to be added to the server.
|
|
@param action: Execute actions after role or status is changed. Default to
|
|
False.
|
|
|
|
@raise ServerActionError: If role is failed to be added.
|
|
"""
|
|
server_models.validate(role=role)
|
|
if role in server.get_role_names():
|
|
raise server_manager_utils.ServerActionError(
|
|
'Server %s already has role %s.' % (server.hostname, role))
|
|
|
|
# Verify server
|
|
if not server_manager_utils.check_server(server.hostname, role):
|
|
raise server_manager_utils.ServerActionError(
|
|
'Server %s is not ready for role %s.' % (server.hostname, role))
|
|
|
|
if (role in server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE and
|
|
server.status == server_models.Server.STATUS.PRIMARY):
|
|
servers = server_models.Server.objects.filter(
|
|
roles__role=role, status=server_models.Server.STATUS.PRIMARY)
|
|
if len(servers) >= 1:
|
|
raise server_manager_utils.ServerActionError(
|
|
'Role %s must be unique. Server %s already has role %s.' %
|
|
(role, servers[0].hostname, role))
|
|
|
|
server_models.ServerRole.objects.create(server=server, role=role)
|
|
|
|
# If needed, apply actions to enable the role for the server.
|
|
server_manager_actions.try_execute(server, [role], enable=True,
|
|
post_change=True, do_action=action)
|
|
|
|
print('Role %s is added to server %s.' % (role, server.hostname))
|
|
|
|
|
|
def _delete_role(server, role, action=False):
|
|
"""Delete a role from the server.
|
|
|
|
@param server: An object of server_models.Server.
|
|
@param role: Role to be deleted from the server.
|
|
@param action: Execute actions after role or status is changed. Default to
|
|
False.
|
|
|
|
@raise ServerActionError: If role is failed to be deleted.
|
|
"""
|
|
server_models.validate(role=role)
|
|
if role not in server.get_role_names():
|
|
raise server_manager_utils.ServerActionError(
|
|
'Server %s does not have role %s.' % (server.hostname, role))
|
|
|
|
if server.status == server_models.Server.STATUS.PRIMARY:
|
|
server_manager_utils.warn_missing_role(role, server)
|
|
|
|
# Apply actions to disable the role for the server before the role is
|
|
# removed from the server.
|
|
server_manager_actions.try_execute(server, [role], enable=False,
|
|
post_change=False, do_action=action)
|
|
|
|
print('Deleting role %s from server %s...' % (role, server.hostname))
|
|
server.roles.get(role=role).delete()
|
|
|
|
# Apply actions to disable the role for the server after the role is
|
|
# removed from the server.
|
|
server_manager_actions.try_execute(server, [role], enable=False,
|
|
post_change=True, do_action=action)
|
|
|
|
if (not server.get_role_names() and
|
|
server.status == server_models.Server.STATUS.PRIMARY):
|
|
print ('Server %s has no role.')
|
|
|
|
print('Role %s is deleted from server %s.' % (role, server.hostname))
|
|
|
|
|
|
def _change_status(server, status, action):
|
|
"""Change the status of the server.
|
|
|
|
@param server: An object of server_models.Server.
|
|
@param status: New status of the server.
|
|
@param action: Execute actions after role or status is changed. Default to
|
|
False.
|
|
|
|
@raise ServerActionError: If status is failed to be changed.
|
|
"""
|
|
server_models.validate(status=status)
|
|
if server.status == status:
|
|
raise server_manager_utils.ServerActionError(
|
|
'Server %s already has status of %s.' %
|
|
(server.hostname, status))
|
|
if (not server.roles.all() and
|
|
status == server_models.Server.STATUS.PRIMARY):
|
|
raise server_manager_utils.ServerActionError(
|
|
'Server %s has no role associated. Server must have a role to '
|
|
'be in status primary.' % server.hostname)
|
|
|
|
# Abort the action if the server's status will be changed to primary and
|
|
# the Autotest instance already has another server running an unique role.
|
|
# For example, a scheduler server is already running, and a repair_required
|
|
# server with role scheduler should not be changed to status primary.
|
|
unique_roles = server.roles.filter(
|
|
role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE)
|
|
if unique_roles and status == server_models.Server.STATUS.PRIMARY:
|
|
for role in unique_roles:
|
|
servers = server_models.Server.objects.filter(
|
|
roles__role=role.role,
|
|
status=server_models.Server.STATUS.PRIMARY)
|
|
if len(servers) == 1:
|
|
raise server_manager_utils.ServerActionError(
|
|
'Role %s must be unique. Server %s already has the '
|
|
'role.' % (role.role, servers[0].hostname))
|
|
|
|
# Post a warning if the server's status will be changed from primary to
|
|
# other value and the server is running a unique role across database, e.g.
|
|
# scheduler.
|
|
if server.status == server_models.Server.STATUS.PRIMARY:
|
|
for role in server.get_role_names():
|
|
server_manager_utils.warn_missing_role(role, server)
|
|
|
|
enable = status == server_models.Server.STATUS.PRIMARY
|
|
server_manager_actions.try_execute(server, server.get_role_names(),
|
|
enable=enable, post_change=False,
|
|
do_action=action)
|
|
|
|
prev_status = server.status
|
|
server.status = status
|
|
server.save()
|
|
|
|
# Apply actions to enable/disable roles of the server after the status is
|
|
# changed.
|
|
server_manager_actions.try_execute(server, server.get_role_names(),
|
|
enable=enable, post_change=True,
|
|
prev_status=prev_status,
|
|
do_action=action)
|
|
|
|
print('Status of server %s is changed from %s to %s. Affected roles: %s' %
|
|
(server.hostname, prev_status, status,
|
|
', '.join(server.get_role_names())))
|
|
|
|
|
|
@server_manager_utils.verify_server(exist=False)
|
|
def create(hostname, role=None, note=None):
|
|
"""Create a new server.
|
|
|
|
The status of new server will always be primary.
|
|
|
|
@param hostname: hostname of the server.
|
|
@param role: role of the new server, default to None.
|
|
@param note: notes about the server, default to None.
|
|
|
|
@return: A Server object that contains the server information.
|
|
"""
|
|
server_models.validate(hostname=hostname, role=role)
|
|
server = server_models.Server.objects.create(
|
|
hostname=hostname, status=server_models.Server.STATUS.PRIMARY,
|
|
note=note, date_created=datetime.datetime.now())
|
|
server_models.ServerRole.objects.create(server=server, role=role)
|
|
return server
|
|
|
|
|
|
@server_manager_utils.verify_server()
|
|
def delete(hostname, server=None):
|
|
"""Delete given server from server database.
|
|
|
|
@param hostname: hostname of the server to be deleted.
|
|
@param server: Server object from database query, this argument should be
|
|
injected by the verify_server_exists decorator.
|
|
|
|
@raise ServerActionError: If delete server action failed, e.g., server is
|
|
not found in database.
|
|
"""
|
|
print('Deleting server %s from server database.' % hostname)
|
|
|
|
if (server_manager_utils.use_server_db() and
|
|
server.status == server_models.Server.STATUS.PRIMARY):
|
|
print('Server %s is in status primary, need to disable its '
|
|
'current roles first.' % hostname)
|
|
for role in server.roles.all():
|
|
_delete_role(server, role.role)
|
|
|
|
server.delete()
|
|
print('Server %s is deleted from server database.' % hostname)
|
|
|
|
|
|
@server_manager_utils.verify_server()
|
|
def modify(hostname, role=None, status=None, delete=False, note=None,
|
|
attribute=None, value=None, action=False, server=None):
|
|
"""Modify given server with specified actions.
|
|
|
|
@param hostname: hostname of the server to be modified.
|
|
@param role: Role to be added to the server.
|
|
@param status: Modify server status.
|
|
@param delete: True to delete given role from the server, default to False.
|
|
@param note: Note of the server.
|
|
@param attribute: Name of an attribute of the server.
|
|
@param value: Value of an attribute of the server.
|
|
@param action: Execute actions after role or status is changed. Default to
|
|
False.
|
|
@param server: Server object from database query, this argument should be
|
|
injected by the verify_server_exists decorator.
|
|
|
|
@raise InvalidDataError: If the operation failed with any wrong value of
|
|
the arguments.
|
|
@raise ServerActionError: If any operation failed.
|
|
"""
|
|
if role:
|
|
if not delete:
|
|
_add_role(server, role, action)
|
|
else:
|
|
_delete_role(server, role, action)
|
|
|
|
if status:
|
|
_change_status(server, status, action)
|
|
|
|
if note is not None:
|
|
server.note = note
|
|
server.save()
|
|
|
|
if attribute and value:
|
|
server_manager_utils.change_attribute(server, attribute, value)
|
|
elif attribute and delete:
|
|
server_manager_utils.delete_attribute(server, attribute)
|
|
|
|
return server
|