| /* |
| * 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; |
| } |