From ba070c39f6c1e7fc093f2a2b25a37c341cc4b43c Mon Sep 17 00:00:00 2001 From: Giorgos Korfiatis <gkorf@grnet.gr> Date: Mon, 7 Oct 2013 15:56:17 +0300 Subject: [PATCH] astakos: Remove custom commit_on_success decorator Prior to 1.3, django wouldn't set the transaction dirty upon a DB exception and thus wouldn't trigger a rollback, resulting in a dangling aborted DB exception. See https://code.djangoproject.com/ticket/9964 Since this is now fixed, there is no need for our custom transaction management. --- snf-astakos-app/astakos/api/projects.py | 26 +++++----- snf-astakos-app/astakos/api/quotas.py | 9 ++-- .../management/commands/component-remove.py | 4 +- .../im/management/commands/project-control.py | 4 +- .../astakos/im/management/commands/quota.py | 4 +- .../commands/reconcile-resources-astakos.py | 4 +- .../im/management/commands/resource-import.py | 4 +- .../im/management/commands/service-import.py | 4 +- .../im/management/commands/user-add.py | 4 +- .../im/management/commands/user-modify.py | 4 +- snf-astakos-app/astakos/im/views/projects.py | 27 +++++----- snf-astakos-app/astakos/test/stress.py | 4 +- snf-astakos-app/astakos/test/views.py | 10 ++-- .../snf_django/lib/db/transaction.py | 52 ------------------- 14 files changed, 53 insertions(+), 107 deletions(-) delete mode 100644 snf-django-lib/snf_django/lib/db/transaction.py diff --git a/snf-astakos-app/astakos/api/projects.py b/snf-astakos-app/astakos/api/projects.py index 4bb775b12..fdfb98341 100644 --- a/snf-astakos-app/astakos/api/projects.py +++ b/snf-astakos-app/astakos/api/projects.py @@ -36,8 +36,8 @@ from django.utils import simplejson as json from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse from django.db.models import Q +from django.db import transaction -from snf_django.lib.db.transaction import commit_on_success_strict from astakos.api.util import json_response from snf_django.lib import api @@ -271,7 +271,7 @@ def projects(request): @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def get_projects(request): user = request.user input_data = read_json_body(request, default={}) @@ -299,7 +299,7 @@ def _get_projects(query, request_user=None): @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def create_project(request): user = request.user data = request.body @@ -319,7 +319,7 @@ def project(request, project_id): @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def get_project(request, project_id): user = request.user with ExceptionHandler(): @@ -337,7 +337,7 @@ def _get_project(project_id, request_user=None): @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def modify_project(request, project_id): user = request.user data = request.body @@ -466,7 +466,7 @@ PROJECT_ACTION = { @csrf_exempt @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def project_action(request, project_id): user = request.user data = request.body @@ -497,7 +497,7 @@ def make_application_query(input_data): @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def get_applications(request): user = request.user input_data = read_json_body(request, default={}) @@ -520,7 +520,7 @@ def _get_applications(query, request_user=None): @csrf_exempt @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def application(request, app_id): user = request.user with ExceptionHandler(): @@ -547,7 +547,7 @@ APPLICATION_ACTION = { @csrf_exempt @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def application_action(request, app_id): user = request.user data = request.body @@ -581,7 +581,7 @@ def make_membership_query(input_data): @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def get_memberships(request): user = request.user input_data = read_json_body(request, default={}) @@ -631,7 +631,7 @@ MEMBERSHIPS_ACTION = { @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def post_memberships(request): user = request.user data = request.body @@ -642,7 +642,7 @@ def post_memberships(request): @api.api_method(http_method="GET", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def membership(request, memb_id): user = request.user with ExceptionHandler(): @@ -669,7 +669,7 @@ MEMBERSHIP_ACTION = { @csrf_exempt @api.api_method(http_method="POST", token_required=True, user_required=False) @user_from_token -@commit_on_success_strict() +@transaction.commit_on_success def membership_action(request, memb_id): user = request.user input_data = read_json_body(request, default={}) diff --git a/snf-astakos-app/astakos/api/quotas.py b/snf-astakos-app/astakos/api/quotas.py index 3bc4cd7d4..1475c8de0 100644 --- a/snf-astakos-app/astakos/api/quotas.py +++ b/snf-astakos-app/astakos/api/quotas.py @@ -34,8 +34,7 @@ from django.utils import simplejson as json from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse - -from snf_django.lib.db.transaction import commit_on_success_strict +from django.db import transaction from snf_django.lib import api from snf_django.lib.api.faults import BadRequest, ItemNotFound @@ -175,7 +174,7 @@ def issue_commission(request): return json_response(data, status_code=status_code) -@commit_on_success_strict() +@transaction.commit_on_success def _issue_commission(clientkey, provisions, name, force, accept): serial = qh.issue_commission(clientkey=clientkey, provisions=provisions, @@ -204,7 +203,7 @@ def conflictingCF(serial): @csrf_exempt @api.api_method(http_method='POST', token_required=True, user_required=False) @component_from_token -@commit_on_success_strict() +@transaction.commit_on_success def resolve_pending_commissions(request): data = request.body try: @@ -260,7 +259,7 @@ def get_commission(request, serial): @csrf_exempt @api.api_method(http_method='POST', token_required=True, user_required=False) @component_from_token -@commit_on_success_strict() +@transaction.commit_on_success def serial_action(request, serial): data = request.body try: diff --git a/snf-astakos-app/astakos/im/management/commands/component-remove.py b/snf-astakos-app/astakos/im/management/commands/component-remove.py index e2593ecf1..b6db6626e 100644 --- a/snf-astakos-app/astakos/im/management/commands/component-remove.py +++ b/snf-astakos-app/astakos/im/management/commands/component-remove.py @@ -32,15 +32,15 @@ # or implied, of GRNET S.A. from django.core.management.base import BaseCommand, CommandError +from django.db import transaction from astakos.im.models import Component -from snf_django.lib.db.transaction import commit_on_success_strict class Command(BaseCommand): args = "<component ID or name>" help = "Remove a component along with its registered services" - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): if len(args) != 1: raise CommandError("Please provide a component ID or name") diff --git a/snf-astakos-app/astakos/im/management/commands/project-control.py b/snf-astakos-app/astakos/im/management/commands/project-control.py index 12981f819..4627e6e8a 100644 --- a/snf-astakos-app/astakos/im/management/commands/project-control.py +++ b/snf-astakos-app/astakos/im/management/commands/project-control.py @@ -33,11 +33,11 @@ from optparse import make_option +from django.db import transaction from django.core.management.base import BaseCommand, CommandError from astakos.im.functions import (terminate, suspend, unsuspend, reinstate, check_expiration, approve_application, deny_application) -from snf_django.lib.db.transaction import commit_on_success_strict class Command(BaseCommand): @@ -86,7 +86,7 @@ class Command(BaseCommand): "e.g. when denying a project")), ) - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): message = options['message'] diff --git a/snf-astakos-app/astakos/im/management/commands/quota.py b/snf-astakos-app/astakos/im/management/commands/quota.py index e848ab195..3cea21d66 100644 --- a/snf-astakos-app/astakos/im/management/commands/quota.py +++ b/snf-astakos-app/astakos/im/management/commands/quota.py @@ -33,13 +33,13 @@ from optparse import make_option from django.core.management.base import CommandError +from django.db import transaction from astakos.im.models import AstakosUser from astakos.im.quotas import ( qh_sync_users_diffs, list_user_quotas, add_base_quota) from astakos.im.functions import get_user_by_uuid from astakos.im.management.commands._common import is_uuid, is_email -from snf_django.lib.db.transaction import commit_on_success_strict from snf_django.management.commands import SynnefoCommand from snf_django.management import utils from ._common import show_quotas, style_options, check_style, units @@ -87,7 +87,7 @@ class Command(SynnefoCommand): ), ) - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): sync = options['sync'] verify = options['verify'] diff --git a/snf-astakos-app/astakos/im/management/commands/reconcile-resources-astakos.py b/snf-astakos-app/astakos/im/management/commands/reconcile-resources-astakos.py index 479589702..79d1849f1 100644 --- a/snf-astakos-app/astakos/im/management/commands/reconcile-resources-astakos.py +++ b/snf-astakos-app/astakos/im/management/commands/reconcile-resources-astakos.py @@ -34,9 +34,9 @@ from optparse import make_option from django.core.management.base import BaseCommand, CommandError +from django.db import transaction from snf_django.management.utils import pprint_table -from snf_django.lib.db.transaction import commit_on_success_strict from astakos.im.models import Component, AstakosUser from astakos.im.quotas import service_get_quotas, SYSTEM from astakos.im.functions import count_pending_app @@ -67,7 +67,7 @@ class Command(BaseCommand): " the quota, independently of their value.") ) - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): write = self.stdout.write force = options['force'] diff --git a/snf-astakos-app/astakos/im/management/commands/resource-import.py b/snf-astakos-app/astakos/im/management/commands/resource-import.py index a1917c0d0..c9dd997ca 100644 --- a/snf-astakos-app/astakos/im/management/commands/resource-import.py +++ b/snf-astakos-app/astakos/im/management/commands/resource-import.py @@ -33,10 +33,10 @@ from optparse import make_option +from django.db import transaction from django.core.management.base import BaseCommand, CommandError from django.utils import simplejson as json -from snf_django.lib.db.transaction import commit_on_success_strict from astakos.im.register import add_resource, RegisterException from ._common import read_from_file @@ -69,7 +69,7 @@ class Command(BaseCommand): raise CommandError(m) self.add_resources(data) - @commit_on_success_strict() + @transaction.commit_on_success def add_resources(self, resources): output = [] for resource in resources: diff --git a/snf-astakos-app/astakos/im/management/commands/service-import.py b/snf-astakos-app/astakos/im/management/commands/service-import.py index 2dd2e1d8f..087b9c67e 100644 --- a/snf-astakos-app/astakos/im/management/commands/service-import.py +++ b/snf-astakos-app/astakos/im/management/commands/service-import.py @@ -33,10 +33,10 @@ from optparse import make_option +from django.db import transaction from django.core.management.base import BaseCommand, CommandError from django.utils import simplejson as json -from snf_django.lib.db.transaction import commit_on_success_strict from astakos.im.register import add_service, add_resource, RegisterException from astakos.im.models import Component from ._common import read_from_file @@ -52,7 +52,7 @@ class Command(BaseCommand): help="Load service definitions from a json file"), ) - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): json_file = options['json'] diff --git a/snf-astakos-app/astakos/im/management/commands/user-add.py b/snf-astakos-app/astakos/im/management/commands/user-add.py index 05cefb1df..9d0fca21d 100644 --- a/snf-astakos-app/astakos/im/management/commands/user-add.py +++ b/snf-astakos-app/astakos/im/management/commands/user-add.py @@ -33,10 +33,10 @@ from optparse import make_option +from django.db import transaction from django.core.management.base import BaseCommand, CommandError from django.core.validators import validate_email from django.core.exceptions import ValidationError -from snf_django.lib.db import transaction from astakos.im.models import AstakosUser @@ -67,7 +67,7 @@ class Command(BaseCommand): help="Add user permission (may be used multiple times)") ) - @transaction.commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): if len(args) != 3: raise CommandError("Invalid number of arguments") diff --git a/snf-astakos-app/astakos/im/management/commands/user-modify.py b/snf-astakos-app/astakos/im/management/commands/user-modify.py index f1fd2ebd8..607684af6 100644 --- a/snf-astakos-app/astakos/im/management/commands/user-modify.py +++ b/snf-astakos-app/astakos/im/management/commands/user-modify.py @@ -36,6 +36,7 @@ import string from optparse import make_option from django.core import management +from django.db import transaction from django.core.management.base import BaseCommand, CommandError from django.contrib.auth.models import Group from django.core.exceptions import ValidationError @@ -47,7 +48,6 @@ from astakos.im import quotas from astakos.im import activation_backends from ._common import (remove_user_permission, add_user_permission, is_uuid, show_resource_value) -from snf_django.lib.db.transaction import commit_on_success_strict activation_backend = activation_backends.get_backend() @@ -151,7 +151,7 @@ class Command(BaseCommand): help="Delete user"), ) - @commit_on_success_strict() + @transaction.commit_on_success def handle(self, *args, **options): if len(args) != 1: raise CommandError("Please provide a user ID") diff --git a/snf-astakos-app/astakos/im/views/projects.py b/snf-astakos-app/astakos/im/views/projects.py index d47f1dbe4..91f6ace28 100644 --- a/snf-astakos-app/astakos/im/views/projects.py +++ b/snf-astakos-app/astakos/im/views/projects.py @@ -48,8 +48,7 @@ from django.utils.translation import ugettext as _ from django.views.generic.list_detail import object_list, object_detail from django.core.exceptions import PermissionDenied from django.views.decorators.http import require_http_methods - -from snf_django.lib.db.transaction import commit_on_success_strict +from django.db import transaction import astakos.im.messages as astakos_messages @@ -123,7 +122,7 @@ def project_add(request): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def create_app_object(request, extra_context=None): try: summary = 'im/projects/projectapplication_form_summary.html' @@ -191,7 +190,7 @@ def project_app_cancel(request, application_id): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def _project_app_cancel(request, application_id): chain_id = None try: @@ -264,7 +263,7 @@ def project_modify(request, application_id): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def update_app_object(request, object_id, extra_context=None): try: summary = 'im/projects/projectapplication_form_summary.html' @@ -296,7 +295,7 @@ def project_detail(request, chain_id): return common_detail(request, chain_id) -@commit_on_success_strict() +@transaction.commit_on_success def addmembers(request, chain_id, addmembers_form): if addmembers_form.is_valid(): try: @@ -476,7 +475,7 @@ def project_join(request, chain_id): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def _project_join(request, chain_id): try: chain_id = int(chain_id) @@ -505,7 +504,7 @@ def project_leave(request, memb_id): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def _project_leave(request, memb_id): try: memb_id = int(memb_id) @@ -534,7 +533,7 @@ def project_cancel_member(request, memb_id): return redirect(next) -@commit_on_success_strict() +@transaction.commit_on_success def _project_cancel_member(request, memb_id): try: cancel_membership(memb_id, request.user) @@ -555,7 +554,7 @@ def project_accept_member(request, memb_id): return redirect_back(request, 'project_list') -@commit_on_success_strict() +@transaction.commit_on_success def _project_accept_member(request, memb_id): try: memb_id = int(memb_id) @@ -580,7 +579,7 @@ def project_remove_member(request, memb_id): return redirect_back(request, 'project_list') -@commit_on_success_strict() +@transaction.commit_on_success def _project_remove_member(request, memb_id): try: memb_id = int(memb_id) @@ -604,7 +603,7 @@ def project_reject_member(request, memb_id): return redirect_back(request, 'project_list') -@commit_on_success_strict() +@transaction.commit_on_success def _project_reject_member(request, memb_id): try: memb_id = int(memb_id) @@ -641,7 +640,7 @@ def project_app_approve(request, application_id): return redirect(reverse('project_detail', args=(chain_id,))) -@commit_on_success_strict() +@transaction.commit_on_success def _project_app_approve(request, application_id): approve_application(application_id) @@ -671,7 +670,7 @@ def project_app_deny(request, application_id): return redirect(reverse('project_list')) -@commit_on_success_strict() +@transaction.commit_on_success def _project_app_deny(request, application_id, reason): deny_application(application_id, reason=reason) diff --git a/snf-astakos-app/astakos/test/stress.py b/snf-astakos-app/astakos/test/stress.py index 4f62677d3..3aab7113c 100755 --- a/snf-astakos-app/astakos/test/stress.py +++ b/snf-astakos-app/astakos/test/stress.py @@ -46,11 +46,11 @@ path = os.path.dirname(os.path.realpath(__file__)) os.environ['SYNNEFO_SETTINGS_DIR'] = path + '/settings' os.environ['DJANGO_SETTINGS_MODULE'] = 'synnefo.settings' +from django.db import transaction from astakos.im.models import AstakosUser from astakos.im.functions import ProjectError from astakos.im import quotas from views import submit, approve, join, leave -from snf_django.lib.db.transaction import commit_on_success_strict USERS = {} PROJECTS = {} @@ -90,7 +90,7 @@ def new_user(): return None -@commit_on_success_strict() +@transaction.commit_on_success def new_users(count): for i in range(count): while True: diff --git a/snf-astakos-app/astakos/test/views.py b/snf-astakos-app/astakos/test/views.py index 8e658b9b7..549394556 100644 --- a/snf-astakos-app/astakos/test/views.py +++ b/snf-astakos-app/astakos/test/views.py @@ -33,25 +33,25 @@ from datetime import datetime, timedelta +from django.db import transaction from astakos.im.models import AstakosUser, Project from astakos.im.functions import (join_project, leave_project, submit_application, approve_application, check_pending_app_quota, ProjectForbidden) -from snf_django.lib.db.transaction import commit_on_success_strict -@commit_on_success_strict() +@transaction.commit_on_success def join(proj_id, user): return join_project(proj_id, user) -@commit_on_success_strict() +@transaction.commit_on_success def leave(memb_id, request_user): return leave_project(memb_id, request_user) -@commit_on_success_strict() +@transaction.commit_on_success def submit(name, user_id, project_id=None): try: owner = AstakosUser.objects.get(id=user_id) @@ -79,6 +79,6 @@ def submit(name, user_id, project_id=None): return app.id, app.chain_id -@commit_on_success_strict() +@transaction.commit_on_success def approve(app_id): approve_application(app_id) diff --git a/snf-django-lib/snf_django/lib/db/transaction.py b/snf-django-lib/snf_django/lib/db/transaction.py deleted file mode 100644 index eb6d33013..000000000 --- a/snf-django-lib/snf_django/lib/db/transaction.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2013 GRNET S.A. All rights reserved. -# -# Redistribution and use in source and binary forms, with or -# without modification, are permitted provided that the following -# conditions are met: -# -# 1. Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials -# provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and -# documentation are those of the authors and should not be -# interpreted as representing official policies, either expressed -# or implied, of GRNET S.A. - - -from functools import wraps -from django.db import transaction - - -def commit_on_success_strict(**kwargs): - def wrap(func): - @wraps(func) - @transaction.commit_manually(**kwargs) - def inner(*args, **kwargs): - try: - result = func(*args, **kwargs) - transaction.commit() - return result - except BaseException as e: - transaction.rollback() - raise - return inner - return wrap -- GitLab