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 testAddRoleToPrimarySuccess(self):
        """Test manager can add a role to a primary server successfully.

        Confirm that actions needs to be taken, e.g., restart scheduler for
        new drone to be added.
        """
        server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
        server_manager_utils.check_server(mox.IgnoreArg(),
                                          mox.IgnoreArg()).AndReturn(True)
        server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
        self.mox.StubOutWithMock(self.PRIMARY_SCHEDULER, 'get_role_names')
        self.PRIMARY_SCHEDULER.get_role_names().AndReturn(
            [server_models.ServerRole.ROLE.SCHEDULER])
        server_models.ServerRole.objects.create(
            server=self.PRIMARY_SCHEDULER,
            role=server_models.ServerRole.ROLE.DRONE).AndReturn(
                self.DRONE_ROLE)
        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._add_role(self.PRIMARY_SCHEDULER,
                                 server_models.ServerRole.ROLE.DRONE,
                                 action=True)
    def testDeleteRoleFromPrimarySuccess(self):
        """Test manager can delete a role from a primary server successfully.

        Confirm that database call is made, and actions are taken, e.g.,
        restart scheduler to delete an existing drone.
        """
        server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
        server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
        self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
        self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
            [server_models.ServerRole.ROLE.DRONE])

        self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
        self.PRIMARY_DRONE.roles.get(
            role=server_models.ServerRole.ROLE.DRONE).AndReturn(
                self.DRONE_ROLE)

        server_models.Server.objects.filter(
            roles__role=server_models.ServerRole.ROLE.SCHEDULER,
            status=server_models.Server.STATUS.PRIMARY).AndReturn(
                [self.PRIMARY_SCHEDULER])
        server_manager.server_manager_utils.warn_missing_role(
            server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
        infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
        self.mox.ReplayAll()
        server_manager._delete_role(self.PRIMARY_DRONE,
                                    server_models.ServerRole.ROLE.DRONE,
                                    action=True)
 def testChangeStatusFail_StatusNoChange(self):
     """Test manager cannot change the status of a server with the same
     status.
     """
     server_models.validate(status=server_models.Server.STATUS.BACKUP)
     self.mox.ReplayAll()
     self.assertRaises(server_manager_utils.ServerActionError,
                       server_manager._change_status,
                       server=self.BACKUP_DRONE,
                       status=server_models.Server.STATUS.BACKUP,
                       action=True)
 def testAddRoleToBackupFail_RoleAlreadyExists(self):
     """Test manager fails to add a role to a backup server if server already
     has the given role.
     """
     server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
     self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
     self.BACKUP_DRONE.get_role_names().AndReturn(
         [server_models.ServerRole.ROLE.DRONE])
     self.mox.ReplayAll()
     self.assertRaises(server_manager_utils.ServerActionError,
                       server_manager._add_role,
                       server=self.BACKUP_DRONE,
                       role=server_models.ServerRole.ROLE.DRONE,
                       action=True)
 def testDeleteRoleFromBackupFail_RoleNotExist(self):
     """Test manager fails to delete a role from a backup server if the
     server does not have the given role.
     """
     server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
     self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
     self.BACKUP_DRONE.get_role_names().AndReturn(
         [server_models.ServerRole.ROLE.DRONE])
     self.mox.ReplayAll()
     self.assertRaises(server_manager_utils.ServerActionError,
                       server_manager._delete_role,
                       server=self.BACKUP_DRONE,
                       role=server_models.ServerRole.ROLE.DEVSERVER,
                       action=True)
 def testAddRoleToBackupFail_CheckServerFail(self):
     """Test manager fails to add a role to a backup server if check_server
     is failed.
     """
     server_manager_utils.check_server(mox.IgnoreArg(),
                                       mox.IgnoreArg()).AndReturn(False)
     server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
     self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
     self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
         [server_models.ServerRole.ROLE.DRONE])
     self.mox.ReplayAll()
     self.assertRaises(server_manager_utils.ServerActionError,
                       server_manager._add_role,
                       server=self.BACKUP_DRONE,
                       role=server_models.ServerRole.ROLE.SCHEDULER,
                       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 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
    def testDeleteRoleFromBackupSuccess(self):
        """Test manager can delete a role from a backup server successfully.

        Confirm that database call is made, and no action is taken, e.g.,
        restart scheduler to delete an existing devserver.
        """
        server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
        server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
        self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
        self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
            [server_models.ServerRole.ROLE.DRONE])
        self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'get')
        self.BACKUP_DRONE.roles.get(
            role=server_models.ServerRole.ROLE.DRONE).AndReturn(
                self.DRONE_ROLE)
        self.mox.ReplayAll()
        server_manager._delete_role(server=self.BACKUP_DRONE,
                                    role=server_models.ServerRole.ROLE.DRONE,
                                    action=True)
 def testChangeStatusFail_UniqueInstance(self):
     """Test manager cannot change the status of a server from backup to
     primary if there is already a primary exists for role doesn't allow
     multiple instances.
     """
     server_models.validate(status=server_models.Server.STATUS.PRIMARY)
     self.mox.StubOutWithMock(self.BACKUP_SCHEDULER.roles, 'filter')
     self.BACKUP_SCHEDULER.roles.filter(
         role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
     ).AndReturn(QueriableList([self.SCHEDULER_ROLE]))
     server_models.Server.objects.filter(
         roles__role=self.SCHEDULER_ROLE.role,
         status=server_models.Server.STATUS.PRIMARY).AndReturn(
             QueriableList([self.PRIMARY_SCHEDULER]))
     self.mox.ReplayAll()
     self.assertRaises(server_manager_utils.ServerActionError,
                       server_manager._change_status,
                       server=self.BACKUP_SCHEDULER,
                       status=server_models.Server.STATUS.PRIMARY,
                       action=True)
def create(hostname, role=None, note=None):
    """Create a new server.

    The status of new server will always be backup, user need to call
    atest server modify hostname --status primary
    to set the server's status to 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.BACKUP,
        note=note,
        date_created=datetime.datetime.now())
    server_models.ServerRole.objects.create(server=server, role=role)
    return server
    def testAddRoleToBackupSuccess(self):
        """Test manager can add a role to a backup server successfully.

        Confirm that database call is made, and no action is taken, e.g.,
        restart scheduler to activate a new devserver.
        """
        server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
        server_manager_utils.check_server(mox.IgnoreArg(),
                                          mox.IgnoreArg()).AndReturn(True)
        server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
        self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
        self.BACKUP_DRONE.get_role_names().AndReturn(
            [server_models.ServerRole.ROLE.DRONE])
        server_models.ServerRole.objects.create(
            server=mox.IgnoreArg(),
            role=server_models.ServerRole.ROLE.DEVSERVER).AndReturn(
                self.DRONE_ROLE)
        self.mox.ReplayAll()
        server_manager._add_role(server=self.BACKUP_DRONE,
                                 role=server_models.ServerRole.ROLE.DEVSERVER,
                                 action=True)
 def testChangeStatusSuccess_BackupToPrimary(self):
     """Test manager can change the status of a backup server to primary.
     """
     server_models.validate(status=server_models.Server.STATUS.PRIMARY)
     server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
     self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
     self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
         [server_models.ServerRole.ROLE.DRONE])
     self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'filter')
     self.BACKUP_DRONE.roles.filter(
         role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
     ).AndReturn(None)
     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.BACKUP_DRONE,
         status=server_models.Server.STATUS.PRIMARY,
         action=True)
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 testDeleteRoleFromPrimarySuccess_NoAction(self):
        """Test manager can delete a role from a primary server successfully.

        Confirm that database call is made, and no action is taken as action
        is set to False.
        """
        server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
        server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
        self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
        self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
            [server_models.ServerRole.ROLE.DRONE])

        self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
        self.PRIMARY_DRONE.roles.get(
            role=server_models.ServerRole.ROLE.DRONE).AndReturn(
                self.DRONE_ROLE)

        server_manager.server_manager_utils.warn_missing_role(
            server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
        self.mox.ReplayAll()
        server_manager._delete_role(self.PRIMARY_DRONE,
                                    server_models.ServerRole.ROLE.DRONE,
                                    action=False)
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())))