def test_connections_lazy_loading_from_ovo(self, get_all_mock): """Test we don't reload connections if data is in OVO.""" vol = objects.Volume(self.backend, size=10) vol._connections = None delattr(vol._ovo, '_obj_volume_attachment') conns = [objects.Connection(self.backend, connector={'k': 'v'}, volume_id=vol.id, status='attached', attach_mode='rw', connection_info={'conn': {}}, name='my_snap')] ovo_conns = [conn._ovo for conn in conns] ovo_attach_list = cinder_ovos.VolumeAttachmentList(objects=ovo_conns) get_all_mock.return_value = ovo_attach_list mock_get_conns = self.persistence.get_connections ovo_result = vol._ovo.volume_attachment mock_get_conns.not_called() self.assertEqual(ovo_attach_list, ovo_result) # Cinderlib object doesn't have the connections yet self.assertIsNone(vol._connections) self.assertEqual(1, len(vol._ovo.volume_attachment)) self.assertEqual(vol._ovo.volume_attachment[0], ovo_result[0]) # There is no second call when we access the cinderlib object, as the # data is retrieved from the OVO that already has it result = vol.connections mock_get_conns.not_called() # Confirm we used the OVO self.assertIs(ovo_conns[0], result[0]._ovo)
def _from_db_object(context, volume, db_volume, expected_attrs=None): if expected_attrs is None: expected_attrs = [] for name, field in volume.fields.items(): if name in Volume.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 '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 volume._context = context volume.obj_reset_changes() return volume
def connections(self): # Lazy loading if self._connections is None: self._connections = self.persistence.get_connections( volume_id=self.id) for conn in self._connections: conn.volume = self ovos = [conn._ovo for conn in self._connections] setattr(self._ovo, CONNECTIONS_OVO_FIELD, cinder_objs.VolumeAttachmentList(objects=ovos)) self._ovo.obj_reset_changes((CONNECTIONS_OVO_FIELD, )) return self._connections
def test_view_get_attachments(self): fake_volume = self._fake_create_volume() fake_volume['attach_status'] = fields.VolumeAttachStatus.ATTACHING att_time = datetime.datetime(2017, 8, 31, 21, 55, 7, tzinfo=iso8601.UTC) a1 = { 'id': fake.UUID1, 'volume_id': fake.UUID2, 'instance': None, 'attached_host': None, 'mountpoint': None, 'attach_time': None, 'attach_status': fields.VolumeAttachStatus.ATTACHING } a2 = { 'id': fake.UUID3, 'volume_id': fake.UUID4, 'instance_uuid': fake.UUID5, 'attached_host': 'host1', 'mountpoint': 'na', 'attach_time': att_time, 'attach_status': fields.VolumeAttachStatus.ATTACHED } attachment1 = objects.VolumeAttachment(self.ctxt, **a1) attachment2 = objects.VolumeAttachment(self.ctxt, **a2) atts = {'objects': [attachment1, attachment2]} attachments = objects.VolumeAttachmentList(self.ctxt, **atts) fake_volume['volume_attachment'] = attachments # get_attachments should only return attachments with the # attached status = ATTACHED attachments = ViewBuilder()._get_attachments(fake_volume) self.assertEqual(1, len(attachments)) self.assertEqual(fake.UUID3, attachments[0]['attachment_id']) self.assertEqual(fake.UUID4, attachments[0]['volume_id']) self.assertEqual(fake.UUID5, attachments[0]['server_id']) self.assertEqual('host1', attachments[0]['host_name']) self.assertEqual('na', attachments[0]['device']) self.assertEqual(att_time, attachments[0]['attached_at'])
def _from_db_object(context, volume, db_volume, expected_attrs=None): if expected_attrs is None: expected_attrs = [] for name, field in volume.fields.items(): if name in 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: volume.metadata = {} metadata = db_volume.get('volume_metadata', []) if metadata: volume.metadata = { item['key']: item['value'] for item in metadata } if 'admin_metadata' in expected_attrs: volume.admin_metadata = {} metadata = db_volume.get('volume_admin_metadata', []) if metadata: volume.admin_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: volume.volume_type = objects.VolumeType._from_db_object( context, objects.VolumeType(), db_volume_type, expected_attrs='extra_specs') 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.objects volume._context = context volume.obj_reset_changes() return volume
def test_obj_load_attr(self, mock_va_get_all_by_vol, mock_vt_get_by_id, mock_admin_metadata_get, mock_metadata_get): volume = objects.Volume._from_db_object(self.context, objects.Volume(), fake_volume.fake_db_volume()) # Test metadata lazy-loaded field metadata = {'foo': 'bar'} mock_metadata_get.return_value = metadata self.assertEqual(metadata, volume.metadata) mock_metadata_get.assert_called_once_with(self.context, volume.id) # Test volume_type lazy-loaded field volume_type = objects.VolumeType(context=self.context, id=5) mock_vt_get_by_id.return_value = volume_type self.assertEqual(volume_type, volume.volume_type) mock_vt_get_by_id.assert_called_once_with(self.context, volume.volume_type_id) # Test volume_attachment lazy-loaded field va_objs = [ objects.VolumeAttachment(context=self.context, id=i) for i in [3, 4, 5] ] va_list = objects.VolumeAttachmentList(context=self.context, objects=va_objs) mock_va_get_all_by_vol.return_value = va_list self.assertEqual(va_list, volume.volume_attachment) mock_va_get_all_by_vol.assert_called_once_with(self.context, volume.id) # Test admin_metadata lazy-loaded field - user context adm_metadata = {'bar': 'foo'} mock_admin_metadata_get.return_value = adm_metadata self.assertEqual({}, volume.admin_metadata) self.assertFalse(mock_admin_metadata_get.called) # Test admin_metadata lazy-loaded field - admin context adm_context = self.context.elevated() volume = objects.Volume._from_db_object(adm_context, objects.Volume(), fake_volume.fake_db_volume()) adm_metadata = {'bar': 'foo'} mock_admin_metadata_get.return_value = adm_metadata self.assertEqual(adm_metadata, volume.admin_metadata) mock_admin_metadata_get.assert_called_once_with(adm_context, volume.id)
def test_volume_detached_with_attachment(self, volume_attachment_get, volume_detached, metadata_delete): va_objs = [ objects.VolumeAttachment(context=self.context, id=i) for i in [fake.OBJECT_ID, fake.OBJECT2_ID, fake.OBJECT3_ID] ] # As changes are not saved, we need reset it here. Later changes # will be checked. for obj in va_objs: obj.obj_reset_changes() va_list = objects.VolumeAttachmentList(context=self.context, objects=va_objs) va_list.obj_reset_changes() volume_attachment_get.return_value = va_list admin_context = context.get_admin_context() volume = fake_volume.fake_volume_obj(admin_context, volume_attachment=va_list, volume_admin_metadata=[{ 'key': 'attached_mode', 'value': 'rw' }]) self.assertEqual(3, len(volume.volume_attachment)) volume_detached.return_value = ({ 'status': 'in-use' }, { 'attached_mode': 'rw' }) with mock.patch.object(admin_context, 'elevated') as mock_elevated: mock_elevated.return_value = admin_context volume.finish_detach(fake.OBJECT_ID) volume_detached.assert_called_once_with(admin_context, volume.id, fake.OBJECT_ID) metadata_delete.assert_called_once_with(admin_context, volume.id, 'attached_mode') self.assertEqual('in-use', volume.status) self.assertEqual({}, volume.cinder_obj_get_changes()) self.assertEqual(2, len(volume.volume_attachment)) self.assertIsNone(volume.admin_metadata.get('attached_mode'))
def connections(self): # Lazy loading if self._connections is None: # Check if the driver has already lazy loaded it using OVOs if self._ovo.obj_attr_is_set(CONNECTIONS_OVO_FIELD): conns = [Connection(None, volume=self, __ovo=ovo) for ovo in getattr(self._ovo, CONNECTIONS_OVO_FIELD).objects] # Retrieve data from persistence storage else: conns = self.persistence.get_connections(volume_id=self.id) for conn in conns: conn.volume = self ovos = [conn._ovo for conn in conns] setattr(self._ovo, CONNECTIONS_OVO_FIELD, cinder_objs.VolumeAttachmentList(objects=ovos)) self._ovo.obj_reset_changes((CONNECTIONS_OVO_FIELD,)) self._connections = conns return self._connections
def test_obj_load_attr(self, mock_sl_get_all_for_volume, mock_cg_get_by_id, mock_va_get_all_by_vol, mock_vt_get_by_id, mock_admin_metadata_get, mock_glance_metadata_get, mock_metadata_get): volume = objects.Volume._from_db_object(self.context, objects.Volume(), fake_volume.fake_db_volume()) # Test metadata lazy-loaded field metadata = {'foo': 'bar'} mock_metadata_get.return_value = metadata self.assertEqual(metadata, volume.metadata) mock_metadata_get.assert_called_once_with(self.context, volume.id) # Test glance_metadata lazy-loaded field glance_metadata = [{'key': 'foo', 'value': 'bar'}] mock_glance_metadata_get.return_value = glance_metadata self.assertEqual({'foo': 'bar'}, volume.glance_metadata) mock_glance_metadata_get.assert_called_once_with( self.context, volume.id) # Test volume_type lazy-loaded field # Case1. volume.volume_type_id = None self.assertIsNone(volume.volume_type) # Case2. volume2.volume_type_id = 1 fake2 = fake_volume.fake_db_volume() fake2.update({'volume_type_id': fake.volume_id}) volume2 = objects.Volume._from_db_object(self.context, objects.Volume(), fake2) volume_type = objects.VolumeType(context=self.context, id=fake.volume_type_id) mock_vt_get_by_id.return_value = volume_type self.assertEqual(volume_type, volume2.volume_type) mock_vt_get_by_id.assert_called_once_with(self.context, volume2.volume_type_id) # Test consistencygroup lazy-loaded field consistencygroup = objects.ConsistencyGroup( context=self.context, id=fake.consistency_group_id) mock_cg_get_by_id.return_value = consistencygroup self.assertEqual(consistencygroup, volume.consistencygroup) mock_cg_get_by_id.assert_called_once_with(self.context, volume.consistencygroup_id) # Test snapshots lazy-loaded field snapshots = objects.SnapshotList(context=self.context, id=fake.snapshot_id) mock_sl_get_all_for_volume.return_value = snapshots self.assertEqual(snapshots, volume.snapshots) mock_sl_get_all_for_volume.assert_called_once_with( self.context, volume.id) # Test volume_attachment lazy-loaded field va_objs = [ objects.VolumeAttachment(context=self.context, id=i) for i in [fake.object_id, fake.object2_id, fake.object3_id] ] va_list = objects.VolumeAttachmentList(context=self.context, objects=va_objs) mock_va_get_all_by_vol.return_value = va_list self.assertEqual(va_list, volume.volume_attachment) mock_va_get_all_by_vol.assert_called_once_with(self.context, volume.id) # Test admin_metadata lazy-loaded field - user context adm_metadata = {'bar': 'foo'} mock_admin_metadata_get.return_value = adm_metadata self.assertEqual({}, volume.admin_metadata) self.assertFalse(mock_admin_metadata_get.called) # Test admin_metadata lazy-loaded field - admin context adm_context = self.context.elevated() volume = objects.Volume._from_db_object(adm_context, objects.Volume(), fake_volume.fake_db_volume()) adm_metadata = {'bar': 'foo'} mock_admin_metadata_get.return_value = adm_metadata self.assertEqual(adm_metadata, volume.admin_metadata) mock_admin_metadata_get.assert_called_once_with(adm_context, volume.id)
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
def __init__(self, backend_or_vol, pool_name=None, **kwargs): # Accept backend name for convenience if isinstance(backend_or_vol, six.string_types): backend_name = backend_or_vol backend_or_vol = self._get_backend(backend_or_vol) elif isinstance(backend_or_vol, self.backend_class): backend_name = backend_or_vol.id elif isinstance(backend_or_vol, Volume): backend_str, pool = backend_or_vol._ovo.host.split('#') backend_name = backend_str.split('@')[-1] pool_name = pool_name or pool for key in backend_or_vol._ovo.fields: if (backend_or_vol._ovo.obj_attr_is_set(key) and key not in self._ignore_keys): kwargs.setdefault(key, getattr(backend_or_vol._ovo, key)) if backend_or_vol.volume_type: kwargs.setdefault('extra_specs', backend_or_vol.volume_type.extra_specs) if backend_or_vol.volume_type.qos_specs: kwargs.setdefault( 'qos_specs', backend_or_vol.volume_type.qos_specs.specs) backend_or_vol = backend_or_vol.backend if '__ovo' not in kwargs: kwargs[CONNECTIONS_OVO_FIELD] = (cinder_objs.VolumeAttachmentList( context=self.CONTEXT)) kwargs['snapshots'] = (cinder_objs.SnapshotList( context=self.CONTEXT)) self._snapshots = [] self._connections = [] qos_specs = kwargs.pop('qos_specs', None) extra_specs = kwargs.pop('extra_specs', {}) super(Volume, self).__init__(backend_or_vol, **kwargs) self._populate_data() self.local_attach = None # If we overwrote the host, then we ignore pool_name and don't set a # default value or copy the one from the source either. if 'host' not in kwargs and '__ovo' not in kwargs: # TODO(geguileo): Add pool support pool_name = pool_name or backend_or_vol.pool_names[0] self._ovo.host = ('%s@%s#%s' % (cfg.CONF.host, backend_name, pool_name)) if qos_specs or extra_specs: if qos_specs: qos_specs = cinder_objs.QualityOfServiceSpecs( id=self.id, name=self.id, consumer='back-end', specs=qos_specs) qos_specs_id = self.id else: qos_specs = qos_specs_id = None self._ovo.volume_type = cinder_objs.VolumeType( context=self.CONTEXT, is_public=True, id=self.id, name=self.id, qos_specs_id=qos_specs_id, extra_specs=extra_specs, qos_specs=qos_specs) self._ovo.volume_type_id = self.id
def __connections_get(self, context, volume_id): # Used by drivers to lazy load volume_attachment connections = self.persistence.get_connections(volume_id=volume_id) ovos = [conn._ovo for conn in connections] result = objects.VolumeAttachmentList(objects=ovos) return result