diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-08-17 13:19:35 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-08-17 13:19:35 +0000 |
| commit | 72c7b866ed92d638bf8f5563ff7ea2568548764a (patch) | |
| tree | 82bc4f86be865677c1d2832793e5cc5896d95423 /nova/db | |
| parent | 53c40cfc18fe5c57ca724e5d7902e18fe09cc09f (diff) | |
| parent | 1cf475d7a135c1078cf7df11c261618af501dc37 (diff) | |
Merge "Revert per-user-quotas"
Diffstat (limited to 'nova/db')
| -rw-r--r-- | nova/db/api.py | 105 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 250 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/migrate_repo/versions/116_drop_user_quotas_key_and_value.py | 98 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/models.py | 15 |
4 files changed, 143 insertions, 325 deletions
diff --git a/nova/db/api.py b/nova/db/api.py index d8274b2db..94fdd8ce2 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -568,12 +568,6 @@ def instance_create(context, values): return IMPL.instance_create(context, values) -def instance_data_get_for_user(context, user_id, project_id, session=None): - """Get (instance_count, total_cores, total_ram) for user.""" - return IMPL.instance_data_get_for_user(context, user_id, project_id, - session=session) - - def instance_data_get_for_project(context, project_id, session=None): """Get (instance_count, total_cores, total_ram) for project.""" return IMPL.instance_data_get_for_project(context, project_id, @@ -955,42 +949,6 @@ def quota_destroy(context, project_id, resource): ################### -def quota_create_for_user(context, user_id, project_id, resource, limit): - """Create a quota for the given user and project.""" - return IMPL.quota_create_for_user(context, user_id, - project_id, resource, limit) - - -def quota_get_for_user(context, user_id, project_id, resource): - """Retrieve a quota or raise if it does not exist.""" - return IMPL.quota_get_for_user(context, user_id, - project_id, resource) - - -def quota_get_all_by_user(context, user_id, project_id): - """Retrieve all quotas associated with a given user and project.""" - return IMPL.quota_get_all_by_user(context, user_id, project_id) - - -def quota_get_remaining(context, project_id): - """Retrieve the remaining quotas associated with a given project.""" - return IMPL.quota_get_remaining(context, project_id) - - -def quota_update_for_user(context, user_id, project_id, resource, limit): - """Update a quota or raise if it does not exist.""" - return IMPL.quota_update_for_user(context, user_id, - project_id, resource, limit) - - -def quota_destroy_for_user(context, user_id, project_id, resource): - """Destroy the quota or raise if it does not exist.""" - return IMPL.quota_destroy_for_user(context, user_id, project_id, resource) - - -################### - - def quota_class_create(context, class_name, resource, limit): """Create a quota class for the given name and resource.""" return IMPL.quota_class_create(context, class_name, resource, limit) @@ -1024,21 +982,16 @@ def quota_class_destroy_all_by_name(context, class_name): ################### -def quota_usage_create(context, user_id, project_id, resource, in_use, - reserved, until_refresh): - """Create a quota usage for the given user and resource.""" - return IMPL.quota_usage_create(context, user_id, project_id, resource, +def quota_usage_create(context, project_id, resource, in_use, reserved, + until_refresh): + """Create a quota usage for the given project and resource.""" + return IMPL.quota_usage_create(context, project_id, resource, in_use, reserved, until_refresh) -def quota_usage_get(context, user_id, project_id, resource): +def quota_usage_get(context, project_id, resource): """Retrieve a quota usage or raise if it does not exist.""" - return IMPL.quota_usage_get(context, user_id, project_id, resource) - - -def quota_usage_get_all_by_user(context, user_id, project_id): - """Retrieve all usage associated with a given user.""" - return IMPL.quota_usage_get_all_by_user(context, user_id, project_id) + return IMPL.quota_usage_get(context, project_id, resource) def quota_usage_get_all_by_project(context, project_id): @@ -1046,25 +999,25 @@ def quota_usage_get_all_by_project(context, project_id): return IMPL.quota_usage_get_all_by_project(context, project_id) -def quota_usage_update(context, user_id, project_id, resource, in_use, - reserved, until_refresh): +def quota_usage_update(context, class_name, resource, in_use, reserved, + until_refresh): """Update a quota usage or raise if it does not exist.""" - return IMPL.quota_usage_update(context, user_id, project_id, resource, + return IMPL.quota_usage_update(context, project_id, resource, in_use, reserved, until_refresh) -def quota_usage_destroy(context, user_id, project_id, resource): +def quota_usage_destroy(context, project_id, resource): """Destroy the quota usage or raise if it does not exist.""" - return IMPL.quota_usage_destroy(context, user_id, project_id, resource) + return IMPL.quota_usage_destroy(context, project_id, resource) ################### -def reservation_create(context, uuid, usage, user_id, project_id, resource, - delta, expire): - """Create a reservation for the given user and resource.""" - return IMPL.reservation_create(context, uuid, usage, user_id, project_id, +def reservation_create(context, uuid, usage, project_id, resource, delta, + expire): + """Create a reservation for the given project and resource.""" + return IMPL.reservation_create(context, uuid, usage, project_id, resource, delta, expire) @@ -1073,9 +1026,9 @@ def reservation_get(context, uuid): return IMPL.reservation_get(context, uuid) -def reservation_get_all_by_user(context, user_id, project_id): - """Retrieve all reservations associated with a given user.""" - return IMPL.reservation_get_all_by_user(context, user_id, project_id) +def reservation_get_all_by_project(context, project_id): + """Retrieve all reservations associated with a given project.""" + return IMPL.reservation_get_all_by_project(context, project_id) def reservation_destroy(context, uuid): @@ -1103,11 +1056,6 @@ def reservation_rollback(context, reservations): return IMPL.reservation_rollback(context, reservations) -def quota_destroy_all_by_user(context, user_id, project_id): - """Destroy all quotas associated with a given user.""" - return IMPL.quota_destroy_all_by_user(context, user_id, project_id) - - def quota_destroy_all_by_project(context, project_id): """Destroy all quotas associated with a given project.""" return IMPL.quota_destroy_all_by_project(context, project_id) @@ -1136,12 +1084,6 @@ def volume_create(context, values): return IMPL.volume_create(context, values) -def volume_data_get_for_user(context, user_id, project_id, session=None): - """Get (volume_count, gigabytes) for user.""" - return IMPL.volume_data_get_for_user(context, user_id, project_id, - session=session) - - def volume_data_get_for_project(context, project_id, session=None): """Get (volume_count, gigabytes) for project.""" return IMPL.volume_data_get_for_project(context, project_id, @@ -1330,11 +1272,6 @@ def security_group_get_by_name(context, project_id, group_name): return IMPL.security_group_get_by_name(context, project_id, group_name) -def security_group_get_by_user(context, user_id, project_id): - """Get all security groups belonging to a user.""" - return IMPL.security_group_get_by_user(context, user_id, project_id) - - def security_group_get_by_project(context, project_id): """Get all security groups belonging to a project.""" return IMPL.security_group_get_by_project(context, project_id) @@ -1370,12 +1307,6 @@ def security_group_destroy(context, security_group_id): return IMPL.security_group_destroy(context, security_group_id) -def security_group_count_by_user(context, user_id, project_id, session=None): - """Count number of security groups for a user in specific project.""" - return IMPL.security_group_count_by_user(context, user_id, project_id, - session=session) - - def security_group_count_by_project(context, project_id, session=None): """Count number of security groups in a project.""" return IMPL.security_group_count_by_project(context, project_id, diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 02b4607c2..d15b7b353 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1442,33 +1442,20 @@ def instance_create(context, values): return instance_ref -def _get_instance_data(context, project_id, user_id=None, session=None): +@require_admin_context +def instance_data_get_for_project(context, project_id, session=None): result = model_query(context, func.count(models.Instance.id), func.sum(models.Instance.vcpus), func.sum(models.Instance.memory_mb), read_deleted="no", session=session).\ - filter_by(project_id=project_id) - if user_id: - result = result.filter_by(user_id=user_id).first() - else: - result = result.first() + filter_by(project_id=project_id).\ + first() # NOTE(vish): convert None to 0 return (result[0] or 0, result[1] or 0, result[2] or 0) -@require_admin_context -def instance_data_get_for_project(context, project_id, session=None): - return _get_instance_data(context, project_id, session=session) - - -@require_admin_context -def instance_data_get_for_user(context, user_id, project_id, session=None): - return _get_instance_data(context, project_id, user_id=user_id, - session=session) - - @require_context def instance_destroy(context, instance_uuid, constraint=None): session = get_session() @@ -2390,11 +2377,10 @@ def quota_get(context, project_id, resource, session=None): @require_context -def quota_get_all_by_project(context, project_id, session=None): +def quota_get_all_by_project(context, project_id): authorize_project_context(context, project_id) - rows = model_query(context, models.Quota, session=session, - read_deleted="no").\ + rows = model_query(context, models.Quota, read_deleted="no").\ filter_by(project_id=project_id).\ all() @@ -2436,97 +2422,6 @@ def quota_destroy(context, project_id, resource): @require_context -def quota_get_for_user(context, user_id, project_id, resource, session=None): - authorize_project_context(context, project_id) - result = model_query(context, models.UserQuota, session=session, - read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - filter_by(resource=resource).\ - first() - - if not result: - raise exception.UserQuotaNotFound(project_id=project_id, - user_id=user_id) - - return result - - -@require_context -def quota_get_all_by_user(context, user_id, project_id): - authorize_project_context(context, project_id) - - rows = model_query(context, models.UserQuota, read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - result = {'user_id': user_id, 'project_id': project_id} - for row in rows: - result[row.resource] = row.hard_limit - - return result - - -@require_context -def quota_get_remaining(context, project_id): - authorize_project_context(context, project_id) - - session = get_session() - with session.begin(): - rows = model_query(context, models.UserQuota, session=session, - read_deleted="no").\ - filter_by(project_id=project_id).\ - all() - - result = quota_get_all_by_project(context, project_id, session=session) - - for row in rows: - if row.resource in result: - result[row.resource] -= row.hard_limit - - result['project_id'] = project_id - - return result - - -@require_context -def quota_create_for_user(context, user_id, project_id, resource, limit): - authorize_project_context(context, project_id) - quota_ref = models.UserQuota() - quota_ref.user_id = user_id - quota_ref.project_id = project_id - quota_ref.resource = resource - quota_ref.hard_limit = limit - quota_ref.save() - return quota_ref - - -@require_context -def quota_update_for_user(context, user_id, project_id, resource, limit): - authorize_project_context(context, project_id) - session = get_session() - with session.begin(): - quota_ref = quota_get_for_user(context, user_id, project_id, resource, - session=session) - quota_ref.hard_limit = limit - quota_ref.save(session=session) - - -@require_context -def quota_destroy_for_user(context, user_id, project_id, resource): - authorize_project_context(context, project_id) - session = get_session() - with session.begin(): - quota_ref = quota_get_for_user(context, user_id, project_id, resource, - session=session) - quota_ref.delete(session=session) - - -################### - - -@require_context def quota_class_get(context, class_name, resource, session=None): result = model_query(context, models.QuotaClass, session=session, read_deleted="no").\ @@ -2601,10 +2496,9 @@ def quota_class_destroy_all_by_name(context, class_name): @require_context -def quota_usage_get(context, user_id, project_id, resource, session=None): +def quota_usage_get(context, project_id, resource, session=None): result = model_query(context, models.QuotaUsage, session=session, read_deleted="no").\ - filter_by(user_id=user_id).\ filter_by(project_id=project_id).\ filter_by(resource=resource).\ first() @@ -2616,22 +2510,6 @@ def quota_usage_get(context, user_id, project_id, resource, session=None): @require_context -def quota_usage_get_all_by_user(context, user_id, project_id): - authorize_project_context(context, project_id) - - rows = model_query(context, models.QuotaUsage, read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - result = {'user_id': user_id, 'project_id': project_id} - for row in rows: - result[row.resource] = dict(in_use=row.in_use, reserved=row.reserved) - - return result - - -@require_context def quota_usage_get_all_by_project(context, project_id): authorize_project_context(context, project_id) @@ -2640,20 +2518,16 @@ def quota_usage_get_all_by_project(context, project_id): all() result = {'project_id': project_id} - in_use = 0 - reserved = 0 for row in rows: - result[row.resource] = dict(in_use=in_use + row.in_use, - reserved=reserved + row.reserved) + result[row.resource] = dict(in_use=row.in_use, reserved=row.reserved) return result @require_admin_context -def quota_usage_create(context, user_id, project_id, resource, in_use, - reserved, until_refresh, session=None): +def quota_usage_create(context, project_id, resource, in_use, reserved, + until_refresh, session=None): quota_usage_ref = models.QuotaUsage() - quota_usage_ref.user_id = user_id quota_usage_ref.project_id = project_id quota_usage_ref.resource = resource quota_usage_ref.in_use = in_use @@ -2665,11 +2539,11 @@ def quota_usage_create(context, user_id, project_id, resource, in_use, @require_admin_context -def quota_usage_update(context, user_id, project_id, resource, in_use, - reserved, until_refresh, session=None): +def quota_usage_update(context, project_id, resource, in_use, reserved, + until_refresh, session=None): def do_update(session): - quota_usage_ref = quota_usage_get(context, user_id, project_id, - resource, session=session) + quota_usage_ref = quota_usage_get(context, project_id, resource, + session=session) quota_usage_ref.in_use = in_use quota_usage_ref.reserved = reserved quota_usage_ref.until_refresh = until_refresh @@ -2685,11 +2559,11 @@ def quota_usage_update(context, user_id, project_id, resource, in_use, @require_admin_context -def quota_usage_destroy(context, user_id, project_id, resource): +def quota_usage_destroy(context, project_id, resource): session = get_session() with session.begin(): - quota_usage_ref = quota_usage_get(context, user_id, project_id, - resource, session=session) + quota_usage_ref = quota_usage_get(context, project_id, resource, + session=session) quota_usage_ref.delete(session=session) @@ -2710,15 +2584,14 @@ def reservation_get(context, uuid, session=None): @require_context -def reservation_get_all_by_user(context, user_id, project_id): +def reservation_get_all_by_project(context, project_id): authorize_project_context(context, project_id) rows = model_query(context, models.QuotaUsage, read_deleted="no").\ - filter_by(user_id=user_id).\ filter_by(project_id=project_id).\ all() - result = {'user_id': user_id, 'project_id': project_id} + result = {'project_id': project_id} for row in rows: result.setdefault(row.resource, {}) result[row.resource][row.uuid] = row.delta @@ -2727,12 +2600,11 @@ def reservation_get_all_by_user(context, user_id, project_id): @require_admin_context -def reservation_create(context, uuid, usage, user_id, project_id, resource, - delta, expire, session=None): +def reservation_create(context, uuid, usage, project_id, resource, delta, + expire, session=None): reservation_ref = models.Reservation() reservation_ref.uuid = uuid reservation_ref.usage_id = usage['id'] - reservation_ref.user_id = user_id reservation_ref.project_id = project_id reservation_ref.resource = resource reservation_ref.delta = delta @@ -2762,7 +2634,6 @@ def _get_quota_usages(context, session): rows = model_query(context, models.QuotaUsage, read_deleted="no", session=session).\ - filter_by(user_id=context.user_id).\ filter_by(project_id=context.project_id).\ with_lockmode('update').\ all() @@ -2787,7 +2658,6 @@ def quota_reserve(context, resources, quotas, deltas, expire, refresh = False if resource not in usages: usages[resource] = quota_usage_create(elevated, - context.user_id, context.project_id, resource, 0, 0, @@ -2811,13 +2681,11 @@ def quota_reserve(context, resources, quotas, deltas, expire, # Grab the sync routine sync = resources[resource].sync - updates = sync(elevated, context.user_id, - context.project_id, session) + updates = sync(elevated, context.project_id, session) for res, in_use in updates.items(): # Make sure we have a destination for the usage! if res not in usages: usages[res] = quota_usage_create(elevated, - context.user_id, context.project_id, res, 0, 0, @@ -2868,7 +2736,6 @@ def quota_reserve(context, resources, quotas, deltas, expire, reservation = reservation_create(elevated, str(utils.gen_uuid()), usages[resource], - context.user_id, context.project_id, resource, delta, expire, session=session) @@ -2953,38 +2820,6 @@ def reservation_rollback(context, reservations): @require_admin_context -def quota_destroy_all_by_user(context, user_id, project_id): - session = get_session() - with session.begin(): - quotas = model_query(context, models.UserQuota, session=session, - read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - for quota_ref in quotas: - quota_ref.delete(session=session) - - quota_usages = model_query(context, models.QuotaUsage, - session=session, read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - for quota_usage_ref in quota_usages: - quota_usage_ref.delete(session=session) - - reservations = model_query(context, models.Reservation, - session=session, read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - for reservation_ref in reservations: - reservation_ref.delete(session=session) - - -@require_admin_context def quota_destroy_all_by_project(context, project_id): session = get_session() with session.begin(): @@ -3089,34 +2924,21 @@ def volume_create(context, values): return volume_ref -def _get_volume_data(context, project_id, user_id=None, session=None): +@require_admin_context +def volume_data_get_for_project(context, project_id, session=None): result = model_query(context, func.count(models.Volume.id), func.sum(models.Volume.size), read_deleted="no", session=session).\ - filter_by(project_id=project_id) - - if user_id: - result = result.filter_by(user_id=user_id).first() - else: - result = result.first() + filter_by(project_id=project_id).\ + first() + # NOTE(vish): convert None to 0 return (result[0] or 0, result[1] or 0) @require_admin_context -def volume_data_get_for_user(context, user_id, project_id, session=None): - return _get_volume_data(context, project_id, user_id=user_id, - session=session) - - -@require_admin_context -def volume_data_get_for_project(context, project_id, session=None): - return _get_volume_data(context, project_id, session=session) - - -@require_admin_context def volume_destroy(context, volume_id): session = get_session() with session.begin(): @@ -3637,14 +3459,6 @@ def security_group_get_by_name(context, project_id, group_name, @require_context -def security_group_get_by_user(context, user_id, project_id): - return _security_group_get_query(context, read_deleted="no").\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - all() - - -@require_context def security_group_get_by_project(context, project_id): return _security_group_get_query(context, read_deleted="no").\ filter_by(project_id=project_id).\ @@ -3740,16 +3554,6 @@ def security_group_destroy(context, security_group_id): @require_context -def security_group_count_by_user(context, user_id, project_id, session=None): - authorize_project_context(context, project_id) - return model_query(context, models.SecurityGroup, read_deleted="no", - session=session).\ - filter_by(user_id=user_id).\ - filter_by(project_id=project_id).\ - count() - - -@require_context def security_group_count_by_project(context, project_id, session=None): authorize_project_context(context, project_id) return model_query(context, models.SecurityGroup, read_deleted="no", diff --git a/nova/db/sqlalchemy/migrate_repo/versions/116_drop_user_quotas_key_and_value.py b/nova/db/sqlalchemy/migrate_repo/versions/116_drop_user_quotas_key_and_value.py new file mode 100644 index 000000000..ccf9d66b8 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/116_drop_user_quotas_key_and_value.py @@ -0,0 +1,98 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# +# 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. + +from nova.openstack.common import log as logging +from sqlalchemy import Boolean, Column, DateTime, Integer +from sqlalchemy import MetaData, String, Table + +LOG = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + # Reverse the previous migration + meta = MetaData() + meta.bind = migrate_engine + + reservations = Table('reservations', meta, autoload=True) + d = reservations.delete(reservations.c.deleted == True) + d.execute() + reservations.drop_column('user_id') + + quota_usages = Table('quota_usages', meta, autoload=True) + d = quota_usages.delete(quota_usages.c.user_id != None) + d.execute() + quota_usages.drop_column('user_id') + + user_quotas = Table('user_quotas', meta, autoload=True) + try: + user_quotas.drop() + except Exception: + LOG.error(_("user_quotas table not dropped")) + raise + + +def downgrade(migrate_engine): + # Undo the reversal of the previous migration + # (data is not preserved) + meta = MetaData() + meta.bind = migrate_engine + + # Add 'user_id' column to quota_usages table. + quota_usages = Table('quota_usages', meta, autoload=True) + user_id = Column('user_id', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False)) + quota_usages.create_column(user_id) + + # Add 'user_id' column to reservations table. + reservations = Table('reservations', meta, autoload=True) + user_id = Column('user_id', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False)) + reservations.create_column(user_id) + + # New table. + user_quotas = Table('user_quotas', meta, + Column('id', Integer(), primary_key=True), + Column('created_at', DateTime(timezone=False)), + Column('updated_at', DateTime(timezone=False)), + Column('deleted_at', DateTime(timezone=False)), + Column('deleted', Boolean(), default=False), + Column('user_id', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False)), + Column('project_id', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False)), + Column('resource', + String(length=255, convert_unicode=False, + assert_unicode=None, unicode_error=None, + _warn_on_bytestring=False), + nullable=False), + Column('hard_limit', Integer(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8', + ) + + try: + user_quotas.create() + except Exception: + LOG.error(_("Table |%s| not created!"), repr(user_quotas)) + raise diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index fa3ebe8f0..7d4435a7a 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -428,19 +428,6 @@ class Quota(BASE, NovaBase): hard_limit = Column(Integer, nullable=True) -class UserQuota(BASE, NovaBase): - """Represents a single quota override for a user.""" - - __tablename__ = 'user_quotas' - id = Column(Integer, primary_key=True) - - user_id = Column(String(255), index=True) - project_id = Column(String(255), index=True) - - resource = Column(String(255)) - hard_limit = Column(Integer, nullable=True) - - class QuotaClass(BASE, NovaBase): """Represents a single quota override for a quota class. @@ -464,7 +451,6 @@ class QuotaUsage(BASE, NovaBase): __tablename__ = 'quota_usages' id = Column(Integer, primary_key=True) - user_id = Column(String(255), index=True) project_id = Column(String(255), index=True) resource = Column(String(255)) @@ -487,7 +473,6 @@ class Reservation(BASE, NovaBase): usage_id = Column(Integer, ForeignKey('quota_usages.id'), nullable=False) - user_id = Column(String(255), index=True) project_id = Column(String(255), index=True) resource = Column(String(255)) |
