Hi Hans,

Thanks for your ack.
I did run pylint with pylintrc in opensaf-code/python directory for the patch 
and the result was good, please see below.
Have you run pylint with pylintrc in opensaf-code/python?

Pylint result
==========
$ pylint --rcfile=python/pylintrc python/samples/clm-tool
************* Module clm-tool
C:  1, 0: Invalid module name "clm-tool" (invalid-name)


Report
======
110 statements analysed.

Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |1          |=          |100.00      |100.00   |
+---------+-------+-----------+-----------+------------+---------+
|class    |1      |1          |=          |100.00      |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|method   |10     |10         |=          |100.00      |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|function |0      |0          |=          |0           |0        |
+---------+-------+-----------+-----------+------------+---------+



External dependencies
---------------------
::

    pyosaf
      \-saAis (clm-tool)
      \-utils
        \-clm (clm-tool)
        \-immom
          \-accessor (clm-tool)



Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |121    |47.83 |121      |=          |
+----------+-------+------+---------+-----------+
|docstring |84     |33.20 |84       |=          |
+----------+-------+------+---------+-----------+
|comment   |19     |7.51  |19       |=          |
+----------+-------+------+---------+-----------+
|empty     |29     |11.46 |29       |=          |
+----------+-------+------+---------+-----------+



Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |0        |=          |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |0.000    |=          |
+-------------------------+------+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |1      |1        |=          |
+-----------+-------+---------+-----------+
|refactor   |0      |0        |=          |
+-----------+-------+---------+-----------+
|warning    |0      |0        |=          |
+-----------+-------+---------+-----------+
|error      |0      |0        |=          |
+-----------+-------+---------+-----------+



Messages
--------

+-------------+------------+
|message id   |occurrences |
+=============+============+
|invalid-name |1           |
+-------------+------------+




------------------------------------------------------------------
Your code has been rated at 9.91/10 (previous run: 9.91/10, +0.00)

Thanks,
/Danh



-----Original Message-----
From: Hans Nordebäck [mailto:[email protected]] 
Sent: Tuesday, December 19, 2017 6:35 PM
To: Danh Vo <[email protected]>; [email protected]; 
[email protected]
Cc: [email protected]
Subject: Re: [PATCH 1/1] pyosaf: Refactor clm-tool sample to make use of new 
pyosaf utils [#2679]

ack with a question, (review only). Have you run pylint on clm-tool? 
There are new remarks such as Invalid variable name, Invalid constant name, Too 
many arguments, etc.

/Thanks HansN


On 12/04/2017 08:46 AM, Danh Vo wrote:
> - Refactor clm-tool.
> - Add new function in clm util for sending node get.
> ---
>   python/pyosaf/utils/clm/__init__.py | 125 +++++++++------
>   python/samples/clm-tool             | 309 
> ++++++++++++++++++++++++++++--------
>   2 files changed, 322 insertions(+), 112 deletions(-)
>
> diff --git a/python/pyosaf/utils/clm/__init__.py 
> b/python/pyosaf/utils/clm/__init__.py
> index 533a4b5..5461d4a 100644
> --- a/python/pyosaf/utils/clm/__init__.py
> +++ b/python/pyosaf/utils/clm/__init__.py
> @@ -44,6 +44,38 @@ saClmClusterNodeGetAsync = 
> decorate(saClm.saClmClusterNodeGetAsync)
>   saClmResponse_4 = decorate(saClm.saClmResponse_4)
>   
>   
> +class ClusterNode(object):
> +    """ Class representing a CLM cluster node """
> +
> +    def __init__(self, node_id, node_address, node_name, 
> execution_environment,
> +                 member, boot_timestamp, initial_view_number):
> +        """ Constructor for ClusterNode class
> +
> +        Args:
> +            node_id (SaClmNodeIdT): Node identifier
> +            node_address (SaClmNodeAddressT): Node network communication
> +                address
> +            node_name (SaNameT): Node name
> +            execution_environment (SaNameT): DN of the PLM execution
> +                environment that hosts the node
> +            member (SaBoolT): Indicate whether this is a CLM member node 
> (True)
> +                or not (False)
> +            boot_timestamp (SaTimeT): Timestamp at which the node was last
> +                booted
> +            initial_view_number (SaUint64T): View number of the latest
> +                membership transition when this configured node joined the
> +                cluster membership
> +        """
> +        self.node_id = node_id
> +        self.node_address_value = node_address.value
> +        self.node_address_family = node_address.family
> +        self.node_name = node_name.value
> +        self.execution_environment = execution_environment
> +        self.member = member
> +        self.boot_timestamp = boot_timestamp
> +        self.initial_view_number = initial_view_number
> +
> +
>   class ClmAgentManager(object):
>       """ This class manages the life cycle of a CLM agent, and also acts as
>       a proxy handler for CLM callbacks """
> @@ -105,7 +137,7 @@ class ClmAgentManager(object):
>                   notification = notification_buffer.notification[i]
>                   clm_cluster_node = notification.clusterNode
>                   cluster_node = \
> -                    create_cluster_node_instance(clm_cluster_node)
> +                    
> + self.create_cluster_node_instance(clm_cluster_node)
>                   node_state = (cluster_node, 
> notification.clusterChange)
>   
>                   node_list.append(node_state) @@ -133,7 +165,7 @@ 
> class ClmAgentManager(object):
>               error = c_error
>   
>               cluster_node = \
> -                create_cluster_node_instance(c_cluster_node.contents)
> +                
> + self.create_cluster_node_instance(c_cluster_node.contents)
>   
>               # Send the node info to user's callback function
>               self.node_get_function(invocation, cluster_node, error) 
> @@ -221,7 +253,7 @@ class ClmAgentManager(object):
>               rc = saClmFinalize(self.handle)
>               if rc != eSaAisErrorT.SA_AIS_OK:
>                   log_err("saClmFinalize FAILED - %s" % 
> eSaAisErrorT.whatis(rc))
> -            elif rc == eSaAisErrorT.SA_AIS_OK \
> +            if rc == eSaAisErrorT.SA_AIS_OK \
>                       or rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE:
>                   # If the Finalize() call returned BAD_HANDLE, the handle 
> should
>                   # already become stale and invalid, so we reset it anyway.
> @@ -229,6 +261,25 @@ class ClmAgentManager(object):
>   
>           return rc
>   
> +    @staticmethod
> +    def create_cluster_node_instance(clm_cluster_node):
> +        """ Create ClusterNode object from cluster node information
> +
> +        Args:
> +            clm_cluster_node (SaClmClusterNodeT): Cluster node 
> + information
> +
> +        Returns:
> +            ClusterNode: An object containing cluster node information
> +        """
> +        return ClusterNode(
> +            node_id=clm_cluster_node.nodeId,
> +            node_address=clm_cluster_node.nodeAddress,
> +            node_name=clm_cluster_node.nodeName,
> +            execution_environment=clm_cluster_node.executionEnvironment,
> +            member=clm_cluster_node.member,
> +            boot_timestamp=clm_cluster_node.bootTimestamp,
> +            initial_view_number=clm_cluster_node.initialViewNumber)
> +
>   
>   class ClmAgent(ClmAgentManager):
>       """ This class acts as a high-level CLM agent, providing CLM 
> functions to @@ -327,7 +378,8 @@ class ClmAgent(ClmAgentManager):
>                   notification = notification_buffer.notification[i]
>                   clm_cluster_node = notification.clusterNode
>   
> -                cluster_node = create_cluster_node_instance(clm_cluster_node)
> +                cluster_node = \
> +                    
> + self.create_cluster_node_instance(clm_cluster_node)
>   
>                   cluster_nodes.append(cluster_node)
>           else:
> @@ -379,7 +431,7 @@ class ClmAgent(ClmAgentManager):
>           """
>           rc = saClmClusterTrackStop(self.handle)
>           if rc != eSaAisErrorT.SA_AIS_OK:
> -            log_err("saClmClusterTrack_4 FAILED - %s" %
> +            log_err("saClmClusterTrackStop FAILED - %s" %
>                       eSaAisErrorT.whatis(rc))
>   
>           if rc == eSaAisErrorT.SA_AIS_ERR_BAD_HANDLE:
> @@ -415,56 +467,29 @@ class ClmAgent(ClmAgentManager):
>   
>           return rc
>   
> -
> -class ClusterNode(object):
> -    """ Class representing a CLM cluster node """
> -
> -    def __init__(self, node_id, node_address, node_name, 
> execution_environment,
> -                 member, boot_timestamp, initial_view_number):
> -        """ Constructor for ClusterNode class
> +    def get_node_info(self, node_id, time_out):
> +        """ Get information of a specific cluster member node.
>   
>           Args:
> -            node_id (SaClmNodeIdT): Node identifier
> -            node_address (SaClmNodeAddressT): Node network communication
> -                address
> -            node_name (SaNameT): Node name
> -            execution_environment (SaNameT): DN of the PLM execution
> -                environment that hosts the node
> -            member (SaBoolT): Indicate whether this is a CLM member node 
> (True)
> -                or not (False)
> -            boot_timestamp (SaTimeT): Timestamp at which the node was last
> -                booted
> -            initial_view_number (SaUint64T): View number of the latest
> -                membership transition when this configured node joined the
> -                cluster membership
> -        """
> -        self.node_id = node_id
> -        self.node_address_value = node_address.value
> -        self.node_address_family = node_address.family
> -        self.node_name = node_name.value
> -        self.execution_environment = execution_environment
> -        self.member = member
> -        self.boot_timestamp = boot_timestamp
> -        self.initial_view_number = initial_view_number
> -
> +            node_id (SaClmNodeIdT): Node id
> +            time_out (SaTimeT): Time-out (in nanosecond) for
> +                saClmClusterNodeGet_4 operation
>   
> -def create_cluster_node_instance(clm_cluster_node):
> -    """ Create ClusterNode object from cluster node information
> +        Returns:
> +            SaAisErrorT: Return code of the saClmClusterNodeGet_4() API call.
> +            ClusterNode: Node info or None if node with `node id` is not 
> found.
> +        """
> +        clm_cluster_node = saClm.SaClmClusterNodeT_4()
>   
> -    Args:
> -        clm_cluster_node (SaClmClusterNodeT): Cluster node information
> +        rc = saClmClusterNodeGet_4(self.handle, node_id, time_out,
> +                                   clm_cluster_node)
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            log_err("saClmClusterNodeGet() FAILED - %s" %
> +                    eSaAisErrorT.whatis(rc))
> +            return rc, None
>   
> -    Returns:
> -        ClusterNode: An object containing cluster node information
> -    """
> -    return ClusterNode(
> -        node_id=clm_cluster_node.nodeId,
> -        node_address=clm_cluster_node.nodeAddress,
> -        node_name=clm_cluster_node.nodeName,
> -        execution_environment=clm_cluster_node.executionEnvironment,
> -        member=clm_cluster_node.member,
> -        boot_timestamp=clm_cluster_node.bootTimestamp,
> -        initial_view_number=clm_cluster_node.initialViewNumber)
> +        cluster_node = self.create_cluster_node_instance(clm_cluster_node)
> +        return rc, cluster_node
>   
>   
>   @deprecate
> diff --git a/python/samples/clm-tool b/python/samples/clm-tool index 
> 89bf0d3..60dcc8f 100755
> --- a/python/samples/clm-tool
> +++ b/python/samples/clm-tool
> @@ -1,67 +1,252 @@
>   #!/usr/bin/env python
> -
> +#####################################################################
> +#######
> +#
> +# (C) Copyright 2015 The OpenSAF Foundation # (C) Copyright 2017 
> +Ericsson AB. All rights reserved.
> +#
> +# 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. This file and 
> +program are licensed # under the GNU Lesser General Public License Version 
> 2.1, February 1999.
> +# The complete license can be accessed from the following location:
> +# http://opensource.org/licenses/lgpl-license.php
> +# See the Copying file included with the OpenSAF distribution for 
> +full # licensing terms.
> +#
> +# Author(s): Ericsson
> +#
> +#####################################################################
> +#######
> +"""
> +This is a SAF CLM utility which supports options to:
> +    - Retrieve information about one or all CLM cluster member nodes.
> +    - Track CLM cluster membership changes.
> +    - Run clm-tool --help/-h for more detail on usage.
> +"""
> +from __future__ import print_function
>   import argparse
>   import sys
> +from select import select
>   
> -from pyosaf import saAis, saClm, saImm
> -
> +from pyosaf.saAis import saAis, eSaAisErrorT, eSaDispatchFlagsT
>   from pyosaf.utils import clm
> -
> -def dn_to_vm_name(vm_dn):
> -    return vm_dn.split(',')[0].split('=')[1]
> -
> -def print_members(members):
> -
> -    for node in members:
> -        if node.member:
> -            vm_name    = dn_to_vm_name(node.node_name)
> -            ip_address = node.node_address_value
> -
> -            print "  - %s  %s" % (vm_name, ip_address)
> -
> -def membership_change(added, removed):
> -    print "Info: Received cluster membership update"
> -
> -    for node in added:
> -        vm_name = dn_to_vm_name(node.node_name)
> -
> -        print "INFO: %s joined the cluster" % vm_name
> -
> -    for node in removed:
> -        vm_name = dn_to_vm_name(node.node_name)
> -
> -        print "INFO: %s left the cluster" % vm_name
> -
> -
> -if __name__ == "__main__":
> -
> -    # Parse command line arguments
> -    parser = argparse.ArgumentParser(
> -        description='Listens to changes to objects of the given classes')
> -
> -    group = parser.add_mutually_exclusive_group(required=True)
> -
> -    group.add_argument('--snapshot', action="store_true",
> -                        help='shows a snapshot of the current membership 
> list')
> -    group.add_argument('--listen', action="store_true", help='listens to 
> changes to all classes')
> -
> -    args = parser.parse_args()
> -
> -    # Initialize the CLM service
> -    clm.initialize(track_fn=membership_change)
> -
> -    if args.snapshot:
> -        print "-" * 10 + " Members " + "-"*10
> -
> -        members = clm.get_members()
> -
> -        print_members(members)
> -
> -        sys.exit(0)
> -
> -    # Start tracking
> -    clm.track()
> -
> -    # Do dispatch forever
> -    while True:
> -        clm.saClmDispatch(clm.HANDLE, 
> saAis.eSaDispatchFlagsT.SA_DISPATCH_BLOCKING)
> +from pyosaf.utils.immom.accessor import ImmOmAccessor
> +
> +
> +class ClmTool(object):
> +    """ This class provides functions of the clm-tool. """
> +    def __init__(self):
> +        self.clm_agent = clm.ClmAgent()
> +        self.clm_agent.init(self.membership_change)
> +        self.sel_obj = self.clm_agent.get_selection_object()
> +
> +    def print_members(self):
> +        """ Print out the name and the IP address of all current member 
> nodes.
> +
> +        Returns:
> +            Boolean: True if cluster members info is printed successfully.
> +                Otherwise, it is False.
> +
> +        """
> +        print("-" * 10 + " Members " + "-" * 10)
> +        rc, members = self.clm_agent.get_members()
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to get current membership. rc:",
> +                  eSaAisErrorT.whatis(rc))
> +            return False
> +        else:
> +            for node in members:
> +                node_name = self.node_dn_to_node_name(node.node_name)
> +                ip_address = node.node_address_value
> +                print("  - %s  %s" % (node_name, ip_address))
> +
> +        return True
> +
> +    def request_node_info(self, node_dn, time_out):
> +        """ Request the information of a specific member node which is
> +        identified by its DN.
> +
> +        Args:
> +            node_dn (str): The DN of SaClmNode class's object.
> +            time_out (int): Timeout in nanosecond.
> +
> +        Returns:
> +            ClusterNode: Node info or None if node with `node_dn` is not 
> found.
> +        """
> +        accessor = ImmOmAccessor()
> +        accessor.init()
> +
> +        rc, clm_node_object = accessor.get(node_dn)
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("%s object does not exist" % node_dn)
> +            return None
> +
> +        node_id = clm_node_object["saClmNodeID"]
> +        rc, mem_node_info = self.clm_agent.get_node_info(node_id, time_out)
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to request node info. rc:", 
> eSaAisErrorT.whatis(rc))
> +            return None
> +
> +        return mem_node_info
> +
> +    def start_tracking(self, track_type):
> +        """ Start tracking member nodes.
> +
> +        Args:
> +            track_type (SaUint8T): Type of cluster membership 
> + tracking
> +
> +        Returns:
> +            Boolean: True if it starts tracking successfully. Otherwise, it 
> is
> +                False.
> +        """
> +        rc = self.clm_agent.track_start(track_type)
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to start tracking. rc:", eSaAisErrorT.whatis(rc))
> +            return False
> +
> +        return True
> +
> +    def stop_tracking(self):
> +        """ Stop tracking member nodes.
> +
> +        Returns:
> +            Boolean: True if it stops tracking successfully. Otherwise, it is
> +                False.
> +        """
> +        rc = self.clm_agent.track_stop()
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to stop tracking. rc:", eSaAisErrorT.whatis(rc))
> +            return False
> +
> +        return True
> +
> +    def dispatch(self, dispatch_flag):
> +        """ Dispatch message to appropriate callback.
> +
> +        Args:
> +            dispatch_flag (eSaDispatchFlagsT): Flags specifying dispatch 
> mode.
> +
> +        Returns:
> +            Boolean: True if it dispatches message successfully. Otherwise, 
> it
> +                is False.
> +        """
> +        rc = self.clm_agent.dispatch(dispatch_flag)
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to dispatch message. rc:", eSaAisErrorT.whatis(rc))
> +            return False
> +
> +        return True
> +
> +    def finalize(self):
> +        """ Finalize the clm agent.
> +
> +        Returns:
> +            Boolean: True if it clm agent finalizes successfully. Otherwise, 
> it
> +                is False.
> +        """
> +        rc = self.clm_agent.finalize()
> +        if rc != eSaAisErrorT.SA_AIS_OK:
> +            print("Failed to finalize ClmAgent. rc:", 
> eSaAisErrorT.whatis(rc))
> +            return False
> +
> +        return True
> +
> +    def membership_change(self, node_list, invocation, step,
> +                          num_of_members, error):
> +        """ Callback to handle membership change event.
> +
> +        Args:
> +            node_list (tuple): A list of tuple which contain cluster node 
> info
> +                and cluster node change type.
> +            invocation (SaInvocationT):  A particular invocation of the
> +                callback function.
> +            step (SaClmChangeStepT): Indicates the tracking step in which
> +                the callback is invoked.
> +            num_of_members (SaUint32T): The current number of members in the
> +                cluster membership.
> +            error (SaAisErrorT): indicates if the CLM was able to perform the
> +                requested operation.
> +        """
> +
> +        print('-' * 10 + 'Membership Change' + '-' * 10)
> +        print("Changed nodes:")
> +        for node in node_list:
> +            self.print_node_info(node[0])
> +            print("\tNode change state:", node[1])
> +            print("\t" + "-" * 10)
> +
> +        print("Invocation:", invocation)
> +        print("Step:", step)
> +        print("Number of members:", num_of_members)
> +        print("Error code:", eSaAisErrorT.whatis(error))
> +
> +    @staticmethod
> +    def print_node_info(cluster_node):
> +        """ Print information of a cluster node.
> +
> +        Args:
> +            cluster_node (ClusterNode): ClusterNode object which is printed.
> +        """
> +        print("\tNode ID:", cluster_node.node_id)
> +        print("\tNode Address:", cluster_node.node_address_value)
> +        print("\tNode Address Family:", cluster_node.node_address_family)
> +        print("\tNode Name:", cluster_node.node_name)
> +        print("\tExecution Environment:",
> +              'None' if cluster_node.execution_environment.length == 0
> +              else cluster_node.execution_environment.value)
> +        print("\tMember:", 'Yes' if cluster_node.member == 1 else 'No')
> +        print("\tBoot Timestamp:", cluster_node.boot_timestamp)
> +        print("\tView Number:", cluster_node.initial_view_number)
> +
> +    @staticmethod
> +    def node_dn_to_node_name(node_dn):
> +        """ Convert from node's DN to node's name.
> +
> +        Args:
> +            node_dn (str): DN of a SaClmNode object.
> +
> +        Returns:
> +            str: Name of node.
> +        """
> +        return node_dn.split(',')[0].split('=')[1]
> +
> +
> +# Main
> +parser = argparse.ArgumentParser(description='This is a SAF CLM utility used 
> '
> +                                             'to view/track CLM cluster '
> +                                             'membership.') group = 
> +parser.add_mutually_exclusive_group(required=True)
> +group.add_argument('-s', '--show', action="store_true",
> +                   help='print info of all current cluster member 
> +nodes.') group.add_argument('-n', '--nodeinfo', type=str,
> +                   help="print info of a specific cluster member 
> +node.") group.add_argument('-t', '--track', action="store_true",
> +                   help='track changes in cluster membership.')
> +
> +clm_tool = ClmTool()
> +result = True
> +
> +args = parser.parse_args()
> +if args.show:
> +    result = clm_tool.print_members() elif args.nodeinfo:
> +    node_info = clm_tool.request_node_info(args.nodeinfo, 6000000000)
> +    if node_info is not None:
> +        clm_tool.print_node_info(node_info)
> +    else:
> +        result = False
> +elif args.track:
> +    fds = [clm_tool.sel_obj.value]
> +    result = clm_tool.start_tracking(saAis.SA_TRACK_CHANGES)
> +
> +    try:
> +        while result:
> +            ioe = select(fds, [], [])
> +            for fd in ioe[0]:
> +                if fd == clm_tool.sel_obj.value:
> +                    result = clm_tool.dispatch(
> +                        eSaDispatchFlagsT.SA_DISPATCH_ALL)
> +    except KeyboardInterrupt:
> +        clm_tool.stop_tracking()
> +
> +clm_tool.finalize()
> +sys.exit(0 if result else 1)



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to