Accepting request 98031 from network:ha-clustering:Factory
Update to latest Pacemaker 1.1.6, accommodate crmsh package split OBS-URL: https://build.opensuse.org/request/show/98031 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/pacemaker?expand=0&rev=43
This commit is contained in:
commit
717bf1b747
@ -1,163 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Andrew Beekhof <andrew@beekhof.net>
|
|
||||||
# Date 1314251944 -36000
|
|
||||||
# Node ID d44ff2711662517d91b542b122218cffa2af3eb1
|
|
||||||
# Parent 4cc8fdf2827a31d41b48b8c97d784c75c9418eda
|
|
||||||
Low: cib: Remove the remaining uses of the xml_child_iter() macro
|
|
||||||
|
|
||||||
diff --git a/lib/cib/cib_acl.c b/lib/cib/cib_acl.c
|
|
||||||
--- a/lib/cib/cib_acl.c
|
|
||||||
+++ b/lib/cib/cib_acl.c
|
|
||||||
@@ -159,8 +159,7 @@ acl_check_diff(xmlNode *request, xmlNode
|
|
||||||
|
|
||||||
orig_diff = diff_xml_object_orig(current_cib, result_cib, FALSE, diff);
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- orig_diff, diff_child,
|
|
||||||
+ for (diff_child = __xml_first_child(orig_diff); diff_child; diff_child = __xml_next(diff_child)) {
|
|
||||||
const char *tag = crm_element_name(diff_child);
|
|
||||||
GListPtr parsed_acl = NULL;
|
|
||||||
|
|
||||||
@@ -176,8 +175,7 @@ acl_check_diff(xmlNode *request, xmlNode
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- diff_child, diff_cib,
|
|
||||||
+ for (diff_cib = __xml_first_child(diff_child); diff_cib; diff_child = __xml_next(diff_cib)) {
|
|
||||||
GHashTable *xml_perms = NULL;
|
|
||||||
|
|
||||||
gen_xml_perms(diff_cib, parsed_acl, &xml_perms);
|
|
||||||
@@ -188,9 +186,9 @@ acl_check_diff(xmlNode *request, xmlNode
|
|
||||||
crm_warn("User '%s' doesn't have enough permission to modify the CIB objects", user);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
free_acl(parsed_acl);
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
|
|
||||||
done:
|
|
||||||
free_xml(orig_diff);
|
|
||||||
@@ -264,8 +262,7 @@ unpack_user_acl(xmlNode *xml_acls, const
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml_acls, xml_acl,
|
|
||||||
+ for (xml_acl = __xml_first_child(xml_acls); xml_acl; xml_acl = __xml_next(xml_acl)) {
|
|
||||||
const char *tag = crm_element_name(xml_acl);
|
|
||||||
const char *id = crm_element_value(xml_acl, XML_ATTR_ID);
|
|
||||||
|
|
||||||
@@ -276,7 +273,7 @@ unpack_user_acl(xmlNode *xml_acls, const
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -296,8 +293,7 @@ user_match(const char *user, const char
|
|
||||||
static gboolean
|
|
||||||
unpack_acl(xmlNode *xml_acls, xmlNode *xml_acl, GListPtr *acl)
|
|
||||||
{
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml_acl, acl_child,
|
|
||||||
+ for (acl_child = __xml_first_child(xml_acl); acl_child; acl_child = __xml_next(acl_child)) {
|
|
||||||
const char *tag = crm_element_name(acl_child);
|
|
||||||
|
|
||||||
if (crm_str_eq(XML_ACL_TAG_ROLE_REF, tag, TRUE)) {
|
|
||||||
@@ -316,8 +312,8 @@ unpack_acl(xmlNode *xml_acls, xmlNode *x
|
|
||||||
static gboolean
|
|
||||||
unpack_role_acl(xmlNode *xml_acls, const char *role, GListPtr *acl)
|
|
||||||
{
|
|
||||||
- xml_child_iter_filter(
|
|
||||||
- xml_acls, xml_acl, XML_ACL_TAG_ROLE,
|
|
||||||
+ for (xml_acl = __xml_first_child(xml_acls); xml_acl; xml_acl = __xml_next(xml_acl)) {
|
|
||||||
+ if(crm_str_eq(XML_ACL_TAG_ROLE, (const char *)child->name, TRUE)) {
|
|
||||||
const char *role_id = crm_element_value(xml_acl, XML_ATTR_ID);
|
|
||||||
|
|
||||||
if (role_id && crm_str_eq(role, role_id, TRUE)) {
|
|
||||||
@@ -325,7 +321,8 @@ unpack_role_acl(xmlNode *xml_acls, const
|
|
||||||
unpack_acl(xml_acls, xml_acl, acl);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -495,12 +492,11 @@ search_xml_children(GListPtr *children,
|
|
||||||
}
|
|
||||||
|
|
||||||
if(search_matches || match_found == 0) {
|
|
||||||
- xml_child_iter(
|
|
||||||
- root, child,
|
|
||||||
+ for (child = __xml_first_child(root); child; child = __xml_next(child)) {
|
|
||||||
match_found += search_xml_children(
|
|
||||||
children, child, tag, field, value,
|
|
||||||
search_matches);
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
return match_found;
|
|
||||||
@@ -563,10 +559,9 @@ update_xml_perms(xmlNode *xml, acl_obj_t
|
|
||||||
crm_debug_3("Permission for element: element_mode=%s, tag=%s, id=%s",
|
|
||||||
perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml, child,
|
|
||||||
+ for (child = __xml_first_child(root); child; child = __xml_next(child)) {
|
|
||||||
update_xml_children_perms(child, perm->mode, xml_perms);
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (perm->attribute_perms == NULL
|
|
||||||
@@ -610,10 +605,9 @@ update_xml_children_perms(xmlNode *xml,
|
|
||||||
crm_debug_4("Permission for child element: element_mode=%s, tag=%s, id=%s",
|
|
||||||
mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml, child,
|
|
||||||
+ for (child = __xml_first_child(root); child; child = __xml_next(child)) {
|
|
||||||
update_xml_children_perms(child, mode, xml_perms);
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
@@ -647,12 +641,11 @@ acl_filter_xml(xmlNode *xml, GHashTable
|
|
||||||
xml_perm_t *perm = NULL;
|
|
||||||
int allow_counter = 0;
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml, child,
|
|
||||||
+ for (child = __xml_first_child(xml); child; child = __xml_next(child)) {
|
|
||||||
if (acl_filter_xml(child, xml_perms) == FALSE) {
|
|
||||||
children_counter++;
|
|
||||||
}
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
|
|
||||||
g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm);
|
|
||||||
|
|
||||||
@@ -720,12 +713,11 @@ acl_check_diff_xml(xmlNode *xml, GHashTa
|
|
||||||
{
|
|
||||||
xml_perm_t *perm = NULL;
|
|
||||||
|
|
||||||
- xml_child_iter(
|
|
||||||
- xml, child,
|
|
||||||
+ for (child = __xml_first_child(xml); child; child = __xml_next(child)) {
|
|
||||||
if (acl_check_diff_xml(child, xml_perms) == FALSE) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
- );
|
|
||||||
+ }
|
|
||||||
|
|
||||||
g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm);
|
|
||||||
|
|
12
bug-728579_pacemaker-stonith-dev-id.diff
Normal file
12
bug-728579_pacemaker-stonith-dev-id.diff
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
diff --git a/fencing/commands.c b/fencing/commands.c
|
||||||
|
index 8269d30..b2660ca 100644
|
||||||
|
--- a/fencing/commands.c
|
||||||
|
+++ b/fencing/commands.c
|
||||||
|
@@ -368,6 +368,7 @@ static stonith_device_t *build_device_from_xml(xmlNode *msg)
|
||||||
|
device->agent = crm_element_value_copy(dev, "agent");
|
||||||
|
device->namespace = crm_element_value_copy(dev, "namespace");
|
||||||
|
device->params = xml2list(dev);
|
||||||
|
+ g_hash_table_insert(device->params, crm_strdup("CRM_" F_STONITH_DEVICE), crm_strdup(device->id));
|
||||||
|
device->work = mainloop_add_trigger(G_PRIORITY_HIGH, stonith_device_dispatch, device);
|
||||||
|
/* TODO: Hook up priority */
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313755383 -7200
|
|
||||||
# Node ID e8ea8fb95f310997995576ee831693b0d3b2736a
|
|
||||||
# Parent 0abb257259ed722abaa32a237c3c284c08ec0737
|
|
||||||
Medium: Shell: enable removal of unmanaged resources (bnc#696506)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/cibconfig.py b/shell/modules/cibconfig.py
|
|
||||||
--- a/shell/modules/cibconfig.py
|
|
||||||
+++ b/shell/modules/cibconfig.py
|
|
||||||
@@ -2303,7 +2303,7 @@ class CibFactory(Singleton):
|
|
||||||
no_object_err(obj_id)
|
|
||||||
rc = False
|
|
||||||
continue
|
|
||||||
- if is_rsc_running(obj_id):
|
|
||||||
+ if is_rsc_managed(obj_id) and is_rsc_running(obj_id):
|
|
||||||
common_err("resource %s is running, can't delete it" % obj_id)
|
|
||||||
rc = False
|
|
||||||
else:
|
|
||||||
diff --git a/shell/modules/xmlutil.py b/shell/modules/xmlutil.py
|
|
||||||
--- a/shell/modules/xmlutil.py
|
|
||||||
+++ b/shell/modules/xmlutil.py
|
|
||||||
@@ -178,6 +178,34 @@ def shadowfile(name):
|
|
||||||
def shadow2doc(name):
|
|
||||||
return file2doc(shadowfile(name))
|
|
||||||
|
|
||||||
+def is_xs_boolean_true(bool):
|
|
||||||
+ return bool.lower() in ("true","1")
|
|
||||||
+def is_rsc_managed(id):
|
|
||||||
+ if not is_live_cib():
|
|
||||||
+ return False
|
|
||||||
+ rsc_node = rsc2node(id)
|
|
||||||
+ if not rsc_node:
|
|
||||||
+ return False
|
|
||||||
+ prop_node = get_properties_node(get_conf_elem(cibdump2doc("crm_config"), "crm_config"))
|
|
||||||
+ # maintenance-mode, if true, overrides all
|
|
||||||
+ attr = get_attr_value(prop_node, "maintenance-mode")
|
|
||||||
+ if attr and is_xs_boolean_true(attr):
|
|
||||||
+ return False
|
|
||||||
+ # then check the rsc is-managed meta attribute
|
|
||||||
+ rsc_meta_node = get_rsc_meta_node(rsc_node)
|
|
||||||
+ attr = get_attr_value(rsc_meta_node, "is-managed")
|
|
||||||
+ if attr:
|
|
||||||
+ return is_xs_boolean_true(attr)
|
|
||||||
+ # then rsc_defaults is-managed attribute
|
|
||||||
+ rsc_dflt_node = get_rscop_defaults_meta_node(get_conf_elem(cibdump2doc("rsc_defaults"), "rsc_defaults"))
|
|
||||||
+ attr = get_attr_value(rsc_dflt_node, "is-managed")
|
|
||||||
+ if attr:
|
|
||||||
+ return is_xs_boolean_true(attr)
|
|
||||||
+ # finally the is-managed-default property
|
|
||||||
+ attr = get_attr_value(prop_node, "is-managed-default")
|
|
||||||
+ if attr:
|
|
||||||
+ return is_xs_boolean_true(attr)
|
|
||||||
+ return True
|
|
||||||
def is_rsc_running(id):
|
|
||||||
if not is_live_cib():
|
|
||||||
return False
|
|
||||||
@@ -691,12 +719,20 @@ def silly_constraint(c_node,rsc_id):
|
|
||||||
def get_rsc_children_ids(node):
|
|
||||||
return [x.getAttribute("id") \
|
|
||||||
for x in node.childNodes if is_child_rsc(x)]
|
|
||||||
-def get_rscop_defaults_meta_node(node):
|
|
||||||
+def get_child_nvset_node(node, attr_set = "meta_attributes"):
|
|
||||||
+ if not node:
|
|
||||||
+ return None
|
|
||||||
for c in node.childNodes:
|
|
||||||
- if not is_element(c) or c.tagName != "meta_attributes":
|
|
||||||
+ if not is_element(c) or c.tagName != attr_set:
|
|
||||||
continue
|
|
||||||
return c
|
|
||||||
return None
|
|
||||||
+def get_rscop_defaults_meta_node(node):
|
|
||||||
+ return get_child_nvset_node(node)
|
|
||||||
+def get_rsc_meta_node(node):
|
|
||||||
+ return get_child_nvset_node(node)
|
|
||||||
+def get_properties_node(node):
|
|
||||||
+ return get_child_nvset_node(node, attr_set = "cluster_property_set")
|
|
||||||
|
|
||||||
def new_cib():
|
|
||||||
doc = xml.dom.minidom.Document()
|
|
||||||
@@ -727,12 +763,19 @@ def new_cib_element(node,tagname,id_pfx)
|
|
||||||
node.appendChild(newnode)
|
|
||||||
return newnode
|
|
||||||
def get_attr_in_set(node,attr):
|
|
||||||
+ if not node:
|
|
||||||
+ return None
|
|
||||||
for c in node.childNodes:
|
|
||||||
if not is_element(c):
|
|
||||||
continue
|
|
||||||
if c.tagName == "nvpair" and c.getAttribute("name") == attr:
|
|
||||||
return c
|
|
||||||
return None
|
|
||||||
+def get_attr_value(node,attr):
|
|
||||||
+ n = get_attr_in_set(node,attr)
|
|
||||||
+ if not n:
|
|
||||||
+ return None
|
|
||||||
+ return n.getAttribute("value")
|
|
||||||
def set_attr(node,attr,value):
|
|
||||||
'''
|
|
||||||
Set an attribute in the attribute set.
|
|
@ -1,13 +0,0 @@
|
|||||||
Index: pacemaker/shell/modules/report.py
|
|
||||||
===================================================================
|
|
||||||
--- pacemaker.orig/shell/modules/report.py
|
|
||||||
+++ pacemaker/shell/modules/report.py
|
|
||||||
@@ -643,6 +643,8 @@ class Report(Singleton):
|
|
||||||
def set_source(self,src):
|
|
||||||
'Set our source.'
|
|
||||||
self.source = src
|
|
||||||
+ if self.source != "live":
|
|
||||||
+ self.reset_period()
|
|
||||||
def set_period(self,from_dt,to_dt):
|
|
||||||
'''
|
|
||||||
Set from/to_dt.
|
|
2213
crm_history.patch
2213
crm_history.patch
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314279513 -7200
|
|
||||||
# Node ID d21f988a419c0c7fa349c4e26f6b500944d91370
|
|
||||||
# Parent 709ef91cfada2822aca53dcef085ddb6952393c5
|
|
||||||
Low: Shell: look for log segments with more care and don't throw exception on seek (bnc#713939)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -72,8 +72,15 @@ def seek_to_edge(f, ts, to_end):
|
|
||||||
Linear search, but should be short.
|
|
||||||
'''
|
|
||||||
if not to_end:
|
|
||||||
+ beg = 0
|
|
||||||
while ts == get_timestamp(f):
|
|
||||||
- f.seek(-1000, 1) # go back 10 or so lines
|
|
||||||
+ if f.tell() < 1000:
|
|
||||||
+ f.seek(0) # otherwise, the seek below throws an exception
|
|
||||||
+ if beg > 0: # avoid infinite loop
|
|
||||||
+ return # goes all the way to the top
|
|
||||||
+ beg += 1
|
|
||||||
+ else:
|
|
||||||
+ f.seek(-1000, 1) # go back 10 or so lines
|
|
||||||
while True:
|
|
||||||
pos = f.tell()
|
|
||||||
s = f.readline()
|
|
||||||
@@ -86,8 +93,8 @@ def seek_to_edge(f, ts, to_end):
|
|
||||||
def log_seek(f, ts, to_end = False):
|
|
||||||
'''
|
|
||||||
f is an open log. Do binary search for the timestamp.
|
|
||||||
- Return the position of the (more or less) first line with a
|
|
||||||
- newer time.
|
|
||||||
+ Return the position of the (more or less) first line with an
|
|
||||||
+ earlier (or later) time.
|
|
||||||
'''
|
|
||||||
first = 0
|
|
||||||
f.seek(0,2)
|
|
@ -1,298 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314632951 -7200
|
|
||||||
# Node ID ccd0c1e1edf9f23cafb4363014acba755f1b4e25
|
|
||||||
# Parent d21f988a419c0c7fa349c4e26f6b500944d91370
|
|
||||||
Medium: Shell: several history improvements
|
|
||||||
|
|
||||||
- add more patterns for fencing
|
|
||||||
- handle better PE files number reaching limit
|
|
||||||
|
|
||||||
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt
|
|
||||||
+++ b/doc/crm.8.txt
|
|
||||||
@@ -2426,7 +2426,8 @@ Example:
|
|
||||||
|
|
||||||
The `latest` command shows a bit of recent history, more
|
|
||||||
precisely whatever happened since the last cluster change (the
|
|
||||||
-latest transition).
|
|
||||||
+latest transition). If the transition is running, the shell will
|
|
||||||
+first wait until it finishes.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
@@ -2540,10 +2541,13 @@ Example:
|
|
||||||
setnodes node_a node_b
|
|
||||||
...............
|
|
||||||
|
|
||||||
-[[cmdhelp_history_resource,resource failed actions]]
|
|
||||||
+[[cmdhelp_history_resource,resource events]]
|
|
||||||
==== `resource`
|
|
||||||
|
|
||||||
-Show status changes and any failures that happened on a resource.
|
|
||||||
+Show actions and any failures that happened on all specified
|
|
||||||
+resources on all nodes. Normally, one gives resource names as
|
|
||||||
+arguments, but it is also possible to use extended regular
|
|
||||||
+expressions.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
@@ -2551,14 +2555,17 @@ Usage:
|
|
||||||
...............
|
|
||||||
Example:
|
|
||||||
...............
|
|
||||||
- resource mydb
|
|
||||||
+ resource bigdb public_ip
|
|
||||||
+ resource bigdb:0
|
|
||||||
+ resource bigdb:.
|
|
||||||
...............
|
|
||||||
|
|
||||||
[[cmdhelp_history_node,node events]]
|
|
||||||
==== `node`
|
|
||||||
|
|
||||||
Show important events that happened on a node. Important events
|
|
||||||
-are node lost and join, standby and online, and fence.
|
|
||||||
+are node lost and join, standby and online, and fence. Use either
|
|
||||||
+node names or extended regular expressions.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
@@ -2572,7 +2579,17 @@ Example:
|
|
||||||
[[cmdhelp_history_log,log content]]
|
|
||||||
==== `log`
|
|
||||||
|
|
||||||
-Show logs for a node or combined logs of all nodes.
|
|
||||||
+Show messages logged on one or more nodes. Leaving out a node
|
|
||||||
+name produces combined logs of all nodes. Messages are sorted by
|
|
||||||
+time and, if the terminal emulations supports it, displayed in
|
|
||||||
+different colours depending on the node to allow for easier
|
|
||||||
+reading.
|
|
||||||
+
|
|
||||||
+The sorting key is the timestamp as written by syslog which
|
|
||||||
+normally has the maximum resolution of one second. Obviously,
|
|
||||||
+messages generated by events which share the same timestamp may
|
|
||||||
+not be sorted in the same way as they happened. Such close events
|
|
||||||
+may actually happen fairly often.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
@@ -2634,8 +2651,8 @@ the transition are printed.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
- transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
- transition showdot [<number>|<file>]
|
|
||||||
+ transition [<number>|<index>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
+ transition showdot [<number>|<index>|<file>]
|
|
||||||
...............
|
|
||||||
Examples:
|
|
||||||
...............
|
|
||||||
diff --git a/shell/modules/log_patterns.py b/shell/modules/log_patterns.py
|
|
||||||
--- a/shell/modules/log_patterns.py
|
|
||||||
+++ b/shell/modules/log_patterns.py
|
|
||||||
@@ -12,34 +12,41 @@
|
|
||||||
# detail level 0 is the lowest, i.e. should match the least
|
|
||||||
# number of relevant messages
|
|
||||||
|
|
||||||
-# NB: If you modify this file, you must follow python syntax!
|
|
||||||
+# NB:
|
|
||||||
+# %% stands for whatever user input we get, for instance a
|
|
||||||
+# resource name or node name or just some regular expression
|
|
||||||
+# in optimal case, it should be surrounded by literals
|
|
||||||
+#
|
|
||||||
+# [Note that resources may contain clone numbers!]
|
|
||||||
|
|
||||||
log_patterns = {
|
|
||||||
"resource": (
|
|
||||||
( # detail 0
|
|
||||||
- "lrmd:.*rsc:%%.*(start|stop|promote|demote|migrate)",
|
|
||||||
- "lrmd:.*RA output:.*%%.*stderr",
|
|
||||||
- "lrmd:.*WARN:.*Managed.*%%.*exited",
|
|
||||||
+ "lrmd:.*rsc:%% (start|stop|promote|demote|migrate)",
|
|
||||||
+ "lrmd:.*RA output: .%%:.*:stderr",
|
|
||||||
+ "lrmd:.*WARN: Managed %%:.*exited",
|
|
||||||
),
|
|
||||||
( # detail 1
|
|
||||||
- "lrmd:.*rsc:%%.*(probe|notify)",
|
|
||||||
- "lrmd:.*info:.*Managed.*%%.*exited",
|
|
||||||
+ "lrmd:.*rsc:%%:.*(probe|notify)",
|
|
||||||
+ "lrmd:.*info: Managed %%:.*exited",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
"node": (
|
|
||||||
( # detail 0
|
|
||||||
- "%%.*Corosync.Cluster.Engine",
|
|
||||||
- "%%.*Executive.Service.RELEASE",
|
|
||||||
- "%%.*crm_shutdown:.Requesting.shutdown",
|
|
||||||
- "%%.*pcmk_shutdown:.Shutdown.complete",
|
|
||||||
- "%%.*Configuration.validated..Starting.heartbeat",
|
|
||||||
- "pengine.*Scheduling Node %%",
|
|
||||||
- "te_fence_node.*Exec.*%%",
|
|
||||||
- "stonith-ng.*log_oper.*reboot.*%%",
|
|
||||||
- "stonithd.*to STONITH.*%%",
|
|
||||||
- "stonithd.*fenced node %%",
|
|
||||||
- "pcmk_peer_update.*(lost|memb): %%",
|
|
||||||
- "crmd.*ccm_event.*(NEW|LOST) %%",
|
|
||||||
+ " %% .*Corosync.Cluster.Engine",
|
|
||||||
+ " %% .*Executive.Service.RELEASE",
|
|
||||||
+ " %% .*crm_shutdown:.Requesting.shutdown",
|
|
||||||
+ " %% .*pcmk_shutdown:.Shutdown.complete",
|
|
||||||
+ " %% .*Configuration.validated..Starting.heartbeat",
|
|
||||||
+ "pengine.*Scheduling Node %% for STONITH",
|
|
||||||
+ "crmd.* tengine_stonith_callback: .* of %% failed",
|
|
||||||
+ "stonith-ng.*log_operation:.*host '%%'",
|
|
||||||
+ "te_fence_node: Exec.*on %% ",
|
|
||||||
+ "pe_fence_node: Node %% will be fenced",
|
|
||||||
+ "stonith-ng.*remote_op_timeout:.*for %% timed",
|
|
||||||
+ "stonithd.*Succeeded.*node %%:",
|
|
||||||
+ "pcmk_peer_update.*(lost|memb): %% ",
|
|
||||||
+ "crmd.*ccm_event.*(NEW|LOST):.* %% ",
|
|
||||||
),
|
|
||||||
( # detail 1
|
|
||||||
),
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -589,7 +589,7 @@ class Report(Singleton):
|
|
||||||
except IOError,msg:
|
|
||||||
common_err("open %s: %s"%(fl[0],msg))
|
|
||||||
continue
|
|
||||||
- pe_l = self.get_transitions([x for x in f], keep_pe_path = True)
|
|
||||||
+ pe_l = self.list_transitions([x for x in f], future_pe = True)
|
|
||||||
if pe_l:
|
|
||||||
l.append([node,pe_l])
|
|
||||||
return l
|
|
||||||
@@ -752,12 +752,13 @@ class Report(Singleton):
|
|
||||||
for n in self.cibnode_l:
|
|
||||||
self.nodecolor[n] = self.nodecolors[i]
|
|
||||||
i = (i+1) % len(self.nodecolors)
|
|
||||||
- def get_transitions(self, msg_l = None, keep_pe_path = False):
|
|
||||||
+ def list_transitions(self, msg_l = None, future_pe = False):
|
|
||||||
'''
|
|
||||||
- Get a list of transitions.
|
|
||||||
+ List transitions by reading logs.
|
|
||||||
Empty transitions are skipped.
|
|
||||||
- Some callers need original PE file path (keep_pe_path),
|
|
||||||
- otherwise we produce the path within the report.
|
|
||||||
+ Some callers need original PE file path (future_pe),
|
|
||||||
+ otherwise we produce the path within the report and check
|
|
||||||
+ if the transition files exist.
|
|
||||||
If the caller doesn't provide the message list, then we
|
|
||||||
build it from the collected log files (self.logobj).
|
|
||||||
Otherwise, we get matches for transition patterns.
|
|
||||||
@@ -786,11 +787,18 @@ class Report(Singleton):
|
|
||||||
continue
|
|
||||||
elif num_actions == -1: # couldn't find messages
|
|
||||||
common_warn("could not find number of actions for transition (%s)" % pe_base)
|
|
||||||
- common_debug("found PE input at %s: %s" % (node, pe_file))
|
|
||||||
- if keep_pe_path:
|
|
||||||
- pe_l.append(pe_file)
|
|
||||||
+ if not future_pe:
|
|
||||||
+ pe_l_file = os.path.join(self.loc, node, "pengine", pe_base)
|
|
||||||
+ if not os.path.isfile(pe_l_file):
|
|
||||||
+ warn_once("%s in the logs, but not in the report" % pe_l_file)
|
|
||||||
+ continue
|
|
||||||
else:
|
|
||||||
- pe_l.append(os.path.join(self.loc, node, "pengine", pe_base))
|
|
||||||
+ pe_l_file = "%s:%s" % (node, pe_file)
|
|
||||||
+ if pe_l_file in pe_l:
|
|
||||||
+ common_warn("duplicate %s, replacing older PE file" % pe_l_file)
|
|
||||||
+ pe_l.remove(pe_l_file)
|
|
||||||
+ common_debug("found PE input: %s" % pe_l_file)
|
|
||||||
+ pe_l.append(pe_l_file)
|
|
||||||
return pe_l
|
|
||||||
def report_setup(self):
|
|
||||||
if not self.loc:
|
|
||||||
@@ -802,11 +810,7 @@ class Report(Singleton):
|
|
||||||
self.set_node_colors()
|
|
||||||
self.logobj = LogSyslog(self.central_log, self.log_l, \
|
|
||||||
self.from_dt, self.to_dt)
|
|
||||||
- self.peinputs_l = self.get_transitions()
|
|
||||||
- for pe_input in self.peinputs_l:
|
|
||||||
- if not os.path.isfile(pe_input):
|
|
||||||
- warn_once("%s in the logs, but not in the report" % pe_input)
|
|
||||||
- self.peinputs_l.remove(pe_input)
|
|
||||||
+ self.peinputs_l = self.list_transitions()
|
|
||||||
def prepare_source(self):
|
|
||||||
'''
|
|
||||||
Unpack a hb_report tarball.
|
|
||||||
@@ -859,7 +863,7 @@ class Report(Singleton):
|
|
||||||
if not args:
|
|
||||||
re_l = mk_re_list(patt_l,"")
|
|
||||||
else:
|
|
||||||
- re_l = mk_re_list(patt_l,r'(%s)\W' % "|".join(args))
|
|
||||||
+ re_l = mk_re_list(patt_l,r'(%s)' % "|".join(args))
|
|
||||||
return re_l
|
|
||||||
def disp(self, s):
|
|
||||||
'color output'
|
|
||||||
@@ -886,11 +890,6 @@ class Report(Singleton):
|
|
||||||
self.error("no logs found")
|
|
||||||
return
|
|
||||||
self.display_logs(self.logobj.get_matches(re_l, log_l))
|
|
||||||
- def match_args(self, cib_l, args):
|
|
||||||
- for a in args:
|
|
||||||
- a_clone = re.sub(r':.*', '', a)
|
|
||||||
- if not (a in cib_l) and not (a_clone in cib_l):
|
|
||||||
- self.warn("%s not found in report, proceeding anyway" % a)
|
|
||||||
def get_desc_line(self,fld):
|
|
||||||
try:
|
|
||||||
f = open(self.desc)
|
|
||||||
@@ -923,8 +922,9 @@ class Report(Singleton):
|
|
||||||
'''
|
|
||||||
Show all events.
|
|
||||||
'''
|
|
||||||
- all_re_l = self.build_re("resource",self.cibrsc_l) + \
|
|
||||||
- self.build_re("node",self.cibnode_l)
|
|
||||||
+ all_re_l = self.build_re("resource", self.cibrsc_l) + \
|
|
||||||
+ self.build_re("node", self.cibnode_l) + \
|
|
||||||
+ self.build_re("events", [])
|
|
||||||
if not all_re_l:
|
|
||||||
self.error("no resources or nodes found")
|
|
||||||
return False
|
|
||||||
@@ -940,6 +940,7 @@ class Report(Singleton):
|
|
||||||
te_invoke_patt = transition_patt[0].replace("%%", pe_num)
|
|
||||||
run_patt = transition_patt[1].replace("%%", pe_num)
|
|
||||||
r = None
|
|
||||||
+ msg_l.reverse()
|
|
||||||
for msg in msg_l:
|
|
||||||
r = re.search(te_invoke_patt, msg)
|
|
||||||
if r:
|
|
||||||
@@ -1009,7 +1010,6 @@ class Report(Singleton):
|
|
||||||
expanded_l += self.cibgrp_d[a]
|
|
||||||
else:
|
|
||||||
expanded_l.append(a)
|
|
||||||
- self.match_args(self.cibrsc_l,expanded_l)
|
|
||||||
rsc_re_l = self.build_re("resource",expanded_l)
|
|
||||||
if not rsc_re_l:
|
|
||||||
return False
|
|
||||||
@@ -1020,7 +1020,6 @@ class Report(Singleton):
|
|
||||||
'''
|
|
||||||
if not self.prepare_source():
|
|
||||||
return False
|
|
||||||
- self.match_args(self.cibnode_l,args)
|
|
||||||
node_re_l = self.build_re("node",args)
|
|
||||||
if not node_re_l:
|
|
||||||
return False
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1877,16 +1877,16 @@ Examine Pacemaker's history: node and re
|
|
||||||
def _get_pe_byidx(self, idx):
|
|
||||||
l = crm_report.pelist()
|
|
||||||
if len(l) < abs(idx):
|
|
||||||
- common_err("pe input file for index %d not found" % (idx+1))
|
|
||||||
+ common_err("PE input file for index %d not found" % (idx+1))
|
|
||||||
return None
|
|
||||||
return l[idx]
|
|
||||||
def _get_pe_bynum(self, n):
|
|
||||||
l = crm_report.pelist([n])
|
|
||||||
if len(l) == 0:
|
|
||||||
- common_err("%s: PE file %d not found" % n)
|
|
||||||
+ common_err("PE file %d not found" % n)
|
|
||||||
return None
|
|
||||||
elif len(l) > 1:
|
|
||||||
- common_err("%s: PE file %d ambiguous" % n)
|
|
||||||
+ common_err("PE file %d ambiguous" % n)
|
|
||||||
return None
|
|
||||||
return l[0]
|
|
||||||
def transition(self,cmd,*args):
|
|
@ -1,20 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1312579593 -7200
|
|
||||||
# Node ID d0359dca5dba3fd6fee856d51cca5ee7ac752ee6
|
|
||||||
# Parent a7acb683b3568ca81d90472f770b0270270d5dfd
|
|
||||||
Low: Shell: relax host key checking in pssh
|
|
||||||
|
|
||||||
diff -r a7acb683b356 -r d0359dca5dba shell/modules/crm_pssh.py
|
|
||||||
--- a/shell/modules/crm_pssh.py Fri Aug 05 23:13:37 2011 +0200
|
|
||||||
+++ b/shell/modules/crm_pssh.py Fri Aug 05 23:26:33 2011 +0200
|
|
||||||
@@ -84,7 +84,8 @@ def do_pssh(l, opts):
|
|
||||||
hosts = []
|
|
||||||
for host, cmdline in l:
|
|
||||||
cmd = ['ssh', host, '-o', 'PasswordAuthentication=no',
|
|
||||||
- '-o', 'SendEnv=PSSH_NODENUM']
|
|
||||||
+ '-o', 'SendEnv=PSSH_NODENUM',
|
|
||||||
+ '-o', 'StrictHostKeyChecking=no']
|
|
||||||
if opts.options:
|
|
||||||
for opt in opts.options:
|
|
||||||
cmd += ['-o', opt]
|
|
@ -1,19 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1312580731 -7200
|
|
||||||
# Node ID 29fd4f04c01f92e54026d9d6bb54d617d8b1fdcd
|
|
||||||
# Parent d0359dca5dba3fd6fee856d51cca5ee7ac752ee6
|
|
||||||
Low: Shell: enforce remote report directory removal for history
|
|
||||||
|
|
||||||
diff -r d0359dca5dba -r 29fd4f04c01f shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py Fri Aug 05 23:26:33 2011 +0200
|
|
||||||
+++ b/shell/modules/report.py Fri Aug 05 23:45:31 2011 +0200
|
|
||||||
@@ -595,7 +595,7 @@ class Report(Singleton):
|
|
||||||
if ext_cmd_nosudo("mkdir -p %s" % os.path.dirname(d)) != 0:
|
|
||||||
return None
|
|
||||||
common_info("retrieving information from cluster nodes, please wait ...")
|
|
||||||
- rc = ext_cmd_nosudo("hb_report -f '%s' %s %s %s" %
|
|
||||||
+ rc = ext_cmd_nosudo("hb_report -Z -f '%s' %s %s %s" %
|
|
||||||
(self.from_dt.ctime(), to_option, nodes_option, d))
|
|
||||||
if rc != 0:
|
|
||||||
if os.path.isfile(tarball):
|
|
@ -1,558 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1312993121 -7200
|
|
||||||
# Node ID b3a014c0f85b2bbe1e6a2360c44fbbfc7ac27b73
|
|
||||||
# Parent a09974a06cdf6a3d73c3cdfa6e4d89d41e2ca9f0
|
|
||||||
Medium: Shell: improve peinputs and transition interface (bnc#710655,711060)
|
|
||||||
|
|
||||||
- allow specifying PE files as relative paths in order to
|
|
||||||
disambiguate between PE inputs with the same number
|
|
||||||
- remove peinputs "get" and "list" subcommands, just use 'v' for the
|
|
||||||
long listing
|
|
||||||
- remove transition "show" subcommand, if there is no subcommand
|
|
||||||
it is assumed that the user wants to do "show"
|
|
||||||
- detect (and ignore) empty transitions
|
|
||||||
- update completion tables
|
|
||||||
|
|
||||||
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt
|
|
||||||
+++ b/doc/crm.8.txt
|
|
||||||
@@ -2560,55 +2560,62 @@ Example:
|
|
||||||
|
|
||||||
Every event in the cluster results in generating one or more
|
|
||||||
Policy Engine (PE) files. These files describe future motions of
|
|
||||||
-resources. The files are listed along with the node where they
|
|
||||||
-were created (the DC at the time). The `get` subcommand will copy
|
|
||||||
-all PE input files to the current working directory (and use ssh
|
|
||||||
-if necessary).
|
|
||||||
+resources. The files are listed as full paths in the current
|
|
||||||
+report directory. Add `v` to also see the creation time stamps.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
- peinputs list [{<range>|<number>} ...]
|
|
||||||
- peinputs get [{<range>|<number>} ...]
|
|
||||||
+ peinputs [{<range>|<number>} ...] [v]
|
|
||||||
|
|
||||||
range :: <n1>:<n2>
|
|
||||||
...............
|
|
||||||
Example:
|
|
||||||
...............
|
|
||||||
- peinputs get 440:444 446
|
|
||||||
+ peinputs
|
|
||||||
+ peinputs 440:444 446
|
|
||||||
+ peinputs v
|
|
||||||
...............
|
|
||||||
|
|
||||||
[[cmdhelp_history_transition,show transition]]
|
|
||||||
==== `transition`
|
|
||||||
|
|
||||||
-The `show` subcommand will print actions planned by the PE and
|
|
||||||
-run graphviz (`dotty`) to display a graphical representation. Of
|
|
||||||
-course, for the latter an X11 session is required. This command
|
|
||||||
-invokes `ptest(8)` in background.
|
|
||||||
+This command will print actions planned by the PE and run
|
|
||||||
+graphviz (`dotty`) to display a graphical representation of the
|
|
||||||
+transition. Of course, for the latter an X11 session is required.
|
|
||||||
+This command invokes `ptest(8)` in background.
|
|
||||||
|
|
||||||
The `showdot` subcommand runs graphviz (`dotty`) to display a
|
|
||||||
graphical representation of the `.dot` file which has been
|
|
||||||
included in the report. Essentially, it shows the calculation
|
|
||||||
produced by `pengine` which is installed on the node where the
|
|
||||||
-report was produced.
|
|
||||||
+report was produced. In optimal case this output should not
|
|
||||||
+differ from the one produced by the locally installed `pengine`.
|
|
||||||
|
|
||||||
If the PE input file number is not provided, it defaults to the
|
|
||||||
last one, i.e. the last transition. If the number is negative,
|
|
||||||
then the corresponding transition relative to the last one is
|
|
||||||
chosen.
|
|
||||||
|
|
||||||
+If there are warning and error PE input files or different nodes
|
|
||||||
+were the DC in the observed timeframe, it may happen that PE
|
|
||||||
+input file numbers collide. In that case provide some unique part
|
|
||||||
+of the path to the file.
|
|
||||||
+
|
|
||||||
After the `ptest` output, logs about events that happened during
|
|
||||||
the transition are printed.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
- transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
- transition showdot [<number>]
|
|
||||||
+ transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
+ transition showdot [<number>|<file>]
|
|
||||||
...............
|
|
||||||
Examples:
|
|
||||||
...............
|
|
||||||
- transition show
|
|
||||||
- transition show 444
|
|
||||||
- transition show -1
|
|
||||||
+ transition
|
|
||||||
+ transition 444
|
|
||||||
+ transition -1
|
|
||||||
+ transition pe-error-3.bz2
|
|
||||||
+ transition node-a/pengine/pe-input-2.bz2
|
|
||||||
transition showdot 444
|
|
||||||
...............
|
|
||||||
|
|
||||||
diff --git a/shell/modules/completion.py b/shell/modules/completion.py
|
|
||||||
--- a/shell/modules/completion.py
|
|
||||||
+++ b/shell/modules/completion.py
|
|
||||||
@@ -165,14 +165,14 @@ def report_node_list(idx,delimiter = Fal
|
|
||||||
if delimiter:
|
|
||||||
return ' '
|
|
||||||
return crm_report.node_list()
|
|
||||||
-def report_pe_cmd_list(idx,delimiter = False):
|
|
||||||
+def report_pe_list_transition(idx,delimiter = False):
|
|
||||||
if delimiter:
|
|
||||||
return ' '
|
|
||||||
- return ["list","get","show","showdot"]
|
|
||||||
-def report_pe_list(idx,delimiter = False):
|
|
||||||
+ return crm_report.peinputs_list() + ["showdot"]
|
|
||||||
+def report_pe_list_peinputs(idx,delimiter = False):
|
|
||||||
if delimiter:
|
|
||||||
return ' '
|
|
||||||
- return crm_report.peinputs_list()
|
|
||||||
+ return crm_report.peinputs_list() + ["v"]
|
|
||||||
|
|
||||||
#
|
|
||||||
# completion for primitives including help for parameters
|
|
||||||
@@ -484,7 +484,8 @@ completer_lists = {
|
|
||||||
"resource" : (report_rsc_list,loop),
|
|
||||||
"node" : (report_node_list,loop),
|
|
||||||
"log" : (report_node_list,loop),
|
|
||||||
- "peinputs" : (report_pe_cmd_list,report_pe_list,loop),
|
|
||||||
+ "peinputs" : (report_pe_list_peinputs,loop),
|
|
||||||
+ "transition" : (report_pe_list_transition,),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
def get_completer_list(level,cmd):
|
|
||||||
diff --git a/shell/modules/crm_pssh.py b/shell/modules/crm_pssh.py
|
|
||||||
--- a/shell/modules/crm_pssh.py
|
|
||||||
+++ b/shell/modules/crm_pssh.py
|
|
||||||
@@ -156,6 +156,9 @@ def next_peinputs(node_pe_l, outdir, err
|
|
||||||
myopts = ["-q", "-o", outdir, "-e", errdir]
|
|
||||||
opts, args = parse_args(myopts)
|
|
||||||
l.append([node, cmdline])
|
|
||||||
+ if not l:
|
|
||||||
+ # is this a failure?
|
|
||||||
+ return True
|
|
||||||
return do_pssh(l, opts)
|
|
||||||
|
|
||||||
# vim:ts=4:sw=4:et:
|
|
||||||
diff --git a/shell/modules/log_patterns.py b/shell/modules/log_patterns.py
|
|
||||||
--- a/shell/modules/log_patterns.py
|
|
||||||
+++ b/shell/modules/log_patterns.py
|
|
||||||
@@ -62,8 +62,3 @@ log_patterns = {
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
-
|
|
||||||
-transition_patt = (
|
|
||||||
- "crmd: .* Processing graph.*derived from .*/pe-[^-]+-(%%)[.]bz2", # transition start
|
|
||||||
- "crmd: .* Transition.*Source=.*/pe-[^-]+-(%%)[.]bz2.: (Stopped|Complete|Terminated)", # and stop
|
|
||||||
-)
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -31,7 +31,7 @@ from term import TerminalController
|
|
||||||
from xmlutil import *
|
|
||||||
from utils import *
|
|
||||||
from msg import *
|
|
||||||
-from log_patterns import log_patterns, transition_patt
|
|
||||||
+from log_patterns import log_patterns
|
|
||||||
_NO_PSSH = False
|
|
||||||
try:
|
|
||||||
from crm_pssh import next_loglines, next_peinputs
|
|
||||||
@@ -297,8 +297,8 @@ def human_date(dt):
|
|
||||||
def is_log(p):
|
|
||||||
return os.path.isfile(p) and os.path.getsize(p) > 0
|
|
||||||
|
|
||||||
-def pe_file_in_range(pe_f, a, ext):
|
|
||||||
- r = re.search("pe-[^-]+-([0-9]+)[.]%s$" % ext, pe_f)
|
|
||||||
+def pe_file_in_range(pe_f, a):
|
|
||||||
+ r = re.search("pe-[^-]+-([0-9]+)[.]bz2$", pe_f)
|
|
||||||
if not r:
|
|
||||||
return None
|
|
||||||
if not a or (a[0] <= int(r.group(1)) <= a[1]):
|
|
||||||
@@ -325,6 +325,17 @@ def update_loginfo(rptlog, logfile, oldp
|
|
||||||
except IOError, msg:
|
|
||||||
common_err("couldn't the update %s.info: %s" % (rptlog, msg))
|
|
||||||
|
|
||||||
+# r.group(1) transition number (a different thing from file number)
|
|
||||||
+# r.group(2) contains full path
|
|
||||||
+# r.group(3) file number
|
|
||||||
+transition_patt = (
|
|
||||||
+ "crmd: .* do_te_invoke: Processing graph ([0-9]+) .*derived from (.*/pe-[^-]+-(%%)[.]bz2)", # transition start
|
|
||||||
+ "crmd: .* run_graph: Transition ([0-9]+).*Source=(.*/pe-[^-]+-(%%)[.]bz2).: (Stopped|Complete|Terminated)", # and stop
|
|
||||||
+# r.group(1) transition number
|
|
||||||
+# r.group(2) number of actions
|
|
||||||
+ "crmd: .* unpack_graph: Unpacked transition (%%): ([0-9]+) actions", # number of actions
|
|
||||||
+)
|
|
||||||
+
|
|
||||||
class Report(Singleton):
|
|
||||||
'''
|
|
||||||
A hb_report class.
|
|
||||||
@@ -346,6 +357,7 @@ class Report(Singleton):
|
|
||||||
self.desc = None
|
|
||||||
self.log_l = []
|
|
||||||
self.central_log = None
|
|
||||||
+ self.peinputs_l = []
|
|
||||||
self.cibgrp_d = {}
|
|
||||||
self.cibrsc_l = []
|
|
||||||
self.cibnode_l = []
|
|
||||||
@@ -363,7 +375,7 @@ class Report(Singleton):
|
|
||||||
return self.cibnode_l
|
|
||||||
def peinputs_list(self):
|
|
||||||
return [re.search("pe-[^-]+-([0-9]+)[.]bz2$", x).group(1)
|
|
||||||
- for x in self._file_list("bz2")]
|
|
||||||
+ for x in self.peinputs_l]
|
|
||||||
def unpack_report(self, tarball):
|
|
||||||
'''
|
|
||||||
Unpack hb_report tarball.
|
|
||||||
@@ -495,28 +507,26 @@ class Report(Singleton):
|
|
||||||
continue
|
|
||||||
u_dir = os.path.join(self.loc, node)
|
|
||||||
rc = ext_cmd_nosudo("tar -C %s -x < %s" % (u_dir,fl[0]))
|
|
||||||
- def find_new_peinputs(self, a):
|
|
||||||
+ def find_new_peinputs(self, node_l):
|
|
||||||
'''
|
|
||||||
- Get a list of pe inputs appearing in logs.
|
|
||||||
+ Get a list of pe inputs appearing in new logs.
|
|
||||||
+ The log is put in self.outdir/node by pssh.
|
|
||||||
'''
|
|
||||||
if not os.path.isdir(self.outdir):
|
|
||||||
return []
|
|
||||||
l = []
|
|
||||||
- trans_re_l = [x.replace("%%","") for x in transition_patt]
|
|
||||||
- for node,rptlog,logfile,nextpos in a:
|
|
||||||
- node_l = []
|
|
||||||
+ for node in node_l:
|
|
||||||
fl = glob.glob("%s/*%s*" % (self.outdir,node))
|
|
||||||
if not fl:
|
|
||||||
continue
|
|
||||||
- for s in file2list(fl[0]):
|
|
||||||
- r = re.search(trans_re_l[0], s)
|
|
||||||
- if not r:
|
|
||||||
- continue
|
|
||||||
- node_l.append(r.group(1))
|
|
||||||
- if node_l:
|
|
||||||
- common_debug("found new PE inputs %s at %s" %
|
|
||||||
- ([os.path.basename(x) for x in node_l], node))
|
|
||||||
- l.append([node,node_l])
|
|
||||||
+ try:
|
|
||||||
+ f = open(fl[0])
|
|
||||||
+ except IOError,msg:
|
|
||||||
+ common_err("open %s: %s"%(fl[0],msg))
|
|
||||||
+ continue
|
|
||||||
+ pe_l = self.get_transitions([x for x in f], keep_pe_path = True)
|
|
||||||
+ if pe_l:
|
|
||||||
+ l.append([node,pe_l])
|
|
||||||
return l
|
|
||||||
def update_live(self):
|
|
||||||
'''
|
|
||||||
@@ -544,7 +554,7 @@ class Report(Singleton):
|
|
||||||
rmdir_r(self.errdir)
|
|
||||||
rc1 = next_loglines(a, self.outdir, self.errdir)
|
|
||||||
self.append_newlogs(a)
|
|
||||||
- pe_l = self.find_new_peinputs(a)
|
|
||||||
+ pe_l = self.find_new_peinputs([x[0] for x in a])
|
|
||||||
rmdir_r(self.outdir)
|
|
||||||
rmdir_r(self.errdir)
|
|
||||||
rc2 = True
|
|
||||||
@@ -677,6 +687,55 @@ class Report(Singleton):
|
|
||||||
for n in self.cibnode_l:
|
|
||||||
self.nodecolor[n] = self.nodecolors[i]
|
|
||||||
i = (i+1) % len(self.nodecolors)
|
|
||||||
+ def get_transitions(self, msg_l = None, keep_pe_path = False):
|
|
||||||
+ '''
|
|
||||||
+ Get a list of transitions.
|
|
||||||
+ Empty transitions are skipped.
|
|
||||||
+ We use the unpack_graph message to see the number of
|
|
||||||
+ actions.
|
|
||||||
+ Some callers need original PE file path (keep_pe_path),
|
|
||||||
+ otherwise we produce the path within the report.
|
|
||||||
+ If the caller doesn't provide the message list, then we
|
|
||||||
+ build it from the collected log files (self.logobj).
|
|
||||||
+ Otherwise, we get matches for transition patterns.
|
|
||||||
+ '''
|
|
||||||
+ trans_re_l = [x.replace("%%", "[0-9]+") for x in transition_patt]
|
|
||||||
+ if not msg_l:
|
|
||||||
+ msg_l = self.logobj.get_matches(trans_re_l)
|
|
||||||
+ else:
|
|
||||||
+ re_s = '|'.join(trans_re_l)
|
|
||||||
+ msg_l = [x for x in msg_l if re.search(re_s, x)]
|
|
||||||
+ pe_l = []
|
|
||||||
+ for msg in msg_l:
|
|
||||||
+ msg_a = msg.split()
|
|
||||||
+ if len(msg_a) < 8:
|
|
||||||
+ # this looks too short
|
|
||||||
+ common_warn("log message <%s> unexpected format, please report a bug" % msg)
|
|
||||||
+ continue
|
|
||||||
+ if msg_a[7] in ("unpack_graph:","run_graph:"):
|
|
||||||
+ continue # we want another message
|
|
||||||
+ node = msg_a[3]
|
|
||||||
+ pe_file = msg_a[-1]
|
|
||||||
+ pe_base = os.path.basename(pe_file)
|
|
||||||
+ # check if there were any actions in this transition
|
|
||||||
+ r = re.search(trans_re_l[0], msg)
|
|
||||||
+ trans_num = r.group(1)
|
|
||||||
+ unpack_patt = transition_patt[2].replace("%%", trans_num)
|
|
||||||
+ num_actions = 0
|
|
||||||
+ for t in msg_l:
|
|
||||||
+ try:
|
|
||||||
+ num_actions = int(re.search(unpack_patt, t).group(2))
|
|
||||||
+ break
|
|
||||||
+ except: pass
|
|
||||||
+ if num_actions == 0: # empty transition
|
|
||||||
+ common_debug("skipping empty transition %s (%s)" % (trans_num, pe_base))
|
|
||||||
+ continue
|
|
||||||
+ common_debug("found PE input at %s: %s" % (node, pe_file))
|
|
||||||
+ if keep_pe_path:
|
|
||||||
+ pe_l.append(pe_file)
|
|
||||||
+ else:
|
|
||||||
+ pe_l.append(os.path.join(self.loc, node, "pengine", pe_base))
|
|
||||||
+ return pe_l
|
|
||||||
def report_setup(self):
|
|
||||||
if not self.loc:
|
|
||||||
return
|
|
||||||
@@ -687,6 +746,11 @@ class Report(Singleton):
|
|
||||||
self.set_node_colors()
|
|
||||||
self.logobj = LogSyslog(self.central_log, self.log_l, \
|
|
||||||
self.from_dt, self.to_dt)
|
|
||||||
+ self.peinputs_l = self.get_transitions()
|
|
||||||
+ for pe_input in self.peinputs_l:
|
|
||||||
+ if not os.path.isfile(pe_input):
|
|
||||||
+ warn_once("%s in the logs, but not in the report" % pe_input)
|
|
||||||
+ self.peinputs_l.remove(pe_input)
|
|
||||||
def prepare_source(self):
|
|
||||||
'''
|
|
||||||
Unpack a hb_report tarball.
|
|
||||||
@@ -821,16 +885,16 @@ class Report(Singleton):
|
|
||||||
Search for events within the given transition.
|
|
||||||
'''
|
|
||||||
pe_base = os.path.basename(pe_file)
|
|
||||||
- r = re.search("pe-[^-]+-([0-9]+)[.]bz2", pe_base)
|
|
||||||
+ r = re.search("pe-[^-]+-([0-9]+)[.]", pe_base)
|
|
||||||
pe_num = r.group(1)
|
|
||||||
trans_re_l = [x.replace("%%",pe_num) for x in transition_patt]
|
|
||||||
trans_start = self.logobj.search_logs(self.log_l, trans_re_l[0])
|
|
||||||
trans_end = self.logobj.search_logs(self.log_l, trans_re_l[1])
|
|
||||||
if not trans_start:
|
|
||||||
- common_warn("transition %s start not found in logs" % pe_base)
|
|
||||||
+ common_warn("start of transition %s not found in logs" % pe_base)
|
|
||||||
return False
|
|
||||||
if not trans_end:
|
|
||||||
- common_warn("transition %s end not found in logs" % pe_base)
|
|
||||||
+ common_warn("end of transition %s not found in logs (transition not complete yet?)" % pe_base)
|
|
||||||
return False
|
|
||||||
common_debug("transition start: %s" % trans_start[0])
|
|
||||||
common_debug("transition end: %s" % trans_end[0])
|
|
||||||
@@ -891,23 +955,23 @@ class Report(Singleton):
|
|
||||||
if not l:
|
|
||||||
return False
|
|
||||||
self.show_logs(log_l = l)
|
|
||||||
- def _file_list(self, ext, a = []):
|
|
||||||
- '''
|
|
||||||
- Return list of PE (or dot) files (abs paths) sorted by
|
|
||||||
- mtime.
|
|
||||||
- Input is a number or a pair of numbers representing
|
|
||||||
- range. Otherwise, all matching files are returned.
|
|
||||||
- '''
|
|
||||||
+ def pelist(self, a = []):
|
|
||||||
if not self.prepare_source():
|
|
||||||
return []
|
|
||||||
- if not isinstance(a,(tuple,list)) and a is not None:
|
|
||||||
+ if isinstance(a,(tuple,list)):
|
|
||||||
+ if len(a) == 1:
|
|
||||||
+ a.append(a[0])
|
|
||||||
+ elif a is not None:
|
|
||||||
a = [a,a]
|
|
||||||
- return sort_by_mtime([x for x in dirwalk(self.loc) \
|
|
||||||
- if pe_file_in_range(x,a,ext)])
|
|
||||||
- def pelist(self, a = []):
|
|
||||||
- return self._file_list("bz2", a)
|
|
||||||
+ return [x for x in self.peinputs_l \
|
|
||||||
+ if pe_file_in_range(x, a)]
|
|
||||||
def dotlist(self, a = []):
|
|
||||||
- return self._file_list("dot", a)
|
|
||||||
+ l = [x.replace("bz2","dot") for x in self.pelist(a)]
|
|
||||||
+ return [x for x in l if os.path.isfile(x)]
|
|
||||||
+ def find_pe_files(self, path):
|
|
||||||
+ 'Find a PE or dot file matching part of the path.'
|
|
||||||
+ pe_l = path.endswith(".dot") and self.dotlist() or self.pelist()
|
|
||||||
+ return [x for x in pe_l if x.endswith(path)]
|
|
||||||
def find_file(self, f):
|
|
||||||
return file_find_by_name(self.loc, f)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1686,8 +1686,8 @@ Examine Pacemaker's history: node and re
|
|
||||||
self.cmd_table["resource"] = (self.resource,(1,),1,0)
|
|
||||||
self.cmd_table["node"] = (self.node,(1,),1,1)
|
|
||||||
self.cmd_table["log"] = (self.log,(0,),1,0)
|
|
||||||
- self.cmd_table["peinputs"] = (self.peinputs,(1,),1,0)
|
|
||||||
- self.cmd_table["transition"] = (self.transition,(1,),1,0)
|
|
||||||
+ self.cmd_table["peinputs"] = (self.peinputs,(0,),1,0)
|
|
||||||
+ self.cmd_table["transition"] = (self.transition,(0,),1,0)
|
|
||||||
self._set_source(options.history)
|
|
||||||
def _no_source(self):
|
|
||||||
common_error("we have no source set yet! please use the source command")
|
|
||||||
@@ -1831,64 +1831,83 @@ Examine Pacemaker's history: node and re
|
|
||||||
s = bz2.decompress(''.join(f))
|
|
||||||
f.close()
|
|
||||||
return run_ptest(s, nograph, scores, utilization, actions, verbosity)
|
|
||||||
- def peinputs(self,cmd,subcmd,*args):
|
|
||||||
- """usage: peinputs list [{<range>|<number>} ...]
|
|
||||||
- peinputs get [{<range>|<number>} ...]"""
|
|
||||||
- if subcmd not in ("get","list"):
|
|
||||||
- bad_usage(cmd,subcmd)
|
|
||||||
- return False
|
|
||||||
- if args:
|
|
||||||
+ def peinputs(self,cmd,*args):
|
|
||||||
+ """usage: peinputs [{<range>|<number>} ...] [v]"""
|
|
||||||
+ argl = list(args)
|
|
||||||
+ long = "v" in argl
|
|
||||||
+ if long:
|
|
||||||
+ argl.remove("v")
|
|
||||||
+ if argl:
|
|
||||||
l = []
|
|
||||||
- for s in args:
|
|
||||||
+ for s in argl:
|
|
||||||
a = convert2ints(s.split(':'))
|
|
||||||
- if len(a) == 2 and not check_range(a):
|
|
||||||
+ if a and len(a) == 2 and not check_range(a):
|
|
||||||
common_err("%s: invalid peinputs range" % a)
|
|
||||||
return False
|
|
||||||
l += crm_report.pelist(a)
|
|
||||||
else:
|
|
||||||
l = crm_report.pelist()
|
|
||||||
if not l: return False
|
|
||||||
- if subcmd == "list":
|
|
||||||
- s = get_stdout("ls -lrt %s" % ' '.join(l))
|
|
||||||
- page_string(s)
|
|
||||||
+ if long:
|
|
||||||
+ s = get_stdout("for f in %s; do ls -l $f; done" % ' '.join(l))
|
|
||||||
else:
|
|
||||||
- print '\n'.join(l)
|
|
||||||
- def transition(self,cmd,subcmd,*args):
|
|
||||||
- """usage: transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
- transition showdot [<number>]"""
|
|
||||||
- if subcmd not in ("show", "showdot"):
|
|
||||||
- bad_usage(cmd,subcmd)
|
|
||||||
- return False
|
|
||||||
- try: n = convert2ints(args[0])
|
|
||||||
- except: n = None
|
|
||||||
- startarg = 1
|
|
||||||
- if n is None:
|
|
||||||
- idx = -1
|
|
||||||
- startarg = 0 # peinput number missing
|
|
||||||
- elif n <= 0:
|
|
||||||
- idx = n - 1
|
|
||||||
- n = [] # to get all peinputs
|
|
||||||
- else:
|
|
||||||
- idx = 0
|
|
||||||
- if subcmd == "showdot":
|
|
||||||
+ s = '\n'.join(l)
|
|
||||||
+ page_string(s)
|
|
||||||
+ def transition(self,cmd,*args):
|
|
||||||
+ """usage: transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
+ transition showdot [<number>|<file>]"""
|
|
||||||
+ argl = list(args)
|
|
||||||
+ subcmd = "show"
|
|
||||||
+ if argl and argl[0] == "showdot":
|
|
||||||
if not user_prefs.dotty:
|
|
||||||
common_err("install graphviz to draw transition graphs")
|
|
||||||
return False
|
|
||||||
- l = crm_report.dotlist(n)
|
|
||||||
+ subcmd = "showdot"
|
|
||||||
+ argl.remove(subcmd)
|
|
||||||
+ f = None
|
|
||||||
+ startarg = 1
|
|
||||||
+ if argl and re.search('pe-', argl[0]):
|
|
||||||
+ l = crm_report.find_pe_files(argl[0])
|
|
||||||
+ if len(l) == 0:
|
|
||||||
+ common_err("%s: path not found" % argl[0])
|
|
||||||
+ return False
|
|
||||||
+ elif len(l) > 1:
|
|
||||||
+ common_err("%s: path ambiguous" % argl[0])
|
|
||||||
+ return False
|
|
||||||
+ f = l[0]
|
|
||||||
else:
|
|
||||||
- l = crm_report.pelist(n)
|
|
||||||
- if len(l) < abs(idx):
|
|
||||||
- common_err("pe input or dot file not found")
|
|
||||||
+ try: n = convert2ints(argl[0])
|
|
||||||
+ except: n = None
|
|
||||||
+ if n is None:
|
|
||||||
+ idx = -1
|
|
||||||
+ startarg = 0 # peinput number missing
|
|
||||||
+ elif n <= 0:
|
|
||||||
+ idx = n - 1
|
|
||||||
+ n = [] # to get all peinputs
|
|
||||||
+ else:
|
|
||||||
+ idx = 0
|
|
||||||
+ if subcmd == "showdot":
|
|
||||||
+ l = crm_report.dotlist(n)
|
|
||||||
+ else:
|
|
||||||
+ l = crm_report.pelist(n)
|
|
||||||
+ if len(l) < abs(idx):
|
|
||||||
+ if subcmd == "show":
|
|
||||||
+ common_err("pe input file not found")
|
|
||||||
+ else:
|
|
||||||
+ common_err("dot file not found")
|
|
||||||
+ return False
|
|
||||||
+ f = l[idx]
|
|
||||||
+ if not f:
|
|
||||||
return False
|
|
||||||
rc = True
|
|
||||||
if subcmd == "show":
|
|
||||||
- self.pe_file = l[idx]
|
|
||||||
+ self.pe_file = f # self.pe_file needed by self.ptest
|
|
||||||
rc = ptestlike(self.ptest,'vv',"%s %s" % \
|
|
||||||
- (cmd, subcmd), *args[startarg:])
|
|
||||||
- if rc:
|
|
||||||
- crm_report.show_transition_log(self.pe_file)
|
|
||||||
+ (cmd, subcmd), *argl[startarg:])
|
|
||||||
else:
|
|
||||||
- show_dot_graph(l[idx])
|
|
||||||
+ show_dot_graph(f.replace("bz2","dot"))
|
|
||||||
+ if rc:
|
|
||||||
+ crm_report.show_transition_log(f)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
class TopLevel(UserInterface):
|
|
||||||
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
||||||
--- a/shell/modules/utils.py
|
|
||||||
+++ b/shell/modules/utils.py
|
|
||||||
@@ -392,7 +392,7 @@ def run_ptest(graph_s, nograph, scores,
|
|
||||||
Pipe graph_s thru ptest(8). Show graph using dotty if requested.
|
|
||||||
'''
|
|
||||||
actions_filter = "grep LogActions: | grep -vw Leave"
|
|
||||||
- ptest = "ptest -X"
|
|
||||||
+ ptest = "2>&1 ptest -X"
|
|
||||||
if verbosity:
|
|
||||||
if actions:
|
|
||||||
verbosity = 'v' * max(3,len(verbosity))
|
|
||||||
@@ -408,7 +408,8 @@ def run_ptest(graph_s, nograph, scores,
|
|
||||||
dotfile = None
|
|
||||||
# ptest prints to stderr
|
|
||||||
if actions:
|
|
||||||
- ptest = "%s 2>&1 | %s" % (ptest, actions_filter)
|
|
||||||
+ ptest = "%s | %s" % (ptest, actions_filter)
|
|
||||||
+ common_debug("invoke: %s" % ptest)
|
|
||||||
print get_stdout(ptest, input_s = graph_s)
|
|
||||||
#page_string(get_stdout(ptest, input_s = graph_s))
|
|
||||||
if dotfile:
|
|
||||||
@@ -443,7 +444,7 @@ def check_range(a):
|
|
||||||
return False
|
|
||||||
if not isinstance(a[0],int) or not isinstance(a[1],int):
|
|
||||||
return False
|
|
||||||
- return (int(a[0]) < int(a[1]))
|
|
||||||
+ return (int(a[0]) <= int(a[1]))
|
|
||||||
|
|
||||||
def sort_by_mtime(l):
|
|
||||||
'Sort a (small) list of files by time mod.'
|
|
@ -1,23 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1312838871 -7200
|
|
||||||
# Node ID a09974a06cdf6a3d73c3cdfa6e4d89d41e2ca9f0
|
|
||||||
# Parent 29fd4f04c01f92e54026d9d6bb54d617d8b1fdcd
|
|
||||||
Low: Shell: avoid DeprecationWarning for BaseException.message
|
|
||||||
|
|
||||||
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
||||||
--- a/shell/modules/utils.py
|
|
||||||
+++ b/shell/modules/utils.py
|
|
||||||
@@ -257,9 +257,9 @@ def acquire_lock(dir):
|
|
||||||
os.mkdir(os.path.join(dir,_LOCKDIR))
|
|
||||||
str2file("%d" % os.getpid(),os.path.join(dir,_LOCKDIR,_PIDF))
|
|
||||||
return True
|
|
||||||
- except OSError, e:
|
|
||||||
- if e.errno != os.errno.EEXIST:
|
|
||||||
- common_err("%s" % e.message)
|
|
||||||
+ except OSError as (errno, strerror):
|
|
||||||
+ if errno != os.errno.EEXIST:
|
|
||||||
+ common_err(strerror)
|
|
||||||
return False
|
|
||||||
time.sleep(0.1)
|
|
||||||
continue
|
|
@ -1,90 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313019300 -7200
|
|
||||||
# Node ID c3068d22de72d1ba616d43c808091bef830eb9f6
|
|
||||||
# Parent b3a014c0f85b2bbe1e6a2360c44fbbfc7ac27b73
|
|
||||||
Medium: Shell: improve capture log slices for transitions (bnc#710907)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -65,7 +65,25 @@ def syslog_ts(s):
|
|
||||||
common_warn("malformed line: %s" % s)
|
|
||||||
return None
|
|
||||||
|
|
||||||
-def log_seek(f, ts, endpos = False):
|
|
||||||
+def seek_to_edge(f, ts, to_end):
|
|
||||||
+ '''
|
|
||||||
+ f contains lines with exactly the timestamp ts.
|
|
||||||
+ Read forward (or backward) till we find the edge.
|
|
||||||
+ Linear search, but should be short.
|
|
||||||
+ '''
|
|
||||||
+ if not to_end:
|
|
||||||
+ while ts == get_timestamp(f):
|
|
||||||
+ f.seek(-1000, 1) # go back 10 or so lines
|
|
||||||
+ while True:
|
|
||||||
+ pos = f.tell()
|
|
||||||
+ s = f.readline()
|
|
||||||
+ curr_ts = syslog_ts(s)
|
|
||||||
+ if (to_end and curr_ts > ts) or \
|
|
||||||
+ (not to_end and curr_ts >= ts):
|
|
||||||
+ break
|
|
||||||
+ f.seek(pos)
|
|
||||||
+
|
|
||||||
+def log_seek(f, ts, to_end = False):
|
|
||||||
'''
|
|
||||||
f is an open log. Do binary search for the timestamp.
|
|
||||||
Return the position of the (more or less) first line with a
|
|
||||||
@@ -75,10 +93,11 @@ def log_seek(f, ts, endpos = False):
|
|
||||||
f.seek(0,2)
|
|
||||||
last = f.tell()
|
|
||||||
if not ts:
|
|
||||||
- return endpos and last or first
|
|
||||||
+ return to_end and last or first
|
|
||||||
badline = 0
|
|
||||||
maxbadline = 10
|
|
||||||
- common_debug("seek ts %s" % time.ctime(ts))
|
|
||||||
+ common_debug("seek %s:%s in %s" %
|
|
||||||
+ (time.ctime(ts), to_end and "end" or "start", f.name))
|
|
||||||
while first <= last:
|
|
||||||
# we can skip some iterations if it's about few lines
|
|
||||||
if abs(first-last) < 120:
|
|
||||||
@@ -98,9 +117,12 @@ def log_seek(f, ts, endpos = False):
|
|
||||||
elif log_ts < ts:
|
|
||||||
first = mid+1
|
|
||||||
else:
|
|
||||||
+ seek_to_edge(f, log_ts, to_end)
|
|
||||||
break
|
|
||||||
- common_debug("sought to %s" % time.ctime(log_ts))
|
|
||||||
- return f.tell()
|
|
||||||
+ fpos = f.tell()
|
|
||||||
+ common_debug("sought to %s (%d)" % (f.readline(), fpos))
|
|
||||||
+ f.seek(fpos)
|
|
||||||
+ return fpos
|
|
||||||
|
|
||||||
def get_timestamp(f):
|
|
||||||
'''
|
|
||||||
@@ -187,7 +209,7 @@ class LogSyslog(object):
|
|
||||||
for log in self.f:
|
|
||||||
f = self.f[log]
|
|
||||||
start = log_seek(f, self.from_ts)
|
|
||||||
- end = log_seek(f, self.to_ts, endpos = True)
|
|
||||||
+ end = log_seek(f, self.to_ts, to_end = True)
|
|
||||||
if start == -1 or end == -1:
|
|
||||||
bad_logs.append(log)
|
|
||||||
else:
|
|
||||||
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
||||||
--- a/shell/modules/utils.py
|
|
||||||
+++ b/shell/modules/utils.py
|
|
||||||
@@ -413,7 +413,10 @@ def run_ptest(graph_s, nograph, scores,
|
|
||||||
print get_stdout(ptest, input_s = graph_s)
|
|
||||||
#page_string(get_stdout(ptest, input_s = graph_s))
|
|
||||||
if dotfile:
|
|
||||||
- show_dot_graph(dotfile)
|
|
||||||
+ if os.path.getsize(dotfile) > 0:
|
|
||||||
+ show_dot_graph(dotfile)
|
|
||||||
+ else:
|
|
||||||
+ common_warn("ptest produced empty dot file")
|
|
||||||
vars.tmpfiles.append(dotfile)
|
|
||||||
else:
|
|
||||||
if not nograph:
|
|
@ -1,245 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313081065 -7200
|
|
||||||
# Node ID 441f4448eba6eda1a2cf44d3d63a0db9f8d56a20
|
|
||||||
# Parent c3068d22de72d1ba616d43c808091bef830eb9f6
|
|
||||||
Medium: Shell: reimplement the history latest command (bnc#710958)
|
|
||||||
|
|
||||||
This command is going to show logs for the latest transition.
|
|
||||||
Basically, it's the same as "history transition", but it will
|
|
||||||
wait for the current (if any) transition to finish.
|
|
||||||
|
|
||||||
(Also, the horrible transition command arg parsing has been
|
|
||||||
improved.)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -467,8 +467,7 @@ class Report(Singleton):
|
|
||||||
def is_last_live_recent(self):
|
|
||||||
'''
|
|
||||||
Look at the last live hb_report. If it's recent enough,
|
|
||||||
- return True. Return True also if self.to_dt is not empty
|
|
||||||
- (not an open end report).
|
|
||||||
+ return True.
|
|
||||||
'''
|
|
||||||
try:
|
|
||||||
last_ts = os.stat(self.desc).st_mtime
|
|
||||||
@@ -800,6 +799,7 @@ class Report(Singleton):
|
|
||||||
if self.source != "live":
|
|
||||||
self.error("refresh not supported")
|
|
||||||
return False
|
|
||||||
+ self.last_live_update = 0
|
|
||||||
self.loc = self.manage_live_report(force)
|
|
||||||
self.report_setup()
|
|
||||||
self.ready = self.check_report()
|
|
||||||
@@ -884,18 +884,10 @@ class Report(Singleton):
|
|
||||||
print "Nodes:",' '.join(self.cibnode_l)
|
|
||||||
print "Groups:",' '.join(self.cibgrp_d.keys())
|
|
||||||
print "Resources:",' '.join(self.cibrsc_l)
|
|
||||||
- def latest(self):
|
|
||||||
- '''
|
|
||||||
- Get the very latest cluster events, basically from the
|
|
||||||
- latest transition.
|
|
||||||
- Some transitions may be empty though.
|
|
||||||
- '''
|
|
||||||
def events(self):
|
|
||||||
'''
|
|
||||||
Show all events.
|
|
||||||
'''
|
|
||||||
- if not self.prepare_source():
|
|
||||||
- return False
|
|
||||||
all_re_l = self.build_re("resource",self.cibrsc_l) + \
|
|
||||||
self.build_re("node",self.cibnode_l)
|
|
||||||
if not all_re_l:
|
|
||||||
@@ -906,6 +898,8 @@ class Report(Singleton):
|
|
||||||
'''
|
|
||||||
Search for events within the given transition.
|
|
||||||
'''
|
|
||||||
+ if not self.prepare_source():
|
|
||||||
+ return False
|
|
||||||
pe_base = os.path.basename(pe_file)
|
|
||||||
r = re.search("pe-[^-]+-([0-9]+)[.]", pe_base)
|
|
||||||
pe_num = r.group(1)
|
|
||||||
@@ -926,6 +920,9 @@ class Report(Singleton):
|
|
||||||
self.warn("strange, no timestamps found")
|
|
||||||
return False
|
|
||||||
# limit the log scope temporarily
|
|
||||||
+ common_info("logs for transition %s (%s-%s)" %
|
|
||||||
+ (pe_file.replace(self.loc+"/",""), \
|
|
||||||
+ shorttime(start_ts), shorttime(end_ts)))
|
|
||||||
self.logobj.set_log_timeframe(start_ts, end_ts)
|
|
||||||
self.events()
|
|
||||||
self.logobj.set_log_timeframe(self.from_dt, self.to_dt)
|
|
||||||
@@ -994,6 +991,11 @@ class Report(Singleton):
|
|
||||||
'Find a PE or dot file matching part of the path.'
|
|
||||||
pe_l = path.endswith(".dot") and self.dotlist() or self.pelist()
|
|
||||||
return [x for x in pe_l if x.endswith(path)]
|
|
||||||
+ def pe2dot(self, f):
|
|
||||||
+ f = f.replace("bz2","dot")
|
|
||||||
+ if os.path.isfile(f):
|
|
||||||
+ return f
|
|
||||||
+ return None
|
|
||||||
def find_file(self, f):
|
|
||||||
return file_find_by_name(self.loc, f)
|
|
||||||
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1796,22 +1796,15 @@ Examine Pacemaker's history: node and re
|
|
||||||
return crm_report.info()
|
|
||||||
def latest(self,cmd):
|
|
||||||
"usage: latest"
|
|
||||||
- try:
|
|
||||||
- prev_level = levels.previous().myname()
|
|
||||||
- except:
|
|
||||||
- prev_level = ''
|
|
||||||
- if prev_level != "cibconfig":
|
|
||||||
- common_err("%s is available only when invoked from configure" % cmd)
|
|
||||||
- return False
|
|
||||||
- ts = cib_factory.last_commit_at()
|
|
||||||
- if not ts:
|
|
||||||
- common_err("no last commit time found")
|
|
||||||
- return False
|
|
||||||
if not wait4dc("transition", not options.batch):
|
|
||||||
return False
|
|
||||||
- self._set_source("live", ts)
|
|
||||||
+ self._set_source("live")
|
|
||||||
crm_report.refresh_source()
|
|
||||||
- return crm_report.events()
|
|
||||||
+ f = self._get_pe_byidx(-1)
|
|
||||||
+ if not f:
|
|
||||||
+ common_err("no transitions found")
|
|
||||||
+ return False
|
|
||||||
+ crm_report.show_transition_log(f)
|
|
||||||
def resource(self,cmd,*args):
|
|
||||||
"usage: resource <rsc> [<rsc> ...]"
|
|
||||||
return crm_report.resource(*args)
|
|
||||||
@@ -1853,6 +1846,30 @@ Examine Pacemaker's history: node and re
|
|
||||||
else:
|
|
||||||
s = '\n'.join(l)
|
|
||||||
page_string(s)
|
|
||||||
+ def _get_pe_byname(self, s):
|
|
||||||
+ l = crm_report.find_pe_files(s)
|
|
||||||
+ if len(l) == 0:
|
|
||||||
+ common_err("%s: path not found" % s)
|
|
||||||
+ return None
|
|
||||||
+ elif len(l) > 1:
|
|
||||||
+ common_err("%s: path ambiguous" % s)
|
|
||||||
+ return None
|
|
||||||
+ return l[0]
|
|
||||||
+ def _get_pe_byidx(self, idx):
|
|
||||||
+ l = crm_report.pelist()
|
|
||||||
+ if len(l) < abs(idx):
|
|
||||||
+ common_err("pe input file not found")
|
|
||||||
+ return None
|
|
||||||
+ return l[idx]
|
|
||||||
+ def _get_pe_bynum(self, n):
|
|
||||||
+ l = crm_report.pelist([n])
|
|
||||||
+ if len(l) == 0:
|
|
||||||
+ common_err("%s: PE file %d not found" % n)
|
|
||||||
+ return None
|
|
||||||
+ elif len(l) > 1:
|
|
||||||
+ common_err("%s: PE file %d ambiguous" % n)
|
|
||||||
+ return None
|
|
||||||
+ return l[0]
|
|
||||||
def transition(self,cmd,*args):
|
|
||||||
"""usage: transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
transition showdot [<number>|<file>]"""
|
|
||||||
@@ -1864,48 +1881,35 @@ Examine Pacemaker's history: node and re
|
|
||||||
return False
|
|
||||||
subcmd = "showdot"
|
|
||||||
argl.remove(subcmd)
|
|
||||||
- f = None
|
|
||||||
- startarg = 1
|
|
||||||
- if argl and re.search('pe-', argl[0]):
|
|
||||||
- l = crm_report.find_pe_files(argl[0])
|
|
||||||
- if len(l) == 0:
|
|
||||||
- common_err("%s: path not found" % argl[0])
|
|
||||||
- return False
|
|
||||||
- elif len(l) > 1:
|
|
||||||
- common_err("%s: path ambiguous" % argl[0])
|
|
||||||
- return False
|
|
||||||
- f = l[0]
|
|
||||||
+ if argl:
|
|
||||||
+ if re.search('pe-', argl[0]):
|
|
||||||
+ f = self._get_pe_byname(argl[0])
|
|
||||||
+ argl.pop(0)
|
|
||||||
+ elif is_int(argl[0]):
|
|
||||||
+ n = int(argl[0])
|
|
||||||
+ if n <= 0:
|
|
||||||
+ f = self._get_pe_byidx(n-1)
|
|
||||||
+ else:
|
|
||||||
+ f = self._get_pe_bynum(n)
|
|
||||||
+ argl.pop(0)
|
|
||||||
+ else:
|
|
||||||
+ f = self._get_pe_byidx(-1)
|
|
||||||
else:
|
|
||||||
- try: n = convert2ints(argl[0])
|
|
||||||
- except: n = None
|
|
||||||
- if n is None:
|
|
||||||
- idx = -1
|
|
||||||
- startarg = 0 # peinput number missing
|
|
||||||
- elif n <= 0:
|
|
||||||
- idx = n - 1
|
|
||||||
- n = [] # to get all peinputs
|
|
||||||
- else:
|
|
||||||
- idx = 0
|
|
||||||
- if subcmd == "showdot":
|
|
||||||
- l = crm_report.dotlist(n)
|
|
||||||
- else:
|
|
||||||
- l = crm_report.pelist(n)
|
|
||||||
- if len(l) < abs(idx):
|
|
||||||
- if subcmd == "show":
|
|
||||||
- common_err("pe input file not found")
|
|
||||||
- else:
|
|
||||||
- common_err("dot file not found")
|
|
||||||
- return False
|
|
||||||
- f = l[idx]
|
|
||||||
+ f = self._get_pe_byidx(-1)
|
|
||||||
if not f:
|
|
||||||
return False
|
|
||||||
rc = True
|
|
||||||
if subcmd == "show":
|
|
||||||
self.pe_file = f # self.pe_file needed by self.ptest
|
|
||||||
+ common_info("running ptest with %s" % f)
|
|
||||||
rc = ptestlike(self.ptest,'vv',"%s %s" % \
|
|
||||||
- (cmd, subcmd), *argl[startarg:])
|
|
||||||
+ (cmd, subcmd), *argl)
|
|
||||||
else:
|
|
||||||
- show_dot_graph(f.replace("bz2","dot"))
|
|
||||||
+ f = crm_report.pe2dot(f)
|
|
||||||
+ if not f:
|
|
||||||
+ common_err("dot file not found in the report")
|
|
||||||
+ return False
|
|
||||||
+ show_dot_graph(f)
|
|
||||||
if rc:
|
|
||||||
crm_report.show_transition_log(f)
|
|
||||||
return rc
|
|
||||||
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
||||||
--- a/shell/modules/utils.py
|
|
||||||
+++ b/shell/modules/utils.py
|
|
||||||
@@ -449,6 +449,9 @@ def check_range(a):
|
|
||||||
return False
|
|
||||||
return (int(a[0]) <= int(a[1]))
|
|
||||||
|
|
||||||
+def shorttime(ts):
|
|
||||||
+ return time.strftime("%X",time.localtime(ts))
|
|
||||||
+
|
|
||||||
def sort_by_mtime(l):
|
|
||||||
'Sort a (small) list of files by time mod.'
|
|
||||||
l2 = [(os.stat(x).st_mtime, x) for x in l]
|
|
||||||
@@ -489,6 +492,13 @@ def convert2ints(l):
|
|
||||||
else: # it's a string then
|
|
||||||
return int(l)
|
|
||||||
except: return None
|
|
||||||
+def is_int(s):
|
|
||||||
+ 'Check if the string can be converted to an integer.'
|
|
||||||
+ try:
|
|
||||||
+ i = int(s)
|
|
||||||
+ return True
|
|
||||||
+ except:
|
|
||||||
+ return False
|
|
||||||
|
|
||||||
def is_process(s):
|
|
||||||
proc = subprocess.Popen("ps -e -o pid,command | grep -qs '%s'" % s, \
|
|
@ -1,207 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313413824 -7200
|
|
||||||
# Node ID 3f3c348aaaed52383f6646b08899943aec8911f4
|
|
||||||
# Parent 441f4448eba6eda1a2cf44d3d63a0db9f8d56a20
|
|
||||||
Medium: Shell: relax transition acceptance
|
|
||||||
|
|
||||||
Sometimes logs are missing one or another transition related
|
|
||||||
message. Try to be more forgiving then.
|
|
||||||
Also, print information about number of actions which were
|
|
||||||
completed, skipped, etc.
|
|
||||||
|
|
||||||
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py
|
|
||||||
+++ b/shell/modules/report.py
|
|
||||||
@@ -320,10 +320,8 @@ def is_log(p):
|
|
||||||
return os.path.isfile(p) and os.path.getsize(p) > 0
|
|
||||||
|
|
||||||
def pe_file_in_range(pe_f, a):
|
|
||||||
- r = re.search("pe-[^-]+-([0-9]+)[.]bz2$", pe_f)
|
|
||||||
- if not r:
|
|
||||||
- return None
|
|
||||||
- if not a or (a[0] <= int(r.group(1)) <= a[1]):
|
|
||||||
+ pe_num = get_pe_num(pe_f)
|
|
||||||
+ if not a or (a[0] <= int(pe_num) <= a[1]):
|
|
||||||
return pe_f
|
|
||||||
return None
|
|
||||||
|
|
||||||
@@ -347,6 +345,12 @@ def update_loginfo(rptlog, logfile, oldp
|
|
||||||
except IOError, msg:
|
|
||||||
common_err("couldn't the update %s.info: %s" % (rptlog, msg))
|
|
||||||
|
|
||||||
+def get_pe_num(pe_file):
|
|
||||||
+ try:
|
|
||||||
+ return re.search("pe-[^-]+-([0-9]+)[.]", pe_file).group(1)
|
|
||||||
+ except:
|
|
||||||
+ return "-1"
|
|
||||||
+
|
|
||||||
# r.group(1) transition number (a different thing from file number)
|
|
||||||
# r.group(2) contains full path
|
|
||||||
# r.group(3) file number
|
|
||||||
@@ -358,6 +362,40 @@ transition_patt = (
|
|
||||||
"crmd: .* unpack_graph: Unpacked transition (%%): ([0-9]+) actions", # number of actions
|
|
||||||
)
|
|
||||||
|
|
||||||
+def run_graph_msg_actions(msg):
|
|
||||||
+ '''
|
|
||||||
+ crmd: [13667]: info: run_graph: Transition 399 (Complete=5,
|
|
||||||
+ Pending=1, Fired=1, Skipped=0, Incomplete=3,
|
|
||||||
+ Source=...
|
|
||||||
+ '''
|
|
||||||
+ d = {}
|
|
||||||
+ s = msg
|
|
||||||
+ while True:
|
|
||||||
+ r = re.search("([A-Z][a-z]+)=([0-9]+)", s)
|
|
||||||
+ if not r:
|
|
||||||
+ return d
|
|
||||||
+ d[r.group(1)] = int(r.group(2))
|
|
||||||
+ s = s[r.end():]
|
|
||||||
+def transition_actions(msg_l, te_invoke_msg, pe_file):
|
|
||||||
+ '''
|
|
||||||
+ Get the number of actions for the transition.
|
|
||||||
+ '''
|
|
||||||
+ # check if there were any actions in this transition
|
|
||||||
+ pe_num = get_pe_num(pe_file)
|
|
||||||
+ te_invoke_patt = transition_patt[0].replace("%%", pe_num)
|
|
||||||
+ run_patt = transition_patt[1].replace("%%", pe_num)
|
|
||||||
+ r = re.search(te_invoke_patt, te_invoke_msg)
|
|
||||||
+ trans_num = r.group(1)
|
|
||||||
+ unpack_patt = transition_patt[2].replace("%%", trans_num)
|
|
||||||
+ for msg in msg_l:
|
|
||||||
+ try:
|
|
||||||
+ return int(re.search(unpack_patt, msg).group(2))
|
|
||||||
+ except:
|
|
||||||
+ if re.search(run_patt, msg):
|
|
||||||
+ act_d = run_graph_msg_actions(msg)
|
|
||||||
+ return sum(act_d.values())
|
|
||||||
+ return -1
|
|
||||||
+
|
|
||||||
class Report(Singleton):
|
|
||||||
'''
|
|
||||||
A hb_report class.
|
|
||||||
@@ -396,8 +434,7 @@ class Report(Singleton):
|
|
||||||
def node_list(self):
|
|
||||||
return self.cibnode_l
|
|
||||||
def peinputs_list(self):
|
|
||||||
- return [re.search("pe-[^-]+-([0-9]+)[.]bz2$", x).group(1)
|
|
||||||
- for x in self.peinputs_l]
|
|
||||||
+ return [get_pe_num(x) for x in self.peinputs_l]
|
|
||||||
def unpack_report(self, tarball):
|
|
||||||
'''
|
|
||||||
Unpack hb_report tarball.
|
|
||||||
@@ -712,8 +749,6 @@ class Report(Singleton):
|
|
||||||
'''
|
|
||||||
Get a list of transitions.
|
|
||||||
Empty transitions are skipped.
|
|
||||||
- We use the unpack_graph message to see the number of
|
|
||||||
- actions.
|
|
||||||
Some callers need original PE file path (keep_pe_path),
|
|
||||||
otherwise we produce the path within the report.
|
|
||||||
If the caller doesn't provide the message list, then we
|
|
||||||
@@ -738,19 +773,12 @@ class Report(Singleton):
|
|
||||||
node = msg_a[3]
|
|
||||||
pe_file = msg_a[-1]
|
|
||||||
pe_base = os.path.basename(pe_file)
|
|
||||||
- # check if there were any actions in this transition
|
|
||||||
- r = re.search(trans_re_l[0], msg)
|
|
||||||
- trans_num = r.group(1)
|
|
||||||
- unpack_patt = transition_patt[2].replace("%%", trans_num)
|
|
||||||
- num_actions = 0
|
|
||||||
- for t in msg_l:
|
|
||||||
- try:
|
|
||||||
- num_actions = int(re.search(unpack_patt, t).group(2))
|
|
||||||
- break
|
|
||||||
- except: pass
|
|
||||||
+ num_actions = transition_actions(msg_l, msg, pe_file)
|
|
||||||
if num_actions == 0: # empty transition
|
|
||||||
- common_debug("skipping empty transition %s (%s)" % (trans_num, pe_base))
|
|
||||||
+ common_debug("skipping empty transition (%s)" % pe_base)
|
|
||||||
continue
|
|
||||||
+ elif num_actions == -1: # couldn't find messages
|
|
||||||
+ common_warn("could not find number of actions for transition (%s)" % pe_base)
|
|
||||||
common_debug("found PE input at %s: %s" % (node, pe_file))
|
|
||||||
if keep_pe_path:
|
|
||||||
pe_l.append(pe_file)
|
|
||||||
@@ -894,6 +922,34 @@ class Report(Singleton):
|
|
||||||
self.error("no resources or nodes found")
|
|
||||||
return False
|
|
||||||
self.show_logs(re_l = all_re_l)
|
|
||||||
+ def get_transition_msgs(self, pe_file, msg_l = []):
|
|
||||||
+ if not msg_l:
|
|
||||||
+ trans_re_l = [x.replace("%%", "[0-9]+") for x in transition_patt]
|
|
||||||
+ msg_l = self.logobj.get_matches(trans_re_l)
|
|
||||||
+ te_invoke_msg = ""
|
|
||||||
+ run_msg = ""
|
|
||||||
+ unpack_msg = ""
|
|
||||||
+ pe_num = get_pe_num(pe_file)
|
|
||||||
+ te_invoke_patt = transition_patt[0].replace("%%", pe_num)
|
|
||||||
+ run_patt = transition_patt[1].replace("%%", pe_num)
|
|
||||||
+ r = None
|
|
||||||
+ for msg in msg_l:
|
|
||||||
+ r = re.search(te_invoke_patt, msg)
|
|
||||||
+ if r:
|
|
||||||
+ te_invoke_msg = msg
|
|
||||||
+ break
|
|
||||||
+ if not r:
|
|
||||||
+ return ["", "", ""]
|
|
||||||
+ trans_num = r.group(1)
|
|
||||||
+ unpack_patt = transition_patt[2].replace("%%", trans_num)
|
|
||||||
+ for msg in msg_l:
|
|
||||||
+ if re.search(run_patt, msg):
|
|
||||||
+ run_msg = msg
|
|
||||||
+ elif re.search(unpack_patt, msg):
|
|
||||||
+ unpack_msg = msg
|
|
||||||
+ if run_msg and unpack_msg:
|
|
||||||
+ break
|
|
||||||
+ return [unpack_msg, te_invoke_msg, run_msg]
|
|
||||||
def show_transition_log(self, pe_file):
|
|
||||||
'''
|
|
||||||
Search for events within the given transition.
|
|
||||||
@@ -901,28 +957,34 @@ class Report(Singleton):
|
|
||||||
if not self.prepare_source():
|
|
||||||
return False
|
|
||||||
pe_base = os.path.basename(pe_file)
|
|
||||||
- r = re.search("pe-[^-]+-([0-9]+)[.]", pe_base)
|
|
||||||
- pe_num = r.group(1)
|
|
||||||
- trans_re_l = [x.replace("%%",pe_num) for x in transition_patt]
|
|
||||||
- trans_start = self.logobj.search_logs(self.log_l, trans_re_l[0])
|
|
||||||
- trans_end = self.logobj.search_logs(self.log_l, trans_re_l[1])
|
|
||||||
- if not trans_start:
|
|
||||||
+ pe_num = get_pe_num(pe_base)
|
|
||||||
+ unpack_msg, te_invoke_msg, run_msg = self.get_transition_msgs(pe_file)
|
|
||||||
+ if not te_invoke_msg:
|
|
||||||
common_warn("start of transition %s not found in logs" % pe_base)
|
|
||||||
return False
|
|
||||||
- if not trans_end:
|
|
||||||
+ if not run_msg:
|
|
||||||
common_warn("end of transition %s not found in logs (transition not complete yet?)" % pe_base)
|
|
||||||
return False
|
|
||||||
- common_debug("transition start: %s" % trans_start[0])
|
|
||||||
- common_debug("transition end: %s" % trans_end[0])
|
|
||||||
- start_ts = syslog_ts(trans_start[0])
|
|
||||||
- end_ts = syslog_ts(trans_end[0])
|
|
||||||
+ common_debug("transition start: %s" % te_invoke_msg)
|
|
||||||
+ common_debug("transition end: %s" % run_msg)
|
|
||||||
+ start_ts = syslog_ts(te_invoke_msg)
|
|
||||||
+ end_ts = syslog_ts(run_msg)
|
|
||||||
if not start_ts or not end_ts:
|
|
||||||
self.warn("strange, no timestamps found")
|
|
||||||
return False
|
|
||||||
- # limit the log scope temporarily
|
|
||||||
+ act_d = run_graph_msg_actions(run_msg)
|
|
||||||
+ total = sum(act_d.values())
|
|
||||||
+ s = ""
|
|
||||||
+ for a in act_d:
|
|
||||||
+ if not act_d[a]:
|
|
||||||
+ continue
|
|
||||||
+ s = "%s %s=%d" % (s, a, act_d[a])
|
|
||||||
+ common_info("transition %s %d actions: %s" %
|
|
||||||
+ (pe_file.replace(self.loc+"/",""), total, s))
|
|
||||||
common_info("logs for transition %s (%s-%s)" %
|
|
||||||
(pe_file.replace(self.loc+"/",""), \
|
|
||||||
shorttime(start_ts), shorttime(end_ts)))
|
|
||||||
+ # limit the log scope temporarily
|
|
||||||
self.logobj.set_log_timeframe(start_ts, end_ts)
|
|
||||||
self.events()
|
|
||||||
self.logobj.set_log_timeframe(self.from_dt, self.to_dt)
|
|
@ -1,34 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313416746 -7200
|
|
||||||
# Node ID 3681d3471fdecde109ea7c25ab2ceb31e1e8646f
|
|
||||||
# Parent 3f3c348aaaed52383f6646b08899943aec8911f4
|
|
||||||
Low: Shell: update log patterns for history
|
|
||||||
|
|
||||||
diff --git a/shell/modules/log_patterns.py b/shell/modules/log_patterns.py
|
|
||||||
--- a/shell/modules/log_patterns.py
|
|
||||||
+++ b/shell/modules/log_patterns.py
|
|
||||||
@@ -3,7 +3,7 @@
|
|
||||||
# log pattern specification
|
|
||||||
#
|
|
||||||
# patterns are grouped one of several classes:
|
|
||||||
-# - resources: pertaining to a resource
|
|
||||||
+# - resource: pertaining to a resource
|
|
||||||
# - node: pertaining to a node
|
|
||||||
# - quorum: quorum changes
|
|
||||||
# - events: other interesting events (core dumps, etc)
|
|
||||||
@@ -17,12 +17,12 @@
|
|
||||||
log_patterns = {
|
|
||||||
"resource": (
|
|
||||||
( # detail 0
|
|
||||||
- "lrmd:.*rsc:%%.*(start|stop)",
|
|
||||||
+ "lrmd:.*rsc:%%.*(start|stop|promote|demote|migrate)",
|
|
||||||
"lrmd:.*RA output:.*%%.*stderr",
|
|
||||||
"lrmd:.*WARN:.*Managed.*%%.*exited",
|
|
||||||
),
|
|
||||||
( # detail 1
|
|
||||||
- "lrmd:.*rsc:%%.*probe",
|
|
||||||
+ "lrmd:.*rsc:%%.*(probe|notify)",
|
|
||||||
"lrmd:.*info:.*Managed.*%%.*exited",
|
|
||||||
),
|
|
||||||
),
|
|
@ -1,47 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314196090 -7200
|
|
||||||
# Node ID 709ef91cfada2822aca53dcef085ddb6952393c5
|
|
||||||
# Parent 3a81b7eae66672dd9873fe6b53ee3c0da6fc87d7
|
|
||||||
Low: Shell: update pe not found message
|
|
||||||
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1822,7 +1822,6 @@ Examine Pacemaker's history: node and re
|
|
||||||
crm_report.refresh_source()
|
|
||||||
f = self._get_pe_byidx(-1)
|
|
||||||
if not f:
|
|
||||||
- common_err("no transitions found")
|
|
||||||
return False
|
|
||||||
crm_report.show_transition_log(f)
|
|
||||||
def resource(self,cmd,*args):
|
|
||||||
@@ -1878,7 +1877,7 @@ Examine Pacemaker's history: node and re
|
|
||||||
def _get_pe_byidx(self, idx):
|
|
||||||
l = crm_report.pelist()
|
|
||||||
if len(l) < abs(idx):
|
|
||||||
- common_err("pe input file not found")
|
|
||||||
+ common_err("pe input file for index %d not found" % (idx+1))
|
|
||||||
return None
|
|
||||||
return l[idx]
|
|
||||||
def _get_pe_bynum(self, n):
|
|
||||||
@@ -1913,7 +1912,8 @@ Examine Pacemaker's history: node and re
|
|
||||||
f = self._get_pe_bynum(n)
|
|
||||||
argl.pop(0)
|
|
||||||
else:
|
|
||||||
- f = self._get_pe_byidx(-1)
|
|
||||||
+ common_err("<%s> doesn't sound like a PE input" % argl[0])
|
|
||||||
+ return False
|
|
||||||
else:
|
|
||||||
f = self._get_pe_byidx(-1)
|
|
||||||
if not f:
|
|
||||||
@@ -1922,8 +1922,7 @@ Examine Pacemaker's history: node and re
|
|
||||||
if subcmd == "show":
|
|
||||||
self.pe_file = f # self.pe_file needed by self.ptest
|
|
||||||
common_info("running ptest with %s" % f)
|
|
||||||
- rc = ptestlike(self.ptest,'vv',"%s %s" % \
|
|
||||||
- (cmd, subcmd), *argl)
|
|
||||||
+ rc = ptestlike(self.ptest,'vv', cmd, *argl)
|
|
||||||
else:
|
|
||||||
f = crm_report.pe2dot(f)
|
|
||||||
if not f:
|
|
@ -1,315 +0,0 @@
|
|||||||
changeset: 10788:6f9cc20dba0d
|
|
||||||
user: Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
date: Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
summary: Dev: Shell: spawn transition command from peinputs
|
|
||||||
|
|
||||||
diff -r b694b75d2e33 -r 6f9cc20dba0d doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
+++ b/doc/crm.8.txt Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
@@ -2565,6 +2565,21 @@ were created (the DC at the time). The `
|
|
||||||
all PE input files to the current working directory (and use ssh
|
|
||||||
if necessary).
|
|
||||||
|
|
||||||
+Usage:
|
|
||||||
+...............
|
|
||||||
+ peinputs list [{<range>|<number>} ...]
|
|
||||||
+ peinputs get [{<range>|<number>} ...]
|
|
||||||
+
|
|
||||||
+ range :: <n1>:<n2>
|
|
||||||
+...............
|
|
||||||
+Example:
|
|
||||||
+...............
|
|
||||||
+ peinputs get 440:444 446
|
|
||||||
+...............
|
|
||||||
+
|
|
||||||
+[[cmdhelp_history_transition,show transition]]
|
|
||||||
+==== `transition`
|
|
||||||
+
|
|
||||||
The `show` subcommand will print actions planned by the PE and
|
|
||||||
run graphviz (`dotty`) to display a graphical representation. Of
|
|
||||||
course, for the latter an X11 session is required. This command
|
|
||||||
@@ -2581,22 +2596,20 @@ last one, i.e. the last transition. If t
|
|
||||||
then the corresponding transition relative to the last one is
|
|
||||||
chosen.
|
|
||||||
|
|
||||||
+After the `ptest` output, logs about events that happened during
|
|
||||||
+the transition are printed.
|
|
||||||
+
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
- peinputs list [{<range>|<number>} ...]
|
|
||||||
- peinputs get [{<range>|<number>} ...]
|
|
||||||
- peinputs show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
- peinputs showdot [<number>]
|
|
||||||
-
|
|
||||||
- range :: <n1>:<n2>
|
|
||||||
+ transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
+ transition showdot [<number>]
|
|
||||||
...............
|
|
||||||
-Example:
|
|
||||||
+Examples:
|
|
||||||
...............
|
|
||||||
- peinputs get 440:444 446
|
|
||||||
- peinputs show
|
|
||||||
- peinputs show 444
|
|
||||||
- peinputs show -1
|
|
||||||
- peinputs showdot 444
|
|
||||||
+ transition show
|
|
||||||
+ transition show 444
|
|
||||||
+ transition show -1
|
|
||||||
+ transition showdot 444
|
|
||||||
...............
|
|
||||||
|
|
||||||
=== `end` (`cd`, `up`)
|
|
||||||
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/log_patterns.py
|
|
||||||
--- a/shell/modules/log_patterns.py Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
+++ b/shell/modules/log_patterns.py Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
@@ -64,6 +64,6 @@ log_patterns = {
|
|
||||||
}
|
|
||||||
|
|
||||||
transition_patt = (
|
|
||||||
- "crmd: .* Processing graph.*derived from (.*bz2)", # transition start
|
|
||||||
- "crmd: .* Transition.*Source=(.*bz2): (Stopped|Complete|Terminated)", # and stop
|
|
||||||
+ "crmd: .* Processing graph.*derived from .*/pe-[^-]+-(%%)[.]bz2", # transition start
|
|
||||||
+ "crmd: .* Transition.*Source=.*/pe-[^-]+-(%%)[.]bz2.: (Stopped|Complete|Terminated)", # and stop
|
|
||||||
)
|
|
||||||
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/report.py
|
|
||||||
--- a/shell/modules/report.py Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
+++ b/shell/modules/report.py Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
@@ -177,8 +177,12 @@ class LogSyslog(object):
|
|
||||||
find out start/end file positions. Logs need to be
|
|
||||||
already open.
|
|
||||||
'''
|
|
||||||
- self.from_ts = convert_dt(from_dt)
|
|
||||||
- self.to_ts = convert_dt(to_dt)
|
|
||||||
+ if isinstance(from_dt, datetime.datetime):
|
|
||||||
+ self.from_ts = convert_dt(from_dt)
|
|
||||||
+ self.to_ts = convert_dt(to_dt)
|
|
||||||
+ else:
|
|
||||||
+ self.from_ts = from_dt
|
|
||||||
+ self.to_ts = to_dt
|
|
||||||
bad_logs = []
|
|
||||||
for log in self.f:
|
|
||||||
f = self.f[log]
|
|
||||||
@@ -498,13 +502,14 @@ class Report(Singleton):
|
|
||||||
if not os.path.isdir(self.outdir):
|
|
||||||
return []
|
|
||||||
l = []
|
|
||||||
+ trans_re_l = [x.replace("%%","") for x in transition_patt]
|
|
||||||
for node,rptlog,logfile,nextpos in a:
|
|
||||||
node_l = []
|
|
||||||
fl = glob.glob("%s/*%s*" % (self.outdir,node))
|
|
||||||
if not fl:
|
|
||||||
continue
|
|
||||||
for s in file2list(fl[0]):
|
|
||||||
- r = re.search(transition_patt[0], s)
|
|
||||||
+ r = re.search(trans_re_l[0], s)
|
|
||||||
if not r:
|
|
||||||
continue
|
|
||||||
node_l.append(r.group(1))
|
|
||||||
@@ -680,7 +685,8 @@ class Report(Singleton):
|
|
||||||
self.find_central_log()
|
|
||||||
self.read_cib()
|
|
||||||
self.set_node_colors()
|
|
||||||
- self.logobj = None
|
|
||||||
+ self.logobj = LogSyslog(self.central_log, self.log_l, \
|
|
||||||
+ self.from_dt, self.to_dt)
|
|
||||||
def prepare_source(self):
|
|
||||||
'''
|
|
||||||
Unpack a hb_report tarball.
|
|
||||||
@@ -740,6 +746,15 @@ class Report(Singleton):
|
|
||||||
try: clr = self.nodecolor[a[3]]
|
|
||||||
except: return s
|
|
||||||
return termctrl.render("${%s}%s${NORMAL}" % (clr,s))
|
|
||||||
+ def display_logs(self, l):
|
|
||||||
+ if not options.batch and sys.stdout.isatty():
|
|
||||||
+ page_string('\n'.join([ self.disp(x) for x in l ]))
|
|
||||||
+ else: # raw output
|
|
||||||
+ try: # in case user quits the next prog in pipe
|
|
||||||
+ for s in l: print s
|
|
||||||
+ except IOError, msg:
|
|
||||||
+ if not ("Broken pipe" in msg):
|
|
||||||
+ common_err(msg)
|
|
||||||
def show_logs(self, log_l = [], re_l = []):
|
|
||||||
'''
|
|
||||||
Print log lines, either matched by re_l or all.
|
|
||||||
@@ -749,18 +764,7 @@ class Report(Singleton):
|
|
||||||
if not self.central_log and not log_l:
|
|
||||||
self.error("no logs found")
|
|
||||||
return
|
|
||||||
- if not self.logobj:
|
|
||||||
- self.logobj = LogSyslog(self.central_log, log_l, \
|
|
||||||
- self.from_dt, self.to_dt)
|
|
||||||
- l = self.logobj.get_matches(re_l, log_l)
|
|
||||||
- if not options.batch and sys.stdout.isatty():
|
|
||||||
- page_string('\n'.join([ self.disp(x) for x in l ]))
|
|
||||||
- else: # raw output
|
|
||||||
- try: # in case user quits the next prog in pipe
|
|
||||||
- for s in l: print s
|
|
||||||
- except IOError, msg:
|
|
||||||
- if not ("Broken pipe" in msg):
|
|
||||||
- common_err(msg)
|
|
||||||
+ self.display_logs(self.logobj.get_matches(re_l, log_l))
|
|
||||||
def match_args(self, cib_l, args):
|
|
||||||
for a in args:
|
|
||||||
a_clone = re.sub(r':.*', '', a)
|
|
||||||
@@ -812,6 +816,34 @@ class Report(Singleton):
|
|
||||||
self.error("no resources or nodes found")
|
|
||||||
return False
|
|
||||||
self.show_logs(re_l = all_re_l)
|
|
||||||
+ def show_transition_log(self, pe_file):
|
|
||||||
+ '''
|
|
||||||
+ Search for events within the given transition.
|
|
||||||
+ '''
|
|
||||||
+ pe_base = os.path.basename(pe_file)
|
|
||||||
+ r = re.search("pe-[^-]+-([0-9]+)[.]bz2", pe_base)
|
|
||||||
+ pe_num = r.group(1)
|
|
||||||
+ trans_re_l = [x.replace("%%",pe_num) for x in transition_patt]
|
|
||||||
+ trans_start = self.logobj.search_logs(self.log_l, trans_re_l[0])
|
|
||||||
+ trans_end = self.logobj.search_logs(self.log_l, trans_re_l[1])
|
|
||||||
+ if not trans_start:
|
|
||||||
+ common_warn("transition %s start not found in logs" % pe_base)
|
|
||||||
+ return False
|
|
||||||
+ if not trans_end:
|
|
||||||
+ common_warn("transition %s end not found in logs" % pe_base)
|
|
||||||
+ return False
|
|
||||||
+ common_debug("transition start: %s" % trans_start[0])
|
|
||||||
+ common_debug("transition end: %s" % trans_end[0])
|
|
||||||
+ start_ts = syslog_ts(trans_start[0])
|
|
||||||
+ end_ts = syslog_ts(trans_end[0])
|
|
||||||
+ if not start_ts or not end_ts:
|
|
||||||
+ self.warn("strange, no timestamps found")
|
|
||||||
+ return False
|
|
||||||
+ # limit the log scope temporarily
|
|
||||||
+ self.logobj.set_log_timeframe(start_ts, end_ts)
|
|
||||||
+ self.events()
|
|
||||||
+ self.logobj.set_log_timeframe(self.from_dt, self.to_dt)
|
|
||||||
+ return True
|
|
||||||
def resource(self,*args):
|
|
||||||
'''
|
|
||||||
Show resource relevant logs.
|
|
||||||
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
+++ b/shell/modules/ui.py.in Mon Jul 18 12:35:57 2011 +0200
|
|
||||||
@@ -1686,7 +1686,8 @@ Examine Pacemaker's history: node and re
|
|
||||||
self.cmd_table["resource"] = (self.resource,(1,),1,0)
|
|
||||||
self.cmd_table["node"] = (self.node,(1,),1,1)
|
|
||||||
self.cmd_table["log"] = (self.log,(0,),1,0)
|
|
||||||
- self.cmd_table["peinputs"] = (self.peinputs,(0,),1,0)
|
|
||||||
+ self.cmd_table["peinputs"] = (self.peinputs,(1,),1,0)
|
|
||||||
+ self.cmd_table["transition"] = (self.transition,(1,),1,0)
|
|
||||||
self._set_source(options.history)
|
|
||||||
def _no_source(self):
|
|
||||||
common_error("we have no source set yet! please use the source command")
|
|
||||||
@@ -1832,57 +1833,63 @@ Examine Pacemaker's history: node and re
|
|
||||||
return run_ptest(s, nograph, scores, utilization, actions, verbosity)
|
|
||||||
def peinputs(self,cmd,subcmd,*args):
|
|
||||||
"""usage: peinputs list [{<range>|<number>} ...]
|
|
||||||
- peinputs get [{<range>|<number>} ...]
|
|
||||||
- peinputs show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
- peinputs showdot [<number>]"""
|
|
||||||
- if subcmd in ("get","list"):
|
|
||||||
- if args:
|
|
||||||
- l = []
|
|
||||||
- for s in args:
|
|
||||||
- a = convert2ints(s.split(':'))
|
|
||||||
- if len(a) == 2 and not check_range(a):
|
|
||||||
- common_err("%s: invalid peinputs range" % a)
|
|
||||||
- return False
|
|
||||||
- l += crm_report.pelist(a)
|
|
||||||
- else:
|
|
||||||
- l = crm_report.pelist()
|
|
||||||
- if not l: return False
|
|
||||||
- if subcmd == "list":
|
|
||||||
- s = get_stdout("ls -lrt %s" % ' '.join(l))
|
|
||||||
- page_string(s)
|
|
||||||
- else:
|
|
||||||
- print '\n'.join(l)
|
|
||||||
- elif subcmd in ("show","showdot"):
|
|
||||||
- try: n = convert2ints(args[0])
|
|
||||||
- except: n = None
|
|
||||||
- startarg = 1
|
|
||||||
- if n is None:
|
|
||||||
- idx = -1
|
|
||||||
- startarg = 0 # peinput number missing
|
|
||||||
- elif n <= 0:
|
|
||||||
- idx = n - 1
|
|
||||||
- n = [] # to get all peinputs
|
|
||||||
- else:
|
|
||||||
- idx = 0
|
|
||||||
- if subcmd == "showdot":
|
|
||||||
- if not user_prefs.dotty:
|
|
||||||
- common_err("install graphviz to draw transition graphs")
|
|
||||||
+ peinputs get [{<range>|<number>} ...]"""
|
|
||||||
+ if subcmd not in ("get","list"):
|
|
||||||
+ bad_usage(cmd,subcmd)
|
|
||||||
+ return False
|
|
||||||
+ if args:
|
|
||||||
+ l = []
|
|
||||||
+ for s in args:
|
|
||||||
+ a = convert2ints(s.split(':'))
|
|
||||||
+ if len(a) == 2 and not check_range(a):
|
|
||||||
+ common_err("%s: invalid peinputs range" % a)
|
|
||||||
return False
|
|
||||||
- l = crm_report.dotlist(n)
|
|
||||||
- else:
|
|
||||||
- l = crm_report.pelist(n)
|
|
||||||
- if len(l) < abs(idx):
|
|
||||||
- common_err("pe input or dot file not found")
|
|
||||||
+ l += crm_report.pelist(a)
|
|
||||||
+ else:
|
|
||||||
+ l = crm_report.pelist()
|
|
||||||
+ if not l: return False
|
|
||||||
+ if subcmd == "list":
|
|
||||||
+ s = get_stdout("ls -lrt %s" % ' '.join(l))
|
|
||||||
+ page_string(s)
|
|
||||||
+ else:
|
|
||||||
+ print '\n'.join(l)
|
|
||||||
+ def transition(self,cmd,subcmd,*args):
|
|
||||||
+ """usage: transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
||||||
+ transition showdot [<number>]"""
|
|
||||||
+ if subcmd not in ("show", "showdot"):
|
|
||||||
+ bad_usage(cmd,subcmd)
|
|
||||||
+ return False
|
|
||||||
+ try: n = convert2ints(args[0])
|
|
||||||
+ except: n = None
|
|
||||||
+ startarg = 1
|
|
||||||
+ if n is None:
|
|
||||||
+ idx = -1
|
|
||||||
+ startarg = 0 # peinput number missing
|
|
||||||
+ elif n <= 0:
|
|
||||||
+ idx = n - 1
|
|
||||||
+ n = [] # to get all peinputs
|
|
||||||
+ else:
|
|
||||||
+ idx = 0
|
|
||||||
+ if subcmd == "showdot":
|
|
||||||
+ if not user_prefs.dotty:
|
|
||||||
+ common_err("install graphviz to draw transition graphs")
|
|
||||||
return False
|
|
||||||
- if subcmd == "show":
|
|
||||||
- self.pe_file = l[idx]
|
|
||||||
- return ptestlike(self.ptest,'vv',"%s %s" % \
|
|
||||||
- (cmd, subcmd), *args[startarg:])
|
|
||||||
- else:
|
|
||||||
- show_dot_graph(l[idx])
|
|
||||||
+ l = crm_report.dotlist(n)
|
|
||||||
else:
|
|
||||||
- bad_usage(cmd,' '.join(subcmd,args))
|
|
||||||
+ l = crm_report.pelist(n)
|
|
||||||
+ if len(l) < abs(idx):
|
|
||||||
+ common_err("pe input or dot file not found")
|
|
||||||
return False
|
|
||||||
+ rc = True
|
|
||||||
+ if subcmd == "show":
|
|
||||||
+ self.pe_file = l[idx]
|
|
||||||
+ rc = ptestlike(self.ptest,'vv',"%s %s" % \
|
|
||||||
+ (cmd, subcmd), *args[startarg:])
|
|
||||||
+ if rc:
|
|
||||||
+ crm_report.show_transition_log(self.pe_file)
|
|
||||||
+ else:
|
|
||||||
+ show_dot_graph(l[idx])
|
|
||||||
+ return rc
|
|
||||||
|
|
||||||
class TopLevel(UserInterface):
|
|
||||||
'''
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
Index: pacemaker/shell/modules/Makefile.am
|
|
||||||
===================================================================
|
|
||||||
--- pacemaker.orig/shell/modules/Makefile.am
|
|
||||||
+++ pacemaker/shell/modules/Makefile.am
|
|
||||||
@@ -35,6 +35,7 @@ modules = __init__.py \
|
|
||||||
ra.py \
|
|
||||||
report.py \
|
|
||||||
log_patterns.py \
|
|
||||||
+ crm_pssh.py \
|
|
||||||
singletonmixin.py \
|
|
||||||
template.py \
|
|
||||||
term.py \
|
|
@ -1,98 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313760016 -7200
|
|
||||||
# Node ID 3a81b7eae66672dd9873fe6b53ee3c0da6fc87d7
|
|
||||||
# Parent e8ea8fb95f310997995576ee831693b0d3b2736a
|
|
||||||
Medium: Shell: support for LRM secrets in resource level
|
|
||||||
|
|
||||||
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt
|
|
||||||
+++ b/doc/crm.8.txt
|
|
||||||
@@ -869,6 +869,34 @@ Example:
|
|
||||||
param ip_0 show ip
|
|
||||||
...............
|
|
||||||
|
|
||||||
+[[cmdhelp_resource_secret,manage sensitive parameters]]
|
|
||||||
+==== `secret`
|
|
||||||
+
|
|
||||||
+Sensitive parameters can be kept in local files rather than CIB
|
|
||||||
+in order to prevent accidental data exposure. Use the `secret`
|
|
||||||
+command to manage such parameters. `stash` and `unstash` move the
|
|
||||||
+value from the CIB and back to the CIB respectively. The `set`
|
|
||||||
+subcommand sets the parameter to the provided value. `delete`
|
|
||||||
+removes the parameter completely. `show` displays the value of
|
|
||||||
+the parameter from the local file. Use `check` to verify if the
|
|
||||||
+local file content is valid.
|
|
||||||
+
|
|
||||||
+Usage:
|
|
||||||
+...............
|
|
||||||
+ secret <rsc> set <param> <value>
|
|
||||||
+ secret <rsc> stash <param>
|
|
||||||
+ secret <rsc> unstash <param>
|
|
||||||
+ secret <rsc> delete <param>
|
|
||||||
+ secret <rsc> show <param>
|
|
||||||
+ secret <rsc> check <param>
|
|
||||||
+...............
|
|
||||||
+Example:
|
|
||||||
+...............
|
|
||||||
+ secret fence_1 show password
|
|
||||||
+ secret fence_1 stash password
|
|
||||||
+ secret fence_1 set password secret_value
|
|
||||||
+...............
|
|
||||||
+
|
|
||||||
[[cmdhelp_resource_meta,manage a meta attribute]]
|
|
||||||
==== `meta`
|
|
||||||
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -661,7 +661,8 @@ def manage_attr(cmd,attr_ext_commands,*a
|
|
||||||
else:
|
|
||||||
bad_usage(cmd,' '.join(args))
|
|
||||||
return False
|
|
||||||
- elif args[1] in ('delete','show'):
|
|
||||||
+ elif args[1] in ('delete','show') or \
|
|
||||||
+ (cmd == "secret" and args[1] in ('stash','unstash','check')):
|
|
||||||
if len(args) == 3:
|
|
||||||
if not is_name_sane(args[0]) \
|
|
||||||
or not is_name_sane(args[2]):
|
|
||||||
@@ -770,6 +771,14 @@ program.
|
|
||||||
'delete': "crm_resource -z -r '%s' -d '%s'",
|
|
||||||
'show': "crm_resource -z -r '%s' -g '%s'",
|
|
||||||
}
|
|
||||||
+ rsc_secret = {
|
|
||||||
+ 'set': "cibsecret set '%s' '%s' '%s'",
|
|
||||||
+ 'stash': "cibsecret stash '%s' '%s'",
|
|
||||||
+ 'unstash': "cibsecret unstash '%s' '%s'",
|
|
||||||
+ 'delete': "cibsecret delete '%s' '%s'",
|
|
||||||
+ 'show': "cibsecret get '%s' '%s'",
|
|
||||||
+ 'check': "cibsecret check '%s' '%s'",
|
|
||||||
+ }
|
|
||||||
rsc_refresh = "crm_resource -R"
|
|
||||||
rsc_refresh_node = "crm_resource -R -H '%s'"
|
|
||||||
rsc_reprobe = "crm_resource -P"
|
|
||||||
@@ -787,6 +796,7 @@ program.
|
|
||||||
self.cmd_table["migrate"] = (self.migrate,(1,4),0,1)
|
|
||||||
self.cmd_table["unmigrate"] = (self.unmigrate,(1,1),0,1)
|
|
||||||
self.cmd_table["param"] = (self.param,(3,4),1,1)
|
|
||||||
+ self.cmd_table["secret"] = (self.secret,(3,4),1,1)
|
|
||||||
self.cmd_table["meta"] = (self.meta,(3,4),1,1)
|
|
||||||
self.cmd_table["utilization"] = (self.utilization,(3,4),1,1)
|
|
||||||
self.cmd_table["failcount"] = (self.failcount,(3,4),0,0)
|
|
||||||
@@ -924,6 +934,16 @@ program.
|
|
||||||
param <rsc> show <param>"""
|
|
||||||
d = lambda: manage_attr(cmd,self.rsc_param,*args)
|
|
||||||
return d()
|
|
||||||
+ def secret(self,cmd,*args):
|
|
||||||
+ """usage:
|
|
||||||
+ secret <rsc> set <param> <value>
|
|
||||||
+ secret <rsc> stash <param>
|
|
||||||
+ secret <rsc> unstash <param>
|
|
||||||
+ secret <rsc> delete <param>
|
|
||||||
+ secret <rsc> show <param>
|
|
||||||
+ secret <rsc> check <param>"""
|
|
||||||
+ d = lambda: manage_attr(cmd,self.rsc_secret,*args)
|
|
||||||
+ return d()
|
|
||||||
def meta(self,cmd,*args):
|
|
||||||
"""usage:
|
|
||||||
meta <rsc> set <attr> <value>
|
|
@ -1,28 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314633641 -7200
|
|
||||||
# Node ID f77e52725f2d98c219d8b22208da0b89b3d42112
|
|
||||||
# Parent ccd0c1e1edf9f23cafb4363014acba755f1b4e25
|
|
||||||
Low: Shell: let the pager decide how to handle output smaller than terminal
|
|
||||||
|
|
||||||
Instead of trying to calculate the size of the output, which may
|
|
||||||
not be trivial, better let the pager deal with it. For instance,
|
|
||||||
less(1) can be configured to exit immediately on a
|
|
||||||
less-than-screenful of input (-F). IIRC, more(1) does that
|
|
||||||
automatically.
|
|
||||||
|
|
||||||
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
||||||
--- a/shell/modules/utils.py
|
|
||||||
+++ b/shell/modules/utils.py
|
|
||||||
@@ -524,10 +524,7 @@ def page_string(s):
|
|
||||||
'Write string through a pager.'
|
|
||||||
if not s:
|
|
||||||
return
|
|
||||||
- w,h = get_winsize()
|
|
||||||
- if s.count('\n') < h:
|
|
||||||
- print s
|
|
||||||
- elif not user_prefs.pager or not sys.stdout.isatty() or options.batch:
|
|
||||||
+ if not user_prefs.pager or not sys.stdout.isatty() or options.batch:
|
|
||||||
print s
|
|
||||||
else:
|
|
||||||
opts = ""
|
|
@ -1,34 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1313589488 -7200
|
|
||||||
# Node ID 0abb257259ed722abaa32a237c3c284c08ec0737
|
|
||||||
# Parent 3681d3471fdecde109ea7c25ab2ceb31e1e8646f
|
|
||||||
Low: Shell: add crm execute directory to the PATH if not already present (bnc#712605)
|
|
||||||
|
|
||||||
Important if crm is run as non-root user. We use sys.argv[0],
|
|
||||||
but perhaps it'd be better to use autoconf @sbindir@ (or however
|
|
||||||
it's named) and set it in vars.sbindir.
|
|
||||||
|
|
||||||
diff --git a/shell/modules/main.py b/shell/modules/main.py
|
|
||||||
--- a/shell/modules/main.py
|
|
||||||
+++ b/shell/modules/main.py
|
|
||||||
@@ -16,6 +16,7 @@
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
+import os
|
|
||||||
import shlex
|
|
||||||
import getopt
|
|
||||||
|
|
||||||
@@ -205,7 +206,10 @@ vars = Vars.getInstance()
|
|
||||||
levels = Levels.getInstance()
|
|
||||||
|
|
||||||
# prefer the user set PATH
|
|
||||||
-os.putenv("PATH", "%s:%s" % (os.getenv("PATH"),vars.crm_daemon_dir))
|
|
||||||
+mybinpath = os.path.dirname(sys.argv[0])
|
|
||||||
+for p in mybinpath, vars.crm_daemon_dir:
|
|
||||||
+ if p not in os.environ["PATH"].split(':'):
|
|
||||||
+ os.environ['PATH'] = "%s:%s" % (os.environ['PATH'], p)
|
|
||||||
|
|
||||||
def set_interactive():
|
|
||||||
'''Set the interactive option only if we're on a tty.'''
|
|
@ -1,148 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314872213 -7200
|
|
||||||
# Node ID 9b07d41c73b456e8189fea757a5c3d9e5b32512d
|
|
||||||
# Parent 825cb3e79d7bc1c4ac30468f8c028c9129d00541
|
|
||||||
High: Shell: geo-cluster support commands
|
|
||||||
|
|
||||||
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt
|
|
||||||
+++ b/doc/crm.8.txt
|
|
||||||
@@ -1133,6 +1133,31 @@ Example:
|
|
||||||
status-attr node_1 show pingd
|
|
||||||
...............
|
|
||||||
|
|
||||||
+[[cmdhelp_site,site support]]
|
|
||||||
+=== `site`
|
|
||||||
+
|
|
||||||
+A cluster may consist of two or more subclusters in different and
|
|
||||||
+distant locations. This set of commands supports such setups.
|
|
||||||
+
|
|
||||||
+[[cmdhelp_site_ticket,manage site tickets]]
|
|
||||||
+==== `ticket`
|
|
||||||
+
|
|
||||||
+Tickets are cluster-wide attributes. They can be managed at the
|
|
||||||
+site where this command is executed.
|
|
||||||
+
|
|
||||||
+It is then possible to constrain resources depending on the
|
|
||||||
+ticket availability (see the <<cmdhelp_configure_rsc_ticket,`rsc_ticket`>> command
|
|
||||||
+for more details).
|
|
||||||
+
|
|
||||||
+Usage:
|
|
||||||
+...............
|
|
||||||
+ ticket {grant|revoke|show|time|delete} <ticket>
|
|
||||||
+...............
|
|
||||||
+Example:
|
|
||||||
+...............
|
|
||||||
+ ticket grant ticket1
|
|
||||||
+...............
|
|
||||||
+
|
|
||||||
[[cmdhelp_options,user preferences]]
|
|
||||||
=== `options`
|
|
||||||
|
|
||||||
@@ -1652,6 +1677,8 @@ resource (or resources) if the ticket is
|
|
||||||
either `stop` or `demote` depending on whether a resource is
|
|
||||||
multi-state.
|
|
||||||
|
|
||||||
+See also the <<cmdhelp_site_ticket,`site`>> set of commands.
|
|
||||||
+
|
|
||||||
Usage:
|
|
||||||
...............
|
|
||||||
rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...]
|
|
||||||
diff --git a/shell/modules/completion.py b/shell/modules/completion.py
|
|
||||||
--- a/shell/modules/completion.py
|
|
||||||
+++ b/shell/modules/completion.py
|
|
||||||
@@ -173,6 +173,10 @@ def report_pe_list_peinputs(idx,delimite
|
|
||||||
if delimiter:
|
|
||||||
return ' '
|
|
||||||
return crm_report.peinputs_list() + ["v"]
|
|
||||||
+def ticket_cmd_list(idx,delimiter = False):
|
|
||||||
+ if delimiter:
|
|
||||||
+ return ' '
|
|
||||||
+ return ["grant","revoke","show","time","delete"]
|
|
||||||
|
|
||||||
#
|
|
||||||
# completion for primitives including help for parameters
|
|
||||||
@@ -488,6 +492,9 @@ completer_lists = {
|
|
||||||
"peinputs" : (report_pe_list_peinputs,loop),
|
|
||||||
"transition" : (report_pe_list_transition,),
|
|
||||||
},
|
|
||||||
+ "site" : {
|
|
||||||
+ "ticket" : (ticket_cmd_list,),
|
|
||||||
+ },
|
|
||||||
}
|
|
||||||
def get_completer_list(level,cmd):
|
|
||||||
'Return a list of completer functions.'
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1938,6 +1938,61 @@ Examine Pacemaker's history: node and re
|
|
||||||
crm_report.show_transition_log(f)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
+class Site(UserInterface):
|
|
||||||
+ '''
|
|
||||||
+ The site class
|
|
||||||
+ '''
|
|
||||||
+ lvl_name = "site"
|
|
||||||
+ desc_short = "Geo-cluster support"
|
|
||||||
+ desc_long = """
|
|
||||||
+The site level.
|
|
||||||
+
|
|
||||||
+Geo-cluster related management.
|
|
||||||
+"""
|
|
||||||
+ crm_ticket = {
|
|
||||||
+ 'grant': "crm_ticket -t '%s' -v true",
|
|
||||||
+ 'revoke': "crm_ticket -t '%s' -v false",
|
|
||||||
+ 'delete': "crm_ticket -t '%s' -D",
|
|
||||||
+ 'show': "crm_ticket -t '%s' -G",
|
|
||||||
+ 'time': "crm_ticket -t '%s' -T",
|
|
||||||
+ }
|
|
||||||
+ def __init__(self):
|
|
||||||
+ UserInterface.__init__(self)
|
|
||||||
+ self.cmd_table["ticket"] = (self.ticket,(2,2),1,0)
|
|
||||||
+ def ticket(self, cmd, subcmd, ticket):
|
|
||||||
+ "usage: ticket {grant|revoke|show|time|delete} <ticket>"
|
|
||||||
+ try:
|
|
||||||
+ attr_cmd = self.crm_ticket[subcmd]
|
|
||||||
+ except:
|
|
||||||
+ bad_usage(cmd,'%s %s' % (subcmd, ticket))
|
|
||||||
+ return False
|
|
||||||
+ if not is_name_sane(ticket):
|
|
||||||
+ return False
|
|
||||||
+ if subcmd not in ("show", "time"):
|
|
||||||
+ return ext_cmd(attr_cmd % ticket) == 0
|
|
||||||
+ l = stdout2list(attr_cmd % ticket)
|
|
||||||
+ try:
|
|
||||||
+ val = l[0].split('=')[3]
|
|
||||||
+ except:
|
|
||||||
+ common_warn("apparently nothing to show for ticket %s" % ticket)
|
|
||||||
+ return False
|
|
||||||
+ if subcmd == "show":
|
|
||||||
+ if val == "false":
|
|
||||||
+ print "ticket %s is revoked" % ticket
|
|
||||||
+ elif val == "true":
|
|
||||||
+ print "ticket %s is granted" % ticket
|
|
||||||
+ else:
|
|
||||||
+ common_warn("unexpected value for ticket %s: %s" % (ticket, val))
|
|
||||||
+ return False
|
|
||||||
+ else: # time
|
|
||||||
+ if not is_int(val):
|
|
||||||
+ common_warn("unexpected value for ticket %s: %s" % (ticket, val))
|
|
||||||
+ return False
|
|
||||||
+ if val == "-1":
|
|
||||||
+ print "%s: no such ticket" % ticket
|
|
||||||
+ return False
|
|
||||||
+ print "ticket %s last time granted on %s" % (ticket, time.ctime(int(val)))
|
|
||||||
+
|
|
||||||
class TopLevel(UserInterface):
|
|
||||||
'''
|
|
||||||
The top level.
|
|
||||||
@@ -1959,6 +2014,7 @@ class TopLevel(UserInterface):
|
|
||||||
self.cmd_table['node'] = NodeMgmt
|
|
||||||
self.cmd_table['options'] = CliOptions
|
|
||||||
self.cmd_table['history'] = History
|
|
||||||
+ self.cmd_table['site'] = Site
|
|
||||||
self.cmd_table['status'] = (self.status,(0,5),0,0)
|
|
||||||
self.cmd_table['ra'] = RA
|
|
||||||
setup_aliases(self)
|
|
@ -1,326 +0,0 @@
|
|||||||
# HG changeset patch
|
|
||||||
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
||||||
# Date 1314783705 -7200
|
|
||||||
# Node ID 825cb3e79d7bc1c4ac30468f8c028c9129d00541
|
|
||||||
# Parent f77e52725f2d98c219d8b22208da0b89b3d42112
|
|
||||||
High: Shell: support for rsc_ticket
|
|
||||||
|
|
||||||
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
||||||
--- a/doc/crm.8.txt
|
|
||||||
+++ b/doc/crm.8.txt
|
|
||||||
@@ -1639,6 +1639,34 @@ Example:
|
|
||||||
order o1 inf: A ( B C )
|
|
||||||
...............
|
|
||||||
|
|
||||||
+[[cmdhelp_configure_rsc_ticket,resources ticket dependency]]
|
|
||||||
+==== `rsc_ticket`
|
|
||||||
+
|
|
||||||
+This constraint expresses dependency of resources on cluster-wide
|
|
||||||
+attributes, also known as tickets. Tickets are mainly used in
|
|
||||||
+geo-clusters, which consist of multiple sites. A ticket may be
|
|
||||||
+granted to a site, thus allowing resources to run there.
|
|
||||||
+
|
|
||||||
+The `loss-policy` attribute specifies what happens to the
|
|
||||||
+resource (or resources) if the ticket is revoked. The default is
|
|
||||||
+either `stop` or `demote` depending on whether a resource is
|
|
||||||
+multi-state.
|
|
||||||
+
|
|
||||||
+Usage:
|
|
||||||
+...............
|
|
||||||
+ rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...]
|
|
||||||
+ [loss-policy=<loss_policy_action>]
|
|
||||||
+
|
|
||||||
+ loss_policy_action :: stop | demote | fence | freeze
|
|
||||||
+...............
|
|
||||||
+Example:
|
|
||||||
+...............
|
|
||||||
+ rsc_ticket ticket-A_public-ip ticket-A: public-ip
|
|
||||||
+ rsc_ticket ticket-A_bigdb ticket-A: bigdb loss-policy=fence
|
|
||||||
+ rsc_ticket ticket-B_storage ticket-B: drbd-a:Master drbd-b:Master
|
|
||||||
+...............
|
|
||||||
+
|
|
||||||
+
|
|
||||||
[[cmdhelp_configure_property,set a cluster property]]
|
|
||||||
==== `property`
|
|
||||||
|
|
||||||
diff --git a/shell/modules/cibconfig.py b/shell/modules/cibconfig.py
|
|
||||||
--- a/shell/modules/cibconfig.py
|
|
||||||
+++ b/shell/modules/cibconfig.py
|
|
||||||
@@ -1243,7 +1243,7 @@ class CibSimpleConstraint(CibObject):
|
|
||||||
if node.getElementsByTagName("resource_set"):
|
|
||||||
col = rsc_set_constraint(node,obj_type)
|
|
||||||
else:
|
|
||||||
- col = two_rsc_constraint(node,obj_type)
|
|
||||||
+ col = simple_rsc_constraint(node,obj_type)
|
|
||||||
if not col:
|
|
||||||
return None
|
|
||||||
symm = node.getAttribute("symmetrical")
|
|
||||||
@@ -1264,6 +1264,27 @@ class CibSimpleConstraint(CibObject):
|
|
||||||
remove_id_used_attributes(oldnode)
|
|
||||||
return headnode
|
|
||||||
|
|
||||||
+class CibRscTicket(CibSimpleConstraint):
|
|
||||||
+ '''
|
|
||||||
+ rsc_ticket constraint.
|
|
||||||
+ '''
|
|
||||||
+ def repr_cli_head(self,node):
|
|
||||||
+ obj_type = vars.cib_cli_map[node.tagName]
|
|
||||||
+ node_id = node.getAttribute("id")
|
|
||||||
+ s = cli_display.keyword(obj_type)
|
|
||||||
+ id = cli_display.id(node_id)
|
|
||||||
+ ticket = cli_display.ticket(node.getAttribute("ticket"))
|
|
||||||
+ if node.getElementsByTagName("resource_set"):
|
|
||||||
+ col = rsc_set_constraint(node,obj_type)
|
|
||||||
+ else:
|
|
||||||
+ col = simple_rsc_constraint(node,obj_type)
|
|
||||||
+ if not col:
|
|
||||||
+ return None
|
|
||||||
+ a = node.getAttribute("loss-policy")
|
|
||||||
+ if a:
|
|
||||||
+ col.append("loss-policy=%s" % a)
|
|
||||||
+ return "%s %s %s: %s" % (s,id,ticket,' '.join(col))
|
|
||||||
+
|
|
||||||
class CibProperty(CibObject):
|
|
||||||
'''
|
|
||||||
Cluster properties.
|
|
||||||
@@ -1371,6 +1392,7 @@ cib_object_map = {
|
|
||||||
"rsc_location": ( "location", CibLocation, "constraints" ),
|
|
||||||
"rsc_colocation": ( "colocation", CibSimpleConstraint, "constraints" ),
|
|
||||||
"rsc_order": ( "order", CibSimpleConstraint, "constraints" ),
|
|
||||||
+ "rsc_ticket": ( "rsc_ticket", CibRscTicket, "constraints" ),
|
|
||||||
"cluster_property_set": ( "property", CibProperty, "crm_config", "cib-bootstrap-options" ),
|
|
||||||
"rsc_defaults": ( "rsc_defaults", CibProperty, "rsc_defaults", "rsc-options" ),
|
|
||||||
"op_defaults": ( "op_defaults", CibProperty, "op_defaults", "op-options" ),
|
|
||||||
diff --git a/shell/modules/clidisplay.py b/shell/modules/clidisplay.py
|
|
||||||
--- a/shell/modules/clidisplay.py
|
|
||||||
+++ b/shell/modules/clidisplay.py
|
|
||||||
@@ -62,6 +62,8 @@ class CliDisplay(Singleton):
|
|
||||||
return self.otherword(4, s)
|
|
||||||
def score(self, s):
|
|
||||||
return self.otherword(5, s)
|
|
||||||
+ def ticket(self, s):
|
|
||||||
+ return self.otherword(5, s)
|
|
||||||
|
|
||||||
user_prefs = UserPrefs.getInstance()
|
|
||||||
vars = Vars.getInstance()
|
|
||||||
diff --git a/shell/modules/cliformat.py b/shell/modules/cliformat.py
|
|
||||||
--- a/shell/modules/cliformat.py
|
|
||||||
+++ b/shell/modules/cliformat.py
|
|
||||||
@@ -226,22 +226,25 @@ def rsc_set_constraint(node,obj_type):
|
|
||||||
action = n.getAttribute("action")
|
|
||||||
for r in n.getElementsByTagName("resource_ref"):
|
|
||||||
rsc = cli_display.rscref(r.getAttribute("id"))
|
|
||||||
- q = (obj_type == "colocation") and role or action
|
|
||||||
+ q = (obj_type == "order") and action or role
|
|
||||||
col.append(q and "%s:%s"%(rsc,q) or rsc)
|
|
||||||
cnt += 1
|
|
||||||
if not sequential:
|
|
||||||
col.append(")")
|
|
||||||
- if cnt <= 2: # a degenerate thingie
|
|
||||||
+ if (obj_type != "rsc_ticket" and cnt <= 2) or \
|
|
||||||
+ (obj_type == "rsc_ticket" and cnt <= 1): # a degenerate thingie
|
|
||||||
col.insert(0,"_rsc_set_")
|
|
||||||
return col
|
|
||||||
-def two_rsc_constraint(node,obj_type):
|
|
||||||
+def simple_rsc_constraint(node,obj_type):
|
|
||||||
col = []
|
|
||||||
if obj_type == "colocation":
|
|
||||||
col.append(mkrscrole(node,"rsc"))
|
|
||||||
col.append(mkrscrole(node,"with-rsc"))
|
|
||||||
- else:
|
|
||||||
+ elif obj_type == "order":
|
|
||||||
col.append(mkrscaction(node,"first"))
|
|
||||||
col.append(mkrscaction(node,"then"))
|
|
||||||
+ else: # rsc_ticket
|
|
||||||
+ col.append(mkrscrole(node,"rsc"))
|
|
||||||
return col
|
|
||||||
|
|
||||||
# this pre (or post)-processing is oversimplified
|
|
||||||
diff --git a/shell/modules/completion.py b/shell/modules/completion.py
|
|
||||||
--- a/shell/modules/completion.py
|
|
||||||
+++ b/shell/modules/completion.py
|
|
||||||
@@ -467,6 +467,7 @@ completer_lists = {
|
|
||||||
"location" : (null_list,rsc_id_list),
|
|
||||||
"colocation" : (null_list,null_list,rsc_id_list,loop),
|
|
||||||
"order" : (null_list,null_list,rsc_id_list,loop),
|
|
||||||
+ "rsc_ticket" : (null_list,null_list,rsc_id_list,loop),
|
|
||||||
"property" : (property_complete,loop),
|
|
||||||
"rsc_defaults" : (prim_complete_meta,loop),
|
|
||||||
"op_defaults" : (op_attr_list,loop),
|
|
||||||
diff --git a/shell/modules/parse.py b/shell/modules/parse.py
|
|
||||||
--- a/shell/modules/parse.py
|
|
||||||
+++ b/shell/modules/parse.py
|
|
||||||
@@ -178,6 +178,15 @@ def parse_op(s):
|
|
||||||
head_pl.append(["name",s[0]])
|
|
||||||
return cli_list
|
|
||||||
|
|
||||||
+def cli_parse_ticket(ticket,pl):
|
|
||||||
+ if ticket.endswith(':'):
|
|
||||||
+ ticket = ticket.rstrip(':')
|
|
||||||
+ else:
|
|
||||||
+ syntax_err(ticket, context = 'rsc_ticket')
|
|
||||||
+ return False
|
|
||||||
+ pl.append(["ticket",ticket])
|
|
||||||
+ return True
|
|
||||||
+
|
|
||||||
def cli_parse_score(score,pl,noattr = False):
|
|
||||||
if score.endswith(':'):
|
|
||||||
score = score.rstrip(':')
|
|
||||||
@@ -197,6 +206,7 @@ def cli_parse_score(score,pl,noattr = Fa
|
|
||||||
else:
|
|
||||||
pl.append(["score-attribute",score])
|
|
||||||
return True
|
|
||||||
+
|
|
||||||
def is_binary_op(s):
|
|
||||||
l = s.split(':')
|
|
||||||
if len(l) == 2:
|
|
||||||
@@ -302,13 +312,13 @@ def parse_location(s):
|
|
||||||
return False
|
|
||||||
return cli_list
|
|
||||||
|
|
||||||
-def cli_opt_symmetrical(p,pl):
|
|
||||||
+def cli_opt_attribute(type, p, pl, attr):
|
|
||||||
if not p:
|
|
||||||
return True
|
|
||||||
pl1 = []
|
|
||||||
cli_parse_attr([p],pl1)
|
|
||||||
- if len(pl1) != 1 or not find_value(pl1,"symmetrical"):
|
|
||||||
- syntax_err(p,context = "order")
|
|
||||||
+ if len(pl1) != 1 or not find_value(pl1, attr):
|
|
||||||
+ syntax_err(p,context = type)
|
|
||||||
return False
|
|
||||||
pl += pl1
|
|
||||||
return True
|
|
||||||
@@ -490,7 +500,33 @@ def parse_order(s):
|
|
||||||
resource_set_obj = ResourceSet(type,s[3:],cli_list)
|
|
||||||
if not resource_set_obj.parse():
|
|
||||||
return False
|
|
||||||
- if not cli_opt_symmetrical(symm,head_pl):
|
|
||||||
+ if not cli_opt_attribute(type, symm, head_pl, "symmetrical"):
|
|
||||||
+ return False
|
|
||||||
+ return cli_list
|
|
||||||
+
|
|
||||||
+def parse_rsc_ticket(s):
|
|
||||||
+ cli_list = []
|
|
||||||
+ head_pl = []
|
|
||||||
+ type = "rsc_ticket"
|
|
||||||
+ cli_list.append([s[0],head_pl])
|
|
||||||
+ if len(s) < 4:
|
|
||||||
+ syntax_err(s,context = "rsc_ticket")
|
|
||||||
+ return False
|
|
||||||
+ head_pl.append(["id",s[1]])
|
|
||||||
+ if not cli_parse_ticket(s[2],head_pl):
|
|
||||||
+ return False
|
|
||||||
+ # save loss-policy for later (if it exists)
|
|
||||||
+ loss_policy = ""
|
|
||||||
+ if is_attribute(s[len(s)-1],"loss-policy"):
|
|
||||||
+ loss_policy = s.pop()
|
|
||||||
+ if len(s) == 4:
|
|
||||||
+ if not cli_parse_rsc_role(s[3], head_pl):
|
|
||||||
+ return False
|
|
||||||
+ else:
|
|
||||||
+ resource_set_obj = ResourceSet(type, s[3:], cli_list)
|
|
||||||
+ if not resource_set_obj.parse():
|
|
||||||
+ return False
|
|
||||||
+ if not cli_opt_attribute(type, loss_policy, head_pl, attr = "loss-policy"):
|
|
||||||
return False
|
|
||||||
return cli_list
|
|
||||||
|
|
||||||
@@ -501,6 +537,8 @@ def parse_constraint(s):
|
|
||||||
return parse_colocation(s)
|
|
||||||
elif keyword_cmp(s[0], "order"):
|
|
||||||
return parse_order(s)
|
|
||||||
+ elif keyword_cmp(s[0], "rsc_ticket"):
|
|
||||||
+ return parse_rsc_ticket(s)
|
|
||||||
def parse_property(s):
|
|
||||||
cli_list = []
|
|
||||||
head_pl = []
|
|
||||||
@@ -708,6 +746,7 @@ class CliParser(object):
|
|
||||||
"colocation": (3,parse_constraint),
|
|
||||||
"collocation": (3,parse_constraint),
|
|
||||||
"order": (3,parse_constraint),
|
|
||||||
+ "rsc_ticket": (3,parse_constraint),
|
|
||||||
"monitor": (3,parse_op),
|
|
||||||
"node": (2,parse_node),
|
|
||||||
"property": (2,parse_property),
|
|
||||||
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
||||||
--- a/shell/modules/ui.py.in
|
|
||||||
+++ b/shell/modules/ui.py.in
|
|
||||||
@@ -1400,6 +1400,7 @@ cluster.
|
|
||||||
self.cmd_table["location"] = (self.conf_location,(2,),1,0)
|
|
||||||
self.cmd_table["colocation"] = (self.conf_colocation,(2,),1,0)
|
|
||||||
self.cmd_table["order"] = (self.conf_order,(2,),1,0)
|
|
||||||
+ self.cmd_table["rsc_ticket"] = (self.conf_rsc_ticket,(2,),1,0)
|
|
||||||
self.cmd_table["property"] = (self.conf_property,(1,),1,0)
|
|
||||||
self.cmd_table["rsc_defaults"] = (self.conf_rsc_defaults,(1,),1,0)
|
|
||||||
self.cmd_table["op_defaults"] = (self.conf_op_defaults,(1,),1,0)
|
|
||||||
@@ -1632,6 +1633,10 @@ cluster.
|
|
||||||
"""usage: order <id> score-type: <first-rsc>[:<action>] <then-rsc>[:<action>]
|
|
||||||
[symmetrical=<bool>]"""
|
|
||||||
return self.__conf_object(cmd,*args)
|
|
||||||
+ def conf_rsc_ticket(self,cmd,*args):
|
|
||||||
+ """usage: rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...]
|
|
||||||
+ [loss-policy=<loss_policy_action>]"""
|
|
||||||
+ return self.__conf_object(cmd,*args)
|
|
||||||
def conf_property(self,cmd,*args):
|
|
||||||
"usage: property [$id=<set_id>] <option>=<value>"
|
|
||||||
return self.__conf_object(cmd,*args)
|
|
||||||
diff --git a/shell/modules/vars.py.in b/shell/modules/vars.py.in
|
|
||||||
--- a/shell/modules/vars.py.in
|
|
||||||
+++ b/shell/modules/vars.py.in
|
|
||||||
@@ -53,6 +53,7 @@ class Vars(Singleton):
|
|
||||||
"rsc_location": "location",
|
|
||||||
"rsc_colocation": "colocation",
|
|
||||||
"rsc_order": "order",
|
|
||||||
+ "rsc_ticket": "rsc_ticket",
|
|
||||||
"cluster_property_set": "property",
|
|
||||||
"rsc_defaults": "rsc_defaults",
|
|
||||||
"op_defaults": "op_defaults",
|
|
||||||
@@ -62,13 +63,13 @@ class Vars(Singleton):
|
|
||||||
container_tags = ("group", "clone", "ms", "master")
|
|
||||||
clonems_tags = ("clone", "ms", "master")
|
|
||||||
resource_tags = ("primitive","group","clone","ms","master")
|
|
||||||
- constraint_tags = ("rsc_location","rsc_colocation","rsc_order")
|
|
||||||
+ constraint_tags = ("rsc_location","rsc_colocation","rsc_order","rsc_ticket")
|
|
||||||
constraint_rsc_refs = ("rsc","with-rsc","first","then")
|
|
||||||
children_tags = ("group", "primitive")
|
|
||||||
nvpairs_tags = ("meta_attributes", "instance_attributes", "utilization")
|
|
||||||
defaults_tags = ("rsc_defaults","op_defaults")
|
|
||||||
resource_cli_names = ("primitive","group","clone","ms","master")
|
|
||||||
- constraint_cli_names = ("location","colocation","collocation","order")
|
|
||||||
+ constraint_cli_names = ("location","colocation","collocation","order","rsc_ticket")
|
|
||||||
nvset_cli_names = ("property","rsc_defaults","op_defaults")
|
|
||||||
op_cli_names = ("monitor", "start", "stop", "migrate_to", "migrate_from","promote","demote","notify")
|
|
||||||
ra_operations = ("probe", "monitor", "start", "stop",
|
|
||||||
diff --git a/shell/modules/xmlutil.py b/shell/modules/xmlutil.py
|
|
||||||
--- a/shell/modules/xmlutil.py
|
|
||||||
+++ b/shell/modules/xmlutil.py
|
|
||||||
@@ -520,7 +520,8 @@ def mss(node_list):
|
|
||||||
def constraints(node_list):
|
|
||||||
return filter_on_tag(node_list,"rsc_location") \
|
|
||||||
+ filter_on_tag(node_list,"rsc_colocation") \
|
|
||||||
- + filter_on_tag(node_list,"rsc_order")
|
|
||||||
+ + filter_on_tag(node_list,"rsc_order") \
|
|
||||||
+ + filter_on_tag(node_list,"rsc_ticket")
|
|
||||||
def properties(node_list):
|
|
||||||
return filter_on_tag(node_list,"cluster_property_set") \
|
|
||||||
+ filter_on_tag(node_list,"rsc_defaults") \
|
|
||||||
@@ -562,7 +563,8 @@ def constraints_cli(node_list):
|
|
||||||
return filter_on_type(node_list,"location") \
|
|
||||||
+ filter_on_type(node_list,"colocation") \
|
|
||||||
+ filter_on_type(node_list,"collocation") \
|
|
||||||
- + filter_on_type(node_list,"order")
|
|
||||||
+ + filter_on_type(node_list,"order") \
|
|
||||||
+ + filter_on_type(node_list,"rsc_ticket")
|
|
||||||
def properties_cli(cl):
|
|
||||||
return filter_on_type(cl,"property") \
|
|
||||||
+ filter_on_type(cl,"rsc_defaults") \
|
|
||||||
@@ -601,6 +603,8 @@ def referenced_resources(node):
|
|
||||||
elif xml_obj_type == "rsc_order":
|
|
||||||
node_list = node.getElementsByTagName("first") + \
|
|
||||||
node.getElementsByTagName("then")
|
|
||||||
+ elif xml_obj_type == "rsc_ticket":
|
|
||||||
+ node_list = node.getElementsByTagName("rsc")
|
|
||||||
return [x.getAttribute("id") for x in node_list]
|
|
||||||
|
|
||||||
def rename_id(node,old_id,new_id):
|
|
255
pacemaker-NodeUtilization-RA.diff
Normal file
255
pacemaker-NodeUtilization-RA.diff
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
commit 41ae609accd114bc5d4a05a74a80d3213d217373
|
||||||
|
Author: Dejan Muhamedagic <dejan@suse.de>
|
||||||
|
Date: Fri Nov 25 13:11:15 2011 +0100
|
||||||
|
|
||||||
|
Medium: RA: add NodeUtilization RA
|
||||||
|
|
||||||
|
diff --git a/extra/resources/Makefile.am b/extra/resources/Makefile.am
|
||||||
|
index bc35401..e38d64d 100644
|
||||||
|
--- a/extra/resources/Makefile.am
|
||||||
|
+++ b/extra/resources/Makefile.am
|
||||||
|
@@ -32,7 +32,8 @@ ocf_SCRIPTS = ClusterMon \
|
||||||
|
pingd \
|
||||||
|
Stateful \
|
||||||
|
SysInfo \
|
||||||
|
- SystemHealth
|
||||||
|
+ SystemHealth \
|
||||||
|
+ NodeUtilization
|
||||||
|
|
||||||
|
if BUILD_XML_HELP
|
||||||
|
man7_MANS = $(ocf_SCRIPTS:%=ocf_pacemaker_%.7)
|
||||||
|
diff --git a/extra/resources/NodeUtilization b/extra/resources/NodeUtilization
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..a2a17c6
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/extra/resources/NodeUtilization
|
||||||
|
@@ -0,0 +1,229 @@
|
||||||
|
+#!/bin/sh
|
||||||
|
+#
|
||||||
|
+#
|
||||||
|
+# NodeUtilization OCF Resource Agent
|
||||||
|
+#
|
||||||
|
+# Copyright (c) 2011 SUSE LINUX, John Shi
|
||||||
|
+# All Rights Reserved.
|
||||||
|
+#
|
||||||
|
+# This program is free software; you can redistribute it and/or modify
|
||||||
|
+# it under the terms of version 2 of the GNU General Public License as
|
||||||
|
+# published by the Free Software Foundation.
|
||||||
|
+#
|
||||||
|
+# This program is distributed in the hope that it would be useful, but
|
||||||
|
+# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
+#
|
||||||
|
+# Further, this software is distributed without any warranty that it is
|
||||||
|
+# free of the rightful claim of any third person regarding infringement
|
||||||
|
+# or the like. Any license provided herein, whether implied or
|
||||||
|
+# otherwise, applies only to this software file. Patent licenses, if
|
||||||
|
+# any, provided herein do not apply to combinations of this program with
|
||||||
|
+# other software, or any other product whatsoever.
|
||||||
|
+#
|
||||||
|
+# You should have received a copy of the GNU General Public License
|
||||||
|
+# along with this program; if not, write the Free Software Foundation,
|
||||||
|
+# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
+#
|
||||||
|
+#######################################################################
|
||||||
|
+# Initialization:
|
||||||
|
+
|
||||||
|
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||||
|
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||||
|
+
|
||||||
|
+#######################################################################
|
||||||
|
+
|
||||||
|
+meta_data() {
|
||||||
|
+ cat <<END
|
||||||
|
+<?xml version="1.0"?>
|
||||||
|
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||||
|
+<resource-agent name="NodeUtilization">
|
||||||
|
+<version>1.0</version>
|
||||||
|
+
|
||||||
|
+<longdesc lang="en">
|
||||||
|
+This is an NodeUtilization Resource Agent.
|
||||||
|
+This agent detects system parameters and put them into CIB by crm_attribute,
|
||||||
|
+and it runs on every node as clone resource.
|
||||||
|
+</longdesc>
|
||||||
|
+<shortdesc lang="en">NodeUtilization resource agent</shortdesc>
|
||||||
|
+
|
||||||
|
+<parameters>
|
||||||
|
+<parameter name="dynamic" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">
|
||||||
|
+If set, some of the HA parameters will be reset if there are
|
||||||
|
+difference between HA parameters and system parameters when HA monitor.
|
||||||
|
+Otherwise, the HA parameters will be set once when the resource instance starts.
|
||||||
|
+</longdesc>
|
||||||
|
+<shortdesc lang="en">Set HA parameters when start or monitor</shortdesc>
|
||||||
|
+<content type="boolean" default="true" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_cpu" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">Enable setting cpu utilization.</longdesc>
|
||||||
|
+<shortdesc lang="en">Enable setting cpu utilization.</shortdesc>
|
||||||
|
+<content type="boolean" default="true" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_cpu_reservation" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">CPU reserved for non-HA related usage.</longdesc>
|
||||||
|
+<shortdesc lang="en">CPU reserved for non-HA related usage.</shortdesc>
|
||||||
|
+<content type="integer" default="1" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_host_memory" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">Enable setting memory utilization of host.</longdesc>
|
||||||
|
+<shortdesc lang="en">Enable setting memory utilization of host.</shortdesc>
|
||||||
|
+<content type="boolean" default="true" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_host_memory_reservation" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">Memory reserved for other services inside host, in MB.</longdesc>
|
||||||
|
+<shortdesc lang="en">Memory reserved for other services inside host, in MB.</shortdesc>
|
||||||
|
+<content type="integer" default="512" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_hv_memory" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">Enable setting the memory utilization of hypervisor.</longdesc>
|
||||||
|
+<shortdesc lang="en">Enable setting the memory utilization of hypervisor.</shortdesc>
|
||||||
|
+<content type="boolean" default="true" />
|
||||||
|
+</parameter>
|
||||||
|
+
|
||||||
|
+<parameter name="utilization_hv_memory_reservation" unique="0" required="0">
|
||||||
|
+<longdesc lang="en">Memory reserved for the hypervisor, in MB.</longdesc>
|
||||||
|
+<shortdesc lang="en">Memory reserved for the hypervisor, in MB.</shortdesc>
|
||||||
|
+<content type="integer" default="512" />
|
||||||
|
+</parameter>
|
||||||
|
+</parameters>
|
||||||
|
+
|
||||||
|
+<actions>
|
||||||
|
+<action name="start" timeout="90" />
|
||||||
|
+<action name="stop" timeout="100" />
|
||||||
|
+<action name="monitor" timeout="20s" interval="60s"/>
|
||||||
|
+<action name="meta-data" timeout="5" />
|
||||||
|
+<action name="validate-all" timeout="30" />
|
||||||
|
+</actions>
|
||||||
|
+</resource-agent>
|
||||||
|
+END
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+set_utilization() {
|
||||||
|
+ host_name="$(hostname)"
|
||||||
|
+
|
||||||
|
+ if ocf_is_true "$OCF_RESKEY_utilization_cpu"; then
|
||||||
|
+ sys_cpu=$(( $(grep -c processor /proc/cpuinfo) - $OCF_RESKEY_utilization_cpu_reservation ))
|
||||||
|
+ uti_cpu=$(crm_attribute -Q -t nodes -U "$host_name" -z -n cpu 2>/dev/null)
|
||||||
|
+
|
||||||
|
+ if [ "$sys_cpu" != "$uti_cpu" ]; then
|
||||||
|
+ if ! crm_attribute -t nodes -U "$host_name" -z -n cpu -v $sys_cpu; then
|
||||||
|
+ ocf_log err "Failed to set cpu of utilization by crm_attribute."
|
||||||
|
+ return 1
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ if ocf_is_true "$OCF_RESKEY_utilization_host_memory"; then
|
||||||
|
+ sys_mem=$(( $(awk '/MemTotal/{printf("%d\n",$2/1024);exit(0)}' /proc/meminfo) - $OCF_RESKEY_utilization_host_memory_reservation ))
|
||||||
|
+ uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n host_memory 2>/dev/null)
|
||||||
|
+
|
||||||
|
+ if [ "$sys_mem" != "$uti_mem" ]; then
|
||||||
|
+ if ! crm_attribute -t nodes -U "$host_name" -z -n host_memory -v $sys_mem; then
|
||||||
|
+ ocf_log err "Failed to set host_memory of utilization by crm_attribute."
|
||||||
|
+ return 1
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ if [ -x /usr/sbin/xm ]; then
|
||||||
|
+ if ocf_is_true "$OCF_RESKEY_utilization_hv_memory"; then
|
||||||
|
+ hv_mem=$(( $(xm info | awk '/total_memory/{printf("%d\n",$3);exit(0)}') - $OCF_RESKEY_utilization_hv_memory_reservation ))
|
||||||
|
+ uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n hv_memory 2>/dev/null)
|
||||||
|
+
|
||||||
|
+ if [ "$hv_mem" != "$uti_mem" ]; then
|
||||||
|
+ if ! crm_attribute -t nodes -U "$host_name" -z -n hv_memory -v $hv_mem; then
|
||||||
|
+ ocf_log err "Failed to set hv_memory of utilization by crm_attribute."
|
||||||
|
+ return 1
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NodeUtilization_usage() {
|
||||||
|
+ cat <<END
|
||||||
|
+usage: $0 {start|stop|monitor|validate-all|meta-data}
|
||||||
|
+
|
||||||
|
+Expects to have a fully populated OCF RA-compliant environment set.
|
||||||
|
+END
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NodeUtilization_start() {
|
||||||
|
+ if ! touch "$OCF_RESKEY_pidfile"; then
|
||||||
|
+ ocf_log err "Failed to touch pidfile: ${OCF_RESKEY_pidfile}."
|
||||||
|
+ exit $OCF_ERR_GENERIC
|
||||||
|
+ fi
|
||||||
|
+ if ! ocf_is_true "$OCF_RESKEY_dynamic"; then
|
||||||
|
+ if ! set_utilization; then
|
||||||
|
+ exit $OCF_ERR_GENERIC
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NodeUtilization_stop() {
|
||||||
|
+ rm -f $OCF_RESKEY_pidfile
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NodeUtilization_monitor() {
|
||||||
|
+ if [ ! -f $OCF_RESKEY_pidfile ]; then
|
||||||
|
+ exit $OCF_NOT_RUNNING
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ if ocf_is_true "$OCF_RESKEY_dynamic"; then
|
||||||
|
+ if ! set_utilization; then
|
||||||
|
+ exit $OCF_ERR_GENERIC
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+NodeUtilization_validate() {
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+: ${OCF_RESKEY_pidfile:="$HA_VARRUN/NodeUtilization-${OCF_RESOURCE_INSTANCE}"}
|
||||||
|
+: ${OCF_RESKEY_dynamic:="true"}
|
||||||
|
+: ${OCF_RESKEY_utilization_cpu:="true"}
|
||||||
|
+: ${OCF_RESKEY_utilization_cpu_reservation="1"}
|
||||||
|
+: ${OCF_RESKEY_utilization_hv_memory:="true"}
|
||||||
|
+: ${OCF_RESKEY_utilization_hv_memory_reservation="512"}
|
||||||
|
+: ${OCF_RESKEY_utilization_host_memory:="true"}
|
||||||
|
+: ${OCF_RESKEY_utilization_host_memory_reservation="512"}
|
||||||
|
+
|
||||||
|
+if [ $# -ne 1 ]; then
|
||||||
|
+ NodeUtilization_usage
|
||||||
|
+ exit $OCF_ERR_ARGS
|
||||||
|
+fi
|
||||||
|
+
|
||||||
|
+case $__OCF_ACTION in
|
||||||
|
+meta-data) meta_data
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+ ;;
|
||||||
|
+start) NodeUtilization_start
|
||||||
|
+ ;;
|
||||||
|
+stop) NodeUtilization_stop
|
||||||
|
+ ;;
|
||||||
|
+monitor) NodeUtilization_monitor
|
||||||
|
+ ;;
|
||||||
|
+validate-all) NodeUtilization_validate
|
||||||
|
+ ;;
|
||||||
|
+usage|help) NodeUtilization_usage
|
||||||
|
+ exit $OCF_SUCCESS
|
||||||
|
+ ;;
|
||||||
|
+*) NodeUtilization_usage
|
||||||
|
+ exit $OCF_ERR_UNIMPLEMENTED
|
||||||
|
+ ;;
|
||||||
|
+esac
|
||||||
|
+
|
||||||
|
+exit $?
|
55
pacemaker-rsc_ticket-schema.diff
Normal file
55
pacemaker-rsc_ticket-schema.diff
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
commit dc88c1f8402e1c978bb4d7816f79a902cf476a08
|
||||||
|
Author: Gao,Yan <ygao@suse.com>
|
||||||
|
Date: Wed Oct 26 17:36:30 2011 +0800
|
||||||
|
|
||||||
|
Medium: xml: Add rsc_ticket support into "pacemaker-1.2" schema
|
||||||
|
|
||||||
|
diff --git a/xml/constraints-1.2.rng b/xml/constraints-1.2.rng
|
||||||
|
index 84708aa..e4b9d80 100644
|
||||||
|
--- a/xml/constraints-1.2.rng
|
||||||
|
+++ b/xml/constraints-1.2.rng
|
||||||
|
@@ -11,6 +11,7 @@
|
||||||
|
<ref name="element-location"/>
|
||||||
|
<ref name="element-colocation"/>
|
||||||
|
<ref name="element-order"/>
|
||||||
|
+ <ref name="element-rsc_ticket"/>
|
||||||
|
</choice>
|
||||||
|
</zeroOrMore>
|
||||||
|
</define>
|
||||||
|
@@ -143,6 +144,36 @@
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
|
+ <define name="element-rsc_ticket">
|
||||||
|
+ <element name="rsc_ticket">
|
||||||
|
+ <attribute name="id"><data type="ID"/></attribute>
|
||||||
|
+ <choice>
|
||||||
|
+ <oneOrMore>
|
||||||
|
+ <ref name="element-resource-set"/>
|
||||||
|
+ </oneOrMore>
|
||||||
|
+ <group>
|
||||||
|
+ <attribute name="rsc"><data type="IDREF"/></attribute>
|
||||||
|
+ <optional>
|
||||||
|
+ <attribute name="rsc-role">
|
||||||
|
+ <ref name="attribute-roles"/>
|
||||||
|
+ </attribute>
|
||||||
|
+ </optional>
|
||||||
|
+ </group>
|
||||||
|
+ </choice>
|
||||||
|
+ <attribute name="ticket"><text/></attribute>
|
||||||
|
+ <optional>
|
||||||
|
+ <attribute name="loss-policy">
|
||||||
|
+ <choice>
|
||||||
|
+ <value>stop</value>
|
||||||
|
+ <value>demote</value>
|
||||||
|
+ <value>fence</value>
|
||||||
|
+ <value>freeze</value>
|
||||||
|
+ </choice>
|
||||||
|
+ </attribute>
|
||||||
|
+ </optional>
|
||||||
|
+ </element>
|
||||||
|
+ </define>
|
||||||
|
+
|
||||||
|
<define name="attribute-actions">
|
||||||
|
<choice>
|
||||||
|
<value>start</value>
|
63
pacemaker-template-schema.diff
Normal file
63
pacemaker-template-schema.diff
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
commit 288cbadc532f1256129d1fcef5716ac1eb7d4bde
|
||||||
|
Author: Gao,Yan <ygao@suse.com>
|
||||||
|
Date: Wed Oct 26 17:45:03 2011 +0800
|
||||||
|
|
||||||
|
Medium: xml: Add resource template support into "pacemaker-1.2" schema
|
||||||
|
|
||||||
|
diff --git a/xml/resources-1.2.rng b/xml/resources-1.2.rng
|
||||||
|
index d2fe1a8..d295b2a 100644
|
||||||
|
--- a/xml/resources-1.2.rng
|
||||||
|
+++ b/xml/resources-1.2.rng
|
||||||
|
@@ -9,6 +9,7 @@
|
||||||
|
<zeroOrMore>
|
||||||
|
<choice>
|
||||||
|
<ref name="element-primitive"/>
|
||||||
|
+ <ref name="element-template"/>
|
||||||
|
<ref name="element-group"/>
|
||||||
|
<ref name="element-clone"/>
|
||||||
|
<ref name="element-master"/>
|
||||||
|
@@ -22,6 +23,44 @@
|
||||||
|
<attribute name="id"><data type="ID"/></attribute>
|
||||||
|
<choice>
|
||||||
|
<group>
|
||||||
|
+ <choice>
|
||||||
|
+ <group>
|
||||||
|
+ <attribute name="class"><value>ocf</value></attribute>
|
||||||
|
+ <attribute name="provider"><text/></attribute>
|
||||||
|
+ </group>
|
||||||
|
+ <attribute name="class">
|
||||||
|
+ <choice>
|
||||||
|
+ <value>lsb</value>
|
||||||
|
+ <value>heartbeat</value>
|
||||||
|
+ <value>stonith</value>
|
||||||
|
+ <value>upstart</value>
|
||||||
|
+ </choice>
|
||||||
|
+ </attribute>
|
||||||
|
+ </choice>
|
||||||
|
+ <attribute name="type"><text/></attribute>
|
||||||
|
+ </group>
|
||||||
|
+ <attribute name="template"><data type="IDREF"/></attribute>
|
||||||
|
+ </choice>
|
||||||
|
+ <optional>
|
||||||
|
+ <attribute name="description"><text/></attribute>
|
||||||
|
+ </optional>
|
||||||
|
+ <ref name="element-resource-extra"/>
|
||||||
|
+ <ref name="element-operations"/>
|
||||||
|
+ <zeroOrMore>
|
||||||
|
+ <element name="utilization">
|
||||||
|
+ <externalRef href="nvset.rng"/>
|
||||||
|
+ </element>
|
||||||
|
+ </zeroOrMore>
|
||||||
|
+ </interleave>
|
||||||
|
+ </element>
|
||||||
|
+ </define>
|
||||||
|
+
|
||||||
|
+ <define name="element-template">
|
||||||
|
+ <element name="template">
|
||||||
|
+ <interleave>
|
||||||
|
+ <attribute name="id"><data type="ID"/></attribute>
|
||||||
|
+ <choice>
|
||||||
|
+ <group>
|
||||||
|
<attribute name="class"><value>ocf</value></attribute>
|
||||||
|
<attribute name="provider"><text/></attribute>
|
||||||
|
</group>
|
@ -1,3 +1,33 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Fri Dec 16 04:42:38 UTC 2011 - tserong@suse.com
|
||||||
|
|
||||||
|
- RA: add NodeUtilization
|
||||||
|
- stonith-ng: export stonith resource name to stonith agents
|
||||||
|
- crmd: Send out all of the meta parameters to lrmd for stop action
|
||||||
|
- RA: Fix the metadata of HealthSMART and SysInfo RAs
|
||||||
|
- stonith: Longer default timeout/interval of operations for stonith
|
||||||
|
resources
|
||||||
|
- Doc: many proof-reading improvements
|
||||||
|
- stonith: Fix the stonith timeout issue (cl#5009, bnc#727498)
|
||||||
|
- update the license information in pacemaker.spec (bnc#726795)
|
||||||
|
- xml: Add rsc_ticket support into "pacemaker-1.2" schema
|
||||||
|
- xml: Add resource template support into "pacemaker-1.2" schema
|
||||||
|
- tools: Avoid problems caused by differences between node name and
|
||||||
|
uname -n
|
||||||
|
- PE: Resolve memory leak when retrieving failure counts
|
||||||
|
- Stonith: Implement a manual override for when nodes are known to be
|
||||||
|
safely off
|
||||||
|
- PE: Implement limit number of concurrent live migrations (FATE#310118)
|
||||||
|
- PE: Implement referencing templates in constraints
|
||||||
|
- PE: Move master based on failure of colocated group
|
||||||
|
- Fencing: Support admin configurable timeouts for API operations
|
||||||
|
- Fencing: Support checking in-progress operations for all nodes
|
||||||
|
- don't package crm shell code
|
||||||
|
- add Requires: crmsh
|
||||||
|
- Build man pages and html versions (bnc#723680)
|
||||||
|
- Shell: template support
|
||||||
|
- Upstream version cs: b988976485d15cb702c9307df55512d323831a5e
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Sun Nov 20 06:47:28 UTC 2011 - coolo@suse.com
|
Sun Nov 20 06:47:28 UTC 2011 - coolo@suse.com
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
# Please submit bugfixes or comments via http://bugs.opensuse.org/
|
# Please submit bugfixes or comments via http://bugs.opensuse.org/
|
||||||
#
|
#
|
||||||
|
|
||||||
# norootforbuild
|
|
||||||
|
|
||||||
%global pcmk_docdir %{_docdir}/%{name}
|
%global pcmk_docdir %{_docdir}/%{name}
|
||||||
%if 0%{?suse_version}
|
%if 0%{?suse_version}
|
||||||
@ -38,48 +37,51 @@
|
|||||||
|
|
||||||
Name: pacemaker
|
Name: pacemaker
|
||||||
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
||||||
|
License: GPL-2.0+ ; LGPL-2.1+
|
||||||
|
Group: Productivity/Clustering/HA
|
||||||
Version: 1.1.6
|
Version: 1.1.6
|
||||||
Release: 0
|
Release: 0
|
||||||
License: GPL-2.0+ ; LGPL-2.1+
|
|
||||||
Url: http://www.clusterlabs.org
|
Url: http://www.clusterlabs.org
|
||||||
Group: Productivity/Clustering/HA
|
|
||||||
Source: pacemaker.tar.bz2
|
Source: pacemaker.tar.bz2
|
||||||
Source2: %{doc_pkg}.tar.gz
|
Source2: %{doc_pkg}.tar.gz
|
||||||
Source100: pacemaker.rpmlintrc
|
Source100: pacemaker.rpmlintrc
|
||||||
Patch1: pacemaker-cts-startcmd.patch
|
Patch1: pacemaker-cts-startcmd.patch
|
||||||
Patch2: acl_fix_d44ff2711662.patch
|
Patch2: rm_crmsh.patch
|
||||||
Patch10: crm_history.patch
|
Patch3: pacemaker-rsc_ticket-schema.diff
|
||||||
Patch11: crm_history_peinputs.patch
|
Patch4: pacemaker-template-schema.diff
|
||||||
Patch12: crm_history_pssh.patch
|
Patch5: bug-728579_pacemaker-stonith-dev-id.diff
|
||||||
Patch13: crm_history_1_d0359dca5dba.patch
|
Patch6: pacemaker-NodeUtilization-RA.diff
|
||||||
Patch14: crm_history_2_29fd4f04c01f.patch
|
|
||||||
Patch15: crm_history_3_b3a014c0f85b.patch
|
|
||||||
Patch16: crm_history_4_a09974a06cdf.patch
|
|
||||||
Patch17: crm_history_5_c3068d22de72.patch
|
|
||||||
Patch18: crm_history-fix-hb_report-limit.patch
|
|
||||||
Patch19: crm_history_6_441f4448eba6.patch
|
|
||||||
Patch20: crm_history_7_3f3c348aaaed.patch
|
|
||||||
Patch21: crm_history_8_3681d3471fde.patch
|
|
||||||
Patch22: crm_path_bnc712605.patch
|
|
||||||
Patch23: crm_deleteunmanaged.patch
|
|
||||||
Patch24: crm_lrmsecrets_3a81b7eae666.patch
|
|
||||||
Patch25: crm_history_9_709ef91cfada.patch
|
|
||||||
Patch26: crm_history_10_d21f988a419c.patch
|
|
||||||
Patch27: crm_history_11_ccd0c1e1edf9.patch
|
|
||||||
Patch28: crm_pager_f77e52725f2d.patch
|
|
||||||
Patch29: crm_tickets_825cb3e79d7b.patch
|
|
||||||
Patch30: crm_site_9b07d41c73b4.patch
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
AutoReqProv: on
|
|
||||||
Conflicts: heartbeat < 3.0
|
Conflicts: heartbeat < 3.0
|
||||||
# We need libglue2, not libheartbeat2
|
# We need libglue2, not libheartbeat2
|
||||||
Conflicts: libheartbeat2 < 3.0.0
|
Conflicts: libheartbeat2 < 3.0.0
|
||||||
PreReq: cluster-glue >= 1.0.6
|
PreReq: cluster-glue >= 1.0.6
|
||||||
Requires: resource-agents openais python python-xml
|
Requires: resource-agents openais python python-xml
|
||||||
Requires: libpacemaker3 = %{version}-%{release} python-curses
|
Requires: libpacemaker3 = %{version}-%{release} python-curses
|
||||||
BuildRequires: e2fsprogs-devel glib2-devel gnutls-devel libesmtp-devel libglue-devel libtool libxml2-devel libxslt-devel ncurses-devel net-snmp-devel pam-devel pkgconfig python-devel resource-agents swig
|
Recommends: crmsh
|
||||||
|
BuildRequires: asciidoc
|
||||||
|
BuildRequires: e2fsprogs-devel
|
||||||
|
BuildRequires: glib2-devel
|
||||||
|
BuildRequires: gnutls-devel
|
||||||
|
BuildRequires: libesmtp-devel
|
||||||
|
BuildRequires: libglue-devel
|
||||||
|
BuildRequires: libtool
|
||||||
|
BuildRequires: libxml2-devel
|
||||||
|
BuildRequires: libxslt-devel
|
||||||
|
BuildRequires: ncurses-devel
|
||||||
|
BuildRequires: net-snmp-devel
|
||||||
|
BuildRequires: pam-devel
|
||||||
|
BuildRequires: pkgconfig
|
||||||
|
BuildRequires: python-devel
|
||||||
|
BuildRequires: resource-agents
|
||||||
|
BuildRequires: swig
|
||||||
%if %with_regression_tests
|
%if %with_regression_tests
|
||||||
BuildRequires: openais procps python python-curses python-xml vim-base
|
BuildRequires: openais
|
||||||
|
BuildRequires: procps
|
||||||
|
BuildRequires: python
|
||||||
|
BuildRequires: python-curses
|
||||||
|
BuildRequires: python-xml
|
||||||
|
BuildRequires: vim-base
|
||||||
%endif
|
%endif
|
||||||
%if %with_ais_support
|
%if %with_ais_support
|
||||||
BuildRequires: libcorosync-devel
|
BuildRequires: libcorosync-devel
|
||||||
@ -93,7 +95,6 @@ Requires: heartbeat
|
|||||||
BuildRequires: libbz2-devel
|
BuildRequires: libbz2-devel
|
||||||
Suggests: graphviz
|
Suggests: graphviz
|
||||||
Recommends: libdlm resource-agents
|
Recommends: libdlm resource-agents
|
||||||
Recommends: python-pssh
|
|
||||||
%if 0%{?suse_version} > 1100
|
%if 0%{?suse_version} > 1100
|
||||||
BuildRequires: docbook-xsl-stylesheets
|
BuildRequires: docbook-xsl-stylesheets
|
||||||
%endif
|
%endif
|
||||||
@ -123,8 +124,8 @@ Authors:
|
|||||||
Andrew Beekhof <abeekhof@suse.de>
|
Andrew Beekhof <abeekhof@suse.de>
|
||||||
|
|
||||||
%package -n libpacemaker3
|
%package -n libpacemaker3
|
||||||
License: GPL-2.0+ ; LGPL-2.1+
|
|
||||||
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
||||||
|
License: GPL-2.0+ ; LGPL-2.1+
|
||||||
Group: Productivity/Clustering/HA
|
Group: Productivity/Clustering/HA
|
||||||
|
|
||||||
%description -n libpacemaker3
|
%description -n libpacemaker3
|
||||||
@ -145,8 +146,8 @@ Authors:
|
|||||||
Andrew Beekhof <abeekhof@suse.de>
|
Andrew Beekhof <abeekhof@suse.de>
|
||||||
|
|
||||||
%package -n libpacemaker-devel
|
%package -n libpacemaker-devel
|
||||||
License: GPL-2.0 ; GPL-2.0+ ; LGPL-2.1+
|
|
||||||
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
Summary: The Pacemaker scalable High-Availability cluster resource manager
|
||||||
|
License: GPL-2.0 ; GPL-2.0+ ; LGPL-2.1+
|
||||||
Group: Development/Libraries/C and C++
|
Group: Development/Libraries/C and C++
|
||||||
Requires: %{name} = %{version}-%{release}
|
Requires: %{name} = %{version}-%{release}
|
||||||
Requires: libpacemaker3 = %{version}-%{release}
|
Requires: libpacemaker3 = %{version}-%{release}
|
||||||
@ -179,28 +180,11 @@ Authors:
|
|||||||
###########################################################
|
###########################################################
|
||||||
%setup -a 2 -n pacemaker -q
|
%setup -a 2 -n pacemaker -q
|
||||||
%patch1 -p1
|
%patch1 -p1
|
||||||
%patch2 -p1 -R
|
%patch2 -p1
|
||||||
%patch10 -p1
|
%patch3 -p1
|
||||||
%patch11 -p1
|
%patch4 -p1
|
||||||
%patch12 -p1
|
%patch5 -p1
|
||||||
%patch13 -p1
|
%patch6 -p1
|
||||||
%patch14 -p1
|
|
||||||
%patch15 -p1
|
|
||||||
%patch16 -p1
|
|
||||||
%patch17 -p1
|
|
||||||
%patch18 -p1
|
|
||||||
%patch19 -p1
|
|
||||||
%patch20 -p1
|
|
||||||
%patch21 -p1
|
|
||||||
%patch22 -p1
|
|
||||||
%patch23 -p1
|
|
||||||
%patch24 -p1
|
|
||||||
%patch25 -p1
|
|
||||||
%patch26 -p1
|
|
||||||
%patch27 -p1
|
|
||||||
%patch28 -p1
|
|
||||||
%patch29 -p1
|
|
||||||
%patch30 -p1
|
|
||||||
###########################################################
|
###########################################################
|
||||||
|
|
||||||
%build
|
%build
|
||||||
@ -241,6 +225,10 @@ rm $RPM_BUILD_ROOT/%{_libdir}/service_crm.so
|
|||||||
# Don't want to ship this just yet:
|
# Don't want to ship this just yet:
|
||||||
rm $RPM_BUILD_ROOT/etc/init.d/pacemaker || true
|
rm $RPM_BUILD_ROOT/etc/init.d/pacemaker || true
|
||||||
rm $RPM_BUILD_ROOT/usr/sbin/pacemaker{d,} || true
|
rm $RPM_BUILD_ROOT/usr/sbin/pacemaker{d,} || true
|
||||||
|
rm $RPM_BUILD_ROOT/usr/bin/ccs2cib || true
|
||||||
|
rm $RPM_BUILD_ROOT/usr/bin/ccs_flatten || true
|
||||||
|
rm $RPM_BUILD_ROOT/usr/bin/disable_rgmanager || true
|
||||||
|
rm $RPM_BUILD_ROOT/usr/sbin/fence_pcmk || true
|
||||||
|
|
||||||
%if %with_gcov
|
%if %with_gcov
|
||||||
GCOV_BASE=$RPM_BUILD_ROOT/%{_var}/lib/pacemaker/gcov
|
GCOV_BASE=$RPM_BUILD_ROOT/%{_var}/lib/pacemaker/gcov
|
||||||
@ -312,7 +300,6 @@ fi
|
|||||||
%{_sbindir}/crm_failcount
|
%{_sbindir}/crm_failcount
|
||||||
%{_sbindir}/crm_master
|
%{_sbindir}/crm_master
|
||||||
%{_sbindir}/crm_mon
|
%{_sbindir}/crm_mon
|
||||||
%{_sbindir}/crm
|
|
||||||
%{_sbindir}/crm_resource
|
%{_sbindir}/crm_resource
|
||||||
%{_sbindir}/crm_report
|
%{_sbindir}/crm_report
|
||||||
%{_sbindir}/crm_standby
|
%{_sbindir}/crm_standby
|
||||||
@ -328,7 +315,6 @@ fi
|
|||||||
%{_sbindir}/crm_simulate
|
%{_sbindir}/crm_simulate
|
||||||
%{_sbindir}/fence_legacy
|
%{_sbindir}/fence_legacy
|
||||||
%{_sbindir}/stonith_admin
|
%{_sbindir}/stonith_admin
|
||||||
%{py_sitedir}/crm
|
|
||||||
|
|
||||||
%dir %attr (750, %{uname}, %{gname}) %{_var}/lib/heartbeat/crm
|
%dir %attr (750, %{uname}, %{gname}) %{_var}/lib/heartbeat/crm
|
||||||
%dir %attr (750, %{uname}, %{gname}) %{_var}/lib/pengine
|
%dir %attr (750, %{uname}, %{gname}) %{_var}/lib/pengine
|
||||||
@ -353,8 +339,7 @@ fi
|
|||||||
%exclude %{pcmk_docdir}/COPYING
|
%exclude %{pcmk_docdir}/COPYING
|
||||||
%exclude %{pcmk_docdir}/COPYING.LIB
|
%exclude %{pcmk_docdir}/COPYING.LIB
|
||||||
%exclude %{_libdir}/pkgconfig
|
%exclude %{_libdir}/pkgconfig
|
||||||
%doc %{pcmk_docdir}
|
%doc %{pcmk_docdir}/*.html
|
||||||
# %doc %{pcmk_docdir}/*.html
|
|
||||||
%doc %{_mandir}/man8/*.8*
|
%doc %{_mandir}/man8/*.8*
|
||||||
%doc %{_mandir}/man7/*.7*
|
%doc %{_mandir}/man7/*.7*
|
||||||
%doc %{pcmk_docdir}/README.hb2openais
|
%doc %{pcmk_docdir}/README.hb2openais
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:148fdba7b16d81529ad9923bfe94241487e9a143753b785583d1850eaa902bb6
|
oid sha256:b6f240cd8995b416aa0bab067137a44025ced19d318f5d489505d4e6c097e8a5
|
||||||
size 15452016
|
size 7754006
|
||||||
|
74
rm_crmsh.patch
Normal file
74
rm_crmsh.patch
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# HG changeset patch
|
||||||
|
# Parent 9971ebba4494012a93c03b40a2c58ec0eb60f50c
|
||||||
|
build: remove crm shell
|
||||||
|
|
||||||
|
diff -r 9971ebba4494 Makefile.am
|
||||||
|
--- a/Makefile.am Wed Aug 31 11:02:11 2011 +1000
|
||||||
|
+++ b/Makefile.am Wed Oct 19 14:44:33 2011 +0200
|
||||||
|
@@ -23,7 +23,7 @@ EXTRA_DIST = autogen.sh Con
|
||||||
|
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure DRF/config-h.in \
|
||||||
|
DRF/stamp-h.in libtool.m4 ltdl.m4 libltdl.tar
|
||||||
|
|
||||||
|
-CORE = $(LIBLTDL_DIR) replace include lib mcp pengine cib crmd fencing tools shell xml
|
||||||
|
+CORE = $(LIBLTDL_DIR) replace include lib mcp pengine cib crmd fencing tools xml
|
||||||
|
SUBDIRS = $(CORE) cts extra doc
|
||||||
|
|
||||||
|
doc_DATA = AUTHORS COPYING COPYING.LIB
|
||||||
|
diff -r 9971ebba4494 configure.ac
|
||||||
|
--- a/configure.ac Wed Aug 31 11:02:11 2011 +1000
|
||||||
|
+++ b/configure.ac Wed Oct 19 14:44:33 2011 +0200
|
||||||
|
@@ -1686,15 +1686,6 @@ tools/Makefile \
|
||||||
|
tools/coverage.sh \
|
||||||
|
tools/hb2openais.sh \
|
||||||
|
tools/crm_primitive.py \
|
||||||
|
-shell/Makefile \
|
||||||
|
- shell/templates/Makefile \
|
||||||
|
- shell/regression/Makefile \
|
||||||
|
- shell/regression/testcases/Makefile \
|
||||||
|
- shell/modules/Makefile \
|
||||||
|
- shell/modules/ui.py \
|
||||||
|
- shell/modules/ra.py \
|
||||||
|
- shell/modules/vars.py \
|
||||||
|
- shell/modules/help.py \
|
||||||
|
xml/Makefile \
|
||||||
|
)
|
||||||
|
|
||||||
|
diff -r 9971ebba4494 doc/Makefile.am
|
||||||
|
--- a/doc/Makefile.am Wed Aug 31 11:02:11 2011 +1000
|
||||||
|
+++ b/doc/Makefile.am Wed Oct 19 14:44:33 2011 +0200
|
||||||
|
@@ -22,7 +22,6 @@ MAINTAINERCLEANFILES = Makefile.in
|
||||||
|
helpdir = $(datadir)/$(PACKAGE)
|
||||||
|
|
||||||
|
ascii = crm_fencing.txt acls.txt
|
||||||
|
-asciiman = crm.8.txt
|
||||||
|
help_DATA = crm.8.txt
|
||||||
|
docbook = Pacemaker_Explained Clusters_from_Scratch
|
||||||
|
doc_DATA = README.hb2openais $(ascii) $(generated_docs)
|
||||||
|
@@ -57,10 +56,7 @@ graphics: $(PNGS)
|
||||||
|
$(INKSCAPE) --file=$< --export-dpi=180 -C --export-png=$@
|
||||||
|
|
||||||
|
if BUILD_ASCIIDOC
|
||||||
|
-generated_docs += $(ascii:%.txt=%.html) $(asciiman:%.txt=%.html)
|
||||||
|
-generated_mans += $(asciiman:%.8.txt=%.8)
|
||||||
|
-$(generated_mans): $(asciiman)
|
||||||
|
-man8_MANS = $(generated_mans)
|
||||||
|
+generated_docs += $(ascii:%.txt=%.html)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_DOCBOOK
|
||||||
|
@@ -122,12 +118,12 @@ brand: $(BRAND_PNGS) $(wildcard publica
|
||||||
|
# find publican-clusterlabs -name "*.noarch.rpm" -exec sudo rpm -Uvh --force \{\} \;
|
||||||
|
|
||||||
|
www: $(generated_docs)
|
||||||
|
- echo rsync -rtz --progress $(generated_docs) $(ascii) $(asciiman) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
- rsync -rtz --progress $(generated_docs) $(ascii) $(asciiman) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
+ echo rsync -rtz --progress $(generated_docs) $(ascii) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
+ rsync -rtz --progress $(generated_docs) $(ascii) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
rm -f $(docbook_txt)
|
||||||
|
make DOCBOOK_FORMATS="pdf,html,html-single,txt,epub" DOCBOOK_LANGS="all" all-local $(generated_docs) $(ascii)
|
||||||
|
echo Uploading current documentation set to clusterlabs.org
|
||||||
|
- rsync -rtz --progress $(generated_docs) $(ascii) $(asciiman) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
+ rsync -rtz --progress $(generated_docs) $(ascii) root@www.clusterlabs.org:/var/www/html/doc/
|
||||||
|
if BUILD_DOCBOOK
|
||||||
|
for book in $(docbook); do \
|
||||||
|
echo Uploading $$book...; \
|
Loading…
x
Reference in New Issue
Block a user