diff options
author | Christian Breunig <christian@breunig.cc> | 2023-03-04 05:37:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-04 05:37:33 +0100 |
commit | 493af3f3417cef5c9898f242a2b885e63e3bdeef (patch) | |
tree | b9536a832d7693f2f35d90fc75b58ff57be4d640 | |
parent | e5eb4f332f03df51d64d51e7f38ee561f298188c (diff) | |
parent | 7ab3b9e021e7ce1c56b9f252a04400a37fd33e71 (diff) | |
download | vyos-1x-493af3f3417cef5c9898f242a2b885e63e3bdeef.tar.gz vyos-1x-493af3f3417cef5c9898f242a2b885e63e3bdeef.zip |
Merge pull request #1862 from jestabro/schema-generate
graphql: T5040: generate schema on installation, rather than dynamically
-rw-r--r-- | debian/vyos-1x.postinst | 3 | ||||
-rw-r--r-- | python/vyos/configquery.py | 2 | ||||
-rw-r--r-- | python/vyos/defaults.py | 1 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_https.py | 3 | ||||
-rw-r--r-- | src/services/api/graphql/bindings.py | 7 | ||||
-rwxr-xr-x | src/services/api/graphql/generate/generate_schema.py | 26 | ||||
-rwxr-xr-x | src/services/api/graphql/generate/schema_from_composite.py | 51 | ||||
-rwxr-xr-x | src/services/api/graphql/generate/schema_from_config_session.py | 51 | ||||
-rwxr-xr-x | src/services/api/graphql/generate/schema_from_op_mode.py | 51 |
9 files changed, 45 insertions, 150 deletions
diff --git a/debian/vyos-1x.postinst b/debian/vyos-1x.postinst index b2f6a7399..f6693c799 100644 --- a/debian/vyos-1x.postinst +++ b/debian/vyos-1x.postinst @@ -114,3 +114,6 @@ done # Remove logrotate items controlled via CLI and VyOS defaults sed -i '/^\/var\/log\/messages$/d' /etc/logrotate.d/rsyslog sed -i '/^\/var\/log\/auth.log$/d' /etc/logrotate.d/rsyslog + +# Generate API GraphQL schema +/usr/libexec/vyos/services/api/graphql/generate/generate_schema.py diff --git a/python/vyos/configquery.py b/python/vyos/configquery.py index 5b097b312..85fef8777 100644 --- a/python/vyos/configquery.py +++ b/python/vyos/configquery.py @@ -88,7 +88,7 @@ class ConfigTreeQuery(GenericConfigQuery): with open(config_file) as f: config_string = f.read() except OSError as err: - raise ConfigQueryError('No config file available') from err + config_string = '' config_source = ConfigSourceString(running_config_text=config_string, session_config_text=config_string) diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index db0def8ed..060a0ba03 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -22,6 +22,7 @@ directories = { 'data' : '/usr/share/vyos/', 'conf_mode' : f'{base_dir}/conf_mode', 'op_mode' : f'{base_dir}/op_mode', + 'services' : f'{base_dir}/services', 'config' : '/opt/vyatta/etc/config', 'current' : '/opt/vyatta/etc/config-migrate/current', 'migrate' : '/opt/vyatta/etc/config-migrate/migrate', diff --git a/smoketest/scripts/cli/test_service_https.py b/smoketest/scripts/cli/test_service_https.py index 0f4b1393c..1adf1f5cf 100755 --- a/smoketest/scripts/cli/test_service_https.py +++ b/smoketest/scripts/cli/test_service_https.py @@ -193,7 +193,8 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase): """ r = request('POST', graphql_url, verify=False, headers=headers, json={'query': query_no_key}) - self.assertEqual(r.status_code, 400) + success = r.json()['data']['SystemStatus']['success'] + self.assertFalse(success) # GraphQL token authentication test: request token; pass in header # of query. diff --git a/src/services/api/graphql/bindings.py b/src/services/api/graphql/bindings.py index aa1ba0eb0..ef4966466 100644 --- a/src/services/api/graphql/bindings.py +++ b/src/services/api/graphql/bindings.py @@ -19,9 +19,6 @@ from . graphql.mutations import mutation from . graphql.directives import directives_dict from . graphql.errors import op_mode_error from . graphql.auth_token_mutation import auth_token_mutation -from . generate.schema_from_op_mode import generate_op_mode_definitions -from . generate.schema_from_config_session import generate_config_session_definitions -from . generate.schema_from_composite import generate_composite_definitions from . libs.token_auth import init_secret from . import state from ariadne import make_executable_schema, load_schema_from_path, snake_case_fallback_resolvers @@ -29,10 +26,6 @@ from ariadne import make_executable_schema, load_schema_from_path, snake_case_fa def generate_schema(): api_schema_dir = vyos.defaults.directories['api_schema'] - generate_op_mode_definitions() - generate_config_session_definitions() - generate_composite_definitions() - if state.settings['app'].state.vyos_auth_type == 'token': init_secret() diff --git a/src/services/api/graphql/generate/generate_schema.py b/src/services/api/graphql/generate/generate_schema.py new file mode 100755 index 000000000..dd5e7ea56 --- /dev/null +++ b/src/services/api/graphql/generate/generate_schema.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. +# +# + +from schema_from_op_mode import generate_op_mode_definitions +from schema_from_config_session import generate_config_session_definitions +from schema_from_composite import generate_composite_definitions + +if __name__ == '__main__': + generate_op_mode_definitions() + generate_config_session_definitions() + generate_composite_definitions() diff --git a/src/services/api/graphql/generate/schema_from_composite.py b/src/services/api/graphql/generate/schema_from_composite.py index 61a08cb2f..50c5d24f8 100755 --- a/src/services/api/graphql/generate/schema_from_composite.py +++ b/src/services/api/graphql/generate/schema_from_composite.py @@ -26,12 +26,9 @@ from jinja2 import Template from vyos.defaults import directories if __package__ is None or __package__ == '': - sys.path.append("/usr/libexec/vyos/services/api") + sys.path.append(os.path.join(directories['services'], 'api')) from graphql.libs.op_mode import snake_to_pascal_case, map_type_name from composite_function import queries, mutations - from vyos.config import Config - from vyos.configdict import dict_merge - from vyos.xml import defaults else: from .. libs.op_mode import snake_to_pascal_case, map_type_name from . composite_function import queries, mutations @@ -39,40 +36,16 @@ else: SCHEMA_PATH = directories['api_schema'] -if __package__ is None or __package__ == '': - # allow running stand-alone - conf = Config() - base = ['service', 'https', 'api'] - graphql_dict = conf.get_config_dict(base, key_mangling=('-', '_'), - no_tag_node_value_mangle=True, - get_first_key=True) - if 'graphql' not in graphql_dict: - exit("graphql is not configured") - - graphql_dict = dict_merge(defaults(base), graphql_dict) - auth_type = graphql_dict['graphql']['authentication']['type'] -else: - auth_type = state.settings['app'].state.vyos_auth_type - -schema_data: dict = {'auth_type': auth_type, - 'schema_name': '', +schema_data: dict = {'schema_name': '', 'schema_fields': []} query_template = """ -{%- if auth_type == 'key' %} input {{ schema_name }}Input { - key: String! + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- elif schema_fields %} -input {{ schema_name }}Input { - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- endif %} type {{ schema_name }} { result: Generic @@ -85,29 +58,17 @@ type {{ schema_name }}Result { } extend type Query { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @compositequery -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @compositequery -{%- endif %} } """ mutation_template = """ -{%- if auth_type == 'key' %} -input {{ schema_name }}Input { - key: String! - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- elif schema_fields %} input {{ schema_name }}Input { + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- endif %} type {{ schema_name }} { result: Generic @@ -120,11 +81,7 @@ type {{ schema_name }}Result { } extend type Mutation { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @compositemutation -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @compositemutation -{%- endif %} } """ diff --git a/src/services/api/graphql/generate/schema_from_config_session.py b/src/services/api/graphql/generate/schema_from_config_session.py index 49bf2440e..831faa41e 100755 --- a/src/services/api/graphql/generate/schema_from_config_session.py +++ b/src/services/api/graphql/generate/schema_from_config_session.py @@ -26,12 +26,9 @@ from jinja2 import Template from vyos.defaults import directories if __package__ is None or __package__ == '': - sys.path.append("/usr/libexec/vyos/services/api") + sys.path.append(os.path.join(directories['services'], 'api')) from graphql.libs.op_mode import snake_to_pascal_case, map_type_name from config_session_function import queries, mutations - from vyos.config import Config - from vyos.configdict import dict_merge - from vyos.xml import defaults else: from .. libs.op_mode import snake_to_pascal_case, map_type_name from . config_session_function import queries, mutations @@ -39,40 +36,16 @@ else: SCHEMA_PATH = directories['api_schema'] -if __package__ is None or __package__ == '': - # allow running stand-alone - conf = Config() - base = ['service', 'https', 'api'] - graphql_dict = conf.get_config_dict(base, key_mangling=('-', '_'), - no_tag_node_value_mangle=True, - get_first_key=True) - if 'graphql' not in graphql_dict: - exit("graphql is not configured") - - graphql_dict = dict_merge(defaults(base), graphql_dict) - auth_type = graphql_dict['graphql']['authentication']['type'] -else: - auth_type = state.settings['app'].state.vyos_auth_type - -schema_data: dict = {'auth_type': auth_type, - 'schema_name': '', +schema_data: dict = {'schema_name': '', 'schema_fields': []} query_template = """ -{%- if auth_type == 'key' %} input {{ schema_name }}Input { - key: String! + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- elif schema_fields %} -input {{ schema_name }}Input { - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- endif %} type {{ schema_name }} { result: Generic @@ -85,29 +58,17 @@ type {{ schema_name }}Result { } extend type Query { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @configsessionquery -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @configsessionquery -{%- endif %} } """ mutation_template = """ -{%- if auth_type == 'key' %} -input {{ schema_name }}Input { - key: String! - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- elif schema_fields %} input {{ schema_name }}Input { + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- endif %} type {{ schema_name }} { result: Generic @@ -120,11 +81,7 @@ type {{ schema_name }}Result { } extend type Mutation { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @configsessionmutation -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @configsessionmutation -{%- endif %} } """ diff --git a/src/services/api/graphql/generate/schema_from_op_mode.py b/src/services/api/graphql/generate/schema_from_op_mode.py index b320a529e..98b2ad7b7 100755 --- a/src/services/api/graphql/generate/schema_from_op_mode.py +++ b/src/services/api/graphql/generate/schema_from_op_mode.py @@ -28,12 +28,9 @@ from vyos.defaults import directories from vyos.opmode import _is_op_mode_function_name as is_op_mode_function_name from vyos.util import load_as_module if __package__ is None or __package__ == '': - sys.path.append("/usr/libexec/vyos/services/api") + sys.path.append(os.path.join(directories['services'], 'api')) from graphql.libs.op_mode import is_show_function_name from graphql.libs.op_mode import snake_to_pascal_case, map_type_name - from vyos.config import Config - from vyos.configdict import dict_merge - from vyos.xml import defaults else: from .. libs.op_mode import is_show_function_name from .. libs.op_mode import snake_to_pascal_case, map_type_name @@ -46,40 +43,16 @@ DATA_DIR = directories['data'] op_mode_include_file = os.path.join(DATA_DIR, 'op-mode-standardized.json') op_mode_error_schema = 'op_mode_error.graphql' -if __package__ is None or __package__ == '': - # allow running stand-alone - conf = Config() - base = ['service', 'https', 'api'] - graphql_dict = conf.get_config_dict(base, key_mangling=('-', '_'), - no_tag_node_value_mangle=True, - get_first_key=True) - if 'graphql' not in graphql_dict: - exit("graphql is not configured") - - graphql_dict = dict_merge(defaults(base), graphql_dict) - auth_type = graphql_dict['graphql']['authentication']['type'] -else: - auth_type = state.settings['app'].state.vyos_auth_type - -schema_data: dict = {'auth_type': auth_type, - 'schema_name': '', +schema_data: dict = {'schema_name': '', 'schema_fields': []} query_template = """ -{%- if auth_type == 'key' %} input {{ schema_name }}Input { - key: String! + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- elif schema_fields %} -input {{ schema_name }}Input { - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- endif %} type {{ schema_name }} { result: Generic @@ -93,29 +66,17 @@ type {{ schema_name }}Result { } extend type Query { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @genopquery -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @genopquery -{%- endif %} } """ mutation_template = """ -{%- if auth_type == 'key' %} -input {{ schema_name }}Input { - key: String! - {%- for field_entry in schema_fields %} - {{ field_entry }} - {%- endfor %} -} -{%- elif schema_fields %} input {{ schema_name }}Input { + key: String {%- for field_entry in schema_fields %} {{ field_entry }} {%- endfor %} } -{%- endif %} type {{ schema_name }} { result: Generic @@ -129,11 +90,7 @@ type {{ schema_name }}Result { } extend type Mutation { -{%- if auth_type == 'key' or schema_fields %} {{ schema_name }}(data: {{ schema_name }}Input) : {{ schema_name }}Result @genopmutation -{%- else %} - {{ schema_name }} : {{ schema_name }}Result @genopquery -{%- endif %} } """ |