/* Parse replicator site element */ static int _add_site(struct lv_segment *seg, const char *key, const struct dm_config_node *sn) { struct dm_pool *mem = seg->lv->vg->vgmem; const struct dm_config_node *cn; struct replicator_site *rsite; if (!(rsite = _get_site(seg->lv, key))) return_0; if (!dm_config_find_node(sn, "site_index")) return SEG_LOG_ERROR("Mandatory site_index is missing for"); rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE); rsite->site_index = _get_config_uint32(sn, "site_index", 0); if (rsite->site_index > seg->rsite_index_highest) return SEG_LOG_ERROR("site_index=%d > highest_site_index=%d for", rsite->site_index, seg->rsite_index_highest); rsite->fall_behind_data = _get_config_uint64(sn, "fall_behind_data", 0); rsite->fall_behind_ios = _get_config_uint32(sn, "fall_behind_ios", 0); rsite->fall_behind_timeout = _get_config_uint32(sn, "fall_behind_timeout", 0); rsite->op_mode = DM_REPLICATOR_SYNC; if (rsite->fall_behind_data || rsite->fall_behind_ios || rsite->fall_behind_timeout) { if (rsite->fall_behind_data && rsite->fall_behind_ios) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_ios in"); if (rsite->fall_behind_data && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_timeout in"); if (rsite->fall_behind_ios && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_ios " "and fall_behind_timeout in"); rsite->op_mode = _get_op_mode(sn, "operation_mode", rsite->op_mode); } if ((cn = dm_config_find_node(sn, "volume_group"))) { if (!cn->v || cn->v->type != DM_CFG_STRING) return SEG_LOG_ERROR("volume_group must be a string in"); if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str))) return_0; } else if (rsite->site_index != 0) return SEG_LOG_ERROR("volume_group is mandatory for remote site in"); return 1; }
/* Destructively merge a new config tree into an existing one */ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, struct dm_config_tree *newdata, config_merge_t merge_type) { struct dm_config_node *root = cft->root; struct dm_config_node *cn, *nextn, *oldn, *cn2; const struct dm_config_node *tn; struct config_source *cs, *csn; for (cn = newdata->root; cn; cn = nextn) { nextn = cn->sib; if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Ignore tags section */ if (!strcmp(cn->key, "tags")) continue; /* If there's a tags node, skip if host tags don't match */ if ((tn = dm_config_find_node(cn->child, "tags"))) { if (!_match_host_tags(&cmd->tags, tn)) continue; } } if (!(oldn = dm_config_find_node(root, cn->key))) { _insert_config_node(&cft->root, cn); if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Remove any "tags" nodes */ for (cn2 = cn->child; cn2; cn2 = cn2->sib) { if (!strcmp(cn2->key, "tags")) { cn->child = cn2->sib; continue; } if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { cn2->sib = cn2->sib->sib; continue; } } } continue; } _merge_section(oldn, cn, merge_type); } /* * Persistent filter loading is based on timestamp, * so we need to know the newest timestamp to make right decision * whether the .cache isn't older then any of configs */ cs = dm_config_get_custom(cft); csn = dm_config_get_custom(newdata); if (cs && csn && (cs->timestamp < csn->timestamp)) cs->timestamp = csn->timestamp; return 1; }
static void test_clone(void) { struct dm_config_tree *tree = dm_config_from_string(conf); struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1); const struct dm_config_value *value; /* Check that the nodes are actually distinct. */ CU_ASSERT(n != tree->root); CU_ASSERT(n->sib != tree->root->sib); CU_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL); CU_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL); CU_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes")); CU_ASSERT(dm_config_has_node(n, "id")); CU_ASSERT(dm_config_has_node(n, "physical_volumes")); CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0")); CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id")); CU_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada")); CU_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo")); CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh")); CU_ASSERT(!dm_config_get_uint32(n, "id", NULL)); CU_ASSERT(dm_config_get_uint32(n, "extent_size", NULL)); /* FIXME: Currently everything parses as a list, even if it's not */ // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL)); // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL)); CU_ASSERT(dm_config_get_list(n, "flags", &value)); CU_ASSERT(value->next == NULL); /* an empty list */ CU_ASSERT(dm_config_get_list(n, "status", &value)); CU_ASSERT(value->next != NULL); /* a non-empty list */ dm_config_destroy(tree); }
/* Destructively merge a new config tree into an existing one */ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, struct dm_config_tree *newdata) { struct dm_config_node *root = cft->root; struct dm_config_node *cn, *nextn, *oldn, *cn2; const struct dm_config_node *tn; for (cn = newdata->root; cn; cn = nextn) { nextn = cn->sib; /* Ignore tags section */ if (!strcmp(cn->key, "tags")) continue; /* If there's a tags node, skip if host tags don't match */ if ((tn = dm_config_find_node(cn->child, "tags"))) { if (!_match_host_tags(&cmd->tags, tn)) continue; } if (!(oldn = dm_config_find_node(root, cn->key))) { _insert_config_node(&cft->root, cn); /* Remove any "tags" nodes */ for (cn2 = cn->child; cn2; cn2 = cn2->sib) { if (!strcmp(cn2->key, "tags")) { cn->child = cn2->sib; continue; } if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { cn2->sib = cn2->sib->sib; continue; } } continue; } _merge_section(oldn, cn); } return 1; }
/* * Merge section cn2 into section cn1 (which has the same name) * overwriting any existing cn1 nodes with matching names. */ static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2, config_merge_t merge_type) { struct dm_config_node *cn, *nextn, *oldn; struct dm_config_value *cv; for (cn = cn2->child; cn; cn = nextn) { nextn = cn->sib; if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Skip "tags" */ if (!strcmp(cn->key, "tags")) continue; } /* Subsection? */ if (!cn->v) /* Ignore - we don't have any of these yet */ continue; /* Not already present? */ if (!(oldn = dm_config_find_node(cn1->child, cn->key))) { _insert_config_node(&cn1->child, cn); continue; } if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Merge certain value lists */ if ((!strcmp(cn1->key, "activation") && !strcmp(cn->key, "volume_list")) || (!strcmp(cn1->key, "devices") && (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) { cv = cn->v; while (cv->next) cv = cv->next; cv->next = oldn->v; } } /* Replace values */ oldn->v = cn->v; } }
int config_write(struct dm_config_tree *cft, const char *file, int argc, char **argv) { const struct dm_config_node *cn; int r = 1; FILE *fp = NULL; if (!file) { fp = stdout; file = "stdout"; } else if (!(fp = fopen(file, "w"))) { log_sys_error("open", file); return 0; } log_verbose("Dumping configuration to %s", file); if (!argc) { if (!dm_config_write_node(cft->root, _putline_fn, fp)) { log_error("Failure while writing to %s", file); r = 0; } } else while (argc--) { if ((cn = dm_config_find_node(cft->root, *argv))) { if (!dm_config_write_node(cn, _putline_fn, fp)) { log_error("Failure while writing to %s", file); r = 0; } } else { log_error("Configuration node %s not found", *argv); r = 0; } argv++; } if (fp && dm_fclose(fp)) { stack; r = 0; } return r; }
int main(int argc, char **argv) { daemon_reply reply; char *cmd; char *uuid; char *name; int val; int ver; if (argc < 2) { printf("lvmetactl dump\n"); printf("lvmetactl pv_list\n"); printf("lvmetactl vg_list\n"); printf("lvmetactl vg_lookup_name <name>\n"); printf("lvmetactl vg_lookup_uuid <uuid>\n"); printf("lvmetactl pv_lookup_uuid <uuid>\n"); printf("lvmetactl set_global_invalid 0|1\n"); printf("lvmetactl get_global_invalid\n"); printf("lvmetactl set_vg_version <uuid> <name> <version>\n"); printf("lvmetactl vg_lock_type <uuid>\n"); return -1; } cmd = argv[1]; h = lvmetad_open(NULL); if (!strcmp(cmd, "dump")) { reply = daemon_send_simple(h, "dump", "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "pv_list")) { reply = daemon_send_simple(h, "pv_list", "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "vg_list")) { reply = daemon_send_simple(h, "vg_list", "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "set_global_invalid")) { if (argc < 3) { printf("set_global_invalid 0|1\n"); return -1; } val = atoi(argv[2]); reply = daemon_send_simple(h, "set_global_info", "global_invalid = %d", val, "token = %s", "skip", NULL); print_reply(reply); } else if (!strcmp(cmd, "get_global_invalid")) { reply = daemon_send_simple(h, "get_global_info", "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "set_vg_version")) { if (argc < 5) { printf("set_vg_version <uuid> <name> <ver>\n"); return -1; } uuid = argv[2]; name = argv[3]; ver = atoi(argv[4]); if ((strlen(uuid) == 1) && (uuid[0] == '-')) uuid = NULL; if ((strlen(name) == 1) && (name[0] == '-')) name = NULL; if (uuid && name) { reply = daemon_send_simple(h, "set_vg_info", "uuid = %s", uuid, "name = %s", name, "version = %d", ver, "token = %s", "skip", NULL); } else if (uuid) { reply = daemon_send_simple(h, "set_vg_info", "uuid = %s", uuid, "version = %d", ver, "token = %s", "skip", NULL); } else if (name) { reply = daemon_send_simple(h, "set_vg_info", "name = %s", name, "version = %d", ver, "token = %s", "skip", NULL); } else { printf("name or uuid required\n"); return -1; } print_reply(reply); } else if (!strcmp(cmd, "vg_lookup_name")) { if (argc < 3) { printf("vg_lookup_name <name>\n"); return -1; } name = argv[2]; reply = daemon_send_simple(h, "vg_lookup", "name = %s", name, "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "vg_lookup_uuid")) { if (argc < 3) { printf("vg_lookup_uuid <uuid>\n"); return -1; } uuid = argv[2]; reply = daemon_send_simple(h, "vg_lookup", "uuid = %s", uuid, "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else if (!strcmp(cmd, "vg_lock_type")) { struct dm_config_node *metadata; const char *lock_type; if (argc < 3) { printf("vg_lock_type <uuid>\n"); return -1; } uuid = argv[2]; reply = daemon_send_simple(h, "vg_lookup", "uuid = %s", uuid, "token = %s", "skip", NULL); /* printf("%s\n", reply.buffer.mem); */ metadata = dm_config_find_node(reply.cft->root, "metadata"); if (!metadata) { printf("no metadata\n"); goto out; } lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL); if (!lock_type) { printf("no lock_type\n"); goto out; } printf("lock_type %s\n", lock_type); } else if (!strcmp(cmd, "pv_lookup_uuid")) { if (argc < 3) { printf("pv_lookup_uuid <uuid>\n"); return -1; } uuid = argv[2]; reply = daemon_send_simple(h, "pv_lookup", "uuid = %s", uuid, "token = %s", "skip", NULL); printf("%s\n", reply.buffer.mem); } else { printf("unknown command\n"); goto out_close; } out: daemon_reply_destroy(reply); out_close: daemon_close(h); return 0; }