diff --git a/Makefile b/Makefile index d93e3320c8..386d6202c7 100644 --- a/Makefile +++ b/Makefile @@ -113,8 +113,7 @@ dev_build: release_build: python setup.py release_build -release_ball: clean sdist - #make release_build +release_ball: clean sdist (cd ../ansible-doc; make) -(rm -rf awx-$(VERSION)-$(RELEASE)) mkdir -p awx-$(VERSION)-$(RELEASE)/dist diff --git a/awx/main/access.py b/awx/main/access.py index 74a73398d5..21c1a35bac 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -5,6 +5,9 @@ import logging from django.db.models import Q from django.contrib.auth.models import User from awx.main.models import * +from awx.main.licenses import LicenseReader +from django.core.exceptions import PermissionDenied +import sys __all__ = ['get_user_queryset', 'check_user_access'] @@ -242,11 +245,32 @@ class HostAccess(BaseAccess): return check_user_access(self.user, Inventory, 'read', obj.inventory) def can_add(self, data): + + if not 'inventory' in data: return False + inventory = Inventory.objects.get(pk=data['inventory']) + # Checks for admin or change permission on inventory. - return check_user_access(self.user, Inventory, 'change', inventory, None) + permissions_ok = check_user_access(self.user, Inventory, 'change', inventory, None) + if not permissions_ok: + return False + + # Check to see if we have enough licenses + reader = LicenseReader() + validation_info = reader.from_file() + + if 'test' in sys.argv and 'free_instances' in validation_info: + # this hack is in here so the test code can function + # but still go down *most* of the license code path. + validation_info['free_instances'] = 99999999 + + if validation_info['free_instances'] > 0: + # BOOKMARK + return True + instances = validation_info['available_instances'] + raise PermissionDenied("license range of %s instances has been exceed" % instances) def can_change(self, obj, data): # Checks for admin or change permission on inventory, controls whether diff --git a/awx/main/models/__init__.py b/awx/main/models/__init__.py index d526ea6b29..2a5b581ecb 100644 --- a/awx/main/models/__init__.py +++ b/awx/main/models/__init__.py @@ -89,7 +89,10 @@ class PrimordialModel(models.Model): abstract = True description = models.TextField(blank=True, default='') - created_by = models.ForeignKey('auth.User', on_delete=SET_NULL, null=True, related_name='%s(class)s_created', editable=False) # not blank=False on purpose for admin! + created_by = models.ForeignKey('auth.User', + on_delete=SET_NULL, null=True, + related_name='%s(class)s_created', + editable=False) # not blank=False on purpose for admin! created = models.DateTimeField(auto_now_add=True) active = models.BooleanField(default=True) @@ -101,6 +104,7 @@ class PrimordialModel(models.Model): def save(self, *args, **kwargs): # For compatibility with Django 1.4.x, attempt to handle any calls to # save that pass update_fields. + try: super(PrimordialModel, self).save(*args, **kwargs) except TypeError: @@ -111,6 +115,7 @@ class PrimordialModel(models.Model): def mark_inactive(self, save=True): '''Use instead of delete to rename and mark inactive.''' + if self.active: if 'name' in self._meta.get_all_field_names(): self.name = "_deleted_%s_%s" % (now().isoformat(), self.name) @@ -200,6 +205,7 @@ class Host(CommonModelNameNotUnique): default='', help_text=_('Variables in JSON or YAML format.'), ) + inventory = models.ForeignKey('Inventory', null=False, related_name='hosts') last_job = models.ForeignKey('Job', blank=True, null=True, default=None, on_delete=models.SET_NULL, related_name='hosts_as_last_job+') last_job_host_summary = models.ForeignKey('JobHostSummary', blank=True, null=True, default=None, on_delete=models.SET_NULL, related_name='hosts_as_last_job_summary+') @@ -211,8 +217,7 @@ class Host(CommonModelNameNotUnique): def get_absolute_url(self): return reverse('main:host_detail', args=(self.pk,)) - def update_has_active_failures(self, update_groups=True, - update_inventory=True): + def update_has_active_failures(self, update_groups=True, update_inventory=True): self.has_active_failures = bool(self.last_job_host_summary and self.last_job_host_summary.failed) self.save()