Source code for glare.tests.unit.test_quotas

# Copyright 2017 - Nokia Networks
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import mock
from six import BytesIO

from glare.common import exception
from glare.common import store_api
from glare.tests.unit import base


[docs]class TestStaticQuotas(base.BaseTestArtifactAPI): """Test static quota limits."""
[docs] def test_count_artifact_number(self): user1_req = self.get_fake_request(self.users['user1']) user2_req = self.get_fake_request(self.users['user2']) # initially there are no artifacts self.assertEqual( 0, len(self.controller.list(user1_req, 'all')['artifacts'])) self.assertEqual( 0, len(self.controller.list(user2_req, 'all')['artifacts'])) # set global limit on 10 artifacts self.config(max_artifact_number=10) # 3 images, 15 heat templates, 10 murano packages self.config(max_artifact_number=3, group='artifact_type:images') self.config(max_artifact_number=15, group='artifact_type:heat_templates') self.config(max_artifact_number=10, group='artifact_type:murano_packages') # create 3 images for user1 for i in range(3): img = self.controller.create( user1_req, 'images', {'name': 'img%d' % i}) # creation of another image fails because of artifact type limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'images', {'name': 'img4'}) # create 7 murano packages for i in range(7): self.controller.create( user1_req, 'murano_packages', {'name': 'mp%d' % i}) # creation of another package fails because of global limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'murano_packages', {'name': 'mp8'}) # delete an image and create another murano package work self.controller.delete(user1_req, 'images', img['id']) self.controller.create(user1_req, 'murano_packages', {'name': 'mp8'}) # user2 can create his own artifacts for i in range(10): self.controller.create( user2_req, 'heat_templates', {'name': 'ht%d' % i}) # creation of another heat template fails because of global limit self.assertRaises(exception.Forbidden, self.controller.create, user2_req, 'heat_templates', {'name': 'ht11'}) # disable global limit and try to create 15 heat templates self.config(max_artifact_number=-1) for i in range(15): self.controller.create( user1_req, 'heat_templates', {'name': 'ht%d' % i}) # creation of another heat template fails because of type limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'heat_templates', {'name': 'ht16'}) # disable type limit for heat templates and create 1 heat templates self.config(max_artifact_number=-1, group='artifact_type:heat_templates') self.controller.create( user1_req, 'heat_templates', {'name': 'ht16'})
[docs] def test_calculate_uploaded_data(self): user1_req = self.get_fake_request(self.users['user1']) user2_req = self.get_fake_request(self.users['user2']) # initially there are no artifacts self.assertEqual( 0, len(self.controller.list(user1_req, 'all')['artifacts'])) self.assertEqual( 0, len(self.controller.list(user2_req, 'all')['artifacts'])) # set global limit on 1000 bytes self.config(max_uploaded_data=1000) # 300 for sample artifact, 1500 for images, 1000 for murano packages self.config(max_uploaded_data=300, group='artifact_type:sample_artifact') self.config(max_uploaded_data=1500, group='artifact_type:images') self.config(max_uploaded_data=1000, group='artifact_type:murano_packages') # create 2 sample artifacts for user 1 art1 = self.controller.create( user1_req, 'sample_artifact', {'name': 'art1'}) art2 = self.controller.create( user1_req, 'sample_artifact', {'name': 'art2'}) # create 3 images for user1 img1 = self.controller.create( user1_req, 'images', {'name': 'img1'}) img2 = self.controller.create( user1_req, 'images', {'name': 'img2'}) img3 = self.controller.create( user1_req, 'images', {'name': 'img3'}) # upload to art1 fails now because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art1['id'], 'blob', BytesIO(b'a' * 301), 'application/octet-stream', 301) # upload to img1 fails now because of global limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img1['id'], 'image', BytesIO(b'a' * 1001), 'application/octet-stream', 1001) # upload 300 bytes to 'blob' of art1 self.controller.upload_blob( user1_req, 'sample_artifact', art1['id'], 'blob', BytesIO(b'a' * 300), 'application/octet-stream', content_length=300) # upload another blob to art1 fails because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art1['id'], 'dict_of_blobs/blob', BytesIO(b'a'), 'application/octet-stream', 1) # upload to art2 fails now because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art2['id'], 'blob', BytesIO(b'a'), 'application/octet-stream', 1) # delete art1 and check that upload to art2 works self.controller.delete(user1_req, 'sample_artifact', art1['id']) self.controller.upload_blob( user1_req, 'sample_artifact', art2['id'], 'blob', BytesIO(b'a' * 300), 'application/octet-stream', 300) # upload 700 bytes to img1 works self.controller.upload_blob( user1_req, 'images', img1['id'], 'image', BytesIO(b'a' * 700), 'application/octet-stream', 700) # upload to img2 fails because of global limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img2['id'], 'image', BytesIO(b'a'), 'application/octet-stream', 1) # user2 can upload data to images img1 = self.controller.create( user2_req, 'images', {'name': 'img1'}) self.controller.upload_blob( user2_req, 'images', img1['id'], 'image', BytesIO(b'a' * 1000), 'application/octet-stream', 1000) # disable global limit and try upload data from user1 again self.config(max_uploaded_data=-1) self.controller.upload_blob( user1_req, 'images', img2['id'], 'image', BytesIO(b'a' * 800), 'application/octet-stream', 800) # uploading more fails because of image type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img3['id'], 'image', BytesIO(b'a'), 'application/octet-stream', 1) # disable type limit and try upload data from user1 again self.config(max_uploaded_data=-1, group='artifact_type:images') self.controller.upload_blob( user1_req, 'images', img3['id'], 'image', BytesIO(b'a' * 1000), 'application/octet-stream', 1000)
[docs]class TestDynamicQuotas(base.BaseTestArtifactAPI): """Test dynamic quota limits."""
[docs] def test_count_artifact_number(self): user1_req = self.get_fake_request(self.users['user1']) user2_req = self.get_fake_request(self.users['user2']) # initially there are no artifacts self.assertEqual( 0, len(self.controller.list(user1_req, 'all')['artifacts'])) self.assertEqual( 0, len(self.controller.list(user2_req, 'all')['artifacts'])) values = { user1_req.context.tenant: { "max_artifact_number:images": 3, "max_artifact_number:heat_templates": 15, "max_artifact_number:murano_packages": 10, "max_artifact_number": 10 }, user2_req.context.tenant: { "max_artifact_number": 10 } } admin_req = self.get_fake_request(self.users["admin"]) # define several quotas self.controller.set_quotas(admin_req, values) # create 3 images for user1 for i in range(3): img = self.controller.create( user1_req, 'images', {'name': 'img%d' % i}) # creation of another image fails because of artifact type limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'images', {'name': 'img4'}) # create 7 murano packages for i in range(7): self.controller.create( user1_req, 'murano_packages', {'name': 'mp%d' % i}) # creation of another package fails because of global limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'murano_packages', {'name': 'mp8'}) # delete an image and create another murano package work self.controller.delete(user1_req, 'images', img['id']) self.controller.create(user1_req, 'murano_packages', {'name': 'mp8'}) # user2 can create his own artifacts for i in range(10): self.controller.create( user2_req, 'heat_templates', {'name': 'ht%d' % i}) # creation of another heat template fails because of global limit self.assertRaises(exception.Forbidden, self.controller.create, user2_req, 'heat_templates', {'name': 'ht11'}) # disable global limit for user1 and try to create 15 heat templates values = { user1_req.context.tenant: { "max_artifact_number:images": 3, "max_artifact_number:heat_templates": 15, "max_artifact_number:murano_packages": 10, "max_artifact_number": -1 } } self.controller.set_quotas(admin_req, values) for i in range(15): self.controller.create( user1_req, 'heat_templates', {'name': 'ht%d' % i}) # creation of another heat template fails because of type limit self.assertRaises(exception.Forbidden, self.controller.create, user1_req, 'heat_templates', {'name': 'ht16'}) # disable type limit for heat templates and create 1 heat templates values = { user1_req.context.tenant: { "max_artifact_number:images": 3, "max_artifact_number:heat_templates": -1, "max_artifact_number:murano_packages": 10, "max_artifact_number": -1 } } self.controller.set_quotas(admin_req, values) # now user1 can create another heat template self.controller.create( user1_req, 'heat_templates', {'name': 'ht16'})
[docs] def test_calculate_uploaded_data(self): user1_req = self.get_fake_request(self.users['user1']) user2_req = self.get_fake_request(self.users['user2']) # initially there are no artifacts self.assertEqual( 0, len(self.controller.list(user1_req, 'all')['artifacts'])) self.assertEqual( 0, len(self.controller.list(user2_req, 'all')['artifacts'])) values = { user1_req.context.tenant: { "max_uploaded_data:images": 1500, "max_uploaded_data:sample_artifact": 300, "max_uploaded_data:murano_packages": 1000, "max_uploaded_data": 1000 }, user2_req.context.tenant: { "max_uploaded_data": 1000 } } admin_req = self.get_fake_request(self.users["admin"]) # define several quotas self.controller.set_quotas(admin_req, values) # create 2 sample artifacts for user 1 art1 = self.controller.create( user1_req, 'sample_artifact', {'name': 'art1'}) art2 = self.controller.create( user1_req, 'sample_artifact', {'name': 'art2'}) # create 3 images for user1 img1 = self.controller.create( user1_req, 'images', {'name': 'img1'}) img2 = self.controller.create( user1_req, 'images', {'name': 'img2'}) img3 = self.controller.create( user1_req, 'images', {'name': 'img3'}) # upload to art1 fails now because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art1['id'], 'blob', BytesIO(b'a' * 301), 'application/octet-stream', 301) # upload to img1 fails now because of global limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img1['id'], 'image', BytesIO(b'a' * 1001), 'application/octet-stream', 1001) # upload 300 bytes to 'blob' of art1 self.controller.upload_blob( user1_req, 'sample_artifact', art1['id'], 'blob', BytesIO(b'a' * 300), 'application/octet-stream', content_length=300) # upload another blob to art1 fails because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art1['id'], 'dict_of_blobs/blob', BytesIO(b'a'), 'application/octet-stream', 1) # upload to art2 fails now because of type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art2['id'], 'blob', BytesIO(b'a'), 'application/octet-stream', 1) # delete art1 and check that upload to art2 works self.controller.delete(user1_req, 'sample_artifact', art1['id']) self.controller.upload_blob( user1_req, 'sample_artifact', art2['id'], 'blob', BytesIO(b'a' * 300), 'application/octet-stream', 300) # upload 700 bytes to img1 works self.controller.upload_blob( user1_req, 'images', img1['id'], 'image', BytesIO(b'a' * 700), 'application/octet-stream', 700) # upload to img2 fails because of global limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img2['id'], 'image', BytesIO(b'a'), 'application/octet-stream', 1) # user2 can upload data to images img1 = self.controller.create( user2_req, 'images', {'name': 'img1'}) self.controller.upload_blob( user2_req, 'images', img1['id'], 'image', BytesIO(b'a' * 1000), 'application/octet-stream', 1000) # disable global limit and try upload data from user1 again values = { user1_req.context.tenant: { "max_uploaded_data:images": 1500, "max_uploaded_data:sample_artifact": 300, "max_uploaded_data:murano_packages": 1000, "max_uploaded_data": -1 } } self.controller.set_quotas(admin_req, values) self.controller.upload_blob( user1_req, 'images', img2['id'], 'image', BytesIO(b'a' * 800), 'application/octet-stream', 800) # uploading more fails because of image type limit self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'images', img3['id'], 'image', BytesIO(b'a'), 'application/octet-stream', 1) # disable type limit and try upload data from user1 again values = { user1_req.context.tenant: { "max_uploaded_data:images": -1, "max_uploaded_data:sample_artifact": 300, "max_uploaded_data:murano_packages": 1000, "max_uploaded_data": -1 } } self.controller.set_quotas(admin_req, values) self.controller.upload_blob( user1_req, 'images', img3['id'], 'image', BytesIO(b'a' * 1000), 'application/octet-stream', 1000)
[docs] def test_quota_upload_no_content_length(self): user1_req = self.get_fake_request(self.users['user1']) user2_req = self.get_fake_request(self.users['user2']) admin_req = self.get_fake_request(self.users['admin']) values = { user1_req.context.tenant: { "max_uploaded_data:sample_artifact": 20, "max_uploaded_data": 5 }, user2_req.context.tenant: { "max_uploaded_data:sample_artifact": 7, "max_uploaded_data": -1 }, admin_req.context.tenant: { "max_uploaded_data:sample_artifact": -1, "max_uploaded_data": -1 } } # define several quotas self.controller.set_quotas(admin_req, values) # create a sample artifacts for user 1 art1 = self.controller.create( user1_req, 'sample_artifact', {'name': 'art1'}) # Max small_blob size is 10. User1 global quota is 5. # Since user doesn't specify how many bytes he wants to upload, # engine can't verify it before upload. Therefore it allocates # 5 available bytes for user and begins upload. If uploaded data # amount exceeds this limit RequestEntityTooLarge is raised and # upload fails. with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 10) self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user1_req, 'sample_artifact', art1['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, user1_req.context, 5, store_type='database') # check that blob wasn't uploaded self.assertIsNone( self.controller.show( user1_req, 'sample_artifact', art1['id'])['small_blob']) # try to upload with smaller amount that doesn't exceeds quota with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 4) self.controller.upload_blob( user1_req, 'sample_artifact', art1['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, user1_req.context, 5, store_type='database') # check that blob was uploaded blob = self.controller.show( user1_req, 'sample_artifact', art1['id'])['small_blob'] self.assertEqual(4, blob['size']) self.assertEqual('active', blob['status']) # create a sample artifacts for user 2 art2 = self.controller.create( user2_req, 'sample_artifact', {'name': 'art2'}) # Max small_blob size is 10. User1 has no global quota, but his # type quota is 7. # Since user doesn't specify how many bytes he wants to upload, # engine can't verify it before upload. Therefore it allocates # 7 available bytes for user and begins upload. If uploaded data # amount exceeds this limit RequestEntityTooLarge is raised and # upload fails. with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 10) self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, user2_req, 'sample_artifact', art2['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, user2_req.context, 7, store_type='database') # check that blob wasn't uploaded self.assertIsNone( self.controller.show( user2_req, 'sample_artifact', art2['id'])['small_blob']) # try to upload with smaller amount that doesn't exceeds quota with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 7) self.controller.upload_blob( user2_req, 'sample_artifact', art2['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, user2_req.context, 7, store_type='database') # check that blob was uploaded blob = self.controller.show( user2_req, 'sample_artifact', art2['id'])['small_blob'] self.assertEqual(7, blob['size']) self.assertEqual('active', blob['status']) # create a sample artifacts for admin arta = self.controller.create( user2_req, 'sample_artifact', {'name': 'arta'}) # Max small_blob size is 10. Admin has no quotas at all. # Since admin doesn't specify how many bytes he wants to upload, # engine can't verify it before upload. Therefore it allocates # 10 available bytes (max allowed small_blob size) for him and begins # upload. If uploaded data amount exceeds this limit # RequestEntityTooLarge is raised and upload fails. with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 11) self.assertRaises( exception.RequestEntityTooLarge, self.controller.upload_blob, admin_req, 'sample_artifact', arta['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, admin_req.context, 10, store_type='database') # check that blob wasn't uploaded self.assertIsNone( self.controller.show( admin_req, 'sample_artifact', arta['id'])['small_blob']) # try to upload with smaller amount that doesn't exceeds quota with mock.patch( 'glare.common.store_api.save_blob_to_store', side_effect=store_api.save_blob_to_store) as mocked_save: data = BytesIO(b'a' * 10) self.controller.upload_blob( admin_req, 'sample_artifact', arta['id'], 'small_blob', data, 'application/octet-stream', content_length=None) mocked_save.assert_called_once_with( mock.ANY, data, admin_req.context, 10, store_type='database') # check that blob was uploaded blob = self.controller.show( admin_req, 'sample_artifact', arta['id'])['small_blob'] self.assertEqual(10, blob['size']) self.assertEqual('active', blob['status'])