Пример #1
0
def _value_startswith(attribute_id, search_string, limit=20):
    """Query attribute starting with search_string

    :param attribute_id: e.g. primary_ip6
    :param search_string: e.g. 2a00
    :param limit: e.g. limit result to n results
    :return:
    """

    query_attribute = Attribute.objects.filter(attribute_id=attribute_id)
    if not query_attribute:
        return []

    attribute = query_attribute.first()
    attribute_model = ServerAttribute.get_model(attribute.type)

    if attribute.type == 'reverse':
        # Should not be queried by client but lets be sure.
        return []

    if attribute.type == 'relation':
        query = Server.objects.filter(servertype_id=attribute_id).filter(
            hostname__startswith=search_string).only('hostname').order_by(
            'hostname')
        return [server.hostname for server in query[:limit]]
    if attribute.type == 'boolean':
        return ['true', 'false']

    query = attribute_model.objects.filter(attribute_id=attribute_id).filter(
        value__startswith=search_string).only('value').distinct(
        'value').order_by('value')
    return [attr.value for attr in query[:limit]]
Пример #2
0
def _real_condition_sql(attribute, template, related_vias):
    model = ServerAttribute.get_model(attribute.type)
    assert model is not None

    # If we come to this point, we must have the item for the entry existing
    # in the related-vias dictionary.  Keep in mind that it also includes
    # the directly attached servertype attribute combinations.  They would
    # have None as the key of the inner dictionary.  If no servertype attribute
    # combinations had been possible, the caller must have returned an empty
    # result, before calling this module to get the SQL query.  No filter
    # is optional in queries after all.
    related_vias = related_vias[attribute.attribute_id]
    assert related_vias

    # We start with the condition for the attributes the server has on
    # its own.  Then, add the conditions for all possible relations.  They
    # are going to be OR'ed together.
    relation_conditions = []
    for related_via_attribute, servertype_ids in related_vias.items():
        if related_via_attribute is None:
            # The condition for directly attached attributes
            relation_condition = 'server.server_id = sub.server_id'
        elif related_via_attribute.type == 'supernet':
            relation_condition = _exists_sql(Server, 'rel1', (
                "rel1.servertype_id = '{0}'".format(
                    related_via_attribute.target_servertype_id),
                'rel1.intern_ip >>= server.intern_ip',
                'rel1.server_id = sub.server_id',
            ))
        elif related_via_attribute.type == 'reverse':
            relation_condition = _exists_sql(ServerRelationAttribute, 'rel1', (
                "rel1.attribute_id = '{0}'".format(
                    related_via_attribute.reversed_attribute_id),
                'rel1.value = server.server_id',
                'rel1.server_id = sub.server_id',
            ))
        else:
            assert related_via_attribute.type == 'relation'
            relation_condition = _exists_sql(ServerRelationAttribute, 'rel1', (
                "rel1.attribute_id = '{0}'".format(
                    related_via_attribute.attribute_id),
                'rel1.server_id = server.server_id',
                'rel1.value = sub.server_id',
            ))
        relation_conditions.append((relation_condition, servertype_ids))

    if len(relation_conditions) == 1:
        mixed_relation_condition = relation_conditions[0][0]
    else:
        mixed_relation_condition = '({0})'.format(' OR '.join(
            '({0} AND server.servertype_id IN ({1}))'.format(
                relation_condition, ', '.join("'{0}'".format(s)
                                              for s in servertype_ids))
            for relation_condition, servertype_ids in relation_conditions))

    return _exists_sql(model, 'sub', (
        mixed_relation_condition,
        "sub.attribute_id = '{0}'".format(attribute.attribute_id),
        template.format('sub.value'),
    ))
Пример #3
0
    def _add_related_attribute(self, attribute, servertype_attribute,
                               servers_by_type):
        related_via_attribute = servertype_attribute.related_via_attribute

        # First, index the related servers for fast access later
        servers_by_related = {}
        for target in servers_by_type[servertype_attribute.servertype_id]:
            attributes = self._server_attributes[target]
            if related_via_attribute in attributes:
                if related_via_attribute.multi:
                    for source in attributes[related_via_attribute]:
                        servers_by_related.setdefault(source,
                                                      []).append(target)
                else:
                    source = attributes[related_via_attribute]
                    servers_by_related.setdefault(source, []).append(target)

        # Then, query and set the related attributes
        for sa in ServerAttribute.get_model(attribute.type).objects.filter(
                server__hostname__in=servers_by_related.keys(),
                attribute=attribute,
        ).prefetch_related('server').defer(
                'server__intern_ip',
                'server__servertype',
        ):
            for target in servers_by_related[sa.server]:
                self._add_attribute_value(target, attribute, sa.get_value())
Пример #4
0
def _upsert_attributes(attribute_lookup, changed, changed_servers):
    for changes in changed:
        object_id = changes['object_id']

        for attribute_id, change in changes.items():
            if attribute_id in Attribute.specials:
                continue

            attribute = attribute_lookup[attribute_id]
            server = changed_servers[object_id]

            action = change['action']
            if action == 'multi':
                for value in change['add']:
                    server.add_attribute(attribute, value)
                continue

            if action not in ('new', 'update'):
                continue
            if change['new'] is None:
                continue

            try:
                server_attribute = server.get_attributes(attribute).get()
            except ServerAttribute.get_model(attribute.type).DoesNotExist:
                server.add_attribute(attribute, change['new'])
            else:
                server_attribute.save_value(change['new'])
Пример #5
0
 def _add_attributes(self, servers_by_type):
     """Add the attributes to the results"""
     for key, attributes in self._attributes_by_type.items():
         if key == 'supernet':
             for attribute in attributes:
                 self._add_supernet_attribute(
                     attribute,
                     (s
                      for st in self._servertype_ids_by_attribute[attribute]
                      for s in servers_by_type[st]))
         elif key == 'domain':
             for attribute in attributes:
                 self._add_domain_attribute(attribute, [
                     s
                     for st in self._servertype_ids_by_attribute[attribute]
                     for s in servers_by_type[st]
                 ])
         elif key == 'reverse':
             reversed_attributes = {
                 a.reversed_attribute_id: a
                 for a in attributes
             }
             for sa in ServerRelationAttribute.objects.filter(
                     value_id__in=self._server_attributes.keys(),
                     attribute_id__in=reversed_attributes.keys(),
             ).prefetch_related('server').defer(
                     'server__intern_ip',
                     'server__servertype',
             ):
                 self._add_attribute_value(
                     sa.value,
                     reversed_attributes[sa.attribute_id],
                     sa.server,
                 )
         else:
             attribute_lookup = {a.attribute_id: a for a in attributes}
             for sa in ServerAttribute.get_model(key).objects.filter(
                     server__in=self._server_attributes.keys(),
                     attribute__in=attributes,
             ).prefetch_related('server').defer(
                     'server__intern_ip',
                     'server__servertype',
             ):
                 self._add_attribute_value(
                     sa.server,
                     attribute_lookup[sa.attribute_id],
                     sa.get_value(),
                 )