Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F2822332
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/pcmk.c b/src/pcmk.c
index fc67f04..58c162b 100644
--- a/src/pcmk.c
+++ b/src/pcmk.c
@@ -1,490 +1,559 @@
/*
* Copyright (C) 2011 Jiaju Zhang <jjzhang@suse.de>
* Copyright (C) 2013-2014 Philipp Marek <philipp.marek@linbit.com>
*
* 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 program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "b_config.h"
+
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "ticket.h"
#include "log.h"
#include "attr.h"
#include "pcmk.h"
#include "inline-fn.h"
#ifdef LIBPACEMAKER
#include <crm/common/results.h>
#include <pacemaker.h>
#endif
#define COMMAND_MAX 2048
const char * interpret_rv(int rv)
{
static char text[64];
if (rv == 0)
return "0";
if (WIFSIGNALED(rv))
sprintf(text, "got signal %d", WTERMSIG(rv));
else
sprintf(text, "exit code %d", WEXITSTATUS(rv));
return text;
}
+#ifdef LIBPACEMAKER
+static int pcmk_write_ticket_atomic(struct ticket_config *tk, bool grant)
+{
+ char *owner_s = NULL;
+ char *expires_s = NULL;
+ char *term_s = NULL;
+ char *grant_s = NULL;
+ char *booth_cfg_name = NULL;
+ GHashTable *attrs = NULL;
+ xmlNode *xml = NULL;
+ int rv;
+
+ attrs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+ if (attrs == NULL) {
+ log_error("out of memory");
+ return -1;
+ }
+
+ if (grant) {
+ grant_s = strdup("true");
+ } else {
+ grant_s = strdup("false");
+ }
+
+ if (grant_s == NULL) {
+ log_error("out of memory");
+ return -1;
+ }
+
+ booth_cfg_name = strdup(booth_conf->name);
+
+ if (booth_cfg_name == NULL) {
+ log_error("out of memory");
+ free(grant_s);
+ return -1;
+ }
+
+ if (asprintf(&owner_s, "%" PRIi32, get_node_id(tk->leader)) == -1 ||
+ asprintf(&expires_s, "%" PRIi64, wall_ts(&tk->term_expires)) == -1 ||
+ asprintf(&term_s, "%" PRIi64, (int64_t) tk->current_term) == -1) {
+ log_error("out of memory");
+ free(owner_s);
+ free(expires_s);
+ free(term_s);
+ free(grant_s);
+ return -1;
+ }
+
+ g_hash_table_insert(attrs, (gpointer) "owner", owner_s);
+ g_hash_table_insert(attrs, (gpointer) "expires", expires_s);
+ g_hash_table_insert(attrs, (gpointer) "term", term_s);
+ g_hash_table_insert(attrs, (gpointer) "granted", grant_s);
+ g_hash_table_insert(attrs, (gpointer) "booth-cfg-name", booth_conf);
+
+ rv = pcmk_ticket_set_attr(&xml, tk->name, attrs, true);
+ g_hash_table_remove_all(attrs);
+ xmlFreeNode(xml);
+
+ if (rv != pcmk_rc_ok) {
+ log_error("pcmk_write_ticket_atomic: %s", pcmk_rc_str(rv));
+ return -1;
+ }
+
+ return 0;
+}
+#else
static int pcmk_write_ticket_atomic(struct ticket_config *tk, bool grant)
{
char cmd[COMMAND_MAX];
int rv;
/* The long format (--attr-value=) for attribute value is used instead of "-v",
* so that NO_ONE (which is -1) isn't seen as another option. */
rv = snprintf(cmd, COMMAND_MAX,
"crm_ticket -t '%s' "
"%s --force "
"-S owner --attr-value=%" PRIi32 " "
"-S expires --attr-value=%" PRIi64 " "
"-S term --attr-value=%" PRIi64 " "
"-S booth-cfg-name --attr-value=%s",
tk->name,
grant ? "-g" : "-r",
(int32_t)get_node_id(tk->leader),
(int64_t)wall_ts(&tk->term_expires),
(int64_t)tk->current_term,
booth_conf->name);
if (rv < 0 || rv >= COMMAND_MAX) {
log_error("pcmk_write_ticket_atomic: cannot format crm_ticket cmdline (probably too long)");
return -1;
}
rv = system(cmd);
log_debug("command: '%s' was executed", cmd);
if (rv != 0)
log_error("\"%s\" failed, %s", cmd, interpret_rv(rv));
return rv;
}
+#endif
static int pcmk_grant_ticket(struct ticket_config *tk)
{
return pcmk_write_ticket_atomic(tk, true);
}
static int pcmk_revoke_ticket(struct ticket_config *tk)
{
return pcmk_write_ticket_atomic(tk, false);
}
#ifdef LIBPACEMAKER
static int pcmk_set_attr(struct ticket_config *tk, const char *attr, const char *val)
{
GHashTable *attrs = NULL;
xmlNode *xml = NULL;
int rv;
attrs = g_hash_table_new(g_str_hash, g_str_equal);
if (attrs == NULL) {
log_error("out of memory");
return -1;
}
g_hash_table_insert(attrs, (gpointer) attr, (gpointer) val);
rv = pcmk_ticket_set_attr(&xml, tk->name, attrs, false);
g_hash_table_destroy(attrs);
xmlFreeNode(xml);
if (rv != pcmk_rc_ok) {
log_error("pcmk_set_attr: %s", pcmk_rc_str(rv));
return -1;
}
return 0;
}
static int pcmk_del_attr(struct ticket_config *tk, const char *attr)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
int rv;
attrs = g_list_append(attrs, (gpointer) attr);
if (attrs == NULL) {
log_error("out of memory");
return -1;
}
rv = pcmk_ticket_remove_attr(&xml, tk->name, attrs, false);
g_list_free(attrs);
xmlFreeNode(xml);
if (rv != pcmk_rc_ok) {
log_error("pcmk_del_attr: %s", pcmk_rc_str(rv));
return -1;
}
return 0;
}
#else
static int _run_crm_ticket(char *cmd)
{
int i, rv;
/* If there are errors, there's not much we can do but retry ... */
for (i=0; i<3 &&
(rv = system(cmd));
i++) ;
log_debug("'%s' gave result %s", cmd, interpret_rv(rv));
return rv;
}
static int pcmk_set_attr(struct ticket_config *tk, const char *attr, const char *val)
{
char cmd[COMMAND_MAX];
int rv;
rv = snprintf(cmd, COMMAND_MAX,
"crm_ticket -t '%s' -S '%s' --attr-value='%s'",
tk->name, attr, val);
if (rv < 0 || rv >= COMMAND_MAX) {
log_error("pcmk_set_attr: cannot format crm_ticket cmdline (probably too long)");
return -1;
}
return _run_crm_ticket(cmd);
}
static int pcmk_del_attr(struct ticket_config *tk, const char *attr)
{
char cmd[COMMAND_MAX];
int rv;
rv = snprintf(cmd, COMMAND_MAX,
"crm_ticket -t '%s' -D '%s'",
tk->name, attr);
if (rv < 0 || rv >= COMMAND_MAX) {
log_error("pcmk_del_attr: cannot format crm_ticket cmdline (probably too long)");
return -1;
}
return _run_crm_ticket(cmd);
}
#endif
typedef int (*attr_f)(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val);
struct attr_tab
{
const char *name;
attr_f handling_f;
};
static int save_expires(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val)
{
secs2tv(unwall_ts(atol(val)), &tk->term_expires);
return 0;
}
static int save_term(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val)
{
tk->current_term = atol(val);
return 0;
}
static int parse_boolean(const char *val)
{
long v;
if (!strncmp(val, "false", 5)) {
v = 0;
} else if (!strncmp(val, "true", 4)) {
v = 1;
} else {
v = atol(val);
}
return v;
}
static int save_granted(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val)
{
tk->is_granted = parse_boolean(val);
return 0;
}
static int save_owner(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val)
{
/* No check, node could have been deconfigured. */
tk->leader = NULL;
return !find_site_by_id(conf, atol(val), &tk->leader);
}
static int ignore_attr(struct booth_config *conf, struct ticket_config *tk,
const char *name, const char *val)
{
return 0;
}
static int save_attr(struct ticket_config *tk, const char *name,
const char *val)
{
/* tell store_geo_attr not to store time, we don't have that
* information available
*/
return store_geo_attr(tk, name, val, 1);
}
struct attr_tab attr_handlers[] = {
{ "expires", save_expires},
{ "term", save_term},
{ "granted", save_granted},
{ "owner", save_owner},
{ "id", ignore_attr},
{ "last-granted", ignore_attr},
{ "booth-cfg-name", ignore_attr},
{ NULL, 0},
};
/* get_attr is currently not used and has not been tested
*/
static int pcmk_get_attr(struct ticket_config *tk, const char *attr, const char **vp)
{
char cmd[COMMAND_MAX];
char line[BOOTH_ATTRVAL_LEN+1];
int rv = 0, pipe_rv;
int res;
FILE *p;
*vp = NULL;
res = snprintf(cmd, COMMAND_MAX,
"crm_ticket -t '%s' -G '%s' --quiet",
tk->name, attr);
if (res < 0 || res >= COMMAND_MAX) {
log_error("pcmk_get_attr: cannot format crm_ticket cmdline (probably too long)");
return -1;
}
p = popen(cmd, "r");
if (p == NULL) {
pipe_rv = errno;
log_error("popen error %d (%s) for \"%s\"",
pipe_rv, strerror(pipe_rv), cmd);
return (pipe_rv != 0 ? pipe_rv : EINVAL);
}
if (fgets(line, BOOTH_ATTRVAL_LEN, p) == NULL) {
rv = ENODATA;
goto out;
}
*vp = g_strdup(line);
out:
pipe_rv = pclose(p);
if (!pipe_rv) {
log_debug("command \"%s\"", cmd);
} else if (WEXITSTATUS(pipe_rv) == 6) {
log_info("command \"%s\", ticket not found", cmd);
} else {
log_error("command \"%s\" %s", cmd, interpret_rv(pipe_rv));
}
return rv | pipe_rv;
}
static int save_attributes(struct booth_config *conf, struct ticket_config *tk,
xmlDocPtr doc)
{
int rv = 0, rc;
xmlNodePtr n;
xmlAttrPtr attr;
xmlChar *v;
struct attr_tab *atp;
n = xmlDocGetRootElement(doc);
if (n == NULL) {
tk_log_error("crm_ticket xml output empty");
return -EINVAL;
}
if (xmlStrcmp(n->name, (const xmlChar *)"ticket_state")) {
tk_log_error("crm_ticket xml root element not ticket_state");
return -EINVAL;
}
for (attr = n->properties; attr; attr = attr->next) {
v = xmlGetProp(n, attr->name);
for (atp = attr_handlers; atp->name; atp++) {
if (!strcmp(atp->name, (const char *) attr->name)) {
rc = atp->handling_f(conf, tk,
(const char *) attr->name,
(const char *) v);
break;
}
}
if (!atp->name) {
rc = save_attr(tk, (const char *) attr->name,
(const char *) v);
}
if (rc) {
tk_log_error("error storing attribute %s", attr->name);
rv |= rc;
}
xmlFree(v);
}
return rv;
}
#define CHUNK_SIZE 256
static int parse_ticket_state(struct booth_config *conf, struct ticket_config *tk,
FILE *p)
{
int rv = 0;
GString *input = NULL;
char line[CHUNK_SIZE];
xmlDocPtr doc = NULL;
int opts = XML_PARSE_COMPACT | XML_PARSE_NONET;
/* skip first two lines of output */
if (fgets(line, CHUNK_SIZE-1, p) == NULL || fgets(line, CHUNK_SIZE-1, p) == NULL) {
tk_log_error("crm_ticket xml output empty");
rv = ENODATA;
goto out;
}
input = g_string_sized_new(CHUNK_SIZE);
if (!input) {
log_error("out of memory");
rv = -1;
goto out;
}
while (fgets(line, CHUNK_SIZE-1, p) != NULL) {
if (!g_string_append(input, line)) {
log_error("out of memory");
rv = -1;
goto out;
}
}
doc = xmlReadDoc((const xmlChar *) input->str, NULL, NULL, opts);
if (doc == NULL) {
const xmlError *errptr = xmlGetLastError();
if (errptr) {
tk_log_error("crm_ticket xml parse failed (domain=%d, level=%d, code=%d): %s",
errptr->domain, errptr->level,
errptr->code, errptr->message);
} else {
tk_log_error("crm_ticket xml parse failed");
}
rv = -EINVAL;
goto out;
}
rv = save_attributes(conf, tk, doc);
out:
if (doc)
xmlFreeDoc(doc);
if (input)
g_string_free(input, TRUE);
return rv;
}
static int pcmk_load_ticket(struct booth_config *conf, struct ticket_config *tk)
{
char cmd[COMMAND_MAX];
int rv = 0, pipe_rv;
int res;
FILE *p;
res = snprintf(cmd, COMMAND_MAX,
"crm_ticket -t '%s' -q",
tk->name);
if (res < 0 || res >= COMMAND_MAX) {
log_error("pcmk_load_ticket: cannot format crm_ticket cmdline (probably too long)");
return -1;
}
p = popen(cmd, "r");
if (p == NULL) {
pipe_rv = errno;
log_error("popen error %d (%s) for \"%s\"",
pipe_rv, strerror(pipe_rv), cmd);
return (pipe_rv != 0 ? pipe_rv : EINVAL);
}
rv = parse_ticket_state(conf, tk, p);
if (!tk->leader) {
/* Hmm, no site found for the ticket we have in the
* CIB!?
* Assume that the ticket belonged to us if it was
* granted here!
*/
log_warn("%s: no site matches; site got reconfigured?",
tk->name);
if (tk->is_granted) {
log_warn("%s: granted here, assume it belonged to us",
tk->name);
set_leader(tk, local);
}
}
pipe_rv = pclose(p);
if (!pipe_rv) {
log_debug("command \"%s\"", cmd);
} else if (WEXITSTATUS(pipe_rv) == 6) {
log_info("command \"%s\", ticket not found", cmd);
} else {
log_error("command \"%s\" %s", cmd, interpret_rv(pipe_rv));
}
return rv | pipe_rv;
}
struct ticket_handler pcmk_handler = {
.grant_ticket = pcmk_grant_ticket,
.revoke_ticket = pcmk_revoke_ticket,
.load_ticket = pcmk_load_ticket,
.set_attr = pcmk_set_attr,
.get_attr = pcmk_get_attr,
.del_attr = pcmk_del_attr,
};
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jan 25, 5:31 AM (13 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1319817
Default Alt Text
(13 KB)
Attached To
Mode
rB Booth
Attached
Detach File
Event Timeline
Log In to Comment