mirror of
https://github.com/ansible/awx.git
synced 2026-01-23 15:38:06 -03:30
Merge branch 'devel' into uxi/templates
This commit is contained in:
commit
81dea61ba9
1
.gitignore
vendored
1
.gitignore
vendored
@ -108,6 +108,7 @@ reports
|
|||||||
*.results
|
*.results
|
||||||
local/
|
local/
|
||||||
*.mo
|
*.mo
|
||||||
|
requirements/vendor
|
||||||
|
|
||||||
# AWX python libs populated by requirements.txt
|
# AWX python libs populated by requirements.txt
|
||||||
awx/lib/.deps_built
|
awx/lib/.deps_built
|
||||||
|
|||||||
54
Makefile
54
Makefile
@ -225,15 +225,18 @@ clean-tmp:
|
|||||||
clean-venv:
|
clean-venv:
|
||||||
rm -rf venv/
|
rm -rf venv/
|
||||||
|
|
||||||
|
clean-dist:
|
||||||
|
rm -rf dist
|
||||||
|
|
||||||
# Remove temporary build files, compiled Python files.
|
# Remove temporary build files, compiled Python files.
|
||||||
clean: clean-rpm clean-deb clean-ui clean-tar clean-packer clean-bundle
|
clean: clean-rpm clean-deb clean-ui clean-tar clean-packer clean-bundle clean-dist
|
||||||
rm -rf awx/public
|
rm -rf awx/public
|
||||||
rm -rf awx/lib/site-packages
|
rm -rf awx/lib/site-packages
|
||||||
rm -rf dist/*
|
|
||||||
rm -rf awx/job_status
|
rm -rf awx/job_status
|
||||||
rm -rf awx/job_output
|
rm -rf awx/job_output
|
||||||
rm -rf reports
|
rm -rf reports
|
||||||
rm -f awx/awx_test.sqlite3
|
rm -f awx/awx_test.sqlite3
|
||||||
|
rm -rf requirements/vendor
|
||||||
rm -rf tmp
|
rm -rf tmp
|
||||||
mkdir tmp
|
mkdir tmp
|
||||||
rm -rf build $(NAME)-$(VERSION) *.egg-info
|
rm -rf build $(NAME)-$(VERSION) *.egg-info
|
||||||
@ -282,7 +285,11 @@ virtualenv_tower:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
requirements_ansible: virtualenv_ansible
|
requirements_ansible: virtualenv_ansible
|
||||||
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed --no-binary $(SRC_ONLY_PKGS) -r requirements/requirements_ansible.txt
|
if [[ "$(PIP_OPTIONS)" == *"--no-index"* ]]; then \
|
||||||
|
cat requirements/requirements_ansible.txt requirements/requirements_ansible_local.txt | $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed -r /dev/stdin ; \
|
||||||
|
else \
|
||||||
|
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) --ignore-installed -r /dev/stdin ; \
|
||||||
|
fi
|
||||||
$(VENV_BASE)/ansible/bin/pip uninstall --yes -r requirements/requirements_ansible_uninstall.txt
|
$(VENV_BASE)/ansible/bin/pip uninstall --yes -r requirements/requirements_ansible_uninstall.txt
|
||||||
|
|
||||||
requirements_ansible_dev:
|
requirements_ansible_dev:
|
||||||
@ -292,7 +299,11 @@ requirements_ansible_dev:
|
|||||||
|
|
||||||
# Install third-party requirements needed for Tower's environment.
|
# Install third-party requirements needed for Tower's environment.
|
||||||
requirements_tower: virtualenv_tower
|
requirements_tower: virtualenv_tower
|
||||||
$(VENV_BASE)/tower/bin/pip install $(PIP_OPTIONS) --ignore-installed --no-binary $(SRC_ONLY_PKGS) -r requirements/requirements.txt
|
if [[ "$(PIP_OPTIONS)" == *"--no-index"* ]]; then \
|
||||||
|
cat requirements/requirements.txt requirements/requirements_local.txt | $(VENV_BASE)/tower/bin/pip install $(PIP_OPTIONS) --ignore-installed -r /dev/stdin ; \
|
||||||
|
else \
|
||||||
|
cat requirements/requirements.txt requirements/requirements_git.txt | $(VENV_BASE)/tower/bin/pip install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) --ignore-installed -r /dev/stdin ; \
|
||||||
|
fi
|
||||||
$(VENV_BASE)/tower/bin/pip uninstall --yes -r requirements/requirements_tower_uninstall.txt
|
$(VENV_BASE)/tower/bin/pip uninstall --yes -r requirements/requirements_tower_uninstall.txt
|
||||||
|
|
||||||
requirements_tower_dev:
|
requirements_tower_dev:
|
||||||
@ -690,39 +701,44 @@ setup_bundle_tarball: setup-bundle-build setup-bundle-build/$(OFFLINE_TAR_FILE)
|
|||||||
rpm-build:
|
rpm-build:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
rpm-build/$(SDIST_TAR_FILE): rpm-build dist/$(SDIST_TAR_FILE)
|
rpm-build/$(SDIST_TAR_FILE): rpm-build dist/$(SDIST_TAR_FILE) tar-build/$(SETUP_TAR_FILE)
|
||||||
cp packaging/rpm/$(NAME).spec rpm-build/
|
cp packaging/rpm/$(NAME).spec rpm-build/
|
||||||
cp packaging/rpm/tower.te rpm-build/
|
cp packaging/rpm/tower.te rpm-build/
|
||||||
cp packaging/rpm/tower.fc rpm-build/
|
cp packaging/rpm/tower.fc rpm-build/
|
||||||
cp packaging/rpm/$(NAME).sysconfig rpm-build/
|
cp packaging/rpm/$(NAME).sysconfig rpm-build/
|
||||||
cp packaging/remove_tower_source.py rpm-build/
|
cp packaging/remove_tower_source.py rpm-build/
|
||||||
cp packaging/bytecompile.sh rpm-build/
|
cp packaging/bytecompile.sh rpm-build/
|
||||||
|
cp tar-build/$(SETUP_TAR_FILE) rpm-build/
|
||||||
if [ "$(OFFICIAL)" != "yes" ] ; then \
|
if [ "$(OFFICIAL)" != "yes" ] ; then \
|
||||||
(cd dist/ && tar zxf $(SDIST_TAR_FILE)) ; \
|
(cd dist/ && tar zxf $(SDIST_TAR_FILE)) ; \
|
||||||
(cd dist/ && mv $(NAME)-$(VERSION)-$(BUILD) $(NAME)-$(VERSION)) ; \
|
(cd dist/ && mv $(NAME)-$(VERSION)-$(BUILD) $(NAME)-$(VERSION)) ; \
|
||||||
(cd dist/ && tar czf ../rpm-build/$(SDIST_TAR_FILE) $(NAME)-$(VERSION)) ; \
|
(cd dist/ && tar czf ../rpm-build/$(SDIST_TAR_FILE) $(NAME)-$(VERSION)) ; \
|
||||||
ln -sf $(SDIST_TAR_FILE) rpm-build/$(NAME)-$(VERSION).tar.gz ; \
|
ln -sf $(SDIST_TAR_FILE) rpm-build/$(NAME)-$(VERSION).tar.gz ; \
|
||||||
|
(cd tar-build/ && tar zxf $(SETUP_TAR_FILE)) ; \
|
||||||
|
(cd tar-build/ && mv $(NAME)-setup-$(VERSION)-$(BUILD) $(NAME)-setup-$(VERSION)) ; \
|
||||||
|
(cd tar-build/ && tar czf ../rpm-build/$(SETUP_TAR_FILE) $(NAME)-setup-$(VERSION)) ; \
|
||||||
|
ln -sf $(SETUP_TAR_FILE) rpm-build/$(NAME)-setup-$(VERSION).tar.gz ; \
|
||||||
else \
|
else \
|
||||||
cp -a dist/$(SDIST_TAR_FILE) rpm-build/ ; \
|
cp -a dist/$(SDIST_TAR_FILE) rpm-build/ ; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rpmtar: sdist rpm-build/$(SDIST_TAR_FILE)
|
rpmtar: sdist rpm-build/$(SDIST_TAR_FILE)
|
||||||
|
|
||||||
brewrpmtar: rpm-build/python-deps.tar.gz rpmtar
|
brewrpmtar: rpm-build/python-deps.tar.gz requirements/requirements_local.txt requirements/requirements_ansible_local.txt rpmtar
|
||||||
|
|
||||||
rpm-build/python-deps.tar.gz: requirements/vendor rpm-build
|
rpm-build/python-deps.tar.gz: requirements/vendor rpm-build
|
||||||
tar czf rpm-build/python-deps.tar.gz requirements/vendor
|
tar czf rpm-build/python-deps.tar.gz requirements/vendor
|
||||||
|
|
||||||
requirements/vendor:
|
requirements/vendor:
|
||||||
pip download \
|
cat requirements/requirements.txt requirements/requirements_git.txt | pip download \
|
||||||
--no-binary=:all: \
|
--no-binary=:all: \
|
||||||
--requirement=requirements/requirements_ansible.txt \
|
--requirement=/dev/stdin \
|
||||||
--dest=$@ \
|
--dest=$@ \
|
||||||
--exists-action=i
|
--exists-action=i
|
||||||
|
|
||||||
pip download \
|
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | pip download \
|
||||||
--no-binary=:all: \
|
--no-binary=:all: \
|
||||||
--requirement=requirements/requirements.txt \
|
--requirement=/dev/stdin \
|
||||||
--dest=$@ \
|
--dest=$@ \
|
||||||
--exists-action=i
|
--exists-action=i
|
||||||
|
|
||||||
@ -732,6 +748,21 @@ requirements/vendor:
|
|||||||
--dest=$@ \
|
--dest=$@ \
|
||||||
--exists-action=i
|
--exists-action=i
|
||||||
|
|
||||||
|
requirements/requirements_local.txt:
|
||||||
|
@echo "This is going to take a while..."
|
||||||
|
pip download \
|
||||||
|
--requirement=requirements/requirements_git.txt \
|
||||||
|
--no-deps \
|
||||||
|
--exists-action=w \
|
||||||
|
--dest=requirements/vendor 2>/dev/null | sed -n 's/^\s*Saved\s*//p' > $@
|
||||||
|
|
||||||
|
requirements/requirements_ansible_local.txt:
|
||||||
|
pip download \
|
||||||
|
--requirement=requirements/requirements_ansible_git.txt \
|
||||||
|
--no-deps \
|
||||||
|
--exists-action=w \
|
||||||
|
--dest=requirements/vendor 2>/dev/null | sed -n 's/^\s*Saved\s*//p' > $@
|
||||||
|
|
||||||
rpm-build/$(RPM_NVR).src.rpm: /etc/mock/$(MOCK_CFG).cfg
|
rpm-build/$(RPM_NVR).src.rpm: /etc/mock/$(MOCK_CFG).cfg
|
||||||
$(MOCK_BIN) -r $(MOCK_CFG) --resultdir rpm-build --buildsrpm --spec rpm-build/$(NAME).spec --sources rpm-build \
|
$(MOCK_BIN) -r $(MOCK_CFG) --resultdir rpm-build --buildsrpm --spec rpm-build/$(NAME).spec --sources rpm-build \
|
||||||
--define "tower_version $(VERSION)" --define "tower_release $(RELEASE)" $(SCL_DEFINES)
|
--define "tower_version $(VERSION)" --define "tower_release $(RELEASE)" $(SCL_DEFINES)
|
||||||
@ -760,6 +791,9 @@ rpm-build/$(GPG_FILE): rpm-build
|
|||||||
|
|
||||||
rpm-sign: rpm-build/$(GPG_FILE) rpmtar rpm-build/$(RPM_NVR).$(RPM_ARCH).rpm
|
rpm-sign: rpm-build/$(GPG_FILE) rpmtar rpm-build/$(RPM_NVR).$(RPM_ARCH).rpm
|
||||||
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(RPM_NVR).$(RPM_ARCH).rpm
|
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(RPM_NVR).$(RPM_ARCH).rpm
|
||||||
|
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(NAME)-ui-$(VERSION)-$(RELEASE)$(RPM_DIST).$(RPM_ARCH).rpm
|
||||||
|
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(NAME)-server-$(VERSION)-$(RELEASE)$(RPM_DIST).$(RPM_ARCH).rpm
|
||||||
|
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(NAME)-setup-$(VERSION)-$(RELEASE)$(RPM_DIST).$(RPM_ARCH).rpm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
deb-build:
|
deb-build:
|
||||||
|
|||||||
@ -75,7 +75,7 @@ class FieldLookupBackend(BaseFilterBackend):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
RESERVED_NAMES = ('page', 'page_size', 'format', 'order', 'order_by',
|
RESERVED_NAMES = ('page', 'page_size', 'format', 'order', 'order_by',
|
||||||
'search', 'type')
|
'search', 'type', 'host_filter')
|
||||||
|
|
||||||
SUPPORTED_LOOKUPS = ('exact', 'iexact', 'contains', 'icontains',
|
SUPPORTED_LOOKUPS = ('exact', 'iexact', 'contains', 'icontains',
|
||||||
'startswith', 'istartswith', 'endswith', 'iendswith',
|
'startswith', 'istartswith', 'endswith', 'iendswith',
|
||||||
|
|||||||
@ -31,6 +31,7 @@ from awx.api.filters import FieldLookupBackend
|
|||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
from awx.main.utils import * # noqa
|
from awx.main.utils import * # noqa
|
||||||
from awx.api.serializers import ResourceAccessListElementSerializer
|
from awx.api.serializers import ResourceAccessListElementSerializer
|
||||||
|
from awx.api.versioning import URLPathVersioning
|
||||||
|
|
||||||
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
|
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
|
||||||
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
|
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
|
||||||
@ -86,6 +87,8 @@ def get_view_description(cls, html=False):
|
|||||||
|
|
||||||
class APIView(views.APIView):
|
class APIView(views.APIView):
|
||||||
|
|
||||||
|
versioning_class = URLPathVersioning
|
||||||
|
|
||||||
def initialize_request(self, request, *args, **kwargs):
|
def initialize_request(self, request, *args, **kwargs):
|
||||||
'''
|
'''
|
||||||
Store the Django REST Framework Request object as an attribute on the
|
Store the Django REST Framework Request object as an attribute on the
|
||||||
@ -161,6 +164,7 @@ class APIView(views.APIView):
|
|||||||
'new_in_240': getattr(self, 'new_in_240', False),
|
'new_in_240': getattr(self, 'new_in_240', False),
|
||||||
'new_in_300': getattr(self, 'new_in_300', False),
|
'new_in_300': getattr(self, 'new_in_300', False),
|
||||||
'new_in_310': getattr(self, 'new_in_310', False),
|
'new_in_310': getattr(self, 'new_in_310', False),
|
||||||
|
'new_in_320': getattr(self, 'new_in_320', False),
|
||||||
'deprecated': getattr(self, 'deprecated', False),
|
'deprecated': getattr(self, 'deprecated', False),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +192,23 @@ class APIView(views.APIView):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def determine_version(self, request, *args, **kwargs):
|
||||||
|
return (
|
||||||
|
getattr(request, 'version', None),
|
||||||
|
getattr(request, 'versioning_scheme', None),
|
||||||
|
)
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
if self.versioning_class is not None:
|
||||||
|
scheme = self.versioning_class()
|
||||||
|
request.version, request.versioning_scheme = (
|
||||||
|
scheme.determine_version(request, *args, **kwargs),
|
||||||
|
scheme
|
||||||
|
)
|
||||||
|
if 'version' in kwargs:
|
||||||
|
kwargs.pop('version')
|
||||||
|
return super(APIView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class GenericAPIView(generics.GenericAPIView, APIView):
|
class GenericAPIView(generics.GenericAPIView, APIView):
|
||||||
# Base class for all model-based views.
|
# Base class for all model-based views.
|
||||||
@ -424,7 +445,7 @@ class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
|
|||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
serializer = self.get_serializer(instance=obj)
|
serializer = self.get_serializer(instance=obj)
|
||||||
|
|
||||||
headers = {'Location': obj.get_absolute_url()}
|
headers = {'Location': obj.get_absolute_url(request)}
|
||||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,10 @@
|
|||||||
# Python
|
# Python
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
import six
|
import six
|
||||||
import logging
|
import urllib
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from dateutil import rrule
|
from dateutil import rrule
|
||||||
|
|
||||||
@ -18,7 +19,6 @@ from django.conf import settings
|
|||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
@ -43,11 +43,12 @@ from awx.main.models import * # noqa
|
|||||||
from awx.main.access import get_user_capabilities
|
from awx.main.access import get_user_capabilities
|
||||||
from awx.main.fields import ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField
|
||||||
from awx.main.utils import (
|
from awx.main.utils import (
|
||||||
get_type_for_model, get_model_for_type, build_url, timestamp_apiformat,
|
get_type_for_model, get_model_for_type, timestamp_apiformat,
|
||||||
camelcase_to_underscore, getattrd, parse_yaml_or_json)
|
camelcase_to_underscore, getattrd, parse_yaml_or_json)
|
||||||
from awx.main.validators import vars_validate_or_raise
|
from awx.main.validators import vars_validate_or_raise
|
||||||
|
|
||||||
from awx.conf.license import feature_enabled
|
from awx.conf.license import feature_enabled
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.api.fields import BooleanNullField, CharNullField, ChoiceNullField, EncryptedPasswordField, VerbatimField
|
from awx.api.fields import BooleanNullField, CharNullField, ChoiceNullField, EncryptedPasswordField, VerbatimField
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.serializers')
|
logger = logging.getLogger('awx.api.serializers')
|
||||||
@ -103,7 +104,7 @@ SUMMARIZABLE_FK_FIELDS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def reverse_gfk(content_object):
|
def reverse_gfk(content_object, request):
|
||||||
'''
|
'''
|
||||||
Computes a reverse for a GenericForeignKey field.
|
Computes a reverse for a GenericForeignKey field.
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ def reverse_gfk(content_object):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
camelcase_to_underscore(content_object.__class__.__name__): content_object.get_absolute_url()
|
camelcase_to_underscore(content_object.__class__.__name__): content_object.get_absolute_url(request=request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,9 +269,9 @@ class BaseSerializer(serializers.ModelSerializer):
|
|||||||
if obj is None or not hasattr(obj, 'get_absolute_url'):
|
if obj is None or not hasattr(obj, 'get_absolute_url'):
|
||||||
return ''
|
return ''
|
||||||
elif isinstance(obj, User):
|
elif isinstance(obj, User):
|
||||||
return reverse('api:user_detail', args=(obj.pk,))
|
return self.reverse('api:user_detail', kwargs={'pk': obj.pk})
|
||||||
else:
|
else:
|
||||||
return obj.get_absolute_url()
|
return obj.get_absolute_url(request=self.context.get('request'))
|
||||||
|
|
||||||
def _get_related(self, obj):
|
def _get_related(self, obj):
|
||||||
return {} if obj is None else self.get_related(obj)
|
return {} if obj is None else self.get_related(obj)
|
||||||
@ -278,9 +279,9 @@ class BaseSerializer(serializers.ModelSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = OrderedDict()
|
res = OrderedDict()
|
||||||
if getattr(obj, 'created_by', None):
|
if getattr(obj, 'created_by', None):
|
||||||
res['created_by'] = reverse('api:user_detail', args=(obj.created_by.pk,))
|
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
|
||||||
if getattr(obj, 'modified_by', None):
|
if getattr(obj, 'modified_by', None):
|
||||||
res['modified_by'] = reverse('api:user_detail', args=(obj.modified_by.pk,))
|
res['modified_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.modified_by.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_summary_fields(self, obj):
|
def _get_summary_fields(self, obj):
|
||||||
@ -496,6 +497,10 @@ class BaseSerializer(serializers.ModelSerializer):
|
|||||||
raise ValidationError(d)
|
raise ValidationError(d)
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
def reverse(self, *args, **kwargs):
|
||||||
|
kwargs['request'] = self.context.get('request')
|
||||||
|
return reverse(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EmptySerializer(serializers.Serializer):
|
class EmptySerializer(serializers.Serializer):
|
||||||
pass
|
pass
|
||||||
@ -525,11 +530,11 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(UnifiedJobTemplateSerializer, self).get_related(obj)
|
res = super(UnifiedJobTemplateSerializer, self).get_related(obj)
|
||||||
if obj.current_job:
|
if obj.current_job:
|
||||||
res['current_job'] = obj.current_job.get_absolute_url()
|
res['current_job'] = obj.current_job.get_absolute_url(request=self.context.get('request'))
|
||||||
if obj.last_job:
|
if obj.last_job:
|
||||||
res['last_job'] = obj.last_job.get_absolute_url()
|
res['last_job'] = obj.last_job.get_absolute_url(request=self.context.get('request'))
|
||||||
if obj.next_schedule:
|
if obj.next_schedule:
|
||||||
res['next_schedule'] = obj.next_schedule.get_absolute_url()
|
res['next_schedule'] = obj.next_schedule.get_absolute_url(request=self.context.get('request'))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_types(self):
|
def get_types(self):
|
||||||
@ -589,19 +594,19 @@ class UnifiedJobSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(UnifiedJobSerializer, self).get_related(obj)
|
res = super(UnifiedJobSerializer, self).get_related(obj)
|
||||||
if obj.unified_job_template:
|
if obj.unified_job_template:
|
||||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(request=self.context.get('request'))
|
||||||
if obj.schedule:
|
if obj.schedule:
|
||||||
res['schedule'] = obj.schedule.get_absolute_url()
|
res['schedule'] = obj.schedule.get_absolute_url(request=self.context.get('request'))
|
||||||
if isinstance(obj, ProjectUpdate):
|
if isinstance(obj, ProjectUpdate):
|
||||||
res['stdout'] = reverse('api:project_update_stdout', args=(obj.pk,))
|
res['stdout'] = self.reverse('api:project_update_stdout', kwargs={'pk': obj.pk})
|
||||||
elif isinstance(obj, InventoryUpdate):
|
elif isinstance(obj, InventoryUpdate):
|
||||||
res['stdout'] = reverse('api:inventory_update_stdout', args=(obj.pk,))
|
res['stdout'] = self.reverse('api:inventory_update_stdout', kwargs={'pk': obj.pk})
|
||||||
elif isinstance(obj, Job):
|
elif isinstance(obj, Job):
|
||||||
res['stdout'] = reverse('api:job_stdout', args=(obj.pk,))
|
res['stdout'] = self.reverse('api:job_stdout', kwargs={'pk': obj.pk})
|
||||||
elif isinstance(obj, AdHocCommand):
|
elif isinstance(obj, AdHocCommand):
|
||||||
res['stdout'] = reverse('api:ad_hoc_command_stdout', args=(obj.pk,))
|
res['stdout'] = self.reverse('api:ad_hoc_command_stdout', kwargs={'pk': obj.pk})
|
||||||
if obj.workflow_job_id:
|
if obj.workflow_job_id:
|
||||||
res['source_workflow_job'] = reverse('api:workflow_job_detail', args=(obj.workflow_job_id,))
|
res['source_workflow_job'] = self.reverse('api:workflow_job_detail', kwargs={'pk': obj.workflow_job_id})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
@ -811,14 +816,14 @@ class UserSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(UserSerializer, self).get_related(obj)
|
res = super(UserSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
teams = reverse('api:user_teams_list', args=(obj.pk,)),
|
teams = self.reverse('api:user_teams_list', kwargs={'pk': obj.pk}),
|
||||||
organizations = reverse('api:user_organizations_list', args=(obj.pk,)),
|
organizations = self.reverse('api:user_organizations_list', kwargs={'pk': obj.pk}),
|
||||||
admin_of_organizations = reverse('api:user_admin_of_organizations_list', args=(obj.pk,)),
|
admin_of_organizations = self.reverse('api:user_admin_of_organizations_list', kwargs={'pk': obj.pk}),
|
||||||
projects = reverse('api:user_projects_list', args=(obj.pk,)),
|
projects = self.reverse('api:user_projects_list', kwargs={'pk': obj.pk}),
|
||||||
credentials = reverse('api:user_credentials_list', args=(obj.pk,)),
|
credentials = self.reverse('api:user_credentials_list', kwargs={'pk': obj.pk}),
|
||||||
roles = reverse('api:user_roles_list', args=(obj.pk,)),
|
roles = self.reverse('api:user_roles_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:user_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:user_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:user_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:user_access_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -864,20 +869,20 @@ class OrganizationSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(OrganizationSerializer, self).get_related(obj)
|
res = super(OrganizationSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
projects = reverse('api:organization_projects_list', args=(obj.pk,)),
|
projects = self.reverse('api:organization_projects_list', kwargs={'pk': obj.pk}),
|
||||||
inventories = reverse('api:organization_inventories_list', args=(obj.pk,)),
|
inventories = self.reverse('api:organization_inventories_list', kwargs={'pk': obj.pk}),
|
||||||
workflow_job_templates = reverse('api:organization_workflow_job_templates_list', args=(obj.pk,)),
|
workflow_job_templates = self.reverse('api:organization_workflow_job_templates_list', kwargs={'pk': obj.pk}),
|
||||||
users = reverse('api:organization_users_list', args=(obj.pk,)),
|
users = self.reverse('api:organization_users_list', kwargs={'pk': obj.pk}),
|
||||||
admins = reverse('api:organization_admins_list', args=(obj.pk,)),
|
admins = self.reverse('api:organization_admins_list', kwargs={'pk': obj.pk}),
|
||||||
teams = reverse('api:organization_teams_list', args=(obj.pk,)),
|
teams = self.reverse('api:organization_teams_list', kwargs={'pk': obj.pk}),
|
||||||
credentials = reverse('api:organization_credential_list', args=(obj.pk,)),
|
credentials = self.reverse('api:organization_credential_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:organization_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:organization_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates = reverse('api:organization_notification_templates_list', args=(obj.pk,)),
|
notification_templates = self.reverse('api:organization_notification_templates_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:organization_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:organization_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:organization_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:organization_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:organization_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:organization_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:organization_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:organization_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:organization_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:organization_access_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -903,8 +908,8 @@ class ProjectOptionsSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(ProjectOptionsSerializer, self).get_related(obj)
|
res = super(ProjectOptionsSerializer, self).get_related(obj)
|
||||||
if obj.credential:
|
if obj.credential:
|
||||||
res['credential'] = reverse('api:credential_detail',
|
res['credential'] = self.reverse('api:credential_detail',
|
||||||
args=(obj.credential.pk,))
|
kwargs={'pk': obj.credential.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
@ -953,28 +958,28 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(ProjectSerializer, self).get_related(obj)
|
res = super(ProjectSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
teams = reverse('api:project_teams_list', args=(obj.pk,)),
|
teams = self.reverse('api:project_teams_list', kwargs={'pk': obj.pk}),
|
||||||
playbooks = reverse('api:project_playbooks', args=(obj.pk,)),
|
playbooks = self.reverse('api:project_playbooks', kwargs={'pk': obj.pk}),
|
||||||
update = reverse('api:project_update_view', args=(obj.pk,)),
|
update = self.reverse('api:project_update_view', kwargs={'pk': obj.pk}),
|
||||||
project_updates = reverse('api:project_updates_list', args=(obj.pk,)),
|
project_updates = self.reverse('api:project_updates_list', kwargs={'pk': obj.pk}),
|
||||||
schedules = reverse('api:project_schedules_list', args=(obj.pk,)),
|
schedules = self.reverse('api:project_schedules_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:project_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:project_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:project_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:project_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:project_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:project_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:project_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:project_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:project_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:project_access_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:project_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:project_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail',
|
res['organization'] = self.reverse('api:organization_detail',
|
||||||
args=(obj.organization.pk,))
|
kwargs={'pk': obj.organization.pk})
|
||||||
# Backwards compatibility.
|
# Backwards compatibility.
|
||||||
if obj.current_update:
|
if obj.current_update:
|
||||||
res['current_update'] = reverse('api:project_update_detail',
|
res['current_update'] = self.reverse('api:project_update_detail',
|
||||||
args=(obj.current_update.pk,))
|
kwargs={'pk': obj.current_update.pk})
|
||||||
if obj.last_update:
|
if obj.last_update:
|
||||||
res['last_update'] = reverse('api:project_update_detail',
|
res['last_update'] = self.reverse('api:project_update_detail',
|
||||||
args=(obj.last_update.pk,))
|
kwargs={'pk': obj.last_update.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -1039,9 +1044,9 @@ class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(ProjectUpdateSerializer, self).get_related(obj)
|
res = super(ProjectUpdateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
project = reverse('api:project_detail', args=(obj.project.pk,)),
|
project = self.reverse('api:project_detail', kwargs={'pk': obj.project.pk}),
|
||||||
cancel = reverse('api:project_update_cancel', args=(obj.pk,)),
|
cancel = self.reverse('api:project_update_cancel', kwargs={'pk': obj.pk}),
|
||||||
notifications = reverse('api:project_update_notifications_list', args=(obj.pk,)),
|
notifications = self.reverse('api:project_update_notifications_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -1078,23 +1083,22 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventorySerializer, self).get_related(obj)
|
res = super(InventorySerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
hosts = reverse('api:inventory_hosts_list', args=(obj.pk,)),
|
hosts = self.reverse('api:inventory_hosts_list', kwargs={'pk': obj.pk}),
|
||||||
groups = reverse('api:inventory_groups_list', args=(obj.pk,)),
|
groups = self.reverse('api:inventory_groups_list', kwargs={'pk': obj.pk}),
|
||||||
root_groups = reverse('api:inventory_root_groups_list', args=(obj.pk,)),
|
root_groups = self.reverse('api:inventory_root_groups_list', kwargs={'pk': obj.pk}),
|
||||||
variable_data = reverse('api:inventory_variable_data', args=(obj.pk,)),
|
variable_data = self.reverse('api:inventory_variable_data', kwargs={'pk': obj.pk}),
|
||||||
script = reverse('api:inventory_script_view', args=(obj.pk,)),
|
script = self.reverse('api:inventory_script_view', kwargs={'pk': obj.pk}),
|
||||||
tree = reverse('api:inventory_tree_view', args=(obj.pk,)),
|
tree = self.reverse('api:inventory_tree_view', kwargs={'pk': obj.pk}),
|
||||||
inventory_sources = reverse('api:inventory_inventory_sources_list', args=(obj.pk,)),
|
inventory_sources = self.reverse('api:inventory_inventory_sources_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:inventory_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
job_templates = reverse('api:inventory_job_template_list', args=(obj.pk,)),
|
job_templates = self.reverse('api:inventory_job_template_list', kwargs={'pk': obj.pk}),
|
||||||
scan_job_templates = reverse('api:inventory_scan_job_template_list', args=(obj.pk,)),
|
scan_job_templates = self.reverse('api:inventory_scan_job_template_list', kwargs={'pk': obj.pk}),
|
||||||
ad_hoc_commands = reverse('api:inventory_ad_hoc_commands_list', args=(obj.pk,)),
|
ad_hoc_commands = self.reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:inventory_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:inventory_access_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:inventory_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
#single_fact = reverse('api:inventory_single_fact_view', args=(obj.pk,)),
|
|
||||||
))
|
))
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -1143,24 +1147,23 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(HostSerializer, self).get_related(obj)
|
res = super(HostSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
variable_data = reverse('api:host_variable_data', args=(obj.pk,)),
|
variable_data = self.reverse('api:host_variable_data', kwargs={'pk': obj.pk}),
|
||||||
groups = reverse('api:host_groups_list', args=(obj.pk,)),
|
groups = self.reverse('api:host_groups_list', kwargs={'pk': obj.pk}),
|
||||||
all_groups = reverse('api:host_all_groups_list', args=(obj.pk,)),
|
all_groups = self.reverse('api:host_all_groups_list', kwargs={'pk': obj.pk}),
|
||||||
job_events = reverse('api:host_job_events_list', args=(obj.pk,)),
|
job_events = self.reverse('api:host_job_events_list', kwargs={'pk': obj.pk}),
|
||||||
job_host_summaries = reverse('api:host_job_host_summaries_list', args=(obj.pk,)),
|
job_host_summaries = self.reverse('api:host_job_host_summaries_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:host_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:host_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
inventory_sources = reverse('api:host_inventory_sources_list', args=(obj.pk,)),
|
inventory_sources = self.reverse('api:host_inventory_sources_list', kwargs={'pk': obj.pk}),
|
||||||
ad_hoc_commands = reverse('api:host_ad_hoc_commands_list', args=(obj.pk,)),
|
ad_hoc_commands = self.reverse('api:host_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
|
||||||
ad_hoc_command_events = reverse('api:host_ad_hoc_command_events_list', args=(obj.pk,)),
|
ad_hoc_command_events = self.reverse('api:host_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
|
||||||
fact_versions = reverse('api:host_fact_versions_list', args=(obj.pk,)),
|
fact_versions = self.reverse('api:host_fact_versions_list', kwargs={'pk': obj.pk}),
|
||||||
#single_fact = reverse('api:host_single_fact_view', args=(obj.pk,)),
|
|
||||||
))
|
))
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
if obj.last_job:
|
if obj.last_job:
|
||||||
res['last_job'] = reverse('api:job_detail', args=(obj.last_job.pk,))
|
res['last_job'] = self.reverse('api:job_detail', kwargs={'pk': obj.last_job.pk})
|
||||||
if obj.last_job_host_summary:
|
if obj.last_job_host_summary:
|
||||||
res['last_job_host_summary'] = reverse('api:job_host_summary_detail', args=(obj.last_job_host_summary.pk,))
|
res['last_job_host_summary'] = self.reverse('api:job_host_summary_detail', kwargs={'pk': obj.last_job_host_summary.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
@ -1253,22 +1256,21 @@ class GroupSerializer(BaseSerializerWithVariables):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(GroupSerializer, self).get_related(obj)
|
res = super(GroupSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
variable_data = reverse('api:group_variable_data', args=(obj.pk,)),
|
variable_data = self.reverse('api:group_variable_data', kwargs={'pk': obj.pk}),
|
||||||
hosts = reverse('api:group_hosts_list', args=(obj.pk,)),
|
hosts = self.reverse('api:group_hosts_list', kwargs={'pk': obj.pk}),
|
||||||
potential_children = reverse('api:group_potential_children_list', args=(obj.pk,)),
|
potential_children = self.reverse('api:group_potential_children_list', kwargs={'pk': obj.pk}),
|
||||||
children = reverse('api:group_children_list', args=(obj.pk,)),
|
children = self.reverse('api:group_children_list', kwargs={'pk': obj.pk}),
|
||||||
all_hosts = reverse('api:group_all_hosts_list', args=(obj.pk,)),
|
all_hosts = self.reverse('api:group_all_hosts_list', kwargs={'pk': obj.pk}),
|
||||||
job_events = reverse('api:group_job_events_list', args=(obj.pk,)),
|
job_events = self.reverse('api:group_job_events_list', kwargs={'pk': obj.pk}),
|
||||||
job_host_summaries = reverse('api:group_job_host_summaries_list', args=(obj.pk,)),
|
job_host_summaries = self.reverse('api:group_job_host_summaries_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:group_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:group_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
inventory_sources = reverse('api:group_inventory_sources_list', args=(obj.pk,)),
|
inventory_sources = self.reverse('api:group_inventory_sources_list', kwargs={'pk': obj.pk}),
|
||||||
ad_hoc_commands = reverse('api:group_ad_hoc_commands_list', args=(obj.pk,)),
|
ad_hoc_commands = self.reverse('api:group_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
|
||||||
#single_fact = reverse('api:group_single_fact_view', args=(obj.pk,)),
|
|
||||||
))
|
))
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
if obj.inventory_source:
|
if obj.inventory_source:
|
||||||
res['inventory_source'] = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,))
|
res['inventory_source'] = self.reverse('api:inventory_source_detail', kwargs={'pk': obj.inventory_source.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_name(self, value):
|
def validate_name(self, value):
|
||||||
@ -1363,11 +1365,11 @@ class CustomInventoryScriptSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(CustomInventoryScriptSerializer, self).get_related(obj)
|
res = super(CustomInventoryScriptSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
object_roles = reverse('api:inventory_script_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:inventory_script_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
|
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@ -1381,10 +1383,10 @@ class InventorySourceOptionsSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
|
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
|
||||||
if obj.credential:
|
if obj.credential:
|
||||||
res['credential'] = reverse('api:credential_detail',
|
res['credential'] = self.reverse('api:credential_detail',
|
||||||
args=(obj.credential.pk,))
|
kwargs={'pk': obj.credential.pk})
|
||||||
if obj.source_script:
|
if obj.source_script:
|
||||||
res['source_script'] = reverse('api:inventory_script_detail', args=(obj.source_script.pk,))
|
res['source_script'] = self.reverse('api:inventory_script_detail', kwargs={'pk': obj.source_script.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_source_vars(self, value):
|
def validate_source_vars(self, value):
|
||||||
@ -1437,27 +1439,27 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventorySourceSerializer, self).get_related(obj)
|
res = super(InventorySourceSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
update = reverse('api:inventory_source_update_view', args=(obj.pk,)),
|
update = self.reverse('api:inventory_source_update_view', kwargs={'pk': obj.pk}),
|
||||||
inventory_updates = reverse('api:inventory_source_updates_list', args=(obj.pk,)),
|
inventory_updates = self.reverse('api:inventory_source_updates_list', kwargs={'pk': obj.pk}),
|
||||||
schedules = reverse('api:inventory_source_schedules_list', args=(obj.pk,)),
|
schedules = self.reverse('api:inventory_source_schedules_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:inventory_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
hosts = reverse('api:inventory_source_hosts_list', args=(obj.pk,)),
|
hosts = self.reverse('api:inventory_source_hosts_list', kwargs={'pk': obj.pk}),
|
||||||
groups = reverse('api:inventory_source_groups_list', args=(obj.pk,)),
|
groups = self.reverse('api:inventory_source_groups_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:inventory_source_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:inventory_source_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:inventory_source_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:inventory_source_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
if obj.group:
|
if obj.group:
|
||||||
res['group'] = reverse('api:group_detail', args=(obj.group.pk,))
|
res['group'] = self.reverse('api:group_detail', kwargs={'pk': obj.group.pk})
|
||||||
# Backwards compatibility.
|
# Backwards compatibility.
|
||||||
if obj.current_update:
|
if obj.current_update:
|
||||||
res['current_update'] = reverse('api:inventory_update_detail',
|
res['current_update'] = self.reverse('api:inventory_update_detail',
|
||||||
args=(obj.current_update.pk,))
|
kwargs={'pk': obj.current_update.pk})
|
||||||
if obj.last_update:
|
if obj.last_update:
|
||||||
res['last_update'] = reverse('api:inventory_update_detail',
|
res['last_update'] = self.reverse('api:inventory_update_detail',
|
||||||
args=(obj.last_update.pk,))
|
kwargs={'pk': obj.last_update.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -1488,9 +1490,9 @@ class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSeri
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventoryUpdateSerializer, self).get_related(obj)
|
res = super(InventoryUpdateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
inventory_source = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,)),
|
inventory_source = self.reverse('api:inventory_source_detail', kwargs={'pk': obj.inventory_source.pk}),
|
||||||
cancel = reverse('api:inventory_update_cancel', args=(obj.pk,)),
|
cancel = self.reverse('api:inventory_update_cancel', kwargs={'pk': obj.pk}),
|
||||||
notifications = reverse('api:inventory_update_notifications_list', args=(obj.pk,)),
|
notifications = self.reverse('api:inventory_update_notifications_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -1518,16 +1520,16 @@ class TeamSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(TeamSerializer, self).get_related(obj)
|
res = super(TeamSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
projects = reverse('api:team_projects_list', args=(obj.pk,)),
|
projects = self.reverse('api:team_projects_list', kwargs={'pk': obj.pk}),
|
||||||
users = reverse('api:team_users_list', args=(obj.pk,)),
|
users = self.reverse('api:team_users_list', kwargs={'pk': obj.pk}),
|
||||||
credentials = reverse('api:team_credentials_list', args=(obj.pk,)),
|
credentials = self.reverse('api:team_credentials_list', kwargs={'pk': obj.pk}),
|
||||||
roles = reverse('api:team_roles_list', args=(obj.pk,)),
|
roles = self.reverse('api:team_roles_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:team_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:team_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:team_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:team_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:team_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:team_access_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -1564,11 +1566,11 @@ class RoleSerializer(BaseSerializer):
|
|||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
ret = super(RoleSerializer, self).get_related(obj)
|
ret = super(RoleSerializer, self).get_related(obj)
|
||||||
ret['users'] = reverse('api:role_users_list', args=(obj.pk,))
|
ret['users'] = self.reverse('api:role_users_list', kwargs={'pk': obj.pk})
|
||||||
ret['teams'] = reverse('api:role_teams_list', args=(obj.pk,))
|
ret['teams'] = self.reverse('api:role_teams_list', kwargs={'pk': obj.pk})
|
||||||
try:
|
try:
|
||||||
if obj.content_object:
|
if obj.content_object:
|
||||||
ret.update(reverse_gfk(obj.content_object))
|
ret.update(reverse_gfk(obj.content_object, self.context.get('request')))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# AttributeError's happen if our content_object is pointing at
|
# AttributeError's happen if our content_object is pointing at
|
||||||
# a model that no longer exists. This is dirty data and ideally
|
# a model that no longer exists. This is dirty data and ideally
|
||||||
@ -1610,7 +1612,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
|||||||
try:
|
try:
|
||||||
role_dict['resource_name'] = role.content_object.name
|
role_dict['resource_name'] = role.content_object.name
|
||||||
role_dict['resource_type'] = role.content_type.name
|
role_dict['resource_type'] = role.content_type.name
|
||||||
role_dict['related'] = reverse_gfk(role.content_object)
|
role_dict['related'] = reverse_gfk(role.content_object, self.context.get('request'))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
if role.content_type is not None:
|
if role.content_type is not None:
|
||||||
@ -1638,7 +1640,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
|||||||
if role.content_type is not None:
|
if role.content_type is not None:
|
||||||
role_dict['resource_name'] = role.content_object.name
|
role_dict['resource_name'] = role.content_object.name
|
||||||
role_dict['resource_type'] = role.content_type.name
|
role_dict['resource_type'] = role.content_type.name
|
||||||
role_dict['related'] = reverse_gfk(role.content_object)
|
role_dict['related'] = reverse_gfk(role.content_object, self.context.get('request'))
|
||||||
role_dict['user_capabilities'] = {'unattach': requesting_user.can_access(
|
role_dict['user_capabilities'] = {'unattach': requesting_user.can_access(
|
||||||
Role, 'unattach', role, team_role, 'parents', data={}, skip_sub_obj_read_check=False)}
|
Role, 'unattach', role, team_role, 'parents', data={}, skip_sub_obj_read_check=False)}
|
||||||
else:
|
else:
|
||||||
@ -1717,22 +1719,22 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
res = super(CredentialSerializer, self).get_related(obj)
|
res = super(CredentialSerializer, self).get_related(obj)
|
||||||
|
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
|
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
activity_stream = reverse('api:credential_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:credential_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:credential_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:credential_access_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:credential_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:credential_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
owner_users = reverse('api:credential_owner_users_list', args=(obj.pk,)),
|
owner_users = self.reverse('api:credential_owner_users_list', kwargs={'pk': obj.pk}),
|
||||||
owner_teams = reverse('api:credential_owner_teams_list', args=(obj.pk,)),
|
owner_teams = self.reverse('api:credential_owner_teams_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
|
|
||||||
parents = [role for role in obj.admin_role.parents.all() if role.object_id is not None]
|
parents = [role for role in obj.admin_role.parents.all() if role.object_id is not None]
|
||||||
if parents:
|
if parents:
|
||||||
res.update({parents[0].content_type.name:parents[0].content_object.get_absolute_url()})
|
res.update({parents[0].content_type.name:parents[0].content_object.get_absolute_url(self.context.get('request'))})
|
||||||
elif len(obj.admin_role.members.all()) > 0:
|
elif len(obj.admin_role.members.all()) > 0:
|
||||||
user = obj.admin_role.members.all()[0]
|
user = obj.admin_role.members.all()[0]
|
||||||
res.update({'user': reverse('api:user_detail', args=(user.pk,))})
|
res.update({'user': self.reverse('api:user_detail', kwargs={'pk': user.pk})})
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -1746,7 +1748,7 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
'type': 'user',
|
'type': 'user',
|
||||||
'name': user.username,
|
'name': user.username,
|
||||||
'description': ' '.join([user.first_name, user.last_name]),
|
'description': ' '.join([user.first_name, user.last_name]),
|
||||||
'url': reverse('api:user_detail', args=(user.pk,)),
|
'url': self.reverse('api:user_detail', kwargs={'pk': user.pk}),
|
||||||
})
|
})
|
||||||
|
|
||||||
for parent in [role for role in obj.admin_role.parents.all() if role.object_id is not None]:
|
for parent in [role for role in obj.admin_role.parents.all() if role.object_id is not None]:
|
||||||
@ -1755,7 +1757,7 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
'type': camelcase_to_underscore(parent.content_object.__class__.__name__),
|
'type': camelcase_to_underscore(parent.content_object.__class__.__name__),
|
||||||
'name': parent.content_object.name,
|
'name': parent.content_object.name,
|
||||||
'description': parent.content_object.description,
|
'description': parent.content_object.description,
|
||||||
'url': parent.content_object.get_absolute_url(),
|
'url': parent.content_object.get_absolute_url(self.context.get('request')),
|
||||||
})
|
})
|
||||||
|
|
||||||
return summary_dict
|
return summary_dict
|
||||||
@ -1862,19 +1864,19 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
|||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(JobOptionsSerializer, self).get_related(obj)
|
res = super(JobOptionsSerializer, self).get_related(obj)
|
||||||
res['labels'] = reverse('api:job_template_label_list', args=(obj.pk,))
|
res['labels'] = self.reverse('api:job_template_label_list', kwargs={'pk': obj.pk})
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
if obj.project:
|
if obj.project:
|
||||||
res['project'] = reverse('api:project_detail', args=(obj.project.pk,))
|
res['project'] = self.reverse('api:project_detail', kwargs={'pk': obj.project.pk})
|
||||||
if obj.credential:
|
if obj.credential:
|
||||||
res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,))
|
res['credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.credential.pk})
|
||||||
if obj.cloud_credential:
|
if obj.cloud_credential:
|
||||||
res['cloud_credential'] = reverse('api:credential_detail',
|
res['cloud_credential'] = self.reverse('api:credential_detail',
|
||||||
args=(obj.cloud_credential.pk,))
|
kwargs={'pk': obj.cloud_credential.pk})
|
||||||
if obj.network_credential:
|
if obj.network_credential:
|
||||||
res['network_credential'] = reverse('api:credential_detail',
|
res['network_credential'] = self.reverse('api:credential_detail',
|
||||||
args=(obj.network_credential.pk,))
|
kwargs={'pk': obj.network_credential.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -1947,20 +1949,20 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(JobTemplateSerializer, self).get_related(obj)
|
res = super(JobTemplateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
jobs = reverse('api:job_template_jobs_list', args=(obj.pk,)),
|
jobs = self.reverse('api:job_template_jobs_list', kwargs={'pk': obj.pk}),
|
||||||
schedules = reverse('api:job_template_schedules_list', args=(obj.pk,)),
|
schedules = self.reverse('api:job_template_schedules_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:job_template_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:job_template_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
launch = reverse('api:job_template_launch', args=(obj.pk,)),
|
launch = self.reverse('api:job_template_launch', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:job_template_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:job_template_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:job_template_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:job_template_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:job_template_access_list', kwargs={'pk': obj.pk}),
|
||||||
survey_spec = reverse('api:job_template_survey_spec', args=(obj.pk,)),
|
survey_spec = self.reverse('api:job_template_survey_spec', kwargs={'pk': obj.pk}),
|
||||||
labels = reverse('api:job_template_label_list', args=(obj.pk,)),
|
labels = self.reverse('api:job_template_label_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:job_template_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:job_template_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.host_config_key:
|
if obj.host_config_key:
|
||||||
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))
|
res['callback'] = self.reverse('api:job_template_callback', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
@ -2015,22 +2017,22 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(JobSerializer, self).get_related(obj)
|
res = super(JobSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
job_events = reverse('api:job_job_events_list', args=(obj.pk,)),
|
job_events = self.reverse('api:job_job_events_list', kwargs={'pk': obj.pk}),
|
||||||
job_host_summaries = reverse('api:job_job_host_summaries_list', args=(obj.pk,)),
|
job_host_summaries = self.reverse('api:job_job_host_summaries_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:job_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:job_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
notifications = reverse('api:job_notifications_list', args=(obj.pk,)),
|
notifications = self.reverse('api:job_notifications_list', kwargs={'pk': obj.pk}),
|
||||||
labels = reverse('api:job_label_list', args=(obj.pk,)),
|
labels = self.reverse('api:job_label_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.job_template:
|
if obj.job_template:
|
||||||
res['job_template'] = reverse('api:job_template_detail',
|
res['job_template'] = self.reverse('api:job_template_detail',
|
||||||
args=(obj.job_template.pk,))
|
kwargs={'pk': obj.job_template.pk})
|
||||||
if obj.can_start or True:
|
if obj.can_start or True:
|
||||||
res['start'] = reverse('api:job_start', args=(obj.pk,))
|
res['start'] = self.reverse('api:job_start', kwargs={'pk': obj.pk})
|
||||||
if obj.can_cancel or True:
|
if obj.can_cancel or True:
|
||||||
res['cancel'] = reverse('api:job_cancel', args=(obj.pk,))
|
res['cancel'] = self.reverse('api:job_cancel', kwargs={'pk': obj.pk})
|
||||||
if obj.project_update:
|
if obj.project_update:
|
||||||
res['project_update'] = reverse('api:project_update_detail', args=(obj.project_update.pk,))
|
res['project_update'] = self.reverse('api:project_update_detail', kwargs={'pk': obj.project_update.pk})
|
||||||
res['relaunch'] = reverse('api:job_relaunch', args=(obj.pk,))
|
res['relaunch'] = self.reverse('api:job_relaunch', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_artifacts(self, obj):
|
def get_artifacts(self, obj):
|
||||||
@ -2175,16 +2177,16 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(AdHocCommandSerializer, self).get_related(obj)
|
res = super(AdHocCommandSerializer, self).get_related(obj)
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
if obj.credential:
|
if obj.credential:
|
||||||
res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,))
|
res['credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.credential.pk})
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
events = reverse('api:ad_hoc_command_ad_hoc_command_events_list', args=(obj.pk,)),
|
events = self.reverse('api:ad_hoc_command_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:ad_hoc_command_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:ad_hoc_command_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
notifications = reverse('api:ad_hoc_command_notifications_list', args=(obj.pk,)),
|
notifications = self.reverse('api:ad_hoc_command_notifications_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
res['cancel'] = reverse('api:ad_hoc_command_cancel', args=(obj.pk,))
|
res['cancel'] = self.reverse('api:ad_hoc_command_cancel', kwargs={'pk': obj.pk})
|
||||||
res['relaunch'] = reverse('api:ad_hoc_command_relaunch', args=(obj.pk,))
|
res['relaunch'] = self.reverse('api:ad_hoc_command_relaunch', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -2229,12 +2231,12 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(SystemJobTemplateSerializer, self).get_related(obj)
|
res = super(SystemJobTemplateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
jobs = reverse('api:system_job_template_jobs_list', args=(obj.pk,)),
|
jobs = self.reverse('api:system_job_template_jobs_list', kwargs={'pk': obj.pk}),
|
||||||
schedules = reverse('api:system_job_template_schedules_list', args=(obj.pk,)),
|
schedules = self.reverse('api:system_job_template_schedules_list', kwargs={'pk': obj.pk}),
|
||||||
launch = reverse('api:system_job_template_launch', args=(obj.pk,)),
|
launch = self.reverse('api:system_job_template_launch', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:system_job_template_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:system_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:system_job_template_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:system_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:system_job_template_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:system_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
|
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
@ -2249,11 +2251,11 @@ class SystemJobSerializer(UnifiedJobSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(SystemJobSerializer, self).get_related(obj)
|
res = super(SystemJobSerializer, self).get_related(obj)
|
||||||
if obj.system_job_template:
|
if obj.system_job_template:
|
||||||
res['system_job_template'] = reverse('api:system_job_template_detail',
|
res['system_job_template'] = self.reverse('api:system_job_template_detail',
|
||||||
args=(obj.system_job_template.pk,))
|
kwargs={'pk': obj.system_job_template.pk})
|
||||||
res['notifications'] = reverse('api:system_job_notifications_list', args=(obj.pk,))
|
res['notifications'] = self.reverse('api:system_job_notifications_list', kwargs={'pk': obj.pk})
|
||||||
if obj.can_cancel or True:
|
if obj.can_cancel or True:
|
||||||
res['cancel'] = reverse('api:system_job_cancel', args=(obj.pk,))
|
res['cancel'] = self.reverse('api:system_job_cancel', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@ -2275,22 +2277,22 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(WorkflowJobTemplateSerializer, self).get_related(obj)
|
res = super(WorkflowJobTemplateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
workflow_jobs = reverse('api:workflow_job_template_jobs_list', args=(obj.pk,)),
|
workflow_jobs = self.reverse('api:workflow_job_template_jobs_list', kwargs={'pk': obj.pk}),
|
||||||
schedules = reverse('api:workflow_job_template_schedules_list', args=(obj.pk,)),
|
schedules = self.reverse('api:workflow_job_template_schedules_list', kwargs={'pk': obj.pk}),
|
||||||
launch = reverse('api:workflow_job_template_launch', args=(obj.pk,)),
|
launch = self.reverse('api:workflow_job_template_launch', kwargs={'pk': obj.pk}),
|
||||||
copy = reverse('api:workflow_job_template_copy', args=(obj.pk,)),
|
copy = self.reverse('api:workflow_job_template_copy', kwargs={'pk': obj.pk}),
|
||||||
workflow_nodes = reverse('api:workflow_job_template_workflow_nodes_list', args=(obj.pk,)),
|
workflow_nodes = self.reverse('api:workflow_job_template_workflow_nodes_list', kwargs={'pk': obj.pk}),
|
||||||
labels = reverse('api:workflow_job_template_label_list', args=(obj.pk,)),
|
labels = self.reverse('api:workflow_job_template_label_list', kwargs={'pk': obj.pk}),
|
||||||
activity_stream = reverse('api:workflow_job_template_activity_stream_list', args=(obj.pk,)),
|
activity_stream = self.reverse('api:workflow_job_template_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_any = reverse('api:workflow_job_template_notification_templates_any_list', args=(obj.pk,)),
|
notification_templates_any = self.reverse('api:workflow_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_success = reverse('api:workflow_job_template_notification_templates_success_list', args=(obj.pk,)),
|
notification_templates_success = self.reverse('api:workflow_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
|
||||||
notification_templates_error = reverse('api:workflow_job_template_notification_templates_error_list', args=(obj.pk,)),
|
notification_templates_error = self.reverse('api:workflow_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
|
||||||
access_list = reverse('api:workflow_job_template_access_list', args=(obj.pk,)),
|
access_list = self.reverse('api:workflow_job_template_access_list', kwargs={'pk': obj.pk}),
|
||||||
object_roles = reverse('api:workflow_job_template_object_roles_list', args=(obj.pk,)),
|
object_roles = self.reverse('api:workflow_job_template_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
survey_spec = reverse('api:workflow_job_template_survey_spec', args=(obj.pk,)),
|
survey_spec = self.reverse('api:workflow_job_template_survey_spec', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_extra_vars(self, value):
|
def validate_extra_vars(self, value):
|
||||||
@ -2312,15 +2314,15 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(WorkflowJobSerializer, self).get_related(obj)
|
res = super(WorkflowJobSerializer, self).get_related(obj)
|
||||||
if obj.workflow_job_template:
|
if obj.workflow_job_template:
|
||||||
res['workflow_job_template'] = reverse('api:workflow_job_template_detail',
|
res['workflow_job_template'] = self.reverse('api:workflow_job_template_detail',
|
||||||
args=(obj.workflow_job_template.pk,))
|
kwargs={'pk': obj.workflow_job_template.pk})
|
||||||
res['notifications'] = reverse('api:workflow_job_notifications_list', args=(obj.pk,))
|
res['notifications'] = self.reverse('api:workflow_job_notifications_list', kwargs={'pk': obj.pk})
|
||||||
res['workflow_nodes'] = reverse('api:workflow_job_workflow_nodes_list', args=(obj.pk,))
|
res['workflow_nodes'] = self.reverse('api:workflow_job_workflow_nodes_list', kwargs={'pk': obj.pk})
|
||||||
res['labels'] = reverse('api:workflow_job_label_list', args=(obj.pk,))
|
res['labels'] = self.reverse('api:workflow_job_label_list', kwargs={'pk': obj.pk})
|
||||||
res['activity_stream'] = reverse('api:workflow_job_activity_stream_list', args=(obj.pk,))
|
res['activity_stream'] = self.reverse('api:workflow_job_activity_stream_list', kwargs={'pk': obj.pk})
|
||||||
res['relaunch'] = reverse('api:workflow_job_relaunch', args=(obj.pk,))
|
res['relaunch'] = self.reverse('api:workflow_job_relaunch', kwargs={'pk': obj.pk})
|
||||||
if obj.can_cancel or True:
|
if obj.can_cancel or True:
|
||||||
res['cancel'] = reverse('api:workflow_job_cancel', args=(obj.pk,))
|
res['cancel'] = self.reverse('api:workflow_job_cancel', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -2362,7 +2364,7 @@ class WorkflowNodeBaseSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(WorkflowNodeBaseSerializer, self).get_related(obj)
|
res = super(WorkflowNodeBaseSerializer, self).get_related(obj)
|
||||||
if obj.unified_job_template:
|
if obj.unified_job_template:
|
||||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(self.context.get('request'))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
@ -2380,11 +2382,11 @@ class WorkflowJobTemplateNodeSerializer(WorkflowNodeBaseSerializer):
|
|||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(WorkflowJobTemplateNodeSerializer, self).get_related(obj)
|
res = super(WorkflowJobTemplateNodeSerializer, self).get_related(obj)
|
||||||
res['success_nodes'] = reverse('api:workflow_job_template_node_success_nodes_list', args=(obj.pk,))
|
res['success_nodes'] = self.reverse('api:workflow_job_template_node_success_nodes_list', kwargs={'pk': obj.pk})
|
||||||
res['failure_nodes'] = reverse('api:workflow_job_template_node_failure_nodes_list', args=(obj.pk,))
|
res['failure_nodes'] = self.reverse('api:workflow_job_template_node_failure_nodes_list', kwargs={'pk': obj.pk})
|
||||||
res['always_nodes'] = reverse('api:workflow_job_template_node_always_nodes_list', args=(obj.pk,))
|
res['always_nodes'] = self.reverse('api:workflow_job_template_node_always_nodes_list', kwargs={'pk': obj.pk})
|
||||||
if obj.workflow_job_template:
|
if obj.workflow_job_template:
|
||||||
res['workflow_job_template'] = reverse('api:workflow_job_template_detail', args=(obj.workflow_job_template.pk,))
|
res['workflow_job_template'] = self.reverse('api:workflow_job_template_detail', kwargs={'pk': obj.workflow_job_template.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
@ -2440,13 +2442,13 @@ class WorkflowJobNodeSerializer(WorkflowNodeBaseSerializer):
|
|||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(WorkflowJobNodeSerializer, self).get_related(obj)
|
res = super(WorkflowJobNodeSerializer, self).get_related(obj)
|
||||||
res['success_nodes'] = reverse('api:workflow_job_node_success_nodes_list', args=(obj.pk,))
|
res['success_nodes'] = self.reverse('api:workflow_job_node_success_nodes_list', kwargs={'pk': obj.pk})
|
||||||
res['failure_nodes'] = reverse('api:workflow_job_node_failure_nodes_list', args=(obj.pk,))
|
res['failure_nodes'] = self.reverse('api:workflow_job_node_failure_nodes_list', kwargs={'pk': obj.pk})
|
||||||
res['always_nodes'] = reverse('api:workflow_job_node_always_nodes_list', args=(obj.pk,))
|
res['always_nodes'] = self.reverse('api:workflow_job_node_always_nodes_list', kwargs={'pk': obj.pk})
|
||||||
if obj.job:
|
if obj.job:
|
||||||
res['job'] = obj.job.get_absolute_url()
|
res['job'] = obj.job.get_absolute_url(self.context.get('request'))
|
||||||
if obj.workflow_job:
|
if obj.workflow_job:
|
||||||
res['workflow_job'] = reverse('api:workflow_job_detail', args=(obj.workflow_job.pk,))
|
res['workflow_job'] = self.reverse('api:workflow_job_detail', kwargs={'pk': obj.workflow_job.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@ -2500,10 +2502,10 @@ class JobHostSummarySerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(JobHostSummarySerializer, self).get_related(obj)
|
res = super(JobHostSummarySerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
job=reverse('api:job_detail', args=(obj.job.pk,))))
|
job=self.reverse('api:job_detail', kwargs={'pk': obj.job.pk})))
|
||||||
if obj.host is not None:
|
if obj.host is not None:
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
host=reverse('api:host_detail', args=(obj.host.pk,))
|
host=self.reverse('api:host_detail', kwargs={'pk': obj.host.pk})
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -2533,16 +2535,16 @@ class JobEventSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(JobEventSerializer, self).get_related(obj)
|
res = super(JobEventSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
job = reverse('api:job_detail', args=(obj.job_id,)),
|
job = self.reverse('api:job_detail', kwargs={'pk': obj.job_id}),
|
||||||
))
|
))
|
||||||
if obj.parent_id:
|
if obj.parent_id:
|
||||||
res['parent'] = reverse('api:job_event_detail', args=(obj.parent_id,))
|
res['parent'] = self.reverse('api:job_event_detail', kwargs={'pk': obj.parent_id})
|
||||||
if obj.children.exists():
|
if obj.children.exists():
|
||||||
res['children'] = reverse('api:job_event_children_list', args=(obj.pk,))
|
res['children'] = self.reverse('api:job_event_children_list', kwargs={'pk': obj.pk})
|
||||||
if obj.host_id:
|
if obj.host_id:
|
||||||
res['host'] = reverse('api:host_detail', args=(obj.host_id,))
|
res['host'] = self.reverse('api:host_detail', kwargs={'pk': obj.host_id})
|
||||||
if obj.hosts.exists():
|
if obj.hosts.exists():
|
||||||
res['hosts'] = reverse('api:job_event_hosts_list', args=(obj.pk,))
|
res['hosts'] = self.reverse('api:job_event_hosts_list', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
@ -2582,10 +2584,10 @@ class AdHocCommandEventSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(AdHocCommandEventSerializer, self).get_related(obj)
|
res = super(AdHocCommandEventSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
ad_hoc_command = reverse('api:ad_hoc_command_detail', args=(obj.ad_hoc_command_id,)),
|
ad_hoc_command = self.reverse('api:ad_hoc_command_detail', kwargs={'pk': obj.ad_hoc_command_id}),
|
||||||
))
|
))
|
||||||
if obj.host:
|
if obj.host:
|
||||||
res['host'] = reverse('api:host_detail', args=(obj.host.pk,))
|
res['host'] = self.reverse('api:host_detail', kwargs={'pk': obj.host.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -2809,11 +2811,11 @@ class NotificationTemplateSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(NotificationTemplateSerializer, self).get_related(obj)
|
res = super(NotificationTemplateSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
test = reverse('api:notification_template_test', args=(obj.pk,)),
|
test = self.reverse('api:notification_template_test', kwargs={'pk': obj.pk}),
|
||||||
notifications = reverse('api:notification_template_notification_list', args=(obj.pk,)),
|
notifications = self.reverse('api:notification_template_notification_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _recent_notifications(self, obj):
|
def _recent_notifications(self, obj):
|
||||||
@ -2883,7 +2885,7 @@ class NotificationSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(NotificationSerializer, self).get_related(obj)
|
res = super(NotificationSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
notification_template = reverse('api:notification_template_detail', args=(obj.notification_template.pk,)),
|
notification_template = self.reverse('api:notification_template_detail', kwargs={'pk': obj.notification_template.pk}),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -2897,7 +2899,7 @@ class LabelSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(LabelSerializer, self).get_related(obj)
|
res = super(LabelSerializer, self).get_related(obj)
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@ -2911,10 +2913,10 @@ class ScheduleSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(ScheduleSerializer, self).get_related(obj)
|
res = super(ScheduleSerializer, self).get_related(obj)
|
||||||
res.update(dict(
|
res.update(dict(
|
||||||
unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)),
|
unified_jobs = self.reverse('api:schedule_unified_jobs_list', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.unified_job_template:
|
if obj.unified_job_template:
|
||||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(self.context.get('request'))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_unified_job_template(self, value):
|
def validate_unified_job_template(self, value):
|
||||||
@ -3038,7 +3040,7 @@ class ActivityStreamSerializer(BaseSerializer):
|
|||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
rel = {}
|
rel = {}
|
||||||
if obj.actor is not None:
|
if obj.actor is not None:
|
||||||
rel['actor'] = reverse('api:user_detail', args=(obj.actor.pk,))
|
rel['actor'] = self.reverse('api:user_detail', kwargs={'pk': obj.actor.pk})
|
||||||
for fk, __ in self._local_summarizable_fk_fields:
|
for fk, __ in self._local_summarizable_fk_fields:
|
||||||
if not hasattr(obj, fk):
|
if not hasattr(obj, fk):
|
||||||
continue
|
continue
|
||||||
@ -3051,12 +3053,12 @@ class ActivityStreamSerializer(BaseSerializer):
|
|||||||
continue
|
continue
|
||||||
id_list.append(getattr(thisItem, 'id', None))
|
id_list.append(getattr(thisItem, 'id', None))
|
||||||
if fk == 'custom_inventory_script':
|
if fk == 'custom_inventory_script':
|
||||||
rel[fk].append(reverse('api:inventory_script_detail', args=(thisItem.id,)))
|
rel[fk].append(self.reverse('api:inventory_script_detail', kwargs={'pk': thisItem.id}))
|
||||||
else:
|
else:
|
||||||
rel[fk].append(reverse('api:' + fk + '_detail', args=(thisItem.id,)))
|
rel[fk].append(self.reverse('api:' + fk + '_detail', kwargs={'pk': thisItem.id}))
|
||||||
|
|
||||||
if fk == 'schedule':
|
if fk == 'schedule':
|
||||||
rel['unified_job_template'] = thisItem.unified_job_template.get_absolute_url()
|
rel['unified_job_template'] = thisItem.unified_job_template.get_absolute_url(self.context.get('request'))
|
||||||
return rel
|
return rel
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
@ -3137,7 +3139,10 @@ class FactVersionSerializer(BaseFactSerializer):
|
|||||||
'datetime': timestamp_apiformat(obj.timestamp),
|
'datetime': timestamp_apiformat(obj.timestamp),
|
||||||
'module': obj.module,
|
'module': obj.module,
|
||||||
}
|
}
|
||||||
res['fact_view'] = build_url('api:host_fact_compare_view', args=(obj.host.pk,), get=params)
|
res['fact_view'] = '%s?%s' % (
|
||||||
|
reverse('api:host_fact_compare_view', kwargs={'pk': obj.host.pk}, request=self.context.get('request')),
|
||||||
|
urllib.urlencode(params)
|
||||||
|
)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@ -3151,7 +3156,7 @@ class FactSerializer(BaseFactSerializer):
|
|||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(FactSerializer, self).get_related(obj)
|
res = super(FactSerializer, self).get_related(obj)
|
||||||
res['host'] = obj.host.get_absolute_url()
|
res['host'] = obj.host.get_absolute_url(self.context.get('request'))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
|
|||||||
@ -9,5 +9,6 @@
|
|||||||
{% if new_in_240 %}> _Added in Ansible Tower 2.4.0_{% endif %}
|
{% if new_in_240 %}> _Added in Ansible Tower 2.4.0_{% endif %}
|
||||||
{% if new_in_300 %}> _Added in Ansible Tower 3.0.0_{% endif %}
|
{% if new_in_300 %}> _Added in Ansible Tower 3.0.0_{% endif %}
|
||||||
{% if new_in_310 %}> _New in Ansible Tower 3.1.0_{% endif %}
|
{% if new_in_310 %}> _New in Ansible Tower 3.1.0_{% endif %}
|
||||||
|
{% if new_in_320 %}> _New in Ansible Tower 3.2.0_{% endif %}
|
||||||
{% if deprecated %}> _This resource has been deprecated and will be removed in a future release_{% endif %}
|
{% if deprecated %}> _This resource has been deprecated and will be removed in a future release_{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -331,7 +331,7 @@ activity_stream_urls = patterns('awx.api.views',
|
|||||||
)
|
)
|
||||||
|
|
||||||
v1_urls = patterns('awx.api.views',
|
v1_urls = patterns('awx.api.views',
|
||||||
url(r'^$', 'api_v1_root_view'),
|
url(r'^$', 'api_version_root_view'),
|
||||||
url(r'^ping/$', 'api_v1_ping_view'),
|
url(r'^ping/$', 'api_v1_ping_view'),
|
||||||
url(r'^config/$', 'api_v1_config_view'),
|
url(r'^config/$', 'api_v1_config_view'),
|
||||||
url(r'^auth/$', 'auth_view'),
|
url(r'^auth/$', 'auth_view'),
|
||||||
@ -376,5 +376,5 @@ v1_urls = patterns('awx.api.views',
|
|||||||
|
|
||||||
urlpatterns = patterns('awx.api.views',
|
urlpatterns = patterns('awx.api.views',
|
||||||
url(r'^$', 'api_root_view'),
|
url(r'^$', 'api_root_view'),
|
||||||
url(r'^v1/', include(v1_urls)),
|
url(r'^(?P<version>(v1|v2))/', include(v1_urls))
|
||||||
)
|
)
|
||||||
|
|||||||
30
awx/api/versioning.py
Normal file
30
awx/api/versioning.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (c) 2017 Ansible by Red Hat
|
||||||
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
from rest_framework.reverse import reverse as drf_reverse
|
||||||
|
from rest_framework.versioning import URLPathVersioning as BaseVersioning
|
||||||
|
|
||||||
|
|
||||||
|
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
|
||||||
|
if request is None or getattr(request, 'version', None) is None:
|
||||||
|
# We need the "current request" to determine the correct version to
|
||||||
|
# prepend to reverse URLs. If there is no "current request", assume
|
||||||
|
# the latest API version.
|
||||||
|
if kwargs is None:
|
||||||
|
kwargs = {}
|
||||||
|
if 'version' not in kwargs:
|
||||||
|
kwargs['version'] = 'v2'
|
||||||
|
return drf_reverse(viewname, args, kwargs, request, format, **extra)
|
||||||
|
|
||||||
|
|
||||||
|
class URLPathVersioning(BaseVersioning):
|
||||||
|
|
||||||
|
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
|
||||||
|
if request.version is not None:
|
||||||
|
kwargs = {} if (kwargs is None) else kwargs
|
||||||
|
kwargs[self.version_param] = request.version
|
||||||
|
request = None
|
||||||
|
|
||||||
|
return super(BaseVersioning, self).reverse(
|
||||||
|
viewname, args, kwargs, request, format, **extra
|
||||||
|
)
|
||||||
163
awx/api/views.py
163
awx/api/views.py
@ -20,7 +20,6 @@ from collections import OrderedDict
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User, AnonymousUser
|
from django.contrib.auth.models import User, AnonymousUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.db.models import Q, Count, F
|
from django.db.models import Q, Count, F
|
||||||
from django.db import IntegrityError, transaction, connection
|
from django.db import IntegrityError, transaction, connection
|
||||||
@ -65,6 +64,7 @@ from awx.main.ha import is_ha_environment
|
|||||||
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
|
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
|
||||||
from awx.api.generics import get_view_name
|
from awx.api.generics import get_view_name
|
||||||
from awx.api.generics import * # noqa
|
from awx.api.generics import * # noqa
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.conf.license import get_license, feature_enabled, feature_exists, LicenseForbids
|
from awx.conf.license import get_license, feature_enabled, feature_exists, LicenseForbids
|
||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
from awx.main.utils import * # noqa
|
from awx.main.utils import * # noqa
|
||||||
@ -78,6 +78,7 @@ from awx.api.metadata import RoleMetadata
|
|||||||
from awx.main.consumers import emit_channel_notification
|
from awx.main.consumers import emit_channel_notification
|
||||||
from awx.main.models.unified_jobs import ACTIVE_STATES
|
from awx.main.models.unified_jobs import ACTIVE_STATES
|
||||||
from awx.main.scheduler.tasks import run_job_complete
|
from awx.main.scheduler.tasks import run_job_complete
|
||||||
|
from awx.main.fields import DynamicFilterField
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.views')
|
logger = logging.getLogger('awx.api.views')
|
||||||
|
|
||||||
@ -128,17 +129,17 @@ class ApiRootView(APIView):
|
|||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
permission_classes = (AllowAny,)
|
permission_classes = (AllowAny,)
|
||||||
view_name = _('REST API')
|
view_name = _('REST API')
|
||||||
|
versioning_class = None
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
''' list supported API versions '''
|
''' list supported API versions '''
|
||||||
|
|
||||||
current = reverse('api:api_v1_root_view', args=[])
|
v1 = reverse('api:api_version_root_view', kwargs={'version': 'v1'})
|
||||||
|
v2 = reverse('api:api_version_root_view', kwargs={'version': 'v2'})
|
||||||
data = dict(
|
data = dict(
|
||||||
description = _('Ansible Tower REST API'),
|
description = _('Ansible Tower REST API'),
|
||||||
current_version = current,
|
current_version = v2,
|
||||||
available_versions = dict(
|
available_versions = dict(v1 = v1, v2 = v2),
|
||||||
v1 = current
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if feature_enabled('rebranding'):
|
if feature_enabled('rebranding'):
|
||||||
data['custom_logo'] = settings.CUSTOM_LOGO
|
data['custom_logo'] = settings.CUSTOM_LOGO
|
||||||
@ -146,52 +147,52 @@ class ApiRootView(APIView):
|
|||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
class ApiV1RootView(APIView):
|
class ApiVersionRootView(APIView):
|
||||||
|
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
view_name = _('Version')
|
||||||
permission_classes = (AllowAny,)
|
permission_classes = (AllowAny,)
|
||||||
view_name = _('Version 1')
|
|
||||||
|
|
||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
''' list top level resources '''
|
''' list top level resources '''
|
||||||
|
|
||||||
data = OrderedDict()
|
data = OrderedDict()
|
||||||
data['authtoken'] = reverse('api:auth_token_view')
|
data['authtoken'] = reverse('api:auth_token_view', request=request)
|
||||||
data['ping'] = reverse('api:api_v1_ping_view')
|
data['ping'] = reverse('api:api_v1_ping_view', request=request)
|
||||||
data['config'] = reverse('api:api_v1_config_view')
|
data['config'] = reverse('api:api_v1_config_view', request=request)
|
||||||
data['settings'] = reverse('api:setting_category_list')
|
data['settings'] = reverse('api:setting_category_list', request=request)
|
||||||
data['me'] = reverse('api:user_me_list')
|
data['me'] = reverse('api:user_me_list', request=request)
|
||||||
data['dashboard'] = reverse('api:dashboard_view')
|
data['dashboard'] = reverse('api:dashboard_view', request=request)
|
||||||
data['organizations'] = reverse('api:organization_list')
|
data['organizations'] = reverse('api:organization_list', request=request)
|
||||||
data['users'] = reverse('api:user_list')
|
data['users'] = reverse('api:user_list', request=request)
|
||||||
data['projects'] = reverse('api:project_list')
|
data['projects'] = reverse('api:project_list', request=request)
|
||||||
data['project_updates'] = reverse('api:project_update_list')
|
data['project_updates'] = reverse('api:project_update_list', request=request)
|
||||||
data['teams'] = reverse('api:team_list')
|
data['teams'] = reverse('api:team_list', request=request)
|
||||||
data['credentials'] = reverse('api:credential_list')
|
data['credentials'] = reverse('api:credential_list', request=request)
|
||||||
data['inventory'] = reverse('api:inventory_list')
|
data['inventory'] = reverse('api:inventory_list', request=request)
|
||||||
data['inventory_scripts'] = reverse('api:inventory_script_list')
|
data['inventory_scripts'] = reverse('api:inventory_script_list', request=request)
|
||||||
data['inventory_sources'] = reverse('api:inventory_source_list')
|
data['inventory_sources'] = reverse('api:inventory_source_list', request=request)
|
||||||
data['inventory_updates'] = reverse('api:inventory_update_list')
|
data['inventory_updates'] = reverse('api:inventory_update_list', request=request)
|
||||||
data['groups'] = reverse('api:group_list')
|
data['groups'] = reverse('api:group_list', request=request)
|
||||||
data['hosts'] = reverse('api:host_list')
|
data['hosts'] = reverse('api:host_list', request=request)
|
||||||
data['job_templates'] = reverse('api:job_template_list')
|
data['job_templates'] = reverse('api:job_template_list', request=request)
|
||||||
data['jobs'] = reverse('api:job_list')
|
data['jobs'] = reverse('api:job_list', request=request)
|
||||||
data['job_events'] = reverse('api:job_event_list')
|
data['job_events'] = reverse('api:job_event_list', request=request)
|
||||||
data['ad_hoc_commands'] = reverse('api:ad_hoc_command_list')
|
data['ad_hoc_commands'] = reverse('api:ad_hoc_command_list', request=request)
|
||||||
data['system_job_templates'] = reverse('api:system_job_template_list')
|
data['system_job_templates'] = reverse('api:system_job_template_list', request=request)
|
||||||
data['system_jobs'] = reverse('api:system_job_list')
|
data['system_jobs'] = reverse('api:system_job_list', request=request)
|
||||||
data['schedules'] = reverse('api:schedule_list')
|
data['schedules'] = reverse('api:schedule_list', request=request)
|
||||||
data['roles'] = reverse('api:role_list')
|
data['roles'] = reverse('api:role_list', request=request)
|
||||||
data['notification_templates'] = reverse('api:notification_template_list')
|
data['notification_templates'] = reverse('api:notification_template_list', request=request)
|
||||||
data['notifications'] = reverse('api:notification_list')
|
data['notifications'] = reverse('api:notification_list', request=request)
|
||||||
data['labels'] = reverse('api:label_list')
|
data['labels'] = reverse('api:label_list', request=request)
|
||||||
data['unified_job_templates'] = reverse('api:unified_job_template_list')
|
data['unified_job_templates'] = reverse('api:unified_job_template_list', request=request)
|
||||||
data['unified_jobs'] = reverse('api:unified_job_list')
|
data['unified_jobs'] = reverse('api:unified_job_list', request=request)
|
||||||
data['activity_stream'] = reverse('api:activity_stream_list')
|
data['activity_stream'] = reverse('api:activity_stream_list', request=request)
|
||||||
data['workflow_job_templates'] = reverse('api:workflow_job_template_list')
|
data['workflow_job_templates'] = reverse('api:workflow_job_template_list', request=request)
|
||||||
data['workflow_jobs'] = reverse('api:workflow_job_list')
|
data['workflow_jobs'] = reverse('api:workflow_job_list', request=request)
|
||||||
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list')
|
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
|
||||||
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list')
|
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
@ -336,12 +337,12 @@ class DashboardView(APIView):
|
|||||||
def get(self, request, format=None):
|
def get(self, request, format=None):
|
||||||
''' Show Dashboard Details '''
|
''' Show Dashboard Details '''
|
||||||
data = OrderedDict()
|
data = OrderedDict()
|
||||||
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view')}
|
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view', request=request)}
|
||||||
user_inventory = get_user_queryset(request.user, Inventory)
|
user_inventory = get_user_queryset(request.user, Inventory)
|
||||||
inventory_with_failed_hosts = user_inventory.filter(hosts_with_active_failures__gt=0)
|
inventory_with_failed_hosts = user_inventory.filter(hosts_with_active_failures__gt=0)
|
||||||
user_inventory_external = user_inventory.filter(has_inventory_sources=True)
|
user_inventory_external = user_inventory.filter(has_inventory_sources=True)
|
||||||
failed_inventory = sum(i.inventory_sources_with_failures for i in user_inventory)
|
failed_inventory = sum(i.inventory_sources_with_failures for i in user_inventory)
|
||||||
data['inventories'] = {'url': reverse('api:inventory_list'),
|
data['inventories'] = {'url': reverse('api:inventory_list', request=request),
|
||||||
'total': user_inventory.count(),
|
'total': user_inventory.count(),
|
||||||
'total_with_inventory_source': user_inventory_external.count(),
|
'total_with_inventory_source': user_inventory_external.count(),
|
||||||
'job_failed': inventory_with_failed_hosts.count(),
|
'job_failed': inventory_with_failed_hosts.count(),
|
||||||
@ -352,13 +353,13 @@ class DashboardView(APIView):
|
|||||||
ec2_inventory_sources = user_inventory_sources.filter(source='ec2')
|
ec2_inventory_sources = user_inventory_sources.filter(source='ec2')
|
||||||
ec2_inventory_failed = ec2_inventory_sources.filter(status='failed')
|
ec2_inventory_failed = ec2_inventory_sources.filter(status='failed')
|
||||||
data['inventory_sources'] = {}
|
data['inventory_sources'] = {}
|
||||||
data['inventory_sources']['rax'] = {'url': reverse('api:inventory_source_list') + "?source=rax",
|
data['inventory_sources']['rax'] = {'url': reverse('api:inventory_source_list', request=request) + "?source=rax",
|
||||||
'label': 'Rackspace',
|
'label': 'Rackspace',
|
||||||
'failures_url': reverse('api:inventory_source_list') + "?source=rax&status=failed",
|
'failures_url': reverse('api:inventory_source_list', request=request) + "?source=rax&status=failed",
|
||||||
'total': rax_inventory_sources.count(),
|
'total': rax_inventory_sources.count(),
|
||||||
'failed': rax_inventory_failed.count()}
|
'failed': rax_inventory_failed.count()}
|
||||||
data['inventory_sources']['ec2'] = {'url': reverse('api:inventory_source_list') + "?source=ec2",
|
data['inventory_sources']['ec2'] = {'url': reverse('api:inventory_source_list', request=request) + "?source=ec2",
|
||||||
'failures_url': reverse('api:inventory_source_list') + "?source=ec2&status=failed",
|
'failures_url': reverse('api:inventory_source_list', request=request) + "?source=ec2&status=failed",
|
||||||
'label': 'Amazon EC2',
|
'label': 'Amazon EC2',
|
||||||
'total': ec2_inventory_sources.count(),
|
'total': ec2_inventory_sources.count(),
|
||||||
'failed': ec2_inventory_failed.count()}
|
'failed': ec2_inventory_failed.count()}
|
||||||
@ -366,23 +367,23 @@ class DashboardView(APIView):
|
|||||||
user_groups = get_user_queryset(request.user, Group)
|
user_groups = get_user_queryset(request.user, Group)
|
||||||
groups_job_failed = (Group.objects.filter(hosts_with_active_failures__gt=0) | Group.objects.filter(groups_with_active_failures__gt=0)).count()
|
groups_job_failed = (Group.objects.filter(hosts_with_active_failures__gt=0) | Group.objects.filter(groups_with_active_failures__gt=0)).count()
|
||||||
groups_inventory_failed = Group.objects.filter(inventory_sources__last_job_failed=True).count()
|
groups_inventory_failed = Group.objects.filter(inventory_sources__last_job_failed=True).count()
|
||||||
data['groups'] = {'url': reverse('api:group_list'),
|
data['groups'] = {'url': reverse('api:group_list', request=request),
|
||||||
'failures_url': reverse('api:group_list') + "?has_active_failures=True",
|
'failures_url': reverse('api:group_list', request=request) + "?has_active_failures=True",
|
||||||
'total': user_groups.count(),
|
'total': user_groups.count(),
|
||||||
'job_failed': groups_job_failed,
|
'job_failed': groups_job_failed,
|
||||||
'inventory_failed': groups_inventory_failed}
|
'inventory_failed': groups_inventory_failed}
|
||||||
|
|
||||||
user_hosts = get_user_queryset(request.user, Host)
|
user_hosts = get_user_queryset(request.user, Host)
|
||||||
user_hosts_failed = user_hosts.filter(has_active_failures=True)
|
user_hosts_failed = user_hosts.filter(has_active_failures=True)
|
||||||
data['hosts'] = {'url': reverse('api:host_list'),
|
data['hosts'] = {'url': reverse('api:host_list', request=request),
|
||||||
'failures_url': reverse('api:host_list') + "?has_active_failures=True",
|
'failures_url': reverse('api:host_list', request=request) + "?has_active_failures=True",
|
||||||
'total': user_hosts.count(),
|
'total': user_hosts.count(),
|
||||||
'failed': user_hosts_failed.count()}
|
'failed': user_hosts_failed.count()}
|
||||||
|
|
||||||
user_projects = get_user_queryset(request.user, Project)
|
user_projects = get_user_queryset(request.user, Project)
|
||||||
user_projects_failed = user_projects.filter(last_job_failed=True)
|
user_projects_failed = user_projects.filter(last_job_failed=True)
|
||||||
data['projects'] = {'url': reverse('api:project_list'),
|
data['projects'] = {'url': reverse('api:project_list', request=request),
|
||||||
'failures_url': reverse('api:project_list') + "?last_job_failed=True",
|
'failures_url': reverse('api:project_list', request=request) + "?last_job_failed=True",
|
||||||
'total': user_projects.count(),
|
'total': user_projects.count(),
|
||||||
'failed': user_projects_failed.count()}
|
'failed': user_projects_failed.count()}
|
||||||
|
|
||||||
@ -393,26 +394,26 @@ class DashboardView(APIView):
|
|||||||
hg_projects = user_projects.filter(scm_type='hg')
|
hg_projects = user_projects.filter(scm_type='hg')
|
||||||
hg_failed_projects = hg_projects.filter(last_job_failed=True)
|
hg_failed_projects = hg_projects.filter(last_job_failed=True)
|
||||||
data['scm_types'] = {}
|
data['scm_types'] = {}
|
||||||
data['scm_types']['git'] = {'url': reverse('api:project_list') + "?scm_type=git",
|
data['scm_types']['git'] = {'url': reverse('api:project_list', request=request) + "?scm_type=git",
|
||||||
'label': 'Git',
|
'label': 'Git',
|
||||||
'failures_url': reverse('api:project_list') + "?scm_type=git&last_job_failed=True",
|
'failures_url': reverse('api:project_list', request=request) + "?scm_type=git&last_job_failed=True",
|
||||||
'total': git_projects.count(),
|
'total': git_projects.count(),
|
||||||
'failed': git_failed_projects.count()}
|
'failed': git_failed_projects.count()}
|
||||||
data['scm_types']['svn'] = {'url': reverse('api:project_list') + "?scm_type=svn",
|
data['scm_types']['svn'] = {'url': reverse('api:project_list', request=request) + "?scm_type=svn",
|
||||||
'label': 'Subversion',
|
'label': 'Subversion',
|
||||||
'failures_url': reverse('api:project_list') + "?scm_type=svn&last_job_failed=True",
|
'failures_url': reverse('api:project_list', request=request) + "?scm_type=svn&last_job_failed=True",
|
||||||
'total': svn_projects.count(),
|
'total': svn_projects.count(),
|
||||||
'failed': svn_failed_projects.count()}
|
'failed': svn_failed_projects.count()}
|
||||||
data['scm_types']['hg'] = {'url': reverse('api:project_list') + "?scm_type=hg",
|
data['scm_types']['hg'] = {'url': reverse('api:project_list', request=request) + "?scm_type=hg",
|
||||||
'label': 'Mercurial',
|
'label': 'Mercurial',
|
||||||
'failures_url': reverse('api:project_list') + "?scm_type=hg&last_job_failed=True",
|
'failures_url': reverse('api:project_list', request=request) + "?scm_type=hg&last_job_failed=True",
|
||||||
'total': hg_projects.count(),
|
'total': hg_projects.count(),
|
||||||
'failed': hg_failed_projects.count()}
|
'failed': hg_failed_projects.count()}
|
||||||
|
|
||||||
user_jobs = get_user_queryset(request.user, Job)
|
user_jobs = get_user_queryset(request.user, Job)
|
||||||
user_failed_jobs = user_jobs.filter(failed=True)
|
user_failed_jobs = user_jobs.filter(failed=True)
|
||||||
data['jobs'] = {'url': reverse('api:job_list'),
|
data['jobs'] = {'url': reverse('api:job_list', request=request),
|
||||||
'failure_url': reverse('api:job_list') + "?failed=True",
|
'failure_url': reverse('api:job_list', request=request) + "?failed=True",
|
||||||
'total': user_jobs.count(),
|
'total': user_jobs.count(),
|
||||||
'failed': user_failed_jobs.count()}
|
'failed': user_failed_jobs.count()}
|
||||||
|
|
||||||
@ -421,15 +422,15 @@ class DashboardView(APIView):
|
|||||||
credential_list = get_user_queryset(request.user, Credential)
|
credential_list = get_user_queryset(request.user, Credential)
|
||||||
job_template_list = get_user_queryset(request.user, JobTemplate)
|
job_template_list = get_user_queryset(request.user, JobTemplate)
|
||||||
organization_list = get_user_queryset(request.user, Organization)
|
organization_list = get_user_queryset(request.user, Organization)
|
||||||
data['users'] = {'url': reverse('api:user_list'),
|
data['users'] = {'url': reverse('api:user_list', request=request),
|
||||||
'total': user_list.count()}
|
'total': user_list.count()}
|
||||||
data['organizations'] = {'url': reverse('api:organization_list'),
|
data['organizations'] = {'url': reverse('api:organization_list', request=request),
|
||||||
'total': organization_list.count()}
|
'total': organization_list.count()}
|
||||||
data['teams'] = {'url': reverse('api:team_list'),
|
data['teams'] = {'url': reverse('api:team_list', request=request),
|
||||||
'total': team_list.count()}
|
'total': team_list.count()}
|
||||||
data['credentials'] = {'url': reverse('api:credential_list'),
|
data['credentials'] = {'url': reverse('api:credential_list', request=request),
|
||||||
'total': credential_list.count()}
|
'total': credential_list.count()}
|
||||||
data['job_templates'] = {'url': reverse('api:job_template_list'),
|
data['job_templates'] = {'url': reverse('api:job_template_list', request=request),
|
||||||
'total': job_template_list.count()}
|
'total': job_template_list.count()}
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
@ -516,6 +517,7 @@ class AuthView(APIView):
|
|||||||
new_in_240 = True
|
new_in_240 = True
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
from rest_framework.reverse import reverse
|
||||||
data = OrderedDict()
|
data = OrderedDict()
|
||||||
err_backend, err_message = request.session.get('social_auth_error', (None, None))
|
err_backend, err_message = request.session.get('social_auth_error', (None, None))
|
||||||
auth_backends = load_backends(settings.AUTHENTICATION_BACKENDS, force_load=True).items()
|
auth_backends = load_backends(settings.AUTHENTICATION_BACKENDS, force_load=True).items()
|
||||||
@ -527,6 +529,7 @@ class AuthView(APIView):
|
|||||||
(not feature_enabled('enterprise_auth') and
|
(not feature_enabled('enterprise_auth') and
|
||||||
name in ['saml', 'radius']):
|
name in ['saml', 'radius']):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
login_url = reverse('social:begin', args=(name,))
|
login_url = reverse('social:begin', args=(name,))
|
||||||
complete_url = request.build_absolute_uri(reverse('social:complete', args=(name,)))
|
complete_url = request.build_absolute_uri(reverse('social:complete', args=(name,)))
|
||||||
backend_data = {
|
backend_data = {
|
||||||
@ -1167,7 +1170,7 @@ class ProjectUpdateView(RetrieveAPIView):
|
|||||||
if not project_update:
|
if not project_update:
|
||||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
else:
|
else:
|
||||||
headers = {'Location': project_update.get_absolute_url()}
|
headers = {'Location': project_update.get_absolute_url(request=request)}
|
||||||
return Response({'project_update': project_update.id},
|
return Response({'project_update': project_update.id},
|
||||||
headers=headers,
|
headers=headers,
|
||||||
status=status.HTTP_202_ACCEPTED)
|
status=status.HTTP_202_ACCEPTED)
|
||||||
@ -1699,6 +1702,14 @@ class HostList(ListCreateAPIView):
|
|||||||
serializer_class = HostSerializer
|
serializer_class = HostSerializer
|
||||||
capabilities_prefetch = ['inventory.admin']
|
capabilities_prefetch = ['inventory.admin']
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super(HostList, self).get_queryset()
|
||||||
|
filter_string = self.request.query_params.get('host_filter', None)
|
||||||
|
if filter_string:
|
||||||
|
filter_q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
qs = qs.filter(filter_q)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class HostDetail(RetrieveUpdateDestroyAPIView):
|
class HostDetail(RetrieveUpdateDestroyAPIView):
|
||||||
|
|
||||||
@ -2273,7 +2284,7 @@ class InventorySourceUpdateView(RetrieveAPIView):
|
|||||||
if not inventory_update:
|
if not inventory_update:
|
||||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
else:
|
else:
|
||||||
headers = {'Location': inventory_update.get_absolute_url()}
|
headers = {'Location': inventory_update.get_absolute_url(request=request)}
|
||||||
return Response(dict(inventory_update=inventory_update.id), status=status.HTTP_202_ACCEPTED, headers=headers)
|
return Response(dict(inventory_update=inventory_update.id), status=status.HTTP_202_ACCEPTED, headers=headers)
|
||||||
else:
|
else:
|
||||||
return self.http_method_not_allowed(request, *args, **kwargs)
|
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||||
@ -2741,7 +2752,7 @@ class JobTemplateCallback(GenericAPIView):
|
|||||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
# Return the location of the new job.
|
# Return the location of the new job.
|
||||||
headers = {'Location': job.get_absolute_url()}
|
headers = {'Location': job.get_absolute_url(request=request)}
|
||||||
return Response(status=status.HTTP_201_CREATED, headers=headers)
|
return Response(status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
@ -3035,7 +3046,7 @@ class WorkflowJobRelaunch(WorkflowsEnforcementMixin, GenericAPIView):
|
|||||||
new_workflow_job.signal_start()
|
new_workflow_job.signal_start()
|
||||||
|
|
||||||
data = WorkflowJobSerializer(new_workflow_job, context=self.get_serializer_context()).data
|
data = WorkflowJobSerializer(new_workflow_job, context=self.get_serializer_context()).data
|
||||||
headers = {'Location': new_workflow_job.get_absolute_url()}
|
headers = {'Location': new_workflow_job.get_absolute_url(request=request)}
|
||||||
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
@ -3419,7 +3430,7 @@ class JobRelaunch(RetrieveAPIView, GenericAPIView):
|
|||||||
data = JobSerializer(new_job, context=self.get_serializer_context()).data
|
data = JobSerializer(new_job, context=self.get_serializer_context()).data
|
||||||
# Add job key to match what old relaunch returned.
|
# Add job key to match what old relaunch returned.
|
||||||
data['job'] = new_job.id
|
data['job'] = new_job.id
|
||||||
headers = {'Location': new_job.get_absolute_url()}
|
headers = {'Location': new_job.get_absolute_url(request=request)}
|
||||||
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
@ -3693,7 +3704,7 @@ class AdHocCommandRelaunch(GenericAPIView):
|
|||||||
data = AdHocCommandSerializer(new_ad_hoc_command, context=self.get_serializer_context()).data
|
data = AdHocCommandSerializer(new_ad_hoc_command, context=self.get_serializer_context()).data
|
||||||
# Add ad_hoc_command key to match what was previously returned.
|
# Add ad_hoc_command key to match what was previously returned.
|
||||||
data['ad_hoc_command'] = new_ad_hoc_command.id
|
data['ad_hoc_command'] = new_ad_hoc_command.id
|
||||||
headers = {'Location': new_ad_hoc_command.get_absolute_url()}
|
headers = {'Location': new_ad_hoc_command.get_absolute_url(request=request)}
|
||||||
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
@ -3994,7 +4005,7 @@ class NotificationTemplateTest(GenericAPIView):
|
|||||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
else:
|
else:
|
||||||
send_notifications.delay([notification.id])
|
send_notifications.delay([notification.id])
|
||||||
headers = {'Location': notification.get_absolute_url()}
|
headers = {'Location': notification.get_absolute_url(request=request)}
|
||||||
return Response({"notification": notification.id},
|
return Response({"notification": notification.id},
|
||||||
headers=headers,
|
headers=headers,
|
||||||
status=status.HTTP_202_ACCEPTED)
|
status=status.HTTP_202_ACCEPTED)
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import sys
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
@ -20,6 +19,7 @@ from rest_framework import status
|
|||||||
# Tower
|
# Tower
|
||||||
from awx.api.generics import * # noqa
|
from awx.api.generics import * # noqa
|
||||||
from awx.api.permissions import IsSuperUser
|
from awx.api.permissions import IsSuperUser
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.utils import * # noqa
|
from awx.main.utils import * # noqa
|
||||||
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
|
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
|
||||||
from awx.conf.license import get_licensed_features
|
from awx.conf.license import get_licensed_features
|
||||||
@ -49,7 +49,7 @@ class SettingCategoryList(ListAPIView):
|
|||||||
else:
|
else:
|
||||||
categories = {}
|
categories = {}
|
||||||
for category_slug in sorted(categories.keys()):
|
for category_slug in sorted(categories.keys()):
|
||||||
url = reverse('api:setting_singleton_detail', args=(category_slug,))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': category_slug}, request=self.request)
|
||||||
setting_categories.append(SettingCategory(url, category_slug, categories[category_slug]))
|
setting_categories.append(SettingCategory(url, category_slug, categories[category_slug]))
|
||||||
return setting_categories
|
return setting_categories
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,7 @@ def executor(tmpdir_factory, request):
|
|||||||
|
|
||||||
cli = PlaybookCLI(['', 'playbook.yml'])
|
cli = PlaybookCLI(['', 'playbook.yml'])
|
||||||
cli.parse()
|
cli.parse()
|
||||||
options = cli.parser.parse_args([])[0]
|
options = cli.parser.parse_args(['-v'])[0]
|
||||||
loader = DataLoader()
|
loader = DataLoader()
|
||||||
variable_manager = VariableManager()
|
variable_manager = VariableManager()
|
||||||
inventory = Inventory(loader=loader, variable_manager=variable_manager,
|
inventory = Inventory(loader=loader, variable_manager=variable_manager,
|
||||||
|
|||||||
@ -30,6 +30,8 @@ from ansible.plugins.callback.default import CallbackModule as DefaultCallbackMo
|
|||||||
from .events import event_context
|
from .events import event_context
|
||||||
from .minimal import CallbackModule as MinimalCallbackModule
|
from .minimal import CallbackModule as MinimalCallbackModule
|
||||||
|
|
||||||
|
CENSORED = "the output has been hidden due to the fact that 'no_log: true' was specified for this result" # noqa
|
||||||
|
|
||||||
|
|
||||||
class BaseCallbackModule(CallbackBase):
|
class BaseCallbackModule(CallbackBase):
|
||||||
'''
|
'''
|
||||||
@ -69,8 +71,12 @@ class BaseCallbackModule(CallbackBase):
|
|||||||
else:
|
else:
|
||||||
task = None
|
task = None
|
||||||
|
|
||||||
if event_data.get('res') and event_data['res'].get('_ansible_no_log', False):
|
if event_data.get('res'):
|
||||||
event_data['res'] = {'censored': "the output has been hidden due to the fact that 'no_log: true' was specified for this result"} # noqa
|
if event_data['res'].get('_ansible_no_log', False):
|
||||||
|
event_data['res'] = {'censored': CENSORED}
|
||||||
|
for i, item in enumerate(event_data['res'].get('results', [])):
|
||||||
|
if event_data['res']['results'][i].get('_ansible_no_log', False):
|
||||||
|
event_data['res']['results'][i] = {'censored': CENSORED}
|
||||||
|
|
||||||
with event_context.display_lock:
|
with event_context.display_lock:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -242,9 +242,11 @@ register(
|
|||||||
field_class=fields.IntegerField,
|
field_class=fields.IntegerField,
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
label=_('Logging Aggregator Port'),
|
label=_('Logging Aggregator Port'),
|
||||||
help_text=_('Port on Logging Aggregator to send logs to (if required).'),
|
help_text=_('Port on Logging Aggregator to send logs to (if required and not'
|
||||||
|
' provided in Logging Aggregator).'),
|
||||||
category=_('Logging'),
|
category=_('Logging'),
|
||||||
category_slug='logging',
|
category_slug='logging',
|
||||||
|
required=False
|
||||||
)
|
)
|
||||||
register(
|
register(
|
||||||
'LOG_AGGREGATOR_TYPE',
|
'LOG_AGGREGATOR_TYPE',
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
# Copyright (c) 2015 Ansible, Inc.
|
# Copyright (c) 2015 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
# Python
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pyparsing import infixNotation, opAssoc, Optional, Literal, CharsNotIn
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db.models.signals import (
|
from django.db.models.signals import (
|
||||||
@ -18,6 +22,7 @@ from django.db.models.fields.related import (
|
|||||||
ReverseManyRelatedObjectsDescriptor,
|
ReverseManyRelatedObjectsDescriptor,
|
||||||
)
|
)
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
# Django-JSONField
|
# Django-JSONField
|
||||||
from jsonfield import JSONField as upstream_JSONField
|
from jsonfield import JSONField as upstream_JSONField
|
||||||
@ -27,7 +32,7 @@ from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role
|
|||||||
from awx.main.utils import get_current_apps
|
from awx.main.utils import get_current_apps
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['AutoOneToOneField', 'ImplicitRoleField', 'JSONField']
|
__all__ = ['AutoOneToOneField', 'ImplicitRoleField', 'JSONField', 'DynamicFilterField']
|
||||||
|
|
||||||
|
|
||||||
class JSONField(upstream_JSONField):
|
class JSONField(upstream_JSONField):
|
||||||
@ -292,3 +297,187 @@ class ImplicitRoleField(models.ForeignKey):
|
|||||||
child_ids = [x for x in Role_.parents.through.objects.filter(to_role_id__in=role_ids).distinct().values_list('from_role_id', flat=True)]
|
child_ids = [x for x in Role_.parents.through.objects.filter(to_role_id__in=role_ids).distinct().values_list('from_role_id', flat=True)]
|
||||||
Role_.objects.filter(id__in=role_ids).delete()
|
Role_.objects.filter(id__in=role_ids).delete()
|
||||||
Role.rebuild_role_ancestor_list([], child_ids)
|
Role.rebuild_role_ancestor_list([], child_ids)
|
||||||
|
|
||||||
|
|
||||||
|
unicode_spaces = [unichr(c) for c in xrange(sys.maxunicode) if unichr(c).isspace()]
|
||||||
|
unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
|
||||||
|
|
||||||
|
|
||||||
|
def string_to_type(t):
|
||||||
|
if t == 'true':
|
||||||
|
return True
|
||||||
|
elif t == 'false':
|
||||||
|
return False
|
||||||
|
|
||||||
|
if re.search('^[-+]?[0-9]+$',t):
|
||||||
|
return int(t)
|
||||||
|
|
||||||
|
if re.search('^[-+]?[0-9]+\.[0-9]+$',t):
|
||||||
|
return float(t)
|
||||||
|
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
class DynamicFilterField(models.TextField):
|
||||||
|
|
||||||
|
|
||||||
|
class BoolOperand(object):
|
||||||
|
def __init__(self, t):
|
||||||
|
#print("Got t %s" % t)
|
||||||
|
kwargs = dict()
|
||||||
|
k, v = self._extract_key_value(t)
|
||||||
|
k, v = self._json_path_to_contains(k, v)
|
||||||
|
kwargs[k] = v
|
||||||
|
self.result = Q(**kwargs)
|
||||||
|
|
||||||
|
'''
|
||||||
|
TODO: We should be able to express this in the grammar and let
|
||||||
|
pyparsing do the heavy lifting.
|
||||||
|
TODO: separate django filter requests from our custom json filter
|
||||||
|
request so we don't process the key any. This could be
|
||||||
|
accomplished using a whitelist or introspecting the
|
||||||
|
relationship refered to to see if it's a jsonb type.
|
||||||
|
'''
|
||||||
|
def _json_path_to_contains(self, k, v):
|
||||||
|
pieces = k.split('__')
|
||||||
|
|
||||||
|
flag_first_arr_found = False
|
||||||
|
|
||||||
|
assembled_k = ''
|
||||||
|
assembled_v = v
|
||||||
|
|
||||||
|
last_kv = None
|
||||||
|
last_v = None
|
||||||
|
|
||||||
|
contains_count = 0
|
||||||
|
for i, piece in enumerate(pieces):
|
||||||
|
if flag_first_arr_found is False and piece.endswith('[]'):
|
||||||
|
assembled_k += '%s__contains' % (piece[0:-2])
|
||||||
|
contains_count += 1
|
||||||
|
flag_first_arr_found = True
|
||||||
|
elif flag_first_arr_found is False and i == len(pieces) - 1:
|
||||||
|
assembled_k += '%s' % piece
|
||||||
|
elif flag_first_arr_found is False:
|
||||||
|
assembled_k += '%s__' % piece
|
||||||
|
elif flag_first_arr_found is True:
|
||||||
|
new_kv = dict()
|
||||||
|
if piece.endswith('[]'):
|
||||||
|
new_v = []
|
||||||
|
new_kv[piece[0:-2]] = new_v
|
||||||
|
else:
|
||||||
|
new_v = dict()
|
||||||
|
new_kv[piece] = new_v
|
||||||
|
|
||||||
|
|
||||||
|
if last_v is None:
|
||||||
|
last_v = []
|
||||||
|
assembled_v = last_v
|
||||||
|
|
||||||
|
if type(last_v) is list:
|
||||||
|
last_v.append(new_kv)
|
||||||
|
elif type(last_v) is dict:
|
||||||
|
last_kv[last_kv.keys()[0]] = new_kv
|
||||||
|
|
||||||
|
last_v = new_v
|
||||||
|
last_kv = new_kv
|
||||||
|
contains_count += 1
|
||||||
|
|
||||||
|
if contains_count > 1:
|
||||||
|
if type(last_v) is list:
|
||||||
|
last_v.append(v)
|
||||||
|
if type(last_v) is dict:
|
||||||
|
last_kv[last_kv.keys()[0]] = v
|
||||||
|
|
||||||
|
return (assembled_k, assembled_v)
|
||||||
|
|
||||||
|
def _extract_key_value(self, t):
|
||||||
|
t_len = len(t)
|
||||||
|
|
||||||
|
k = None
|
||||||
|
v = None
|
||||||
|
|
||||||
|
# key
|
||||||
|
# "something"=
|
||||||
|
v_offset = 2
|
||||||
|
if t_len >= 2 and t[0] == "\"" and t[2] == "\"":
|
||||||
|
k = t[1]
|
||||||
|
v_offset = 4
|
||||||
|
# something=
|
||||||
|
else:
|
||||||
|
k = t[0]
|
||||||
|
|
||||||
|
# value
|
||||||
|
# ="something"
|
||||||
|
if t_len > (v_offset + 2) and t[v_offset] == "\"" and t[v_offset + 2] == "\"":
|
||||||
|
v = t[v_offset + 1]
|
||||||
|
# empty ""
|
||||||
|
elif t_len > (v_offset + 1):
|
||||||
|
v = ""
|
||||||
|
# no ""
|
||||||
|
else:
|
||||||
|
v = string_to_type(t[v_offset])
|
||||||
|
|
||||||
|
return (k, v)
|
||||||
|
|
||||||
|
|
||||||
|
class BoolBinOp(object):
|
||||||
|
def __init__(self, t):
|
||||||
|
self.left = t[0][0].result
|
||||||
|
self.right = t[0][2].result
|
||||||
|
|
||||||
|
self.result = self.execute_logic(self.left, self.right)
|
||||||
|
|
||||||
|
|
||||||
|
class BoolAnd(BoolBinOp):
|
||||||
|
def execute_logic(self, left, right):
|
||||||
|
return left & right
|
||||||
|
|
||||||
|
|
||||||
|
class BoolOr(BoolBinOp):
|
||||||
|
def execute_logic(self, left, right):
|
||||||
|
return left | right
|
||||||
|
|
||||||
|
|
||||||
|
class BoolNot(object):
|
||||||
|
def __init__(self,t):
|
||||||
|
self.right = t[0][1]
|
||||||
|
self.result = ~self.right
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_string_to_q(cls, filter_string):
|
||||||
|
|
||||||
|
'''
|
||||||
|
TODO:
|
||||||
|
* handle values with " via: a.b.c.d="hello\"world"
|
||||||
|
* handle keys with " via: a.\"b.c="yeah"
|
||||||
|
* handle key with __ in it
|
||||||
|
|
||||||
|
* add not support
|
||||||
|
|
||||||
|
* transform [] into contains via: a.b.c[].d[].e.f[]="blah"
|
||||||
|
|
||||||
|
* handle optional value quoted: a.b.c=""
|
||||||
|
|
||||||
|
'''
|
||||||
|
atom = CharsNotIn(unicode_spaces_other)
|
||||||
|
atom_inside_quotes = CharsNotIn(u'"')
|
||||||
|
atom_quoted = Literal('"') + Optional(atom_inside_quotes) + Literal('"')
|
||||||
|
EQUAL = Literal('=')
|
||||||
|
|
||||||
|
grammar = ((atom_quoted | atom) + EQUAL + Optional((atom_quoted | atom)))
|
||||||
|
grammar.setParseAction(cls.BoolOperand)
|
||||||
|
|
||||||
|
boolExpr = infixNotation(grammar, [
|
||||||
|
#("not", 1, opAssoc.RIGHT, cls.BoolNot),
|
||||||
|
("and", 2, opAssoc.LEFT, cls.BoolAnd),
|
||||||
|
("or", 2, opAssoc.LEFT, cls.BoolOr),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = boolExpr.parseString('(' + filter_string + ')')
|
||||||
|
if len(res) > 0:
|
||||||
|
return res[0].result
|
||||||
|
|
||||||
|
raise RuntimeError("Parsing the filter_string %s went terribly wrong" % filter_string)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
# Copyright (c) 2015 Ansible, Inc.
|
# Copyright (c) 2015 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
# Tower
|
||||||
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
__all__ = ['ActivityStream']
|
__all__ = ['ActivityStream']
|
||||||
@ -63,8 +65,8 @@ class ActivityStream(models.Model):
|
|||||||
label = models.ManyToManyField("Label", blank=True)
|
label = models.ManyToManyField("Label", blank=True)
|
||||||
role = models.ManyToManyField("Role", blank=True)
|
role = models.ManyToManyField("Role", blank=True)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:activity_stream_detail', args=(self.pk,))
|
return reverse('api:activity_stream_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
# Python
|
# Python
|
||||||
import datetime
|
import datetime
|
||||||
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import logging
|
import logging
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
@ -15,9 +16,9 @@ from django.utils.text import Truncator
|
|||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.models.unified_jobs import * # noqa
|
from awx.main.models.unified_jobs import * # noqa
|
||||||
from awx.main.models.notifications import JobNotificationMixin, NotificationTemplate
|
from awx.main.models.notifications import JobNotificationMixin, NotificationTemplate
|
||||||
@ -142,8 +143,8 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
|
|||||||
from awx.main.tasks import RunAdHocCommand
|
from awx.main.tasks import RunAdHocCommand
|
||||||
return RunAdHocCommand
|
return RunAdHocCommand
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:ad_hoc_command_detail', args=(self.pk,))
|
return reverse('api:ad_hoc_command_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urljoin(settings.TOWER_URL_BASE, "/#/ad_hoc_commands/{}".format(self.pk))
|
return urljoin(settings.TOWER_URL_BASE, "/#/ad_hoc_commands/{}".format(self.pk))
|
||||||
@ -152,7 +153,7 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
|
|||||||
def task_auth_token(self):
|
def task_auth_token(self):
|
||||||
'''Return temporary auth token used for task requests via API.'''
|
'''Return temporary auth token used for task requests via API.'''
|
||||||
if self.status == 'running':
|
if self.status == 'running':
|
||||||
h = hmac.new(settings.SECRET_KEY, self.created.isoformat())
|
h = hmac.new(settings.SECRET_KEY, self.created.isoformat(), digestmod=hashlib.sha1)
|
||||||
return '%d-%s' % (self.pk, h.hexdigest())
|
return '%d-%s' % (self.pk, h.hexdigest())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -317,8 +318,8 @@ class AdHocCommandEvent(CreatedModifiedModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:ad_hoc_command_event_detail', args=(self.pk,))
|
return reverse('api:ad_hoc_command_event_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())
|
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.fields import ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
from awx.main.utils import decrypt_field
|
from awx.main.utils import decrypt_field
|
||||||
@ -271,8 +271,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
|||||||
needed.append(field)
|
needed.append(field)
|
||||||
return needed
|
return needed
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:credential_detail', args=(self.pk,))
|
return reverse('api:credential_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def clean_host(self):
|
def clean_host(self):
|
||||||
"""Ensure that if this is a type of credential that requires a
|
"""Ensure that if this is a type of credential that requires a
|
||||||
|
|||||||
@ -14,10 +14,10 @@ from django.db import models
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
|
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
|
||||||
from awx.main.managers import HostManager
|
from awx.main.managers import HostManager
|
||||||
@ -117,9 +117,8 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
'admin_role',
|
'admin_role',
|
||||||
])
|
])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:inventory_detail', args=(self.pk,))
|
return reverse('api:inventory_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
|
|
||||||
variables_dict = VarsDictProperty('variables')
|
variables_dict = VarsDictProperty('variables')
|
||||||
|
|
||||||
@ -389,8 +388,8 @@ class Host(CommonModelNameNotUnique):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:host_detail', args=(self.pk,))
|
return reverse('api:host_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def update_computed_fields(self, update_inventory=True, update_groups=True):
|
def update_computed_fields(self, update_inventory=True, update_groups=True):
|
||||||
'''
|
'''
|
||||||
@ -520,8 +519,8 @@ class Group(CommonModelNameNotUnique):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:group_detail', args=(self.pk,))
|
return reverse('api:group_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def delete_recursive(self):
|
def delete_recursive(self):
|
||||||
@ -1137,8 +1136,8 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
|
|||||||
else:
|
else:
|
||||||
return 'none'
|
return 'none'
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:inventory_source_detail', args=(self.pk,))
|
return reverse('api:inventory_source_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def _can_update(self):
|
def _can_update(self):
|
||||||
if self.source == 'custom':
|
if self.source == 'custom':
|
||||||
@ -1246,8 +1245,8 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin):
|
|||||||
update_fields.append('name')
|
update_fields.append('name')
|
||||||
super(InventoryUpdate, self).save(*args, **kwargs)
|
super(InventoryUpdate, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:inventory_update_detail', args=(self.pk,))
|
return reverse('api:inventory_update_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urljoin(settings.TOWER_URL_BASE, "/#/inventory_sync/{}".format(self.pk))
|
return urljoin(settings.TOWER_URL_BASE, "/#/inventory_sync/{}".format(self.pk))
|
||||||
@ -1322,5 +1321,5 @@ class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
parent_role=['organization.auditor_role', 'organization.member_role', 'admin_role'],
|
parent_role=['organization.auditor_role', 'organization.member_role', 'admin_role'],
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:inventory_script_detail', args=(self.pk,))
|
return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
# Python
|
# Python
|
||||||
import datetime
|
import datetime
|
||||||
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
@ -17,9 +18,9 @@ from django.utils.encoding import force_text
|
|||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.models.unified_jobs import * # noqa
|
from awx.main.models.unified_jobs import * # noqa
|
||||||
@ -292,8 +293,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
|||||||
'''
|
'''
|
||||||
return self.create_unified_job(**kwargs)
|
return self.create_unified_job(**kwargs)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:job_template_detail', args=(self.pk,))
|
return reverse('api:job_template_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def can_start_without_user_input(self, callback_extra_vars=None):
|
def can_start_without_user_input(self, callback_extra_vars=None):
|
||||||
'''
|
'''
|
||||||
@ -470,8 +471,8 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
|
|||||||
def _get_unified_job_template_class(cls):
|
def _get_unified_job_template_class(cls):
|
||||||
return JobTemplate
|
return JobTemplate
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:job_detail', args=(self.pk,))
|
return reverse('api:job_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urljoin(settings.TOWER_URL_BASE, "/#/jobs/{}".format(self.pk))
|
return urljoin(settings.TOWER_URL_BASE, "/#/jobs/{}".format(self.pk))
|
||||||
@ -480,7 +481,7 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
|
|||||||
def task_auth_token(self):
|
def task_auth_token(self):
|
||||||
'''Return temporary auth token used for task requests via API.'''
|
'''Return temporary auth token used for task requests via API.'''
|
||||||
if self.status == 'running':
|
if self.status == 'running':
|
||||||
h = hmac.new(settings.SECRET_KEY, self.created.isoformat())
|
h = hmac.new(settings.SECRET_KEY, self.created.isoformat(), digestmod=hashlib.sha1)
|
||||||
return '%d-%s' % (self.pk, h.hexdigest())
|
return '%d-%s' % (self.pk, h.hexdigest())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -687,8 +688,8 @@ class JobHostSummary(CreatedModifiedModel):
|
|||||||
(self.host.name, self.changed, self.dark, self.failures, self.ok,
|
(self.host.name, self.changed, self.dark, self.failures, self.ok,
|
||||||
self.processed, self.skipped)
|
self.processed, self.skipped)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:job_host_summary_detail', args=(self.pk,))
|
return reverse('api:job_host_summary_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# If update_fields has been specified, add our field names to it,
|
# If update_fields has been specified, add our field names to it,
|
||||||
@ -905,8 +906,8 @@ class JobEvent(CreatedModifiedModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:job_event_detail', args=(self.pk,))
|
return reverse('api:job_event_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s @ %s' % (self.get_event_display2(), self.created.isoformat())
|
return u'%s @ %s' % (self.get_event_display2(), self.created.isoformat())
|
||||||
@ -1219,8 +1220,8 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
|
|||||||
def _get_unified_job_field_names(cls):
|
def _get_unified_job_field_names(cls):
|
||||||
return ['name', 'description', 'job_type', 'extra_vars']
|
return ['name', 'description', 'job_type', 'extra_vars']
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:system_job_template_detail', args=(self.pk,))
|
return reverse('api:system_job_template_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_timeout_blocked(self):
|
def cache_timeout_blocked(self):
|
||||||
@ -1275,8 +1276,8 @@ class SystemJob(UnifiedJob, SystemJobOptions, JobNotificationMixin):
|
|||||||
def websocket_emit_data(self):
|
def websocket_emit_data(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:system_job_detail', args=(self.pk,))
|
return reverse('api:system_job_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urljoin(settings.TOWER_URL_BASE, "/#/management_jobs/{}".format(self.pk))
|
return urljoin(settings.TOWER_URL_BASE, "/#/management_jobs/{}".format(self.pk))
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.base import CommonModelNameNotUnique
|
from awx.main.models.base import CommonModelNameNotUnique
|
||||||
from awx.main.models.unified_jobs import UnifiedJobTemplate, UnifiedJob
|
from awx.main.models.unified_jobs import UnifiedJobTemplate, UnifiedJob
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ class Label(CommonModelNameNotUnique):
|
|||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:label_detail', args=(self.pk,))
|
return reverse('api:label_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_orphaned_labels():
|
def get_orphaned_labels():
|
||||||
|
|||||||
@ -130,13 +130,18 @@ class SurveyJobTemplateMixin(models.Model):
|
|||||||
for survey_element in self.survey_spec.get("spec", []):
|
for survey_element in self.survey_spec.get("spec", []):
|
||||||
default = survey_element.get('default')
|
default = survey_element.get('default')
|
||||||
variable_key = survey_element.get('variable')
|
variable_key = survey_element.get('variable')
|
||||||
|
|
||||||
if survey_element.get('type') == 'password':
|
if survey_element.get('type') == 'password':
|
||||||
if variable_key in kwargs_extra_vars and default:
|
if variable_key in kwargs_extra_vars and default:
|
||||||
kw_value = kwargs_extra_vars[variable_key]
|
kw_value = kwargs_extra_vars[variable_key]
|
||||||
if kw_value.startswith('$encrypted$') and kw_value != default:
|
if kw_value.startswith('$encrypted$') and kw_value != default:
|
||||||
kwargs_extra_vars[variable_key] = default
|
kwargs_extra_vars[variable_key] = default
|
||||||
|
|
||||||
if default is not None:
|
if default is not None:
|
||||||
extra_vars[variable_key] = default
|
data = {variable_key: default}
|
||||||
|
errors = self._survey_element_validation(survey_element, data)
|
||||||
|
if not errors:
|
||||||
|
extra_vars[variable_key] = default
|
||||||
|
|
||||||
# Overwrite job template extra vars with explicit job extra vars
|
# Overwrite job template extra vars with explicit job extra vars
|
||||||
# and add on job extra vars
|
# and add on job extra vars
|
||||||
@ -144,6 +149,65 @@ class SurveyJobTemplateMixin(models.Model):
|
|||||||
kwargs['extra_vars'] = json.dumps(extra_vars)
|
kwargs['extra_vars'] = json.dumps(extra_vars)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
def _survey_element_validation(self, survey_element, data):
|
||||||
|
errors = []
|
||||||
|
if survey_element['variable'] not in data and survey_element['required']:
|
||||||
|
errors.append("'%s' value missing" % survey_element['variable'])
|
||||||
|
elif survey_element['type'] in ["textarea", "text", "password"]:
|
||||||
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) not in (str, unicode):
|
||||||
|
errors.append("Value %s for '%s' expected to be a string." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
return errors
|
||||||
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and len(data[survey_element['variable']]) < int(survey_element['min']):
|
||||||
|
errors.append("'%s' value %s is too small (length is %s must be at least %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], len(data[survey_element['variable']]), survey_element['min']))
|
||||||
|
if 'max' in survey_element and survey_element['max'] not in ["", None] and len(data[survey_element['variable']]) > int(survey_element['max']):
|
||||||
|
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
|
elif survey_element['type'] == 'integer':
|
||||||
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) != int:
|
||||||
|
errors.append("Value %s for '%s' expected to be an integer." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
return errors
|
||||||
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and survey_element['variable'] in data and \
|
||||||
|
data[survey_element['variable']] < int(survey_element['min']):
|
||||||
|
errors.append("'%s' value %s is too small (must be at least %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
||||||
|
if 'max' in survey_element and survey_element['max'] not in ["", None] and survey_element['variable'] in data and \
|
||||||
|
data[survey_element['variable']] > int(survey_element['max']):
|
||||||
|
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
|
elif survey_element['type'] == 'float':
|
||||||
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) not in (float, int):
|
||||||
|
errors.append("Value %s for '%s' expected to be a numeric type." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
return errors
|
||||||
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and data[survey_element['variable']] < float(survey_element['min']):
|
||||||
|
errors.append("'%s' value %s is too small (must be at least %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
||||||
|
if 'max' in survey_element and survey_element['max'] not in ["", None] and data[survey_element['variable']] > float(survey_element['max']):
|
||||||
|
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
||||||
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
|
elif survey_element['type'] == 'multiselect':
|
||||||
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) != list:
|
||||||
|
errors.append("'%s' value is expected to be a list." % survey_element['variable'])
|
||||||
|
else:
|
||||||
|
for val in data[survey_element['variable']]:
|
||||||
|
if val not in survey_element['choices']:
|
||||||
|
errors.append("Value %s for '%s' expected to be one of %s." % (val, survey_element['variable'],
|
||||||
|
survey_element['choices']))
|
||||||
|
elif survey_element['type'] == 'multiplechoice':
|
||||||
|
if survey_element['variable'] in data:
|
||||||
|
if data[survey_element['variable']] not in survey_element['choices']:
|
||||||
|
errors.append("Value %s for '%s' expected to be one of %s." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable'],
|
||||||
|
survey_element['choices']))
|
||||||
|
return errors
|
||||||
|
|
||||||
def survey_variable_validation(self, data):
|
def survey_variable_validation(self, data):
|
||||||
errors = []
|
errors = []
|
||||||
if not self.survey_enabled:
|
if not self.survey_enabled:
|
||||||
@ -153,62 +217,7 @@ class SurveyJobTemplateMixin(models.Model):
|
|||||||
if 'description' not in self.survey_spec:
|
if 'description' not in self.survey_spec:
|
||||||
errors.append("'description' missing from survey spec.")
|
errors.append("'description' missing from survey spec.")
|
||||||
for survey_element in self.survey_spec.get("spec", []):
|
for survey_element in self.survey_spec.get("spec", []):
|
||||||
if survey_element['variable'] not in data and \
|
errors += self._survey_element_validation(survey_element, data)
|
||||||
survey_element['required']:
|
|
||||||
errors.append("'%s' value missing" % survey_element['variable'])
|
|
||||||
elif survey_element['type'] in ["textarea", "text", "password"]:
|
|
||||||
if survey_element['variable'] in data:
|
|
||||||
if type(data[survey_element['variable']]) not in (str, unicode):
|
|
||||||
errors.append("Value %s for '%s' expected to be a string." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable']))
|
|
||||||
continue
|
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and len(data[survey_element['variable']]) < int(survey_element['min']):
|
|
||||||
errors.append("'%s' value %s is too small (length is %s must be at least %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], len(data[survey_element['variable']]), survey_element['min']))
|
|
||||||
if 'max' in survey_element and survey_element['max'] not in ["", None] and len(data[survey_element['variable']]) > int(survey_element['max']):
|
|
||||||
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
|
||||||
elif survey_element['type'] == 'integer':
|
|
||||||
if survey_element['variable'] in data:
|
|
||||||
if type(data[survey_element['variable']]) != int:
|
|
||||||
errors.append("Value %s for '%s' expected to be an integer." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable']))
|
|
||||||
continue
|
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and survey_element['variable'] in data and \
|
|
||||||
data[survey_element['variable']] < int(survey_element['min']):
|
|
||||||
errors.append("'%s' value %s is too small (must be at least %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
|
||||||
if 'max' in survey_element and survey_element['max'] not in ["", None] and survey_element['variable'] in data and \
|
|
||||||
data[survey_element['variable']] > int(survey_element['max']):
|
|
||||||
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
|
||||||
elif survey_element['type'] == 'float':
|
|
||||||
if survey_element['variable'] in data:
|
|
||||||
if type(data[survey_element['variable']]) not in (float, int):
|
|
||||||
errors.append("Value %s for '%s' expected to be a numeric type." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable']))
|
|
||||||
continue
|
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and data[survey_element['variable']] < float(survey_element['min']):
|
|
||||||
errors.append("'%s' value %s is too small (must be at least %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
|
||||||
if 'max' in survey_element and survey_element['max'] not in ["", None] and data[survey_element['variable']] > float(survey_element['max']):
|
|
||||||
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
|
||||||
elif survey_element['type'] == 'multiselect':
|
|
||||||
if survey_element['variable'] in data:
|
|
||||||
if type(data[survey_element['variable']]) != list:
|
|
||||||
errors.append("'%s' value is expected to be a list." % survey_element['variable'])
|
|
||||||
else:
|
|
||||||
for val in data[survey_element['variable']]:
|
|
||||||
if val not in survey_element['choices']:
|
|
||||||
errors.append("Value %s for '%s' expected to be one of %s." % (val, survey_element['variable'],
|
|
||||||
survey_element['choices']))
|
|
||||||
elif survey_element['type'] == 'multiplechoice':
|
|
||||||
if survey_element['variable'] in data:
|
|
||||||
if data[survey_element['variable']] not in survey_element['choices']:
|
|
||||||
errors.append("Value %s for '%s' expected to be one of %s." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable'],
|
|
||||||
survey_element['choices']))
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,12 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.mail.message import EmailMessage
|
from django.core.mail.message import EmailMessage
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
|
|
||||||
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.utils import encrypt_field, decrypt_field
|
from awx.main.utils import encrypt_field, decrypt_field
|
||||||
from awx.main.notifications.email_backend import CustomEmailBackend
|
from awx.main.notifications.email_backend import CustomEmailBackend
|
||||||
@ -56,8 +57,8 @@ class NotificationTemplate(CommonModel):
|
|||||||
|
|
||||||
notification_configuration = JSONField(blank=False)
|
notification_configuration = JSONField(blank=False)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:notification_template_detail', args=(self.pk,))
|
return reverse('api:notification_template_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def notification_class(self):
|
def notification_class(self):
|
||||||
@ -169,9 +170,9 @@ class Notification(CreatedModifiedModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
body = JSONField(blank=True)
|
body = JSONField(blank=True)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:notification_detail', args=(self.pk,))
|
return reverse('api:notification_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
|
|
||||||
class JobNotificationMixin(object):
|
class JobNotificationMixin(object):
|
||||||
|
|||||||
@ -10,12 +10,12 @@ import uuid
|
|||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.timezone import now as tz_now
|
from django.utils.timezone import now as tz_now
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
|
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.models.rbac import (
|
from awx.main.models.rbac import (
|
||||||
@ -65,8 +65,8 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:organization_detail', args=(self.pk,))
|
return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -109,8 +109,8 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
parent_role=['organization.auditor_role', 'member_role'],
|
parent_role=['organization.auditor_role', 'member_role'],
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:team_detail', args=(self.pk,))
|
return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
|
|
||||||
class Permission(CommonModelNameNotUnique):
|
class Permission(CommonModelNameNotUnique):
|
||||||
@ -167,8 +167,8 @@ class Permission(CommonModelNameNotUnique):
|
|||||||
'+adhoc' if self.run_ad_hoc_commands else '',
|
'+adhoc' if self.run_ad_hoc_commands else '',
|
||||||
))
|
))
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:permission_detail', args=(self.pk,))
|
return reverse('api:permission_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
|
|
||||||
class Profile(CreatedModifiedModel):
|
class Profile(CreatedModifiedModel):
|
||||||
@ -326,6 +326,6 @@ class AuthToken(BaseModel):
|
|||||||
|
|
||||||
# Add get_absolute_url method to User model if not present.
|
# Add get_absolute_url method to User model if not present.
|
||||||
if not hasattr(User, 'get_absolute_url'):
|
if not hasattr(User, 'get_absolute_url'):
|
||||||
def user_get_absolute_url(user):
|
def user_get_absolute_url(user, request=None):
|
||||||
return reverse('api:user_detail', args=(user.pk,))
|
return reverse('api:user_detail', kwargs={'pk': user.pk}, request=request)
|
||||||
User.add_to_class('get_absolute_url', user_get_absolute_url)
|
User.add_to_class('get_absolute_url', user_get_absolute_url)
|
||||||
|
|||||||
@ -14,10 +14,10 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from django.utils.encoding import smart_str, smart_text
|
from django.utils.encoding import smart_str, smart_text
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.timezone import now, make_aware, get_default_timezone
|
from django.utils.timezone import now, make_aware, get_default_timezone
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.models.notifications import (
|
from awx.main.models.notifications import (
|
||||||
NotificationTemplate,
|
NotificationTemplate,
|
||||||
@ -401,8 +401,8 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
|
|||||||
success=list(success_notification_templates),
|
success=list(success_notification_templates),
|
||||||
any=list(any_notification_templates))
|
any=list(any_notification_templates))
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:project_detail', args=(self.pk,))
|
return reverse('api:project_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
|
|
||||||
class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
|
class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
|
||||||
@ -470,8 +470,8 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
|
|||||||
def result_stdout_limited(self, start_line=0, end_line=None, redact_sensitive=True):
|
def result_stdout_limited(self, start_line=0, end_line=None, redact_sensitive=True):
|
||||||
return self._result_stdout_raw_limited(start_line, end_line, redact_sensitive=redact_sensitive, escape_ascii=True)
|
return self._result_stdout_raw_limited(start_line, end_line, redact_sensitive=redact_sensitive, escape_ascii=True)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:project_update_detail', args=(self.pk,))
|
return reverse('api:project_update_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urlparse.urljoin(settings.TOWER_URL_BASE, "/#/scm_update/{}".format(self.pk))
|
return urlparse.urljoin(settings.TOWER_URL_BASE, "/#/scm_update/{}".format(self.pk))
|
||||||
|
|||||||
@ -9,13 +9,12 @@ import re
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db import models, transaction, connection
|
from django.db import models, transaction, connection
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from django.contrib.auth.models import User # noqa
|
from django.contrib.auth.models import User # noqa
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
|
|
||||||
@ -145,8 +144,8 @@ class Role(models.Model):
|
|||||||
super(Role, self).save(*args, **kwargs)
|
super(Role, self).save(*args, **kwargs)
|
||||||
self.rebuild_role_ancestor_list([self.id], [])
|
self.rebuild_role_ancestor_list([self.id], [])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:role_detail', args=(self.pk,))
|
return reverse('api:role_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def __contains__(self, accessor):
|
def __contains__(self, accessor):
|
||||||
if type(accessor) == User:
|
if type(accessor) == User:
|
||||||
|
|||||||
@ -13,10 +13,10 @@ from django.utils.timezone import now, make_aware, get_default_timezone
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.utils import ignore_inventory_computed_fields
|
from awx.main.utils import ignore_inventory_computed_fields
|
||||||
from awx.main.consumers import emit_channel_notification
|
from awx.main.consumers import emit_channel_notification
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from awx.main.fields import JSONField
|
from awx.main.fields import JSONField
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.models.schedule')
|
logger = logging.getLogger('awx.main.models.schedule')
|
||||||
@ -98,8 +98,8 @@ class Schedule(CommonModel):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run)
|
return u'%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:schedule_detail', args=(self.pk,))
|
return reverse('api:schedule_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def update_computed_fields(self):
|
def update_computed_fields(self):
|
||||||
future_rs = dateutil.rrule.rrulestr(self.rrule, forceset=True)
|
future_rs = dateutil.rrule.rrulestr(self.rrule, forceset=True)
|
||||||
|
|||||||
@ -153,10 +153,10 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
|
|||||||
related_name='%(class)s_labels'
|
related_name='%(class)s_labels'
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
real_instance = self.get_real_instance()
|
real_instance = self.get_real_instance()
|
||||||
if real_instance != self:
|
if real_instance != self:
|
||||||
return real_instance.get_absolute_url()
|
return real_instance.get_absolute_url(request=request)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,10 @@
|
|||||||
# Django
|
# Django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
#from django import settings as tower_settings
|
#from django import settings as tower_settings
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models import prevent_search, UnifiedJobTemplate, UnifiedJob
|
from awx.main.models import prevent_search, UnifiedJobTemplate, UnifiedJob
|
||||||
from awx.main.models.notifications import (
|
from awx.main.models.notifications import (
|
||||||
NotificationTemplate,
|
NotificationTemplate,
|
||||||
@ -177,8 +177,8 @@ class WorkflowJobTemplateNode(WorkflowNodeBase):
|
|||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:workflow_job_template_node_detail', args=(self.pk,))
|
return reverse('api:workflow_job_template_node_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def create_wfjt_node_copy(self, user, workflow_job_template=None):
|
def create_wfjt_node_copy(self, user, workflow_job_template=None):
|
||||||
'''
|
'''
|
||||||
@ -223,8 +223,8 @@ class WorkflowJobNode(WorkflowNodeBase):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:workflow_job_node_detail', args=(self.pk,))
|
return reverse('api:workflow_job_node_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_job_kwargs(self):
|
def get_job_kwargs(self):
|
||||||
'''
|
'''
|
||||||
@ -365,8 +365,8 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
|
|||||||
return (base_list +
|
return (base_list +
|
||||||
['survey_spec', 'survey_enabled', 'organization'])
|
['survey_spec', 'survey_enabled', 'organization'])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:workflow_job_template_detail', args=(self.pk,))
|
return reverse('api:workflow_job_template_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_timeout_blocked(self):
|
def cache_timeout_blocked(self):
|
||||||
@ -467,8 +467,8 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificatio
|
|||||||
def socketio_emit_data(self):
|
def socketio_emit_data(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self, request=None):
|
||||||
return reverse('api:workflow_job_detail', args=(self.pk,))
|
return reverse('api:workflow_job_detail', kwargs={'pk': self.pk}, request=request)
|
||||||
|
|
||||||
def get_ui_url(self):
|
def get_ui_url(self):
|
||||||
return urljoin(settings.TOWER_URL_BASE, '/#/workflows/{}'.format(self.pk))
|
return urljoin(settings.TOWER_URL_BASE, '/#/workflows/{}'.format(self.pk))
|
||||||
|
|||||||
@ -43,6 +43,7 @@ from django.core.mail import send_mail
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
@ -235,7 +236,11 @@ def _send_notification_templates(instance, status_str):
|
|||||||
|
|
||||||
@task(bind=True, queue='default')
|
@task(bind=True, queue='default')
|
||||||
def handle_work_success(self, result, task_actual):
|
def handle_work_success(self, result, task_actual):
|
||||||
instance = UnifiedJob.get_instance_by_type(task_actual['type'], task_actual['id'])
|
try:
|
||||||
|
instance = UnifiedJob.get_instance_by_type(task_actual['type'], task_actual['id'])
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
logger.warning('Missing job `{}` in success callback.'.format(task_actual['id']))
|
||||||
|
return
|
||||||
if not instance:
|
if not instance:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.middleware import ActivityStreamMiddleware
|
from awx.main.middleware import ActivityStreamMiddleware
|
||||||
from awx.main.models.activity_stream import ActivityStream
|
from awx.main.models.activity_stream import ActivityStream
|
||||||
from awx.main.access import ActivityStreamAccess
|
from awx.main.access import ActivityStreamAccess
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
|
|
||||||
def mock_feature_enabled(feature):
|
def mock_feature_enabled(feature):
|
||||||
return True
|
return True
|
||||||
@ -37,7 +36,7 @@ def test_basic_fields(monkeypatch, organization, get, user, settings):
|
|||||||
activity_stream.save()
|
activity_stream.save()
|
||||||
|
|
||||||
aspk = activity_stream.pk
|
aspk = activity_stream.pk
|
||||||
url = reverse('api:activity_stream_detail', args=(aspk,))
|
url = reverse('api:activity_stream_detail', kwargs={'pk': aspk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@ -64,7 +63,7 @@ def test_middleware_actor_added(monkeypatch, post, get, user, settings):
|
|||||||
org_id = response.data['id']
|
org_id = response.data['id']
|
||||||
activity_stream = ActivityStream.objects.filter(organization__pk=org_id).first()
|
activity_stream = ActivityStream.objects.filter(organization__pk=org_id).first()
|
||||||
|
|
||||||
url = reverse('api:activity_stream_detail', args=(activity_stream.pk,))
|
url = reverse('api:activity_stream_detail', kwargs={'pk': activity_stream.pk})
|
||||||
response = get(url, u)
|
response = get(url, u)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@ -147,14 +146,14 @@ def test_stream_user_direct_role_updates(get, post, organization_factory):
|
|||||||
users=['test'],
|
users=['test'],
|
||||||
inventories=['inv1'])
|
inventories=['inv1'])
|
||||||
|
|
||||||
url = reverse('api:user_roles_list', args=(objects.users.test.pk,))
|
url = reverse('api:user_roles_list', kwargs={'pk': objects.users.test.pk})
|
||||||
post(url, dict(id=objects.inventories.inv1.read_role.pk), objects.superusers.admin)
|
post(url, dict(id=objects.inventories.inv1.read_role.pk), objects.superusers.admin)
|
||||||
|
|
||||||
activity_stream = ActivityStream.objects.filter(
|
activity_stream = ActivityStream.objects.filter(
|
||||||
inventory__pk=objects.inventories.inv1.pk,
|
inventory__pk=objects.inventories.inv1.pk,
|
||||||
user__pk=objects.users.test.pk,
|
user__pk=objects.users.test.pk,
|
||||||
role__pk=objects.inventories.inv1.read_role.pk).first()
|
role__pk=objects.inventories.inv1.read_role.pk).first()
|
||||||
url = reverse('api:activity_stream_detail', args=(activity_stream.pk,))
|
url = reverse('api:activity_stream_detail', kwargs={'pk': activity_stream.pk})
|
||||||
response = get(url, objects.users.test)
|
response = get(url, objects.users.test)
|
||||||
|
|
||||||
assert response.data['object1'] == 'user'
|
assert response.data['object1'] == 'user'
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import mock # noqa
|
import mock # noqa
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -108,8 +108,8 @@ def test_user_post_ad_hoc_command_list_without_inventory(alice, post_adhoc, inve
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_admin_post_inventory_ad_hoc_command_list(admin, post_adhoc, inventory):
|
def test_admin_post_inventory_ad_hoc_command_list(admin, post_adhoc, inventory):
|
||||||
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', args=(inventory.id,)), {'inventory': None}, admin, expect=201)
|
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inventory.id}), {'inventory': None}, admin, expect=201)
|
||||||
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', args=(inventory.id,)), {}, admin, expect=201)
|
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inventory.id}), {}, admin, expect=201)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -121,19 +121,19 @@ def test_get_inventory_ad_hoc_command_list(admin, alice, post_adhoc, get, invent
|
|||||||
post_adhoc(reverse('api:ad_hoc_command_list'), {'inventory': inv2.id}, admin, expect=201)
|
post_adhoc(reverse('api:ad_hoc_command_list'), {'inventory': inv2.id}, admin, expect=201)
|
||||||
res = get(reverse('api:ad_hoc_command_list'), admin, expect=200)
|
res = get(reverse('api:ad_hoc_command_list'), admin, expect=200)
|
||||||
assert res.data['count'] == 2
|
assert res.data['count'] == 2
|
||||||
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), admin, expect=200)
|
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), admin, expect=200)
|
||||||
assert res.data['count'] == 1
|
assert res.data['count'] == 1
|
||||||
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv2.id,)), admin, expect=200)
|
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv2.id}), admin, expect=200)
|
||||||
assert res.data['count'] == 1
|
assert res.data['count'] == 1
|
||||||
|
|
||||||
inv1.adhoc_role.members.add(alice)
|
inv1.adhoc_role.members.add(alice)
|
||||||
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), alice, expect=200)
|
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), alice, expect=200)
|
||||||
assert res.data['count'] == 1
|
assert res.data['count'] == 1
|
||||||
|
|
||||||
machine_credential.use_role.members.add(alice)
|
machine_credential.use_role.members.add(alice)
|
||||||
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), alice, expect=200)
|
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), alice, expect=200)
|
||||||
assert res.data['count'] == 1
|
assert res.data['count'] == 1
|
||||||
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv2.id,)), alice, expect=403)
|
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv2.id}), alice, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -10,7 +10,7 @@ def test_user_role_view_access(rando, inventory, mocker, post):
|
|||||||
data = {"id": role_pk}
|
data = {"id": role_pk}
|
||||||
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
||||||
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
||||||
post(url=reverse('api:user_roles_list', args=(rando.pk,)),
|
post(url=reverse('api:user_roles_list', kwargs={'pk': rando.pk}),
|
||||||
data=data, user=rando, expect=403)
|
data=data, user=rando, expect=403)
|
||||||
mock_access.can_attach.assert_called_once_with(
|
mock_access.can_attach.assert_called_once_with(
|
||||||
inventory.admin_role, rando, 'members', data,
|
inventory.admin_role, rando, 'members', data,
|
||||||
@ -25,7 +25,7 @@ def test_team_role_view_access(rando, team, inventory, mocker, post):
|
|||||||
data = {"id": role_pk}
|
data = {"id": role_pk}
|
||||||
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
||||||
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
||||||
post(url=reverse('api:team_roles_list', args=(team.pk,)),
|
post(url=reverse('api:team_roles_list', kwargs={'pk': team.pk}),
|
||||||
data=data, user=rando, expect=403)
|
data=data, user=rando, expect=403)
|
||||||
mock_access.can_attach.assert_called_once_with(
|
mock_access.can_attach.assert_called_once_with(
|
||||||
inventory.admin_role, team, 'member_role.parents', data,
|
inventory.admin_role, team, 'member_role.parents', data,
|
||||||
@ -40,7 +40,7 @@ def test_role_team_view_access(rando, team, inventory, mocker, post):
|
|||||||
data = {"id": team.pk}
|
data = {"id": team.pk}
|
||||||
mock_access = mocker.MagicMock(return_value=False, __name__='mocked')
|
mock_access = mocker.MagicMock(return_value=False, __name__='mocked')
|
||||||
with mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access):
|
with mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access):
|
||||||
post(url=reverse('api:role_teams_list', args=(role_pk,)),
|
post(url=reverse('api:role_teams_list', kwargs={'pk': role_pk}),
|
||||||
data=data, user=rando, expect=403)
|
data=data, user=rando, expect=403)
|
||||||
mock_access.assert_called_once_with(
|
mock_access.assert_called_once_with(
|
||||||
inventory.admin_role, team, 'member_role.parents', data,
|
inventory.admin_role, team, 'member_role.parents', data,
|
||||||
@ -54,7 +54,7 @@ def test_org_associate_with_junk_data(rando, admin_user, organization, post):
|
|||||||
will turn off if the action is an association
|
will turn off if the action is an association
|
||||||
"""
|
"""
|
||||||
user_data = {'is_system_auditor': True, 'id': rando.pk}
|
user_data = {'is_system_auditor': True, 'id': rando.pk}
|
||||||
post(url=reverse('api:organization_users_list', args=(organization.pk,)),
|
post(url=reverse('api:organization_users_list', kwargs={'pk': organization.pk}),
|
||||||
data=user_data, expect=204, user=admin_user)
|
data=user_data, expect=204, user=admin_user)
|
||||||
# assure user is now an org member
|
# assure user is now an org member
|
||||||
assert rando in organization.member_role
|
assert rando in organization.member_role
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import mock # noqa
|
import mock # noqa
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -36,14 +36,14 @@ def test_credential_validation_error_with_bad_user(post, admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_create_user_credential_via_user_credentials_list(post, get, alice):
|
def test_create_user_credential_via_user_credentials_list(post, get, alice):
|
||||||
response = post(reverse('api:user_credentials_list', args=(alice.pk,)), {
|
response = post(reverse('api:user_credentials_list', kwargs={'pk': alice.pk}), {
|
||||||
'user': alice.pk,
|
'user': alice.pk,
|
||||||
'name': 'Some name',
|
'name': 'Some name',
|
||||||
'username': 'someusername',
|
'username': 'someusername',
|
||||||
}, alice)
|
}, alice)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
response = get(reverse('api:user_credentials_list', args=(alice.pk,)), alice)
|
response = get(reverse('api:user_credentials_list', kwargs={'pk': alice.pk}), alice)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ def test_create_user_credential_via_credentials_list_xfail(post, alice, bob):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_create_user_credential_via_user_credentials_list_xfail(post, alice, bob):
|
def test_create_user_credential_via_user_credentials_list_xfail(post, alice, bob):
|
||||||
response = post(reverse('api:user_credentials_list', args=(bob.pk,)), {
|
response = post(reverse('api:user_credentials_list', kwargs={'pk': bob.pk}), {
|
||||||
'user': bob.pk,
|
'user': bob.pk,
|
||||||
'name': 'Some name',
|
'name': 'Some name',
|
||||||
'username': 'someusername'
|
'username': 'someusername'
|
||||||
@ -82,7 +82,7 @@ def test_create_team_credential(post, get, team, organization, org_admin, team_m
|
|||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
response = get(reverse('api:team_credentials_list', args=(team.pk,)), team_member)
|
response = get(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), team_member)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
|
|
||||||
@ -92,14 +92,14 @@ def test_create_team_credential(post, get, team, organization, org_admin, team_m
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_create_team_credential_via_team_credentials_list(post, get, team, org_admin, team_member):
|
def test_create_team_credential_via_team_credentials_list(post, get, team, org_admin, team_member):
|
||||||
response = post(reverse('api:team_credentials_list', args=(team.pk,)), {
|
response = post(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), {
|
||||||
'team': team.pk,
|
'team': team.pk,
|
||||||
'name': 'Some name',
|
'name': 'Some name',
|
||||||
'username': 'someusername',
|
'username': 'someusername',
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
response = get(reverse('api:team_credentials_list', args=(team.pk,)), team_member)
|
response = get(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), team_member)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ def test_create_team_credential_by_team_member_xfail(post, team, organization, a
|
|||||||
def test_grant_org_credential_to_org_user_through_role_users(post, credential, organization, org_admin, org_member):
|
def test_grant_org_credential_to_org_user_through_role_users(post, credential, organization, org_admin, org_member):
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': org_member.id
|
'id': org_member.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -146,7 +146,7 @@ def test_grant_org_credential_to_org_user_through_role_users(post, credential, o
|
|||||||
def test_grant_org_credential_to_org_user_through_user_roles(post, credential, organization, org_admin, org_member):
|
def test_grant_org_credential_to_org_user_through_user_roles(post, credential, organization, org_admin, org_member):
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:user_roles_list', args=(org_member.id,)), {
|
response = post(reverse('api:user_roles_list', kwargs={'pk': org_member.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -156,7 +156,7 @@ def test_grant_org_credential_to_org_user_through_user_roles(post, credential, o
|
|||||||
def test_grant_org_credential_to_non_org_user_through_role_users(post, credential, organization, org_admin, alice):
|
def test_grant_org_credential_to_non_org_user_through_role_users(post, credential, organization, org_admin, alice):
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': alice.id
|
'id': alice.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -166,7 +166,7 @@ def test_grant_org_credential_to_non_org_user_through_role_users(post, credentia
|
|||||||
def test_grant_org_credential_to_non_org_user_through_user_roles(post, credential, organization, org_admin, alice):
|
def test_grant_org_credential_to_non_org_user_through_user_roles(post, credential, organization, org_admin, alice):
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:user_roles_list', args=(alice.id,)), {
|
response = post(reverse('api:user_roles_list', kwargs={'pk': alice.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -176,7 +176,7 @@ def test_grant_org_credential_to_non_org_user_through_user_roles(post, credentia
|
|||||||
def test_grant_private_credential_to_user_through_role_users(post, credential, alice, bob):
|
def test_grant_private_credential_to_user_through_role_users(post, credential, alice, bob):
|
||||||
# normal users can't do this
|
# normal users can't do this
|
||||||
credential.admin_role.members.add(alice)
|
credential.admin_role.members.add(alice)
|
||||||
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': bob.id
|
'id': bob.id
|
||||||
}, alice)
|
}, alice)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -186,7 +186,7 @@ def test_grant_private_credential_to_user_through_role_users(post, credential, a
|
|||||||
def test_grant_private_credential_to_org_user_through_role_users(post, credential, org_admin, org_member):
|
def test_grant_private_credential_to_org_user_through_role_users(post, credential, org_admin, org_member):
|
||||||
# org admins can't either
|
# org admins can't either
|
||||||
credential.admin_role.members.add(org_admin)
|
credential.admin_role.members.add(org_admin)
|
||||||
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': org_member.id
|
'id': org_member.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -195,7 +195,7 @@ def test_grant_private_credential_to_org_user_through_role_users(post, credentia
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sa_grant_private_credential_to_user_through_role_users(post, credential, admin, bob):
|
def test_sa_grant_private_credential_to_user_through_role_users(post, credential, admin, bob):
|
||||||
# but system admins can
|
# but system admins can
|
||||||
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': bob.id
|
'id': bob.id
|
||||||
}, admin)
|
}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -205,7 +205,7 @@ def test_sa_grant_private_credential_to_user_through_role_users(post, credential
|
|||||||
def test_grant_private_credential_to_user_through_user_roles(post, credential, alice, bob):
|
def test_grant_private_credential_to_user_through_user_roles(post, credential, alice, bob):
|
||||||
# normal users can't do this
|
# normal users can't do this
|
||||||
credential.admin_role.members.add(alice)
|
credential.admin_role.members.add(alice)
|
||||||
response = post(reverse('api:user_roles_list', args=(bob.id,)), {
|
response = post(reverse('api:user_roles_list', kwargs={'pk': bob.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, alice)
|
}, alice)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -215,7 +215,7 @@ def test_grant_private_credential_to_user_through_user_roles(post, credential, a
|
|||||||
def test_grant_private_credential_to_org_user_through_user_roles(post, credential, org_admin, org_member):
|
def test_grant_private_credential_to_org_user_through_user_roles(post, credential, org_admin, org_member):
|
||||||
# org admins can't either
|
# org admins can't either
|
||||||
credential.admin_role.members.add(org_admin)
|
credential.admin_role.members.add(org_admin)
|
||||||
response = post(reverse('api:user_roles_list', args=(org_member.id,)), {
|
response = post(reverse('api:user_roles_list', kwargs={'pk': org_member.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -224,7 +224,7 @@ def test_grant_private_credential_to_org_user_through_user_roles(post, credentia
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sa_grant_private_credential_to_user_through_user_roles(post, credential, admin, bob):
|
def test_sa_grant_private_credential_to_user_through_user_roles(post, credential, admin, bob):
|
||||||
# but system admins can
|
# but system admins can
|
||||||
response = post(reverse('api:user_roles_list', args=(bob.id,)), {
|
response = post(reverse('api:user_roles_list', kwargs={'pk': bob.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, admin)
|
}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -235,7 +235,7 @@ def test_grant_org_credential_to_team_through_role_teams(post, credential, organ
|
|||||||
assert org_auditor not in credential.read_role
|
assert org_auditor not in credential.read_role
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:role_teams_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': team.id
|
'id': team.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -247,7 +247,7 @@ def test_grant_org_credential_to_team_through_team_roles(post, credential, organ
|
|||||||
assert org_auditor not in credential.read_role
|
assert org_auditor not in credential.read_role
|
||||||
credential.organization = organization
|
credential.organization = organization
|
||||||
credential.save()
|
credential.save()
|
||||||
response = post(reverse('api:team_roles_list', args=(team.id,)), {
|
response = post(reverse('api:team_roles_list', kwargs={'pk': team.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -257,7 +257,7 @@ def test_grant_org_credential_to_team_through_team_roles(post, credential, organ
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sa_grant_private_credential_to_team_through_role_teams(post, credential, admin, team):
|
def test_sa_grant_private_credential_to_team_through_role_teams(post, credential, admin, team):
|
||||||
# not even a system admin can grant a private cred to a team though
|
# not even a system admin can grant a private cred to a team though
|
||||||
response = post(reverse('api:role_teams_list', args=(credential.use_role.id,)), {
|
response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {
|
||||||
'id': team.id
|
'id': team.id
|
||||||
}, admin)
|
}, admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -266,7 +266,7 @@ def test_sa_grant_private_credential_to_team_through_role_teams(post, credential
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sa_grant_private_credential_to_team_through_team_roles(post, credential, admin, team):
|
def test_sa_grant_private_credential_to_team_through_team_roles(post, credential, admin, team):
|
||||||
# not even a system admin can grant a private cred to a team though
|
# not even a system admin can grant a private cred to a team though
|
||||||
response = post(reverse('api:role_teams_list', args=(team.id,)), {
|
response = post(reverse('api:role_teams_list', kwargs={'pk': team.id}), {
|
||||||
'id': credential.use_role.id
|
'id': credential.use_role.id
|
||||||
}, admin)
|
}, admin)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
@ -305,7 +305,7 @@ def test_credential_detail(post, get, organization, org_admin):
|
|||||||
'organization': organization.id,
|
'organization': organization.id,
|
||||||
}, org_admin)
|
}, org_admin)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
response = get(reverse('api:credential_detail', args=(response.data['id'],)), org_admin)
|
response = get(reverse('api:credential_detail', kwargs={'pk': response.data['id']}), org_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
summary_fields = response.data['summary_fields']
|
summary_fields = response.data['summary_fields']
|
||||||
assert 'organization' in summary_fields
|
assert 'organization' in summary_fields
|
||||||
@ -330,11 +330,11 @@ def test_list_created_org_credentials(post, get, organization, org_admin, org_me
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 0
|
assert response.data['count'] == 0
|
||||||
|
|
||||||
response = get(reverse('api:organization_credential_list', args=(organization.pk,)), org_admin)
|
response = get(reverse('api:organization_credential_list', kwargs={'pk': organization.pk}), org_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
|
|
||||||
response = get(reverse('api:organization_credential_list', args=(organization.pk,)), org_member)
|
response = get(reverse('api:organization_credential_list', kwargs={'pk': organization.pk}), org_member)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 0
|
assert response.data['count'] == 0
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,11 @@ import urlparse
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.fact import Fact
|
from awx.main.models.fact import Fact
|
||||||
from awx.main.utils import timestamp_apiformat
|
from awx.main.utils import timestamp_apiformat
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ def setup_common(hosts, fact_scans, get, user, epoch=timezone.now(), get_params=
|
|||||||
hosts = hosts(host_count=host_count)
|
hosts = hosts(host_count=host_count)
|
||||||
fact_scans(fact_scans=3, timestamp_epoch=epoch)
|
fact_scans(fact_scans=3, timestamp_epoch=epoch)
|
||||||
|
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True), data=get_params)
|
response = get(url, user('admin', True), data=get_params)
|
||||||
|
|
||||||
return (hosts[0], response)
|
return (hosts[0], response)
|
||||||
@ -37,7 +37,7 @@ def check_url(url1_full, fact_known, module):
|
|||||||
url1 = url1_split.path
|
url1 = url1_split.path
|
||||||
url1_params = urlparse.parse_qsl(url1_split.query)
|
url1_params = urlparse.parse_qsl(url1_split.query)
|
||||||
|
|
||||||
url2 = reverse('api:host_fact_compare_view', args=(fact_known.host.pk,))
|
url2 = reverse('api:host_fact_compare_view', kwargs={'pk': fact_known.host.pk})
|
||||||
url2_params = [('module', module), ('datetime', timestamp_apiformat(fact_known.timestamp))]
|
url2_params = [('module', module), ('datetime', timestamp_apiformat(fact_known.timestamp))]
|
||||||
|
|
||||||
assert url1 == url2
|
assert url1 == url2
|
||||||
@ -64,7 +64,7 @@ def check_system_tracking_feature_forbidden(response):
|
|||||||
@pytest.mark.license_feature
|
@pytest.mark.license_feature
|
||||||
def test_system_tracking_license_get(hosts, get, user):
|
def test_system_tracking_license_get(hosts, get, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
check_system_tracking_feature_forbidden(response)
|
check_system_tracking_feature_forbidden(response)
|
||||||
@ -75,7 +75,7 @@ def test_system_tracking_license_get(hosts, get, user):
|
|||||||
@pytest.mark.license_feature
|
@pytest.mark.license_feature
|
||||||
def test_system_tracking_license_options(hosts, options, user):
|
def test_system_tracking_license_options(hosts, options, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = options(url, None, user('admin', True))
|
response = options(url, None, user('admin', True))
|
||||||
|
|
||||||
check_system_tracking_feature_forbidden(response)
|
check_system_tracking_feature_forbidden(response)
|
||||||
@ -86,7 +86,7 @@ def test_system_tracking_license_options(hosts, options, user):
|
|||||||
@pytest.mark.license_feature
|
@pytest.mark.license_feature
|
||||||
def test_no_facts_db(hosts, get, user):
|
def test_no_facts_db(hosts, get, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
response_expected = {
|
response_expected = {
|
||||||
@ -119,7 +119,7 @@ def test_basic_options_fields(hosts, fact_scans, options, user, monkeypatch_json
|
|||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
fact_scans(fact_scans=1)
|
fact_scans(fact_scans=1)
|
||||||
|
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = options(url, None, user('admin', True), pk=hosts[0].id)
|
response = options(url, None, user('admin', True), pk=hosts[0].id)
|
||||||
|
|
||||||
assert 'related' in response.data['actions']['GET']
|
assert 'related' in response.data['actions']['GET']
|
||||||
@ -228,7 +228,7 @@ def _test_user_access_control(hosts, fact_scans, get, user_obj, team_obj):
|
|||||||
|
|
||||||
team_obj.member_role.members.add(user_obj)
|
team_obj.member_role.members.add(user_obj)
|
||||||
|
|
||||||
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user_obj)
|
response = get(url, user_obj)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import mock
|
|||||||
import pytest
|
import pytest
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.utils import timestamp_apiformat
|
from awx.main.utils import timestamp_apiformat
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ def setup_common(hosts, fact_scans, get, user, epoch=timezone.now(), module_name
|
|||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
facts = fact_scans(fact_scans=1, timestamp_epoch=epoch)
|
facts = fact_scans(fact_scans=1, timestamp_epoch=epoch)
|
||||||
|
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True), data=get_params)
|
response = get(url, user('admin', True), data=get_params)
|
||||||
|
|
||||||
fact_known = find_fact(facts, hosts[0].id, module_name, epoch)
|
fact_known = find_fact(facts, hosts[0].id, module_name, epoch)
|
||||||
@ -44,7 +44,7 @@ def check_system_tracking_feature_forbidden(response):
|
|||||||
@pytest.mark.license_feature
|
@pytest.mark.license_feature
|
||||||
def test_system_tracking_license_get(hosts, get, user):
|
def test_system_tracking_license_get(hosts, get, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
check_system_tracking_feature_forbidden(response)
|
check_system_tracking_feature_forbidden(response)
|
||||||
@ -55,7 +55,7 @@ def test_system_tracking_license_get(hosts, get, user):
|
|||||||
@pytest.mark.license_feature
|
@pytest.mark.license_feature
|
||||||
def test_system_tracking_license_options(hosts, options, user):
|
def test_system_tracking_license_options(hosts, options, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = options(url, None, user('admin', True))
|
response = options(url, None, user('admin', True))
|
||||||
|
|
||||||
check_system_tracking_feature_forbidden(response)
|
check_system_tracking_feature_forbidden(response)
|
||||||
@ -65,7 +65,7 @@ def test_system_tracking_license_options(hosts, options, user):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_no_fact_found(hosts, get, user):
|
def test_no_fact_found(hosts, get, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
expected_response = {
|
expected_response = {
|
||||||
@ -81,7 +81,7 @@ def test_basic_fields(hosts, fact_scans, get, user, monkeypatch_jsonbfield_get_d
|
|||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
fact_scans(fact_scans=1)
|
fact_scans(fact_scans=1)
|
||||||
|
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
assert 'related' in response.data
|
assert 'related' in response.data
|
||||||
@ -95,7 +95,7 @@ def test_basic_fields(hosts, fact_scans, get, user, monkeypatch_jsonbfield_get_d
|
|||||||
assert 'name' in response.data['summary_fields']['host']
|
assert 'name' in response.data['summary_fields']['host']
|
||||||
assert 'description' in response.data['summary_fields']['host']
|
assert 'description' in response.data['summary_fields']['host']
|
||||||
assert 'host' in response.data['related']
|
assert 'host' in response.data['related']
|
||||||
assert reverse('api:host_detail', args=(hosts[0].pk,)) == response.data['related']['host']
|
assert reverse('api:host_detail', kwargs={'pk': hosts[0].pk}) == response.data['related']['host']
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('awx.api.views.feature_enabled', new=mock_feature_enabled)
|
@mock.patch('awx.api.views.feature_enabled', new=mock_feature_enabled)
|
||||||
@ -149,7 +149,7 @@ def _test_user_access_control(hosts, fact_scans, get, user_obj, team_obj):
|
|||||||
|
|
||||||
team_obj.member_role.members.add(user_obj)
|
team_obj.member_role.members.add(user_obj)
|
||||||
|
|
||||||
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
|
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user_obj)
|
response = get(url, user_obj)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,17 @@
|
|||||||
# Other host tests should live here to make this test suite more complete.
|
# Other host tests should live here to make this test suite more complete.
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_basic_fields(hosts, fact_scans, get, user):
|
def test_basic_fields(hosts, fact_scans, get, user):
|
||||||
hosts = hosts(host_count=1)
|
hosts = hosts(host_count=1)
|
||||||
|
|
||||||
url = reverse('api:host_detail', args=(hosts[0].pk,))
|
url = reverse('api:host_detail', kwargs={'pk': hosts[0].pk})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
|
|
||||||
assert 'related' in response.data
|
assert 'related' in response.data
|
||||||
assert 'fact_versions' in response.data['related']
|
assert 'fact_versions' in response.data['related']
|
||||||
assert reverse('api:host_fact_versions_list', args=(hosts[0].pk,)) == response.data['related']['fact_versions']
|
assert reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk}) == response.data['related']['fact_versions']
|
||||||
|
|
||||||
|
|||||||
49
awx/main/tests/functional/api/test_host_filter.py
Normal file
49
awx/main/tests/functional/api/test_host_filter.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# TODO: As of writing this our only concern is ensuring that the fact feature is reflected in the Host endpoint.
|
||||||
|
# Other host tests should live here to make this test suite more complete.
|
||||||
|
import pytest
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
from awx.main.models import Organization, Host, Group, Inventory
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def inventory_structure():
|
||||||
|
org = Organization.objects.create(name="org")
|
||||||
|
inv = Inventory.objects.create(name="inv", organization=org)
|
||||||
|
Host.objects.create(name="host1", inventory=inv)
|
||||||
|
Host.objects.create(name="host2", inventory=inv)
|
||||||
|
Host.objects.create(name="host3", inventory=inv)
|
||||||
|
Group.objects.create(name="g1", inventory=inv)
|
||||||
|
Group.objects.create(name="g2", inventory=inv)
|
||||||
|
Group.objects.create(name="g3", inventory=inv)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_q1(inventory_structure, get, user):
|
||||||
|
def evaluate_query(query, expected_hosts):
|
||||||
|
url = reverse('api:host_list')
|
||||||
|
get_params = "?host_filter=%s" % urllib.quote(query, safe='')
|
||||||
|
response = get(url + get_params, user('admin', True))
|
||||||
|
|
||||||
|
hosts = response.data['results']
|
||||||
|
|
||||||
|
assert len(expected_hosts) == len(hosts)
|
||||||
|
|
||||||
|
host_ids = [host['id'] for host in hosts]
|
||||||
|
for i, expected_host in enumerate(expected_hosts):
|
||||||
|
assert expected_host.id in host_ids
|
||||||
|
|
||||||
|
hosts = Host.objects.all()
|
||||||
|
groups = Group.objects.all()
|
||||||
|
|
||||||
|
groups[0].hosts.add(hosts[0], hosts[1])
|
||||||
|
groups[1].hosts.add(hosts[0], hosts[1], hosts[2])
|
||||||
|
|
||||||
|
query = '(name="host1" and groups__name="g1")'
|
||||||
|
evaluate_query(query, [hosts[0]])
|
||||||
|
|
||||||
|
query = '(name="host1" and groups__name="g1") or (name="host3" and groups__name="g2")'
|
||||||
|
evaluate_query(query, [hosts[0], hosts[2]])
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -12,10 +12,10 @@ def test_inventory_source_notification_on_cloud_only(get, post, group_factory, u
|
|||||||
not_is = g_not.inventory_source
|
not_is = g_not.inventory_source
|
||||||
cloud_is.source = 'ec2'
|
cloud_is.source = 'ec2'
|
||||||
cloud_is.save()
|
cloud_is.save()
|
||||||
url = reverse('api:inventory_source_notification_templates_any_list', args=(cloud_is.id,))
|
url = reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': cloud_is.id})
|
||||||
response = post(url, dict(id=notification_template.id), u)
|
response = post(url, dict(id=notification_template.id), u)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
url = reverse('api:inventory_source_notification_templates_success_list', args=(not_is.id,))
|
url = reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': not_is.id})
|
||||||
response = post(url, dict(id=notification_template.id), u)
|
response = post(url, dict(id=notification_template.id), u)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ def test_edit_inventory(put, inventory, alice, role_field, expected_status_code)
|
|||||||
data = { 'organization': inventory.organization.id, 'name': 'New name', 'description': 'Hello world', }
|
data = { 'organization': inventory.organization.id, 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(inventory, role_field).members.add(alice)
|
getattr(inventory, role_field).members.add(alice)
|
||||||
put(reverse('api:inventory_detail', args=(inventory.id,)), data, alice, expect=expected_status_code)
|
put(reverse('api:inventory_detail', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('order_by', ('script', '-script', 'script,pk', '-script,pk'))
|
@pytest.mark.parametrize('order_by', ('script', '-script', 'script,pk', '-script,pk'))
|
||||||
@ -62,7 +62,7 @@ def test_create_inventory_group(post, inventory, alice, role_field, expected_sta
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(inventory, role_field).members.add(alice)
|
getattr(inventory, role_field).members.add(alice)
|
||||||
post(reverse('api:inventory_groups_list', args=(inventory.id,)), data, alice, expect=expected_status_code)
|
post(reverse('api:inventory_groups_list', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -77,7 +77,7 @@ def test_create_inventory_group_child(post, group, alice, role_field, expected_s
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(group.inventory, role_field).members.add(alice)
|
getattr(group.inventory, role_field).members.add(alice)
|
||||||
post(reverse('api:group_children_list', args=(group.id,)), data, alice, expect=expected_status_code)
|
post(reverse('api:group_children_list', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -92,7 +92,7 @@ def test_edit_inventory_group(put, group, alice, role_field, expected_status_cod
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(group.inventory, role_field).members.add(alice)
|
getattr(group.inventory, role_field).members.add(alice)
|
||||||
put(reverse('api:group_detail', args=(group.id,)), data, alice, expect=expected_status_code)
|
put(reverse('api:group_detail', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -106,7 +106,7 @@ def test_edit_inventory_group(put, group, alice, role_field, expected_status_cod
|
|||||||
def test_delete_inventory_group(delete, group, alice, role_field, expected_status_code):
|
def test_delete_inventory_group(delete, group, alice, role_field, expected_status_code):
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(group.inventory, role_field).members.add(alice)
|
getattr(group.inventory, role_field).members.add(alice)
|
||||||
delete(reverse('api:group_detail', args=(group.id,)), alice, expect=expected_status_code)
|
delete(reverse('api:group_detail', kwargs={'pk': group.id}), alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -121,7 +121,7 @@ def test_create_inventory_host(post, inventory, alice, role_field, expected_stat
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(inventory, role_field).members.add(alice)
|
getattr(inventory, role_field).members.add(alice)
|
||||||
post(reverse('api:inventory_hosts_list', args=(inventory.id,)), data, alice, expect=expected_status_code)
|
post(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -136,7 +136,7 @@ def test_create_inventory_group_host(post, group, alice, role_field, expected_st
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(group.inventory, role_field).members.add(alice)
|
getattr(group.inventory, role_field).members.add(alice)
|
||||||
post(reverse('api:group_hosts_list', args=(group.id,)), data, alice, expect=expected_status_code)
|
post(reverse('api:group_hosts_list', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -151,7 +151,7 @@ def test_edit_inventory_host(put, host, alice, role_field, expected_status_code)
|
|||||||
data = { 'name': 'New name', 'description': 'Hello world', }
|
data = { 'name': 'New name', 'description': 'Hello world', }
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(host.inventory, role_field).members.add(alice)
|
getattr(host.inventory, role_field).members.add(alice)
|
||||||
put(reverse('api:host_detail', args=(host.id,)), data, alice, expect=expected_status_code)
|
put(reverse('api:host_detail', kwargs={'pk': host.id}), data, alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -165,7 +165,7 @@ def test_edit_inventory_host(put, host, alice, role_field, expected_status_code)
|
|||||||
def test_delete_inventory_host(delete, host, alice, role_field, expected_status_code):
|
def test_delete_inventory_host(delete, host, alice, role_field, expected_status_code):
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(host.inventory, role_field).members.add(alice)
|
getattr(host.inventory, role_field).members.add(alice)
|
||||||
delete(reverse('api:host_detail', args=(host.id,)), alice, expect=expected_status_code)
|
delete(reverse('api:host_detail', kwargs={'pk': host.id}), alice, expect=expected_status_code)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("role_field,expected_status_code", [
|
@pytest.mark.parametrize("role_field,expected_status_code", [
|
||||||
@ -179,4 +179,4 @@ def test_delete_inventory_host(delete, host, alice, role_field, expected_status_
|
|||||||
def test_inventory_source_update(post, inventory_source, alice, role_field, expected_status_code):
|
def test_inventory_source_update(post, inventory_source, alice, role_field, expected_status_code):
|
||||||
if role_field:
|
if role_field:
|
||||||
getattr(inventory_source.group.inventory, role_field).members.add(alice)
|
getattr(inventory_source.group.inventory, role_field).members.add(alice)
|
||||||
post(reverse('api:inventory_source_update_view', args=(inventory_source.id,)), {}, alice, expect=expected_status_code)
|
post(reverse('api:inventory_source_update_view', kwargs={'pk': inventory_source.id}), {}, alice, expect=expected_status_code)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from awx.main.models.credential import Credential
|
|||||||
from awx.main.models.inventory import Inventory
|
from awx.main.models.inventory import Inventory
|
||||||
from awx.main.models.jobs import Job, JobTemplate
|
from awx.main.models.jobs import Job, JobTemplate
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -85,7 +85,7 @@ def test_job_ignore_unprompted_vars(runtime_data, job_template_prompts, post, ad
|
|||||||
|
|
||||||
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
runtime_data, admin_user, expect=201)
|
runtime_data, admin_user, expect=201)
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
assert JobTemplate.create_unified_job.call_args == ({'extra_vars':{}},)
|
assert JobTemplate.create_unified_job.call_args == ({'extra_vars':{}},)
|
||||||
@ -116,7 +116,7 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, admi
|
|||||||
|
|
||||||
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
runtime_data, admin_user, expect=201)
|
runtime_data, admin_user, expect=201)
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
|
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
|
||||||
@ -136,7 +136,7 @@ def test_job_accept_null_tags(job_template_prompts, post, admin_user, mocker):
|
|||||||
|
|
||||||
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
||||||
post(reverse('api:job_template_launch', args=[job_template.pk]),
|
post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}),
|
||||||
{'job_tags': '', 'skip_tags': ''}, admin_user, expect=201)
|
{'job_tags': '', 'skip_tags': ''}, admin_user, expect=201)
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
assert JobTemplate.create_unified_job.call_args == ({'job_tags':'', 'skip_tags':''},)
|
assert JobTemplate.create_unified_job.call_args == ({'job_tags':'', 'skip_tags':''},)
|
||||||
@ -162,7 +162,7 @@ def test_job_accept_prompted_vars_null(runtime_data, job_template_prompts_null,
|
|||||||
|
|
||||||
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}),
|
||||||
runtime_data, rando, expect=201)
|
runtime_data, rando, expect=201)
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
|
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
|
||||||
@ -178,7 +178,7 @@ def test_job_reject_invalid_prompted_vars(runtime_data, job_template_prompts, po
|
|||||||
job_template = job_template_prompts(True)
|
job_template = job_template_prompts(True)
|
||||||
|
|
||||||
response = post(
|
response = post(
|
||||||
reverse('api:job_template_launch', args=[job_template.pk]),
|
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(job_type='foobicate', # foobicate is not a valid job type
|
dict(job_type='foobicate', # foobicate is not a valid job type
|
||||||
inventory=87865, credential=48474), admin_user, expect=400)
|
inventory=87865, credential=48474), admin_user, expect=400)
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ def test_job_reject_invalid_prompted_extra_vars(runtime_data, job_template_promp
|
|||||||
job_template = job_template_prompts(True)
|
job_template = job_template_prompts(True)
|
||||||
|
|
||||||
response = post(
|
response = post(
|
||||||
reverse('api:job_template_launch', args=[job_template.pk]),
|
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(extra_vars='{"unbalanced brackets":'), admin_user, expect=400)
|
dict(extra_vars='{"unbalanced brackets":'), admin_user, expect=400)
|
||||||
|
|
||||||
assert 'extra_vars' in response.data
|
assert 'extra_vars' in response.data
|
||||||
@ -207,7 +207,7 @@ def test_job_launch_fails_without_inventory(deploy_jobtemplate, post, admin_user
|
|||||||
deploy_jobtemplate.save()
|
deploy_jobtemplate.save()
|
||||||
|
|
||||||
response = post(reverse('api:job_template_launch',
|
response = post(reverse('api:job_template_launch',
|
||||||
args=[deploy_jobtemplate.pk]), {}, admin_user, expect=400)
|
kwargs={'pk': deploy_jobtemplate.pk}), {}, admin_user, expect=400)
|
||||||
|
|
||||||
assert response.data['inventory'] == ["Job Template 'inventory' is missing or undefined."]
|
assert response.data['inventory'] == ["Job Template 'inventory' is missing or undefined."]
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ def test_job_launch_fails_without_inventory_access(job_template_prompts, runtime
|
|||||||
job_template.execute_role.members.add(rando)
|
job_template.execute_role.members.add(rando)
|
||||||
|
|
||||||
# Assure that giving an inventory without access to the inventory blocks the launch
|
# Assure that giving an inventory without access to the inventory blocks the launch
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(inventory=runtime_data['inventory']), rando, expect=403)
|
dict(inventory=runtime_data['inventory']), rando, expect=403)
|
||||||
|
|
||||||
assert response.data['detail'] == u'You do not have permission to perform this action.'
|
assert response.data['detail'] == u'You do not have permission to perform this action.'
|
||||||
@ -232,7 +232,7 @@ def test_job_launch_fails_without_credential_access(job_template_prompts, runtim
|
|||||||
job_template.execute_role.members.add(rando)
|
job_template.execute_role.members.add(rando)
|
||||||
|
|
||||||
# Assure that giving a credential without access blocks the launch
|
# Assure that giving a credential without access blocks the launch
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(credential=runtime_data['credential']), rando, expect=403)
|
dict(credential=runtime_data['credential']), rando, expect=403)
|
||||||
|
|
||||||
assert response.data['detail'] == u'You do not have permission to perform this action.'
|
assert response.data['detail'] == u'You do not have permission to perform this action.'
|
||||||
@ -244,7 +244,7 @@ def test_job_block_scan_job_type_change(job_template_prompts, post, admin_user):
|
|||||||
job_template = job_template_prompts(True)
|
job_template = job_template_prompts(True)
|
||||||
|
|
||||||
# Assure that changing the type of a scan job blocks the launch
|
# Assure that changing the type of a scan job blocks the launch
|
||||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(job_type='scan'), admin_user, expect=400)
|
dict(job_type='scan'), admin_user, expect=400)
|
||||||
|
|
||||||
assert 'job_type' in response.data
|
assert 'job_type' in response.data
|
||||||
@ -255,7 +255,7 @@ def test_job_block_scan_job_type_change(job_template_prompts, post, admin_user):
|
|||||||
def test_job_block_scan_job_inv_change(mocker, bad_scan_JT, runtime_data, post, admin_user):
|
def test_job_block_scan_job_inv_change(mocker, bad_scan_JT, runtime_data, post, admin_user):
|
||||||
# Assure that giving a new inventory for a scan job blocks the launch
|
# Assure that giving a new inventory for a scan job blocks the launch
|
||||||
with mocker.patch('awx.main.access.BaseAccess.check_license'):
|
with mocker.patch('awx.main.access.BaseAccess.check_license'):
|
||||||
response = post(reverse('api:job_template_launch', args=[bad_scan_JT.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk': bad_scan_JT.pk}),
|
||||||
dict(inventory=runtime_data['inventory']), admin_user,
|
dict(inventory=runtime_data['inventory']), admin_user,
|
||||||
expect=400)
|
expect=400)
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ def test_job_launch_unprompted_vars_with_survey(mocker, survey_spec_factory, job
|
|||||||
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
|
||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
||||||
response = post(
|
response = post(
|
||||||
reverse('api:job_template_launch', args=[job_template.pk]),
|
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
|
||||||
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}),
|
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}),
|
||||||
admin_user, expect=201)
|
admin_user, expect=201)
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
@ -362,7 +362,7 @@ def test_callback_accept_prompted_extra_var(mocker, survey_spec_factory, job_tem
|
|||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
||||||
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
|
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
|
||||||
post(
|
post(
|
||||||
reverse('api:job_template_callback', args=[job_template.pk]),
|
reverse('api:job_template_callback', kwargs={'pk': job_template.pk}),
|
||||||
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
|
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
|
||||||
admin_user, expect=201, format='json')
|
admin_user, expect=201, format='json')
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
@ -387,7 +387,7 @@ def test_callback_ignore_unprompted_extra_var(mocker, survey_spec_factory, job_t
|
|||||||
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
|
||||||
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
|
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
|
||||||
post(
|
post(
|
||||||
reverse('api:job_template_callback', args=[job_template.pk]),
|
reverse('api:job_template_callback', kwargs={'pk':job_template.pk}),
|
||||||
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
|
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
|
||||||
admin_user, expect=201, format='json')
|
admin_user, expect=201, format='json')
|
||||||
assert JobTemplate.create_unified_job.called
|
assert JobTemplate.create_unified_job.called
|
||||||
|
|||||||
@ -2,11 +2,11 @@ import pytest
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.api.serializers import JobTemplateSerializer, JobLaunchSerializer
|
from awx.api.serializers import JobTemplateSerializer, JobLaunchSerializer
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.jobs import Job
|
from awx.main.models.jobs import Job
|
||||||
from awx.main.migrations import _save_password_keys as save_password_keys
|
from awx.main.migrations import _save_password_keys as save_password_keys
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ def test_edit_sensitive_fields(patch, job_template_factory, alice, grant_project
|
|||||||
if grant_inventory:
|
if grant_inventory:
|
||||||
objs.inventory.use_role.members.add(alice)
|
objs.inventory.use_role.members.add(alice)
|
||||||
|
|
||||||
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
|
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
|
||||||
'name': 'Some name',
|
'name': 'Some name',
|
||||||
'project': objs.project.id,
|
'project': objs.project.id,
|
||||||
'credential': objs.credential.id,
|
'credential': objs.credential.id,
|
||||||
@ -72,7 +72,7 @@ def test_reject_dict_extra_vars_patch(patch, job_template_factory, admin_user):
|
|||||||
jt = job_template_factory(
|
jt = job_template_factory(
|
||||||
'jt', organization='org1', project='prj', inventory='inv', credential='cred'
|
'jt', organization='org1', project='prj', inventory='inv', credential='cred'
|
||||||
).job_template
|
).job_template
|
||||||
patch(reverse('api:job_template_detail', args=(jt.id,)),
|
patch(reverse('api:job_template_detail', kwargs={'pk': jt.id}),
|
||||||
{'extra_vars': {'foo': 5}}, admin_user, expect=400)
|
{'extra_vars': {'foo': 5}}, admin_user, expect=400)
|
||||||
|
|
||||||
|
|
||||||
@ -84,12 +84,12 @@ def test_edit_playbook(patch, job_template_factory, alice):
|
|||||||
objs.credential.use_role.members.add(alice)
|
objs.credential.use_role.members.add(alice)
|
||||||
objs.inventory.use_role.members.add(alice)
|
objs.inventory.use_role.members.add(alice)
|
||||||
|
|
||||||
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
|
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
|
||||||
'playbook': 'alt-helloworld.yml',
|
'playbook': 'alt-helloworld.yml',
|
||||||
}, alice, expect=200)
|
}, alice, expect=200)
|
||||||
|
|
||||||
objs.inventory.use_role.members.remove(alice)
|
objs.inventory.use_role.members.remove(alice)
|
||||||
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
|
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
|
||||||
'playbook': 'helloworld.yml',
|
'playbook': 'helloworld.yml',
|
||||||
}, alice, expect=403)
|
}, alice, expect=403)
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ def test_invalid_json_body(patch, job_template_factory, alice, json_body):
|
|||||||
objs = job_template_factory('jt', organization='org1')
|
objs = job_template_factory('jt', organization='org1')
|
||||||
objs.job_template.admin_role.members.add(alice)
|
objs.job_template.admin_role.members.add(alice)
|
||||||
resp = patch(
|
resp = patch(
|
||||||
reverse('api:job_template_detail', args=(objs.job_template.id,)),
|
reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}),
|
||||||
json_body,
|
json_body,
|
||||||
alice,
|
alice,
|
||||||
expect=400
|
expect=400
|
||||||
@ -117,7 +117,7 @@ def test_edit_nonsenstive(patch, job_template_factory, alice):
|
|||||||
jt = objs.job_template
|
jt = objs.job_template
|
||||||
jt.admin_role.members.add(alice)
|
jt.admin_role.members.add(alice)
|
||||||
|
|
||||||
res = patch(reverse('api:job_template_detail', args=(jt.id,)), {
|
res = patch(reverse('api:job_template_detail', kwargs={'pk': jt.id}), {
|
||||||
'name': 'updated',
|
'name': 'updated',
|
||||||
'description': 'bar',
|
'description': 'bar',
|
||||||
'forks': 14,
|
'forks': 14,
|
||||||
@ -157,7 +157,7 @@ def test_job_template_role_user(post, organization_factory, job_template_factory
|
|||||||
inventory='test_inv',
|
inventory='test_inv',
|
||||||
project='test_proj')
|
project='test_proj')
|
||||||
|
|
||||||
url = reverse('api:user_roles_list', args=(objects.users.test.pk,))
|
url = reverse('api:user_roles_list', kwargs={'pk': objects.users.test.pk})
|
||||||
response = post(url, dict(id=jt_objects.job_template.execute_role.pk), objects.superusers.admin)
|
response = post(url, dict(id=jt_objects.job_template.execute_role.pk), objects.superusers.admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
@ -168,12 +168,12 @@ def test_jt_admin_copy_edit_functional(jt_copy_edit, rando, get, post):
|
|||||||
jt_copy_edit.admin_role.members.add(rando)
|
jt_copy_edit.admin_role.members.add(rando)
|
||||||
jt_copy_edit.save()
|
jt_copy_edit.save()
|
||||||
|
|
||||||
get_response = get(reverse('api:job_template_detail', args=[jt_copy_edit.pk]), user=rando)
|
get_response = get(reverse('api:job_template_detail', kwargs={'pk':jt_copy_edit.pk}), user=rando)
|
||||||
assert get_response.status_code == 200
|
assert get_response.status_code == 200
|
||||||
|
|
||||||
post_data = get_response.data
|
post_data = get_response.data
|
||||||
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
|
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
|
||||||
post_response = post(reverse('api:job_template_list', args=[]), user=rando, data=post_data)
|
post_response = post(reverse('api:job_template_list'), user=rando, data=post_data)
|
||||||
assert post_response.status_code == 403
|
assert post_response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ def test_disallow_template_delete_on_running_job(job_template_factory, delete, a
|
|||||||
inventory='i',
|
inventory='i',
|
||||||
organization='o')
|
organization='o')
|
||||||
objects.job_template.create_unified_job()
|
objects.job_template.create_unified_job()
|
||||||
delete_response = delete(reverse('api:job_template_detail', args=[objects.job_template.pk]), user=admin_user)
|
delete_response = delete(reverse('api:job_template_detail', kwargs={'pk': objects.job_template.pk}), user=admin_user)
|
||||||
assert delete_response.status_code == 409
|
assert delete_response.status_code == 409
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -70,7 +70,7 @@ def test_org_counts_detail_admin(resourced_organization, user, get):
|
|||||||
# Check that all types of resources are counted by a superuser
|
# Check that all types of resources are counted by a superuser
|
||||||
external_admin = user('admin', True)
|
external_admin = user('admin', True)
|
||||||
response = get(reverse('api:organization_detail',
|
response = get(reverse('api:organization_detail',
|
||||||
args=[resourced_organization.pk]), external_admin)
|
kwargs={'pk': resourced_organization.pk}), external_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
counts = response.data['summary_fields']['related_field_counts']
|
counts = response.data['summary_fields']['related_field_counts']
|
||||||
@ -82,7 +82,7 @@ def test_org_counts_detail_member(resourced_organization, user, get):
|
|||||||
# Check that a non-admin org member can only see users / admin in detail view
|
# Check that a non-admin org member can only see users / admin in detail view
|
||||||
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
||||||
response = get(reverse('api:organization_detail',
|
response = get(reverse('api:organization_detail',
|
||||||
args=[resourced_organization.pk]), member_user)
|
kwargs={'pk': resourced_organization.pk}), member_user)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
counts = response.data['summary_fields']['related_field_counts']
|
counts = response.data['summary_fields']['related_field_counts']
|
||||||
@ -100,7 +100,7 @@ def test_org_counts_detail_member(resourced_organization, user, get):
|
|||||||
def test_org_counts_list_admin(resourced_organization, user, get):
|
def test_org_counts_list_admin(resourced_organization, user, get):
|
||||||
# Check that all types of resources are counted by a superuser
|
# Check that all types of resources are counted by a superuser
|
||||||
external_admin = user('admin', True)
|
external_admin = user('admin', True)
|
||||||
response = get(reverse('api:organization_list', args=[]), external_admin)
|
response = get(reverse('api:organization_list'), external_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
||||||
@ -112,7 +112,7 @@ def test_org_counts_list_member(resourced_organization, user, get):
|
|||||||
# Check that a non-admin user can only see the full project and
|
# Check that a non-admin user can only see the full project and
|
||||||
# user count, consistent with the RBAC rules
|
# user count, consistent with the RBAC rules
|
||||||
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
||||||
response = get(reverse('api:organization_list', args=[]), member_user)
|
response = get(reverse('api:organization_list'), member_user)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
||||||
@ -131,7 +131,7 @@ def test_org_counts_list_member(resourced_organization, user, get):
|
|||||||
def test_new_org_zero_counts(user, post):
|
def test_new_org_zero_counts(user, post):
|
||||||
# Check that a POST to the organization list endpoint returns
|
# Check that a POST to the organization list endpoint returns
|
||||||
# correct counts, including the new record
|
# correct counts, including the new record
|
||||||
org_list_url = reverse('api:organization_list', args=[])
|
org_list_url = reverse('api:organization_list')
|
||||||
post_response = post(url=org_list_url, data={'name': 'test organization',
|
post_response = post(url=org_list_url, data={'name': 'test organization',
|
||||||
'description': ''}, user=user('admin', True))
|
'description': ''}, user=user('admin', True))
|
||||||
assert post_response.status_code == 201
|
assert post_response.status_code == 201
|
||||||
@ -146,7 +146,7 @@ def test_two_organizations(resourced_organization, organizations, user, get):
|
|||||||
# Check correct results for two organizations are returned
|
# Check correct results for two organizations are returned
|
||||||
external_admin = user('admin', True)
|
external_admin = user('admin', True)
|
||||||
organization_zero = organizations(1)[0]
|
organization_zero = organizations(1)[0]
|
||||||
response = get(reverse('api:organization_list', args=[]), external_admin)
|
response = get(reverse('api:organization_list'), external_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
org_id_full = resourced_organization.id
|
org_id_full = resourced_organization.id
|
||||||
@ -171,12 +171,12 @@ def test_scan_JT_counted(resourced_organization, user, get):
|
|||||||
counts_dict['job_templates'] += 1
|
counts_dict['job_templates'] += 1
|
||||||
|
|
||||||
# Test list view
|
# Test list view
|
||||||
list_response = get(reverse('api:organization_list', args=[]), admin_user)
|
list_response = get(reverse('api:organization_list'), admin_user)
|
||||||
assert list_response.status_code == 200
|
assert list_response.status_code == 200
|
||||||
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
|
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
|
||||||
|
|
||||||
# Test detail view
|
# Test detail view
|
||||||
detail_response = get(reverse('api:organization_detail', args=[resourced_organization.pk]), admin_user)
|
detail_response = get(reverse('api:organization_detail', kwargs={'pk': resourced_organization.pk}), admin_user)
|
||||||
assert detail_response.status_code == 200
|
assert detail_response.status_code == 200
|
||||||
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
|
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
|
||||||
|
|
||||||
@ -194,12 +194,12 @@ def test_JT_not_double_counted(resourced_organization, user, get):
|
|||||||
counts_dict['job_templates'] += 1
|
counts_dict['job_templates'] += 1
|
||||||
|
|
||||||
# Test list view
|
# Test list view
|
||||||
list_response = get(reverse('api:organization_list', args=[]), admin_user)
|
list_response = get(reverse('api:organization_list'), admin_user)
|
||||||
assert list_response.status_code == 200
|
assert list_response.status_code == 200
|
||||||
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
|
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
|
||||||
|
|
||||||
# Test detail view
|
# Test detail view
|
||||||
detail_response = get(reverse('api:organization_detail', args=[resourced_organization.pk]), admin_user)
|
detail_response = get(reverse('api:organization_detail', kwargs={'pk': resourced_organization.pk}), admin_user)
|
||||||
assert detail_response.status_code == 200
|
assert detail_response.status_code == 200
|
||||||
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
|
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ def test_JT_associated_with_project(organizations, project, user, get):
|
|||||||
inventory=unrelated_inv,
|
inventory=unrelated_inv,
|
||||||
playbook="test_playbook.yml")
|
playbook="test_playbook.yml")
|
||||||
|
|
||||||
response = get(reverse('api:organization_list', args=[]), external_admin)
|
response = get(reverse('api:organization_list'), external_admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
org_id = organization.id
|
org_id = organization.id
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import mock
|
|||||||
|
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
@ -29,10 +29,10 @@ def test_organization_list_access_tests(options, head, get, admin, alice):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_organization_access_tests(organization, get, admin, alice, bob):
|
def test_organization_access_tests(organization, get, admin, alice, bob):
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
get(reverse('api:organization_detail', args=(organization.id,)), user=admin, expect=200)
|
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=admin, expect=200)
|
||||||
get(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=200)
|
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=200)
|
||||||
get(reverse('api:organization_detail', args=(organization.id,)), user=bob, expect=403)
|
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=bob, expect=403)
|
||||||
get(reverse('api:organization_detail', args=(organization.id,)), user=None, expect=401)
|
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=None, expect=401)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -68,9 +68,9 @@ def test_organization_project_list(organization, project_factory, get, alice, bo
|
|||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
organization.member_role.members.add(bob)
|
organization.member_role.members.add(bob)
|
||||||
prj1.use_role.members.add(bob)
|
prj1.use_role.members.add(bob)
|
||||||
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=alice).data['count'] == 2
|
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
|
||||||
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=bob).data['count'] == 1
|
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
|
||||||
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=rando).status_code == 403
|
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=rando).status_code == 403
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -78,12 +78,12 @@ def test_organization_user_list(organization, get, admin, alice, bob):
|
|||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
organization.member_role.members.add(bob)
|
organization.member_role.members.add(bob)
|
||||||
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=admin).data['count'] == 2
|
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=admin).data['count'] == 2
|
||||||
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=alice).data['count'] == 2
|
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
|
||||||
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=bob).data['count'] == 2
|
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 2
|
||||||
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=admin).data['count'] == 1
|
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=admin).data['count'] == 1
|
||||||
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=alice).data['count'] == 1
|
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 1
|
||||||
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=bob).data['count'] == 1
|
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -93,9 +93,9 @@ def test_organization_inventory_list(organization, inventory_factory, get, alice
|
|||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
organization.member_role.members.add(bob)
|
organization.member_role.members.add(bob)
|
||||||
inv1.use_role.members.add(bob)
|
inv1.use_role.members.add(bob)
|
||||||
assert get(reverse('api:organization_inventories_list', args=(organization.id,)), user=alice).data['count'] == 2
|
assert get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
|
||||||
assert get(reverse('api:organization_inventories_list', args=(organization.id,)), user=bob).data['count'] == 1
|
assert get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
|
||||||
get(reverse('api:organization_inventories_list', args=(organization.id,)), user=rando, expect=403)
|
get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=rando, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -123,25 +123,25 @@ def test_create_organization_xfail(post, alice):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_user_to_organization(post, organization, alice, bob):
|
def test_add_user_to_organization(post, organization, alice, bob):
|
||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=204)
|
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=204)
|
||||||
assert bob in organization.member_role
|
assert bob in organization.member_role
|
||||||
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
|
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
|
||||||
assert bob not in organization.member_role
|
assert bob not in organization.member_role
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_user_to_organization_xfail(post, organization, alice, bob):
|
def test_add_user_to_organization_xfail(post, organization, alice, bob):
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=403)
|
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_admin_to_organization(post, organization, alice, bob):
|
def test_add_admin_to_organization(post, organization, alice, bob):
|
||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=204)
|
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=204)
|
||||||
assert bob in organization.admin_role
|
assert bob in organization.admin_role
|
||||||
assert bob in organization.member_role
|
assert bob in organization.member_role
|
||||||
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
|
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
|
||||||
assert bob not in organization.admin_role
|
assert bob not in organization.admin_role
|
||||||
assert bob not in organization.member_role
|
assert bob not in organization.member_role
|
||||||
|
|
||||||
@ -149,42 +149,42 @@ def test_add_admin_to_organization(post, organization, alice, bob):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_admin_to_organization_xfail(post, organization, alice, bob):
|
def test_add_admin_to_organization_xfail(post, organization, alice, bob):
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=403)
|
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_update_organization(get, put, organization, alice, bob):
|
def test_update_organization(get, put, organization, alice, bob):
|
||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
data = get(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=200).data
|
data = get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=200).data
|
||||||
data['description'] = 'hi'
|
data['description'] = 'hi'
|
||||||
put(reverse('api:organization_detail', args=(organization.id,)), data, user=alice, expect=200)
|
put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=alice, expect=200)
|
||||||
organization.refresh_from_db()
|
organization.refresh_from_db()
|
||||||
assert organization.description == 'hi'
|
assert organization.description == 'hi'
|
||||||
data['description'] = 'bye'
|
data['description'] = 'bye'
|
||||||
put(reverse('api:organization_detail', args=(organization.id,)), data, user=bob, expect=403)
|
put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=bob, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
||||||
def test_delete_organization(delete, organization, admin):
|
def test_delete_organization(delete, organization, admin):
|
||||||
delete(reverse('api:organization_detail', args=(organization.id,)), user=admin, expect=204)
|
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=admin, expect=204)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
||||||
def test_delete_organization2(delete, organization, alice):
|
def test_delete_organization2(delete, organization, alice):
|
||||||
organization.admin_role.members.add(alice)
|
organization.admin_role.members.add(alice)
|
||||||
delete(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=204)
|
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=204)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
||||||
def test_delete_organization_xfail1(delete, organization, alice):
|
def test_delete_organization_xfail1(delete, organization, alice):
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
delete(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=403)
|
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=403)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
|
||||||
def test_delete_organization_xfail2(delete, organization):
|
def test_delete_organization_xfail2(delete, organization):
|
||||||
delete(reverse('api:organization_detail', args=(organization.id,)), user=None, expect=401)
|
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=None, expect=401)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
from awx.main.models import Role, Group, UnifiedJobTemplate, JobTemplate
|
from awx.main.models import Role, Group, UnifiedJobTemplate, JobTemplate
|
||||||
@ -30,17 +30,17 @@ class TestOptionsRBAC:
|
|||||||
def test_inventory_group_host_can_add(self, inventory, alice, options):
|
def test_inventory_group_host_can_add(self, inventory, alice, options):
|
||||||
inventory.admin_role.members.add(alice)
|
inventory.admin_role.members.add(alice)
|
||||||
|
|
||||||
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), alice)
|
response = options(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.pk}), alice)
|
||||||
assert 'POST' in response.data['actions']
|
assert 'POST' in response.data['actions']
|
||||||
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), alice)
|
response = options(reverse('api:inventory_groups_list', kwargs={'pk': inventory.pk}), alice)
|
||||||
assert 'POST' in response.data['actions']
|
assert 'POST' in response.data['actions']
|
||||||
|
|
||||||
def test_inventory_group_host_can_not_add(self, inventory, bob, options):
|
def test_inventory_group_host_can_not_add(self, inventory, bob, options):
|
||||||
inventory.read_role.members.add(bob)
|
inventory.read_role.members.add(bob)
|
||||||
|
|
||||||
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), bob)
|
response = options(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.pk}), bob)
|
||||||
assert 'POST' not in response.data['actions']
|
assert 'POST' not in response.data['actions']
|
||||||
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), bob)
|
response = options(reverse('api:inventory_groups_list', kwargs={'pk': inventory.pk}), bob)
|
||||||
assert 'POST' not in response.data['actions']
|
assert 'POST' not in response.data['actions']
|
||||||
|
|
||||||
def test_user_list_can_add(self, org_member, org_admin, options):
|
def test_user_list_can_add(self, org_member, org_admin, options):
|
||||||
@ -192,7 +192,7 @@ class TestAccessListCapabilities:
|
|||||||
inventory.admin_role.members.add(rando)
|
inventory.admin_role.members.add(rando)
|
||||||
|
|
||||||
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), rando)
|
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), rando)
|
||||||
|
|
||||||
mock_access_method.assert_called_once_with(inventory.admin_role, rando, 'members', **self.extra_kwargs)
|
mock_access_method.assert_called_once_with(inventory.admin_role, rando, 'members', **self.extra_kwargs)
|
||||||
self._assert_one_in_list(response.data)
|
self._assert_one_in_list(response.data)
|
||||||
@ -202,7 +202,7 @@ class TestAccessListCapabilities:
|
|||||||
def test_access_list_indirect_access_capability(
|
def test_access_list_indirect_access_capability(
|
||||||
self, inventory, organization, org_admin, get, mocker, mock_access_method):
|
self, inventory, organization, org_admin, get, mocker, mock_access_method):
|
||||||
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), org_admin)
|
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), org_admin)
|
||||||
|
|
||||||
mock_access_method.assert_called_once_with(organization.admin_role, org_admin, 'members', **self.extra_kwargs)
|
mock_access_method.assert_called_once_with(organization.admin_role, org_admin, 'members', **self.extra_kwargs)
|
||||||
self._assert_one_in_list(response.data, sublist='indirect_access')
|
self._assert_one_in_list(response.data, sublist='indirect_access')
|
||||||
@ -214,7 +214,7 @@ class TestAccessListCapabilities:
|
|||||||
team.member_role.children.add(inventory.admin_role)
|
team.member_role.children.add(inventory.admin_role)
|
||||||
|
|
||||||
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), team_member)
|
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), team_member)
|
||||||
|
|
||||||
mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', **self.extra_kwargs)
|
mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', **self.extra_kwargs)
|
||||||
self._assert_one_in_list(response.data)
|
self._assert_one_in_list(response.data)
|
||||||
@ -223,7 +223,7 @@ class TestAccessListCapabilities:
|
|||||||
|
|
||||||
def test_user_access_list_direct_access_capability(self, rando, get):
|
def test_user_access_list_direct_access_capability(self, rando, get):
|
||||||
"When a user views their own access list, they cannot unattach their admin role"
|
"When a user views their own access list, they cannot unattach their admin role"
|
||||||
response = get(reverse('api:user_access_list', args=(rando.id,)), rando)
|
response = get(reverse('api:user_access_list', kwargs={'pk': rando.id}), rando)
|
||||||
direct_access_list = response.data['results'][0]['summary_fields']['direct_access']
|
direct_access_list = response.data['results'][0]['summary_fields']['direct_access']
|
||||||
assert not direct_access_list[0]['role']['user_capabilities']['unattach']
|
assert not direct_access_list[0]['role']['user_capabilities']['unattach']
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ def test_team_roles_unattach(mocker, team, team_member, inventory, mock_access_m
|
|||||||
team.member_role.children.add(inventory.admin_role)
|
team.member_role.children.add(inventory.admin_role)
|
||||||
|
|
||||||
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
|
response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member)
|
||||||
|
|
||||||
# Did we assess whether team_member can remove team's permission to the inventory?
|
# Did we assess whether team_member can remove team's permission to the inventory?
|
||||||
mock_access_method.assert_called_once_with(
|
mock_access_method.assert_called_once_with(
|
||||||
@ -248,7 +248,7 @@ def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_metho
|
|||||||
organization.member_role.members.add(bob)
|
organization.member_role.members.add(bob)
|
||||||
|
|
||||||
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
|
response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob)
|
||||||
|
|
||||||
# Did we assess whether bob can remove alice's permission to the inventory?
|
# Did we assess whether bob can remove alice's permission to the inventory?
|
||||||
mock_access_method.assert_called_once_with(
|
mock_access_method.assert_called_once_with(
|
||||||
@ -259,7 +259,7 @@ def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_metho
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_team_roles_unattach_functional(team, team_member, inventory, get):
|
def test_team_roles_unattach_functional(team, team_member, inventory, get):
|
||||||
team.member_role.children.add(inventory.admin_role)
|
team.member_role.children.add(inventory.admin_role)
|
||||||
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
|
response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member)
|
||||||
# Team member should be able to remove access to inventory, becauase
|
# Team member should be able to remove access to inventory, becauase
|
||||||
# the inventory admin_role grants that ability
|
# the inventory admin_role grants that ability
|
||||||
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
||||||
@ -269,7 +269,7 @@ def test_team_roles_unattach_functional(team, team_member, inventory, get):
|
|||||||
def test_user_roles_unattach_functional(organization, alice, bob, get):
|
def test_user_roles_unattach_functional(organization, alice, bob, get):
|
||||||
organization.member_role.members.add(alice)
|
organization.member_role.members.add(alice)
|
||||||
organization.member_role.members.add(bob)
|
organization.member_role.members.add(bob)
|
||||||
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
|
response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob)
|
||||||
# Org members cannot revoke the membership of other members
|
# Org members cannot revoke the membership of other members
|
||||||
assert not response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
assert not response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ def test_prefetch_jt_copy_capability(job_template, project, inventory, machine_c
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_manual_projects_no_update(project, get, admin_user):
|
def test_manual_projects_no_update(project, get, admin_user):
|
||||||
response = get(reverse('api:project_detail', args=[project.pk]), admin_user, expect=200)
|
response = get(reverse('api:project_detail', kwargs={'pk': project.pk}), admin_user, expect=200)
|
||||||
assert not response.data['summary_fields']['user_capabilities']['start']
|
assert not response.data['summary_fields']['user_capabilities']['start']
|
||||||
assert not response.data['summary_fields']['user_capabilities']['schedule']
|
assert not response.data['summary_fields']['user_capabilities']['schedule']
|
||||||
|
|
||||||
@ -369,5 +369,5 @@ def test_license_check_not_called(mocker, job_template, project, org_admin, get)
|
|||||||
job_template.save() # need this to make the JT visible
|
job_template.save() # need this to make the JT visible
|
||||||
mock_license_check = mocker.MagicMock()
|
mock_license_check = mocker.MagicMock()
|
||||||
with mocker.patch('awx.main.access.BaseAccess.check_license', mock_license_check):
|
with mocker.patch('awx.main.access.BaseAccess.check_license', mock_license_check):
|
||||||
get(reverse('api:job_template_detail', args=[job_template.pk]), org_admin, expect=200)
|
get(reverse('api:job_template_detail', kwargs={'pk': job_template.pk}), org_admin, expect=200)
|
||||||
assert not mock_license_check.called
|
assert not mock_license_check.called
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models import Role
|
from awx.main.models import Role
|
||||||
|
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ def test_indirect_access_list(get, organization, project, team_factory, user, ad
|
|||||||
|
|
||||||
project_admin_team.admin_role.members.add(team_admin)
|
project_admin_team.admin_role.members.add(team_admin)
|
||||||
|
|
||||||
result = get(reverse('api:project_access_list', args=(project.id,)), admin)
|
result = get(reverse('api:project_access_list', kwargs={'pk': project.id}), admin)
|
||||||
assert result.status_code == 200
|
assert result.status_code == 200
|
||||||
|
|
||||||
# Result should be:
|
# Result should be:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
@ -9,10 +9,8 @@ import os
|
|||||||
# Mock
|
# Mock
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
# Django
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.conf.models import Setting
|
from awx.conf.models import Setting
|
||||||
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
|
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
|
||||||
|
|
||||||
@ -32,7 +30,7 @@ def mock_no_license_file(mocker):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get, put, patch, delete, admin, enterprise_license):
|
def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get, put, patch, delete, admin, enterprise_license):
|
||||||
url = reverse('api:setting_singleton_detail', args=('system',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'})
|
||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
assert not response.data['LICENSE']
|
assert not response.data['LICENSE']
|
||||||
Setting.objects.create(key='TOWER_URL_BASE', value='https://towerhost')
|
Setting.objects.create(key='TOWER_URL_BASE', value='https://towerhost')
|
||||||
@ -53,13 +51,13 @@ def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_url_base_defaults_to_request(options, admin):
|
def test_url_base_defaults_to_request(options, admin):
|
||||||
# If TOWER_URL_BASE is not set, default to the Tower request hostname
|
# If TOWER_URL_BASE is not set, default to the Tower request hostname
|
||||||
resp = options(reverse('api:setting_singleton_detail', args=('system',)), user=admin, expect=200)
|
resp = options(reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'}), user=admin, expect=200)
|
||||||
assert resp.data['actions']['PUT']['TOWER_URL_BASE']['default'] == 'http://testserver'
|
assert resp.data['actions']['PUT']['TOWER_URL_BASE']['default'] == 'http://testserver'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_jobs_settings(get, put, patch, delete, admin):
|
def test_jobs_settings(get, put, patch, delete, admin):
|
||||||
url = reverse('api:setting_singleton_detail', args=('jobs',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'jobs'})
|
||||||
get(url, user=admin, expect=200)
|
get(url, user=admin, expect=200)
|
||||||
delete(url, user=admin, expect=204)
|
delete(url, user=admin, expect=204)
|
||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
@ -80,7 +78,7 @@ def test_jobs_settings(get, put, patch, delete, admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_ldap_settings(get, put, patch, delete, admin, enterprise_license):
|
def test_ldap_settings(get, put, patch, delete, admin, enterprise_license):
|
||||||
url = reverse('api:setting_singleton_detail', args=('ldap',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'})
|
||||||
get(url, user=admin, expect=404)
|
get(url, user=admin, expect=404)
|
||||||
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
||||||
get(url, user=admin, expect=200)
|
get(url, user=admin, expect=200)
|
||||||
@ -107,7 +105,7 @@ def test_ldap_settings(get, put, patch, delete, admin, enterprise_license):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_empty_ldap_dn(get, put, patch, delete, admin, enterprise_license,
|
def test_empty_ldap_dn(get, put, patch, delete, admin, enterprise_license,
|
||||||
setting):
|
setting):
|
||||||
url = reverse('api:setting_singleton_detail', args=('ldap',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'})
|
||||||
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
||||||
|
|
||||||
patch(url, user=admin, data={setting: ''}, expect=200)
|
patch(url, user=admin, data={setting: ''}, expect=200)
|
||||||
@ -121,7 +119,7 @@ def test_empty_ldap_dn(get, put, patch, delete, admin, enterprise_license,
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_radius_settings(get, put, patch, delete, admin, enterprise_license, settings):
|
def test_radius_settings(get, put, patch, delete, admin, enterprise_license, settings):
|
||||||
url = reverse('api:setting_singleton_detail', args=('radius',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'radius'})
|
||||||
get(url, user=admin, expect=404)
|
get(url, user=admin, expect=404)
|
||||||
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
Setting.objects.create(key='LICENSE', value=enterprise_license)
|
||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
@ -155,7 +153,7 @@ def test_radius_settings(get, put, patch, delete, admin, enterprise_license, set
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_ui_settings(get, put, patch, delete, admin, enterprise_license):
|
def test_ui_settings(get, put, patch, delete, admin, enterprise_license):
|
||||||
url = reverse('api:setting_singleton_detail', args=('ui',))
|
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ui'})
|
||||||
response = get(url, user=admin, expect=200)
|
response = get(url, user=admin, expect=200)
|
||||||
assert 'CUSTOM_LOGO' not in response.data
|
assert 'CUSTOM_LOGO' not in response.data
|
||||||
assert 'CUSTOM_LOGIN_INFO' not in response.data
|
assert 'CUSTOM_LOGIN_INFO' not in response.data
|
||||||
@ -199,7 +197,6 @@ def test_logging_aggregrator_connection_test_requires_superuser(get, post, alice
|
|||||||
@pytest.mark.parametrize('key', [
|
@pytest.mark.parametrize('key', [
|
||||||
'LOG_AGGREGATOR_TYPE',
|
'LOG_AGGREGATOR_TYPE',
|
||||||
'LOG_AGGREGATOR_HOST',
|
'LOG_AGGREGATOR_HOST',
|
||||||
'LOG_AGGREGATOR_PORT',
|
|
||||||
])
|
])
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_logging_aggregrator_connection_test_bad_request(get, post, admin, key):
|
def test_logging_aggregrator_connection_test_bad_request(get, post, admin, key):
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import mock
|
|||||||
import pytest
|
import pytest
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.jobs import JobTemplate, Job
|
from awx.main.models.jobs import JobTemplate, Job
|
||||||
from awx.main.models.activity_stream import ActivityStream
|
from awx.main.models.activity_stream import ActivityStream
|
||||||
from awx.conf.license import LicenseForbids
|
from awx.conf.license import LicenseForbids
|
||||||
@ -30,7 +30,7 @@ def job_template_with_survey(job_template_factory):
|
|||||||
def test_survey_spec_view_denied(job_template_with_survey, get, admin_user):
|
def test_survey_spec_view_denied(job_template_with_survey, get, admin_user):
|
||||||
# TODO: Test non-enterprise license
|
# TODO: Test non-enterprise license
|
||||||
response = get(reverse('api:job_template_survey_spec',
|
response = get(reverse('api:job_template_survey_spec',
|
||||||
args=(job_template_with_survey.id,)), admin_user, expect=402)
|
kwargs={'pk': job_template_with_survey.id}), admin_user, expect=402)
|
||||||
assert response.data['detail'] == 'Your license does not allow adding surveys.'
|
assert response.data['detail'] == 'Your license does not allow adding surveys.'
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ def test_deny_creating_with_survey(project, post, admin_user):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@pytest.mark.survey
|
@pytest.mark.survey
|
||||||
def test_survey_spec_view_allowed(deploy_jobtemplate, get, admin_user):
|
def test_survey_spec_view_allowed(deploy_jobtemplate, get, admin_user):
|
||||||
get(reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
|
get(reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
|
||||||
admin_user, expect=200)
|
admin_user, expect=200)
|
||||||
|
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ def test_survey_spec_view_allowed(deploy_jobtemplate, get, admin_user):
|
|||||||
@pytest.mark.survey
|
@pytest.mark.survey
|
||||||
def test_survey_spec_sucessful_creation(survey_spec_factory, job_template, post, admin_user):
|
def test_survey_spec_sucessful_creation(survey_spec_factory, job_template, post, admin_user):
|
||||||
survey_input_data = survey_spec_factory('new_question')
|
survey_input_data = survey_spec_factory('new_question')
|
||||||
post(url=reverse('api:job_template_survey_spec', args=(job_template.id,)),
|
post(url=reverse('api:job_template_survey_spec', kwargs={'pk': job_template.id}),
|
||||||
data=survey_input_data, user=admin_user, expect=200)
|
data=survey_input_data, user=admin_user, expect=200)
|
||||||
updated_jt = JobTemplate.objects.get(pk=job_template.pk)
|
updated_jt = JobTemplate.objects.get(pk=job_template.pk)
|
||||||
assert updated_jt.survey_spec == survey_input_data
|
assert updated_jt.survey_spec == survey_input_data
|
||||||
@ -98,10 +98,14 @@ def test_survey_spec_sucessful_creation(survey_spec_factory, job_template, post,
|
|||||||
def test_survey_spec_non_dict_error(deploy_jobtemplate, post, admin_user):
|
def test_survey_spec_non_dict_error(deploy_jobtemplate, post, admin_user):
|
||||||
"""When a question doesn't follow the standard format, verify error thrown."""
|
"""When a question doesn't follow the standard format, verify error thrown."""
|
||||||
response = post(
|
response = post(
|
||||||
url=reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
|
url=reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
|
||||||
data={"description": "Email of the submitter",
|
data={
|
||||||
"spec": ["What is your email?"], "name": "Email survey"},
|
"description": "Email of the submitter",
|
||||||
user=admin_user, expect=400)
|
"spec": ["What is your email?"], "name": "Email survey"
|
||||||
|
},
|
||||||
|
user=admin_user,
|
||||||
|
expect=400
|
||||||
|
)
|
||||||
assert response.data['error'] == "Survey question 0 is not a json object."
|
assert response.data['error'] == "Survey question 0 is not a json object."
|
||||||
|
|
||||||
|
|
||||||
@ -110,9 +114,11 @@ def test_survey_spec_non_dict_error(deploy_jobtemplate, post, admin_user):
|
|||||||
@pytest.mark.survey
|
@pytest.mark.survey
|
||||||
def test_survey_spec_dual_names_error(survey_spec_factory, deploy_jobtemplate, post, user):
|
def test_survey_spec_dual_names_error(survey_spec_factory, deploy_jobtemplate, post, user):
|
||||||
response = post(
|
response = post(
|
||||||
url=reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
|
url=reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
|
||||||
data=survey_spec_factory(['submitter_email', 'submitter_email']),
|
data=survey_spec_factory(['submitter_email', 'submitter_email']),
|
||||||
user=user('admin', True), expect=400)
|
user=user('admin', True),
|
||||||
|
expect=400
|
||||||
|
)
|
||||||
assert response.data['error'] == "'variable' 'submitter_email' duplicated in survey question 1."
|
assert response.data['error'] == "'variable' 'submitter_email' duplicated in survey question 1."
|
||||||
|
|
||||||
|
|
||||||
@ -166,7 +172,7 @@ def test_job_template_delete_access_with_survey(job_template_with_survey, admin_
|
|||||||
@pytest.mark.survey
|
@pytest.mark.survey
|
||||||
def test_delete_survey_spec_without_license(job_template_with_survey, delete, admin_user):
|
def test_delete_survey_spec_without_license(job_template_with_survey, delete, admin_user):
|
||||||
"""Functional delete test through the survey_spec view."""
|
"""Functional delete test through the survey_spec view."""
|
||||||
delete(reverse('api:job_template_survey_spec', args=[job_template_with_survey.pk]),
|
delete(reverse('api:job_template_survey_spec', kwargs={'pk': job_template_with_survey.pk}),
|
||||||
admin_user, expect=200)
|
admin_user, expect=200)
|
||||||
new_jt = JobTemplate.objects.get(pk=job_template_with_survey.pk)
|
new_jt = JobTemplate.objects.get(pk=job_template_with_survey.pk)
|
||||||
assert new_jt.survey_spec == {}
|
assert new_jt.survey_spec == {}
|
||||||
@ -185,7 +191,7 @@ def test_launch_survey_enabled_but_no_survey_spec(job_template_factory, post, ad
|
|||||||
obj = objects.job_template
|
obj = objects.job_template
|
||||||
obj.survey_enabled = True
|
obj.survey_enabled = True
|
||||||
obj.save()
|
obj.save()
|
||||||
response = post(reverse('api:job_template_launch', args=[obj.pk]),
|
response = post(reverse('api:job_template_launch', kwargs={'pk':obj.pk}),
|
||||||
dict(extra_vars=dict(survey_var=7)), admin_user, expect=201)
|
dict(extra_vars=dict(survey_var=7)), admin_user, expect=201)
|
||||||
assert 'survey_var' in response.data['ignored_fields']['extra_vars']
|
assert 'survey_var' in response.data['ignored_fields']['extra_vars']
|
||||||
|
|
||||||
@ -205,7 +211,7 @@ def test_launch_with_non_empty_survey_spec_no_license(job_template_factory, post
|
|||||||
obj = objects.job_template
|
obj = objects.job_template
|
||||||
obj.survey_enabled = False
|
obj.survey_enabled = False
|
||||||
obj.save()
|
obj.save()
|
||||||
post(reverse('api:job_template_launch', args=[obj.pk]), {}, admin_user, expect=201)
|
post(reverse('api:job_template_launch', kwargs={'pk': obj.pk}), {}, admin_user, expect=201)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
from awx.main.models import UnifiedJob, ProjectUpdate
|
from awx.main.models import UnifiedJob, ProjectUpdate
|
||||||
from awx.main.tests.base import URI
|
from awx.main.tests.base import URI
|
||||||
|
|
||||||
@ -60,7 +59,7 @@ formats = [
|
|||||||
def test_project_update_redaction_enabled(get, format, content_type, test_cases, admin):
|
def test_project_update_redaction_enabled(get, format, content_type, test_cases, admin):
|
||||||
for test_data in test_cases:
|
for test_data in test_cases:
|
||||||
job = test_data['project']
|
job = test_data['project']
|
||||||
response = get(reverse("api:project_update_stdout", args=(job.pk,)) + "?format=" + format, user=admin, expect=200, accept=content_type)
|
response = get(reverse("api:project_update_stdout", kwargs={'pk': job.pk}) + "?format=" + format, user=admin, expect=200, accept=content_type)
|
||||||
assert content_type in response['CONTENT-TYPE']
|
assert content_type in response['CONTENT-TYPE']
|
||||||
assert response.data is not None
|
assert response.data is not None
|
||||||
content = response.data['content'] if format == 'json' else response.data
|
content = response.data['content'] if format == 'json' else response.data
|
||||||
@ -74,7 +73,7 @@ def test_project_update_redaction_enabled(get, format, content_type, test_cases,
|
|||||||
def test_job_redaction_disabled(get, format, content_type, negative_test_cases, admin):
|
def test_job_redaction_disabled(get, format, content_type, negative_test_cases, admin):
|
||||||
for test_data in negative_test_cases:
|
for test_data in negative_test_cases:
|
||||||
job = test_data['job']
|
job = test_data['job']
|
||||||
response = get(reverse("api:job_stdout", args=(job.pk,)) + "?format=" + format, user=admin, expect=200, format=format)
|
response = get(reverse("api:job_stdout", kwargs={'pk': job.pk}) + "?format=" + format, user=admin, expect=200, format=format)
|
||||||
content = response.data['content'] if format == 'json' else response.data
|
content = response.data['content'] if format == 'json' else response.data
|
||||||
assert response.data is not None
|
assert response.data is not None
|
||||||
assert test_data['uri'].username in content
|
assert test_data['uri'].username in content
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -39,7 +39,7 @@ def test_create_delete_create_user(post, delete, admin):
|
|||||||
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)
|
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
response = delete(reverse('api:user_detail', args=(response.data['id'],)), admin)
|
response = delete(reverse('api:user_detail', kwargs={'pk': response.data['id']}), admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)
|
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.notifications import NotificationTemplate, Notification
|
from awx.main.models.notifications import NotificationTemplate, Notification
|
||||||
from awx.main.models.inventory import Inventory, Group
|
from awx.main.models.inventory import Inventory, Group
|
||||||
from awx.main.models.jobs import JobTemplate
|
from awx.main.models.jobs import JobTemplate
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_notification_template_list(get, user, notification_template):
|
def test_get_notification_template_list(get, user, notification_template):
|
||||||
@ -29,7 +28,7 @@ def test_basic_parameterization(get, post, user, organization):
|
|||||||
headers={"Test": "Header"})),
|
headers={"Test": "Header"})),
|
||||||
u)
|
u)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
url = reverse('api:notification_template_detail', args=(response.data['id'],))
|
url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']})
|
||||||
response = get(url, u)
|
response = get(url, u)
|
||||||
assert 'related' in response.data
|
assert 'related' in response.data
|
||||||
assert 'organization' in response.data['related']
|
assert 'organization' in response.data['related']
|
||||||
@ -60,7 +59,7 @@ def test_encrypted_subfields(get, post, user, organization):
|
|||||||
u)
|
u)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
notification_template_actual = NotificationTemplate.objects.get(id=response.data['id'])
|
notification_template_actual = NotificationTemplate.objects.get(id=response.data['id'])
|
||||||
url = reverse('api:notification_template_detail', args=(response.data['id'],))
|
url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']})
|
||||||
response = get(url, u)
|
response = get(url, u)
|
||||||
assert response.data['notification_configuration']['account_token'] == "$encrypted$"
|
assert response.data['notification_configuration']['account_token'] == "$encrypted$"
|
||||||
with mock.patch.object(notification_template_actual.notification_class, "send_messages", assert_send):
|
with mock.patch.object(notification_template_actual.notification_class, "send_messages", assert_send):
|
||||||
@ -89,13 +88,13 @@ def test_inherited_notification_templates(get, post, user, organization, project
|
|||||||
g.save()
|
g.save()
|
||||||
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
|
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
|
||||||
jt.save()
|
jt.save()
|
||||||
url = reverse('api:organization_notification_templates_any_list', args=(organization.id,))
|
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
|
||||||
response = post(url, dict(id=notification_templates[0]), u)
|
response = post(url, dict(id=notification_templates[0]), u)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
url = reverse('api:project_notification_templates_any_list', args=(project.id,))
|
url = reverse('api:project_notification_templates_any_list', kwargs={'pk': project.id})
|
||||||
response = post(url, dict(id=notification_templates[1]), u)
|
response = post(url, dict(id=notification_templates[1]), u)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
url = reverse('api:job_template_notification_templates_any_list', args=(jt.id,))
|
url = reverse('api:job_template_notification_templates_any_list', kwargs={'pk': jt.id})
|
||||||
response = post(url, dict(id=notification_templates[2]), u)
|
response = post(url, dict(id=notification_templates[2]), u)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
assert len(jt.notification_templates['any']) == 3
|
assert len(jt.notification_templates['any']) == 3
|
||||||
@ -113,18 +112,18 @@ def test_notification_template_merging(get, post, user, organization, project, n
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_notification_template_simple_patch(patch, notification_template, admin):
|
def test_notification_template_simple_patch(patch, notification_template, admin):
|
||||||
patch(reverse('api:notification_template_detail', args=(notification_template.id,)), { 'name': 'foo'}, admin, expect=200)
|
patch(reverse('api:notification_template_detail', kwargs={'pk': notification_template.id}), { 'name': 'foo'}, admin, expect=200)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_notification_template_invalid_notification_type(patch, notification_template, admin):
|
def test_notification_template_invalid_notification_type(patch, notification_template, admin):
|
||||||
patch(reverse('api:notification_template_detail', args=(notification_template.id,)), { 'notification_type': 'invalid'}, admin, expect=400)
|
patch(reverse('api:notification_template_detail', kwargs={'pk': notification_template.id}), { 'notification_type': 'invalid'}, admin, expect=400)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_disallow_delete_when_notifications_pending(delete, user, notification_template):
|
def test_disallow_delete_when_notifications_pending(delete, user, notification_template):
|
||||||
u = user('superuser', True)
|
u = user('superuser', True)
|
||||||
url = reverse('api:notification_template_detail', args=(notification_template.id,))
|
url = reverse('api:notification_template_detail', kwargs={'pk': notification_template.id})
|
||||||
Notification.objects.create(notification_template=notification_template,
|
Notification.objects.create(notification_template=notification_template,
|
||||||
status='pending')
|
status='pending')
|
||||||
response = delete(url, user=u)
|
response = delete(url, user=u)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
import mock # noqa
|
import mock # noqa
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models import Project
|
from awx.main.models import Project
|
||||||
|
|
||||||
|
|
||||||
@ -38,13 +38,13 @@ def test_user_project_paged_list(get, organization_factory):
|
|||||||
|
|
||||||
# first page has first project and no previous page
|
# first page has first project and no previous page
|
||||||
pk = objects.users.alice.pk
|
pk = objects.users.alice.pk
|
||||||
url = reverse('api:user_projects_list', args=(pk,))
|
url = reverse('api:user_projects_list', kwargs={'pk':pk,})
|
||||||
results = get(url, objects.users.alice, QUERY_STRING='page_size=1').data
|
results = get(url, objects.users.alice, QUERY_STRING='page_size=1').data
|
||||||
assert results['count'] == 3
|
assert results['count'] == 3
|
||||||
assert len(results['results']) == 1
|
assert len(results['results']) == 1
|
||||||
assert results['previous'] is None
|
assert results['previous'] is None
|
||||||
assert results['next'] == (
|
assert results['next'] == (
|
||||||
'/api/v1/users/%s/projects/?page=2&page_size=1' % pk
|
'/api/v2/users/%s/projects/?page=2&page_size=1' % pk
|
||||||
)
|
)
|
||||||
|
|
||||||
# second page has one more, a previous and next page
|
# second page has one more, a previous and next page
|
||||||
@ -52,10 +52,10 @@ def test_user_project_paged_list(get, organization_factory):
|
|||||||
QUERY_STRING='page=2&page_size=1').data
|
QUERY_STRING='page=2&page_size=1').data
|
||||||
assert len(results['results']) == 1
|
assert len(results['results']) == 1
|
||||||
assert results['previous'] == (
|
assert results['previous'] == (
|
||||||
'/api/v1/users/%s/projects/?page=1&page_size=1' % pk
|
'/api/v2/users/%s/projects/?page=1&page_size=1' % pk
|
||||||
)
|
)
|
||||||
assert results['next'] == (
|
assert results['next'] == (
|
||||||
'/api/v1/users/%s/projects/?page=3&page_size=1' % pk
|
'/api/v2/users/%s/projects/?page=3&page_size=1' % pk
|
||||||
)
|
)
|
||||||
|
|
||||||
# third page has last project and a previous page
|
# third page has last project and a previous page
|
||||||
@ -63,7 +63,7 @@ def test_user_project_paged_list(get, organization_factory):
|
|||||||
QUERY_STRING='page=3&page_size=1').data
|
QUERY_STRING='page=3&page_size=1').data
|
||||||
assert len(results['results']) == 1
|
assert len(results['results']) == 1
|
||||||
assert results['previous'] == (
|
assert results['previous'] == (
|
||||||
'/api/v1/users/%s/projects/?page=2&page_size=1' % pk
|
'/api/v2/users/%s/projects/?page=2&page_size=1' % pk
|
||||||
)
|
)
|
||||||
assert results['next'] is None
|
assert results['next'] is None
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
|
|||||||
roles=['project-☁-1.admin_role:alice','project-☁-2.admin_role:alice'],
|
roles=['project-☁-1.admin_role:alice','project-☁-2.admin_role:alice'],
|
||||||
)
|
)
|
||||||
pk = objects.users.alice.pk
|
pk = objects.users.alice.pk
|
||||||
url = reverse('api:user_projects_list', args=(pk,))
|
url = reverse('api:user_projects_list', kwargs={'pk':pk,})
|
||||||
|
|
||||||
# first on first page, next page link contains unicode char
|
# first on first page, next page link contains unicode char
|
||||||
results = get(url, objects.users.alice,
|
results = get(url, objects.users.alice,
|
||||||
@ -89,7 +89,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
|
|||||||
assert results['count'] == 2
|
assert results['count'] == 2
|
||||||
assert len(results['results']) == 1
|
assert len(results['results']) == 1
|
||||||
assert results['next'] == (
|
assert results['next'] == (
|
||||||
'/api/v1/users/%s/projects/?page=2&page_size=1&search=%%E2%%98%%81' % pk # noqa
|
'/api/v2/users/%s/projects/?page=2&page_size=1&search=%%E2%%98%%81' % pk # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
# second project on second page, previous page link contains unicode char
|
# second project on second page, previous page link contains unicode char
|
||||||
@ -98,7 +98,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
|
|||||||
assert results['count'] == 2
|
assert results['count'] == 2
|
||||||
assert len(results['results']) == 1
|
assert len(results['results']) == 1
|
||||||
assert results['previous'] == (
|
assert results['previous'] == (
|
||||||
'/api/v1/users/%s/projects/?page=1&page_size=1&search=%%E2%%98%%81' % pk # noqa
|
'/api/v2/users/%s/projects/?page=1&page_size=1&search=%%E2%%98%%81' % pk # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -114,21 +114,23 @@ def test_user_project_list(get, organization_factory):
|
|||||||
'bob project.admin_role:bob',
|
'bob project.admin_role:bob',
|
||||||
'shared project.admin_role:bob',
|
'shared project.admin_role:bob',
|
||||||
'shared project.admin_role:alice'])
|
'shared project.admin_role:alice'])
|
||||||
|
assert get(reverse(
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.superusers.admin).data['count'] == 3
|
'api:user_projects_list',
|
||||||
|
kwargs={'pk':objects.superusers.admin.pk,}
|
||||||
|
), objects.superusers.admin).data['count'] == 3
|
||||||
|
|
||||||
# admins can see everyones projects
|
# admins can see everyones projects
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.superusers.admin).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.alice.pk,}), objects.superusers.admin).data['count'] == 2
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.superusers.admin).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.bob.pk,}), objects.superusers.admin).data['count'] == 2
|
||||||
|
|
||||||
# users can see their own projects
|
# users can see their own projects
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.users.alice).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.alice.pk,}), objects.users.alice).data['count'] == 2
|
||||||
|
|
||||||
# alice should only be able to see the shared project when looking at bobs projects
|
# alice should only be able to see the shared project when looking at bobs projects
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.users.alice).data['count'] == 1
|
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.bob.pk,}), objects.users.alice).data['count'] == 1
|
||||||
|
|
||||||
# alice should see all projects they can see when viewing an admin
|
# alice should see all projects they can see when viewing an admin
|
||||||
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.users.alice).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.superusers.admin.pk,}), objects.users.alice).data['count'] == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -139,35 +141,35 @@ def test_team_project_list(get, team_project_list):
|
|||||||
alice, bob, admin = objects.users.alice, objects.users.bob, objects.superusers.admin
|
alice, bob, admin = objects.users.alice, objects.users.bob, objects.superusers.admin
|
||||||
|
|
||||||
# admins can see all projects on a team
|
# admins can see all projects on a team
|
||||||
assert get(reverse('api:team_projects_list', args=(team1.pk,)), admin).data['count'] == 2
|
assert get(reverse('api:team_projects_list', kwargs={'pk':team1.pk,}), admin).data['count'] == 2
|
||||||
assert get(reverse('api:team_projects_list', args=(team2.pk,)), admin).data['count'] == 2
|
assert get(reverse('api:team_projects_list', kwargs={'pk':team2.pk,}), admin).data['count'] == 2
|
||||||
|
|
||||||
# users can see all projects on teams they are a member of
|
# users can see all projects on teams they are a member of
|
||||||
assert get(reverse('api:team_projects_list', args=(team1.pk,)), alice).data['count'] == 2
|
assert get(reverse('api:team_projects_list', kwargs={'pk':team1.pk,}), alice).data['count'] == 2
|
||||||
|
|
||||||
# but if she does, then she should only see the shared project
|
# but if she does, then she should only see the shared project
|
||||||
team2.read_role.members.add(alice)
|
team2.read_role.members.add(alice)
|
||||||
assert get(reverse('api:team_projects_list', args=(team2.pk,)), alice).data['count'] == 1
|
assert get(reverse('api:team_projects_list', kwargs={'pk':team2.pk,}), alice).data['count'] == 1
|
||||||
team2.read_role.members.remove(alice)
|
team2.read_role.members.remove(alice)
|
||||||
|
|
||||||
# admins can see all projects
|
# admins can see all projects
|
||||||
assert get(reverse('api:user_projects_list', args=(admin.pk,)), admin).data['count'] == 3
|
assert get(reverse('api:user_projects_list', kwargs={'pk':admin.pk,}), admin).data['count'] == 3
|
||||||
|
|
||||||
# admins can see everyones projects
|
# admins can see everyones projects
|
||||||
assert get(reverse('api:user_projects_list', args=(alice.pk,)), admin).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':alice.pk,}), admin).data['count'] == 2
|
||||||
assert get(reverse('api:user_projects_list', args=(bob.pk,)), admin).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':bob.pk,}), admin).data['count'] == 2
|
||||||
|
|
||||||
# users can see their own projects
|
# users can see their own projects
|
||||||
assert get(reverse('api:user_projects_list', args=(alice.pk,)), alice).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':alice.pk,}), alice).data['count'] == 2
|
||||||
|
|
||||||
# alice should see all projects they can see when viewing an admin
|
# alice should see all projects they can see when viewing an admin
|
||||||
assert get(reverse('api:user_projects_list', args=(admin.pk,)), alice).data['count'] == 2
|
assert get(reverse('api:user_projects_list', kwargs={'pk':admin.pk,}), alice).data['count'] == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_team_project_list_fail1(get, team_project_list):
|
def test_team_project_list_fail1(get, team_project_list):
|
||||||
objects = team_project_list
|
objects = team_project_list
|
||||||
res = get(reverse('api:team_projects_list', args=(objects.teams.team2.pk,)), objects.users.alice)
|
res = get(reverse('api:team_projects_list', kwargs={'pk':objects.teams.team2.pk,}), objects.users.alice)
|
||||||
assert res.status_code == 403
|
assert res.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
@ -210,19 +212,22 @@ def test_create_project_null_organization_xfail(post, organization, org_admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db()
|
@pytest.mark.django_db()
|
||||||
def test_patch_project_null_organization(patch, organization, project, admin):
|
def test_patch_project_null_organization(patch, organization, project, admin):
|
||||||
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': organization.id}, admin, expect=200)
|
patch(reverse('api:project_detail', kwargs={'pk':project.id,}), { 'name': 't', 'organization': organization.id}, admin, expect=200)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db()
|
@pytest.mark.django_db()
|
||||||
def test_patch_project_null_organization_xfail(patch, project, org_admin):
|
def test_patch_project_null_organization_xfail(patch, project, org_admin):
|
||||||
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': None}, org_admin, expect=400)
|
patch(reverse('api:project_detail', kwargs={'pk':project.id,}), { 'name': 't', 'organization': None}, org_admin, expect=400)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_cannot_schedule_manual_project(project, admin_user, post):
|
def test_cannot_schedule_manual_project(project, admin_user, post):
|
||||||
response = post(
|
response = post(
|
||||||
reverse('api:project_schedules_list', args=(project.pk,)),
|
reverse('api:project_schedules_list', kwargs={'pk':project.pk,}),
|
||||||
{"name": "foo", "description": "", "enabled": True,
|
{
|
||||||
|
"name": "foo", "description": "", "enabled": True,
|
||||||
"rrule": "DTSTART:20160926T040000Z RRULE:FREQ=HOURLY;INTERVAL=1",
|
"rrule": "DTSTART:20160926T040000Z RRULE:FREQ=HOURLY;INTERVAL=1",
|
||||||
"extra_data": {}}, admin_user, expect=400)
|
"extra_data": {}
|
||||||
|
}, admin_user, expect=400
|
||||||
|
)
|
||||||
assert 'Manual' in response.data['unified_job_template'][0]
|
assert 'Manual' in response.data['unified_job_template'][0]
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import mock # noqa
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.core.urlresolvers import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.rbac import Role, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR
|
from awx.main.models.rbac import Role, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR
|
||||||
|
|
||||||
|
|
||||||
@ -78,14 +78,14 @@ def test_roles_filter_visibility(get, organization, project, admin, alice, bob):
|
|||||||
Role.singleton('system_auditor').members.add(alice)
|
Role.singleton('system_auditor').members.add(alice)
|
||||||
project.update_role.members.add(admin)
|
project.update_role.members.add(admin)
|
||||||
|
|
||||||
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1
|
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1
|
||||||
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=alice).data['count'] == 1
|
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=alice).data['count'] == 1
|
||||||
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 0
|
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 0
|
||||||
organization.auditor_role.members.add(bob)
|
organization.auditor_role.members.add(bob)
|
||||||
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
|
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
|
||||||
organization.auditor_role.members.remove(bob)
|
organization.auditor_role.members.remove(bob)
|
||||||
project.use_role.members.add(bob) # sibling role should still grant visibility
|
project.use_role.members.add(bob) # sibling role should still grant visibility
|
||||||
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
|
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@ -104,7 +104,7 @@ def test_cant_delete_role(delete, admin):
|
|||||||
# Some day we might want to do this, but until that is speced out, lets
|
# Some day we might want to do this, but until that is speced out, lets
|
||||||
# ensure we don't slip up and allow this implicitly through some helper or
|
# ensure we don't slip up and allow this implicitly through some helper or
|
||||||
# another
|
# another
|
||||||
response = delete(reverse('api:role_detail', args=(admin.admin_role.id,)), admin)
|
response = delete(reverse('api:role_detail', kwargs={'pk': admin.admin_role.id}), admin)
|
||||||
assert response.status_code == 405
|
assert response.status_code == 405
|
||||||
|
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ def test_cant_delete_role(delete, admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_user_roles_list(get, admin):
|
def test_get_user_roles_list(get, admin):
|
||||||
url = reverse('api:user_roles_list', args=(admin.id,))
|
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
roles = response.data
|
roles = response.data
|
||||||
@ -136,7 +136,7 @@ def test_user_view_other_user_roles(organization, inventory, team, get, alice, b
|
|||||||
# Bob is an org admin, alice can see this.
|
# Bob is an org admin, alice can see this.
|
||||||
# Bob is in a team that alice is not, alice cannot see that bob is a member of that team.
|
# Bob is in a team that alice is not, alice cannot see that bob is a member of that team.
|
||||||
|
|
||||||
url = reverse('api:user_roles_list', args=(bob.id,))
|
url = reverse('api:user_roles_list', kwargs={'pk': bob.id})
|
||||||
response = get(url, alice)
|
response = get(url, alice)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
roles = response.data
|
roles = response.data
|
||||||
@ -171,7 +171,7 @@ def test_user_view_other_user_roles(organization, inventory, team, get, alice, b
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_role_to_user(role, post, admin):
|
def test_add_role_to_user(role, post, admin):
|
||||||
assert admin.roles.filter(id=role.id).count() == 0
|
assert admin.roles.filter(id=role.id).count() == 0
|
||||||
url = reverse('api:user_roles_list', args=(admin.id,))
|
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
|
||||||
|
|
||||||
response = post(url, {'id': role.id}, admin)
|
response = post(url, {'id': role.id}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -189,7 +189,7 @@ def test_add_role_to_user(role, post, admin):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_remove_role_from_user(role, post, admin):
|
def test_remove_role_from_user(role, post, admin):
|
||||||
assert admin.roles.filter(id=role.id).count() == 0
|
assert admin.roles.filter(id=role.id).count() == 0
|
||||||
url = reverse('api:user_roles_list', args=(admin.id,))
|
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
|
||||||
response = post(url, {'id': role.id}, admin)
|
response = post(url, {'id': role.id}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
assert admin.roles.filter(id=role.id).count() == 1
|
assert admin.roles.filter(id=role.id).count() == 1
|
||||||
@ -207,7 +207,7 @@ def test_remove_role_from_user(role, post, admin):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_teams_roles_list(get, team, organization, admin):
|
def test_get_teams_roles_list(get, team, organization, admin):
|
||||||
team.member_role.children.add(organization.admin_role)
|
team.member_role.children.add(organization.admin_role)
|
||||||
url = reverse('api:team_roles_list', args=(team.id,))
|
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
roles = response.data
|
roles = response.data
|
||||||
@ -219,7 +219,7 @@ def test_get_teams_roles_list(get, team, organization, admin):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_role_to_teams(team, post, admin):
|
def test_add_role_to_teams(team, post, admin):
|
||||||
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
|
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
|
||||||
url = reverse('api:team_roles_list', args=(team.id,))
|
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
|
||||||
|
|
||||||
response = post(url, {'id': team.member_role.id}, admin)
|
response = post(url, {'id': team.member_role.id}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
@ -237,7 +237,7 @@ def test_add_role_to_teams(team, post, admin):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_remove_role_from_teams(team, post, admin):
|
def test_remove_role_from_teams(team, post, admin):
|
||||||
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
|
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
|
||||||
url = reverse('api:team_roles_list', args=(team.id,))
|
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
|
||||||
response = post(url, {'id': team.member_role.id}, admin)
|
response = post(url, {'id': team.member_role.id}, admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
assert team.member_role.children.filter(id=team.member_role.id).count() == 1
|
assert team.member_role.children.filter(id=team.member_role.id).count() == 1
|
||||||
@ -254,7 +254,7 @@ def test_remove_role_from_teams(team, post, admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_role(get, admin, role):
|
def test_get_role(get, admin, role):
|
||||||
url = reverse('api:role_detail', args=(role.id,))
|
url = reverse('api:role_detail', kwargs={'pk': role.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['id'] == role.id
|
assert response.data['id'] == role.id
|
||||||
@ -262,7 +262,7 @@ def test_get_role(get, admin, role):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_put_role_405(put, admin, role):
|
def test_put_role_405(put, admin, role):
|
||||||
url = reverse('api:role_detail', args=(role.id,))
|
url = reverse('api:role_detail', kwargs={'pk': role.id})
|
||||||
response = put(url, {'name': 'Some new name'}, admin)
|
response = put(url, {'name': 'Some new name'}, admin)
|
||||||
assert response.status_code == 405
|
assert response.status_code == 405
|
||||||
#r = Role.objects.get(id=role.id)
|
#r = Role.objects.get(id=role.id)
|
||||||
@ -271,7 +271,7 @@ def test_put_role_405(put, admin, role):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_put_role_access_denied(put, alice, role):
|
def test_put_role_access_denied(put, alice, role):
|
||||||
url = reverse('api:role_detail', args=(role.id,))
|
url = reverse('api:role_detail', kwargs={'pk': role.id})
|
||||||
response = put(url, {'name': 'Some new name'}, alice)
|
response = put(url, {'name': 'Some new name'}, alice)
|
||||||
assert response.status_code == 403 or response.status_code == 405
|
assert response.status_code == 403 or response.status_code == 405
|
||||||
|
|
||||||
@ -284,7 +284,7 @@ def test_put_role_access_denied(put, alice, role):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_role_users(get, admin, role):
|
def test_get_role_users(get, admin, role):
|
||||||
role.members.add(admin)
|
role.members.add(admin)
|
||||||
url = reverse('api:role_users_list', args=(role.id,))
|
url = reverse('api:role_users_list', kwargs={'pk': role.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
@ -293,7 +293,7 @@ def test_get_role_users(get, admin, role):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_user_to_role(post, admin, role):
|
def test_add_user_to_role(post, admin, role):
|
||||||
url = reverse('api:role_users_list', args=(role.id,))
|
url = reverse('api:role_users_list', kwargs={'pk': role.id})
|
||||||
assert role.members.filter(id=admin.id).count() == 0
|
assert role.members.filter(id=admin.id).count() == 0
|
||||||
post(url, {'id': admin.id}, admin)
|
post(url, {'id': admin.id}, admin)
|
||||||
assert role.members.filter(id=admin.id).count() == 1
|
assert role.members.filter(id=admin.id).count() == 1
|
||||||
@ -302,7 +302,7 @@ def test_add_user_to_role(post, admin, role):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_remove_user_to_role(post, admin, role):
|
def test_remove_user_to_role(post, admin, role):
|
||||||
role.members.add(admin)
|
role.members.add(admin)
|
||||||
url = reverse('api:role_users_list', args=(role.id,))
|
url = reverse('api:role_users_list', kwargs={'pk': role.id})
|
||||||
assert role.members.filter(id=admin.id).count() == 1
|
assert role.members.filter(id=admin.id).count() == 1
|
||||||
post(url, {'disassociate': True, 'id': admin.id}, admin)
|
post(url, {'disassociate': True, 'id': admin.id}, admin)
|
||||||
assert role.members.filter(id=admin.id).count() == 0
|
assert role.members.filter(id=admin.id).count() == 0
|
||||||
@ -318,7 +318,7 @@ def test_org_admin_add_user_to_job_template(post, organization, check_jobtemplat
|
|||||||
assert org_admin in check_jobtemplate.admin_role
|
assert org_admin in check_jobtemplate.admin_role
|
||||||
assert joe not in check_jobtemplate.execute_role
|
assert joe not in check_jobtemplate.execute_role
|
||||||
|
|
||||||
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, org_admin)
|
post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'id': joe.id}, org_admin)
|
||||||
assert joe in check_jobtemplate.execute_role
|
assert joe in check_jobtemplate.execute_role
|
||||||
|
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ def test_org_admin_remove_user_from_job_template(post, organization, check_jobte
|
|||||||
assert org_admin in check_jobtemplate.admin_role
|
assert org_admin in check_jobtemplate.admin_role
|
||||||
assert joe in check_jobtemplate.execute_role
|
assert joe in check_jobtemplate.execute_role
|
||||||
|
|
||||||
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, org_admin)
|
post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'disassociate': True, 'id': joe.id}, org_admin)
|
||||||
assert joe not in check_jobtemplate.execute_role
|
assert joe not in check_jobtemplate.execute_role
|
||||||
|
|
||||||
|
|
||||||
@ -347,7 +347,7 @@ def test_user_fail_to_add_user_to_job_template(post, organization, check_jobtemp
|
|||||||
assert joe not in check_jobtemplate.execute_role
|
assert joe not in check_jobtemplate.execute_role
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, rando)
|
res = post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'id': joe.id}, rando)
|
||||||
assert res.status_code == 403
|
assert res.status_code == 403
|
||||||
|
|
||||||
assert joe not in check_jobtemplate.execute_role
|
assert joe not in check_jobtemplate.execute_role
|
||||||
@ -364,7 +364,7 @@ def test_user_fail_to_remove_user_to_job_template(post, organization, check_jobt
|
|||||||
assert joe in check_jobtemplate.execute_role
|
assert joe in check_jobtemplate.execute_role
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, rando)
|
res = post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'disassociate': True, 'id': joe.id}, rando)
|
||||||
assert res.status_code == 403
|
assert res.status_code == 403
|
||||||
|
|
||||||
assert joe in check_jobtemplate.execute_role
|
assert joe in check_jobtemplate.execute_role
|
||||||
@ -378,7 +378,7 @@ def test_user_fail_to_remove_user_to_job_template(post, organization, check_jobt
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_get_role_teams(get, team, admin, role):
|
def test_get_role_teams(get, team, admin, role):
|
||||||
role.parents.add(team.member_role)
|
role.parents.add(team.member_role)
|
||||||
url = reverse('api:role_teams_list', args=(role.id,))
|
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
@ -387,7 +387,7 @@ def test_get_role_teams(get, team, admin, role):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_add_team_to_role(post, team, admin, role):
|
def test_add_team_to_role(post, team, admin, role):
|
||||||
url = reverse('api:role_teams_list', args=(role.id,))
|
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
|
||||||
assert role.members.filter(id=admin.id).count() == 0
|
assert role.members.filter(id=admin.id).count() == 0
|
||||||
res = post(url, {'id': team.id}, admin)
|
res = post(url, {'id': team.id}, admin)
|
||||||
assert res.status_code == 204
|
assert res.status_code == 204
|
||||||
@ -397,7 +397,7 @@ def test_add_team_to_role(post, team, admin, role):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_remove_team_from_role(post, team, admin, role):
|
def test_remove_team_from_role(post, team, admin, role):
|
||||||
role.members.add(admin)
|
role.members.add(admin)
|
||||||
url = reverse('api:role_teams_list', args=(role.id,))
|
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
|
||||||
assert role.members.filter(id=admin.id).count() == 1
|
assert role.members.filter(id=admin.id).count() == 1
|
||||||
res = post(url, {'disassociate': True, 'id': team.id}, admin)
|
res = post(url, {'disassociate': True, 'id': team.id}, admin)
|
||||||
assert res.status_code == 204
|
assert res.status_code == 204
|
||||||
@ -412,7 +412,7 @@ def test_remove_team_from_role(post, team, admin, role):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_role_parents(get, team, admin, role):
|
def test_role_parents(get, team, admin, role):
|
||||||
role.parents.add(team.member_role)
|
role.parents.add(team.member_role)
|
||||||
url = reverse('api:role_parents_list', args=(role.id,))
|
url = reverse('api:role_parents_list', kwargs={'pk': role.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 1
|
assert response.data['count'] == 1
|
||||||
@ -427,7 +427,7 @@ def test_role_parents(get, team, admin, role):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_role_children(get, team, admin, role):
|
def test_role_children(get, team, admin, role):
|
||||||
role.parents.add(team.member_role)
|
role.parents.add(team.member_role)
|
||||||
url = reverse('api:role_children_list', args=(team.member_role.id,))
|
url = reverse('api:role_children_list', kwargs={'pk': team.member_role.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['count'] == 2
|
assert response.data['count'] == 2
|
||||||
@ -441,7 +441,7 @@ def test_role_children(get, team, admin, role):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_ensure_rbac_fields_are_present(organization, get, admin):
|
def test_ensure_rbac_fields_are_present(organization, get, admin):
|
||||||
url = reverse('api:organization_detail', args=(organization.id,))
|
url = reverse('api:organization_detail', kwargs={'pk': organization.id})
|
||||||
response = get(url, admin)
|
response = get(url, admin)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
org = response.data
|
org = response.data
|
||||||
@ -450,7 +450,7 @@ def test_ensure_rbac_fields_are_present(organization, get, admin):
|
|||||||
assert 'object_roles' in org['summary_fields']
|
assert 'object_roles' in org['summary_fields']
|
||||||
|
|
||||||
role_pk = org['summary_fields']['object_roles']['admin_role']['id']
|
role_pk = org['summary_fields']['object_roles']['admin_role']['id']
|
||||||
role_url = reverse('api:role_detail', args=(role_pk,))
|
role_url = reverse('api:role_detail', kwargs={'pk': role_pk})
|
||||||
org_role_response = get(role_url, admin)
|
org_role_response = get(role_url, admin)
|
||||||
|
|
||||||
assert org_role_response.status_code == 200
|
assert org_role_response.status_code == 200
|
||||||
@ -460,7 +460,7 @@ def test_ensure_rbac_fields_are_present(organization, get, admin):
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_ensure_role_summary_is_present(organization, get, user):
|
def test_ensure_role_summary_is_present(organization, get, user):
|
||||||
url = reverse('api:organization_detail', args=(organization.id,))
|
url = reverse('api:organization_detail', kwargs={'pk': organization.id})
|
||||||
response = get(url, user('admin', True))
|
response = get(url, user('admin', True))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
org = response.data
|
org = response.data
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
from awx.main.access import (
|
from awx.main.access import (
|
||||||
BaseAccess,
|
BaseAccess,
|
||||||
JobTemplateAccess,
|
JobTemplateAccess,
|
||||||
@ -12,7 +13,6 @@ from awx.main.models.jobs import JobTemplate
|
|||||||
from awx.main.models.schedules import Schedule
|
from awx.main.models.schedules import Schedule
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -250,7 +250,7 @@ def test_job_template_creator_access(project, rando, post):
|
|||||||
with mock.patch(
|
with mock.patch(
|
||||||
'awx.main.models.projects.ProjectOptions.playbooks',
|
'awx.main.models.projects.ProjectOptions.playbooks',
|
||||||
new_callable=mock.PropertyMock(return_value=['helloworld.yml'])):
|
new_callable=mock.PropertyMock(return_value=['helloworld.yml'])):
|
||||||
response = post(reverse('api:job_template_list', args=[]), dict(
|
response = post(reverse('api:job_template_list'), dict(
|
||||||
name='newly-created-jt',
|
name='newly-created-jt',
|
||||||
job_type='run',
|
job_type='run',
|
||||||
ask_inventory_on_launch=True,
|
ask_inventory_on_launch=True,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import pytest
|
|||||||
def get_related_assert():
|
def get_related_assert():
|
||||||
def fn(model_obj, related, resource_name, related_resource_name):
|
def fn(model_obj, related, resource_name, related_resource_name):
|
||||||
assert related_resource_name in related
|
assert related_resource_name in related
|
||||||
assert related[related_resource_name] == '/api/v1/%s/%d/%s/' % (resource_name, model_obj.pk, related_resource_name)
|
assert related[related_resource_name] == '/api/v2/%s/%d/%s/' % (resource_name, model_obj.pk, related_resource_name)
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,7 @@ class TestJobSerializerGetRelated():
|
|||||||
def test_job_template_present(self, get_related_mock_and_run, job):
|
def test_job_template_present(self, get_related_mock_and_run, job):
|
||||||
related = get_related_mock_and_run(JobSerializer, job)
|
related = get_related_mock_and_run(JobSerializer, job)
|
||||||
assert 'job_template' in related
|
assert 'job_template' in related
|
||||||
assert related['job_template'] == '/api/v1/%s/%d/' % ('job_templates', job.job_template.pk)
|
assert related['job_template'] == '/api/v2/%s/%d/' % ('job_templates', job.job_template.pk)
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('awx.api.serializers.BaseSerializer.to_representation', lambda self,obj: {
|
@mock.patch('awx.api.serializers.BaseSerializer.to_representation', lambda self,obj: {
|
||||||
|
|||||||
@ -104,7 +104,7 @@ class TestJobTemplateSerializerGetSummaryFields():
|
|||||||
serializer.show_capabilities = ['copy', 'edit']
|
serializer.show_capabilities = ['copy', 'edit']
|
||||||
serializer._summary_field_labels = lambda self: []
|
serializer._summary_field_labels = lambda self: []
|
||||||
serializer._recent_jobs = lambda self: []
|
serializer._recent_jobs = lambda self: []
|
||||||
request = APIRequestFactory().get('/api/v1/job_templates/42/')
|
request = APIRequestFactory().get('/api/v2/job_templates/42/')
|
||||||
request.user = user
|
request.user = user
|
||||||
view = JobTemplateDetail()
|
view = JobTemplateDetail()
|
||||||
view.request = request
|
view.request = request
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class TestWorkflowNodeBaseSerializerGetRelated():
|
|||||||
def test_workflow_unified_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
|
def test_workflow_unified_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
|
||||||
related = get_related_mock_and_run(WorkflowNodeBaseSerializer, workflow_job_template_node_related)
|
related = get_related_mock_and_run(WorkflowNodeBaseSerializer, workflow_job_template_node_related)
|
||||||
assert 'unified_job_template' in related
|
assert 'unified_job_template' in related
|
||||||
assert related['unified_job_template'] == '/api/v1/%s/%d/' % ('job_templates', workflow_job_template_node_related.unified_job_template.pk)
|
assert related['unified_job_template'] == '/api/v2/%s/%d/' % ('job_templates', workflow_job_template_node_related.unified_job_template.pk)
|
||||||
|
|
||||||
def test_workflow_unified_job_template_absent(self, workflow_job_template_node):
|
def test_workflow_unified_job_template_absent(self, workflow_job_template_node):
|
||||||
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
|
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
|
||||||
@ -100,7 +100,7 @@ class TestWorkflowJobTemplateNodeSerializerGetRelated():
|
|||||||
def test_workflow_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
|
def test_workflow_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
|
||||||
related = get_related_mock_and_run(WorkflowJobTemplateNodeSerializer, workflow_job_template_node_related)
|
related = get_related_mock_and_run(WorkflowJobTemplateNodeSerializer, workflow_job_template_node_related)
|
||||||
assert 'workflow_job_template' in related
|
assert 'workflow_job_template' in related
|
||||||
assert related['workflow_job_template'] == '/api/v1/%s/%d/' % ('workflow_job_templates', workflow_job_template_node_related.workflow_job_template.pk)
|
assert related['workflow_job_template'] == '/api/v2/%s/%d/' % ('workflow_job_templates', workflow_job_template_node_related.workflow_job_template.pk)
|
||||||
|
|
||||||
def test_workflow_job_template_absent(self, workflow_job_template_node):
|
def test_workflow_job_template_absent(self, workflow_job_template_node):
|
||||||
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
|
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
|
||||||
@ -179,7 +179,7 @@ class TestWorkflowJobNodeSerializerGetRelated():
|
|||||||
def test_workflow_job_present(self, get_related_mock_and_run, workflow_job_node_related):
|
def test_workflow_job_present(self, get_related_mock_and_run, workflow_job_node_related):
|
||||||
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
|
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
|
||||||
assert 'workflow_job' in related
|
assert 'workflow_job' in related
|
||||||
assert related['workflow_job'] == '/api/v1/%s/%d/' % ('workflow_jobs', workflow_job_node_related.workflow_job.pk)
|
assert related['workflow_job'] == '/api/v2/%s/%d/' % ('workflow_jobs', workflow_job_node_related.workflow_job.pk)
|
||||||
|
|
||||||
def test_workflow_job_absent(self, workflow_job_node):
|
def test_workflow_job_absent(self, workflow_job_node):
|
||||||
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)
|
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)
|
||||||
@ -188,7 +188,7 @@ class TestWorkflowJobNodeSerializerGetRelated():
|
|||||||
def test_job_present(self, get_related_mock_and_run, workflow_job_node_related):
|
def test_job_present(self, get_related_mock_and_run, workflow_job_node_related):
|
||||||
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
|
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
|
||||||
assert 'job' in related
|
assert 'job' in related
|
||||||
assert related['job'] == '/api/v1/%s/%d/' % ('jobs', workflow_job_node_related.job.pk)
|
assert related['job'] == '/api/v2/%s/%d/' % ('jobs', workflow_job_node_related.job.pk)
|
||||||
|
|
||||||
def test_job_absent(self, workflow_job_node):
|
def test_job_absent(self, workflow_job_node):
|
||||||
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)
|
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)
|
||||||
|
|||||||
@ -7,10 +7,19 @@ from awx.api.filters import FieldLookupBackend
|
|||||||
from awx.main.models import (AdHocCommand, AuthToken, CustomInventoryScript,
|
from awx.main.models import (AdHocCommand, AuthToken, CustomInventoryScript,
|
||||||
Credential, Job, JobTemplate, SystemJob,
|
Credential, Job, JobTemplate, SystemJob,
|
||||||
UnifiedJob, User, WorkflowJob,
|
UnifiedJob, User, WorkflowJob,
|
||||||
WorkflowJobTemplate, WorkflowJobOptions)
|
WorkflowJobTemplate, WorkflowJobOptions,
|
||||||
|
InventorySource)
|
||||||
from awx.main.models.jobs import JobOptions
|
from awx.main.models.jobs import JobOptions
|
||||||
|
|
||||||
|
|
||||||
|
def test_related():
|
||||||
|
field_lookup = FieldLookupBackend()
|
||||||
|
lookup = '__'.join(['inventory', 'organization', 'pk'])
|
||||||
|
field, new_lookup = field_lookup.get_field_from_lookup(InventorySource, lookup)
|
||||||
|
print(field)
|
||||||
|
print(new_lookup)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(u"empty_value", [u'', ''])
|
@pytest.mark.parametrize(u"empty_value", [u'', ''])
|
||||||
def test_empty_in(empty_value):
|
def test_empty_in(empty_value):
|
||||||
field_lookup = FieldLookupBackend()
|
field_lookup = FieldLookupBackend()
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import pytest
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
ApiV1RootView,
|
ApiVersionRootView,
|
||||||
JobTemplateLabelList,
|
JobTemplateLabelList,
|
||||||
JobTemplateSurveySpec,
|
JobTemplateSurveySpec,
|
||||||
)
|
)
|
||||||
@ -17,7 +17,7 @@ def mock_response_new(mocker):
|
|||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
class TestApiV1RootView:
|
class TestApiRootView:
|
||||||
def test_get_endpoints(self, mocker, mock_response_new):
|
def test_get_endpoints(self, mocker, mock_response_new):
|
||||||
endpoints = [
|
endpoints = [
|
||||||
'authtoken',
|
'authtoken',
|
||||||
@ -51,7 +51,7 @@ class TestApiV1RootView:
|
|||||||
'workflow_job_templates',
|
'workflow_job_templates',
|
||||||
'workflow_jobs',
|
'workflow_jobs',
|
||||||
]
|
]
|
||||||
view = ApiV1RootView()
|
view = ApiVersionRootView()
|
||||||
ret = view.get(mocker.MagicMock())
|
ret = view.get(mocker.MagicMock())
|
||||||
|
|
||||||
assert ret == mock_response_new
|
assert ret == mock_response_new
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import json
|
|||||||
from awx.main.tasks import RunJob
|
from awx.main.tasks import RunJob
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
Job,
|
Job,
|
||||||
|
JobTemplate,
|
||||||
WorkflowJobTemplate
|
WorkflowJobTemplate
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -78,6 +79,18 @@ def test_job_args_unredacted_passwords(job):
|
|||||||
assert extra_vars['secret_key'] == 'my_password'
|
assert extra_vars['secret_key'] == 'my_password'
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_kwargs_survey_invalid_default(survey_spec_factory):
|
||||||
|
spec = survey_spec_factory('var2')
|
||||||
|
spec['spec'][0]['required'] = False
|
||||||
|
spec['spec'][0]['min'] = 3
|
||||||
|
spec['spec'][0]['default'] = 1
|
||||||
|
jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True, extra_vars="var2: 2")
|
||||||
|
defaulted_extra_vars = jt._update_unified_job_kwargs()
|
||||||
|
assert 'extra_vars' in defaulted_extra_vars
|
||||||
|
# Make sure we did not set the invalid default of 1
|
||||||
|
assert json.loads(defaulted_extra_vars['extra_vars'])['var2'] == 2
|
||||||
|
|
||||||
|
|
||||||
class TestWorkflowSurveys:
|
class TestWorkflowSurveys:
|
||||||
def test_update_kwargs_survey_defaults(self, survey_spec_factory):
|
def test_update_kwargs_survey_defaults(self, survey_spec_factory):
|
||||||
"Assure that the survey default over-rides a JT variable"
|
"Assure that the survey default over-rides a JT variable"
|
||||||
|
|||||||
81
awx/main/tests/unit/test_fields.py
Normal file
81
awx/main/tests/unit/test_fields.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
# Python
|
||||||
|
import pytest
|
||||||
|
from pyparsing import ParseException
|
||||||
|
|
||||||
|
# AWX
|
||||||
|
from awx.main.fields import DynamicFilterField
|
||||||
|
|
||||||
|
# Django
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
|
class TestDynamicFilterFieldFilterStringToQ():
|
||||||
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
|
('facts__facts__blank=""', Q(facts__facts__blank="")),
|
||||||
|
('"facts__facts__ space "="f"', Q(**{ "facts__facts__ space ": "f"})),
|
||||||
|
('"facts__facts__ e "=no_quotes_here', Q(**{ "facts__facts__ e ": "no_quotes_here"})),
|
||||||
|
('a__b__c=3', Q(**{ "a__b__c": 3})),
|
||||||
|
('a__b__c=3.14', Q(**{ "a__b__c": 3.14})),
|
||||||
|
('a__b__c=true', Q(**{ "a__b__c": True})),
|
||||||
|
('a__b__c=false', Q(**{ "a__b__c": False})),
|
||||||
|
('a__b__c="true"', Q(**{ "a__b__c": "true"})),
|
||||||
|
#('"a__b\"__c"="true"', Q(**{ "a__b\"__c": "true"})),
|
||||||
|
#('a__b\"__c="true"', Q(**{ "a__b\"__c": "true"})),
|
||||||
|
])
|
||||||
|
def test_query_generated(self, filter_string, q_expected):
|
||||||
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
assert str(q) == str(q_expected)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filter_string", [
|
||||||
|
'facts__facts__blank='
|
||||||
|
'a__b__c__ space =ggg',
|
||||||
|
])
|
||||||
|
def test_invalid_filter_strings(self, filter_string):
|
||||||
|
with pytest.raises(ParseException):
|
||||||
|
DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
|
(u'(a=abc\u1F5E3def)', Q(**{u"a": u"abc\u1F5E3def"})),
|
||||||
|
])
|
||||||
|
def test_unicode(self, filter_string, q_expected):
|
||||||
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
assert str(q) == str(q_expected)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
|
('(a=b)', Q(**{"a": "b"})),
|
||||||
|
('a=b and c=d', Q(**{"a": "b"}) & Q(**{"c": "d"})),
|
||||||
|
('(a=b and c=d)', Q(**{"a": "b"}) & Q(**{"c": "d"})),
|
||||||
|
('a=b or c=d', Q(**{"a": "b"}) | Q(**{"c": "d"})),
|
||||||
|
('(a=b and c=d) or (e=f)', (Q(**{"a": "b"}) & Q(**{"c": "d"})) | (Q(**{"e": "f"}))),
|
||||||
|
('(a=b) and (c=d or (e=f and (g=h or i=j))) or (y=z)', Q(**{"a": "b"}) & (Q(**{"c": "d"}) | (Q(**{"e": "f"}) & (Q(**{"g": "h"}) | Q(**{"i": "j"})))) | Q(**{"y": "z"}))
|
||||||
|
])
|
||||||
|
def test_boolean_parenthesis(self, filter_string, q_expected):
|
||||||
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
assert str(q) == str(q_expected)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
|
('a__b__c[]=3', Q(**{ "a__b__c__contains": 3})),
|
||||||
|
('a__b__c[]=3.14', Q(**{ "a__b__c__contains": 3.14})),
|
||||||
|
('a__b__c[]=true', Q(**{ "a__b__c__contains": True})),
|
||||||
|
('a__b__c[]=false', Q(**{ "a__b__c__contains": False})),
|
||||||
|
('a__b__c[]="true"', Q(**{ "a__b__c__contains": "true"})),
|
||||||
|
('a__b__c[]__d[]="foobar"', Q(**{ "a__b__c__contains": [{"d": ["foobar"]}]})),
|
||||||
|
('a__b__c[]__d="foobar"', Q(**{ "a__b__c__contains": [{"d": "foobar"}]})),
|
||||||
|
('a__b__c[]__d__e="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": "foobar"}}]})),
|
||||||
|
('a__b__c[]__d__e[]="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": ["foobar"]}}]})),
|
||||||
|
('a__b__c[]__d__e__f[]="foobar"', Q(**{ "a__b__c__contains": [{"d": {"e": {"f": ["foobar"]}}}]})),
|
||||||
|
('(a__b__c[]__d__e__f[]="foobar") and (a__b__c[]__d__e[]="foobar")', Q(**{ "a__b__c__contains": [{"d": {"e": {"f": ["foobar"]}}}]}) & Q(**{ "a__b__c__contains": [{"d": {"e": ["foobar"]}}]})),
|
||||||
|
#('"a__b\"__c"="true"', Q(**{ "a__b\"__c": "true"})),
|
||||||
|
#('a__b\"__c="true"', Q(**{ "a__b\"__c": "true"})),
|
||||||
|
])
|
||||||
|
def test_contains_query_generated(self, filter_string, q_expected):
|
||||||
|
q = DynamicFilterField.filter_string_to_q(filter_string)
|
||||||
|
assert str(q) == str(q_expected)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
#('"facts__quoted_val"="f\"oo"', 1),
|
||||||
|
#('facts__facts__arr[]="foo"', 1),
|
||||||
|
#('facts__facts__arr_nested[]__a[]="foo"', 1),
|
||||||
|
'''
|
||||||
@ -2,10 +2,12 @@ from contextlib import contextmanager
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
import mock
|
||||||
|
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
UnifiedJob,
|
UnifiedJob,
|
||||||
Notification,
|
Notification,
|
||||||
|
ProjectUpdate
|
||||||
)
|
)
|
||||||
|
|
||||||
from awx.main import tasks
|
from awx.main import tasks
|
||||||
@ -31,6 +33,13 @@ def test_send_notifications_job_id(mocker):
|
|||||||
assert UnifiedJob.objects.get.called_with(id=1)
|
assert UnifiedJob.objects.get.called_with(id=1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_work_success_callback_missing_job():
|
||||||
|
task_data = {'type': 'project_update', 'id': 9999}
|
||||||
|
with mock.patch('django.db.models.query.QuerySet.get') as get_mock:
|
||||||
|
get_mock.side_effect = ProjectUpdate.DoesNotExist()
|
||||||
|
assert tasks.handle_work_success(None, task_data) is None
|
||||||
|
|
||||||
|
|
||||||
def test_send_notifications_list(mocker):
|
def test_send_notifications_list(mocker):
|
||||||
patches = list()
|
patches = list()
|
||||||
|
|
||||||
|
|||||||
@ -147,7 +147,17 @@ def test_https_logging_handler_splunk_auth_info():
|
|||||||
('http://localhost', None, 'http://localhost'),
|
('http://localhost', None, 'http://localhost'),
|
||||||
('http://localhost', 80, 'http://localhost'),
|
('http://localhost', 80, 'http://localhost'),
|
||||||
('http://localhost', 8080, 'http://localhost:8080'),
|
('http://localhost', 8080, 'http://localhost:8080'),
|
||||||
('https://localhost', 443, 'https://localhost:443')
|
('https://localhost', 443, 'https://localhost:443'),
|
||||||
|
('ftp://localhost', 443, 'ftp://localhost:443'),
|
||||||
|
('https://localhost:550', 443, 'https://localhost:550'),
|
||||||
|
('https://localhost:yoho/foobar', 443, 'https://localhost:443/foobar'),
|
||||||
|
('https://localhost:yoho/foobar', None, 'https://localhost:yoho/foobar'),
|
||||||
|
('http://splunk.server:8088/services/collector/event', 80,
|
||||||
|
'http://splunk.server:8088/services/collector/event'),
|
||||||
|
('http://splunk.server/services/collector/event', 80,
|
||||||
|
'http://splunk.server/services/collector/event'),
|
||||||
|
('http://splunk.server/services/collector/event', 8088,
|
||||||
|
'http://splunk.server:8088/services/collector/event'),
|
||||||
])
|
])
|
||||||
def test_https_logging_handler_http_host_format(host, port, normalized):
|
def test_https_logging_handler_http_host_format(host, port, normalized):
|
||||||
handler = HTTPSHandler(host=host, port=port)
|
handler = HTTPSHandler(host=host, port=port)
|
||||||
|
|||||||
@ -12,7 +12,6 @@ from awx.main.utils.common import ( # noqa
|
|||||||
encrypt_field,
|
encrypt_field,
|
||||||
parse_yaml_or_json,
|
parse_yaml_or_json,
|
||||||
decrypt_field,
|
decrypt_field,
|
||||||
build_url,
|
|
||||||
timestamp_apiformat,
|
timestamp_apiformat,
|
||||||
model_instance_diff,
|
model_instance_diff,
|
||||||
model_to_dict,
|
model_to_dict,
|
||||||
|
|||||||
@ -31,7 +31,6 @@ from django.db.models import ManyToManyField
|
|||||||
from rest_framework.exceptions import ParseError, PermissionDenied
|
from rest_framework.exceptions import ParseError, PermissionDenied
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
||||||
# PyCrypto
|
# PyCrypto
|
||||||
@ -736,14 +735,6 @@ def get_pk_from_dict(_dict, key):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def build_url(*args, **kwargs):
|
|
||||||
get = kwargs.pop('get', {})
|
|
||||||
url = reverse(*args, **kwargs)
|
|
||||||
if get:
|
|
||||||
url += '?' + urllib.urlencode(get)
|
|
||||||
return url
|
|
||||||
|
|
||||||
|
|
||||||
def timestamp_apiformat(timestamp):
|
def timestamp_apiformat(timestamp):
|
||||||
timestamp = timestamp.isoformat()
|
timestamp = timestamp.isoformat()
|
||||||
if timestamp.endswith('+00:00'):
|
if timestamp.endswith('+00:00'):
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import logging
|
|||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
|
import urlparse
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
@ -148,10 +149,21 @@ class BaseHTTPSHandler(logging.Handler):
|
|||||||
|
|
||||||
def get_http_host(self):
|
def get_http_host(self):
|
||||||
host = self.host or ''
|
host = self.host or ''
|
||||||
if not host.startswith('http'):
|
# urlparse requires scheme to be provided, default to use http if
|
||||||
host = 'http://%s' % self.host
|
# missing
|
||||||
if self.port != 80 and self.port is not None:
|
if not urlparse.urlsplit(host).scheme:
|
||||||
host = '%s:%s' % (host, str(self.port))
|
host = 'http://%s' % host
|
||||||
|
parsed = urlparse.urlsplit(host)
|
||||||
|
# Insert self.port if its special and port number is either not
|
||||||
|
# given in host or given as non-numerical
|
||||||
|
try:
|
||||||
|
port = parsed.port or self.port
|
||||||
|
except ValueError:
|
||||||
|
port = self.port
|
||||||
|
if port not in (80, None):
|
||||||
|
new_netloc = '%s:%s' % (parsed.hostname, port)
|
||||||
|
return urlparse.urlunsplit((parsed.scheme, new_netloc, parsed.path,
|
||||||
|
parsed.query, parsed.fragment))
|
||||||
return host
|
return host
|
||||||
|
|
||||||
def get_post_kwargs(self, payload_input):
|
def get_post_kwargs(self, payload_input):
|
||||||
|
|||||||
@ -108,8 +108,8 @@
|
|||||||
- name: update project using insights
|
- name: update project using insights
|
||||||
uri:
|
uri:
|
||||||
url: "{{insights_url}}/r/insights/v1/maintenance?ansible=true"
|
url: "{{insights_url}}/r/insights/v1/maintenance?ansible=true"
|
||||||
user: "{{scm_username|quote}}"
|
user: "{{scm_username}}"
|
||||||
password: "{{scm_password|quote}}"
|
password: "{{scm_password}}"
|
||||||
force_basic_auth: yes
|
force_basic_auth: yes
|
||||||
when: scm_type == 'insights'
|
when: scm_type == 'insights'
|
||||||
register: insights_output
|
register: insights_output
|
||||||
@ -124,8 +124,8 @@
|
|||||||
get_url:
|
get_url:
|
||||||
url: "{{insights_url}}/r/insights/v3/maintenance/{{item.maintenance_id}}/playbook"
|
url: "{{insights_url}}/r/insights/v3/maintenance/{{item.maintenance_id}}/playbook"
|
||||||
dest: "{{project_path|quote}}/{{item.name}}-{{item.maintenance_id}}.yml"
|
dest: "{{project_path|quote}}/{{item.name}}-{{item.maintenance_id}}.yml"
|
||||||
url_username: "{{scm_username|quote}}"
|
url_username: "{{scm_username}}"
|
||||||
url_password: "{{scm_password|quote}}"
|
url_password: "{{scm_password}}"
|
||||||
force_basic_auth: yes
|
force_basic_auth: yes
|
||||||
force: yes
|
force: yes
|
||||||
when: scm_type == 'insights' and item.name != None
|
when: scm_type == 'insights' and item.name != None
|
||||||
@ -136,8 +136,8 @@
|
|||||||
get_url:
|
get_url:
|
||||||
url: "{{insights_url}}/r/insights/v3/maintenance/{{item.maintenance_id}}/playbook"
|
url: "{{insights_url}}/r/insights/v3/maintenance/{{item.maintenance_id}}/playbook"
|
||||||
dest: "{{project_path|quote}}/insights-plan-{{item.maintenance_id}}.yml"
|
dest: "{{project_path|quote}}/insights-plan-{{item.maintenance_id}}.yml"
|
||||||
url_username: "{{scm_username|quote}}"
|
url_username: "{{scm_username}}"
|
||||||
url_password: "{{scm_password|quote}}"
|
url_password: "{{scm_password}}"
|
||||||
force_basic_auth: yes
|
force_basic_auth: yes
|
||||||
force: yes
|
force: yes
|
||||||
when: scm_type == 'insights' and item.name == None
|
when: scm_type == 'insights' and item.name == None
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbar-collapse">
|
<div class="collapse navbar-collapse" id="navbar-collapse">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li><a href="{% url 'api:user_me_list' %}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Logged in as {{ user }}{% if user.get_full_name %} ({{ user.get_full_name }}){% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="visible-xs-inline">Logged in as </span>{{ user }}{% if user.get_full_name %}<span class="visible-xs-inline"> ({{ user.get_full_name }})</span>{% endif %}</a></li>
|
<li><a href="{% url 'api:user_me_list' version=request.version %}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Logged in as {{ user }}{% if user.get_full_name %} ({{ user.get_full_name }}){% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="visible-xs-inline">Logged in as </span>{{ user }}{% if user.get_full_name %}<span class="visible-xs-inline"> ({{ user.get_full_name }})</span>{% endif %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Ansible Tower API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'Ansible Tower API Guide' %}</span></a></li>
|
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Ansible Tower API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'Ansible Tower API Guide' %}</span></a></li>
|
||||||
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to Ansible Tower' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to Ansible Tower' %}</span></a></li>
|
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to Ansible Tower' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to Ansible Tower' %}</span></a></li>
|
||||||
|
|||||||
@ -474,6 +474,20 @@ input[type='radio']:checked:before {
|
|||||||
outline:none;
|
outline:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Form-inputLabelContainer {
|
||||||
|
width: 100%;
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Form-inputLabelContainer[for=variables] {
|
||||||
|
width: auto;
|
||||||
|
display: inline-block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Form-mixedInputGroup {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.FormToggle {}
|
.FormToggle {}
|
||||||
.FormToggle-container {
|
.FormToggle-container {
|
||||||
margin: 0 0 0 10px;
|
margin: 0 0 0 10px;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ table, tbody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.List-well {
|
.List-well {
|
||||||
margin-top: 25px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.List-table{
|
.List-table{
|
||||||
@ -118,14 +118,12 @@ table, tbody {
|
|||||||
|
|
||||||
.List-header {
|
.List-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 34px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.List-title {
|
.List-title {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 34px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.List-titleBadge {
|
.List-titleBadge {
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<span class="HostEvent-title">{{event.host_name}}</span>
|
<span class="HostEvent-title">{{event.host_name}}</span>
|
||||||
<!-- close -->
|
<!-- close -->
|
||||||
<button ui-sref="jobResult" type="button" class="close">
|
<button ng-click="closeHostEvent()" type="button" class="close">
|
||||||
<i class="fa fa-times-circle"></i>
|
<i class="fa fa-times-circle"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<!-- controls -->
|
<!-- controls -->
|
||||||
<div class="HostEvent-controls">
|
<div class="HostEvent-controls">
|
||||||
<button ui-sref="jobResult" class="btn btn-sm btn-default HostEvent-close">Close</button>
|
<button ng-click="closeHostEvent()" class="btn btn-sm btn-default HostEvent-close">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -19,7 +19,8 @@
|
|||||||
var container = document.getElementById(el);
|
var container = document.getElementById(el);
|
||||||
var editor = CodeMirror.fromTextArea(container, { // jshint ignore:line
|
var editor = CodeMirror.fromTextArea(container, { // jshint ignore:line
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
mode: mode
|
mode: mode,
|
||||||
|
readOnly: true
|
||||||
});
|
});
|
||||||
editor.setSize("100%", 200);
|
editor.setSize("100%", 200);
|
||||||
editor.getDoc().setValue(data);
|
editor.getDoc().setValue(data);
|
||||||
@ -29,6 +30,19 @@
|
|||||||
return $state.current.name === name;
|
return $state.current.name === name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.getActiveHostIndex = function(){
|
||||||
|
var result = $scope.hostResults.filter(function( obj ) {
|
||||||
|
return obj.id === $scope.event.id;
|
||||||
|
});
|
||||||
|
return $scope.hostResults.indexOf(result[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.closeHostEvent = function() {
|
||||||
|
// Unbind the listener so it doesn't fire when we close the modal via navigation
|
||||||
|
$('#HostEvent').off('hidden.bs.modal');
|
||||||
|
$state.go('jobDetail');
|
||||||
|
};
|
||||||
|
|
||||||
var init = function(){
|
var init = function(){
|
||||||
hostEvent.event_name = hostEvent.event;
|
hostEvent.event_name = hostEvent.event;
|
||||||
$scope.event = _.cloneDeep(hostEvent);
|
$scope.event = _.cloneDeep(hostEvent);
|
||||||
@ -81,6 +95,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$('#HostEvent').modal('show');
|
$('#HostEvent').modal('show');
|
||||||
|
|
||||||
|
$('#HostEvent').on('hidden.bs.modal', function () {
|
||||||
|
$scope.closeHostEvent();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
init();
|
init();
|
||||||
}];
|
}];
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
.HostStatusBar-tooltipBadge {
|
.HostStatusBar-tooltipBadge {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
border: 1px solid @default-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.HostStatusBar-tooltipBadge--ok {
|
.HostStatusBar-tooltipBadge--ok {
|
||||||
|
|||||||
@ -38,7 +38,8 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
|
|||||||
|
|
||||||
// used for tag search
|
// used for tag search
|
||||||
$scope.list = {
|
$scope.list = {
|
||||||
basePath: jobData.related.job_events
|
basePath: jobData.related.job_events,
|
||||||
|
name: 'job_events'
|
||||||
};
|
};
|
||||||
|
|
||||||
// used for tag search
|
// used for tag search
|
||||||
@ -450,13 +451,6 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
|
|||||||
var getSkeleton = function(url) {
|
var getSkeleton = function(url) {
|
||||||
jobResultsService.getEvents(url)
|
jobResultsService.getEvents(url)
|
||||||
.then(events => {
|
.then(events => {
|
||||||
// old job check: if the job is complete, there is result stdout, and
|
|
||||||
// there are no job events, it's an old job
|
|
||||||
if ($scope.jobFinished) {
|
|
||||||
$scope.showLegacyJobErrorMessage = $scope.job.result_stdout.length &&
|
|
||||||
!events.results.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.results.forEach(event => {
|
events.results.forEach(event => {
|
||||||
if (event.start_line === 0 && event.end_line === 0) {
|
if (event.start_line === 0 && event.end_line === 0) {
|
||||||
$scope.isOld++;
|
$scope.isOld++;
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
.License-container{
|
.License-container{
|
||||||
.OnePlusTwo-container;
|
.OnePlusTwo-container;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.License-container--missing {
|
.License-container--missing {
|
||||||
|
|||||||
@ -18,7 +18,8 @@
|
|||||||
}
|
}
|
||||||
.PortalMode-filterHolder {
|
.PortalMode-filterHolder {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 35px;
|
right: 1px;
|
||||||
|
margin-right: 25px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -1368,4 +1368,33 @@ function(ConfigurationUtils, i18n, $rootScope) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}])
|
||||||
|
|
||||||
|
.directive('awRequireMultiple', [function() {
|
||||||
|
return {
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function postLink(scope, element, attrs, ngModel) {
|
||||||
|
// Watch for changes to the required attribute
|
||||||
|
attrs.$observe('required', function(value) {
|
||||||
|
if(value) {
|
||||||
|
ngModel.$validators.required = function (value) {
|
||||||
|
if(angular.isArray(value)) {
|
||||||
|
if(value.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (!value[0] || value[0] === "") ? false : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete ngModel.$validators.required;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@ -794,7 +794,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += (horizontal) ? "class=\"" + getFieldWidth() + "\"" : "";
|
html += (horizontal) ? "class=\"" + getFieldWidth() + "\"" : "";
|
||||||
html += ">\n";
|
html += ">\n";
|
||||||
|
|
||||||
html += (field.clear || field.genMD5) ? "<div class=\"input-group\">\n" : "";
|
html += (field.clear || field.genMD5) ? "<div class=\"input-group Form-mixedInputGroup\">\n" : "";
|
||||||
|
|
||||||
if (field.control === null || field.control === undefined || field.control) {
|
if (field.control === null || field.control === undefined || field.control) {
|
||||||
html += "<input ";
|
html += "<input ";
|
||||||
@ -878,7 +878,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += "\t" + label();
|
html += "\t" + label();
|
||||||
if (field.hasShowInputButton) {
|
if (field.hasShowInputButton) {
|
||||||
var tooltip = i18n._("Toggle the display of plaintext.");
|
var tooltip = i18n._("Toggle the display of plaintext.");
|
||||||
html += "\<div class='input-group";
|
html += "\<div class='input-group Form-mixedInputGroup";
|
||||||
html += (horizontal) ? " " + getFieldWidth() : "";
|
html += (horizontal) ? " " + getFieldWidth() : "";
|
||||||
html += "'>\n";
|
html += "'>\n";
|
||||||
// TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field.
|
// TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field.
|
||||||
@ -1357,7 +1357,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += (horizontal) ? "class=\"" + getFieldWidth() + "\"" : "";
|
html += (horizontal) ? "class=\"" + getFieldWidth() + "\"" : "";
|
||||||
html += ">\n";
|
html += ">\n";
|
||||||
|
|
||||||
html += `<div class="input-group">`;
|
html += `<div class="input-group Form-mixedInputGroup">`;
|
||||||
html += "<span class=\"input-group-btn\">\n";
|
html += "<span class=\"input-group-btn\">\n";
|
||||||
html += `<button type="button" class="Form-lookupButton btn btn-default" ng-click="${field.ngClick || defaultLookupNgClick}"
|
html += `<button type="button" class="Form-lookupButton btn btn-default" ng-click="${field.ngClick || defaultLookupNgClick}"
|
||||||
${field.readonly || field.showonly}
|
${field.readonly || field.showonly}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export default
|
|||||||
this.canAdd = function(apiPath) {
|
this.canAdd = function(apiPath) {
|
||||||
var canAddVal = $q.defer();
|
var canAddVal = $q.defer();
|
||||||
|
|
||||||
if (apiPath.indexOf("api/v1") > -1) {
|
if (/api\/v[0-9]+\//.test(apiPath)) {
|
||||||
Rest.setUrl(apiPath);
|
Rest.setUrl(apiPath);
|
||||||
} else {
|
} else {
|
||||||
Rest.setUrl(GetBasePath(apiPath));
|
Rest.setUrl(GetBasePath(apiPath));
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
.SmartSearch-searchTermContainer {
|
.SmartSearch-searchTermContainer {
|
||||||
flex: initial;
|
flex: initial;
|
||||||
width: 50%;
|
width: 100%;
|
||||||
border: 1px solid @d7grey;
|
border: 1px solid @d7grey;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<select class="form-control SurveyMaker-previewSelect" ng-model="selectedValue" multi-select ng-required="isRequired" ng-disabled="isDisabled">
|
<select class="form-control SurveyMaker-previewSelect" ng-model="selectedValue" multi-select ng-required="isRequired" ng-disabled="isDisabled" aw-require-multiple>
|
||||||
<option ng-repeat="choice in choices" value="{{choice}}">{{choice}}</option>
|
<option ng-repeat="choice in choices" value="{{choice}}">{{choice}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -207,7 +207,7 @@ export default ['$state','moment', '$timeout', '$window',
|
|||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
let userCanAddEdit = (scope.workflowJobTemplateObjt && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate;
|
let userCanAddEdit = (scope.workflowJobTemplateObj && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate;
|
||||||
if(scope.dimensionsSet) {
|
if(scope.dimensionsSet) {
|
||||||
// Declare the nodes
|
// Declare the nodes
|
||||||
let nodes = tree.nodes(scope.treeData),
|
let nodes = tree.nodes(scope.treeData),
|
||||||
@ -813,7 +813,7 @@ export default ['$state','moment', '$timeout', '$window',
|
|||||||
|
|
||||||
function add_node() {
|
function add_node() {
|
||||||
this.on("click", function(d) {
|
this.on("click", function(d) {
|
||||||
if((scope.workflowJobTemplateObjt && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
if((scope.workflowJobTemplateObj && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
||||||
scope.addNode({
|
scope.addNode({
|
||||||
parent: d,
|
parent: d,
|
||||||
betweenTwoNodes: false
|
betweenTwoNodes: false
|
||||||
@ -824,7 +824,7 @@ export default ['$state','moment', '$timeout', '$window',
|
|||||||
|
|
||||||
function add_node_between() {
|
function add_node_between() {
|
||||||
this.on("click", function(d) {
|
this.on("click", function(d) {
|
||||||
if((scope.workflowJobTemplateObjt && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
if((scope.workflowJobTemplateObj && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
||||||
scope.addNode({
|
scope.addNode({
|
||||||
parent: d,
|
parent: d,
|
||||||
betweenTwoNodes: true
|
betweenTwoNodes: true
|
||||||
@ -835,7 +835,7 @@ export default ['$state','moment', '$timeout', '$window',
|
|||||||
|
|
||||||
function remove_node() {
|
function remove_node() {
|
||||||
this.on("click", function(d) {
|
this.on("click", function(d) {
|
||||||
if((scope.workflowJobTemplateObjt && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
if((scope.workflowJobTemplateObj && scope.workflowJobTemplateObj.summary_fields && scope.workflowJobTemplateObj.summary_fields.user_capabilities && scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) || scope.canAddWorkflowJobTemplate) {
|
||||||
scope.deleteNode({
|
scope.deleteNode({
|
||||||
nodeToDelete: d
|
nodeToDelete: d
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
-e git+https://github.com/ansible/ansiconv.git@tower_1.0.0#egg=ansiconv
|
|
||||||
-e git+https://github.com/ansible/django-jsonbfield@fix-sqlite_serialization#egg=jsonbfield
|
|
||||||
-e git+https://github.com/ansible/django-qsstats-magic.git@tower_0.7.2#egg=django-qsstats-magic
|
|
||||||
-e git+https://github.com/ansible/dm.xmlsec.binding.git@master#egg=dm.xmlsec.binding
|
|
||||||
-e git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
|
||||||
apache-libcloud==1.3.0
|
apache-libcloud==1.3.0
|
||||||
appdirs==1.4.2
|
appdirs==1.4.2
|
||||||
asgi-amqp==0.4.1
|
asgi-amqp==0.4.1
|
||||||
|
|||||||
@ -4,11 +4,6 @@
|
|||||||
#
|
#
|
||||||
# pip-compile --output-file requirements/requirements.txt requirements/requirements.in
|
# pip-compile --output-file requirements/requirements.txt requirements/requirements.in
|
||||||
#
|
#
|
||||||
git+https://github.com/ansible/ansiconv.git@tower_1.0.0#egg=ansiconv
|
|
||||||
git+https://github.com/ansible/django-qsstats-magic.git@tower_0.7.2#egg=django-qsstats-magic
|
|
||||||
git+https://github.com/ansible/dm.xmlsec.binding.git@master#egg=dm.xmlsec.binding
|
|
||||||
git+https://github.com/ansible/django-jsonbfield@fix-sqlite_serialization#egg=jsonbfield
|
|
||||||
git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
|
||||||
adal==0.4.3 # via msrestazure
|
adal==0.4.3 # via msrestazure
|
||||||
amqp==1.4.9 # via kombu
|
amqp==1.4.9 # via kombu
|
||||||
anyjson==0.3.3 # via kombu
|
anyjson==0.3.3 # via kombu
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
-e git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
|
||||||
apache-libcloud==1.3.0
|
apache-libcloud==1.3.0
|
||||||
azure==2.0.0rc6
|
azure==2.0.0rc6
|
||||||
backports.ssl-match-hostname==3.5.0.1
|
backports.ssl-match-hostname==3.5.0.1
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#
|
#
|
||||||
# pip-compile --output-file requirements/requirements_ansible.txt requirements/requirements_ansible.in
|
# pip-compile --output-file requirements/requirements_ansible.txt requirements/requirements_ansible.in
|
||||||
#
|
#
|
||||||
git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
|
||||||
adal==0.4.3 # via msrestazure
|
adal==0.4.3 # via msrestazure
|
||||||
amqp==1.4.9 # via kombu
|
amqp==1.4.9 # via kombu
|
||||||
anyjson==0.3.3 # via kombu
|
anyjson==0.3.3 # via kombu
|
||||||
|
|||||||
1
requirements/requirements_ansible_git.txt
Normal file
1
requirements/requirements_ansible_git.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
||||||
5
requirements/requirements_git.txt
Normal file
5
requirements/requirements_git.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
git+https://github.com/ansible/ansiconv.git@tower_1.0.0#egg=ansiconv
|
||||||
|
git+https://github.com/ansible/django-qsstats-magic.git@tower_0.7.2#egg=django-qsstats-magic
|
||||||
|
git+https://github.com/ansible/dm.xmlsec.binding.git@master#egg=dm.xmlsec.binding
|
||||||
|
git+https://github.com/ansible/django-jsonbfield@fix-sqlite_serialization#egg=jsonbfield
|
||||||
|
git+https://github.com/chrismeyersfsu/pyrax@tower#egg=pyrax
|
||||||
3
setup.py
3
setup.py
@ -126,7 +126,8 @@ setup(
|
|||||||
("%s" % docdir, ["docs/licenses/*",]),
|
("%s" % docdir, ["docs/licenses/*",]),
|
||||||
("%s" % bindir, ["tools/scripts/ansible-tower-service",
|
("%s" % bindir, ["tools/scripts/ansible-tower-service",
|
||||||
"tools/scripts/failure-event-handler",
|
"tools/scripts/failure-event-handler",
|
||||||
"tools/scripts/tower-python"]),
|
"tools/scripts/tower-python",
|
||||||
|
"tools/scripts/ansible-tower-setup"]),
|
||||||
("%s" % sosconfig, ["tools/sosreport/tower.py"])]),
|
("%s" % sosconfig, ["tools/sosreport/tower.py"])]),
|
||||||
options = {
|
options = {
|
||||||
'egg_info': {
|
'egg_info': {
|
||||||
|
|||||||
@ -67,3 +67,7 @@ services:
|
|||||||
image: postgres:9.4.1
|
image: postgres:9.4.1
|
||||||
memcached:
|
memcached:
|
||||||
image: memcached:alpine
|
image: memcached:alpine
|
||||||
|
logstash:
|
||||||
|
build:
|
||||||
|
context: ./docker-compose
|
||||||
|
dockerfile: Dockerfile-logstash
|
||||||
|
|||||||
@ -3,7 +3,9 @@ FROM centos:7
|
|||||||
ADD Makefile /tmp/Makefile
|
ADD Makefile /tmp/Makefile
|
||||||
RUN mkdir /tmp/requirements
|
RUN mkdir /tmp/requirements
|
||||||
ADD requirements/requirements.txt \
|
ADD requirements/requirements.txt \
|
||||||
|
requirements/requirements_git.txt \
|
||||||
requirements/requirements_ansible.txt \
|
requirements/requirements_ansible.txt \
|
||||||
|
requirements/requirements_ansible_git.txt \
|
||||||
requirements/requirements_dev.txt \
|
requirements/requirements_dev.txt \
|
||||||
requirements/requirements_ansible_uninstall.txt \
|
requirements/requirements_ansible_uninstall.txt \
|
||||||
requirements/requirements_tower_uninstall.txt \
|
requirements/requirements_tower_uninstall.txt \
|
||||||
|
|||||||
3
tools/scripts/ansible-tower-setup
Executable file
3
tools/scripts/ansible-tower-setup
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exec /var/lib/awx/setup/setup.sh "$@"
|
||||||
Loading…
x
Reference in New Issue
Block a user