Hi Danh,

ok, good. When I run with the same pylintrc yesterday I got:

************* Module clm-tool
C:  1, 0: Invalid module name "clm-tool" (invalid-name)
F: 30, 0: Unable to import 'pyosaf.saAis' (import-error)
F: 31, 0: Unable to import 'pyosaf.utils' (import-error)
F: 32, 0: Unable to import 'pyosaf.utils.immom.accessor' (import-error)
C: 51, 8: Invalid variable name "rc" (invalid-name)
C: 78, 8: Invalid variable name "rc" (invalid-name)
C: 84, 8: Invalid variable name "rc" (invalid-name)
C:101, 8: Invalid variable name "rc" (invalid-name)
C:115, 8: Invalid variable name "rc" (invalid-name)
C:132, 8: Invalid variable name "rc" (invalid-name)
C:146, 8: Invalid variable name "rc" (invalid-name)
R:153, 4: Too many arguments (6/5) (too-many-arguments)
C:214, 0: Invalid constant name "parser" (invalid-name)
C:217, 0: Invalid constant name "group" (invalid-name)
C:225, 0: Invalid constant name "clm_tool" (invalid-name)
C:226, 0: Invalid constant name "result" (invalid-name)
C:228, 0: Invalid constant name "args" (invalid-name)
C:230, 4: Invalid constant name "result" (invalid-name)
C:232, 4: Invalid constant name "node_info" (invalid-name)
C:236, 8: Invalid constant name "result" (invalid-name)
C:238, 4: Invalid constant name "fds" (invalid-name)
C:239, 4: Invalid constant name "result" (invalid-name)
C:243,12: Invalid constant name "ioe" (invalid-name)


Report
======
111 statements analysed.

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

 :

strange, anyhow it is ack from me.

/Regards HansN



On 12/20/2017 05:05 AM, Danh Vo wrote:
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