def testChangeStatusSuccess_PrimaryToRepairFailed(self):
     """Test manager can change the status of a primary server to
     repair_required.
     """
     server_models.validate(
         status=server_models.Server.STATUS.REPAIR_REQUIRED)
     self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'filter')
     self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
     self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
         [server_models.ServerRole.ROLE.DRONE])
     self.PRIMARY_DRONE.roles.filter(
         role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
     ).AndReturn(None)
     server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
     server_manager_utils.warn_missing_role(
         server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
     server_models.Server.objects.filter(
         roles__role=server_models.ServerRole.ROLE.SCHEDULER,
         status=server_models.Server.STATUS.PRIMARY).AndReturn(
             [self.PRIMARY_SCHEDULER])
     infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
     self.mox.ReplayAll()
     server_manager._change_status(
         server=self.PRIMARY_DRONE,
         status=server_models.Server.STATUS.REPAIR_REQUIRED,
         action=True)
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 the server is in status primary and has no role, change its status to
    # backup.
    if (not server.get_role_names()
            and server.status == server_models.Server.STATUS.PRIMARY):
        print(
            'Server %s has no role, change its status from primary to backup' %
            server.hostname)
        server.status = server_models.Server.STATUS.BACKUP
        server.save()

    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 backup 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())))