Beispiel #1
0
    def _set_rpsl_object_schemas(self):
        """
        Create the schemas for each specific RPSL object class.
        Each of these implements RPSLObject, and RPSLPerson/RPSLRole
        implement RPSLContact as well.
        """
        self.graphql_types = defaultdict(dict)
        schemas = OrderedDict()
        for object_class, klass in OBJECT_CLASS_MAPPING.items():
            object_name = klass.__name__
            graphql_fields = OrderedDict()
            graphql_fields['rpslPk'] = 'String'
            graphql_fields['objectClass'] = 'String'
            graphql_fields['objectText'] = 'String'
            graphql_fields['updated'] = 'String'
            graphql_fields['journal'] = '[RPSLJournalEntry]'
            for field_name, field in klass.fields.items():
                graphql_type = self._graphql_type_for_rpsl_field(field)
                graphql_fields[snake_to_camel_case(field_name)] = graphql_type
                self.graphql_types[snake_to_camel_case(
                    object_name)][field_name] = graphql_type

                reference_name, reference_type = self._grapql_type_for_reference_field(
                    field_name, field)
                if reference_name and reference_type:
                    graphql_fields[reference_name] = reference_type
                    self.graphql_types[object_name][
                        reference_name] = reference_type

            for field_name in klass.field_extracts:
                if field_name.startswith('asn'):
                    graphql_type = 'ASN'
                elif field_name == 'prefix':
                    graphql_type = 'IP'
                elif field_name == 'prefix_length':
                    graphql_type = 'Int'
                else:
                    graphql_type = 'String'
                graphql_fields[snake_to_camel_case(field_name)] = graphql_type
            if klass.rpki_relevant:
                graphql_fields['rpkiStatus'] = 'RPKIStatus'
                graphql_fields['rpkiMaxLength'] = 'Int'
                self.graphql_types[object_name]['rpki_max_length'] = 'Int'
            implements = 'RPSLContact & RPSLObject' if klass in [
                RPSLPerson, RPSLRole
            ] else 'RPSLObject'
            schema = self._generate_schema_str(object_name, 'type',
                                               graphql_fields, implements)
            schemas[object_name] = schema
        self.rpsl_object_schemas = schemas
Beispiel #2
0
 def _grapql_type_for_reference_field(
         self, field_name: str,
         rpsl_field: RPSLTextField) -> Tuple[Optional[str], Optional[str]]:
     """
     Return the GraphQL name and type for a reference field.
     For example, for a field "admin-c" that refers to person/role,
     returns ('adminC', '[RPSLContactUnion!]').
     Some fields are excluded because they are syntactical references,
     not real references.
     """
     if isinstance(rpsl_field, RPSLReferenceField) and getattr(
             rpsl_field, 'referring', None):
         rpsl_field.resolve_references()
         graphql_name = snake_to_camel_case(field_name) + 'Objs'
         grapql_referring = set(rpsl_field.referring_object_classes)
         if RPSLAutNum in grapql_referring:
             grapql_referring.remove(RPSLAutNum)
         if RPSLInetRtr in grapql_referring:
             grapql_referring.remove(RPSLInetRtr)
         if grapql_referring == {RPSLPerson, RPSLRole}:
             graphql_type = '[RPSLContactUnion!]'
         else:
             graphql_type = '[' + grapql_referring.pop().__name__ + '!]'
         return graphql_name, graphql_type
     return None, None
Beispiel #3
0
 def _set_rpsl_query_fields(self):
     """
     Create a sub-schema for the fields that can be queried for RPSL objects.
     This includes all fields from all objects, along with a few
     special fields.
     """
     string_list_fields = {'rpsl_pk', 'sources',
                           'object_class'}.union(lookup_field_names())
     params = [
         snake_to_camel_case(p) + ': [String!]'
         for p in sorted(string_list_fields)
     ]
     params += [
         'ipExact: IP',
         'ipLessSpecific: IP',
         'ipLessSpecificOneLevel: IP',
         'ipMoreSpecific: IP',
         'ipAny: IP',
         'asn: [ASN!]',
         'rpkiStatus: [RPKIStatus!]',
         'scopeFilterStatus: [ScopeFilterStatus!]',
         'textSearch: String',
         'recordLimit: Int',
         'sqlTrace: Boolean',
     ]
     self.rpsl_query_fields = ', '.join(params)
Beispiel #4
0
def _rpsl_db_query_to_graphql_out(query: RPSLDatabaseQuery,
                                  info: GraphQLResolveInfo):
    """
    Given an RPSL database query, execute it and clean up the output
    to be suitable to return to GraphQL.

    Main changes are:
    - Enum handling
    - Adding the asn and prefix fields if applicable
    - Ensuring the right fields are returned as a list of strings or a string
    """
    database_handler = info.context['request'].app.state.database_handler
    if info.context.get('sql_trace'):
        if 'sql_queries' not in info.context:
            info.context['sql_queries'] = [repr(query)]
        else:
            info.context['sql_queries'].append(repr(query))

    for row in database_handler.execute_query(query, refresh_on_error=True):
        graphql_result = {
            snake_to_camel_case(k): v
            for k, v in row.items() if k != 'parsed_data'
        }
        if 'object_text' in row:
            graphql_result['objectText'] = remove_auth_hashes(
                row['object_text'])
        if 'rpki_status' in row:
            graphql_result['rpkiStatus'] = row['rpki_status']
        if row.get('ip_first') is not None and row.get('prefix_length'):
            graphql_result['prefix'] = row['ip_first'] + '/' + str(
                row['prefix_length'])
        if row.get('asn_first') is not None and row.get(
                'asn_first') == row.get('asn_last'):
            graphql_result['asn'] = row['asn_first']

        object_type = resolve_rpsl_object_type(row)
        for key, value in row.get('parsed_data', dict()).items():
            if key == 'auth':
                value = [remove_auth_hashes(v) for v in value]
            graphql_type = schema.graphql_types[object_type][key]
            if graphql_type == 'String' and isinstance(value, list):
                value = '\n'.join(value)
            graphql_result[snake_to_camel_case(key)] = value
        yield graphql_result
Beispiel #5
0
def resolve_database_status(_,
                            info: GraphQLResolveInfo,
                            sources: Optional[List[str]] = None):
    """Resolve a databaseStatus query"""
    query_resolver = QueryResolver(
        info.context['request'].app.state.preloader,
        info.context['request'].app.state.database_handler)
    for name, data in query_resolver.database_status(sources=sources).items():
        camel_case_data = OrderedDict(data)
        camel_case_data['source'] = name
        for key, value in data.items():
            camel_case_data[snake_to_camel_case(key)] = value
        yield camel_case_data
Beispiel #6
0
    def _dict_for_common_fields(self, common_fields: List[str]):
        common_field_dict = OrderedDict()
        for field_name in sorted(common_fields):
            try:
                # These fields are present in all relevant object, so this is a safe check
                rpsl_field = RPSLPerson.fields[field_name]
                graphql_type = self._graphql_type_for_rpsl_field(rpsl_field)

                reference_name, reference_type = self._grapql_type_for_reference_field(
                    field_name, rpsl_field)
                if reference_name and reference_type:
                    common_field_dict[reference_name] = reference_type
            except KeyError:
                graphql_type = 'String'
            common_field_dict[snake_to_camel_case(field_name)] = graphql_type
        return common_field_dict
Beispiel #7
0
def resolve_rpsl_object_journal(rpsl_object, info: GraphQLResolveInfo):
    """
    Resolve a journal subquery on an RPSL object.
    """
    database_handler = info.context['request'].app.state.database_handler
    access_list = f"sources.{rpsl_object['source']}.nrtm_access_list"
    if not is_client_permitted(info.context['request'].client.host,
                               access_list):
        raise GraphQLError(
            f"Access to journal denied for source {rpsl_object['source']}")

    query = RPSLDatabaseJournalQuery()
    query.sources([rpsl_object['source']]).rpsl_pk(rpsl_object['rpslPk'])
    for row in database_handler.execute_query(query, refresh_on_error=True):
        response = {snake_to_camel_case(k): v for k, v in row.items()}
        response['operation'] = response['operation'].name
        if response['origin']:
            response['origin'] = response['origin'].name
        if response['objectText']:
            response['objectText'] = remove_auth_hashes(response['objectText'])
        yield response