mirror of
https://github.com/ansible/awx.git
synced 2026-05-13 04:17:36 -02:30
Drop objects that cannot be read or do not have a natural key
don't fail hard.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import itertools
|
import itertools
|
||||||
|
import logging
|
||||||
|
|
||||||
from awxkit.api.resources import resources
|
from awxkit.api.resources import resources
|
||||||
import awxkit.exceptions as exc
|
import awxkit.exceptions as exc
|
||||||
@@ -7,6 +8,9 @@ from . import page
|
|||||||
from ..mixins import has_create
|
from ..mixins import has_create
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
EXPORTABLE_RESOURCES = [
|
EXPORTABLE_RESOURCES = [
|
||||||
'users',
|
'users',
|
||||||
'organizations',
|
'organizations',
|
||||||
@@ -73,6 +77,8 @@ class ApiV2(base.Base):
|
|||||||
if 'POST' not in options.r.headers.get('Allow', ''):
|
if 'POST' not in options.r.headers.get('Allow', ''):
|
||||||
return self._options.setdefault(url, None)
|
return self._options.setdefault(url, None)
|
||||||
|
|
||||||
|
# FIXME: if POST isn't in the actions, this is a view where we
|
||||||
|
# don't have write permissions. Try to do something anyway.
|
||||||
return self._options.setdefault(url, options.json['actions'].get('POST', {}))
|
return self._options.setdefault(url, options.json['actions'].get('POST', {}))
|
||||||
|
|
||||||
# Export methods
|
# Export methods
|
||||||
@@ -84,53 +90,60 @@ class ApiV2(base.Base):
|
|||||||
if options is None: # Deprecated endpoint or insufficient permissions
|
if options is None: # Deprecated endpoint or insufficient permissions
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
# Note: doing asset[key] automatically parses json blob strings, which can be a problem.
|
||||||
# Note: doing asset[key] automatically parses json blob strings, which can be a problem.
|
fields = {
|
||||||
fields = {
|
key: asset.json[key] for key in options
|
||||||
key: asset.json[key] for key in options
|
if key in asset.json and key not in asset.related and key != 'id'
|
||||||
if key in asset.json and key not in asset.related and key != 'id'
|
}
|
||||||
}
|
fields['natural_key'] = asset.get_natural_key()
|
||||||
fields['natural_key'] = asset.get_natural_key()
|
|
||||||
|
|
||||||
fk_fields = {
|
for key in options:
|
||||||
|
if not key in asset.related:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
# FIXME: use caching by url
|
# FIXME: use caching by url
|
||||||
key: asset.related[key].get().get_natural_key() for key in options
|
fields[key] = asset.related[key].get().get_natural_key()
|
||||||
if key in asset.related
|
except exc.Forbidden:
|
||||||
}
|
log.warning("This object cannot be read: %s", asset.related[key])
|
||||||
|
pass # FIXME: what if the fk is mandatory?
|
||||||
|
|
||||||
related = {}
|
related = {}
|
||||||
for key, related_endpoint in asset.related.items():
|
for key, related_endpoint in asset.related.items():
|
||||||
if key in asset.json or not related_endpoint:
|
if key in asset.json or not related_endpoint:
|
||||||
|
continue
|
||||||
|
if key == 'object_roles':
|
||||||
|
continue # FIXME: we should aggregate all visited roles
|
||||||
|
|
||||||
|
rel = related_endpoint._create()
|
||||||
|
if rel.__class__.__name__ in EXPORTABLE_RELATIONS:
|
||||||
|
by_natural_key = True
|
||||||
|
related_options = self._get_options(related_endpoint)
|
||||||
|
if related_options is None:
|
||||||
continue
|
continue
|
||||||
if key == 'object_roles': # FIXME
|
elif rel.__class__.__name__ in EXPORTABLE_DEPENDENT_OBJECTS:
|
||||||
continue
|
by_natural_key, related_options = False, None
|
||||||
rel = related_endpoint._create()
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
if rel.__class__.__name__ in EXPORTABLE_RELATIONS:
|
try:
|
||||||
by_natural_key = True
|
# FIXME: use caching by url
|
||||||
related_options = self._get_options(related_endpoint)
|
data = rel.get(all_pages=True)
|
||||||
if related_options is None:
|
except exc.Forbidden:
|
||||||
continue
|
log.warning("This object cannot be read: %s", related_endpoint)
|
||||||
elif rel.__class__.__name__ in EXPORTABLE_DEPENDENT_OBJECTS:
|
continue
|
||||||
by_natural_key, related_options = False, None
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
data = related_endpoint.get(all_pages=True)
|
if 'results' in data:
|
||||||
if 'results' in data:
|
results = (
|
||||||
related[key] = [
|
x.get_natural_key() if by_natural_key else self._serialize_asset(x, related_options)
|
||||||
x.get_natural_key() if by_natural_key else self._serialize_asset(x, related_options)
|
for x in data.results
|
||||||
for x in data.results
|
)
|
||||||
]
|
related[key] = [x for x in results if x is not None]
|
||||||
else:
|
else:
|
||||||
related[key] = data.json
|
related[key] = data.json
|
||||||
except exc.Forbidden:
|
|
||||||
return None
|
|
||||||
|
|
||||||
related_fields = {'related': related} if related else {}
|
if related:
|
||||||
|
fields['related'] = related
|
||||||
|
|
||||||
fields.update(fk_fields)
|
|
||||||
fields.update(related_fields)
|
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def _get_assets(self, resource, value):
|
def _get_assets(self, resource, value):
|
||||||
|
|||||||
@@ -318,7 +318,10 @@ class Page(object):
|
|||||||
return page_cls(self.connection, endpoint=endpoint).get(**kw)
|
return page_cls(self.connection, endpoint=endpoint).get(**kw)
|
||||||
|
|
||||||
def get_natural_key(self):
|
def get_natural_key(self):
|
||||||
|
warn = "This object does not have a natural key: %s"
|
||||||
|
|
||||||
if not getattr(self, 'NATURAL_KEY', None):
|
if not getattr(self, 'NATURAL_KEY', None):
|
||||||
|
log.warning(warn, getattr(self, 'endpoint', ''))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
natural_key = {}
|
natural_key = {}
|
||||||
@@ -328,10 +331,12 @@ class Page(object):
|
|||||||
# FIXME: use caching by url
|
# FIXME: use caching by url
|
||||||
natural_key[key] = self.related[key].get().get_natural_key()
|
natural_key[key] = self.related[key].get().get_natural_key()
|
||||||
except exc.Forbidden:
|
except exc.Forbidden:
|
||||||
|
log.warning("This object cannot be read: %s", getattr(self, 'endpoint', ''))
|
||||||
return None
|
return None
|
||||||
elif key in self:
|
elif key in self:
|
||||||
natural_key[key] = self[key]
|
natural_key[key] = self[key]
|
||||||
if not natural_key:
|
if not natural_key:
|
||||||
|
log.warning(warn, getattr(self, 'endpoint', ''))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
natural_key['type'] = self['type']
|
natural_key['type'] = self['type']
|
||||||
@@ -397,6 +402,7 @@ class PageList(object):
|
|||||||
return self.__item_class__(self.connection).create(*a, **kw)
|
return self.__item_class__(self.connection).create(*a, **kw)
|
||||||
|
|
||||||
def get_natural_key(self):
|
def get_natural_key(self):
|
||||||
|
log.warning("This object does not have a natural key: %s", getattr(self, 'endpoint', ''))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user