# 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.

"""


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
