mirror of
https://github.com/ansible/awx.git
synced 2026-08-03 11:30:00 -02:30
Merge pull request #4600 from ryanpetrello/cli-json-inputs
cli: improve parsing of JSON inputs Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -5,6 +5,8 @@ from collections import OrderedDict
|
||||
|
||||
# Django
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models.fields import PositiveIntegerField, BooleanField
|
||||
from django.db.models.fields.related import ForeignKey
|
||||
from django.http import Http404
|
||||
from django.utils.encoding import force_text, smart_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@@ -14,9 +16,11 @@ from rest_framework import exceptions
|
||||
from rest_framework import metadata
|
||||
from rest_framework import serializers
|
||||
from rest_framework.relations import RelatedField, ManyRelatedField
|
||||
from rest_framework.fields import JSONField as DRFJSONField
|
||||
from rest_framework.request import clone_request
|
||||
|
||||
# AWX
|
||||
from awx.main.fields import JSONField
|
||||
from awx.main.models import InventorySource, NotificationTemplate
|
||||
|
||||
|
||||
@@ -68,6 +72,8 @@ class Metadata(metadata.SimpleMetadata):
|
||||
else:
|
||||
for model_field in serializer.Meta.model._meta.fields:
|
||||
if field.field_name == model_field.name:
|
||||
if getattr(model_field, '__accepts_json__', None):
|
||||
field_info['type'] = 'json'
|
||||
field_info['filterable'] = True
|
||||
break
|
||||
else:
|
||||
@@ -126,14 +132,36 @@ class Metadata(metadata.SimpleMetadata):
|
||||
|
||||
|
||||
# Update type of fields returned...
|
||||
model_field = None
|
||||
if serializer and hasattr(serializer, 'Meta') and hasattr(serializer.Meta, 'model'):
|
||||
try:
|
||||
model_field = serializer.Meta.model._meta.get_field(field.field_name)
|
||||
except Exception:
|
||||
pass
|
||||
if field.field_name == 'type':
|
||||
field_info['type'] = 'choice'
|
||||
elif field.field_name == 'url':
|
||||
elif field.field_name in ('url', 'custom_virtualenv', 'token'):
|
||||
field_info['type'] = 'string'
|
||||
elif field.field_name in ('related', 'summary_fields'):
|
||||
field_info['type'] = 'object'
|
||||
elif isinstance(field, PositiveIntegerField):
|
||||
field_info['type'] = 'integer'
|
||||
elif field.field_name in ('created', 'modified'):
|
||||
field_info['type'] = 'datetime'
|
||||
elif (
|
||||
RelatedField in field.__class__.__bases__ or
|
||||
isinstance(model_field, ForeignKey)
|
||||
):
|
||||
field_info['type'] = 'id'
|
||||
elif (
|
||||
isinstance(field, JSONField) or
|
||||
isinstance(model_field, JSONField) or
|
||||
isinstance(field, DRFJSONField) or
|
||||
isinstance(getattr(field, 'model_field', None), JSONField)
|
||||
):
|
||||
field_info['type'] = 'json'
|
||||
elif isinstance(model_field, BooleanField):
|
||||
field_info['type'] = 'boolean'
|
||||
|
||||
return field_info
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ from django.db.models.signals import pre_delete # noqa
|
||||
|
||||
# AWX
|
||||
from awx.main.models.base import ( # noqa
|
||||
BaseModel, PrimordialModel, prevent_search, CLOUD_INVENTORY_SOURCES, VERBOSITY_CHOICES
|
||||
BaseModel, PrimordialModel, prevent_search, accepts_json,
|
||||
CLOUD_INVENTORY_SOURCES, VERBOSITY_CHOICES
|
||||
)
|
||||
from awx.main.models.unified_jobs import ( # noqa
|
||||
UnifiedJob, UnifiedJobTemplate, StdoutMaxBytesExceeded
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# Tower
|
||||
from awx.api.versioning import reverse
|
||||
from awx.main.fields import JSONField
|
||||
from awx.main.models.base import accepts_json
|
||||
|
||||
# Django
|
||||
from django.db import models
|
||||
@@ -34,7 +35,7 @@ class ActivityStream(models.Model):
|
||||
actor = models.ForeignKey('auth.User', null=True, on_delete=models.SET_NULL, related_name='activity_stream')
|
||||
operation = models.CharField(max_length=13, choices=OPERATION_CHOICES)
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
changes = models.TextField(blank=True)
|
||||
changes = accepts_json(models.TextField(blank=True))
|
||||
deleted_actor = JSONField(null=True)
|
||||
action_node = models.CharField(
|
||||
blank=True,
|
||||
|
||||
@@ -408,3 +408,14 @@ def prevent_search(relation):
|
||||
"""
|
||||
setattr(relation, '__prevent_search__', True)
|
||||
return relation
|
||||
|
||||
|
||||
def accepts_json(relation):
|
||||
"""
|
||||
Used to mark a model field as allowing JSON e.g,. JobTemplate.extra_vars
|
||||
This is *mostly* used as a way to provide type hints for certain fields
|
||||
so that HTTP OPTIONS reports the type data we need for the CLI to allow
|
||||
JSON/YAML input.
|
||||
"""
|
||||
setattr(relation, '__accepts_json__', True)
|
||||
return relation
|
||||
|
||||
@@ -45,7 +45,7 @@ from awx.main.models.base import (
|
||||
CommonModelNameNotUnique,
|
||||
VarsDictProperty,
|
||||
CLOUD_INVENTORY_SOURCES,
|
||||
prevent_search
|
||||
prevent_search, accepts_json
|
||||
)
|
||||
from awx.main.models.events import InventoryUpdateEvent
|
||||
from awx.main.models.unified_jobs import UnifiedJob, UnifiedJobTemplate
|
||||
@@ -93,11 +93,11 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
)
|
||||
variables = models.TextField(
|
||||
variables = accepts_json(models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=_('Inventory variables in JSON or YAML format.'),
|
||||
)
|
||||
))
|
||||
has_active_failures = models.BooleanField(
|
||||
default=False,
|
||||
editable=False,
|
||||
@@ -608,11 +608,11 @@ class Host(CommonModelNameNotUnique, RelatedJobsMixin):
|
||||
default='',
|
||||
help_text=_('The value used by the remote inventory source to uniquely identify the host'),
|
||||
)
|
||||
variables = models.TextField(
|
||||
variables = accepts_json(models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=_('Host variables in JSON or YAML format.'),
|
||||
)
|
||||
))
|
||||
last_job = models.ForeignKey(
|
||||
'Job',
|
||||
related_name='hosts_as_last_job+',
|
||||
@@ -796,11 +796,11 @@ class Group(CommonModelNameNotUnique, RelatedJobsMixin):
|
||||
related_name='children',
|
||||
blank=True,
|
||||
)
|
||||
variables = models.TextField(
|
||||
variables = accepts_json(models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=_('Group variables in JSON or YAML format.'),
|
||||
)
|
||||
))
|
||||
hosts = models.ManyToManyField(
|
||||
'Host',
|
||||
related_name='groups',
|
||||
|
||||
@@ -27,7 +27,7 @@ from rest_framework.exceptions import ParseError
|
||||
from awx.api.versioning import reverse
|
||||
from awx.main.models.base import (
|
||||
BaseModel, CreatedModifiedModel,
|
||||
prevent_search,
|
||||
prevent_search, accepts_json,
|
||||
JOB_TYPE_CHOICES, VERBOSITY_CHOICES,
|
||||
VarsDictProperty
|
||||
)
|
||||
@@ -116,10 +116,10 @@ class JobOptions(BaseModel):
|
||||
blank=True,
|
||||
default=0,
|
||||
)
|
||||
extra_vars = prevent_search(models.TextField(
|
||||
extra_vars = prevent_search(accepts_json(models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
))
|
||||
)))
|
||||
job_tags = models.CharField(
|
||||
max_length=1024,
|
||||
blank=True,
|
||||
|
||||
@@ -13,7 +13,8 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
# AWX
|
||||
from awx.api.versioning import reverse
|
||||
from awx.main.models import prevent_search, UnifiedJobTemplate, UnifiedJob
|
||||
from awx.main.models import (prevent_search, accepts_json, UnifiedJobTemplate,
|
||||
UnifiedJob)
|
||||
from awx.main.models.notifications import (
|
||||
NotificationTemplate,
|
||||
JobNotificationMixin
|
||||
@@ -291,10 +292,10 @@ class WorkflowJobOptions(BaseModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
extra_vars = prevent_search(models.TextField(
|
||||
extra_vars = accepts_json(prevent_search(models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
))
|
||||
)))
|
||||
allow_simultaneous = models.BooleanField(
|
||||
default=False
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user