- Fix amf_demo to make it work.
   - Modify README for the latest amf_demo.
---
 python/samples/README   |  35 ++--
 python/samples/amf_demo | 436 +++++++++++++++++++++++++++++++-----------------
 2 files changed, 303 insertions(+), 168 deletions(-)

diff --git a/python/samples/README b/python/samples/README
index 84aa99c..1ba472a 100644
--- a/python/samples/README
+++ b/python/samples/README
@@ -1,28 +1,29 @@
 Sample code in this directory:
 
 amf_demo:
-       Drop-in replacement for C-compiled version; written in python.
-       You can use the same clc-cli script as is used for the C-version:
-               opensaf-staging/samples/avsv/amf_demo_script
+        Drop-in replacement for C-compiled version; written in python.
+        You can use the same clc-cli script and model as are used for the 
C-version:
+            opensaf-code/samples/amf/sa_aware/amf_demo_script
+            opensaf-code/samples/amf/sa_aware/AppConfig-2N.xml
 
 immadm:
-       CLI utility that simulates the C-version of the utility.
-       Run 'immadm --help' for specific options and arguments.
+        CLI utility that simulates the C-version of the utility.
+        Run 'immadm --help' for specific options and arguments.
 
 immlist:
-       CLI utility that simulates the C-version of the utility.
-       Run 'immlist --help' for specific options and arguments.
+        CLI utility that simulates the C-version of the utility.
+        Run 'immlist --help' for specific options and arguments.
 
 immbase.py:
-       Module required by immadm and immlist; contains logging interface and
-       other services.
+        Module required by immadm and immlist; contains logging interface and
+        other services.
 
 clm-tool:
         CLI utility that can be used that demonstrates how to fetch a list of
-        current members of the cluster and how to monitor changes to the 
+        current members of the cluster and how to monitor changes to the
         cluster. Run 'clm-tool --help' for specific options and arguments.
 
-imm-listener: 
+imm-listener:
         The Imm Lister OI demonstrates how to build an
         applier. It listens to changes to SampleClass1 and simply
         prints them on stdout. It's an applier which means that it
@@ -50,7 +51,7 @@ time-reporter:
         from an OI and inclusion of the OI logic into a select loop
         owned by the application. It creates a runtime object timeId=1
         of the class TimeSample and updates its hours, minutes and
-        seconds attributes once every second. 
+        seconds attributes once every second.
         Run 'time-reporter --help' for specific options and arguments
 
 ping-pong:
@@ -80,13 +81,13 @@ ntfsend:
         'ntfsend --help' for specific options and arguments.
 
 ntfsubscribe:
-       The ntfsubscribe sample application is a copy of the
-       ntfsubscribe tool, implemented in Python. It listens for
-       notifications and logs received notifications in the
-       terminal. Run 'ntfsubscribe --help'.
+        The ntfsubscribe sample application is a copy of the
+        ntfsubscribe tool, implemented in Python. It listens for
+        notifications and logs received notifications in the
+        terminal. Run 'ntfsubscribe --help'.
 
 Logging for all apps/utils goes to /var/log/opensaf/saflog/saLogSystem*.log
 
-The IMM OI samples use the classes defined in the classes.xml file. Load it 
with immcfg -f classes.xml before trying them. 
+The IMM OI samples use the classes defined in the classes.xml file. Load it 
with immcfg -f classes.xml before trying them.
 
 Each sample OI is implemented in two versions, one using straight callbacks 
and one using a class that subclasses Implementer or Applier. The latter is 
named <oi-name>-inheritance-impl
diff --git a/python/samples/amf_demo b/python/samples/amf_demo
index edeeff0..60b37fe 100644
--- a/python/samples/amf_demo
+++ b/python/samples/amf_demo
@@ -2,6 +2,7 @@
 ############################################################################
 #
 # (C) Copyright 2011 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
@@ -13,160 +14,293 @@
 # licensing terms.
 #
 # Author(s): Wind River Systems, Inc.
+#            Ericsson
 #
 ############################################################################
-
-from pyosaf.utils import log
-from pyosaf.utils.log.logger import SafLogger
-from pyosaf.saAmf import *
-from pyosaf.saLog import *
-import select
-import sys
+# pylint: disable=unused-argument
+"""
+This is a small demo which illustrates how to use AMF Python interfaces.
+"""
 import os
+import sys
+import errno
+import signal
+import socket
+import hashlib
+from select import select, error
+
+from pyosaf.utils import log_info, log_err
+from pyosaf.saAis import eSaAisErrorT, eSaDispatchFlagsT, SaNameT, SaVersionT
+from pyosaf import saAmf
+
+SA_AMF_CSI_ADD_ONE = saAmf.saAmf.SA_AMF_CSI_ADD_ONE
+SA_AMF_CSI_TARGET_ONE = saAmf.saAmf.SA_AMF_CSI_TARGET_ONE
+SA_AMF_CSI_TARGET_ALL = saAmf.saAmf.SA_AMF_CSI_TARGET_ALL
+
+
+class AmfDemo(object):
+    """ This class encapsulates functions provided by AMF. """
+    ha_state_map = {1: 'ACTIVE',
+                    2: 'STANDBY',
+                    3: 'QUIESCED',
+                    4: 'QUIESCING'}
+
+    def __init__(self, health_check_key, signal_handler):
+        self.handle = saAmf.SaAmfHandleT()
+        self.version = SaVersionT('B', 4, 1)
+        self.callbacks = saAmf.SaAmfCallbacksT_4()
+        self.sel_obj = saAmf.SaSelectionObjectT()
+        self.comp_name = SaNameT()
+        self.health_check_key = saAmf.SaAmfHealthcheckKeyT(health_check_key)
+        self.healthcheck_count = 1
+        self.term_handler = signal_handler
+
+    def initialize(self):
+        """ Initialize with AMF service and register as AMF component. """
+        self.callbacks.saAmfHealthcheckCallback = \
+            saAmf.SaAmfHealthcheckCallbackT(self.health_check_callback)
+        self.callbacks.saAmfComponentTerminateCallback = \
+            saAmf.SaAmfComponentTerminateCallbackT(
+                self.component_terminate_callback)
+        self.callbacks.saAmfCSISetCallback = \
+            saAmf.SaAmfCSISetCallbackT(self.csi_set_callback)
+        self.callbacks.saAmfCSIRemoveCallback = \
+            saAmf.SaAmfCSIRemoveCallbackT(self.csi_remove_callback)
+
+        log_info("Start initialization.")
+
+        rc = saAmf.saAmfInitialize_4(self.handle, self.callbacks, self.version)
+        if not self.check_rc("saAmfInitialize", rc):
+            return False
+
+        rc = saAmf.saAmfSelectionObjectGet(self.handle, self.sel_obj)
+        if not self.check_rc("saAmfSelectionObjectGet", rc):
+            return False
+
+        rc = saAmf.saAmfComponentNameGet(self.handle, self.comp_name)
+        if not self.check_rc("saAmfComponentNameGet", rc):
+            return False
+
+        rc = saAmf.saAmfComponentRegister(self.handle, self.comp_name, None)
+        if not self.check_rc("saAmfComponentRegister", rc):
+            return False
+
+        invocation_type = saAmf.eSaAmfHealthcheckInvocationT.\
+            SA_AMF_HEALTHCHECK_AMF_INVOKED
+        recovery_type = saAmf.eSaAmfRecommendedRecoveryT.\
+            SA_AMF_COMPONENT_FAILOVER
+        rc = saAmf.saAmfHealthcheckStart(self.handle, self.comp_name,
+                                         self.health_check_key,
+                                         invocation_type,
+                                         recovery_type)
+        if not self.check_rc("saAmfHealthcheckStart", rc):
+            return False
+
+        log_info("Initialization finished successfully.")
+        return True
+
+    def finalize(self):
+        """ Finalize amf handle """
+        rc = saAmf.saAmfFinalize(self.handle)
+        return self.check_rc("saAmfFinalize", rc)
+
+    def dispatch(self):
+        """ Dispatch message to appropriate callback """
+        rc = saAmf.saAmfDispatch(self.handle,
+                                 eSaDispatchFlagsT.SA_DISPATCH_ALL)
+        return self.check_rc("saAmfDispatch", rc)
+
+    def health_check_callback(self, invocation, comp_name, health_check_key):
+        """ Callback to handle health-check event.
+
+        Args:
+            invocation (SaInvocationT): A particular invocation of the
+                callback function.
+            comp_name (POINTER(SaNameT)): A pointer to the name of the
+                component that must undergo the particular healthcheck.
+            health_check_key (POINTER(SaAmfHealthcheckKeyT)): A pointer to the
+                key of the healthcheck to be executed.
+        """
+        log_info("Health check callback is invoked [%s]" %
+                 self.healthcheck_count)
+        rc = saAmf.saAmfResponse_4(self.handle, invocation, None,
+                                   eSaAisErrorT.SA_AIS_OK)
+        self.check_rc("saAmfResponse_4", rc)
+        self.healthcheck_count += 1
+
+    def csi_set_callback(self, invocation, comp_name, ha_state, csi_desc):
+        """ Callback to handle CSI set event.
+
+         Args:
+             invocation (SaInvocationT): A particular invocation of the
+                callback function.
+             comp_name (POINTER(SaNameT)): A pointer to the name of the
+                component which CSI assigns to.
+             ha_state (SaAmfHAStateT): The new HA state.
+             csi_desc (SaAmfCSIDescriptorT): Information about the
+                CSI targeted by this callback invocation.
+         """
+        log_info("CSI set callback is invoked")
+        next_ha_state = AmfDemo.ha_state_map[ha_state]
+        csi_name = csi_desc.csiName
+        csi_flags = csi_desc.csiFlags
+
+        if csi_flags in [SA_AMF_CSI_ADD_ONE, SA_AMF_CSI_TARGET_ONE]:
+            log_info("%s got %s assignment for %s" %
+                     (str(comp_name[0]), next_ha_state, str(csi_name)))
+        elif csi_flags == SA_AMF_CSI_TARGET_ALL:
+            log_info("%s got %s assignment for all CSI" %
+                     (str(comp_name[0]), next_ha_state))
+
+        if ha_state == saAmf.eSaAmfHAStateT.SA_AMF_HA_QUIESCING:
+            rc = saAmf.saAmfCSIQuiescingComplete(self.handle, invocation,
+                                                 eSaAisErrorT.SA_AIS_OK)
+            self.check_rc("saAmfCSIQuiescingComplete", rc)
+
+        rc = saAmf.saAmfResponse_4(self.handle, invocation, None,
+                                   eSaAisErrorT.SA_AIS_OK)
+        self.check_rc("saAmfResponse_4", rc)
+
+    def csi_remove_callback(self, invocation, comp_name, csi_name, csi_flags):
+        """ Callback to handle CSI remove event.
+
+         Args:
+             invocation (SaInvocationT): A particular invocation of the
+                callback function.
+             comp_name (POINTER(SaNameT)): A pointer to the name of the
+                component which CSI will be remove.
+             csi_name (POINTER(SaNameT)): A pointer to the name of the CSI
+                which must be removed from component.
+             csi_flags (SaAmfCSIFlagsT): The flag specifies whether one or more
+                CSIs are affected.
+         """
+        log_info("CSI remove callback is invoked")
+        if csi_flags == SA_AMF_CSI_TARGET_ONE:
+            log_info("Removing assignment of %s from %s" %
+                     (str(csi_name[0]), str(comp_name[0])))
+        elif csi_flags == SA_AMF_CSI_TARGET_ALL:
+            log_info("Removing ALL assignments from %s" % str(comp_name[0]))
+
+        rc = saAmf.saAmfResponse_4(self.handle, invocation, None,
+                                   eSaAisErrorT.SA_AIS_OK)
+        self.check_rc("saAmfResponse_4", rc)
+
+    def component_terminate_callback(self, invocation, comp_name):
+        """ Callback to handle component terminate event.
+
+         Args:
+             invocation (SaInvocationT): A particular invocation of the
+                callback function.
+             comp_name (POINTER(SaNameT)):  A pointer to the name of the
+                component to be terminated.
+         """
+        log_info("Component terminate callback is invoked")
+        log_info("Component %s is terminating" % str(comp_name[0]))
+        rc = saAmf.saAmfResponse_4(self.handle, invocation, None,
+                                   eSaAisErrorT.SA_AIS_OK)
+        self.check_rc("saAmfResponse_4", rc)
+        self.term_handler.send_terminate_msg()
+
+    @staticmethod
+    def check_rc(function_name, rc):
+        """ Check return code if it ok or not.
+
+        Args:
+            function_name (str): The name of the function.
+            rc (eSaAisErrorT): Return code which is checked.
+
+        Returns:
+            bool: True if rc is SA_AIS_OK. Otherwise, it is False.
+        """
+        if rc != eSaAisErrorT.SA_AIS_OK:
+            err_str = eSaAisErrorT.whatis(rc)
+            log_err("%s FAILED, rc: %s" % (function_name, err_str))
+            return False
+
+        return True
+
+
+class SignalHandler(object):
+    """ Util class for signal handling """
+    def __init__(self):
+        self.term_socket = socket.socketpair()
+        self.write_fd = self.term_socket[0].fileno()
+        self.listen_fd = self.term_socket[1].fileno()
+        signal.signal(signal.SIGTERM, self.handle_signal)
+        signal.signal(signal.SIGINT, self.handle_signal)
+
+    def handle_signal(self, signum, frame):
+        """ Handle terminate or interrupt signal """
+        if signum == signal.SIGINT:
+            log_info("SIGINT is caught!")
+        elif signum == signal.SIGTERM:
+            log_info("SIGTERM is caught!")
+            self.send_terminate_msg()
+
+    def send_terminate_msg(self):
+        os.write(self.write_fd, "Terminate request")
+
+
+def create_pid_file(pid, comp_name):
+    """ Create pid file which is handled by amf_demo_script.
+
+    Args:
+        pid (int): PID of the child process.
+        comp_name(str): Component name which is specified by
+            SA_AMF_COMPONENT_NAME environment variable.
+    """
+    md5 = hashlib.md5(comp_name + '\n').hexdigest()
+    pid_file_path = "/tmp/%s.pid" % md5
+    with open(pid_file_path, 'w') as md5_file:
+        md5_file.write(str(pid))
+
+
+def create_daemon(comp_name):
+    """ Create a child process and detach it from main process.
+
+    Args:
+        comp_name (str): Component name which is specified by
+            SA_AMF_COMPONENT_NAME environment variable.
+    """
+    pid = os.fork()
+    if pid != 0:
+        create_pid_file(pid, comp_name)
+        sys.exit(0)
 
-exec_name = os.path.basename(__file__)
-
-def chexit(funcName, rc):
-       if rc != eSaAisErrorT.SA_AIS_OK:
-               errstr = '%s FAILED (%s)!' % (funcName, eSaAisErrorT.whatis(rc))
-               raise ValueError(errstr)
-
-class AmfIface(object):
-       @staticmethod
-       def log(logstr):
-               if AmfIface.logger:
-                       AmfIface.logger.log(logstr)
-               else:
-                       print logstr
-
-       @staticmethod
-       def healthcheckCallback(invocation, compName, healthcheckKey):
-               saAmfResponse(AmfIface.amfHandle,
-                               invocation, eSaAisErrorT.SA_AIS_OK)
-
-       @staticmethod
-       def componentTerminateCallback(invocation, compName):
-               AmfIface.log('%s: componentTerminateCallback' %
-                       compName[0].value)
-               saAmfResponse(AmfIface.amfHandle,
-                               invocation, eSaAisErrorT.SA_AIS_OK)
-               AmfIface.isRunning = False
-
-       @staticmethod
-       def csiSetCallback(invocation, compName, haState, csiDescriptor):
-               AmfIface.log('%s: csiSetCallback: %s: %s' %
-                       (compName[0].value,
-                               csiDescriptor.csiName.value,
-                               eSaAmfHAStateT.whatis(haState)))
-               saAmfResponse(AmfIface.amfHandle,
-                               invocation, eSaAisErrorT.SA_AIS_OK)
-               if haState == eSaAmfHAStateT.SA_AMF_HA_QUIESCING:
-                       saAmfCSIQuiescingComplete(AmfIface.amfHandle,
-                                       invocation, eSaAisErrorT.SA_AIS_OK)
-
-       @staticmethod
-       def csiRemoveCallback(invocation, compName, csiName, csi_flags):
-                AmfIface.log('%s: csiRemoveCallback: %s' %
-                         (compName[0].value, csiName[0].value))
-               saAmfResponse(AmfIface.amfHandle,
-                               invocation, eSaAisErrorT.SA_AIS_OK)
-
-       @staticmethod
-       def protectionGroupTrackCallback(csiName, buffer, memberCount, error):
-               pass
-
-       @staticmethod
-       def proxiedComponentInstantiateCallback(invocation, proxiedCompName):
-               pass
-
-       @staticmethod
-       def proxiedComponentCleanupCallback(invocation, proxiedCompName):
-               pass
-
-       @staticmethod
-       def initialize(logger):
-               AmfIface.logger = logger
-               AmfIface.isRunning = False
-               AmfIface.amfHandle = SaAmfHandleT()
-               AmfIface.callbacks = SaAmfCallbacksT()
-               AmfIface.fd = SaSelectionObjectT()
-               AmfIface.compName = SaNameT()
-
-               AmfIface.callbacks.saAmfHealthcheckCallback = \
-                       SaAmfHealthcheckCallbackT(
-                               AmfIface.healthcheckCallback)
-               AmfIface.callbacks.saAmfComponentTerminateCallback = \
-                       SaAmfComponentTerminateCallbackT(
-                               AmfIface.componentTerminateCallback)
-               AmfIface.callbacks.saAmfCSISetCallback = \
-                       SaAmfCSISetCallbackT(
-                               AmfIface.csiSetCallback)
-               AmfIface.callbacks.saAmfCSIRemoveCallback = \
-                       SaAmfCSIRemoveCallbackT(
-                               AmfIface.csiRemoveCallback)
-               AmfIface.callbacks.saAmfProtectionGroupTrackCallback = \
-                       SaAmfProtectionGroupTrackCallbackT(
-                               AmfIface.protectionGroupTrackCallback)
-               AmfIface.callbacks.saAmfProxiedComponentInstantiateCallback = \
-                       SaAmfProxiedComponentInstantiateCallbackT(
-                               AmfIface.proxiedComponentInstantiateCallback)
-               AmfIface.callbacks.saAmfProxiedComponentCleanupCallback = \
-                       SaAmfProxiedComponentCleanupCallbackT(
-                               AmfIface.proxiedComponentCleanupCallback)
-
-               amf_version = SaVersionT('B', 1, 1)
-               chexit('saAmfInitialize',
-                       saAmfInitialize(AmfIface.amfHandle, AmfIface.callbacks,
-                       amf_version))
-               chexit('saAmfSelectionObjectGet',
-                       saAmfSelectionObjectGet(AmfIface.amfHandle,
-                       AmfIface.fd))
-               chexit('saAmfComponentNameGet',
-                       saAmfComponentNameGet(AmfIface.amfHandle,
-                       AmfIface.compName))
-               chexit('saAmfComponentRegister',
-                       saAmfComponentRegister(AmfIface.amfHandle,
-                       AmfIface.compName, None))
-
-               AmfIface.log('%s: REGISTERED.' % AmfIface.compName.value)
-               AmfIface.isRunning = True
-
-               healthcheckKey = SaAmfHealthcheckKeyT('AmfDemo')
-               it = eSaAmfHealthcheckInvocationT.SA_AMF_HEALTHCHECK_AMF_INVOKED
-               rt = eSaAmfRecommendedRecoveryT.SA_AMF_COMPONENT_FAILOVER
-
-               chexit('saAmfHealthcheckStart',
-                       saAmfHealthcheckStart(AmfIface.amfHandle,
-                       AmfIface.compName, healthcheckKey, it, rt))
-
-                AmfIface.log('%s: STARTED HEALTHCHECK %s' %
-                        (AmfIface.compName.value, healthcheckKey.key))
-
-       @staticmethod
-       def finalize():
-               saAmfComponentUnregister(AmfIface.amfHandle,
-                               AmfIface.compName, None)
-               saAmfFinalize(AmfIface.amfHandle)
-
-       @staticmethod
-       def dispatch(readfds):
-               if AmfIface.fd.value in readfds:
-                       chexit('saAmfDispatch',
-                               saAmfDispatch(AmfIface.amfHandle,
-                               eSaDispatchFlagsT.SA_DISPATCH_ALL))
-
-def main():
-       logger = SafLogger()
-       AmfIface.initialize(logger)
-
-       readfds = [logger.fd.value, AmfIface.fd.value]
-       while AmfIface.isRunning:
-               input, output, excepts = select.select(readfds, [], [])
-               logger.dispatch(input)
-               AmfIface.dispatch(input)
-
-       AmfIface.finalize()
-       logger.finalize()
 
 if __name__ == '__main__':
-       main()
+    env_comp_name = os.getenv("SA_AMF_COMPONENT_NAME")
+    if env_comp_name is None:
+        log_err("This process is not started by AMF. Exiting ...")
+        sys.exit(1)
+
+    create_daemon(env_comp_name)
+    terminate_handler = SignalHandler()
+
+    amf_demo = AmfDemo("AmfDemo", terminate_handler)
+    result = amf_demo.initialize()
+    if not result:
+        sys.exit(1)
+
+    fds = [amf_demo.sel_obj.value, amf_demo.term_handler.listen_fd]
+
+    stop_flag = False
+    while not stop_flag:
+        try:
+            ioe = select(fds, [], [])
+        except error as err:
+            if err[0] != errno.EINTR:
+                log_err("Something went wrong: %r" % err)
+                result = False
+            continue
+
+        for fd in ioe[0]:
+            if fd == amf_demo.term_handler.listen_fd:
+                stop_flag = True
+            elif fd == amf_demo.sel_obj.value:
+                result = amf_demo.dispatch()
+                if not result:
+                    stop_flag = True
+
+    amf_demo.finalize()
+    sys.exit(0 if result else 1)
-- 
2.7.4


------------------------------------------------------------------------------
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