summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2023-03-04 05:37:33 +0100
committerGitHub <noreply@github.com>2023-03-04 05:37:33 +0100
commit493af3f3417cef5c9898f242a2b885e63e3bdeef (patch)
treeb9536a832d7693f2f35d90fc75b58ff57be4d640
parente5eb4f332f03df51d64d51e7f38ee561f298188c (diff)
parent7ab3b9e021e7ce1c56b9f252a04400a37fd33e71 (diff)
downloadvyos-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.postinst3
-rw-r--r--python/vyos/configquery.py2
-rw-r--r--python/vyos/defaults.py1
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py3
-rw-r--r--src/services/api/graphql/bindings.py7
-rwxr-xr-xsrc/services/api/graphql/generate/generate_schema.py26
-rwxr-xr-xsrc/services/api/graphql/generate/schema_from_composite.py51
-rwxr-xr-xsrc/services/api/graphql/generate/schema_from_config_session.py51
-rwxr-xr-xsrc/services/api/graphql/generate/schema_from_op_mode.py51
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 %}
}
"""