Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: beekhof/pacemaker
...
head fork: beekhof/pacemaker
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 8 files changed
  • 0 commit comments
  • 1 contributor
View
9 configure.ac
@@ -564,6 +564,13 @@ dnl was NOT being expanded all the time thus causing things to fail.
AC_CHECK_PROGS(LIBTOOL, glibtool libtool libtool15 libtool13)
AM_PATH_PYTHON
+SWIG_ENABLE_CXX
+SWIG_PYTHON
+
+# As above, pre-expand so the values can be used in .py.in files
+eval pythondir="`eval echo ${pythondir}`"
+eval pyexecdir="`eval echo ${pyexecdir}`"
+
AC_CHECK_PROGS(MAKE, gmake make)
AC_PATH_PROGS(HTML2TXT, lynx w3m)
AC_PATH_PROGS(HELP2MAN, help2man)
@@ -578,6 +585,7 @@ AC_PATH_PROGS(SCP, scp, /usr/bin/scp)
AC_PATH_PROGS(TAR, tar)
AC_PATH_PROGS(MD5, md5)
AC_PATH_PROGS(TEST, test)
+AC_PATH_PROGS(SWIG, swig)
AC_PATH_PROGS(PKGCONFIG, pkg-config)
AC_PATH_PROGS(XML2CONFIG, xml2-config)
AC_PATH_PROGS(VALGRIND_BIN, valgrind, /usr/bin/valgrind)
@@ -1660,6 +1668,7 @@ cib/Makefile \
crmd/Makefile \
pengine/Makefile \
pengine/regression.core.sh \
+ pengine/pacemaker.py \
doc/Makefile \
doc/Pacemaker_Explained/publican.cfg \
doc/Clusters_from_Scratch/publican.cfg \
View
42 configure.in
@@ -1,42 +0,0 @@
-# -*- Autoconf -*-
-# Process this file with autoconf to produce a configure script.
-
-AC_PREREQ([2.62])
-AC_INIT([ccs2cib], [0.5.2], [lon@metamorphism.com])
-AC_CONFIG_SRCDIR([reslist.c])
-AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE
-
-# Checks for programs.
-AC_PROG_CC
-AC_PATH_PROGS(XML2CONFIG, xml2-config)
-
-# Checks for libraries. - pulled from Pacemaker 1.1
-AC_MSG_CHECKING(for special libxml2 includes)
-if test "x$XML2CONFIG" = "x"; then
- AC_MSG_ERROR(libxml2 config not found)
-else
- XML2HEAD="`$XML2CONFIG --cflags`"
- AC_MSG_RESULT($XML2HEAD)
- AC_CHECK_LIB(xml2, xmlParseFile)
-fi
-
-CPPFLAGS="$CPPFLAGS $XML2HEAD"
-
-# Checks for header files.
-AC_CHECK_HEADERS([stdint.h stdlib.h string.h unistd.h])
-
-# Checks for typedefs, structures, and compiler characteristics.
-AC_C_INLINE
-AC_TYPE_INT64_T
-AC_TYPE_SIZE_T
-AC_TYPE_SSIZE_T
-
-# Checks for library functions.
-AC_FUNC_FORK
-AC_FUNC_MALLOC
-AC_FUNC_REALLOC
-AC_CHECK_FUNCS([dup2 memset strcasecmp strchr strdup strncasecmp strrchr strstr])
-
-AC_CONFIG_FILES([Makefile])
-AC_OUTPUT
View
4 include/crm/crm.h
@@ -83,7 +83,9 @@ extern const char *crm_system_name;
# define INFINITY_S "INFINITY"
# define MINUS_INFINITY_S "-INFINITY"
-# define INFINITY 1000000
+# ifndef INFINITY
+# define INFINITY 1000000
+# endif
/* Sub-systems */
# define CRM_SYSTEM_DC "dc"
View
37 include/crm/pengine/api.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef PENGINE_API__H
+# define PENGINE_API__H
+#include <crm/pengine/status.h>
+#include <crm/common/xml.h>
+
+pe_working_set_t *pengine_create(void);
+void pengine_cleanup(pe_working_set_t * data_set);
+void pengine_destroy(pe_working_set_t * data_set);
+
+int pengine_status_text(pe_working_set_t * data_set, const char *input_string);
+int pengine_run_text(pe_working_set_t * data_set, const char *xml_input);
+const char *pengine_graph_text(pe_working_set_t * data_set);
+
+int pengine_status_xml(pe_working_set_t * data_set, xmlNode *xml_input);
+int pengine_run_xml(pe_working_set_t * data_set, xmlNode *xml_input);
+xmlNode *pengine_graph_xml(pe_working_set_t * data_set);
+
+char *pengine_bucket_for_object(pe_working_set_t * data_set, char *object_id, int calculated);
+
+#endif
View
27 pengine/Makefile.am
@@ -63,6 +63,9 @@ pengine.7: pengine.xml
$(XSLTPROC) $(MANPAGE_XSLT) $(top_builddir)/pengine/$<
endif
+pengine_wrap.c: pengine.i
+ swig -python pengine.i
+
## SOURCES
noinst_HEADERS = allocate.h utils.h pengine.h
#utils.h pengine.h
@@ -70,10 +73,32 @@ noinst_HEADERS = allocate.h utils.h pengine.h
libpengine_la_LDFLAGS = -version-info 3:0:0
# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version
libpengine_la_SOURCES = pengine.c allocate.c utils.c constraints.c \
- native.c group.c clone.c master.c graph.c
+ native.c group.c clone.c master.c graph.c api.c
libpengine_la_LIBADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/cib/libcib.la
+
+BUILT_SOURCES = $(srcdir)/pengine_wrap.c
+SWIG_SOURCES = pengine.i
+
+python_PYTHON = pacemaker.py
+
+# To use, both /usr/lib64/python2.7/site-packages/pacemaker and
+# /usr/lib/python2.7/site-packages/pacemaker need to be in the
+# Python path :-/
+pkgpython_PYTHON = pengine.py
+pkgpyexec_LTLIBRARIES = _pengine.la
+
+_pengine_la_SOURCES = $(BUILT_SOURCES) $(SWIG_SOURCES)
+_pengine_la_CFLAGS = $(shell $(PKGCONFIG) python --cflags) $(CFLAGS) -Wno-missing-prototypes
+_pengine_la_LDFLAGS = -module
+_pengine_la_LIBADD = $(top_builddir)/pengine/libpengine.la
+_pengine_la_DEPENDENCIES = $(top_builddir)/pengine/libpengine.la
+
+
+$(srcdir)/%_wrap.c : %.i
+ $(SWIG) -python -nothreads -py3 -O -o $@ $<
+
pengine_SOURCES = main.c
pengine_LDADD = $(top_builddir)/lib/cib/libcib.la $(COMMONLIBS)
# libcib for get_object_root()
View
101 pengine/api.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 Andrew Beekhof <andrew@beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <crm_internal.h>
+#include <crm/pengine/api.h>
+
+extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
+extern xmlNode *do_calculations(pe_working_set_t * data_set, xmlNode * xml_input, ha_time_t * now);
+
+pe_working_set_t *pengine_create(void)
+{
+ pe_working_set_t *data_set = NULL;
+ crm_malloc0(data_set, sizeof(pe_working_set_t));
+ set_working_set_defaults(data_set);
+ return data_set;
+}
+
+void pengine_cleanup(pe_working_set_t * data_set)
+{
+ cleanup_alloc_calculations(data_set);
+}
+
+void pengine_destroy(pe_working_set_t * data_set)
+{
+ cleanup_alloc_calculations(data_set);
+ crm_free(data_set);
+}
+
+int pengine_status_text(pe_working_set_t * data_set, const char *input_string)
+{
+ xmlNode *xml = string2xml(input_string);
+ return pengine_status_xml(data_set, xml);
+}
+
+int pengine_run_text(pe_working_set_t * data_set, const char *input_string)
+{
+ xmlNode *xml = string2xml(input_string);
+ return pengine_run_xml(data_set, xml);
+}
+
+const char *pengine_graph_text(pe_working_set_t * data_set)
+{
+ return dump_xml_unformatted(data_set->graph);
+}
+
+/* xml_input is owned by data_set after the call */
+int pengine_status_xml(pe_working_set_t * data_set, xmlNode *xml_input)
+{
+ pengine_cleanup(data_set);
+ data_set->input = xml_input;
+
+ return cluster_status(data_set);
+}
+
+/* xml_input is owned by data_set after the call */
+int pengine_run_xml(pe_working_set_t * data_set, xmlNode *xml_input)
+{
+ pengine_cleanup(data_set);
+ if(do_calculations(data_set, xml_input, NULL) != NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+xmlNode *pengine_graph_xml(pe_working_set_t * data_set)
+{
+ return data_set->graph;
+}
+
+char *pengine_bucket_for_object(pe_working_set_t * data_set, char *object_id, int calculated)
+{
+ resource_t *rsc = pe_find_resource(data_set->resources, object_id);
+ if(rsc == NULL) {
+ return NULL;
+ }
+
+ if(calculated && rsc->allocated_to) {
+ return crm_strdup(rsc->allocated_to->details->uname);
+ } else if(!calculated && rsc->running_on) {
+ node_t *n = rsc->running_on->data;
+ return crm_strdup(n->details->uname);
+ }
+
+ return NULL;
+}
+
View
267 pengine/pacemaker.py.in
@@ -0,0 +1,267 @@
+import sys
+
+sys.path.append("@pythondir@/pacemaker")
+sys.path.append("@pyexecdir@/pacemaker")
+
+import pengine
+import xml.dom.minidom
+
+class PolicyEngine:
+
+ def set_option(self, name, value):
+ n = self.doc.createElement("nvpair")
+ n.setAttribute("id", "option-%s" % name)
+ n.setAttribute("name", name)
+ n.setAttribute("value", value)
+ self.xml['options'].appendChild(n)
+
+ def __init__(self):
+
+ self.xml = {}
+ self.nested = {}
+ self.objects = {}
+ self.ws = pengine.pengine_create()
+
+ self.doc = xml.dom.minidom.Document()
+ self.xml['cib'] = self.doc.createElement("cib")
+ self.xml['cib'].setAttribute("validate-with", "pacemaker-1.0")
+ self.xml['cib'].setAttribute("admin_epoch", "1")
+ self.xml['cib'].setAttribute("epoch", "1")
+ self.xml['cib'].setAttribute("num_updates", "1")
+
+ self.xml['nodes'] = self.doc.createElement("nodes")
+ self.xml['resources'] = self.doc.createElement("resources")
+ self.xml['constraints'] = self.doc.createElement("constraints")
+ self.xml['status'] = self.doc.createElement("status")
+
+ self.xml['options'] = self.doc.createElement("cluster_property_set")
+ self.xml['options'].setAttribute("id", "defaults")
+
+ crm_config = self.doc.createElement("crm_config")
+ crm_config.appendChild(self.xml['options'])
+
+ config = self.doc.createElement("configuration")
+ config.appendChild(crm_config)
+ config.appendChild(self.xml['nodes'])
+ config.appendChild(self.xml['resources'])
+ config.appendChild(self.xml['constraints'])
+
+ self.doc.appendChild(self.xml['cib'])
+
+ self.xml['cib'].appendChild(config)
+ self.xml['cib'].appendChild(self.xml['status'])
+
+ self.set_option("stonith-enabled", "false")
+ self.set_option("enable-startup-probes", "false")
+ self.set_option("no-quorum-policy", "ignore")
+ self.set_option("default-resource-stickiness", "INFINITY")
+
+ def get_object(self, name):
+ if self.objects.has_key(name):
+ return self.objects[name]
+ return None
+
+ def get_bucket(self, name):
+ for o in self.xml['nodes'].childNodes:
+ if o.getAttribute("id") == name:
+ return o
+ return None
+
+ def get_assigned_bucket(self, name, calculated=False):
+ return pengine.pengine_bucket_for_object(self.ws, name, calculated)
+
+ def add_container(self, name, parents=[]):
+ container = self
+ for key in parents:
+ if container.nested.has_key(key):
+ container = container.nested[key]
+ else:
+ print "No parent %s found for heirarchy %s" % (key, repr(parents))
+ break
+
+ container.nested[name] = PolicyEngine()
+ container.add_bucket(name)
+
+ def add_bucket(self, name, parents=[]):
+ container = self
+ for key in parents:
+ if container.nested.has_key(key):
+ container = container.nested[key]
+ else:
+ print "No parent %s found for heirarchy %s" % (key, repr(parents))
+ break
+
+ n = container.doc.createElement("node")
+ n.setAttribute("id", name)
+ n.setAttribute("uname", name)
+ n.setAttribute("type", "member")
+ container.xml['nodes'].appendChild(n)
+
+ n = container.doc.createElement("node_state")
+ n.setAttribute("id", name)
+ n.setAttribute("uname", name)
+ n.setAttribute("ha", "active")
+ n.setAttribute("crmd", "online")
+ n.setAttribute("join", "member")
+ n.setAttribute("expected", "member")
+ n.setAttribute("in_ccm", "true")
+ container.xml['status'].appendChild(n)
+
+ def add_object(self, name):
+
+ if not self.get_object(name):
+ n = self.doc.createElement("primitive")
+ n.setAttribute("id", name)
+ n.setAttribute("class", "ocf")
+ n.setAttribute("type", "Dummy")
+ n.setAttribute("provider", "pacemaker")
+ self.xml['resources'].appendChild(n)
+ self.objects[name] = n
+
+ def _set_object_assignment(self, name, bucket, action):
+
+ if not self.get_object(name):
+ self.add_object(name)
+
+ if not self.get_bucket(bucket):
+ self.add_bucket(bucket)
+
+ for o in self.xml['status'].childNodes:
+ if o.getAttribute("id") != bucket:
+ continue
+
+ lrm = None
+ rlist = None
+ l = o.getElementsByTagName("lrm")
+ if l:
+ lrm = l[0]
+ if not lrm:
+ lrm = self.doc.createElement("lrm")
+ lrm.setAttribute("id", bucket)
+ o.appendChild(lrm)
+
+ l = lrm.getElementsByTagName("lrm_resources")
+ if l:
+ rlist = l[0]
+ if not rlist:
+ rlist = self.doc.createElement("lrm_resources")
+ rlist.setAttribute("id", bucket)
+ lrm.appendChild(rlist)
+
+ h = None
+ for r in rlist.childNodes:
+ if r.nodeType == r.ELEMENT_NODE and r.tagName == "lrm_resource" and r.getAttribute("id") == name:
+ h = r
+
+ if not h:
+ h = self.doc.createElement("lrm_resource")
+ h.setAttribute("id", name)
+ h.setAttribute("class", "ocf")
+ h.setAttribute("type", "Dummy")
+ h.setAttribute("provider", "pacemaker")
+ h.setAttribute("op-count", "0")
+ rlist.appendChild(h)
+
+ count = int(h.getAttribute("op-count"))+1
+ h.setAttribute("op-count", str(count))
+
+ op = self.doc.createElement("lrm_rsc_op")
+ op.setAttribute("id", "%s_%s_0" % (name, action))
+ op.setAttribute("operation", action)
+ op.setAttribute("interval", "0")
+ op.setAttribute("op-status", "0")
+ op.setAttribute("rc-code", "0")
+ op.setAttribute("call-id", str(count))
+ op.setAttribute("crm_feature_set", "3.0")
+ op.setAttribute("op-digest", "f2317cad3d54cec5d7d7aa7d0bf35cf8")
+ h.appendChild(op)
+
+ def assign_object(self, name, bucket):
+ return self._set_object_assignment(name, bucket, "start")
+
+ def unassign_object(self, name, bucket):
+ return self._set_object_assignment(name, bucket, "stop")
+
+ def run(self, assign=True):
+ xmltext = self.doc.toprettyxml()
+ rc = pengine.pengine_run_text(self.ws, xmltext)
+
+ if assign:
+ for o in self.objects.keys():
+ b = self.get_assigned_bucket(o, True)
+ old_b = self.get_assigned_bucket(o, False)
+
+ if not b:
+ # TODO(beekhof): Implement removal
+ if not old_b:
+ print o+" not assigned"
+ elif self.nested.has_key(b):
+ print o+" removed from nested bucket "+old_b
+ else:
+ print o+" removed from bucket "+old_b
+
+ elif not old_b:
+ self.assign_object(o, b)
+ if self.nested.has_key(b):
+ print o+" assigned to nested bucket "+b
+ self.nested[b].add_object(o)
+ else:
+ print o+" assigned to bucket "+b
+
+ elif old_b == b:
+ if self.nested.has_key(b):
+ print o+" still assigned to nested bucket "+b
+ else:
+ print o+" still assigned to bucket "+b
+ else:
+ # TODO(beekhof): Implement removal
+ if self.nested.has_key(b):
+ print o+" moved to nested bucket "+b
+ else:
+ print o+" moved to bucket "+b
+
+ for key in self.nested.keys():
+ print ""
+ print "Running nested bucket: "+key
+ self.nested[key].run(assign)
+
+ return rc
+
+ def graph(self):
+ return xml.dom.minidom.parseString(pengine.pengine_graph_text(self.ws))
+
+ def update(self):
+ return None
+
+if __name__ == '__main__':
+ n = 0
+ zpe = PolicyEngine()
+ zpe.add_container("zone-1")
+ zpe.add_container("zone-2")
+
+ while n < 8:
+ c = 1+(n % 2)
+ n = n + 1
+ print "Adding host-%d to zone-%d" % (n, c)
+ p = []
+ p.append("zone-%d" % c)
+ zpe.add_bucket("host-%d" % n, ["zone-%d" % c])
+
+ n=0
+ while n < 10:
+ n = n + 1
+ zpe.add_object("guest-%d" % n)
+
+ print ""
+ print "Initial run"
+ zpe.run(True)
+
+ while n < 20:
+ n = n + 1
+ zpe.add_object("guest-%d" % n)
+
+ print ""
+ print "Second run"
+ zpe.run(True)
+ print zpe.doc.toprettyxml()
+ print zpe.nested['zone-1'].doc.toprettyxml()
View
31 pengine/pengine.i
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+%module pengine
+%{
+#include <crm/pengine/api.h>
+%}
+
+pe_working_set_t *pengine_create(void);
+void pengine_cleanup(pe_working_set_t * data_set);
+void pengine_destroy(pe_working_set_t * data_set);
+
+int pengine_run_text(pe_working_set_t * data_set, const char *xml_input);
+const char *pengine_graph_text(pe_working_set_t * data_set);
+
+char *pengine_bucket_for_object(pe_working_set_t * data_set, char *object_id, int calculated);

No commit comments for this range

Something went wrong with that request. Please try again.