コード例 #1
0
    def create_worker(self, pinned=True):
        """Create a worker entry at the API."""
        # This method is mostly called from the rpc layer, therefore it checks
        # if it's cleanable given current pinned version.
        if not self.is_cleanable(pinned):
            return False

        resource_type = self.__class__.__name__

        entry_in_db = False

        # This will only loop on very rare race conditions
        while not entry_in_db:
            try:
                # On the common case there won't be an entry in the DB, that's
                # why we try to create first.
                db.worker_create(self._context,
                                 status=self.status,
                                 resource_type=resource_type,
                                 resource_id=self.id)
                entry_in_db = True
            except exception.WorkerExists:
                try:
                    db.worker_update(self._context,
                                     None,
                                     filters={
                                         'resource_type': resource_type,
                                         'resource_id': self.id
                                     },
                                     service_id=None,
                                     status=self.status)
                    entry_in_db = True
                except exception.WorkerNotFound:
                    pass
        return entry_in_db
コード例 #2
0
ファイル: cleanable.py プロジェクト: NetApp/cinder
    def create_worker(self, pinned=True):
        """Create a worker entry at the API."""
        # This method is mostly called from the rpc layer, therefore it checks
        # if it's cleanable given current pinned version.
        if not self.is_cleanable(pinned):
            return False

        resource_type = self.__class__.__name__

        entry_in_db = False

        # This will only loop on very rare race conditions
        while not entry_in_db:
            try:
                # On the common case there won't be an entry in the DB, that's
                # why we try to create first.
                db.worker_create(self._context, status=self.status,
                                 resource_type=resource_type,
                                 resource_id=self.id)
                entry_in_db = True
            except exception.WorkerExists:
                try:
                    db.worker_update(self._context, None,
                                     filters={'resource_type': resource_type,
                                              'resource_id': self.id},
                                     service_id=None,
                                     status=self.status)
                    entry_in_db = True
                except exception.WorkerNotFound:
                    pass
        return entry_in_db
コード例 #3
0
 def test_workers_init_not_supported(self):
     # Fake a Db that doesn't support sub-second resolution in datetimes
     db.worker_update(
         self.ctxt, None,
         {'resource_type': 'SENTINEL', 'ignore_sentinel': False},
         updated_at=datetime.utcnow().replace(microsecond=0))
     db.workers_init()
     self.assertFalse(db.sqlalchemy.api.DB_SUPPORTS_SUBSECOND_RESOLUTION)
コード例 #4
0
ファイル: test_db_worker_api.py プロジェクト: makr123/cinder
 def test_workers_init_not_supported(self):
     # Fake a Db that doesn't support sub-second resolution in datetimes
     db.worker_update(self.ctxt,
                      None, {
                          'resource_type': 'SENTINEL',
                          'ignore_sentinel': False
                      },
                      updated_at=datetime.utcnow().replace(microsecond=0))
     db.workers_init()
     self.assertFalse(db.sqlalchemy.api.DB_SUPPORTS_SUBSECOND_RESOLUTION)
コード例 #5
0
    def set_worker(self):
        worker = self.worker

        service_id = service.Service.service_id
        resource_type = self.__class__.__name__

        if worker:
            if worker.cleaning:
                return
        else:
            try:
                worker = db.worker_get(self._context,
                                       resource_type=resource_type,
                                       resource_id=self.id)
            except exception.WorkerNotFound:
                # If the call didn't come from an RPC call we still have to
                # create the entry in the DB.
                try:
                    self.worker = db.worker_create(self._context,
                                                   status=self.status,
                                                   resource_type=resource_type,
                                                   resource_id=self.id,
                                                   service_id=service_id)
                    return
                except exception.WorkerExists:
                    # If 2 cleanable operations are competing for this resource
                    # and the other one created the entry first that one won
                    raise exception.CleanableInUse(type=resource_type,
                                                   id=self.id)

        # If we have to claim this work or if the status has changed we have
        # to update DB.
        if (worker.service_id != service_id or worker.status != self.status):
            try:
                db.worker_update(self._context,
                                 worker.id,
                                 filters={
                                     'service_id': worker.service_id,
                                     'status': worker.status,
                                     'race_preventer': worker.race_preventer,
                                     'updated_at': worker.updated_at
                                 },
                                 service_id=service_id,
                                 status=self.status,
                                 orm_worker=worker)
            except exception.WorkerNotFound:
                self.worker = None
                raise exception.CleanableInUse(type=self.__class__.__name__,
                                               id=self.id)
        self.worker = worker
コード例 #6
0
ファイル: cleanable.py プロジェクト: ebalduf/cinder-backports
    def set_worker(self):
        worker = self.worker

        service_id = service.Service.service_id
        resource_type = self.__class__.__name__

        if worker:
            if worker.cleaning:
                return
        else:
            try:
                worker = db.worker_get(self._context,
                                       resource_type=resource_type,
                                       resource_id=self.id)
            except exception.WorkerNotFound:
                # If the call didn't come from an RPC call we still have to
                # create the entry in the DB.
                try:
                    self.worker = db.worker_create(self._context,
                                                   status=self.status,
                                                   resource_type=resource_type,
                                                   resource_id=self.id,
                                                   service_id=service_id)
                    return
                except exception.WorkerExists:
                    # If 2 cleanable operations are competing for this resource
                    # and the other one created the entry first that one won
                    raise exception.CleanableInUse(type=resource_type,
                                                   id=self.id)

        # If we have to claim this work or if the status has changed we have
        # to update DB.
        if (worker.service_id != service_id or worker.status != self.status):
            try:
                db.worker_update(
                    self._context, worker.id,
                    filters={'service_id': worker.service_id,
                             'status': worker.status,
                             'race_preventer': worker.race_preventer,
                             'updated_at': worker.updated_at},
                    service_id=service_id,
                    status=self.status,
                    orm_worker=worker)
            except exception.WorkerNotFound:
                self.worker = None
                raise exception.CleanableInUse(type=self.__class__.__name__,
                                               id=self.id)
        self.worker = worker
コード例 #7
0
ファイル: test_db_worker_api.py プロジェクト: C2python/cinder
    def test_worker_update_update_orm(self):
        """Test worker update updating the worker orm object."""
        worker = self._create_workers(1)[0]
        res = db.worker_update(self.ctxt, worker.id, orm_worker=worker,
                               service_id=1)
        self.assertEqual(1, res)

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ['updated_at'])
コード例 #8
0
ファイル: test_db_worker_api.py プロジェクト: makr123/cinder
    def test_worker_update(self):
        """Test basic worker update."""
        worker = self._create_workers(1)[0]
        worker = db.worker_get(self.ctxt, id=worker.id)
        res = db.worker_update(self.ctxt, worker.id, service_id=1)
        self.assertEqual(1, res)
        worker.service_id = 1

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ['updated_at'])
コード例 #9
0
ファイル: test_db_worker_api.py プロジェクト: C2python/cinder
    def test_worker_update(self):
        """Test basic worker update."""
        worker = self._create_workers(1)[0]
        worker = db.worker_get(self.ctxt, id=worker.id)
        res = db.worker_update(self.ctxt, worker.id, service_id=1)
        self.assertEqual(1, res)
        worker.service_id = 1

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ['updated_at'])
コード例 #10
0
    def test_worker_update_update_orm(self):
        """Test worker update updating the worker orm object."""
        worker = self._create_workers(1)[0]
        res = db.worker_update(self.ctxt, worker.id, orm_worker=worker, service_id=1)
        self.assertEqual(1, res)

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        # If we are updating the ORM object we don't ignore the update_at field
        # because it will get updated in the ORM instance.
        self._assertEqualObjects(worker, db_worker)
コード例 #11
0
    def test_worker_update_update_orm(self):
        """Test worker update updating the worker orm object."""
        worker = self._create_workers(1)[0]
        res = db.worker_update(self.ctxt,
                               worker.id,
                               orm_worker=worker,
                               service_id=1)
        self.assertEqual(1, res)

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ['updated_at'])
コード例 #12
0
ファイル: test_db_worker_api.py プロジェクト: makr123/cinder
    def test_worker_update_update_orm(self):
        """Test worker update updating the worker orm object."""
        worker = self._create_workers(1)[0]
        res = db.worker_update(self.ctxt,
                               worker.id,
                               orm_worker=worker,
                               service_id=1)
        self.assertEqual(1, res)

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        # If we are updating the ORM object we don't ignore the update_at field
        # because it will get updated in the ORM instance.
        self._assertEqualObjects(worker, db_worker)
コード例 #13
0
ファイル: test_db_worker_api.py プロジェクト: makr123/cinder
    def test_worker_update_no_subsecond(self):
        """Test basic worker update."""
        db.sqlalchemy.api.DB_SUPPORTS_SUBSECOND_RESOLUTION = False
        worker = self._create_workers(1)[0]
        worker = db.worker_get(self.ctxt, id=worker.id)
        now = datetime.utcnow().replace(microsecond=123)
        with mock.patch('oslo_utils.timeutils.utcnow', return_value=now):
            res = db.worker_update(self.ctxt, worker.id, service_id=1)
        self.assertEqual(1, res)
        worker.service_id = 1

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ['updated_at'])
        self.assertEqual(0, db_worker.updated_at.microsecond)
コード例 #14
0
    def test_worker_update_no_subsecond(self):
        """Test basic worker update."""
        db.sqlalchemy.api.DB_SUPPORTS_SUBSECOND_RESOLUTION = False
        worker = self._create_workers(1)[0]
        worker = db.worker_get(self.ctxt, id=worker.id)
        now = datetime.utcnow().replace(microsecond=123)
        with mock.patch("oslo_utils.timeutils.utcnow", return_value=now):
            res = db.worker_update(self.ctxt, worker.id, service_id=1)
        self.assertEqual(1, res)
        worker.service_id = 1

        db_worker = db.worker_get(self.ctxt, id=worker.id)
        self._assertEqualObjects(worker, db_worker, ["updated_at"])
        self.assertEqual(0, db_worker.updated_at.microsecond)
コード例 #15
0
    def do_cleanup(self, context, cleanup_request):
        LOG.info('Initiating service %s cleanup', cleanup_request.service_id)

        # If the 'until' field in the cleanup request is not set, we default to
        # this very moment.
        until = cleanup_request.until or timeutils.utcnow()
        keep_entry = False

        to_clean = db.worker_get_all(
            context,
            resource_type=cleanup_request.resource_type,
            resource_id=cleanup_request.resource_id,
            service_id=cleanup_request.service_id,
            until=until)

        for clean in to_clean:
            original_service_id = clean.service_id
            original_time = clean.updated_at
            # Try to do a soft delete to mark the entry as being cleaned up
            # by us (setting service id to our service id).
            res = db.worker_claim_for_cleanup(context,
                                              claimer_id=self.service_id,
                                              orm_worker=clean)

            # Claim may fail if entry is being cleaned by another service, has
            # been removed (finished cleaning) by another service or the user
            # started a new cleanable operation.
            # In any of these cases we don't have to do cleanup or remove the
            # worker entry.
            if not res:
                continue

            # Try to get versioned object for resource we have to cleanup
            try:
                vo_cls = getattr(objects, clean.resource_type)
                vo = vo_cls.get_by_id(context, clean.resource_id)
                # Set the worker DB entry in the VO and mark it as being a
                # clean operation
                clean.cleaning = True
                vo.worker = clean
            except exception.NotFound:
                LOG.debug('Skipping cleanup for non existent %(type)s %(id)s.',
                          {
                              'type': clean.resource_type,
                              'id': clean.resource_id
                          })
            else:
                # Resource status should match
                if vo.status != clean.status:
                    LOG.debug(
                        'Skipping cleanup for mismatching work on '
                        '%(type)s %(id)s: %(exp_sts)s <> %(found_sts)s.', {
                            'type': clean.resource_type,
                            'id': clean.resource_id,
                            'exp_sts': clean.status,
                            'found_sts': vo.status
                        })
                else:
                    LOG.info(
                        'Cleaning %(type)s with id %(id)s and status '
                        '%(status)s', {
                            'type': clean.resource_type,
                            'id': clean.resource_id,
                            'status': clean.status
                        },
                        resource=vo)
                    try:
                        # Some cleanup jobs are performed asynchronously, so
                        # we don't delete the worker entry, they'll take care
                        # of it
                        keep_entry = self._do_cleanup(context, vo)
                    except Exception:
                        LOG.exception('Could not perform cleanup.')
                        # Return the worker DB entry to the original service
                        db.worker_update(context,
                                         clean.id,
                                         service_id=original_service_id,
                                         updated_at=original_time)
                        continue

            # The resource either didn't exist or was properly cleaned, either
            # way we can remove the entry from the worker table if the cleanup
            # method doesn't want to keep the entry (for example for delayed
            # deletion).
            if not keep_entry and not db.worker_destroy(context, id=clean.id):
                LOG.warning('Could not remove worker entry %s.', clean.id)

        LOG.info('Service %s cleanup completed.', cleanup_request.service_id)
コード例 #16
0
ファイル: manager.py プロジェクト: ebalduf/cinder-backports
    def do_cleanup(self, context, cleanup_request):
        LOG.info('Initiating service %s cleanup',
                 cleanup_request.service_id)

        # If the 'until' field in the cleanup request is not set, we default to
        # this very moment.
        until = cleanup_request.until or timeutils.utcnow()
        keep_entry = False

        to_clean = db.worker_get_all(
            context,
            resource_type=cleanup_request.resource_type,
            resource_id=cleanup_request.resource_id,
            service_id=cleanup_request.service_id,
            until=until)

        for clean in to_clean:
            original_service_id = clean.service_id
            original_time = clean.updated_at
            # Try to do a soft delete to mark the entry as being cleaned up
            # by us (setting service id to our service id).
            res = db.worker_claim_for_cleanup(context,
                                              claimer_id=self.service_id,
                                              orm_worker=clean)

            # Claim may fail if entry is being cleaned by another service, has
            # been removed (finished cleaning) by another service or the user
            # started a new cleanable operation.
            # In any of these cases we don't have to do cleanup or remove the
            # worker entry.
            if not res:
                continue

            # Try to get versioned object for resource we have to cleanup
            try:
                vo_cls = getattr(objects, clean.resource_type)
                vo = vo_cls.get_by_id(context, clean.resource_id)
                # Set the worker DB entry in the VO and mark it as being a
                # clean operation
                clean.cleaning = True
                vo.worker = clean
            except exception.NotFound:
                LOG.debug('Skipping cleanup for non existent %(type)s %(id)s.',
                          {'type': clean.resource_type,
                           'id': clean.resource_id})
            else:
                # Resource status should match
                if vo.status != clean.status:
                    LOG.debug('Skipping cleanup for mismatching work on '
                              '%(type)s %(id)s: %(exp_sts)s <> %(found_sts)s.',
                              {'type': clean.resource_type,
                               'id': clean.resource_id,
                               'exp_sts': clean.status,
                               'found_sts': vo.status})
                else:
                    LOG.info('Cleaning %(type)s with id %(id)s and status '
                             '%(status)s',
                             {'type': clean.resource_type,
                              'id': clean.resource_id,
                              'status': clean.status},
                             resource=vo)
                    try:
                        # Some cleanup jobs are performed asynchronously, so
                        # we don't delete the worker entry, they'll take care
                        # of it
                        keep_entry = self._do_cleanup(context, vo)
                    except Exception:
                        LOG.exception('Could not perform cleanup.')
                        # Return the worker DB entry to the original service
                        db.worker_update(context, clean.id,
                                         service_id=original_service_id,
                                         updated_at=original_time)
                        continue

            # The resource either didn't exist or was properly cleaned, either
            # way we can remove the entry from the worker table if the cleanup
            # method doesn't want to keep the entry (for example for delayed
            # deletion).
            if not keep_entry and not db.worker_destroy(context, id=clean.id):
                LOG.warning('Could not remove worker entry %s.', clean.id)

        LOG.info('Service %s cleanup completed.', cleanup_request.service_id)