Example #1
0
    def test_work_cleanup(self, get_mock, vol_clean_mock, sch_clean_mock):
        args = dict(service_id=1, cluster_name='cluster_name', host='host',
                    binary=constants.VOLUME_BINARY, is_up=False, disabled=True,
                    resource_id=fake.VOLUME_ID, resource_type='Volume')

        cluster = objects.Cluster(id=1, name=args['cluster_name'],
                                  binary=constants.VOLUME_BINARY)
        services = [objects.Service(self.context,
                                    id=2, host='hostname',
                                    cluster_name=cluster.name,
                                    binary=constants.VOLUME_BINARY,
                                    cluster=cluster),
                    objects.Service(self.context,
                                    id=3, host='hostname',
                                    cluster_name=None,
                                    binary=constants.SCHEDULER_BINARY),
                    objects.Service(self.context,
                                    id=4, host='hostname',
                                    cluster_name=None,
                                    binary=constants.VOLUME_BINARY)]
        get_mock.return_value = services

        cleanup_request = objects.CleanupRequest(self.context, **args)
        res = self.manager.work_cleanup(self.context, cleanup_request)
        self.assertEqual((services[:2], services[2:]), res)
        self.assertEqual(1, vol_clean_mock.call_count)
        self.assertEqual(1, sch_clean_mock.call_count)
    def test_failover_api_success_multiple_results(self, failover_mock):
        """Succeed to failover multiple services for the same backend."""
        rep_field = fields.ReplicationStatus
        cluster_name = 'mycluster@backend1'
        cluster = objects.Cluster(self.context,
                                  name=cluster_name,
                                  replication_status=rep_field.ENABLED,
                                  binary=constants.VOLUME_BINARY)
        cluster.create()
        services = [
            objects.Service(self.context, host='host1@backend1',
                            cluster_name=cluster_name,
                            replication_status=rep_field.ENABLED,
                            binary=constants.VOLUME_BINARY),
            objects.Service(self.context, host='host2@backend1',
                            cluster_name=cluster_name,
                            replication_status=rep_field.ENABLED,
                            binary=constants.VOLUME_BINARY),
        ]
        services[0].create()
        services[1].create()

        self.volume_api.failover(self.context, None, cluster_name,
                                 mock.sentinel.secondary_id)

        for service in services + [cluster]:
            self.assertEqual(rep_field.ENABLED, service.replication_status)
            service.refresh()
            self.assertEqual(rep_field.FAILING_OVER,
                             service.replication_status)

        failover_mock.assert_called_once_with(self.context, mock.ANY,
                                              mock.sentinel.secondary_id)
        self.assertEqual(services[0].id, failover_mock.call_args[0][1].id)
Example #3
0
    def _from_db_object(context, service, db_service, expected_attrs=None):
        expected_attrs = expected_attrs or []
        for name, field in service.fields.items():
            if ((name == 'uuid' and not db_service.get(name))
                    or name in service.OPTIONAL_FIELDS):
                continue

            value = db_service.get(name)
            if isinstance(field, fields.IntegerField):
                value = value or 0
            elif isinstance(field, fields.DateTimeField):
                value = value or None
            service[name] = value

        service._context = context
        if 'cluster' in expected_attrs:
            db_cluster = db_service.get('cluster')
            # If this service doesn't belong to a cluster the cluster field in
            # the ORM instance will have value of None.
            if db_cluster:
                service.cluster = objects.Cluster(context)
                objects.Cluster._from_db_object(context, service.cluster,
                                                db_cluster)
            else:
                service.cluster = None

        service.obj_reset_changes()

        return service
Example #4
0
    def _ensure_cluster_exists(self, context, service):
        if self.cluster:
            try:
                cluster = objects.Cluster.get_by_id(context, None,
                                                    name=self.cluster,
                                                    binary=self.binary)
                # If the cluster already exists, then the service replication
                # fields must match those of the cluster unless the service
                # is in error status.
                error_states = (fields.ReplicationStatus.ERROR,
                                fields.ReplicationStatus.FAILOVER_ERROR)
                if service.replication_status not in error_states:
                    for attr in ('replication_status', 'active_backend_id',
                                 'frozen'):
                        if getattr(service, attr) != getattr(cluster, attr):
                            setattr(service, attr, getattr(cluster, attr))

            except exception.ClusterNotFound:
                # Since the cluster didn't exist, we copy replication fields
                # from the service.
                cluster = objects.Cluster(
                    context=context,
                    name=self.cluster,
                    binary=self.binary,
                    disabled=service.disabled,
                    replication_status=service.replication_status,
                    active_backend_id=service.active_backend_id,
                    frozen=service.frozen)
                try:
                    cluster.create()

                # Race condition occurred and another service created the
                # cluster, so we can continue as it already exists.
                except exception.ClusterExists:
                    pass
Example #5
0
 def test_cleanup_destination_volume_cluster_cache_hit(self):
     cluster = objects.Cluster(id=1, name='mycluster',
                               binary=constants.VOLUME_BINARY)
     service = objects.Service(id=2, host='hostname',
                               cluster_name=cluster.name,
                               binary=constants.VOLUME_BINARY)
     cluster_cache = {'cinder-volume': {'mycluster': cluster}}
     result = self.manager._cleanup_destination(cluster_cache, service)
     expected = self.manager.volume_api.do_cleanup, cluster, cluster.name
     self.assertEqual(expected, result)
Example #6
0
 def tests_obj_make_compatible(self, version):
     new_fields = {'replication_status': 'error', 'frozen': True,
                   'active_backend_id': 'replication'}
     cluster = objects.Cluster(self.context, **new_fields)
     primitive = cluster.obj_to_primitive(version)
     converted_cluster = objects.Cluster.obj_from_primitive(primitive)
     for key, value in new_fields.items():
         if version == '1.0':
             self.assertFalse(converted_cluster.obj_attr_is_set(key))
         else:
             self.assertEqual(value, getattr(converted_cluster, key))
    def test_lazy_loading_cluster_field(self, cluster_get):
        cluster_orm = fake_cluster.fake_cluster_orm(name='mycluster')
        cluster_get.return_value = cluster_orm
        cluster = objects.Cluster._from_db_object(self.context,
                                                  objects.Cluster(),
                                                  cluster_orm)

        service = fake_service.fake_service_obj(self.context,
                                                cluster_name='mycluster')
        self.assertEqual(cluster, service.cluster)
        cluster_get.assert_called_once_with(self.context, None,
                                            name='mycluster')
Example #8
0
 def test_cleanup_destination_volume_cluster_cache_miss(self, get_mock):
     cluster = objects.Cluster(id=1, name='mycluster',
                               binary=constants.VOLUME_BINARY)
     service = objects.Service(self.context,
                               id=2, host='hostname',
                               cluster_name=cluster.name,
                               binary=constants.VOLUME_BINARY)
     get_mock.return_value = cluster
     cluster_cache = collections.defaultdict(dict)
     result = self.manager._cleanup_destination(cluster_cache, service)
     expected = self.manager.volume_api.do_cleanup, cluster, cluster.name
     self.assertEqual(expected, result)
Example #9
0
    def test_obj_make_compatible_cluster_added(self, version):
        extra_data = {'cluster_name': 'cluster_name',
                      'cluster': objects.Cluster()}
        volume = objects.Volume(self.context, host='host', **extra_data)

        serializer = ovo_base.CinderObjectSerializer(version)
        primitive = serializer.serialize_entity(self.context, volume)

        converted_volume = objects.Volume.obj_from_primitive(primitive)
        is_set = version == '1.7'
        for key in extra_data:
            self.assertEqual(is_set, converted_volume.obj_attr_is_set(key))
        self.assertEqual('host', converted_volume.host)
    def test_ensure_cluster_exists_cluster_exists_non_relicated(self,
                                                                get_mock):
        cluster = objects.Cluster(
            name='cluster_name', active_backend_id=None, frozen=False,
            replication_status=fields.ReplicationStatus.NOT_CAPABLE)
        get_mock.return_value = cluster

        app = service.Service.create(host=self.host,
                                     binary=self.binary,
                                     topic=self.topic)
        svc = objects.Service.get_by_id(self.ctxt, app.service_id)
        app.cluster = cluster.name
        app._ensure_cluster_exists(self.ctxt, svc)
        get_mock.assert_called_once_with(self.ctxt, None, name=cluster.name,
                                         binary=app.binary)
        self.assertEqual({}, svc.cinder_obj_get_changes())
    def test_ensure_cluster_exists_cluster_change(self, get_mock):
        """We copy replication fields from the cluster to the service."""
        changes = dict(replication_status=fields.ReplicationStatus.FAILED_OVER,
                       active_backend_id='secondary',
                       frozen=True)
        cluster = objects.Cluster(name='cluster_name', **changes)
        get_mock.return_value = cluster

        app = service.Service.create(host=self.host,
                                     binary=self.binary,
                                     topic=self.topic)
        svc = objects.Service.get_by_id(self.ctxt, app.service_id)
        app.cluster = cluster.name
        app._ensure_cluster_exists(self.ctxt, svc)
        get_mock.assert_called_once_with(self.ctxt, None, name=cluster.name,
                                         binary=app.binary)
        self.assertEqual(changes, svc.cinder_obj_get_changes())
    def test_failover_api_fail_multiple_results_not_updated(
            self, failover_mock):
        """Fail if none of the services could be updated."""
        rep_field = fields.ReplicationStatus
        cluster_name = 'mycluster@backend1'
        cluster = objects.Cluster(self.context,
                                  name=cluster_name,
                                  replication_status=rep_field.ENABLED,
                                  binary=constants.VOLUME_BINARY)
        cluster.create()
        down_time = timeutils.datetime.datetime(1970, 1, 1)
        services = [
            # This service is down
            objects.Service(self.context,
                            host='host1@backend1',
                            cluster_name=cluster_name,
                            replication_status=rep_field.ENABLED,
                            created_at=down_time,
                            updated_at=down_time,
                            modified_at=down_time,
                            binary=constants.VOLUME_BINARY),
            # This service is not with the right replication status
            objects.Service(self.context,
                            host='host2@backend1',
                            cluster_name=cluster_name,
                            replication_status=rep_field.ERROR,
                            binary=constants.VOLUME_BINARY),
        ]
        services[0].create()
        services[1].create()

        self.assertRaises(exception.InvalidInput, self.volume_api.failover,
                          self.context, None, cluster_name,
                          mock.sentinel.secondary_id)

        for service in services:
            svc = objects.Service.get_by_id(self.context, service.id)
            self.assertEqual(service.replication_status,
                             svc.replication_status)

        cluster.refresh()
        self.assertEqual(rep_field.ENABLED, cluster.replication_status)

        failover_mock.assert_not_called()
Example #13
0
    def _ensure_cluster_exists(self, context, disabled=None):
        if self.cluster:
            try:
                objects.Cluster.get_by_id(context,
                                          None,
                                          name=self.cluster,
                                          binary=self.binary)
            except exception.ClusterNotFound:
                cluster = objects.Cluster(context=context,
                                          name=self.cluster,
                                          binary=self.binary)
                # If disabled has been specified overwrite default value
                if disabled is not None:
                    cluster.disabled = disabled
                try:
                    cluster.create()

                # Race condition occurred and another service created the
                # cluster, so we can continue as it already exists.
                except exception.ClusterExists:
                    pass
Example #14
0
    def _from_db_object(cls,
                        context,
                        consistencygroup,
                        db_consistencygroup,
                        expected_attrs=None):
        if expected_attrs is None:
            expected_attrs = []
        for name, field in consistencygroup.fields.items():
            if name in cls.OPTIONAL_FIELDS:
                continue
            value = db_consistencygroup.get(name)
            setattr(consistencygroup, name, value)

        if 'cgsnapshots' in expected_attrs:
            cgsnapshots = base.obj_make_list(
                context, objects.CGSnapshotList(context), objects.CGSnapshot,
                db_consistencygroup['cgsnapshots'])
            consistencygroup.cgsnapshots = cgsnapshots

        if 'volumes' in expected_attrs:
            volumes = base.obj_make_list(context, objects.VolumeList(context),
                                         objects.Volume,
                                         db_consistencygroup['volumes'])
            consistencygroup.volumes = volumes

        if 'cluster' in expected_attrs:
            db_cluster = db_consistencygroup.get('cluster')
            # If this consistency group doesn't belong to a cluster the cluster
            # field in the ORM instance will have value of None.
            if db_cluster:
                consistencygroup.cluster = objects.Cluster(context)
                objects.Cluster._from_db_object(context,
                                                consistencygroup.cluster,
                                                db_cluster)
            else:
                consistencygroup.cluster = None

        consistencygroup._context = context
        consistencygroup.obj_reset_changes()
        return consistencygroup
Example #15
0
    def _from_db_object(context, service, db_service, expected_attrs=None):
        expected_attrs = expected_attrs or []
        for name, field in service.fields.items():
            if ((name == 'uuid' and not db_service.get(name))
                    or name in service.OPTIONAL_FIELDS):
                continue

            value = db_service.get(name)
            if isinstance(field, fields.IntegerField):
                value = value or 0
            elif isinstance(field, fields.DateTimeField):
                value = value or None
            service[name] = value

        service._context = context
        if 'cluster' in expected_attrs:
            db_cluster = db_service.get('cluster')
            # If this service doesn't belong to a cluster the cluster field in
            # the ORM instance will have value of None.
            if db_cluster:
                service.cluster = objects.Cluster(context)
                objects.Cluster._from_db_object(context, service.cluster,
                                                db_cluster)
            else:
                service.cluster = None

        service.obj_reset_changes()

        # TODO(jdg): Remove in S when we're sure all Services have UUID in db
        if 'uuid' not in service:
            service.uuid = uuidutils.generate_uuid()
            LOG.debug('Generated UUID %(uuid)s for service %(id)i',
                      dict(uuid=service.uuid, id=service.id))
            service.save()

        return service
Example #16
0
def fake_cluster_ovo(context, **updates):
    """Create a fake Cluster versioned object."""
    return objects.Cluster._from_db_object(context, objects.Cluster(),
                                           fake_cluster_orm(**updates))
Example #17
0
    def _from_db_object(cls, context, volume, db_volume, expected_attrs=None):
        if expected_attrs is None:
            expected_attrs = []
        for name, field in volume.fields.items():
            if name in cls.OPTIONAL_FIELDS:
                continue
            value = db_volume.get(name)
            if isinstance(field, fields.IntegerField):
                value = value or 0
            volume[name] = value

        # Get data from db_volume object that was queried by joined query
        # from DB
        if 'metadata' in expected_attrs:
            metadata = db_volume.get('volume_metadata', [])
            volume.metadata = {item['key']: item['value'] for item in metadata}
        if 'admin_metadata' in expected_attrs:
            metadata = db_volume.get('volume_admin_metadata', [])
            volume.admin_metadata = {item['key']: item['value']
                                     for item in metadata}
        if 'glance_metadata' in expected_attrs:
            metadata = db_volume.get('volume_glance_metadata', [])
            volume.glance_metadata = {item['key']: item['value']
                                      for item in metadata}
        if 'volume_type' in expected_attrs:
            db_volume_type = db_volume.get('volume_type')
            if db_volume_type:
                vt_expected_attrs = []
                if 'volume_type.extra_specs' in expected_attrs:
                    vt_expected_attrs.append('extra_specs')
                volume.volume_type = objects.VolumeType._from_db_object(
                    context, objects.VolumeType(), db_volume_type,
                    expected_attrs=vt_expected_attrs)
        if 'volume_attachment' in expected_attrs:
            attachments = base.obj_make_list(
                context, objects.VolumeAttachmentList(context),
                objects.VolumeAttachment,
                db_volume.get('volume_attachment'))
            volume.volume_attachment = attachments
        if volume.consistencygroup_id and 'consistencygroup' in expected_attrs:
            consistencygroup = objects.ConsistencyGroup(context)
            consistencygroup._from_db_object(context,
                                             consistencygroup,
                                             db_volume['consistencygroup'])
            volume.consistencygroup = consistencygroup
        if 'snapshots' in expected_attrs:
            snapshots = base.obj_make_list(
                context, objects.SnapshotList(context),
                objects.Snapshot,
                db_volume['snapshots'])
            volume.snapshots = snapshots
        if 'cluster' in expected_attrs:
            db_cluster = db_volume.get('cluster')
            # If this volume doesn't belong to a cluster the cluster field in
            # the ORM instance will have value of None.
            if db_cluster:
                volume.cluster = objects.Cluster(context)
                objects.Cluster._from_db_object(context, volume.cluster,
                                                db_cluster)
            else:
                volume.cluster = None
        if volume.group_id and 'group' in expected_attrs:
            group = objects.Group(context)
            group._from_db_object(context,
                                  group,
                                  db_volume['group'])
            volume.group = group

        volume._context = context
        volume.obj_reset_changes()
        return volume
Example #18
0
 def test_create(self, cluster_create_mock):
     cluster = objects.Cluster(context=self.context, name='cluster_name')
     cluster.create()
     self.assertEqual(self.cluster.id, cluster.id)
     cluster_create_mock.assert_called_once_with(self.context,
                                                 {'name': 'cluster_name'})