Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit 8e7bf0fddc8b86fdecd110dbf653bdd2ddb60aae
Author: Peter Hatina <phatina(a)redhat.com>
Date: Fri Sep 19 14:53:01 2014 +0200
fix signal() behavior in non-main thread
>---------------------------------------------------------------
cli/lmi/shell/LMIMethod.py | 114 ++++++++++++++++++++++++++++---------------
1 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/cli/lmi/shell/LMIMethod.py b/cli/lmi/shell/LMIMethod.py
index b6f1775..988f9ab 100644
--- a/cli/lmi/shell/LMIMethod.py
+++ b/cli/lmi/shell/LMIMethod.py
@@ -54,46 +54,82 @@ from lmi.shell.LMIExceptions import *
logger = logging.getLogger(__name__)
-class LMISignalHelper(object):
+class LMISignalHelperBase(object):
"""
- Helper class, which takes care of signal (de)registration and handling.
+ Base signal handling class.
"""
- _instance = None
-
- def __new__(cls):
- if cls._instance is None:
- cls._instance = super(LMISignalHelper, cls).__new__(cls)
- LMISignalHelper.reset(cls._instance)
- return cls._instance
+ @staticmethod
+ def signal(signo, handler):
+ """
+ Calls signal() for signo, handler and returns the old signal handler.
+ If signo is list of signals, the signal() call is applied for each
+ signo. If handler is also list, each signal from signo will be handled
+ by corresponding handler. In such case, tuple of previous handlers will
+ be returned.
+ """
+ if isinstance(signo, (list, tuple)):
+ if not isinstance(handler, (list, tuple)):
+ handler = [handler] * len(signo)
+ signo_handler = zip(signo, handler)
+ if not signo_handler:
+ return (None,) * len(signo)
+ old_handlers = []
+ for signal, handler in signo_handler:
+ old_handlers.append(
+ LMISignalHelperBase.signal_core(signal, handler))
+ return tuple(old_handlers)
+ else:
+ return LMISignalHelperBase.signal_core(signal, handler)
- def reset(self):
+ @staticmethod
+ def signal_core(signo, handler):
"""
- Resets the single instance into default state.
+ Wrapper method for signal.signal(). In case of ValueError, it returns
+ None, old signal handler otherwise. If handler is None, default signal
+ handler is set for such signal.
"""
- self._handler_sigint = None
- self._handler_sigterm = None
+ try:
+ if handler is None:
+ handler = signal.SIG_DFL
+ return signal.signal(signo, handler)
+ except ValueError:
+ return None
+
+
+class LMIMethodSignalHelper(LMISignalHelperBase):
+ """
+ Helper class which takes care of signal (de)registration and handling.
+ """
+
+ INTERRUPT_SIGNALS = (
+ signal.SIGINT,
+ signal.SIGTERM)
+
+ def __init__(self):
+ super(LMIMethodSignalHelper, self).__init__()
self._signal_handled = False
- self._instance._callbacks = collections.OrderedDict()
+ self._signal_prev_handlers = (signal.SIG_DFL,) * 2
+ self._callbacks = collections.OrderedDict()
def signal_attach(self):
"""
Registers *SIGINT* and *SIGTERM* signals to local handler in which, the
flags for each signal are modified, if such signal is caught.
"""
+ def handler(sig, action):
+ self.signal_handler(sig, action)
+
self._signal_handled = False
- self._handler_sigint = signal.signal(
- signal.SIGINT, LMISignalHelper.__signal_handler)
- self._handler_sigterm = signal.signal(
- signal.SIGTERM, LMISignalHelper.__signal_handler)
+ self._signal_prev_handlers = self.signal(
+ self.INTERRUPT_SIGNALS, handler)
def signal_detach(self):
"""
Unregisters *SIGINT* and *SIGTERM* handler and removes all the attached
callbacks.
"""
- signal.signal(signal.SIGINT, self._handler_sigint)
- signal.signal(signal.SIGTERM, self._handler_sigterm)
+ self.signal(self.INTERRUPT_SIGNALS, self._signal_prev_handlers)
def signal_handled(self):
"""
@@ -120,21 +156,17 @@ class LMISignalHelper(object):
"""
self._callbacks.pop(cb_name)
- @staticmethod
- def __signal_handler(signo, frame):
+ def signal_handler(self, signo, frame):
"""
Signal handler, which is called, when *SIGINT* and *SIGTERM* are sent
to the LMIShell.
:param int signo: signal number
:param frame: -- stack frame
-
- **NOTE:** see help(signal)
"""
- if signo in (signal.SIGINT, signal.SIGTERM):
- LMISignalHelper._instance._signal_handled = True
- for cb in LMISignalHelper._instance._callbacks.values():
- cb()
+ if signo in self.INTERRUPT_SIGNALS:
+ self._signal_handled = True
+ [cb() for cb in self._callbacks.values()]
class LMIMethod(LMIWrapperBaseObject):
@@ -433,14 +465,15 @@ class LMIMethod(LMIWrapperBaseObject):
# Register signal callback for SIGINT, SIGTERM with callback,
# which awakes waiting thread for immediate return.
- LMISignalHelper().callback_attach(
+ signal_helper = LMIMethodSignalHelper()
+ signal_helper.callback_attach(
"indication", lambda: LMIMethod.__wake(cond))
- LMISignalHelper().signal_attach()
+ signal_helper.signal_attach()
# Wait for the job to finish
wake_cnt = 0
cond.acquire()
- while not LMISignalHelper().signal_handled() and \
+ while not signal_helper.signal_handled() and \
not job_finished.value and \
not lmi_is_job_finished(job_inst):
cond.wait(LMIMethod._COND_WAIT_TIME)
@@ -469,8 +502,8 @@ class LMIMethod(LMIWrapperBaseObject):
break
# Unregister signal handler
- LMISignalHelper().signal_detach()
- LMISignalHelper().callback_detach("indication")
+ signal_helper.signal_detach()
+ signal_helper.callback_detach("indication")
cond.release()
@@ -480,7 +513,7 @@ class LMIMethod(LMIWrapperBaseObject):
self._conn.client.delete_instance(cim_handler.path)
if job_exception.value:
raise job_exception.value
- if LMISignalHelper().signal_handled() and not job_finished.value:
+ if signal_helper.signal_handled() and not job_finished.value:
# We got SIGINT or SIGTERM, when waiting for the job, cancelling
# the job
logger.warn("Cancelling a job '%s'" % job_inst.Name)
@@ -506,9 +539,10 @@ class LMIMethod(LMIWrapperBaseObject):
# Register signal callback for SIGINT, SIGTERM with callback,
# which awakes waiting thread for immediate return.
- LMISignalHelper().callback_attach(
+ signal_helper = LMIMethodSignalHelper()
+ signal_helper.callback_attach(
"polling", lambda: LMIMethod.__wake(cond))
- LMISignalHelper().signal_attach()
+ signal_helper.signal_attach()
cond = threading.Condition()
cond.acquire()
@@ -517,7 +551,7 @@ class LMIMethod(LMIWrapperBaseObject):
try:
sleep_time = 1
- while not LMISignalHelper().signal_handled() and \
+ while not signal_helper.signal_handled() and \
not lmi_is_job_finished(job_inst):
# Sleep, a bit longer in every iteration
cond.wait(sleep_time)
@@ -539,10 +573,10 @@ class LMIMethod(LMIWrapperBaseObject):
cond.release()
# Unregister signal handler and callback
- LMISignalHelper().signal_detach()
- LMISignalHelper().callback_detach("polling")
+ signal_helper.signal_detach()
+ signal_helper.callback_detach("polling")
- if LMISignalHelper().signal_handled() and \
+ if signal_helper.signal_handled() and \
not lmi_is_job_finished(job_inst):
# We got SIGINT or SIGTERM, when waiting for the job, cancelling
# the job
Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit 6353405e63aeb711a3a68bb317349763c4f1e2a2
Author: Jan Safranek <jsafrane(a)redhat.com>
Date: Wed Sep 17 12:30:00 2014 +0200
Add readthedocs target to makefiles.
For readthedocs.org, we do not want Contents, Tables and indices and similar
chapters (i.e. we want the same as e.g. epub target), however we *do* want
to include developer API documentation.
Therefore include shell/code and scripts/devel/api in the 'rtd' target.
>---------------------------------------------------------------
doc/README.md | 6 +++++-
doc/src/Makefile | 2 +-
doc/src/scripts/Makefile | 2 +-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/doc/README.md b/doc/README.md
index 65a93d3..f17bd9b 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -5,7 +5,11 @@ It's available online on [pythonhosted][].
How to build
------------
-Supported builds are *html*, *pdflatex* and *epub*.
+Supported builds are *html*, *pdflatex*, *epub* and *rtd*.
+
+*rtd* build is similar to *html*, i.e. generates html files, however these
+files are intended to be included in overall OpenLMI documentation on
+readthedocs.org. It ommits several chapters, which would clutter navigation.
### Requirements
diff --git a/doc/src/Makefile b/doc/src/Makefile
index c73aa55..a4db2d0 100644
--- a/doc/src/Makefile
+++ b/doc/src/Makefile
@@ -86,7 +86,7 @@ shell-index-%:
echo " shell/return_values"; \
echo " shell/interactive_interface"; \
echo " shell/builtins"; \
- if [ "$*" == html ]; then \
+ if [ "$*" == html -o "$*" == rtd ]; then \
echo " shell/code"; \
fi; \
) > shell-index.rst
diff --git a/doc/src/scripts/Makefile b/doc/src/scripts/Makefile
index 6f3afd4..716e35b 100644
--- a/doc/src/scripts/Makefile
+++ b/doc/src/scripts/Makefile
@@ -17,7 +17,7 @@ devindex:
echo " devel/basics"; \
echo " devel/command-classes"; \
echo " devel/command-properties"; \
- if [ "$(BUILD)" == html ]; then \
+ if [ "$(BUILD)" == html -o "$(BUILD)" == rtd ]; then \
echo " devel/api"; \
fi; \
) > development.rst
Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit e4585db4bbe726d6343a0b337a599de5d3981763
Author: Michal Minar <miminar(a)redhat.com>
Date: Tue Sep 9 15:56:04 2014 +0200
documentation overhaul
Restructured whole documentation.
Lot of corrections and style improvements in scripts documentation.
Makefiles control the build. They generate index files and table of
contents.
Html build makes an index.rst composed of shell-index.rst and
metacommand-index.rst with single table of contents of depth 1.
It's the only build with autogenerated doc out of source code.
Man page build makes the index.rst of just shell-index.rst. Man page of
LMI metacommand is build separately.
Latex and other builds again contain both shell's and metacommand's
documentation. No autogerated documentation is included.
>---------------------------------------------------------------
Diff suppressed because of size. To see it, use:
git diff --patch-with-stat --no-color --find-copies-harder --ignore-space-at-eol ^e4585db4bbe726d6343a0b337a599de5d3981763~1 e4585db4bbe726d6343a0b337a599de5d3981763
Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit 5ceb2363f92d007fcc907cde2d2f738c1fd6fce1
Author: Peter Hatina <phatina(a)redhat.com>
Date: Mon Sep 1 12:39:08 2014 +0200
bump release version to 0.10.1
>---------------------------------------------------------------
cli/lmi/shell/LMIShellVersion.py | 2 +-
cli/man/lmi.1 | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cli/lmi/shell/LMIShellVersion.py b/cli/lmi/shell/LMIShellVersion.py
index 6df2b4e..d32920a 100644
--- a/cli/lmi/shell/LMIShellVersion.py
+++ b/cli/lmi/shell/LMIShellVersion.py
@@ -13,4 +13,4 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
-__version__ = "0.9.2"
+__version__ = "0.10.1"
diff --git a/cli/man/lmi.1 b/cli/man/lmi.1
index fa9e616..f803377 100644
--- a/cli/man/lmi.1
+++ b/cli/man/lmi.1
@@ -1,4 +1,4 @@
-.TH lmi 1 "June 2014" "openlmi-scripts 1.0.0" "User Commands"
+.TH lmi 1 "September 2014" "openlmi-scripts 1.0.0" "User Commands"
.SH NAME
lmi \- meta-command for managing systems with OpenLMI providers
Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit 39d1348ba4f762e57c72ce02adcd1a59f12d3bd3
Author: Peter Hatina <phatina(a)redhat.com>
Date: Mon Sep 1 12:16:32 2014 +0200
fix compat.CIMIndicationListener indication delivery
When using PyWBEM, no indications are being passed to callbacks due to wrong prefix present in path.
>---------------------------------------------------------------
cli/lmi/shell/LMIMethod.py | 7 ++-----
cli/lmi/shell/compat/CIMIndicationListener.py | 21 +++++++++++++++++----
2 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/cli/lmi/shell/LMIMethod.py b/cli/lmi/shell/LMIMethod.py
index b30d265..b6f1775 100644
--- a/cli/lmi/shell/LMIMethod.py
+++ b/cli/lmi/shell/LMIMethod.py
@@ -393,14 +393,11 @@ class LMIMethod(LMIWrapperBaseObject):
s.close()
# Create handler object
- indication_prefix = ""
- if HAVE_LMIWBEM:
- indication_prefix = "CIMListener/"
cim_handler_props = {
"Name": indication_name,
- "Destination": "%s://%s:%d/%s%s" % (
+ "Destination": "%s://%s:%d/CIMListener/%s" % (
"https" if listener.uses_ssl else "http",
- destination, listener.port, indication_prefix, indication_name),
+ destination, listener.port, indication_name),
}
cim_handler, _, _ = self._conn.client.create_instance(
"CIM_IndicationHandlerCIMXML",
diff --git a/cli/lmi/shell/compat/CIMIndicationListener.py b/cli/lmi/shell/compat/CIMIndicationListener.py
index 6b8a2d1..d2d939e 100644
--- a/cli/lmi/shell/compat/CIMIndicationListener.py
+++ b/cli/lmi/shell/compat/CIMIndicationListener.py
@@ -53,6 +53,8 @@ class CIMIndicationHandler(ThreadingMixIn, BaseHTTPRequestHandler):
listener is designed as concurrent server to properly handle each incoming
indication.
"""
+ CIMLISTENER_PREFIX = "/CIMListener"
+
def do_POST(self):
"""
Overridden method, which is called, when a indication is received. It
@@ -98,12 +100,23 @@ class CIMIndicationHandler(ThreadingMixIn, BaseHTTPRequestHandler):
ind_dict = export_methods.values()[0]
if "NewIndication" in ind_dict:
ind = ind_dict["NewIndication"]
+
path = self.path
- if path.startswith("CIMListener/"):
- # We got an indication with lmiwbem CIMListener prefix. We are
- # using pywbem now so it's necessary to strip the prefix.
- path = path[12:]
+ cimlistener_ind = path.find(self.CIMLISTENER_PREFIX)
+ if cimlistener_ind != -1:
+ # We got an indication with lmiwbem's CIMListener substring
+ # present. We are using pywbem now, so it's necessary to strip the
+ # prefix also with the substring (from the beginning). We try to
+ # mimic Pegasus::CIMListener behavior here.
+ path = path[cimlistener_ind + len(self.CIMLISTENER_PREFIX):]
+
+ if path[0] == '/':
+ # Path of the received indication may be prefixed by additional
+ # slash. Drop it then.
+ path = path[1:]
+
if path in self.server._handlers:
+ # We found the indication handler. Execute the callback.
cb = self.server._handlers[path]
cb.callback(ind, *cb.args, **cb.kwargs)