Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP2
resource-agents.11371
0021-1233.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0021-1233.patch of Package resource-agents.11371
From 35c6faa1f43fd0751677a94573d5f5a2e76d73be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Thu, 4 Oct 2018 17:01:14 +0200 Subject: [PATCH 1/6] dev: ocf.py: Add missing imports to example --- doc/writing-python-agents.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/writing-python-agents.md b/doc/writing-python-agents.md index aeb4acbd6..584b1c997 100644 --- a/doc/writing-python-agents.md +++ b/doc/writing-python-agents.md @@ -60,6 +60,9 @@ logger.error("Something went terribly wrong.") ## Run loop and metadata example ``` python +import os +import sys + OCF_FUNCTIONS_DIR="%s/lib/heartbeat" % os.environ.get("OCF_ROOT") sys.path.append(OCF_FUNCTIONS_DIR) import ocf From 4b5d63a4faf54f91431795fb6c705dba679b0cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Thu, 4 Oct 2018 17:01:43 +0200 Subject: [PATCH 2/6] dev: ocf.py: Catch and log exceptions in a controlled way --- heartbeat/ocf.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/heartbeat/ocf.py b/heartbeat/ocf.py index 451a41dec..b16b5d4dd 100644 --- a/heartbeat/ocf.py +++ b/heartbeat/ocf.py @@ -141,6 +141,8 @@ def emit(self, record): logger = logging.LoggerAdapter(log, {'OCF_RESOURCE_INSTANCE': OCF_RESOURCE_INSTANCE}) +_exit_reason_set = False + def ocf_exit_reason(msg): """ Print exit error string to stderr. @@ -148,10 +150,12 @@ def ocf_exit_reason(msg): Allows the OCF agent to provide a string describing why the exit code was returned. """ + global _exit_reason_set cookie = env.get("OCF_EXIT_REASON_PREFIX", "ocf-exit-reason:") sys.stderr.write("{}{}\n".format(cookie, msg)) sys.stderr.flush() logger.error(msg) + _exit_reason_set = True def have_binary(name): @@ -343,10 +347,17 @@ def default_for_parameter(paramname): return meta.default return None arglist = [get_parameter(p, default_for_parameter(p)) for p in params] - rc = func(*arglist) - if rc is None: - rc = OCF_SUCCESS - return rc + try: + rc = func(*arglist) + if rc is None: + rc = OCF_SUCCESS + return rc + except Exception as err: + if not _exit_reason_set: + ocf_exit_reason(str(err)) + else: + logger.error(str(err)) + return OCF_ERR_GENERIC if OCF_ACTION is None: ocf_exit_reason("No action argument set") From 655ffe758f3b19ec2667eb6720c77d77e07f415f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Thu, 4 Oct 2018 17:33:06 +0200 Subject: [PATCH 3/6] dev: ocf.py: Print usage help when passed -h/--help as argument --- heartbeat/ocf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/heartbeat/ocf.py b/heartbeat/ocf.py index b16b5d4dd..ff4c67c6e 100644 --- a/heartbeat/ocf.py +++ b/heartbeat/ocf.py @@ -359,6 +359,11 @@ def default_for_parameter(paramname): logger.error(str(err)) return OCF_ERR_GENERIC + if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"): + sys.stdout.write("usage: %s {%s}\n\n" % (sys.argv[0], "|".join(sorted(handlers.keys()))) + + "Expects to have a fully populated OCF RA compliant environment set.\n") + sys.exit(OCF_SUCCESS) + if OCF_ACTION is None: ocf_exit_reason("No action argument set") sys.exit(OCF_ERR_UNIMPLEMENTED) From c95b3cdab92dc1ea2924c1ece302f6871f4f63e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Thu, 4 Oct 2018 17:43:21 +0200 Subject: [PATCH 4/6] dev: ocf.py: Enable passing handler as argument to add_action, and add Metadata.run() helper --- heartbeat/ocf.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/heartbeat/ocf.py b/heartbeat/ocf.py index ff4c67c6e..a95fa1c81 100644 --- a/heartbeat/ocf.py +++ b/heartbeat/ocf.py @@ -266,6 +266,7 @@ def __init__(self, name, shortdesc, longdesc): self.longdesc = longdesc self.parameters = [] self.actions = [] + self._handlers = {} def add_parameter(self, name, shortdesc="", longdesc="", content_type="string", unique=False, required=False, default=None): for param in self.parameters: @@ -280,11 +281,13 @@ def add_parameter(self, name, shortdesc="", longdesc="", content_type="string", default=default)) return self - def add_action(self, name, timeout=None, interval=None, depth=None): + def add_action(self, name, timeout=None, interval=None, depth=None, handler=None): self.actions.append(Action(name=name, timeout=timeout, interval=interval, depth=depth)) + if handler is not None: + self._handlers[name] = handler return self def __str__(self): @@ -312,8 +315,11 @@ def __str__(self): parameters="".join(str(p) for p in self.parameters), actions="".join(str(a) for a in self.actions)) + def run(self): + run(self) -def run(metadata, handlers): + +def run(metadata, handlers=None): """ Main loop implementation for resource agents. Does not return. @@ -330,6 +336,9 @@ def run(metadata, handlers): """ import inspect + metadata._handlers.update(handlers or {}) + handlers = metadata._handlers + def check_required_params(): for p in metadata.parameters: if p.required and get_parameter(p.name) is None: From f9f067f670cea824544c61d5471865cc5cf54ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Thu, 4 Oct 2018 17:59:03 +0200 Subject: [PATCH 5/6] dev: ocf.py: Rename Metadata to Agent --- doc/writing-python-agents.md | 29 +++++++++++------------- heartbeat/ocf.py | 43 +++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/doc/writing-python-agents.md b/doc/writing-python-agents.md index 584b1c997..1b87e753a 100644 --- a/doc/writing-python-agents.md +++ b/doc/writing-python-agents.md @@ -54,7 +54,7 @@ logger.error("Something went terribly wrong.") * `have_binary`: Returns True if the given binary is available. * `is_true`: Converts an OCF truth value to a Python boolean. * `get_parameter`: Looks up the matching `OCF_RESKEY_` environment variable. -* `Metadata`: Class which helps to generate the XML metadata. +* `Agent`: Class which helps to generate the XML metadata. * `run`: OCF run loop implementation. ## Run loop and metadata example @@ -72,21 +72,18 @@ def start_action(argument): def main(): - metadata = ocf.Metadata("example-agent", - shortdesc="This is an example agent", - longdesc="An example of how to " + - "write an agent in Python using the ocf " + - "Python library.") - metadata.add_parameter("argument", - shortdesc="Example argument", - longdesc="This argument is just an example.", - content_type="string", - default="foobar") - metadata.add_action("start", timeout=60) - ocf.run(metadata, - handlers={ - "start": start_action - }) + agent = ocf.Agent("example-agent", + shortdesc="This is an example agent", + longdesc="An example of how to " + + "write an agent in Python using the ocf " + + "Python library.") + agent.add_parameter("argument", + shortdesc="Example argument", + longdesc="This argument is just an example.", + content_type="string", + default="foobar") + agent.add_action("start", timeout=60, handler=start_action) + agent.run() if __name__ == "__main__": main() diff --git a/heartbeat/ocf.py b/heartbeat/ocf.py index a95fa1c81..e34066617 100644 --- a/heartbeat/ocf.py +++ b/heartbeat/ocf.py @@ -217,6 +217,9 @@ def __init__(self, name, shortdesc, longdesc, content_type, unique, required, de self.default = default def __str__(self): + return self.to_xml() + + def to_xml(self): ret = '<parameter name="' + self.name + '"' if self.unique: ret += ' unique="1"' @@ -233,6 +236,7 @@ def __str__(self): return ret + class Action(object): def __init__(self, name, timeout, interval, depth): self.name = name @@ -241,6 +245,9 @@ def __init__(self, name, timeout, interval, depth): self.depth = depth def __str__(self): + return self.to_xml() + + def to_xml(self): def opt(s, name, var): if var is not None: if type(var) == int: @@ -255,9 +262,16 @@ def opt(s, name, var): return ret -class Metadata(object): +class Agent(object): """ - Metadata XML generator helper. + OCF Resource Agent metadata XML generator helper. + + Use add_parameter/add_action to define parameters + and actions for the agent. Then call run() to + start the agent main loop. + + See doc/writing-python-agents.md for an example + of how to use it. """ def __init__(self, name, shortdesc, longdesc): @@ -291,6 +305,9 @@ def add_action(self, name, timeout=None, interval=None, depth=None, handler=None return self def __str__(self): + return self.to_xml() + + def to_xml(self): return """<?xml version="1.0"?> <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> <resource-agent name="{name}"> @@ -312,21 +329,21 @@ def __str__(self): """.format(name=self.name, longdesc=self.longdesc, shortdesc=self.shortdesc, - parameters="".join(str(p) for p in self.parameters), - actions="".join(str(a) for a in self.actions)) + parameters="".join(p.to_xml() for p in self.parameters), + actions="".join(a.to_xml() for a in self.actions)) def run(self): run(self) -def run(metadata, handlers=None): +def run(agent, handlers=None): """ Main loop implementation for resource agents. Does not return. Arguments: - metadata: Metadata structure generated by ocf.Metadata + agent: Agent object. handlers: Dict of action name to handler function. @@ -336,11 +353,11 @@ def run(metadata, handlers=None): """ import inspect - metadata._handlers.update(handlers or {}) - handlers = metadata._handlers + agent._handlers.update(handlers or {}) + handlers = agent._handlers def check_required_params(): - for p in metadata.parameters: + for p in agent.parameters: if p.required and get_parameter(p.name) is None: ocf_exit_reason("{}: Required parameter not set".format(p.name)) sys.exit(OCF_ERR_CONFIGURED) @@ -351,7 +368,7 @@ def call_handler(func): else: params = inspect.getargspec(func).args def default_for_parameter(paramname): - for meta in metadata.parameters: + for meta in agent.parameters: if meta.name == paramname: return meta.default return None @@ -377,7 +394,7 @@ def default_for_parameter(paramname): ocf_exit_reason("No action argument set") sys.exit(OCF_ERR_UNIMPLEMENTED) if OCF_ACTION in ('meta-data', 'usage', 'methods'): - sys.stdout.write(str(metadata) + "\n") + sys.stdout.write(agent.to_xml() + "\n") sys.exit(OCF_SUCCESS) check_required_params() @@ -392,7 +409,7 @@ def default_for_parameter(paramname): class TestMetadata(unittest.TestCase): def test_noparams_noactions(self): - m = Metadata("foo", shortdesc="shortdesc", longdesc="longdesc") + m = Agent("foo", shortdesc="shortdesc", longdesc="longdesc") self.assertEqual("""<?xml version="1.0"?> <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> <resource-agent name="foo"> @@ -414,7 +431,7 @@ def test_noparams_noactions(self): """, str(m)) def test_params_actions(self): - m = Metadata("foo", shortdesc="shortdesc", longdesc="longdesc") + m = Agent("foo", shortdesc="shortdesc", longdesc="longdesc") m.add_parameter("testparam") m.add_action("start") self.assertEqual(str(m.actions[0]), '<action name="start" />\n') From ee1e4551eeb85af89815ef136c42e944bb50e0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se> Date: Mon, 8 Oct 2018 14:53:24 +0200 Subject: [PATCH 6/6] dev: ocf.py: Only lookup default if parameter is not set --- heartbeat/ocf.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/heartbeat/ocf.py b/heartbeat/ocf.py index e34066617..72ec90820 100644 --- a/heartbeat/ocf.py +++ b/heartbeat/ocf.py @@ -367,12 +367,14 @@ def call_handler(func): params = inspect.signature(func).parameters.keys() else: params = inspect.getargspec(func).args - def default_for_parameter(paramname): - for meta in agent.parameters: - if meta.name == paramname: - return meta.default - return None - arglist = [get_parameter(p, default_for_parameter(p)) for p in params] + def value_for_parameter(param): + val = get_parameter(val) + if val is not None: + return val + for p in agent.parameters: + if p.name == param: + return p.default + arglist = [value_for_parameter(p) for p in params] try: rc = func(*arglist) if rc is None:
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor