def _json_path_to_contains(self, k, v): from awx.main.fields import JSONBField # avoid a circular import if not k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP): v = self.strip_quotes_traditional_logic(v) return (k, v) for match in JSONBField.get_lookups().keys(): match = '__{}'.format(match) if k.endswith(match): if match == '__exact': # appending __exact is basically a no-op, because that's # what the query means if you leave it off k = k[:-len(match)] logger.error( 'host_filter:{} does not support searching with {}'. format(SmartFilter.SEARCHABLE_RELATIONSHIP, match)) # Strip off leading relationship key if k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP + '__'): strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP) + 2 else: strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP) k = k[strip_len:] pieces = k.split(u'__') assembled_k = u'%s__contains' % ( SmartFilter.SEARCHABLE_RELATIONSHIP) assembled_v = None last_v = None last_kv = None for i, piece in enumerate(pieces): new_kv = dict() if piece.endswith(u'[]'): new_v = [] new_kv[piece[0:-2]] = new_v else: new_v = dict() new_kv[piece] = new_v if last_kv is None: assembled_v = new_kv elif type(last_v) is list: last_v.append(new_kv) elif type(last_v) is dict: last_kv[list(last_kv.keys())[0]] = new_kv last_v = new_v last_kv = new_kv v = self.strip_quotes_json_logic(v) if type(last_v) is list: last_v.append(v) elif type(last_v) is dict: last_kv[list(last_kv.keys())[0]] = v return (assembled_k, assembled_v)
class Fact(models.Model): """A model representing a fact returned from Ansible. Facts are stored as JSON dictionaries. """ host = models.ForeignKey( 'Host', related_name='facts', db_index=True, on_delete=models.CASCADE, help_text=_('Host for the facts that the fact scan captured.'), ) timestamp = models.DateTimeField( default=None, editable=False, help_text=_( 'Date and time of the corresponding fact scan gathering time.')) module = models.CharField(max_length=128) facts = JSONBField( blank=True, default={}, help_text= _('Arbitrary JSON structure of module facts captured at timestamp for a single host.' )) class Meta: app_label = 'main' index_together = [ ["timestamp", "module", "host"], ] @staticmethod def get_host_fact(host_id, module, timestamp): qs = Fact.objects.filter( host__id=host_id, module=module, timestamp__lte=timestamp).order_by('-timestamp') if qs: return qs[0] else: return None @staticmethod def get_timeline(host_id, module=None, ts_from=None, ts_to=None): kwargs = { 'host__id': host_id, } if module: kwargs['module'] = module if ts_from and ts_to and ts_from == ts_to: kwargs['timestamp'] = ts_from else: if ts_from: kwargs['timestamp__gt'] = ts_from if ts_to: kwargs['timestamp__lte'] = ts_to return Fact.objects.filter(**kwargs).order_by('-timestamp').only( 'timestamp', 'module').order_by('-timestamp', 'module') @staticmethod def add_fact(host_id, module, timestamp, facts): fact_obj = Fact.objects.create(host_id=host_id, module=module, timestamp=timestamp, facts=facts) fact_obj.save() return fact_obj