Merge pull request #1536 from chrismeyersfsu/fix-protect_instance_groups

prevent instance group delete if running jobs
This commit is contained in:
Chris Meyers
2018-03-15 14:57:45 -04:00
committed by GitHub
15 changed files with 337 additions and 129 deletions
+9 -79
View File
@@ -15,7 +15,7 @@ from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
# Django REST Framework
from rest_framework.exceptions import ParseError, PermissionDenied, ValidationError
from rest_framework.exceptions import ParseError, PermissionDenied
# Django OAuth Toolkit
from awx.main.models.oauth import OAuth2Application, OAuth2AccessToken
@@ -28,14 +28,13 @@ from awx.main.utils import (
get_licenser,
)
from awx.main.models import * # noqa
from awx.main.models.unified_jobs import ACTIVE_STATES
from awx.main.models.mixins import ResourceMixin
from awx.conf.license import LicenseForbids, feature_enabled
__all__ = ['get_user_queryset', 'check_user_access', 'check_user_access_with_errors',
'user_accessible_objects', 'consumer_access',
'user_admin_role', 'ActiveJobConflict',]
'user_admin_role',]
logger = logging.getLogger('awx.main.access')
@@ -75,16 +74,6 @@ def get_object_from_data(field, Model, data, obj=None):
raise ParseError(_("Bad data found in related field %s." % field))
class ActiveJobConflict(ValidationError):
status_code = 409
def __init__(self, active_jobs):
super(ActiveJobConflict, self).__init__({
"conflict": _("Resource is being used by running jobs."),
"active_jobs": active_jobs
})
def register_access(model_class, access_class):
access_registry[model_class] = access_class
@@ -473,9 +462,6 @@ class InstanceGroupAccess(BaseAccess):
def can_change(self, obj, data):
return self.user.is_superuser
def can_delete(self, obj):
return self.user.is_superuser
class UserAccess(BaseAccess):
'''
@@ -658,15 +644,6 @@ class OrganizationAccess(BaseAccess):
is_change_possible = self.can_change(obj, None)
if not is_change_possible:
return False
active_jobs = []
active_jobs.extend([dict(type="job", id=o.id)
for o in Job.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES)])
active_jobs.extend([dict(type="project_update", id=o.id)
for o in ProjectUpdate.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES)])
active_jobs.extend([dict(type="inventory_update", id=o.id)
for o in InventoryUpdate.objects.filter(inventory_source__inventory__organization=obj, status__in=ACTIVE_STATES)])
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
@@ -749,19 +726,7 @@ class InventoryAccess(BaseAccess):
return self.user in obj.update_role
def can_delete(self, obj):
is_can_admin = self.can_admin(obj, None)
if not is_can_admin:
return False
active_jobs = []
active_jobs.extend([dict(type="job", id=o.id)
for o in Job.objects.filter(inventory=obj, status__in=ACTIVE_STATES)])
active_jobs.extend([dict(type="inventory_update", id=o.id)
for o in InventoryUpdate.objects.filter(inventory_source__inventory=obj, status__in=ACTIVE_STATES)])
active_jobs.extend([dict(type="ad_hoc_command", id=o.id)
for o in AdHocCommand.objects.filter(inventory=obj, status__in=ACTIVE_STATES)])
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
return self.can_admin(obj, None)
def can_run_ad_hoc_commands(self, obj):
return self.user in obj.adhoc_role
@@ -878,15 +843,7 @@ class GroupAccess(BaseAccess):
return True
def can_delete(self, obj):
is_delete_allowed = bool(obj and self.user in obj.inventory.admin_role)
if not is_delete_allowed:
return False
active_jobs = []
active_jobs.extend([dict(type="inventory_update", id=o.id)
for o in InventoryUpdate.objects.filter(inventory_source__in=obj.inventory_sources.all(), status__in=ACTIVE_STATES)])
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
return bool(obj and self.user in obj.inventory.admin_role)
def can_start(self, obj, validate_license=True):
# TODO: Delete for 3.3, only used by v1 serializer
@@ -935,9 +892,6 @@ class InventorySourceAccess(BaseAccess):
if not self.user.is_superuser and \
not (obj and obj.inventory and self.user.can_access(Inventory, 'admin', obj.inventory, None)):
return False
active_jobs_qs = InventoryUpdate.objects.filter(inventory_source=obj, status__in=ACTIVE_STATES)
if active_jobs_qs.exists():
raise ActiveJobConflict([dict(type="inventory_update", id=o.id) for o in active_jobs_qs.all()])
return True
@check_superuser
@@ -1199,23 +1153,13 @@ class ProjectAccess(BaseAccess):
return False
return self.user in obj.admin_role
def can_delete(self, obj):
is_change_allowed = self.can_change(obj, None)
if not is_change_allowed:
return False
active_jobs = []
active_jobs.extend([dict(type="job", id=o.id)
for o in Job.objects.filter(project=obj, status__in=ACTIVE_STATES)])
active_jobs.extend([dict(type="project_update", id=o.id)
for o in ProjectUpdate.objects.filter(project=obj, status__in=ACTIVE_STATES)])
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
@check_superuser
def can_start(self, obj, validate_license=True):
return obj and self.user in obj.update_role
def can_delete(self, obj):
return self.can_change(obj, None)
class ProjectUpdateAccess(BaseAccess):
'''
@@ -1382,14 +1326,7 @@ class JobTemplateAccess(BaseAccess):
return True
def can_delete(self, obj):
is_delete_allowed = self.user.is_superuser or self.user in obj.admin_role
if not is_delete_allowed:
return False
active_jobs = [dict(type="job", id=o.id)
for o in obj.jobs.filter(status__in=ACTIVE_STATES)]
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
return self.user.is_superuser or self.user in obj.admin_role
@check_superuser
def can_attach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
@@ -1890,14 +1827,7 @@ class WorkflowJobTemplateAccess(BaseAccess):
self.user in obj.admin_role)
def can_delete(self, obj):
is_delete_allowed = self.user.is_superuser or self.user in obj.admin_role
if not is_delete_allowed:
return False
active_jobs = [dict(type="workflow_job", id=o.id)
for o in obj.workflow_jobs.filter(status__in=ACTIVE_STATES)]
if len(active_jobs) > 0:
raise ActiveJobConflict(active_jobs)
return True
return self.user.is_superuser or self.user in obj.admin_role
class WorkflowJobAccess(BaseAccess):