diff options
Diffstat (limited to 'src')
19 files changed, 339 insertions, 416 deletions
| diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py index 2bbd7142a..8746cc701 100755 --- a/src/conf_mode/ssh.py +++ b/src/conf_mode/ssh.py @@ -73,6 +73,9 @@ def verify(ssh):      if not ssh:          return None +    if 'rekey' in ssh and 'data' not in ssh['rekey']: +        raise ConfigError(f'Rekey data is required!') +      verify_vrf(ssh)      return None diff --git a/src/op_mode/conntrack.py b/src/op_mode/conntrack.py index b27aa6060..fff537936 100755 --- a/src/op_mode/conntrack.py +++ b/src/op_mode/conntrack.py @@ -48,6 +48,14 @@ def _get_raw_data(family):      Return: dictionary      """      xml = _get_xml_data(family) +    if len(xml) == 0: +        output = {'conntrack': +            { +                'error': True, +                'reason': 'entries not found' +            } +        } +        return output      return _xml_to_dict(xml) @@ -72,7 +80,8 @@ def get_formatted_output(dict_data):      :return: formatted output      """      data_entries = [] -    #dict_data = _get_raw_data(family) +    if 'error' in dict_data['conntrack']: +        return 'Entries not found'      for entry in dict_data['conntrack']['flow']:          orig_src, orig_dst, orig_sport, orig_dport = {}, {}, {}, {}          reply_src, reply_dst, reply_sport, reply_dport = {}, {}, {}, {} diff --git a/src/services/api/graphql/graphql/directives.py b/src/services/api/graphql/graphql/directives.py index d8ceefae6..d75d72582 100644 --- a/src/services/api/graphql/graphql/directives.py +++ b/src/services/api/graphql/graphql/directives.py @@ -31,54 +31,21 @@ class VyosDirective(SchemaDirectiveVisitor):          field.resolve = func          return field - -class ConfigureDirective(VyosDirective): -    """ -    Class providing implementation of 'configure' directive in schema. -    """ -    def visit_field_definition(self, field, object_type): -        super().visit_field_definition(field, object_type, -                                       make_resolver=make_configure_resolver) - -class ShowConfigDirective(VyosDirective): -    """ -    Class providing implementation of 'show' directive in schema. -    """ -    def visit_field_definition(self, field, object_type): -        super().visit_field_definition(field, object_type, -                                       make_resolver=make_show_config_resolver) - -class SystemStatusDirective(VyosDirective): -    """ -    Class providing implementation of 'system_status' directive in schema. -    """ -    def visit_field_definition(self, field, object_type): -        super().visit_field_definition(field, object_type, -                                       make_resolver=make_system_status_resolver) - -class ConfigFileDirective(VyosDirective): -    """ -    Class providing implementation of 'configfile' directive in schema. -    """ -    def visit_field_definition(self, field, object_type): -        super().visit_field_definition(field, object_type, -                                       make_resolver=make_config_file_resolver) - -class ShowDirective(VyosDirective): +class ConfigSessionQueryDirective(VyosDirective):      """ -    Class providing implementation of 'show' directive in schema. +    Class providing implementation of 'configsessionquery' directive in schema.      """      def visit_field_definition(self, field, object_type):          super().visit_field_definition(field, object_type, -                                       make_resolver=make_show_resolver) +                                       make_resolver=make_config_session_query_resolver) -class ImageDirective(VyosDirective): +class ConfigSessionMutationDirective(VyosDirective):      """ -    Class providing implementation of 'image' directive in schema. +    Class providing implementation of 'configsessionmutation' directive in schema.      """      def visit_field_definition(self, field, object_type):          super().visit_field_definition(field, object_type, -                                       make_resolver=make_image_resolver) +                                       make_resolver=make_config_session_mutation_resolver)  class GenOpQueryDirective(VyosDirective):      """ @@ -96,11 +63,16 @@ class GenOpMutationDirective(VyosDirective):          super().visit_field_definition(field, object_type,                                         make_resolver=make_gen_op_mutation_resolver) -directives_dict = {"configure": ConfigureDirective, -                   "showconfig": ShowConfigDirective, -                   "systemstatus": SystemStatusDirective, -                   "configfile": ConfigFileDirective, -                   "show": ShowDirective, -                   "image": ImageDirective, +class SystemStatusDirective(VyosDirective): +    """ +    Class providing implementation of 'system_status' directive in schema. +    """ +    def visit_field_definition(self, field, object_type): +        super().visit_field_definition(field, object_type, +                                       make_resolver=make_system_status_resolver) + +directives_dict = {"configsessionquery": ConfigSessionQueryDirective, +                   "configsessionmutation": ConfigSessionMutationDirective,                     "genopquery": GenOpQueryDirective, -                   "genopmutation": GenOpMutationDirective} +                   "genopmutation": GenOpMutationDirective, +                   "systemstatus": SystemStatusDirective} diff --git a/src/services/api/graphql/graphql/mutations.py b/src/services/api/graphql/graphql/mutations.py index 5ccc9b0b6..f7d285a77 100644 --- a/src/services/api/graphql/graphql/mutations.py +++ b/src/services/api/graphql/graphql/mutations.py @@ -106,24 +106,9 @@ def make_mutation_resolver(mutation_name, class_name, session_func):      return func_impl -def make_prefix_resolver(mutation_name, prefix=[]): -    for pre in prefix: -        Pre = pre.capitalize() -        if Pre in mutation_name: -            class_name = mutation_name.replace(Pre, '', 1) -            return make_mutation_resolver(mutation_name, class_name, pre) -    raise Exception - -def make_configure_resolver(mutation_name): -    class_name = mutation_name -    return make_mutation_resolver(mutation_name, class_name, 'configure') - -def make_config_file_resolver(mutation_name): -    return make_prefix_resolver(mutation_name, prefix=['save', 'load']) - -def make_image_resolver(mutation_name): -    return make_prefix_resolver(mutation_name, prefix=['add', 'delete']) +def make_config_session_mutation_resolver(mutation_name): +    return make_mutation_resolver(mutation_name, mutation_name, +                                  convert_camel_case_to_snake(mutation_name))  def make_gen_op_mutation_resolver(mutation_name): -    class_name = mutation_name -    return make_mutation_resolver(mutation_name, class_name, 'gen_op_mutation') +    return make_mutation_resolver(mutation_name, mutation_name, 'gen_op_mutation') diff --git a/src/services/api/graphql/graphql/queries.py b/src/services/api/graphql/graphql/queries.py index b46914dcc..5f3a7d005 100644 --- a/src/services/api/graphql/graphql/queries.py +++ b/src/services/api/graphql/graphql/queries.py @@ -106,18 +106,12 @@ def make_query_resolver(query_name, class_name, session_func):      return func_impl -def make_show_config_resolver(query_name): -    class_name = query_name -    return make_query_resolver(query_name, class_name, 'show_config') - -def make_system_status_resolver(query_name): -    class_name = query_name -    return make_query_resolver(query_name, class_name, 'system_status') - -def make_show_resolver(query_name): -    class_name = query_name -    return make_query_resolver(query_name, class_name, 'show') +def make_config_session_query_resolver(query_name): +    return make_query_resolver(query_name, query_name, +                               convert_camel_case_to_snake(query_name))  def make_gen_op_query_resolver(query_name): -    class_name = query_name -    return make_query_resolver(query_name, class_name, 'gen_op_query') +    return make_query_resolver(query_name, query_name, 'gen_op_query') + +def make_system_status_resolver(query_name): +    return make_query_resolver(query_name, query_name, 'system_status') diff --git a/src/services/api/graphql/graphql/schema/config_file.graphql b/src/services/api/graphql/graphql/schema/config_file.graphql deleted file mode 100644 index a7263114b..000000000 --- a/src/services/api/graphql/graphql/schema/config_file.graphql +++ /dev/null @@ -1,29 +0,0 @@ -input SaveConfigFileInput { -    key: String! -    fileName: String -} - -type SaveConfigFile { -    fileName: String -} - -type SaveConfigFileResult { -    data: SaveConfigFile -    success: Boolean! -    errors: [String] -} - -input LoadConfigFileInput { -    key: String! -    fileName: String! -} - -type LoadConfigFile { -    fileName: String! -} - -type LoadConfigFileResult { -    data: LoadConfigFile -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/configsession.graphql b/src/services/api/graphql/graphql/schema/configsession.graphql new file mode 100644 index 000000000..b1deac4b3 --- /dev/null +++ b/src/services/api/graphql/graphql/schema/configsession.graphql @@ -0,0 +1,115 @@ + +input ShowConfigInput { +    key: String! +    path: [String!]! +    configFormat: String = null +} + +type ShowConfig { +    result: Generic +} + +type ShowConfigResult { +    data: ShowConfig +    success: Boolean! +    errors: [String] +} + +extend type Query { +    ShowConfig(data: ShowConfigInput) : ShowConfigResult @configsessionquery +} + +input ShowInput { +    key: String! +    path: [String!]! +} + +type Show { +    result: Generic +} + +type ShowResult { +    data: Show +    success: Boolean! +    errors: [String] +} + +extend type Query { +    Show(data: ShowInput) : ShowResult @configsessionquery +} + +input SaveConfigFileInput { +    key: String! +    fileName: String = null +} + +type SaveConfigFile { +    result: Generic +} + +type SaveConfigFileResult { +    data: SaveConfigFile +    success: Boolean! +    errors: [String] +} + +extend type Mutation { +    SaveConfigFile(data: SaveConfigFileInput) : SaveConfigFileResult @configsessionmutation +} + +input LoadConfigFileInput { +    key: String! +    fileName: String! +} + +type LoadConfigFile { +    result: Generic +} + +type LoadConfigFileResult { +    data: LoadConfigFile +    success: Boolean! +    errors: [String] +} + +extend type Mutation { +    LoadConfigFile(data: LoadConfigFileInput) : LoadConfigFileResult @configsessionmutation +} + +input AddSystemImageInput { +    key: String! +    location: String! +} + +type AddSystemImage { +    result: Generic +} + +type AddSystemImageResult { +    data: AddSystemImage +    success: Boolean! +    errors: [String] +} + +extend type Mutation { +    AddSystemImage(data: AddSystemImageInput) : AddSystemImageResult @configsessionmutation +} + +input DeleteSystemImageInput { +    key: String! +    name: String! +} + +type DeleteSystemImage { +    result: Generic +} + +type DeleteSystemImageResult { +    data: DeleteSystemImage +    success: Boolean! +    errors: [String] +} + +extend type Mutation { +    DeleteSystemImage(data: DeleteSystemImageInput) : DeleteSystemImageResult @configsessionmutation +}
\ No newline at end of file diff --git a/src/services/api/graphql/graphql/schema/dhcp_server.graphql b/src/services/api/graphql/graphql/schema/dhcp_server.graphql deleted file mode 100644 index 345c349ac..000000000 --- a/src/services/api/graphql/graphql/schema/dhcp_server.graphql +++ /dev/null @@ -1,36 +0,0 @@ -input DhcpServerConfigInput { -    key: String! -    sharedNetworkName: String -    subnet: String -    defaultRouter: String -    nameServer: String -    domainName: String -    lease: Int -    range: Int -    start: String -    stop: String -    dnsForwardingAllowFrom: String -    dnsForwardingCacheSize: Int -    dnsForwardingListenAddress: String -} - -type DhcpServerConfig { -    sharedNetworkName: String -    subnet: String -    defaultRouter: String -    nameServer: String -    domainName: String -    lease: Int -    range: Int -    start: String -    stop: String -    dnsForwardingAllowFrom: String -    dnsForwardingCacheSize: Int -    dnsForwardingListenAddress: String -} - -type CreateDhcpServerResult { -    data: DhcpServerConfig -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/firewall_group.graphql b/src/services/api/graphql/graphql/schema/firewall_group.graphql deleted file mode 100644 index 9454d2997..000000000 --- a/src/services/api/graphql/graphql/schema/firewall_group.graphql +++ /dev/null @@ -1,101 +0,0 @@ -input CreateFirewallAddressGroupInput { -    key: String! -    name: String! -    address: [String] -} - -type CreateFirewallAddressGroup { -    name: String! -    address: [String] -} - -type CreateFirewallAddressGroupResult { -    data: CreateFirewallAddressGroup -    success: Boolean! -    errors: [String] -} - -input UpdateFirewallAddressGroupMembersInput { -    key: String! -    name: String! -    address: [String!]! -} - -type UpdateFirewallAddressGroupMembers { -    name: String! -    address: [String!]! -} - -type UpdateFirewallAddressGroupMembersResult { -    data: UpdateFirewallAddressGroupMembers -    success: Boolean! -    errors: [String] -} - -input RemoveFirewallAddressGroupMembersInput { -    key: String! -    name: String! -    address: [String!]! -} - -type RemoveFirewallAddressGroupMembers { -    name: String! -    address: [String!]! -} - -type RemoveFirewallAddressGroupMembersResult { -    data: RemoveFirewallAddressGroupMembers -    success: Boolean! -    errors: [String] -} - -input CreateFirewallAddressIpv6GroupInput { -    key: String! -    name: String! -    address: [String] -} - -type CreateFirewallAddressIpv6Group { -    name: String! -    address: [String] -} - -type CreateFirewallAddressIpv6GroupResult { -    data: CreateFirewallAddressIpv6Group -    success: Boolean! -    errors: [String] -} - -input UpdateFirewallAddressIpv6GroupMembersInput { -    key: String! -    name: String! -    address: [String!]! -} - -type UpdateFirewallAddressIpv6GroupMembers { -    name: String! -    address: [String!]! -} - -type UpdateFirewallAddressIpv6GroupMembersResult { -    data: UpdateFirewallAddressIpv6GroupMembers -    success: Boolean! -    errors: [String] -} - -input RemoveFirewallAddressIpv6GroupMembersInput { -    key: String! -    name: String! -    address: [String!]! -} - -type RemoveFirewallAddressIpv6GroupMembers { -    name: String! -    address: [String!]! -} - -type RemoveFirewallAddressIpv6GroupMembersResult { -    data: RemoveFirewallAddressIpv6GroupMembers -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/image.graphql b/src/services/api/graphql/graphql/schema/image.graphql deleted file mode 100644 index 485033875..000000000 --- a/src/services/api/graphql/graphql/schema/image.graphql +++ /dev/null @@ -1,31 +0,0 @@ -input AddSystemImageInput { -    key: String! -    location: String! -} - -type AddSystemImage { -    location: String -    result: String -} - -type AddSystemImageResult { -    data: AddSystemImage -    success: Boolean! -    errors: [String] -} - -input DeleteSystemImageInput { -    key: String! -    name: String! -} - -type DeleteSystemImage { -    name: String -    result: String -} - -type DeleteSystemImageResult { -    data: DeleteSystemImage -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/interface_ethernet.graphql b/src/services/api/graphql/graphql/schema/interface_ethernet.graphql deleted file mode 100644 index 8a17d919f..000000000 --- a/src/services/api/graphql/graphql/schema/interface_ethernet.graphql +++ /dev/null @@ -1,19 +0,0 @@ -input InterfaceEthernetConfigInput { -    key: String! -    interface: String -    address: String -    replace: Boolean = true -    description: String -} - -type InterfaceEthernetConfig { -    interface: String -    address: String -    description: String -} - -type CreateInterfaceEthernetResult { -    data: InterfaceEthernetConfig -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/schema.graphql b/src/services/api/graphql/graphql/schema/schema.graphql index 624be2620..2acecade4 100644 --- a/src/services/api/graphql/graphql/schema/schema.graphql +++ b/src/services/api/graphql/graphql/schema/schema.graphql @@ -3,34 +3,16 @@ schema {      mutation: Mutation  } -directive @configure on FIELD_DEFINITION -directive @configfile on FIELD_DEFINITION -directive @show on FIELD_DEFINITION -directive @showconfig on FIELD_DEFINITION  directive @systemstatus on FIELD_DEFINITION -directive @image on FIELD_DEFINITION +directive @configsessionquery on FIELD_DEFINITION +directive @configsessionmutation on FIELD_DEFINITION  directive @genopquery on FIELD_DEFINITION  directive @genopmutation on FIELD_DEFINITION  scalar Generic  type Query { -    Show(data: ShowInput) : ShowResult @show -    ShowConfig(data: ShowConfigInput) : ShowConfigResult @showconfig      SystemStatus(data: SystemStatusInput) : SystemStatusResult @systemstatus  } -type Mutation { -    CreateDhcpServer(data: DhcpServerConfigInput) : CreateDhcpServerResult @configure -    CreateInterfaceEthernet(data: InterfaceEthernetConfigInput) : CreateInterfaceEthernetResult @configure -    CreateFirewallAddressGroup(data: CreateFirewallAddressGroupInput) : CreateFirewallAddressGroupResult @configure -    UpdateFirewallAddressGroupMembers(data: UpdateFirewallAddressGroupMembersInput) : UpdateFirewallAddressGroupMembersResult @configure -    RemoveFirewallAddressGroupMembers(data: RemoveFirewallAddressGroupMembersInput) : RemoveFirewallAddressGroupMembersResult @configure -    CreateFirewallAddressIpv6Group(data: CreateFirewallAddressIpv6GroupInput) : CreateFirewallAddressIpv6GroupResult @configure -    UpdateFirewallAddressIpv6GroupMembers(data: UpdateFirewallAddressIpv6GroupMembersInput) : UpdateFirewallAddressIpv6GroupMembersResult @configure -    RemoveFirewallAddressIpv6GroupMembers(data: RemoveFirewallAddressIpv6GroupMembersInput) : RemoveFirewallAddressIpv6GroupMembersResult @configure -    SaveConfigFile(data: SaveConfigFileInput) : SaveConfigFileResult @configfile -    LoadConfigFile(data: LoadConfigFileInput) : LoadConfigFileResult @configfile -    AddSystemImage(data: AddSystemImageInput) : AddSystemImageResult @image -    DeleteSystemImage(data: DeleteSystemImageInput) : DeleteSystemImageResult @image -} +type Mutation diff --git a/src/services/api/graphql/graphql/schema/show.graphql b/src/services/api/graphql/graphql/schema/show.graphql deleted file mode 100644 index 278ed536b..000000000 --- a/src/services/api/graphql/graphql/schema/show.graphql +++ /dev/null @@ -1,15 +0,0 @@ -input ShowInput { -    key: String! -    path: [String!]! -} - -type Show { -    path: [String] -    result: String -} - -type ShowResult { -    data: Show -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/graphql/schema/show_config.graphql b/src/services/api/graphql/graphql/schema/show_config.graphql deleted file mode 100644 index 5a1fe43da..000000000 --- a/src/services/api/graphql/graphql/schema/show_config.graphql +++ /dev/null @@ -1,21 +0,0 @@ -""" -Use 'scalar Generic' for show config output, to avoid attempts to -JSON-serialize in case of JSON output. -""" - -input ShowConfigInput { -    key: String! -    path: [String!]! -    configFormat: String -} - -type ShowConfig { -    path: [String] -    result: Generic -} - -type ShowConfigResult { -    data: ShowConfig -    success: Boolean! -    errors: [String] -} diff --git a/src/services/api/graphql/session/session.py b/src/services/api/graphql/session/session.py index f7510841e..f990e63d0 100644 --- a/src/services/api/graphql/session/session.py +++ b/src/services/api/graphql/session/session.py @@ -45,40 +45,6 @@ class Session:          except Exception:              self._op_mode_list = None -    def configure(self): -        session = self._session -        data = self._data -        func_base_name = self._name - -        tmpl_file = f'{func_base_name}.tmpl' -        cmd_file = f'/tmp/{func_base_name}.cmds' -        tmpl_dir = directories['api_templates'] - -        try: -            render(cmd_file, tmpl_file, data, location=tmpl_dir) -            commands = [] -            with open(cmd_file) as f: -                lines = f.readlines() -            for line in lines: -                commands.append(line.split()) -            for cmd in commands: -                if cmd[0] == 'set': -                    session.set(cmd[1:]) -                elif cmd[0] == 'delete': -                    session.delete(cmd[1:]) -                else: -                    raise ValueError('Operation must be "set" or "delete"') -            session.commit() -        except Exception as error: -            raise error - -    def delete_path_if_childless(self, path): -        session = self._session -        config = Config(session.get_session_env()) -        if not config.list_nodes(path): -            session.delete(path) -            session.commit() -      def show_config(self):          session = self._session          data = self._data @@ -94,7 +60,7 @@ class Session:          return out -    def save(self): +    def save_config_file(self):          session = self._session          data = self._data          if 'file_name' not in data or not data['file_name']: @@ -105,7 +71,7 @@ class Session:          except Exception as error:              raise error -    def load(self): +    def load_config_file(self):          session = self._session          data = self._data @@ -127,7 +93,7 @@ class Session:          return out -    def add(self): +    def add_system_image(self):          session = self._session          data = self._data @@ -138,7 +104,7 @@ class Session:          return res -    def delete(self): +    def delete_system_image(self):          session = self._session          data = self._data diff --git a/src/services/api/graphql/utils/config_session_function.py b/src/services/api/graphql/utils/config_session_function.py new file mode 100644 index 000000000..fc0dd7a87 --- /dev/null +++ b/src/services/api/graphql/utils/config_session_function.py @@ -0,0 +1,28 @@ +# typing information for native configsession functions; used to generate +# schema definition files +import typing + +def show_config(path: list[str], configFormat: typing.Optional[str]): +    pass + +def show(path: list[str]): +    pass + +queries = {'show_config': show_config, +           'show': show} + +def save_config_file(fileName: typing.Optional[str]): +    pass +def load_config_file(fileName: str): +    pass +def add_system_image(location: str): +    pass +def delete_system_image(name: str): +    pass + +mutations = {'save_config_file': save_config_file, +             'load_config_file': load_config_file, +             'add_system_image': add_system_image, +             'delete_system_image': delete_system_image} + + diff --git a/src/services/api/graphql/utils/schema_from_config_session.py b/src/services/api/graphql/utils/schema_from_config_session.py new file mode 100755 index 000000000..ea78aaf88 --- /dev/null +++ b/src/services/api/graphql/utils/schema_from_config_session.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# +# +# A utility to generate GraphQL schema defintions from typing information of +# (wrappers of) native configsession functions. + +import os +import json +from inspect import signature, getmembers, isfunction, isclass, getmro +from jinja2 import Template + +if __package__ is None or __package__ == '': +    from util import snake_to_pascal_case, map_type_name +else: +    from . util import snake_to_pascal_case, map_type_name + +# this will be run locally before the build +SCHEMA_PATH = '../graphql/schema' + +schema_data: dict = {'schema_name': '', +                     'schema_fields': []} + +query_template  = """ +input {{ schema_name }}Input { +    key: String! +    {%- for field_entry in schema_fields %} +    {{ field_entry }} +    {%- endfor %} +} + +type {{ schema_name }} { +    result: Generic +} + +type {{ schema_name }}Result { +    data: {{ schema_name }} +    success: Boolean! +    errors: [String] +} + +extend type Query { +    {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @configsessionquery +} +""" + +mutation_template  = """ +input {{ schema_name }}Input { +    key: String! +    {%- for field_entry in schema_fields %} +    {{ field_entry }} +    {%- endfor %} +} + +type {{ schema_name }} { +    result: Generic +} + +type {{ schema_name }}Result { +    data: {{ schema_name }} +    success: Boolean! +    errors: [String] +} + +extend type Mutation { +    {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @configsessionmutation +} +""" + +def create_schema(func_name: str, func: callable, template: str) -> str: +    sig = signature(func) + +    field_dict = {} +    for k in sig.parameters: +        field_dict[sig.parameters[k].name] = map_type_name(sig.parameters[k].annotation) + +    schema_fields = [] +    for k,v in field_dict.items(): +        schema_fields.append(k+': '+v) + +    schema_data['schema_name'] = snake_to_pascal_case(func_name) +    schema_data['schema_fields'] = schema_fields + +    j2_template = Template(template) +    res = j2_template.render(schema_data) + +    return res + +def generate_config_session_definitions(): +    from config_session_function import queries, mutations + +    results = [] +    for name,func in queries.items(): +        res = create_schema(name, func, query_template) +        results.append(res) + +    for name,func in mutations.items(): +        res = create_schema(name, func, mutation_template) +        results.append(res) + +    out = '\n'.join(results) +    with open(f'{SCHEMA_PATH}/configsession.graphql', 'w') as f: +        f.write(out) + +if __name__ == '__main__': +    generate_config_session_definitions() diff --git a/src/services/api/graphql/utils/schema_from_op_mode.py b/src/services/api/graphql/utils/schema_from_op_mode.py index 379d15250..57d63628b 100755 --- a/src/services/api/graphql/utils/schema_from_op_mode.py +++ b/src/services/api/graphql/utils/schema_from_op_mode.py @@ -20,15 +20,16 @@  import os  import json -import typing  from inspect import signature, getmembers, isfunction, isclass, getmro  from jinja2 import Template  from vyos.defaults import directories  if __package__ is None or __package__ == '':      from util import load_as_module, is_op_mode_function_name, is_show_function_name +    from util import snake_to_pascal_case, map_type_name  else:      from . util import load_as_module, is_op_mode_function_name, is_show_function_name +    from . util import snake_to_pascal_case, map_type_name  OP_MODE_PATH = directories['op_mode']  SCHEMA_PATH = directories['api_schema'] @@ -103,35 +104,12 @@ type {{ name }} implements OpModeError {  {%- endfor %}  """ -def _snake_to_pascal_case(name: str) -> str: -    res = ''.join(map(str.title, name.split('_'))) -    return res - -def _map_type_name(type_name: type, optional: bool = False) -> str: -    if type_name == str: -        return 'String!' if not optional else 'String = null' -    if type_name == int: -        return 'Int!' if not optional else 'Int = null' -    if type_name == bool: -        return 'Boolean!' if not optional else 'Boolean = false' -    if typing.get_origin(type_name) == list: -        if not optional: -            return f'[{_map_type_name(typing.get_args(type_name)[0])}]!' -        return f'[{_map_type_name(typing.get_args(type_name)[0])}]' -    # typing.Optional is typing.Union[_, NoneType] -    if (typing.get_origin(type_name) is typing.Union and -            typing.get_args(type_name)[1] == type(None)): -        return f'{_map_type_name(typing.get_args(type_name)[0], optional=True)}' - -    # scalar 'Generic' is defined in schema.graphql -    return 'Generic' -  def create_schema(func_name: str, base_name: str, func: callable) -> str:      sig = signature(func)      field_dict = {}      for k in sig.parameters: -        field_dict[sig.parameters[k].name] = _map_type_name(sig.parameters[k].annotation) +        field_dict[sig.parameters[k].name] = map_type_name(sig.parameters[k].annotation)      # It is assumed that if one is generating a schema for a 'show_*'      # function, that 'get_raw_data' is present and 'raw' is desired. @@ -142,7 +120,7 @@ def create_schema(func_name: str, base_name: str, func: callable) -> str:      for k,v in field_dict.items():          schema_fields.append(k+': '+v) -    schema_data['schema_name'] = _snake_to_pascal_case(func_name + '_' + base_name) +    schema_data['schema_name'] = snake_to_pascal_case(func_name + '_' + base_name)      schema_data['schema_fields'] = schema_fields      if is_show_function_name(func_name): diff --git a/src/services/api/graphql/utils/util.py b/src/services/api/graphql/utils/util.py index 073126853..da2bcdb5b 100644 --- a/src/services/api/graphql/utils/util.py +++ b/src/services/api/graphql/utils/util.py @@ -15,6 +15,7 @@  import os  import re +import typing  import importlib.util  from vyos.defaults import directories @@ -74,3 +75,26 @@ def split_compound_op_mode_name(name: str, files: list):              pair = (pair[0], f[0])              return pair      return (name, '') + +def snake_to_pascal_case(name: str) -> str: +    res = ''.join(map(str.title, name.split('_'))) +    return res + +def map_type_name(type_name: type, optional: bool = False) -> str: +    if type_name == str: +        return 'String!' if not optional else 'String = null' +    if type_name == int: +        return 'Int!' if not optional else 'Int = null' +    if type_name == bool: +        return 'Boolean!' if not optional else 'Boolean = false' +    if typing.get_origin(type_name) == list: +        if not optional: +            return f'[{map_type_name(typing.get_args(type_name)[0])}]!' +        return f'[{map_type_name(typing.get_args(type_name)[0])}]' +    # typing.Optional is typing.Union[_, NoneType] +    if (typing.get_origin(type_name) is typing.Union and +            typing.get_args(type_name)[1] == type(None)): +        return f'{map_type_name(typing.get_args(type_name)[0], optional=True)}' + +    # scalar 'Generic' is defined in schema.graphql +    return 'Generic' | 
