Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F117520516
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/services/api/graphql/graphql/directives.py b/src/services/api/graphql/graphql/directives.py
index f5cd88acd..55aceca1b 100644
--- a/src/services/api/graphql/graphql/directives.py
+++ b/src/services/api/graphql/graphql/directives.py
@@ -1,37 +1,45 @@
from ariadne import SchemaDirectiveVisitor, ObjectType
-from . mutations import make_configure_resolver, make_config_file_resolver
+from . mutations import *
def non(arg):
pass
class VyosDirective(SchemaDirectiveVisitor):
def visit_field_definition(self, field, object_type, make_resolver=non):
name = f'{field.type}'
# field.type contains the return value of the mutation; trim value
# to produce canonical name
name = name.replace('Result', '', 1)
func = make_resolver(name)
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 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)
-directives_dict = {"configure": ConfigureDirective, "configfile": ConfigFileDirective}
+class ShowDirective(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_resolver)
+
+directives_dict = {"configure": ConfigureDirective,
+ "configfile": ConfigFileDirective,
+ "show": ShowDirective}
diff --git a/src/services/api/graphql/graphql/mutations.py b/src/services/api/graphql/graphql/mutations.py
index 8a28b13d7..5913ee8b1 100644
--- a/src/services/api/graphql/graphql/mutations.py
+++ b/src/services/api/graphql/graphql/mutations.py
@@ -1,80 +1,85 @@
from importlib import import_module
from typing import Any, Dict
from ariadne import ObjectType, convert_kwargs_to_snake_case, convert_camel_case_to_snake
from graphql import GraphQLResolveInfo
from makefun import with_signature
from .. import state
from api.graphql.recipes.session import Session
mutation = ObjectType("Mutation")
def make_resolver(mutation_name, class_name, session_func):
"""Dynamically generate a resolver for the mutation named in the
schema by 'mutation_name'.
Dynamic generation is provided using the package 'makefun' (via the
decorator 'with_signature'), which provides signature-preserving
function wrappers; it provides several improvements over, say,
functools.wraps.
:raise Exception:
raising ConfigErrors, or internal errors
"""
func_base_name = convert_camel_case_to_snake(class_name)
resolver_name = f'resolve_{func_base_name}'
func_sig = '(obj: Any, info: GraphQLResolveInfo, data: Dict)'
@mutation.field(mutation_name)
@convert_kwargs_to_snake_case
@with_signature(func_sig, func_name=resolver_name)
async def func_impl(*args, **kwargs):
try:
if 'data' not in kwargs:
return {
"success": False,
"errors": ['missing data']
}
data = kwargs['data']
session = state.settings['app'].state.vyos_session
# one may override the session functions with a local subclass
try:
mod = import_module(f'api.graphql.recipes.{func_base_name}')
klass = getattr(mod, class_name)
except ImportError:
# otherwise, dynamically generate subclass to invoke subclass
# name based templates
klass = type(class_name, (Session,), {})
k = klass(session, data)
method = getattr(k, session_func)
- method()
+ result = method()
+ data['result'] = result
return {
"success": True,
"data": data
}
except Exception as error:
return {
"success": False,
"errors": [str(error)]
}
return func_impl
def make_configure_resolver(mutation_name):
class_name = mutation_name
return make_resolver(mutation_name, class_name, 'configure')
def make_config_file_resolver(mutation_name):
if 'Save' in mutation_name:
class_name = mutation_name.replace('Save', '', 1)
return make_resolver(mutation_name, class_name, 'save')
elif 'Load' in mutation_name:
class_name = mutation_name.replace('Load', '', 1)
return make_resolver(mutation_name, class_name, 'load')
else:
raise Exception
+
+def make_show_resolver(mutation_name):
+ class_name = mutation_name
+ return make_resolver(mutation_name, class_name, 'show')
diff --git a/src/services/api/graphql/graphql/schema/schema.graphql b/src/services/api/graphql/graphql/schema/schema.graphql
index 9e97a0d60..764a50130 100644
--- a/src/services/api/graphql/graphql/schema/schema.graphql
+++ b/src/services/api/graphql/graphql/schema/schema.graphql
@@ -1,21 +1,23 @@
schema {
query: Query
mutation: Mutation
}
type Query {
_dummy: String
}
directive @configure on FIELD_DEFINITION
directive @configfile on FIELD_DEFINITION
+directive @show on FIELD_DEFINITION
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
SaveConfigFile(data: SaveConfigFileInput) : SaveConfigFileResult @configfile
LoadConfigFile(data: LoadConfigFileInput) : LoadConfigFileResult @configfile
+ Show(data: ShowInput) : ShowResult @show
}
diff --git a/src/services/api/graphql/graphql/schema/show.graphql b/src/services/api/graphql/graphql/schema/show.graphql
new file mode 100644
index 000000000..c7709e48b
--- /dev/null
+++ b/src/services/api/graphql/graphql/schema/show.graphql
@@ -0,0 +1,14 @@
+input ShowInput {
+ path: [String!]!
+}
+
+type Show {
+ path: [String]
+ result: String
+}
+
+type ShowResult {
+ data: Show
+ success: Boolean!
+ errors: [String]
+}
diff --git a/src/services/api/graphql/recipes/session.py b/src/services/api/graphql/recipes/session.py
index b96cc1753..c6c3209c0 100644
--- a/src/services/api/graphql/recipes/session.py
+++ b/src/services/api/graphql/recipes/session.py
@@ -1,65 +1,77 @@
from ariadne import convert_camel_case_to_snake
import vyos.defaults
from vyos.config import Config
from vyos.template import render
class Session(object):
def __init__(self, session, data):
self._session = session
self._data = data
self._name = convert_camel_case_to_snake(type(self).__name__)
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 = vyos.defaults.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 save(self):
session = self._session
data = self._data
if 'file_name' not in data or not data['file_name']:
data['file_name'] = '/config/config.boot'
try:
session.save_config(data['file_name'])
except Exception as error:
raise error
def load(self):
session = self._session
data = self._data
try:
session.load_config(data['file_name'])
session.commit()
except Exception as error:
raise error
+
+ def show(self):
+ session = self._session
+ data = self._data
+ out = ''
+
+ try:
+ out = session.show(data['path'])
+ except Exception as error:
+ raise error
+
+ return out
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Sep 26, 10:53 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4284972
Default Alt Text
(9 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment