def test_negative_create_snapshot_conflict(self, mock_req): ctxt = context.get_admin_context() extra_specs = { "Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick" } type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = { 'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000' } qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) SNAPSHOT1['volume_type_id'] = type_ref['id'] mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_409_CONFLICT_RESP ]) self.configuration.ise_completion_retries = 1 self.setup_driver() self.assertRaises(exception.XIODriverException, self.driver.create_snapshot, SNAPSHOT1)
def test_retype_volume(self, mock_req): ctxt = context.get_admin_context() extra_specs = {"Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = {'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000'} qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) VOLUME1['volume_type_id'] = type_ref['id'] # New volume type extra_specs = {"Feature:Pool": "1", "Feature:Raid": "5", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT2', extra_specs) specs = {'qos:minIOPS': '30', 'qos:maxIOPS': '3000', 'qos:burstIOPS': '10000'} qos = qos_specs.create(ctxt, 'fake-qos2', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_MODIFY_VOLUME_RESP]) self.setup_driver() self.driver.retype(ctxt, VOLUME1, type_ref, 0, 0)
def test_disassociate_all(self): def fake_db_disassociate_all(context, id): if id == 'Trouble': raise db_exc.DBError() pass def fake_qos_specs_get(context, id): if id == 'NotFound': raise exception.QoSSpecsNotFound(specs_id=id) else: pass type1_ref = volume_types.create(self.ctxt, 'TypeName1') type2_ref = volume_types.create(self.ctxt, 'TypeName2') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type1_ref['id']) qos_specs.associate_qos_with_type(self.ctxt, specs_id, type2_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(2, len(res)) qos_specs.disassociate_all(self.ctxt, specs_id) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(0, len(res)) self.stubs.Set(db, 'qos_specs_disassociate_all', fake_db_disassociate_all) self.stubs.Set(qos_specs, 'get_qos_specs', fake_qos_specs_get) self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_all, self.ctxt, 'Trouble')
def test_create_volume_chap(self, mock_req): ctxt = context.get_admin_context() extra_specs = { "Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick" } type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = { 'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000' } qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) VOLUME1['volume_type_id'] = type_ref['id'] self.setup_driver() if self.configuration.ise_protocol == 'iscsi': mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_CREATE_VOLUME_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_GET_IONETWORKS_CHAP_RESP ]) exp_result = {} exp_result = {"provider_auth": "CHAP abc abc"} act_result = self.driver.create_volume(VOLUME1) self.assertDictMatch(exp_result, act_result) elif self.configuration.ise_protocol == 'fibre_channel': mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_CREATE_VOLUME_RESP, ISE_GET_VOL1_STATUS_RESP ]) self.driver.create_volume(VOLUME1)
def test_negative_create_snapshot_invalid_state_recover(self, mock_req): ctxt = context.get_admin_context() extra_specs = { "Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick" } type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = { 'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000' } qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) SNAPSHOT1['volume_type_id'] = type_ref['id'] mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_400_INVALID_STATE_RESP, ISE_PREP_SNAPSHOT_RESP, ISE_GET_SNAP1_STATUS_RESP, ISE_CREATE_SNAPSHOT_RESP, ISE_GET_SNAP1_STATUS_RESP ]) self.setup_driver() self.driver.create_snapshot(SNAPSHOT1)
def test_disassociate_qos_specs(self): def fake_db_disassociate(context, id, type_id): if id == 'Trouble': raise db_exc.DBError() elif type_id == 'NotFound': raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEquals(len(res[specs_id].keys()), 1) qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEquals(len(res[specs_id].keys()), 0) self.stubs.Set(db, 'qos_specs_disassociate', fake_db_disassociate) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.disassociate_qos_specs, self.ctxt, 'specs-id', 'NotFound') self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_qos_specs, self.ctxt, 'Trouble', 'id')
def test_disassociate_all(self): def fake_db_disassociate_all(context, id): if id == 'Trouble': raise db_exc.DBError() pass type1_ref = volume_types.create(self.ctxt, 'TypeName1') type2_ref = volume_types.create(self.ctxt, 'TypeName2') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type1_ref['id']) qos_specs.associate_qos_with_type(self.ctxt, specs_id, type2_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEquals(len(res[specs_id].keys()), 2) qos_specs.disassociate_all(self.ctxt, specs_id) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEquals(len(res[specs_id].keys()), 0) self.stubs.Set(db, 'qos_specs_disassociate_all', fake_db_disassociate_all) self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_all, self.ctxt, 'Trouble')
def test_create_volume_chap(self, mock_req): ctxt = context.get_admin_context() extra_specs = {"Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = {'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000'} qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) VOLUME1['volume_type_id'] = type_ref['id'] self.setup_driver() if self.configuration.ise_protocol == 'iscsi': mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_CREATE_VOLUME_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_GET_IONETWORKS_CHAP_RESP]) exp_result = {} exp_result = {"provider_auth": "CHAP abc abc"} act_result = self.driver.create_volume(VOLUME1) self.assertDictMatch(exp_result, act_result) elif self.configuration.ise_protocol == 'fibre_channel': mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_CREATE_VOLUME_RESP, ISE_GET_VOL1_STATUS_RESP]) self.driver.create_volume(VOLUME1)
def test_get_volume_type_qos_specs(self): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', { 'k1': 'v1', 'k2': 'v2', 'k3': 'v3' }) type_ref = volume_types.create(self.ctxt, "type1", { "key2": "val2", "key3": "val3" }) res = volume_types.get_volume_type_qos_specs(type_ref['id']) self.assertIsNone(res['qos_specs']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected = { 'qos_specs': { 'id': qos_ref['id'], 'name': 'qos-specs-1', 'consumer': 'back-end', 'specs': { 'k1': 'v1', 'k2': 'v2', 'k3': 'v3' } } } res = volume_types.get_volume_type_qos_specs(type_ref['id']) self.assertDictMatch(expected, res)
def test_disassociate_qos_specs(self): def fake_db_disassociate(context, id, type_id): raise db_exc.DBError() type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(1, len(res)) qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(0, len(res)) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.disassociate_qos_specs, self.ctxt, specs_id, 'NotFound') # Verify we can disassociate specs from volume_type even if they are # not associated with no error qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) self.mock_object(db, 'qos_specs_disassociate', fake_db_disassociate) self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_qos_specs, self.ctxt, specs_id, type_ref['id'])
def test_disassociate_qos_specs(self): def fake_qos_specs_get(context, id): if id == 'NotFound': raise exception.QoSSpecsNotFound(specs_id=id) else: pass def fake_db_disassociate(context, id, type_id): if id == 'Trouble': raise db_exc.DBError() elif type_id == 'NotFound': raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(len(res), 1) qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(len(res), 0) self.stubs.Set(db, 'qos_specs_disassociate', fake_db_disassociate) self.stubs.Set(qos_specs, 'get_qos_specs', fake_qos_specs_get) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.disassociate_qos_specs, self.ctxt, 'specs-id', 'NotFound') self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_qos_specs, self.ctxt, 'Trouble', 'id')
def test_disassociate_qos_specs(self): def fake_db_disassociate(context, id, type_id): raise db_exc.DBError() type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(1, len(res)) qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(0, len(res)) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.disassociate_qos_specs, self.ctxt, specs_id, 'NotFound') # Verify we can disassociate specs from volume_type even if they are # not associated with no error qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id']) qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) self.stubs.Set(db, 'qos_specs_disassociate', fake_db_disassociate) self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_qos_specs, self.ctxt, specs_id, type_ref['id'])
def test_disassociate_all(self): def fake_db_disassociate_all(context, id): if id == "Trouble": raise db_exc.DBError() pass def fake_qos_specs_get(context, id): if id == "NotFound": raise exception.QoSSpecsNotFound(specs_id=id) else: pass type1_ref = volume_types.create(self.ctxt, "TypeName1") type2_ref = volume_types.create(self.ctxt, "TypeName2") specs_id = self._create_qos_specs("QoSName") qos_specs.associate_qos_with_type(self.ctxt, specs_id, type1_ref["id"]) qos_specs.associate_qos_with_type(self.ctxt, specs_id, type2_ref["id"]) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(2, len(res)) qos_specs.disassociate_all(self.ctxt, specs_id) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(0, len(res)) self.mock_object(db, "qos_specs_disassociate_all", fake_db_disassociate_all) self.mock_object(qos_specs, "get_qos_specs", fake_qos_specs_get) self.assertRaises(exception.QoSSpecsDisassociateFailed, qos_specs.disassociate_all, self.ctxt, "Trouble")
def _fake_volume_type(*args, **kwargs): ctxt = context.get_admin_context() type_ref = volume_types.create(ctxt, "qos_extra_specs", {}) qos_ref = qos_specs.create(ctxt, 'qos-specs', {}) qos_specs.associate_qos_with_type(ctxt, qos_ref['id'], type_ref['id']) qos_type = volume_types.get_volume_type(ctxt, type_ref['id']) return qos_type
def test_manage_existing(self, mock_req): ctxt = context.get_admin_context() extra_specs = { "Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick" } type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = { 'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000' } qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) VOLUME1['volume_type_id'] = type_ref['id'] self.setup_driver() if self.configuration.ise_protocol == 'iscsi': mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_MODIFY_VOLUME_RESP, ISE_GET_IONETWORKS_RESP ]) elif self.configuration.ise_protocol == 'fibre_channel': mock_req.side_effect = iter([ ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_MODIFY_VOLUME_RESP ]) self.driver.manage_existing(VOLUME1, {'source-name': 'testvol'})
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] authorize(context) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s" % {'id': id, 'type_id': type_id}) try: qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.VolumeTypeNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=202)
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] authorize(context) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s", {'id': id, 'type_id': type_id}) try: qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.VolumeTypeNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=202)
def test_create_volume_Qos_by_volumeType_QoSspec(self, connmock): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'fio-qos': 'Policy 2'}) type_ref = volume_types.create(self.ctxt, "type1", { "volume_backend_name": "fio-ioControl", "qos:fio-qos": "Policy 4" }) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected_qos_result = '00000000-00000000-0000-000000000008' # Policy 2 qos = self.drv._set_qos_by_volume_type(type_ref['id']) self.assertEqual(qos, expected_qos_result)
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s", {'id': id, 'type_id': type_id}) try: spec = qos_specs.get_qos_specs(context, id) qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=http_client.ACCEPTED)
def test_create_volume_Qos_by_volumeType_QoSspec(self, connmock): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'fio-qos': 'Policy 2'}) type_ref = volume_types.create(self.ctxt, "type1", {"volume_backend_name": "fio-ioControl", "qos:fio-qos": "Policy 4"} ) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected_qos_result = '00000000-00000000-0000-000000000008' # Policy 2 qos = self.drv._set_qos_by_volume_type(type_ref['id']) self.assertEqual(qos, expected_qos_result)
def test_set_by_qos_spec(self): sfv = solidfire.SolidFireDriver(configuration=self.configuration) qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'minIOPS': '1000', 'maxIOPS': '10000', 'burstIOPS': '20000'}) type_ref = volume_types.create(self.ctxt, "type1", {"qos:minIOPS": "100", "qos:burstIOPS": "300", "qos:maxIOPS": "200"}) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id']) self.assertEqual(self.expected_qos_results, qos)
def test_set_by_qos_spec(self): sfv = SolidFireDriver(configuration=self.configuration) qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'minIOPS': '1000', 'maxIOPS': '10000', 'burstIOPS': '20000'}) type_ref = volume_types.create(self.ctxt, "type1", {"qos:minIOPS": "100", "qos:burstIOPS": "300", "qos:maxIOPS": "200"}) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id']) self.assertEqual(qos, self.expected_qos_results)
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s", { 'id': id, 'type_id': type_id }) try: spec = qos_specs.get_qos_specs(context, id) qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=http_client.ACCEPTED)
def test_associate_qos_with_type(self): def fake_qos_specs_get(context, id): if id == 'NotFound': raise exception.QoSSpecsNotFound(specs_id=id) else: pass def fake_db_associate(context, id, type_id): if id == 'Trouble': raise db_exc.DBError() elif type_id == 'NotFound': raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass def fake_vol_type_qos_get(type_id): if type_id == 'Invalid': return {'qos_specs': {'id': 'Invalid'}} else: return {'qos_specs': None} type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(1, len(res)) self.assertEqual('TypeName', res[0]['name']) self.assertEqual(type_ref['id'], res[0]['id']) self.stubs.Set(db, 'qos_specs_associate', fake_db_associate) self.stubs.Set(qos_specs, 'get_qos_specs', fake_qos_specs_get) self.stubs.Set(volume_types, 'get_volume_type_qos_specs', fake_vol_type_qos_get) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.associate_qos_with_type, self.ctxt, 'specs-id', 'NotFound') self.assertRaises(exception.QoSSpecsAssociateFailed, qos_specs.associate_qos_with_type, self.ctxt, 'Trouble', 'id') self.assertRaises(exception.QoSSpecsNotFound, qos_specs.associate_qos_with_type, self.ctxt, 'NotFound', 'id') self.assertRaises(exception.InvalidVolumeType, qos_specs.associate_qos_with_type, self.ctxt, 'specs-id', 'Invalid')
def test_associate_qos_with_type(self): def fake_qos_specs_get(context, id): if id == 'NotFound': raise exception.QoSSpecsNotFound(specs_id=id) else: pass def fake_db_associate(context, id, type_id): if id == 'Trouble': raise db_exc.DBError() elif type_id == 'NotFound': raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass def fake_vol_type_qos_get(type_id): if type_id == 'Invalid': return {'qos_specs': {'id': 'Invalid'}} else: return {'qos_specs': None} type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(1, len(res)) self.assertEqual('TypeName', res[0]['name']) self.assertEqual(type_ref['id'], res[0]['id']) self.mock_object(db, 'qos_specs_associate', fake_db_associate) self.mock_object(qos_specs, 'get_qos_specs', fake_qos_specs_get) self.mock_object(volume_types, 'get_volume_type_qos_specs', fake_vol_type_qos_get) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.associate_qos_with_type, self.ctxt, 'specs-id', 'NotFound') self.assertRaises(exception.QoSSpecsAssociateFailed, qos_specs.associate_qos_with_type, self.ctxt, 'Trouble', 'id') self.assertRaises(exception.QoSSpecsNotFound, qos_specs.associate_qos_with_type, self.ctxt, 'NotFound', 'id') self.assertRaises(exception.InvalidVolumeType, qos_specs.associate_qos_with_type, self.ctxt, 'specs-id', 'Invalid')
def test_get_volume_type_qos_specs(self): qos_ref = qos_specs.create(self.ctxt, "qos-specs-1", {"k1": "v1", "k2": "v2", "k3": "v3"}) type_ref = volume_types.create(self.ctxt, "type1", {"key2": "val2", "key3": "val3"}) res = volume_types.get_volume_type_qos_specs(type_ref["id"]) self.assertIsNone(res["qos_specs"]) qos_specs.associate_qos_with_type(self.ctxt, qos_ref["id"], type_ref["id"]) expected = { "qos_specs": { "id": qos_ref["id"], "name": "qos-specs-1", "consumer": "back-end", "specs": {"k1": "v1", "k2": "v2", "k3": "v3"}, } } res = volume_types.get_volume_type_qos_specs(type_ref["id"]) self.assertDictMatch(expected, res)
def test_get_volume_type_qos_specs(self): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}) type_ref = volume_types.create(self.ctxt, "type1", {"key2": "val2", "key3": "val3"}) res = volume_types.get_volume_type_qos_specs(type_ref['id']) self.assertEquals(res['qos_specs'], {}) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected = {'qos_specs': {'consumer': 'back-end', 'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}} res = volume_types.get_volume_type_qos_specs(type_ref['id']) self.assertDictMatch(expected, res)
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] authorize(context) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("associcate(): id: %s, type_id: %s" % (id, type_id)) try: qos_specs.get_qos_specs(context, id) qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id) notifier_api.notify(context, 'QoSSpecs', 'qos_specs.associate', notifier_api.INFO, notifier_info) except exception.VolumeTypeNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=err) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPNotFound(explanation=err) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError(explanation=err) return webob.Response(status_int=202)
def test_associate_qos_with_type(self): def fake_qos_specs_get(context, id): if id == "NotFound": raise exception.QoSSpecsNotFound(specs_id=id) else: pass def fake_db_associate(context, id, type_id): if id == "Trouble": raise db_exc.DBError() elif type_id == "NotFound": raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass def fake_vol_type_qos_get(type_id): if type_id == "Invalid": return {"qos_specs": {"id": "Invalid"}} else: return {"qos_specs": None} type_ref = volume_types.create(self.ctxt, "TypeName") specs_id = self._create_qos_specs("QoSName") qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref["id"]) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEqual(1, len(res)) self.assertEqual("TypeName", res[0]["name"]) self.assertEqual(type_ref["id"], res[0]["id"]) self.mock_object(db, "qos_specs_associate", fake_db_associate) self.mock_object(qos_specs, "get_qos_specs", fake_qos_specs_get) self.mock_object(volume_types, "get_volume_type_qos_specs", fake_vol_type_qos_get) self.assertRaises( exception.VolumeTypeNotFound, qos_specs.associate_qos_with_type, self.ctxt, "specs-id", "NotFound" ) self.assertRaises( exception.QoSSpecsAssociateFailed, qos_specs.associate_qos_with_type, self.ctxt, "Trouble", "id" ) self.assertRaises(exception.QoSSpecsNotFound, qos_specs.associate_qos_with_type, self.ctxt, "NotFound", "id") self.assertRaises( exception.InvalidVolumeType, qos_specs.associate_qos_with_type, self.ctxt, "specs-id", "Invalid" )
def test_negative_create_snapshot_conflict(self, mock_req): ctxt = context.get_admin_context() extra_specs = {"Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = {'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000'} qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) SNAPSHOT1['volume_type_id'] = type_ref['id'] mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_409_CONFLICT_RESP]) self.configuration.ise_completion_retries = 1 self.setup_driver() self.assertRaises(exception.XIODriverException, self.driver.create_snapshot, SNAPSHOT1)
def test_create_volume_from_snapshot(self, mock_req): ctxt = context.get_admin_context() extra_specs = {"Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = {'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000'} qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) SNAPSHOT1['volume_type_id'] = type_ref['id'] mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_GET_SNAP1_STATUS_RESP, ISE_PREP_SNAPSHOT_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_CREATE_SNAPSHOT_RESP, ISE_GET_VOL1_STATUS_RESP]) self.setup_driver() self.driver.create_volume_from_snapshot(VOLUME1, SNAPSHOT1)
def test_get_volume_type_qos_specs(self): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}) type_ref = volume_types.create(self.ctxt, "type1", {"key2": "val2", "key3": "val3"}) res = volume_types.get_volume_type_qos_specs(type_ref['id']) self.assertIsNone(res['qos_specs']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected = {'qos_specs': {'id': qos_ref['id'], 'name': 'qos-specs-1', 'consumer': 'back-end', 'specs': { 'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}}} res = volume_types.get_volume_type_qos_specs(type_ref['id']) specs = db.qos_specs_get(self.ctxt, qos_ref['id']) expected['qos_specs']['created_at'] = specs['created_at'] self.assertDictEqual(expected, res)
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ["cinder.context"] authorize(context) type_id = req.params.get("vol_type_id", None) if not type_id: msg = _("Volume Type id must not be None.") notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, "qos_specs.delete", notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s" % {"id": id, "type_id": type_id}) try: qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id) notifier_api.notify(context, "QoSSpecs", "qos_specs.associate", notifier_api.INFO, notifier_info) except exception.VolumeTypeNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, "qos_specs.associate", notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, "qos_specs.associate", notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, "qos_specs.associate", notifier_err) self._notify_qos_specs_error(context, "qos_specs.associate", notifier_err) raise webob.exc.HTTPBadRequest(explanation=str(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, "qos_specs.associate", notifier_err) raise webob.exc.HTTPInternalServerError(explanation=str(err)) return webob.Response(status_int=202)
def test_manage_existing(self, mock_req): ctxt = context.get_admin_context() extra_specs = {"Feature:Pool": "1", "Feature:Raid": "1", "Affinity:Type": "flash", "Alloc:Type": "thick"} type_ref = volume_types.create(ctxt, 'VT1', extra_specs) specs = {'qos:minIOPS': '20', 'qos:maxIOPS': '2000', 'qos:burstIOPS': '5000'} qos = qos_specs.create(ctxt, 'fake-qos', specs) qos_specs.associate_qos_with_type(ctxt, qos['id'], type_ref['id']) VOLUME1['volume_type_id'] = type_ref['id'] self.setup_driver() if self.configuration.ise_protocol == 'iscsi': mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_MODIFY_VOLUME_RESP, ISE_GET_IONETWORKS_RESP]) elif self.configuration.ise_protocol == 'fibre_channel': mock_req.side_effect = iter([ISE_GET_QUERY_RESP, ISE_GET_VOL1_STATUS_RESP, ISE_MODIFY_VOLUME_RESP]) self.driver.manage_existing(VOLUME1, {'source-name': 'testvol'})
def test_associate_qos_with_type(self): def fake_db_associate(context, id, type_id): if id == 'Trouble': raise db_exc.DBError() elif type_id == 'NotFound': raise exception.VolumeTypeNotFound(volume_type_id=type_id) pass type_ref = volume_types.create(self.ctxt, 'TypeName') specs_id = self._create_qos_specs('QoSName') qos_specs.associate_qos_with_type(self.ctxt, specs_id, type_ref['id']) res = qos_specs.get_associations(self.ctxt, specs_id) self.assertEquals(len(res[specs_id].keys()), 1) self.assertTrue('TypeName' in res[specs_id].keys()) self.assertTrue(type_ref['id'] in res[specs_id].values()) self.stubs.Set(db, 'qos_specs_associate', fake_db_associate) self.assertRaises(exception.VolumeTypeNotFound, qos_specs.associate_qos_with_type, self.ctxt, 'specs-id', 'NotFound') self.assertRaises(exception.QoSSpecsAssociateFailed, qos_specs.associate_qos_with_type, self.ctxt, 'Trouble', 'id')
def test_volume_types_diff(self): #type_ref 1 and 2 have the same extra_specs, while 3 has different keyvals1 = {"key1": "val1", "key2": "val2"} keyvals2 = {"key1": "val0", "key2": "val2"} type_ref1 = volume_types.create(self.ctxt, "type1", keyvals1) type_ref2 = volume_types.create(self.ctxt, "type2", keyvals1) type_ref3 = volume_types.create(self.ctxt, "type3", keyvals2) # Check equality with only extra_specs diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertEqual(True, same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref3['id']) self.assertEqual(False, same) self.assertEqual(('val1', 'val0'), diff['extra_specs']['key1']) #qos_ref 1 and 2 have the same specs, while 3 has different qos_keyvals1 = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} qos_keyvals2 = {'k1': 'v0', 'k2': 'v2', 'k3': 'v3'} qos_ref1 = qos_specs.create(self.ctxt, 'qos-specs-1', qos_keyvals1) qos_ref2 = qos_specs.create(self.ctxt, 'qos-specs-2', qos_keyvals1) qos_ref3 = qos_specs.create(self.ctxt, 'qos-specs-3', qos_keyvals2) # Check equality with qos specs too qos_specs.associate_qos_with_type(self.ctxt, qos_ref1['id'], type_ref1['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2['id'], type_ref2['id']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertEqual(True, same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v1'), diff['qos_specs']['k1']) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref2['id'], type_ref2['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref3['id'], type_ref2['id']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertEqual(False, same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v0'), diff['qos_specs']['k1']) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref3['id'], type_ref2['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2['id'], type_ref2['id']) # And add encryption for good measure enc_keyvals1 = {'cipher': 'c1', 'key_size': 256, 'provider': 'p1', 'control_location': 'front-end'} enc_keyvals2 = {'cipher': 'c1', 'key_size': 128, 'provider': 'p1', 'control_location': 'front-end'} db.volume_type_encryption_create(self.ctxt, type_ref1['id'], enc_keyvals1) db.volume_type_encryption_create(self.ctxt, type_ref2['id'], enc_keyvals2) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertEqual(False, same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v1'), diff['qos_specs']['k1']) self.assertEqual((256, 128), diff['encryption']['key_size'])
def test_volume_types_diff(self): # type_ref 1 and 2 have the same extra_specs, while 3 has different keyvals1 = {"key1": "val1", "key2": "val2"} keyvals2 = {"key1": "val0", "key2": "val2"} type_ref1 = volume_types.create(self.ctxt, "type1", keyvals1) type_ref2 = volume_types.create(self.ctxt, "type2", keyvals1) type_ref3 = volume_types.create(self.ctxt, "type3", keyvals2) # Check equality with only extra_specs diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertTrue(same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref3['id']) self.assertFalse(same) self.assertEqual(('val1', 'val0'), diff['extra_specs']['key1']) # qos_ref 1 and 2 have the same specs, while 3 has different qos_keyvals1 = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} qos_keyvals2 = {'k1': 'v0', 'k2': 'v2', 'k3': 'v3'} qos_ref1 = qos_specs.create(self.ctxt, 'qos-specs-1', qos_keyvals1) qos_ref2 = qos_specs.create(self.ctxt, 'qos-specs-2', qos_keyvals1) qos_ref3 = qos_specs.create(self.ctxt, 'qos-specs-3', qos_keyvals2) # Check equality with qos specs too qos_specs.associate_qos_with_type(self.ctxt, qos_ref1['id'], type_ref1['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2['id'], type_ref2['id']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertTrue(same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v1'), diff['qos_specs']['k1']) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref2['id'], type_ref2['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref3['id'], type_ref2['id']) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertFalse(same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v0'), diff['qos_specs']['k1']) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref3['id'], type_ref2['id']) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2['id'], type_ref2['id']) # And add encryption for good measure enc_keyvals1 = {'cipher': 'c1', 'key_size': 256, 'provider': 'p1', 'control_location': 'front-end', 'encryption_id': 'uuid1'} enc_keyvals2 = {'cipher': 'c1', 'key_size': 128, 'provider': 'p1', 'control_location': 'front-end', 'encryption_id': 'uuid2'} db.volume_type_encryption_create(self.ctxt, type_ref1['id'], enc_keyvals1) db.volume_type_encryption_create(self.ctxt, type_ref2['id'], enc_keyvals2) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1['id'], type_ref2['id']) self.assertFalse(same) self.assertEqual(('val1', 'val1'), diff['extra_specs']['key1']) self.assertEqual(('v1', 'v1'), diff['qos_specs']['k1']) self.assertEqual((256, 128), diff['encryption']['key_size']) # Check diff equals type specs when one type is None diff, same = volume_types.volume_types_diff(self.ctxt, None, type_ref1['id']) self.assertFalse(same) self.assertEqual({'key1': (None, 'val1'), 'key2': (None, 'val2')}, diff['extra_specs']) self.assertEqual({'consumer': (None, 'back-end'), 'k1': (None, 'v1'), 'k2': (None, 'v2'), 'k3': (None, 'v3')}, diff['qos_specs']) self.assertEqual({'cipher': (None, 'c1'), 'control_location': (None, 'front-end'), 'deleted': (None, False), 'key_size': (None, 256), 'provider': (None, 'p1'), 'encryption_id': (None, 'uuid1')}, diff['encryption'])
def test_volume_types_diff(self): # type_ref 1 and 2 have the same extra_specs, while 3 has different keyvals1 = {"key1": "val1", "key2": "val2"} keyvals2 = {"key1": "val0", "key2": "val2"} type_ref1 = volume_types.create(self.ctxt, "type1", keyvals1) type_ref2 = volume_types.create(self.ctxt, "type2", keyvals1) type_ref3 = volume_types.create(self.ctxt, "type3", keyvals2) # Check equality with only extra_specs diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1["id"], type_ref2["id"]) self.assertTrue(same) self.assertEqual(diff["extra_specs"]["key1"], ("val1", "val1")) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1["id"], type_ref3["id"]) self.assertFalse(same) self.assertEqual(diff["extra_specs"]["key1"], ("val1", "val0")) # qos_ref 1 and 2 have the same specs, while 3 has different qos_keyvals1 = {"k1": "v1", "k2": "v2", "k3": "v3"} qos_keyvals2 = {"k1": "v0", "k2": "v2", "k3": "v3"} qos_ref1 = qos_specs.create(self.ctxt, "qos-specs-1", qos_keyvals1) qos_ref2 = qos_specs.create(self.ctxt, "qos-specs-2", qos_keyvals1) qos_ref3 = qos_specs.create(self.ctxt, "qos-specs-3", qos_keyvals2) # Check equality with qos specs too qos_specs.associate_qos_with_type(self.ctxt, qos_ref1["id"], type_ref1["id"]) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2["id"], type_ref2["id"]) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1["id"], type_ref2["id"]) self.assertTrue(same) self.assertEqual(diff["extra_specs"]["key1"], ("val1", "val1")) self.assertEqual(diff["qos_specs"]["k1"], ("v1", "v1")) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref2["id"], type_ref2["id"]) qos_specs.associate_qos_with_type(self.ctxt, qos_ref3["id"], type_ref2["id"]) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1["id"], type_ref2["id"]) self.assertFalse(same) self.assertEqual(diff["extra_specs"]["key1"], ("val1", "val1")) self.assertEqual(diff["qos_specs"]["k1"], ("v1", "v0")) qos_specs.disassociate_qos_specs(self.ctxt, qos_ref3["id"], type_ref2["id"]) qos_specs.associate_qos_with_type(self.ctxt, qos_ref2["id"], type_ref2["id"]) # And add encryption for good measure enc_keyvals1 = { "cipher": "c1", "key_size": 256, "provider": "p1", "control_location": "front-end", "encryption_id": "uuid1", } enc_keyvals2 = { "cipher": "c1", "key_size": 128, "provider": "p1", "control_location": "front-end", "encryption_id": "uuid2", } db.volume_type_encryption_create(self.ctxt, type_ref1["id"], enc_keyvals1) db.volume_type_encryption_create(self.ctxt, type_ref2["id"], enc_keyvals2) diff, same = volume_types.volume_types_diff(self.ctxt, type_ref1["id"], type_ref2["id"]) self.assertFalse(same) self.assertEqual(diff["extra_specs"]["key1"], ("val1", "val1")) self.assertEqual(diff["qos_specs"]["k1"], ("v1", "v1")) self.assertEqual(diff["encryption"]["key_size"], (256, 128)) # Check diff equals type specs when one type is None diff, same = volume_types.volume_types_diff(self.ctxt, None, type_ref1["id"]) self.assertFalse(same) self.assertEqual(diff["extra_specs"], {"key1": (None, "val1"), "key2": (None, "val2")}) self.assertEqual( diff["qos_specs"], {"consumer": (None, "back-end"), "k1": (None, "v1"), "k2": (None, "v2"), "k3": (None, "v3")}, ) self.assertEqual( diff["encryption"], { "cipher": (None, "c1"), "control_location": (None, "front-end"), "deleted": (None, False), "key_size": (None, 256), "provider": (None, "p1"), "encryption_id": (None, "uuid1"), }, )