diff options
18 files changed, 426 insertions, 145 deletions
diff --git a/moonclient/moonclient/authz_policies.py b/moonclient/moonclient/authz_policies.py deleted file mode 100644 index 66ab39c0..00000000 --- a/moonclient/moonclient/authz_policies.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. - -import logging - -from cliff.lister import Lister - - -class AuthzPolicies(Lister): - """List all Intra_Extensions.""" - - log = logging.getLogger(__name__) - - def get_parser(self, prog_name): - parser = super(AuthzPolicies, self).get_parser(prog_name) - return parser - - def take_action(self, parsed_args): - policies = self.app.get_url("/v3/OS-MOON/authz_policies", authtoken=True)["authz_policies"] - return ( - ("name",), - ((_name, ) for _name in policies) - ) diff --git a/moonclient/moonclient/configuration.py b/moonclient/moonclient/configuration.py new file mode 100644 index 00000000..df80d71e --- /dev/null +++ b/moonclient/moonclient/configuration.py @@ -0,0 +1,70 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import logging + +from cliff.lister import Lister + + +class TemplatesList(Lister): + """List all policy templates.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TemplatesList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + templates = self.app.get_url("/v3/OS-MOON/configuration/templates", authtoken=True) + self.app.stdout.write(templates) + self.app.stdout.write("\n") + return ( + ("id", "name", "description"), + ((template_id, templates[template_id]["name"], templates[template_id]["description"]) + for template_id in templates) + ) + + +class AggregationAlgorithmsList(Lister): + """List all aggregation algorithms.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(AggregationAlgorithmsList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + templates = self.app.get_url("/v3/OS-MOON/configuration/aggregation_algorithms", authtoken=True) + self.app.stdout.write(templates) + self.app.stdout.write("\n") + return ( + ("id", "name", "description"), + ((template_id, templates[template_id]["name"], templates[template_id]["description"]) + for template_id in templates) + ) + + +class SubMetaRuleAlgorithmsList(Lister): + """List all aggregation algorithms.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(SubMetaRuleAlgorithmsList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + templates = self.app.get_url("/v3/OS-MOON/configuration/sub_meta_rule_algorithms", authtoken=True) + self.app.stdout.write(templates) + self.app.stdout.write("\n") + return ( + ("id", "name", "description"), + ((template_id, templates[template_id]["name"], templates[template_id]["description"]) + for template_id in templates) + ) + + diff --git a/moonclient/moonclient/shell.py b/moonclient/moonclient/shell.py index 406e0a7f..5005095e 100644 --- a/moonclient/moonclient/shell.py +++ b/moonclient/moonclient/shell.py @@ -90,6 +90,9 @@ class MoonClient(App): break return self._intraextension + def get_tenant_uuid(self, tenant_name): + return self.get_url("/v3/projects?name={}".format(tenant_name), authtoken=True)["projects"][0]["id"] + def get_url(self, url, post_data=None, delete_data=None, method="GET", authtoken=None): if post_data: method = "POST" @@ -97,6 +100,7 @@ class MoonClient(App): method = "DELETE" self.log.debug("\033[32m{} {}\033[m".format(method, url)) conn = httplib.HTTPConnection(self.host, self.port) + self.log.info("Host: {}:{}".format(self.host, self.port)) headers = { "Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", diff --git a/moonclient/moonclient/tenants.py b/moonclient/moonclient/tenants.py new file mode 100644 index 00000000..b51b00ee --- /dev/null +++ b/moonclient/moonclient/tenants.py @@ -0,0 +1,199 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import logging + +from cliff.lister import Lister +from cliff.command import Command + + +class TenantList(Lister): + """List all tenants.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TenantList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + tenants = self.app.get_url("/v3/OS-MOON/tenants", authtoken=True) + self.log.debug(tenants) + return ( + ("id", "name", "description", "intra_authz_extension_id", "intra_admin_extension_id"), + (( + tenant_id, + tenants[tenant_id]["name"], + tenants[tenant_id]["description"], + tenants[tenant_id]["intra_authz_extension_id"], + tenants[tenant_id]["intra_admin_extension_id"], + ) + for tenant_id in tenants) + ) + + +class TenantAdd(Command): + """Add a tenant.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TenantAdd, self).get_parser(prog_name) + parser.add_argument( + 'tenant_name', + metavar='<tenant-name>', + help='Tenant name', + ) + parser.add_argument( + '--authz', + metavar='<authz-intraextension-uuid>', + help='Authz IntraExtension UUID', + ) + parser.add_argument( + '--admin', + metavar='<admin-intraextension-uuid>', + help='Admin IntraExtension UUID', + ) + parser.add_argument( + '--desc', + metavar='<tenant-description-str>', + help='Tenant description', + ) + return parser + + def take_action(self, parsed_args): + post_data = dict() + post_data["tenant_name"] = parsed_args.tenant_name + if parsed_args.authz: + post_data["tenant_intra_authz_extension_id"] = parsed_args.authz + if parsed_args.admin: + post_data["tenant_intra_admin_extension_id"] = parsed_args.admin + if parsed_args.desc: + post_data["description"] = parsed_args.desc + tenants = self.app.get_url("/v3/OS-MOON/tenants", + post_data=post_data, + authtoken=True) + return ( + ("id", "name", "description", "intra_authz_extension_id", "intra_admin_extension_id"), + (( + tenant_id, + tenants[tenant_id]["name"], + tenants[tenant_id]["description"], + tenants[tenant_id]["intra_authz_extension_id"], + tenants[tenant_id]["intra_admin_extension_id"], + ) + for tenant_id in tenants) + ) + + +class TenantShow(Command): + """Show information about a tenant.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TenantShow, self).get_parser(prog_name) + parser.add_argument( + 'tenant_name', + metavar='<tenant-name>', + help='Tenant name', + ) + return parser + + def take_action(self, parsed_args): + tenants = self.app.get_url("/v3/OS-MOON/tenants/{}".format(parsed_args.tenant_name), + authtoken=True) + return ( + ("id", "name", "description", "intra_authz_extension_id", "intra_admin_extension_id"), + (( + tenant_id, + tenants[tenant_id]["name"], + tenants[tenant_id]["description"], + tenants[tenant_id]["intra_authz_extension_id"], + tenants[tenant_id]["intra_admin_extension_id"], + ) + for tenant_id in tenants) + ) + + +class TenantSet(Command): + """Modify a tenant.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TenantSet, self).get_parser(prog_name) + parser.add_argument( + 'tenant_id', + metavar='<tenant-id>', + help='Tenant UUID', + ) + parser.add_argument( + '--name', + metavar='<tenant-name>', + help='Tenant name', + ) + parser.add_argument( + '--authz', + metavar='<authz-intraextension-uuid>', + help='Authz IntraExtension UUID', + ) + parser.add_argument( + '--admin', + metavar='<admin-intraextension-uuid>', + help='Admin IntraExtension UUID', + ) + parser.add_argument( + '--desc', + metavar='<tenant-description-str>', + help='Tenant description', + ) + return parser + + def take_action(self, parsed_args): + post_data = dict() + post_data["id"] = parsed_args.tenant_id + if parsed_args.name: + post_data["name"] = parsed_args.tenant_name + if parsed_args.authz: + post_data["intra_authz_extension_id"] = parsed_args.authz + if parsed_args.admin: + post_data["intra_admin_extension_id"] = parsed_args.admin + if parsed_args.desc: + post_data["description"] = parsed_args.desc + tenants = self.app.get_url("/v3/OS-MOON/tenants/{}".format(post_data["id"]), + post_data=post_data, + authtoken=True) + return ( + ("id", "name", "description", "intra_authz_extension_id", "intra_admin_extension_id"), + (( + tenant_id, + tenants[tenant_id]["name"], + tenants[tenant_id]["description"], + tenants[tenant_id]["intra_authz_extension_id"], + tenants[tenant_id]["intra_admin_extension_id"], + ) + for tenant_id in tenants) + ) + + +class TenantDelete(Command): + """Modify a tenant.""" + + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TenantDelete, self).get_parser(prog_name) + parser.add_argument( + 'tenant_id', + metavar='<tenant-id>', + help='Tenant UUID', + ) + return parser + + def take_action(self, parsed_args): + self.app.get_url("/v3/OS-MOON/tenants/{}".format(parsed_args.tenant_id), + method="DELETE", + authtoken=True) diff --git a/moonclient/moonclient/tests.py b/moonclient/moonclient/tests.py index 5b02576c..e058fd9b 100644 --- a/moonclient/moonclient/tests.py +++ b/moonclient/moonclient/tests.py @@ -1 +1,56 @@ -__author__ = 'vdsq3226' +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import logging +import json +import shlex +import re +from cliff.lister import Lister +from cliff.command import Command + + +class TestsLaunch(Lister): + """List all Intra_Extensions.""" + + log = logging.getLogger(__name__) + result_vars = dict() + + def get_parser(self, prog_name): + parser = super(TestsLaunch, self).get_parser(prog_name) + parser.add_argument( + '--testfile', + metavar='<filename>', + help='Filename that contains tests to run', + ) + return parser + + def __replace_var_in_str(self, data_str): + for exp in re.findall("\$\w+"): + if exp.replace("$", "") in self.result_vars: + data_str.replace(exp, self.result_vars[exp.replace("$", "")]) + return data_str + + def __compare_results(self, expected, observed): + if expected in observed: + return True + return False + + def take_action(self, parsed_args): + tests_dict = json.load(open(parsed_args.testfile)) + data = list() + for group_name, tests_list in tests_dict.iteritems(): + for test in tests_list: + data_tmp = list() + command = self.__replace_var_in_str(test["command"]) + result = self.app.run_subcommand(shlex.split(command)) + data_tmp.append(test["name"]) + data_tmp.append(self.__compare_results(test["result"], result)) + data_tmp.append(test["description"]) + data.append(data_tmp) + + return ( + ("test_name", "result", "description"), + data + ) diff --git a/moonclient/moonclient/tests/functional_tests.json b/moonclient/moonclient/tests/functional_tests.json deleted file mode 100644 index e69de29b..00000000 --- a/moonclient/moonclient/tests/functional_tests.json +++ /dev/null diff --git a/moonclient/moonclient/tests/tests_intra_extensions.json b/moonclient/moonclient/tests/tests_intra_extensions.json new file mode 100644 index 00000000..a6d369aa --- /dev/null +++ b/moonclient/moonclient/tests/tests_intra_extensions.json @@ -0,0 +1,43 @@ +{ + "command_prefix": "moon", + "tests_group": { + "group1": [ + { + "name": "create_intraextension_authz", + "command": "intraextension create --policy_model policy_authz func_test", + "result": "%uuid_authz%", + "description": "Create an authz intra extension" + }, + { + "name": "list_intraextension_authz", + "command": "intraextension list", + "result": "$uuid_authz", + "description": "Check the existence of that authz intra extension" + }, + { + "name": "create_intraextension_admin", + "command": "intraextension create --policy_model policy_admin func_test", + "result": "%uuid_admin%", + "description": "Create an admin intra extension" + }, + { + "name": "list_intraextension_admin", + "command": "intraextension list", + "result": "$uuid_admin", + "description": "Check the existence of that admin intra extension" + }, + { + "name": "set_tenant_authz", + "command": "intraextension tenant set authz $uuid_authz demo", + "result": "", + "description": "Connect the authz intra extension to the tenant demo" + }, + { + "name": "set_tenant_admin", + "command": "intraextension tenant set authz $uuid_authz demo", + "result": "", + "description": "Connect the admin intra extension to the tenant demo" + } + ] + } +}
\ No newline at end of file diff --git a/moonclient/moonclient/tests/tests_tenants.json b/moonclient/moonclient/tests/tests_tenants.json new file mode 100644 index 00000000..76e2b10c --- /dev/null +++ b/moonclient/moonclient/tests/tests_tenants.json @@ -0,0 +1,43 @@ +{ + "command_prefix": "moon", + "tests_group": { + "group1": [ + { + "name": "list tenant", + "command": "tenant list", + "result": "^$", + "description": "List all tenants (must be empty)" + }, + { + "name": "add tenant demo", + "command": "tenant add demo", + "result": "Tenant created: (?P<uuid>\\w+)", + "description": "Add a new tenant" + }, + { + "name": "create_intraextension_admin", + "command": "intraextension create --policy_model policy_admin func_test", + "result": "%uuid_admin%", + "description": "Create an admin intra extension" + }, + { + "name": "list_intraextension_admin", + "command": "intraextension list", + "result": "$uuid_admin", + "description": "Check the existence of that admin intra extension" + }, + { + "name": "set_tenant_authz", + "command": "intraextension tenant set authz $uuid_authz demo", + "result": "", + "description": "Connect the authz intra extension to the tenant demo" + }, + { + "name": "set_tenant_admin", + "command": "intraextension tenant set authz $uuid_authz demo", + "result": "", + "description": "Connect the admin intra extension to the tenant demo" + } + ] + } +}
\ No newline at end of file diff --git a/moonclient/python_moonclient.egg-info/PKG-INFO b/moonclient/python_moonclient.egg-info/PKG-INFO deleted file mode 100644 index 271dc838..00000000 --- a/moonclient/python_moonclient.egg-info/PKG-INFO +++ /dev/null @@ -1,22 +0,0 @@ -Metadata-Version: 1.1 -Name: python-moonclient -Version: 0.1 -Summary: Python Moon client -Home-page: https://github.com/... -Author: Thomas Duval -Author-email: thomas.duval@orange.com -License: UNKNOWN -Download-URL: https://github.com/.../tarball/master -Description: Moon Client - - -Platform: Any -Classifier: Development Status :: 3 - Alpha -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Intended Audience :: Developers -Classifier: Environment :: Console diff --git a/moonclient/python_moonclient.egg-info/SOURCES.txt b/moonclient/python_moonclient.egg-info/SOURCES.txt deleted file mode 100644 index 4b0096d8..00000000 --- a/moonclient/python_moonclient.egg-info/SOURCES.txt +++ /dev/null @@ -1,33 +0,0 @@ -MANIFEST.in -README.rst -setup.cfg -setup.py -moonclient/__init__.py -moonclient/action_assignments.py -moonclient/action_categories.py -moonclient/action_category_scope.py -moonclient/actions.py -moonclient/authz_policies.py -moonclient/intraextension.py -moonclient/logs.py -moonclient/metarules.py -moonclient/object_assignments.py -moonclient/object_categories.py -moonclient/object_category_scope.py -moonclient/objects.py -moonclient/rules.py -moonclient/shell.py -moonclient/subject_assignments.py -moonclient/subject_categories.py -moonclient/subject_category_scope.py -moonclient/subjects.py -moonclient/tests/functional_tests.sh -python_moonclient.egg-info/PKG-INFO -python_moonclient.egg-info/SOURCES.txt -python_moonclient.egg-info/dependency_links.txt -python_moonclient.egg-info/entry_points.txt -python_moonclient.egg-info/namespace_packages.txt -python_moonclient.egg-info/not-zip-safe -python_moonclient.egg-info/pbr.json -python_moonclient.egg-info/requires.txt -python_moonclient.egg-info/top_level.txt
\ No newline at end of file diff --git a/moonclient/python_moonclient.egg-info/dependency_links.txt b/moonclient/python_moonclient.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891..00000000 --- a/moonclient/python_moonclient.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/moonclient/python_moonclient.egg-info/entry_points.txt b/moonclient/python_moonclient.egg-info/entry_points.txt deleted file mode 100644 index 2075f10a..00000000 --- a/moonclient/python_moonclient.egg-info/entry_points.txt +++ /dev/null @@ -1,57 +0,0 @@ -[moon.client] -actions_list = moonclient.actions:ActionsList -subject_categories_delete = moonclient.subject_categories:SubjectCategoriesDelete -objects_delete = moonclient.objects:ObjectsDelete -submetarule_show = moonclient.metarules:SubMetaRuleShow -actions_add = moonclient.actions:ActionsAdd -subjects_add = moonclient.subjects:SubjectsAdd -subject_category_scope_add = moonclient.subject_category_scope:SubjectCategoryScopeAdd -intraextension_show = moonclient.intraextension:IntraExtensionShow -rules_add = moonclient.rules:RuleAdd -subject_categories_list = moonclient.subject_categories:SubjectCategoriesList -action_categories_delete = moonclient.action_categories:ActionCategoriesDelete -subjects_delete = moonclient.subjects:SubjectsDelete -action_category_scope_list = moonclient.action_category_scope:ActionCategoryScopeList -subject_category_scope_delete = moonclient.subject_category_scope:SubjectCategoryScopeDelete -subjects_list = moonclient.subjects:SubjectsList -object_assignments_delete = moonclient.object_assignments:ObjectAssignmentsDelete -subject_category_scope_list = moonclient.subject_category_scope:SubjectCategoryScopeList -intraextension_delete = moonclient.intraextension:IntraExtensionDelete -rules_list = moonclient.rules:RulesList -logs = moonclient.logs:LogsList -actions_delete = moonclient.actions:ActionsDelete -object_assignments_list = moonclient.object_assignments:ObjectAssignmentsList -object_category_scope_delete = moonclient.object_category_scope:ObjectCategoryScopeDelete -policies_list = moonclient.authz_policies:AuthzPolicies -subject_categories_add = moonclient.subject_categories:SubjectCategoriesAdd -intraextension_tenant_set = moonclient.intraextension:TenantSet -subject_assignments_add = moonclient.subject_assignments:SubjectAssignmentsAdd -object_categories_delete = moonclient.object_categories:ObjectCategoriesDelete -intraextension_create = moonclient.intraextension:IntraExtensionCreate -object_category_scope_add = moonclient.object_category_scope:ObjectCategoryScopeAdd -intraextension_list = moonclient.intraextension:IntraExtensionList -action_assignments_list = moonclient.action_assignments:ActionAssignmentsList -action_assignments_delete = moonclient.action_assignments:ActionAssignmentsDelete -aggregation_algorithms_list = moonclient.metarules:AggregationAlgorithmsList -action_assignments_add = moonclient.action_assignments:ActionAssignmentsAdd -submetarule_set = moonclient.metarules:SubMetaRuleSet -action_categories_list = moonclient.action_categories:ActionCategoriesList -objects_add = moonclient.objects:ObjectsAdd -object_assignments_add = moonclient.object_assignments:ObjectAssignmentsAdd -action_categories_add = moonclient.action_categories:ActionCategoriesAdd -object_categories_add = moonclient.object_categories:ObjectCategoriesAdd -aggregation_algorithm_set = moonclient.metarules:AggregationAlgorithmSet -subject_assignments_delete = moonclient.subject_assignments:SubjectAssignmentsDelete -submetarule_relation_list = moonclient.metarules:SubMetaRuleRelationList -action_category_scope_delete = moonclient.action_category_scope:ActionCategoryScopeDelete -action_category_scope_add = moonclient.action_category_scope:ActionCategoryScopeAdd -rules_delete = moonclient.rules:RuleDelete -subject_assignments_list = moonclient.subject_assignments:SubjectAssignmentsList -aggregation_algorithm_show = moonclient.metarules:AggregationAlgorithmShow -object_categories_list = moonclient.object_categories:ObjectCategoriesList -objects_list = moonclient.objects:ObjectsList -object_category_scope_list = moonclient.object_category_scope:ObjectCategoryScopeList - -[console_scripts] -moon = moonclient.shell:main - diff --git a/moonclient/python_moonclient.egg-info/namespace_packages.txt b/moonclient/python_moonclient.egg-info/namespace_packages.txt deleted file mode 100644 index 8b137891..00000000 --- a/moonclient/python_moonclient.egg-info/namespace_packages.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/moonclient/python_moonclient.egg-info/not-zip-safe b/moonclient/python_moonclient.egg-info/not-zip-safe deleted file mode 100644 index 8b137891..00000000 --- a/moonclient/python_moonclient.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/moonclient/python_moonclient.egg-info/pbr.json b/moonclient/python_moonclient.egg-info/pbr.json deleted file mode 100644 index b5537aae..00000000 --- a/moonclient/python_moonclient.egg-info/pbr.json +++ /dev/null @@ -1 +0,0 @@ -{"is_release": false, "git_version": "ab3fa18"}
\ No newline at end of file diff --git a/moonclient/python_moonclient.egg-info/requires.txt b/moonclient/python_moonclient.egg-info/requires.txt deleted file mode 100644 index 4ba12194..00000000 --- a/moonclient/python_moonclient.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -cliff
\ No newline at end of file diff --git a/moonclient/python_moonclient.egg-info/top_level.txt b/moonclient/python_moonclient.egg-info/top_level.txt deleted file mode 100644 index aeaf6094..00000000 --- a/moonclient/python_moonclient.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -moonclient diff --git a/moonclient/setup.py b/moonclient/setup.py index e88d3a09..2da0ab1b 100644 --- a/moonclient/setup.py +++ b/moonclient/setup.py @@ -58,12 +58,22 @@ setup( 'moon = moonclient.shell:main' ], 'moon.client': [ - 'policy_list = moonclient.authz_policy:AuthzPolicies', + 'templates_list = moonclient.configuration:TemplatesList', + 'aggregation_algorithms_list = moonclient.configuration:AggregationAlgorithmsList', + 'submetarule_algorithms_list = moonclient.configuration:SubMetaRuleAlgorithmsList', + + 'tenant_add = moonclient.tenants:TenantAdd', + 'tenant_set = moonclient.tenants:TenantSet', + 'tenant_list = moonclient.tenants:TenantList', + 'tenant_show = moonclient.tenants:TenantShow', + 'tenant_delete = moonclient.tenants:TenantDelete', + 'intraextension_tenant_set = moonclient.intraextension:TenantSet', 'intraextension_create = moonclient.intraextension:IntraExtensionCreate', 'intraextension_list = moonclient.intraextension:IntraExtensionList', 'intraextension_delete = moonclient.intraextension:IntraExtensionDelete', 'intraextension_show = moonclient.intraextension:IntraExtensionShow', + 'subject_list = moonclient.subjects:SubjectsList', 'subject_add = moonclient.subjects:SubjectsAdd', 'subject_delete = moonclient.subjects:SubjectsDelete', |