blob: 0f453e08ac5b81da7433159fce7ba325da00f1c2 [file] [log] [blame]
/*
* Copyright (C) 2012
* David Vossel <davidvossel@gmail.com>
*
* This program is crm_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 program 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/common/xml.h>
#include <crm/msg_xml.h>
#include <crm/stonith-ng.h>
#include <crm/fencing/internal.h>
#include <internal.h>
#include <standalone_config.h>
struct device {
char *name;
char *agent;
char *hostlist;
char *hostmap;
struct {
char *key;
char *val;
} key_vals[STANDALONE_CFG_MAX_KEYVALS];
int key_vals_count;
struct device *next;
};
struct topology {
char *node_name;
struct {
char *device_name;
unsigned int level;
} priority_levels[STANDALONE_CFG_MAX_KEYVALS];
int priority_levels_count;
struct topology *next;
};
static struct device *dev_list;
static struct topology *topo_list;
static struct device *
find_device(const char *name)
{
struct device *dev = NULL;
for (dev = dev_list; dev != NULL; dev = dev->next) {
if (!strcasecmp(dev->name, name)) {
break;
}
}
return dev;
}
static struct topology *
find_topology(const char *name)
{
struct topology *topo = NULL;
for (topo = topo_list; topo != NULL; topo = topo->next) {
if (!strcasecmp(topo->node_name, name)) {
break;
}
}
return topo;
}
static void
add_device(struct device *dev)
{
dev->next = dev_list;
dev_list = dev;
}
static void
add_topology(struct topology *topo)
{
topo->next = topo_list;
topo_list = topo;
}
int
standalone_cfg_add_device(const char *device, const char *agent)
{
struct device *dev = NULL;
if (!device || !agent) {
return -1;
}
/* just ignore duplicates */
if (find_device(device)) {
return 0;
}
dev = calloc(1, sizeof(struct device));
dev->name = strdup(device);
dev->agent = strdup(agent);
add_device(dev);
return 0;
}
int
standalone_cfg_add_device_options(const char *device, const char *key, const char *value)
{
struct device *dev;
if (!device || !key || !value) {
return -1;
} else if (!(dev = find_device(device))) {
crm_err("Standalone config error, could not find device %s to add key value %s=%s to",
device, key, value);
return -1;
} else if (dev->key_vals_count >= STANDALONE_CFG_MAX_KEYVALS) {
return -1;
}
dev->key_vals[dev->key_vals_count].key = strdup(key);
dev->key_vals[dev->key_vals_count].val = strdup(value);
dev->key_vals_count++;
return 0;
}
int
standalone_cfg_add_node(const char *node, const char *device, const char *ports)
{
struct device *dev;
char **ptr;
char *tmp;
size_t len = strlen(":;") + 1;
size_t offset = 0;
/* note that ports may be NULL, it is not a required argument */
if (!node || !device) {
return -1;
} else if (!(dev = find_device(device))) {
crm_err("Standalone config error, could not find device %s to add mode %s to",
device, node);
return -1;
}
ptr = &dev->hostlist;
len += strlen(node);
if (ports) {
ptr = &dev->hostmap;
len += strlen(ports);
}
tmp = *ptr;
if (tmp) {
offset = strlen(tmp);
tmp = realloc_safe(tmp, len + offset + 1);
} else {
tmp = malloc(len);
}
*ptr = tmp;
tmp += offset;
if (ports) {
sprintf(tmp, "%s:%s;", node, ports);
} else {
sprintf(tmp, "%s ", node);
}
return 0;
}
int
standalone_cfg_add_node_priority(const char *node, const char *device, unsigned int level)
{
struct topology *topo = NULL;
int new = 0;
if (!node || !device) {
return -1;
}
if (!(topo = find_topology(node))) {
new = 1;
topo = calloc(1, sizeof(struct topology));
topo->node_name = strdup(node);
} else if (topo->priority_levels_count >= STANDALONE_CFG_MAX_KEYVALS) {
return -1;
}
topo->priority_levels[topo->priority_levels_count].device_name = strdup(device);
topo->priority_levels[topo->priority_levels_count].level = level;
topo->priority_levels_count++;
if (new) {
add_topology(topo);
}
return 0;
}
static int
destroy_topology(void)
{
struct topology *topo = NULL;
int i;
while (topo_list) {
topo = topo_list;
free(topo->node_name);
for (i = 0; i < topo->priority_levels_count; i++) {
free(topo->priority_levels[i].device_name);
}
topo_list = topo->next;
free(topo);
}
return 0;
}
static int
destroy_devices(void)
{
struct device *dev = NULL;
int i;
while (dev_list) {
dev = dev_list;
free(dev->name);
free(dev->agent);
free(dev->hostlist);
free(dev->hostmap);
for (i = 0; i < dev->key_vals_count; i++) {
free(dev->key_vals[i].key);
free(dev->key_vals[i].val);
}
dev_list = dev->next;
free(dev);
}
return 0;
}
static int
cfg_register_topology(struct topology *topo)
{
stonith_key_value_t *devices = NULL;
xmlNode *data;
char *dump;
int i;
int res = 0;
for (i = 0; i < topo->priority_levels_count; i++) {
devices = stonith_key_value_add(devices, NULL, topo->priority_levels[i].device_name);
data = create_level_registration_xml(topo->node_name, NULL, NULL, NULL,
topo->priority_levels[i].level, devices);
dump = dump_xml_formatted(data);
crm_info("Standalone config level being added:\n%s", dump);
res |= stonith_level_register(data, NULL);
free(dump);
free_xml(data);
stonith_key_value_freeall(devices, 1, 1);
}
return res;
}
static int
cfg_register_device(struct device *dev)
{
stonith_key_value_t *params = NULL;
xmlNode *data;
char *dump;
int i;
int res;
/* create the parameter list */
if (dev->hostlist) {
params = stonith_key_value_add(params, STONITH_ATTR_HOSTLIST, dev->hostlist);
}
if (dev->hostmap) {
params = stonith_key_value_add(params, STONITH_ATTR_HOSTMAP, dev->hostmap);
}
for (i = 0; i < dev->key_vals_count; i++) {
params stonith_key_value_add(params, dev->key_vals[i].key, dev->key_vals[i].val);
}
/* generate xml */
data = create_device_registration_xml(dev->name, __FUNCTION__, dev->agent, params);
dump = dump_xml_formatted(data);
crm_info("Standalone device being added:\n%s", dump);
res = stonith_device_register(data, NULL, FALSE);
free(dump);
free_xml(data);
stonith_key_value_freeall(params, 1, 1);
return res;
}
int
standalone_cfg_commit(void)
{
struct device *dev = NULL;
struct topology *topo = NULL;
for (dev = dev_list; dev != NULL; dev = dev->next) {
cfg_register_device(dev);
}
for (topo = topo_list; topo != NULL; topo = topo->next) {
cfg_register_topology(topo);
}
destroy_devices();
destroy_topology();
return 0;
}