Ejemplo n.º 1
0
def add_del_agent_id(dut,
                     interface_name=None,
                     action="add",
                     cli_type="",
                     sflow_list="global",
                     skip_error_check=False):
    """
    API to add/del SFLOW AGENT ID
    Author: Chaitanya Vella ([email protected])
    :param dut:
    :param interface_name:
    :param action: add / del
    :return: True / False
    """
    cli_type = st.get_ui_type(dut, cli_type=cli_type)
    cli_type = "klish" if cli_type in ["rest-put", "rest-patch"] else cli_type
    if action not in ["add", "del"]:
        st.log("Unsupported action {}..".format(action))
        return False
    if cli_type == "click":
        if action != "add":
            command = "config sflow agent-id {}".format(action)
        else:
            if not interface_name:
                st.log("Interface name -- {} not provided ".format(
                    interface_name))
                return False
            command = "config sflow agent-id {} {}".format(
                action, interface_name)
    elif cli_type == "klish":
        if action != "add":
            command = "no sflow agent-id"
        else:
            command = "sflow agent-id {}".format(interface_name)
    elif cli_type == "rest":
        url = "{}/SFLOW/SFLOW_LIST={}/agent_id".format(REST_URI, sflow_list)
        if action == "add":
            data = {"sonic-sflow:agent_id": interface_name}
            output = st.rest_modify(dut, url, data)
            st.log("REST del agent_id OUTPUT -- {}".format(output))
            if output and output["status"] != 204:
                return False
        else:
            output = st.rest_delete(dut, url)
            st.log("REST del agent_id OUTPUT -- {}".format(output))
            if output and output["status"] != 204:
                return False
        return True
    else:
        st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
        return False
    if utils_obj.ensure_cli_type(cli_type, ["click", "klish"]) and command:
        output = st.config(dut,
                           command,
                           type=cli_type,
                           skip_error_check=skip_error_check)
        return output
    return True
Ejemplo n.º 2
0
def config_max_sessions(dut, **kwargs):
    """
    API to configure max mirror sessions
    Author: Chaitanya Vella ([email protected])
    :param dut:
    :param kwargs: {"cli_ype":"rest","data":[{"name":"Mirror1","src_ip":"10.20.3.1","dst_ip":"10.23.3.5",
    "gre_type":"0x855","dscp":16,"ttl":5,"queue":6,"dst_port":"Ethernet28","src_port":"Ethernet20",
    "direction":"rx/tx"},{"name":"Mirror2","dst_port":"Ethernet20","src_port":"Ethernet22","direction":"rx"},
    {"name":"Mirror3","dst_port":"Ethernet26","src_port":"Ethernet22","direction":"tx"}],"action":"config"}
    :return: response/False
    """
    cli_type = kwargs.get("cli_type", "rest")
    if cli_type == "rest":
        status = 204
        data = kwargs.get("data")
        action = data.get("action", "config")
        rest_url = "/restconf/data/{}".format(YANG_MODEL)
        if action == "config":
            if data.get("data"):
                rest_data = dict()
                rest_data[YANG_MODEL] = dict()
                rest_data[YANG_MODEL]["MIRROR_SESSION"] = dict()
                rest_data[YANG_MODEL]["MIRROR_SESSION"][
                    "MIRROR_SESSION_LIST"] = make_list(data.get("data"))
                response = st.rest_modify(dut, rest_url, rest_data)
            else:
                st.log("Required data not found -- {}".format(data))
                return False
        elif action == "unconfig":
            response = st.rest_delete(dut, rest_url)
        elif action == "get":
            response = st.rest_read(dut, rest_url)
            status = 200
        else:
            st.log("Unsupporte ACTION -- {}".format(action))
            return False
        if response and response["status"] == status:
            return response
        else:
            st.log("RESPONSE -- {}".format(response))
            return False
    else:
        st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
        return False
Ejemplo n.º 3
0
def config_domain(dut, domain_id, **kwargs):
    '''
    Author: [email protected]
    :param dut:
    :param domain_id: Mclag domain_id
    :param local_ip: Mclag peer1 IP
    :param peer_ip: Mclag peer2 IP
    :param kwargs: optional parameters can be <local_ip|peer_ip|peer_interface|config|cli_type>
    :return:

    usage:
    config_domain(dut1,10, local_ip="10.10.10.1", peer_ip="10.10.10.2", delay_restore_timer="60")
    config_domain(dut1,10, local_ip="10.10.10.1", peer_ip="10.10.10.2", peer_interface='Ethernet0001')
    config_domain(dut1,10, config='del')
    '''
    ### Optional parameters processing
    local_ip = kwargs.get('local_ip', None)
    peer_ip = kwargs.get('peer_ip', None)
    peer_intf = kwargs.get('peer_interface', None)
    delay_restore_timer = kwargs.get('delay_restore_timer', None)
    config = kwargs.get('config', 'add')
    cli_type = kwargs.pop('cli_type', st.get_ui_type(dut, **kwargs))

    if cli_type == 'click':
        cmd = "config mclag {} {}".format(config, domain_id)
        if config == 'add':
            if 'local_ip' not in kwargs or 'peer_ip' not in kwargs:
                st.error("Mandatory parameters local_ip and peer_ip not found")
                return False
            cmd += " {} {}".format(local_ip, peer_ip)
            if 'peer_interface' in kwargs:
                cmd += ' {}'.format(peer_intf)
        #cmd += ' \n'
        output = st.config(dut, cmd)
        if "Missing argument" in output:
            st.error("Argument Missing")
            return False
        if "invalid peer ip address" in output:
            st.error("Invalid peer_ip address")
            return False
        if "invalid local ip address" in output:
            st.error("Invalid local_ip address")
            return False
        if "interface name is invalid" in output:
            st.error("Invalid peer interface")
            return False
    elif cli_type == 'klish':
        config = 'no ' if config == 'del' else ''
        if config == '':
            cmd = "mclag domain {}".format(domain_id)
            if 'local_ip' in kwargs:
                cmd = cmd + "\n" + "source-ip {}".format(local_ip)
            if 'peer_ip' in kwargs:
                cmd = cmd + "\n" + "peer-ip {}".format(peer_ip)
            if 'peer_interface' in kwargs:
                pintf = get_interface_number_from_name(peer_intf)
                cmd = cmd + "\n" + "peer-link {} {}".format(
                    pintf['type'], pintf['number'])
            if 'delay_restore_timer' in kwargs:
                cmd = cmd + "\n" + "delay-restore {}".format(
                    delay_restore_timer)
            cmd = cmd + "\n" + "exit"
        elif config == 'no ':
            if 'local_ip' in kwargs or 'peer_ip' in kwargs or 'peer_interface' in kwargs or 'delay_restore_timer' in kwargs:
                cmd = "mclag domain {}".format(domain_id)
                if 'local_ip' in kwargs:
                    cmd = cmd + "\n" + "{}source-ip".format(config)
                if 'peer_ip' in kwargs:
                    cmd = cmd + "\n" + "{}peer-ip".format(config)
                if 'peer_interface' in kwargs:
                    cmd = cmd + "\n" + "{}peer-link".format(config)
                if 'delay_restore_timer' in kwargs:
                    cmd = cmd + "\n" + "{}delay-restore".format(config)
                cmd = cmd + "\n" + "exit"
            else:
                cmd = "{}mclag domain {}".format(config, domain_id)
        output = st.config(dut, cmd, type="klish", conf=True)
        if "Could not connect to Management REST Server" in output:
            st.error("klish mode not working.")
            return False
    elif cli_type in ["rest-put", "rest-patch"]:
        if config == 'del':
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url_del = rest_urls['mclag_config_domain'].format(
                int(domain_id))
            output = st.rest_delete(dut, rest_url_del)
            if not output["status"] in [200, 204]:
                st.error(
                    "Failed to delete the mclag domain using REST in {} due to bad request {}"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest delete mclag domain return status {}".format(
                        output['status']))
                return True
        if 'local_ip' in kwargs:
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url = rest_urls['mclag_config_all']
            rest_data = {
                "openconfig-mclag:mclag-domains": {
                    "mclag-domain": [{
                        "domain-id": int(domain_id),
                        "config": {
                            "domain-id": int(domain_id),
                            "source-address": local_ip
                        }
                    }]
                }
            }
            output = st.rest_create(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure using POST source-address in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation using POST for source-address return status {}"
                    .format(output['status']))
        if 'peer_ip' in kwargs:
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url = rest_urls['mclag_config_peer_ip'].format(int(domain_id))
            rest_data = {"openconfig-mclag:peer-address": peer_ip}
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure peer-address in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation for peer-address return status {}".
                    format(output['status']))
        if 'peer_interface' in kwargs:
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url = rest_urls['mclag_config_peer_link'].format(
                int(domain_id))
            rest_data = {"openconfig-mclag:peer-link": peer_intf}
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure peer-link in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log("PASS: Rest operation for peer-link return status {}".
                       format(output['status']))
        if 'delay_restore_timer' in kwargs:
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url = rest_urls['mclag_config_delay_restore'].format(
                int(domain_id))
            rest_data = {
                "openconfig-mclag:delay-restore": int(delay_restore_timer)
            }
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure delay_restore_timer in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation for delay_restore_timer return status {}"
                    .format(output['status']))
        if 'keepalive_interval' in kwargs:
            rest_urls = st.get_datastore(dut, 'rest_urls')
            rest_url = rest_urls['mclag_config_keepalive'].format(
                int(domain_id))
            rest_data = {
                "openconfig-mclag:keepalive-interval":
                int(kwargs['keepalive_interval'])
            }
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure keepalive-interval in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation for keepalive-interval return status {}"
                    .format(output['status']))
        if 'session_timeout' in kwargs:
            rest_url = rest_urls['mclag_config_session_timeout'].format(
                int(domain_id))
            rest_data = {
                "openconfig-mclag:session-timeout":
                int(kwargs['session_timeout'])
            }
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure session-timeout in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation for session-timeout return status {}"
                    .format(output['status']))
        if 'mclag_system_mac' in kwargs:
            rest_url = rest_urls['mclag_config_mclag_system_mac'].format(
                int(domain_id))
            rest_data = {
                "openconfig-mclag:mclag-system-mac": kwargs['mclag_system_mac']
            }
            output = st.rest_modify(dut, path=rest_url, data=rest_data)
            if output["status"] not in [200, 204, 201]:
                st.error(
                    "Failed to configure mclag-system-mac in {} due to bad request {} seen for REST command"
                    .format(dut, output["status"]))
                return False
            else:
                st.log(
                    "PASS: Rest operation for mclag-system-mac return status {}"
                    .format(output['status']))
        for arg1 in kwargs:
            if arg1 not in [
                    'mclag_system_mac', 'session_timeout',
                    'keepalive_interval', 'delay_restore_timer',
                    'peer_interface', 'peer_ip', 'local_ip'
            ]:
                st.error("ARG {} is not supported through REST".format(arg1))
    return True
Ejemplo n.º 4
0
def config_attributes(dut, **kwargs):
    """
    Common API to configure sflow sample rate on interface, polling interval and sample rate per speed.
    Author: Chaitanya Vella ([email protected])
    :param dut:
    :param kwargs:
    :return: True
    NOTE:
    1) To configure interface sample rate,
        config_sflow_attributes(dut, sample_rate=100, interface_name="Ethernet10")
    2) To configure polling interval
        config_sflow_attributes(dut, polling_interval=20)
    3) To configure sample rate per speed
        config_sflow_attributes(dut, speed=10G, sample_rate=10000)
    """
    cli_type = st.get_ui_type(dut, **kwargs)
    cli_type = "klish" if cli_type in ["rest-put", "rest-patch"] else cli_type
    sflow_key = kwargs.get("sflow_key", "global")
    command = ""
    commands = list()
    if "sample_rate" in kwargs and "interface_name" in kwargs:
        if cli_type == "click":
            command += "config sflow interface sample-rate {} {}".format(
                kwargs["interface_name"], kwargs["sample_rate"])
            commands.append(command)
        elif cli_type == "klish":
            interface_details = utils_obj.get_interface_number_from_name(
                kwargs["interface_name"])
            if not interface_details:
                st.log(
                    "Interface details not found {}".format(interface_details))
                return False
            commands.append("interface {} {}".format(
                interface_details.get("type"),
                interface_details.get("number")))
            if "no_form" in kwargs:
                command = "no sflow sampling-rate"
            else:
                command = "sflow sampling-rate {}".format(
                    kwargs["sample_rate"])
            commands.append(command)
            commands.append("exit")
        elif cli_type == "rest":
            data = {"sonic-sflow:sample_rate": int(kwargs["sample_rate"])}
            url = "{}/SFLOW_SESSION/SFLOW_SESSION_LIST={}/sample_rate".format(
                REST_URI, kwargs["interface_name"])
            output = st.rest_modify(dut, url, data)
            st.log("REST config_attributes SAMPLE RATE OUTPUT  -- {}".format(
                output))
            if output and output["status"] != 204:
                return False
            return True
        else:
            st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
            return False
        st.config(dut, commands, type=cli_type)
    if "polling_interval" in kwargs:
        if cli_type == "click":
            command += "config sflow polling-interval {};".format(
                kwargs["polling_interval"])
            commands.append(command)
        elif cli_type == "klish":
            if "no_form" in kwargs:
                command = "no sflow polling-interval"
            else:
                command = "sflow polling-interval {}".format(
                    kwargs["polling_interval"])
            commands.append(command)
        elif cli_type == "rest":
            data = {
                "sonic-sflow:polling_interval": int(kwargs["polling_interval"])
            }
            url = "{}/SFLOW/SFLOW_LIST={}/polling_interval".format(
                REST_URI, sflow_key)
            output = st.rest_modify(dut, url, data)
            st.log("REST config_attributes POLLING RATE OUTPUT  -- {}".format(
                output))
            if output and output["status"] != 204:
                return False
            return True
        else:
            st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
            return False
        st.config(dut, commands, type=cli_type)
    return True
Ejemplo n.º 5
0
def enable_disable_config(dut,
                          interface=False,
                          interface_name=None,
                          action="enable",
                          cli_type="",
                          sflow_key="global"):
    """
    API to enable / disable SFLOW Globally / on interface level
    Author: Chaitanya Vella ([email protected])
    :param dut:
    :param interface:
    :param interface_name:
    :param action:
    :return:
    """
    cli_type = st.get_ui_type(dut, cli_type=cli_type)
    cli_type = "klish" if cli_type in ["rest-put", "rest-patch"] else cli_type
    if action not in ["enable", "disable"]:
        st.log("Unsupported action {} ".format(action))
        return False
    if interface and interface_name:
        commands = list()
        if cli_type == "click":
            command = "config sflow interface {} {}".format(
                action, interface_name)
            commands.append(command)
        elif cli_type == "klish":
            interface_details = utils_obj.get_interface_number_from_name(
                interface_name)
            if not interface_details:
                st.log(
                    "Interface details not found {}".format(interface_details))
                return False
            commands.append("interface {} {}".format(
                interface_details.get("type"),
                interface_details.get("number")))
            if action == "enable":
                command = "sflow {}".format(action)
            else:
                command = "no sflow enable"
            commands.append(command)
        elif cli_type == "rest":
            session_list = dict()
            session_list["sonic-sflow:SFLOW_SESSION_LIST"] = list()
            session_data = dict()
            session_data["ifname"] = interface_name
            session_data[
                "admin_state"] = "up" if action == "enable" else "down"
            session_list["sonic-sflow:SFLOW_SESSION_LIST"].append(session_data)
            url = "{}/SFLOW_SESSION".format(REST_URI)
            output = st.rest_modify(dut,
                                    url,
                                    session_list,
                                    SFLOW_SESSION_LIST=interface_name)
            st.log("ENABLE / DISABLE SFLOW AT INTF level -- {}".format(output))
            if output and output["status"] != 204:
                return False
            return True
        else:
            st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
            return False
        if commands:
            st.config(dut, commands, type=cli_type)
    else:
        if cli_type == "click":
            command = "config sflow {}".format(action)
        elif cli_type == "klish":
            if action != "enable":
                command = "no sflow enable"
            else:
                command = "sflow enable"
        elif cli_type == "rest":
            data = {
                "sonic-sflow:admin_state":
                "up" if action == "enable" else "down"
            }
            url = "{}/SFLOW/SFLOW_LIST={}/admin_state".format(
                REST_URI, sflow_key)
            output = st.rest_modify(dut, url, data)
            st.log(
                "ENABLE / DISABLE SFLOW AT GLOBAL level -- {}".format(output))
            if output and output["status"] != 204:
                return False
            return True
        else:
            st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
            return False
        if command:
            st.config(dut, command, type=cli_type)
    return True
Ejemplo n.º 6
0
def add_del_collector(dut,
                      collector_name,
                      ip_address=None,
                      port_number=None,
                      action="add",
                      cli_type="",
                      skip_error_check=False):
    """
    API to add/del SFLOW collector
    Author: Chaitanya Vella ([email protected])
    :param dut:
    :param collector_name:
    :param ip_address: IPV4 / IPV6 address, this is optional for del operations
    :param port_number: None, this is optional for del operations
    :param action: add / del
    :return: True / False
    """
    cli_type = st.get_ui_type(dut, cli_type=cli_type)
    cli_type = "klish" if cli_type in ["rest-put", "rest-patch"] else cli_type
    command = None
    if action == "add":
        if ip_address:
            if cli_type == "click":
                command = "config sflow collector add {} {} --port {}".format(collector_name, ip_address, port_number) if port_number else \
                "config sflow collector add {} {}".format(collector_name, ip_address)
            elif cli_type == "klish":
                command = "sflow collector {} {}".format( ip_address, port_number) if port_number else \
                "sflow collector {}".format(ip_address)
            elif cli_type == "rest":
                data = dict()
                data["sonic-sflow:SFLOW_COLLECTOR"] = dict()
                data["sonic-sflow:SFLOW_COLLECTOR"][
                    "sonic-sflow:SFLOW_COLLECTOR_LIST"] = list()
                collector_data = dict()
                collector_data["collector_name"] = collector_name
                collector_data["collector_ip"] = ip_address
                collector_data["collector_port"] = int(
                    port_number) if port_number else DEFAULT_COLLECTOR_PORT
                data["sonic-sflow:SFLOW_COLLECTOR"][
                    "sonic-sflow:SFLOW_COLLECTOR_LIST"].append(collector_data)
                json_data = data
                url = "{}/SFLOW_COLLECTOR".format(REST_URI)
                output = st.rest_modify(dut, url, json_data)
                st.log(
                    "ADD / DEL COLLECTOR AT INTF level -- {}".format(output))
                if output and output["status"] != 204:
                    return False
                return True
            else:
                st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
                return False
        else:
            st.log("IP ADDRESS not provided for add operation ..")
            return False
    elif action == "del":
        if cli_type == "click":
            command = "config sflow collector del {}".format(collector_name)
        elif cli_type == "klish":
            command = "no sflow collector {} {}".format( ip_address, port_number) if port_number else \
                "no sflow collector {}".format(ip_address)
        elif cli_type == "rest":
            url = "{}/SFLOW_COLLECTOR".format(REST_URI)
            output = st.rest_delete(dut,
                                    url,
                                    SFLOW_COLLECTOR_LIST=collector_name)
            st.log("ADD / DEL COLLECTOR AT INTF level -- {}".format(output))
            if output and output["status"] != 204:
                return False
            return True
        else:
            st.log("UNSUPPORTED CLI TYPE -- {}".format(cli_type))
            return False
    if cli_type != "rest" and command and utils_obj.ensure_cli_type(
            cli_type, ["click", "klish"]):
        output = st.config(dut,
                           command,
                           type=cli_type,
                           skip_error_check=skip_error_check)
        return output
    return True
Ejemplo n.º 7
0
def rest_operation(dut, **kwargs):
    op = kwargs.get("http_method")
    url = kwargs.get("rest_url")
    data = kwargs.get("json_data")
    timeout = kwargs.get("timeout", 5)
    log_msg = []
    status_map = {200 : "Rest operation successful", 201 : "Rest operation successful", 204 : "Rest operation successful", 400 : "Bad Request", 401 : "Unauthorized", 403 : "Forbidden", 404 : "Page not found", 405 : "Method not allowed", 409 : "Conflict", 415 : "Unsupported Media Type", 500 : "Internal Server Error"}
    retval = {}
    rest_result = True
    log_msg.append("[{}] -- HTTP METHOD : {}".format(dut, op.upper()))
    log_msg.append("URL : {}".format(url))
    if data:
        log_msg.append("PAYLOAD : {}".format(data))
    if not op or not url:
        st.log("Please provide http_method: {} or rest_url: {}".format(op,url))
        return False
    op = op.lower()
    if op in ["get","delete"]:
        params = {"path":url, "rest_timeout":timeout}
    elif op in ["post", "put", "patch"]:
        params = {"path": url, "data":data,"rest_timeout": timeout}
    else:
        st.log("Please provide valid Http method")
        return False
    if kwargs.get("username"):
        params.update({"rest_username":kwargs.get("username")})
    if kwargs.get("password"):
        params.update({"rest_password":kwargs.get("password")})
    for iteration in range(1,5):
        try:
            if op == "get":
                retval = st.rest_read(dut, **params)
            elif op == "post":
                retval = st.rest_create(dut, **params)
            elif op == "put":
                retval = st.rest_update(dut, **params)
            elif op == "delete":
                retval = st.rest_delete(dut, **params)
            elif op == "patch":
                retval = st.rest_modify(dut, **params)
            else:
                st.log("Please provide valid Http method")
                return False
            break
        except Exception as e:
            if iteration > 2:
                credentials = st.get_credentials(dut)
                st.rest_init(dut, credentials[0], credentials[1], credentials[2])
            if op == "get":
                tout = 180 if int(timeout) < 180 else timeout
                st.log("Setting timeout to {} sec".format(tout))
                params.update({"rest_timeout": tout})
            st.error(e)
    if "url" in retval.keys():
        host_ip = re.findall(r'([0-9]+(?:\.[0-9]+){3})', retval["url"])
        if host_ip:
            log_msg.insert(1, "HOST IP : {}".format(host_ip[0]))
    if "status" in retval.keys():
        log_msg.append("STATUS : {} - {}".format(retval["status"], status_map[retval["status"]]))
        rest_result = True if retval["status"] in [200, 201, 204] else False
    if op == "get":
        if "output" in retval.keys():
            log_msg.append("OUTPUT : {}".format(retval["output"]))
    if rest_result:
        st.log("{}".format(", ".join(log_msg)))
    else:
        st.error("{}".format(", ".join(log_msg)))
    return retval