Skip to content

Commit

Permalink
EOS-20329: Cli framework movement (Seagate#303)
Browse files Browse the repository at this point in the history
* CLI framework movement to pyutils: initial commit

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Cortxcli framework movement modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Code cleanup and Codacy issue resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Adding cli entry to setup.py

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Adding cli/schema files entry datafiles

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Resolving codacy issue

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Update liscence

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Add common validators to pyutils

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Update cli_validators.py

* Add RestCLient class consumable for Rest calls

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Add RestCLient class consumable for Rest calls

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Changing dir name cli -> cli_framework

Signed-off-by: Udayan Yaragattikar <[email protected]>

* MessageBus: Rest Interface using aiohttp (Seagate#257)

* EOS-20462: Adding rsyslog service restart. (Seagate#286)

* Adding rsyslog service restart

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Codacy issues resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Fix service handler

Signed-off-by: Udayan Yaragattikar <[email protected]>

* reverting the change

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Resolve codacy issue

* Resolving codacy issue

Co-authored-by: Sachin Punadikar <[email protected]>

* MessageBus: Rest Interface using aiohttp

This commit incorporated all the changes of PR 254.
And a few modifications as well.

Signed-off-by: Rahul Tripathi <[email protected]>

* Creating error class

Signed-off-by: Rahul Tripathi <[email protected]>

* Revert "Creating error class"

This reverts commit e7675f6a3add2c4d5935e08bb30812e373846bcd.

* Fixes with some cosmetic changes

Signed-off-by: Rahul Tripathi <[email protected]>

Co-authored-by: Udayan Yaragattikar <[email protected]>
Co-authored-by: Sachin Punadikar <[email protected]>

* EOS-16256: Instantiation of Event message and its attributes (Seagate#278)

* Implementation of Iem set and print method

Signed-off-by: Selvakumar <[email protected]>

* Change copyright year

Signed-off-by: Selvakumar <[email protected]>

* Change in class interfaces

Signed-off-by: Selvakumar <[email protected]>

* Cosmetic changes

Signed-off-by: Selvakumar <[email protected]>

* Implemented send and receive

Signed-off-by: Selvakumar <[email protected]>

* Change hex values to string and method parameters

Signed-off-by: Selvakumar <[email protected]>

* Change hex values to string and method parameters

Signed-off-by: Selvakumar <[email protected]>

* Initialise client in init by a bool parameter

Signed-off-by: Selvakumar <[email protected]>

* Remove unneccesary validation

Signed-off-by: Selvakumar <[email protected]>

* Added test code and Derived Error from UtilsError

Signed-off-by: Selvakumar <[email protected]>

* Update Multiline comments

Signed-off-by: Selvakumar <[email protected]>

* Defined Alert schema and added more testcases

Signed-off-by: Selvakumar <[email protected]>

* Modify BaseError to UtilsError

Signed-off-by: Selvakumar <[email protected]>

* fix codacy issues

Signed-off-by: Selvakumar <[email protected]>

* fix codacy issues

Signed-off-by: Selvakumar <[email protected]>

* change multiline comments

Signed-off-by: Selvakumar <[email protected]>

* Make alert schema consistent

Signed-off-by: Selvakumar <[email protected]>

* Resolve conflicting files

Signed-off-by: Selvakumar <[email protected]>

* Changing ArgumentError->CliError

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Move cli_validators to validator directory

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Codacy issues resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Adding provider classes

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Adding unit testcases for cli framework

Signed-off-by: Udayan Yaragattikar <[email protected]>

* minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Codacy issue resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Resolvinf comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Rename test cli framework

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing  comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing  comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modification

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modification

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Codacy issue  resolve

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modification

Signed-off-by: Udayan Yaragattikar <[email protected]>

* minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modificattions for cli framework

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modificattions for cli framework

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Minor modifications

Signed-off-by: Udayan Yaragattikar <[email protected]>

* codacy iissue resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* minor change

* Test commit

Signed-off-by: root <[email protected]>

* Update users.json

* Adding v_format validator

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Added unittestcases for Format validator

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Resolve codacy issue

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Codacy issue resolved

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Addressing comments

Signed-off-by: Udayan Yaragattikar <[email protected]>

* Removed format validator

Signed-off-by: Udayan Yaragattikar <[email protected]>

Co-authored-by: rahul-tripathi-git <[email protected]>
Co-authored-by: Sachin Punadikar <[email protected]>
Co-authored-by: Selva Nambi <[email protected]>
Co-authored-by: root <[email protected]>
  • Loading branch information
5 people authored Jun 8, 2021
1 parent d528e33 commit 1ff3cfa
Show file tree
Hide file tree
Showing 14 changed files with 841 additions and 1 deletion.
3 changes: 2 additions & 1 deletion py-utils/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ def get_install_requirements() -> list:
'cortx.utils.product_features', 'cortx.utils.security',
'cortx.utils.schema', 'cortx.utils.appliance_info',
'cortx.setup', 'cortx.utils.service',
'cortx.utils.setup', 'cortx.utils.setup.kafka',
'cortx.utils.setup', 'cortx.utils.setup.kafka',
'cortx.utils.cli_framework',
'cortx.utils.rest_server', 'cortx.utils.iem_framework'
],
package_data={
Expand Down
14 changes: 14 additions & 0 deletions py-utils/src/utils/cli_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# CORTX-Py-Utils: CORTX Python common library.
# Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# For any questions about this software or licensing,
# please email [email protected] or [email protected].
55 changes: 55 additions & 0 deletions py-utils/src/utils/cli_framework/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# CORTX-Py-Utils: CORTX Python common library.
# Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# For any questions about this software or licensing,
# please email [email protected] or [email protected].

from importlib import import_module
import aiohttp


class Client:
""" Base class for invoking business logic functionality """

def __init__(self, url):
self._url = url

def call(self, command):
pass


class CliClient(Client):
"""Class Handles Direct Calls for CLI"""
def __init__(self):
super(CliClient, self).__init__(None)

async def call(self, command):
module_obj = import_module(command.comm.get("target"))
if command.comm.get("class", None):
if command.comm.get("is_static", False):
target = getattr(module_obj, command.comm.get("class"))
else:
target = getattr(module_obj, command.comm.get("class"))()
else:
target = module_obj
return await getattr(target, command.comm.get("method"))(command)


class RestClient(Client):
""" Class handles REST call for cli"""
# TODO: Implement RestClient as per the use case.
def __init__(self):
super(RestClient, self).__init__(None)

def call(self, session, cmd, action, options, args, method):
#TODO: Implement to create rest request.
pass
208 changes: 208 additions & 0 deletions py-utils/src/utils/cli_framework/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# CORTX-Py-Utils: CORTX Python common library.
# Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# For any questions about this software or licensing,
# please email [email protected] or [email protected].


import json
from typing import Dict, Any
from dict2xml import dict2xml
from prettytable import PrettyTable
from cortx.utils.cli_framework import const

class Command:
"""CLI Command Base Class"""

def __init__(self, name, options, args):
self._method = options["comm"]["method"]
self._target = options["comm"]["target"]
self._comm = options["comm"]
self._options = options
self._args = args
self._name = name
self._output = options["output"]
self._need_confirmation = options["need_confirmation"]
self._sub_command_name = options["sub_command_name"]

@property
def name(self):
return self._name

@property
def options(self):
return self._options

@property
def args(self):
return self._args

@property
def method(self):
return self._method

@property
def target(self):
return self._target

@property
def comm(self):
return self._comm

@property
def need_confirmation(self):
return self._need_confirmation

@property
def sub_command_name(self):
return self._sub_command_name

def process_response(self, response, out, err):
"""Process Response as per display method in format else normal display"""
output_obj = Output(self, response)
return output_obj.dump(out, err, **self._output,
output_type=self._options.get("format","success"))


class Output:
"""CLI Response Display Class"""
def __init__(self, command, response):
self.command = command
self.rc = response.rc()
self.output = response.output()

def dump(self, out, err, output_type, **kwargs) -> None:
"""Dump the Output on CLI"""
# Todo: Need to fetch the response messages from a file for localization.
# TODO: Check 201 response code also for creation requests.
if self.rc not in (200, 201, const.OPERATION_SUCESSFUL) :
if isinstance(self.output, str):
errstr = Output.error(self.rc, self.output)
else:
errstr = Output.error(self.rc, kwargs.get("error") ,
self.output)
err.write(f"{errstr}\n" or "")
return None
elif output_type:
output = getattr(Output, f"dump_{output_type}")(self.output,
**kwargs)
out.write(f"{output}\n")

@staticmethod
def dump_success(output: Any, **kwargs) -> str:
"""
Accepts String as Output and Returns the Same.
:param output: Output String
:return: str
"""
return str(kwargs.get("success", output))

@staticmethod
def error(rc: int, message: str, stacktrace=None) -> str:
"""Format for Error message"""
if not stacktrace:
return f"error({rc}): {message}\n"
return f"error({rc}): Error:- {stacktrace.get('message')}"

@staticmethod
def create_by_row(table_obj, table,data):
"""
Features Creation of Table By Filling each row data.
This Works for Data which is in format as follows:
1) Either the Data is in an array of Dictionaries.
e.g.
{
"filters":[
{
"key1":"value1",
"key2":"value2"
},
{
"key1":"value1",
"key2":"value2"
}
]
}
2) The Data is a complete Single Dictionary.
{
"key1":"value1",
"key2":"value2"
}
:param table_obj: Pretty Table Object :type:Object
:param data: data to be displayed in Table :type:dict
:param table: Table Output From Json :type:dict
:return:
"""
table_obj.field_names = table["headers"].values()
if table.get("filters", False):
for each_row in data[table["filters"]]:
table_obj.add_row(
[each_row.get(x) for x in table["headers"].keys()])
else:
table_obj.add_row([data.get(x) for x in table["headers"].keys()])

@staticmethod
def create_by_column(table_obj, table, data):
"""
Features Creation of Table By Filling each column data.
This Works for Data which is in format as follows:
1) For a Response Where the data compromised of multiple Keys and each
contain list of Options.
e.g.:
{
"key1" : ["Value1", "Value2", ......., "ValueN"],
"key2" : ["Value1", "Value2", ......., "ValueN"]
}
:param table_obj: Pretty Table Object :type:Object
:param data: data to be displayed in Table :type:dict
:param table: Table Output From Json :type:dict
:return:
"""
# Finds the List which has Max Values.
max_length_list = max(map(lambda key: len(data[key]), table["headers"].keys()))
for each_key in table["headers"].keys():
# Make All the Other Lists to same length to maintain Uniformity for the
# table displayed on CLI.
padding_length = max_length_list - len(data[each_key])
new_data = data[each_key]
new_data.extend(padding_length * [table.get("padding_element", " ")])
# Add Padded List to the Column.
table_obj.add_column(table["headers"][each_key], new_data)

@staticmethod
def dump_table(data: Any, table: Dict, **kwargs: Dict) -> str:
"""
Format for Table Data
:param data: data to be displayed in Table :type:dict
:param table: Table Output From Json :type:dict
:return: Created Table. :type Str
"""
table_obj = PrettyTable()
if table.get("create_by_column", False):
Output.create_by_column(table_obj, table, data)
else:
Output.create_by_row(table_obj, table, data)
return "{0}".format(table_obj)

@staticmethod
def dump_xml(data, **kwargs: Dict) -> str:
"""Format for XML Data"""
return dict2xml(data)

@staticmethod
def dump_json(data, **kwargs: Dict) -> str:
"""Format for Json Data"""
return json.dumps(data, indent=4, sort_keys=True)
72 changes: 72 additions & 0 deletions py-utils/src/utils/cli_framework/command_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CORTX-Py-Utils: CORTX Python common library.
# Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# For any questions about this software or licensing,
# please email [email protected] or [email protected].

import sys
import os
from cortx.utils.schema.payload import Json
from cortx.utils.cli_framework import const
from cortx.utils.cli_framework.parser import ArgumentParser, CommandParser


class CommandFactory(object):
"""
Factory for representing and creating command objects using
a generic skeleton.
"""

@staticmethod
def get_command(argv, permissions={}, component_cmd_dir="", excluded_cmds=[], hidden_cmds=[]):
"""
Parse the command line as per the syntax and retuns
returns command representing the command line.
"""
if len(argv) <= 1:
argv.append("-h")

commands_files = os.listdir(component_cmd_dir)
excluded_cmds.extend(const.EXCLUDED_COMMANDS)

commands = [command.split(".json")[0] for command in commands_files
if command.split(".json")[0] not in excluded_cmds]
if permissions:
# common commands both in commands and permissions key list
commands = [command for command in commands if command in permissions.keys()]
parser = ArgumentParser(description="Cortx cli commands")
hidden_cmds.extend(const.HIDDEN_COMMANDS)
metavar = set(commands).difference(set(hidden_cmds))
subparsers = parser.add_subparsers(metavar=metavar)

if argv[0] in commands:
# get command json file and filter only allowed first level sub_command
# create filter_permission_json
cmd_from_file = Json(os.path.join(component_cmd_dir, f"{argv[0]}.json")).load()
cmd_obj = CommandParser(cmd_from_file, permissions.get(argv[0], {}))
cmd_obj._handle_main_parse(subparsers)
namespace = parser.parse_args(argv)

CommandFactory._edit_arguments(namespace)

sys_module = sys.modules[__name__]
for attr in ["command", "action", "args"]:
setattr(sys_module, attr, getattr(namespace, attr))
delattr(namespace, attr)
return command(action, vars(namespace), args)

@staticmethod
def _edit_arguments(namespace):
# temporary solution till user create api is not fixed
# remove when fixed
if namespace.action == "users" and namespace.sub_command_name == "create":
namespace.roles = [namespace.roles]
19 changes: 19 additions & 0 deletions py-utils/src/utils/cli_framework/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CORTX-Py-Utils: CORTX Python common library.
# Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# For any questions about this software or licensing,
# please email [email protected] or [email protected].

SUB_COMMANDS_PERMISSIONS = "permissions_tag"
EXCLUDED_COMMANDS=[]
HIDDEN_COMMANDS = []
OPERATION_SUCESSFUL = 0x0000
Loading

0 comments on commit 1ff3cfa

Please sign in to comment.