public inbox for cluster-cvs@sourceware.org help / color / mirror / Atom feed
From: Lon Hohberger <lon@fedoraproject.org> To: cluster-cvs-relay@redhat.com Subject: cluster: STABLE3 - rgmanager: Remove unused proof-of-concept code Date: Mon, 22 Jun 2009 13:33:00 -0000 [thread overview] Message-ID: <20090622133232.79ECE1201EF@lists.fedorahosted.org> (raw) Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=52685e0f57063583d6af537d1ea2e1539e437372 Commit: 52685e0f57063583d6af537d1ea2e1539e437372 Parent: a4c5b74ee1152c6645e77b0a778a83c491d07597 Author: Lon Hohberger <lhh@redhat.com> AuthorDate: Fri May 29 10:30:19 2009 -0400 Committer: Lon Hohberger <lhh@redhat.com> CommitterDate: Mon Jun 22 09:32:02 2009 -0400 rgmanager: Remove unused proof-of-concept code This code implmented a rudimentary A* search dependency engine. Unfortunately: * rgmanager didn't use it * it was buggy and incomplete * it causes lots of compiler warnings Signed-off-by: Lon Hohberger <lhh@redhat.com> --- rgmanager/include/depends.h | 134 --- rgmanager/src/daemons/Makefile | 6 +- rgmanager/src/daemons/depends.c | 2512 --------------------------------------- rgmanager/src/daemons/dtest.c | 810 ------------- rgmanager/src/daemons/test.c | 40 - 5 files changed, 2 insertions(+), 3500 deletions(-) diff --git a/rgmanager/include/depends.h b/rgmanager/include/depends.h deleted file mode 100644 index 72f2958..0000000 --- a/rgmanager/include/depends.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef _DEPENDS_H -#define _DEPENDS_H - -#include <resgroup.h> -#include <list.h> - -typedef enum { - DEP_COLO_UNSPEC = 0, - DEP_COLO_ALWAYS = 1, - DEP_COLO_NEVER = 2 -} dep_colo_t; - -typedef enum { - DEP_REQ_UNSPEC = 0, - DEP_REQ_START = 1, - DEP_REQ_ALWAYS = 2 -} dep_req_t; - -typedef enum { - DEP_FLAG_CYCLIC = 0x1, - DEP_FLAG_TERMINAL = 0x2, - DEP_FLAG_IMPOSSIBLE = 0x4, - DEP_FLAG_IMPLIED = 0x8, - DEP_FLAG_NEVER = 0x10, - DEP_FLAG_ALWAYS = 0x20 -} dep_flag_t; - -typedef enum { - RS_ILLEGAL_NODE = 0x1, - RS_DEAD_NODE = 0x2, - RS_BEEN_STARTED = 0x4, - RS_BEEN_STOPPED = 0x8, - RS_IMMUTABLE = 0x10, - RS_ORDERED = 0x20, - RS_FAILBACK = 0x40, - RS_BROKEN = 0x80 -} rs_flag_t; - -typedef enum { - DN_BROKEN_COLO = 0x1, - DN_BROKEN_NONCOLO = 0x2, - DN_BROKEN_REQ = 0x4 -} dep_node_flag_t; - -typedef struct _dn_node { - list_head(); - char *dn_name; - struct _dep *dn_ptr; - dep_colo_t dn_colo; - dep_req_t dn_req; - int dn_traversed; - dep_node_flag_t dn_flags; -} dep_node_t; - -typedef struct _dep { - list_head(); - char *d_name; - dep_node_t *d_nodes; - dep_flag_t d_flags; - int d_hits; - int d_deps; -} dep_t; - - -typedef struct _res_state { - rg_state_t rs_status; - int *rs_allowed; - int rs_allowed_len; - rs_flag_t rs_flags; -} dep_rs_t; - - -/* List of operations to take current state -> ideal state */ -typedef struct _dep_op { - list_head(); - struct _dep_op *do_child; - char do_res[64]; - int do_op; - int do_nodeid; - int do_iter; -} dep_op_t; - - - -int construct_depends(int ccsfd, dep_t **deps); -void deconstruct_depends(dep_t **deps); -void print_depends(FILE *fp, dep_t **deps); -void print_depends_dot(FILE *fp, dep_t **deps); - -/* Check cluster state given: - * all resource (service) states, - * all available nodes to each resource, - * all online nodes. - * - * Returns # of errors (negative), # of stopped services (positive), or - * 0 if the cluster state is ideal. - * - * Note: Call dep_reset() when you're done to clear error flags in the - * graph. - */ -int dep_check(dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen); - -/* Clear error flags in the graph + states */ -void dep_reset(dep_t **deps, dep_rs_t *rs, int slen); - -/* Print out our errors */ -void dep_print_errors(dep_t **deps, dep_rs_t *rs, int slen); - -dep_rs_t * dep_rstate_alloc(resource_node_t **restree, fod_t **domains, - int *nodes, int nlen, int *rs_cnt); -void dep_rstate_free(dep_rs_t *states, int cnt); - -/* Dump graphviz-compatible output to fp (includes errors in graph */ -int dep_cluster_state_dot(FILE *fp, dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen); -int dep_cluster_state(FILE *fp, dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen); - -/* Calculate transition list */ -int dep_calc_trans(dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen, dep_op_t **op_list, int *iter); - -int dep_copy_tree(dep_t **dest, dep_t **src); - -int dep_apply_trans(dep_t **deps, dep_rs_t *states, - int slen, dep_op_t **op_list); - -int dep_check_operation(char *res, int operation, int target, - dep_t **deps, dep_rs_t *_states, - int slen, int *nodes, int nlen, dep_op_t **oplist); -int dep_tree_dup(dep_t **dest, dep_t **src); - -#endif diff --git a/rgmanager/src/daemons/Makefile b/rgmanager/src/daemons/Makefile index 14f269a..7ce5a96 100644 --- a/rgmanager/src/daemons/Makefile +++ b/rgmanager/src/daemons/Makefile @@ -14,8 +14,7 @@ include $(OBJDIR)/make/clean.mk include $(OBJDIR)/make/install.mk include $(OBJDIR)/make/uninstall.mk -OBJS1= depends.o \ - fo_domain.o \ +OBJS1= fo_domain.o \ groups.o \ main.o \ reslist.o \ @@ -37,8 +36,7 @@ OBJS2= test-noccs.o OBJS3= dtest-noccs.o -SHAREDOBJS= depends-noccs.o \ - fo_domain-noccs.o \ +SHAREDOBJS= fo_domain-noccs.o \ restart_counter.o \ reslist-noccs.o \ resrules-noccs.o \ diff --git a/rgmanager/src/daemons/depends.c b/rgmanager/src/daemons/depends.c deleted file mode 100644 index d9dda8d..0000000 --- a/rgmanager/src/daemons/depends.c +++ /dev/null @@ -1,2512 +0,0 @@ -/** @file - * CCS dependency parsing, based on failover domain parsing - * Transition generation based on simple brute-force / best-first - * tree search. - * - * Allows specification of two types of rules concerning service states: - * - * - requirement: A -> B means B must be running either for A to start or - * at all times (if B stops, A will be stopped) - * - colocation: A -> B means that A must be run on the same node as B - * (note that colocation doesn't mean that B must be running; - * to do both, you must enable a requirement). - * A X> B means that A must be run on a different node from B. - * - * Known bugs: If more than 1 error is introduced in the graph, - * the 'find-ideal-state' function sometimes will refuse to run - */ -#include <string.h> -#include <list.h> -#include <time.h> -#include <restart_counter.h> -#include <logging.h> -#include <resgroup.h> -#include <reslist.h> -#include <ccs.h> -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> -#include <members.h> -#include <reslist.h> -#include <depends.h> -#include <ctype.h> - -struct _try { - dep_op_t *ops; - int score; - int depth; -}; - -void deconstruct_dep(dep_t *dep); -int dep_graph_validate(dep_t **deps); -fod_t *fod_find_domain(fod_t **domains, char *name); - -//#define DEBUG - -#ifdef NO_CCS -#define ccs_get(fd, query, ret) conf_get(query, ret) -#endif - -/* - <dependencies> - <dependency name="service:bar"> - <target name="service:foo" colocate="always|never|unspec" - require="start|always|unspec"/> - </dependency> - </dependencies> - */ - -static dep_node_t * -get_dep_node(int ccsfd, char *base, int idx, dep_t *dep, int *_done) -{ - dep_node_t *dn; - char xpath[256]; - char *ret; - int c; - - *_done = 0; - snprintf(xpath, sizeof(xpath), "%s/target[%d]/@name", - base, idx); - if (ccs_get(ccsfd, xpath, &ret) != 0) { - *_done = 1; - return NULL; - } - - list_for(&dep->d_nodes, dn, c) { - if (strcasecmp(ret, dn->dn_name)) - continue; - - printf("#XX: Target %s defined multiple times in " - "dependency block %s\n", ret, dep->d_name); - free(ret); - return NULL; - } - - dn = malloc(sizeof(*dn)); - if (!dn) - return NULL; - memset(dn, 0, sizeof(*dn)); - - /* Already malloc'd; simply store */ - dn->dn_name = ret; - dn->dn_ptr = NULL; - dn->dn_req = DEP_REQ_UNSPEC; - dn->dn_colo = DEP_COLO_UNSPEC; - - snprintf(xpath, sizeof(xpath), "%s/target[%d]/@require", - base, idx); - if (ccs_get(ccsfd, xpath, &ret) == 0 && ret) { - - if (!strcasecmp(ret, "start")) { - dn->dn_req = DEP_REQ_START; - } else if (!strcasecmp(ret, "always")) { - dn->dn_req = DEP_REQ_ALWAYS; - } else if (!strcasecmp(ret, "unspec")) { - dn->dn_req = DEP_REQ_UNSPEC; - } else { - dn->dn_req = atoi(ret); - } - - free(ret); - } - - snprintf(xpath, sizeof(xpath), "%s/target[%d]/@colocate", - base, idx); - if (ccs_get(ccsfd, xpath, &ret) == 0 && ret) { - - if (!strcasecmp(ret, "never")) { - dn->dn_colo = DEP_COLO_NEVER; - } else if (!strcasecmp(ret, "always")) { - dn->dn_colo = DEP_COLO_ALWAYS; - } else if (!strcasecmp(ret, "unspec")) { - dn->dn_colo = DEP_COLO_UNSPEC; - } else { - dn->dn_colo = atoi(ret); - } - - free(ret); - } - - if (dn->dn_req == DEP_REQ_UNSPEC && - dn->dn_colo == DEP_COLO_UNSPEC) { - printf("Dropping dependency target %s: no rule in use\n", - dn->dn_name); - free(dn->dn_name); - free(dn); - return NULL; - } - - return dn; -} - - -static dep_t * -get_dep(int ccsfd, char *base, int idx, dep_t **deps, int *_done) -{ - dep_t *dep; - dep_node_t *dn; - char xpath[256]; - char *ret; - int x = 1, c; - int done; - - *_done = 0; - snprintf(xpath, sizeof(xpath), "%s/dependency[%d]/@name", - base, idx); - if (ccs_get(ccsfd, xpath, &ret) != 0) { - *_done = 1; - return NULL; - } - - list_for(deps, dep, c) { - if (strcasecmp(dep->d_name, ret)) - continue; - - printf("#XX: Dependency block %s defined multiple " - "times\n", ret); - free(ret); - return NULL; - } - - dep = malloc(sizeof(*dep)); - if (!dep) - return NULL; - memset(dep, 0, sizeof(*dep)); - dep->d_name = ret; - dep->d_nodes = NULL; - dep->d_flags = 0; - dep->d_hits = 0; - dep->d_deps = 0; - - snprintf(xpath, sizeof(xpath), "%s/dependency[%d]", - base, idx); - - do { - dn = get_dep_node(ccsfd, xpath, x++, dep, &done); - if (dn) { - dep->d_deps++; - list_insert(&dep->d_nodes, dn); - } - } while (!done); - - if (!dep->d_nodes) { - printf("Dropping dependency block %s: No targets\n", - dep->d_name); - free(dep->d_name); - free(dep); - return NULL; - } - - return dep; -} - - -/** - * Constructs links in the dependency tree - */ -static void -dep_construct_tree(dep_t **deps) -{ - dep_t *curr, *curr2, *dep; - dep_node_t *dn; - int done, found, a, b, c; - - do { - done = 1; - list_for(deps, curr, a) { - list_for(&curr->d_nodes, dn, b) { - found = 0; - list_for(deps, curr2, c) { - if (!strcasecmp(curr2->d_name, - dn->dn_name)) { - if (!dn->dn_ptr) { - dn->dn_ptr = curr2; - dn->dn_ptr->d_hits++; - } - found = 1; - } - } - - if (!found) { - done=0; - - dep = malloc(sizeof(*dep)); - if (!dep) - return; - memset(dep, 0, sizeof(*dep)); - dep->d_name = strdup(dn->dn_name); - if (!dep->d_name) - return; - dep->d_nodes = NULL; - dep->d_flags = DEP_FLAG_IMPLIED; - dep->d_hits = 1; - dep->d_deps = 0; - dn->dn_ptr = dep; - - list_insert(deps, dep); - - break; - } - } - - if (!done) - break; - } - } while (!done); -} - - -/** - * similar API to failover domain - */ -int -construct_depends(int ccsfd, dep_t **deps) -{ - char xpath[256]; - int x = 1, done, c; - dep_t *dep, *curr; - - snprintf(xpath, sizeof(xpath), - RESOURCE_TREE_ROOT "/dependencies"); - - do { - dep = get_dep(ccsfd, xpath, x++, deps, &done); - if (dep) { - list_insert(deps, dep); - } - } while (!done); - - /* Insert terminal dependency nodes & construct tree */ - /* XXX optimize */ - dep_construct_tree(deps); - - dep_graph_validate(deps); - - do { - done = 1; - list_for(deps, curr, c) { - if (curr->d_flags & - (DEP_FLAG_CYCLIC | DEP_FLAG_IMPOSSIBLE)) { - printf("Removing dependency block %s: " - "Invalid\n", curr->d_name); - done = 0; - - list_remove(deps, curr); - deconstruct_dep(curr); - break; - } - } - } while (!done); - - return 0; -} - - -void -deconstruct_dep(dep_t *dep) -{ - dep_node_t *node; - - while ((node = dep->d_nodes)) { - list_remove(&dep->d_nodes, node); - if (node->dn_name) - free(node->dn_name); - free(node); - } - - if (dep->d_name) - free(dep->d_name); - free(dep); -} - - -void -deconstruct_depends(dep_t **deps) -{ - dep_t *dep = NULL; - - while ((dep = *deps)) { - list_remove(deps, dep); - deconstruct_dep(dep); - } -} - - -static inline dep_rs_t * -_find_state(char *name, dep_rs_t *sl, int slen) -{ - int x; - - for (x = 0; x < slen; x++) - if (!strcasecmp(sl[x].rs_status.rs_name, name)) - return &sl[x]; - - return NULL; -} - - -static int -rs_running(char *name, dep_rs_t *sl, int slen) -{ - dep_rs_t *rs = NULL; - - if (name) { - rs = _find_state(name, sl, slen); - } else if (slen == 1) { - rs = sl; - } - - if (rs) { - if (rs->rs_flags & RS_BROKEN) - return -1; - return (rs->rs_status.rs_state == RG_STATE_STARTING || - rs->rs_status.rs_state == RG_STATE_STARTED || - rs->rs_status.rs_state == RG_STATE_STOPPING ); - } - - return 0; -} - - -int -dep_tree_dup(dep_t **dest, dep_t **src) -{ - dep_t *dep, *dep_cpy; - dep_node_t *dn, *dn_cpy; - int a, b; - - list_for(src, dep, a) { - while ((dep_cpy = malloc(sizeof(dep_t))) == NULL) - usleep(10000); - memset(dep_cpy, 0, sizeof(dep_t)); - while ((dep_cpy->d_name = strdup(dep->d_name)) == NULL) - usleep(10000); - - dep_cpy->d_flags &= ~(DEP_FLAG_ALWAYS|DEP_FLAG_NEVER); - - list_for(&dep->d_nodes, dn, b) { - while ((dn_cpy = malloc(sizeof(dep_node_t))) == NULL) - usleep(10000); - memset(dn_cpy, 0, sizeof(dep_node_t)); - while ((dn_cpy->dn_name = strdup(dn->dn_name)) == NULL) - usleep(10000); - dn_cpy->dn_colo = dn->dn_colo; - dn_cpy->dn_req = dn->dn_req; - - /* Flags are all errors right now... */ - /* dn_cpy->dn_flags = dn->dn_flags; */ - list_insert(&dep_cpy->d_nodes, dn_cpy); - } - - list_insert(dest, dep_cpy); - } - - /* Construct internal tree */ - dep_construct_tree(dest); - - return 0; -} - - -static void -dep_tree_print(FILE *fp, dep_t *start, dep_t *dep, int level) -{ - dep_node_t *dn = NULL; - int x, c; - - if (!dep) - return; - - if ((dep == start) && level) { - fprintf(fp, "[cycles to %s]\n", start->d_name); - return; - } - - fprintf(fp, "%s\n",dep->d_name); - - if (dep->d_nodes) { - list_for(&dep->d_nodes, dn, c) { - for (x = 0; x < level; x++) - fprintf(fp, " "); - fprintf(fp, "|\n"); - for (x = 0; x < level; x++) - fprintf(fp, " "); - fprintf(fp, "+-"); - switch(dn->dn_colo) { - case DEP_COLO_UNSPEC: - fprintf(fp, "--"); - break; - case DEP_COLO_ALWAYS: - fprintf(fp, "Ca"); - break; - case DEP_COLO_NEVER: - fprintf(fp, "Cn"); - break; - } - switch(dn->dn_req) { - case DEP_REQ_UNSPEC: - fprintf(fp, "--"); - break; - case DEP_REQ_START: - fprintf(fp, "Rs"); - break; - case DEP_REQ_ALWAYS: - fprintf(fp, "Ra"); - break; - } - fprintf(fp, "-> "); - - if (dn->dn_traversed) { - fprintf(fp, "[cycles to %s]\n", - dn->dn_ptr->d_name); - } else { - dn->dn_traversed = 1; - dep_tree_print(fp, start, dn->dn_ptr, level+1); - dn->dn_traversed = 0; - } - - } - } -} - - -static void -_dot_clean_string(char *str) -{ - int x; - - /* - if (strncmp(str, "service:", 8) == 0) - memmove(str, str+8, strlen(str)-8+1); - */ - - if (!isalpha(str[0])) - str[0] = '_'; - - for (x = 0; x < strlen(str); x++) { - if (isalnum(str[x])) - continue; - if (str[x] == '_' || str[x] == '-') - continue; - str[x] = '_'; - } -} - - -void -print_dep_tree_dot(FILE *fp, dep_t *start, dep_t *dep, int level) -{ - dep_node_t *dn = NULL; - char src[64], dest[64]; - int c; - - if (!dep) - return; - - if ((dep == start) && level) - return; - - if (dep->d_nodes) { - list_for(&dep->d_nodes, dn, c) { - if (dn->dn_traversed) - continue; - - strncpy(src, dep->d_name, sizeof(src)); - strncpy(dest, dn->dn_name, sizeof(dest)); - _dot_clean_string(src); - _dot_clean_string(dest); - - dn->dn_traversed = 1; - switch(dn->dn_colo) { - case DEP_COLO_UNSPEC: - break; - case DEP_COLO_ALWAYS: - fprintf(fp, "\tedge [color=black, " - "arrowhead=diamond, label=\"Ca\""); - if (dn->dn_flags & DN_BROKEN_COLO) - fprintf(fp, ", style=dashed"); - else - fprintf(fp, ", style=solid"); - fprintf(fp, "];\n"); - fprintf(fp, "\t%s -> %s;\n", src, dest); - break; - case DEP_COLO_NEVER: - fprintf(fp, "\tedge [color=red, " - "arrowhead=diamond, label=\"Cn\""); - if (dn->dn_flags & DN_BROKEN_NONCOLO) - fprintf(fp, ", style=dashed"); - else - fprintf(fp, ", style=solid"); - fprintf(fp, "];\n"); - fprintf(fp, "\t%s -> %s;\n", src, dest); - break; - } - switch(dn->dn_req) { - case DEP_REQ_UNSPEC: - break; - case DEP_REQ_START: - fprintf(fp, "\tedge [color=green, " - "arrowhead=vee, label=\"Rs\""); - if (dn->dn_flags & DN_BROKEN_REQ) - fprintf(fp, ", style=dashed"); - else - fprintf(fp, ", style=solid"); - fprintf(fp, "];\n"); - fprintf(fp, "\t%s -> %s;\n", src, dest); - break; - case DEP_REQ_ALWAYS: - fprintf(fp, "\tedge [color=black, " - "arrowhead=vee, label=\"Ra\""); - if (dn->dn_flags & DN_BROKEN_REQ) - fprintf(fp, ", style=dashed"); - else - fprintf(fp, ", style=solid"); - fprintf(fp, "];\n"); - fprintf(fp, "\t%s -> %s;\n", src, dest); - break; - } - - print_dep_tree_dot(fp, start, dn->dn_ptr, level+1); - - } - } -} - - -/** - * Check for cyclic 'require' dependency. - */ -static int -find_cyclic_req(dep_t *dep, dep_t *what) -{ - dep_node_t *dn; - int ret, c; - - if (dep == what) - return 2; - - if (!dep->d_nodes) - return 0; - - /* initialize */ - if (what == NULL) - what = dep; - - list_for(&dep->d_nodes, dn, c) { - - if (!dn->dn_traversed && - dn->dn_req != DEP_REQ_UNSPEC) { - dn->dn_traversed = 1; - ret = find_cyclic_req(dn->dn_ptr, what); - dn->dn_traversed = 0; - - if (ret == 2) { - printf("Error: Cyclic Requirement: \n"); - printf(" %s ... -> %s -> %s\n", - what->d_name, - dep->d_name, - dn->dn_ptr->d_name); - } - if (ret) - return 1; - } else if (dn->dn_traversed) - return 1; - } - - return 0; -} - - -/** - * Tag all nodes which have colocation requirements - */ -static int -tag_colo(dep_t *dep, dep_t *what, dep_colo_t colo) -{ - dep_node_t *dn; - int ret = 0, c; - - /* How did we get here? */ - switch(colo) { - case DEP_COLO_ALWAYS: - if (dep->d_flags & DEP_FLAG_NEVER) - ret = 1; - dep->d_flags |= DEP_FLAG_ALWAYS; - break; - case DEP_COLO_NEVER: - if (dep->d_flags & DEP_FLAG_ALWAYS) - ret = 1; - dep->d_flags |= DEP_FLAG_NEVER; - break; - default: - break; - } - - if (dep == what) - goto out; - - if (!dep->d_nodes) - goto out; - - /* Start if this is the first call*/ - if (what == NULL) - what = dep; - - list_for(&dep->d_nodes, dn, c) { - - if (!dn->dn_traversed) { - dn->dn_traversed = 1; - ret += tag_colo(dn->dn_ptr, what, dn->dn_colo); - dn->dn_traversed = 0; - } - - } - -out: - if (ret) - dep->d_flags |= DEP_FLAG_IMPOSSIBLE; - return ret; -} - - -int -dep_print_dep_errors(dep_t **deps) -{ - dep_t *dep; - dep_node_t *dn; - int a, b; - - list_for(deps, dep, a) { - list_for(&dep->d_nodes, dn, b) { - if (dn->dn_flags & DN_BROKEN_COLO) { - printf("Resource %s must colocate with " - "resource %s\n", dep->d_name, - dn->dn_name); - } - if (dn->dn_flags & DN_BROKEN_NONCOLO) { - printf("Resource %s must never colocate with " - "resource %s\n", dep->d_name, - dn->dn_name); - } - if (dn->dn_flags & DN_BROKEN_REQ) { - printf("Resource %s depends on " - "resource %s\n", dep->d_name, - dn->dn_name); - } - } - } - - return 0; -} - - -int -dep_print_state_errors(dep_rs_t *rs, int slen) -{ - int x; - - for (x = 0; x < slen; x++) { - if (rs[x].rs_flags & RS_ILLEGAL_NODE) - printf("Resource %s on illegal node %d\n", - rs[x].rs_status.rs_name, - rs[x].rs_status.rs_owner); - if (rs[x].rs_flags & RS_DEAD_NODE) - printf("Resource %s on dead/offline node %d\n", - rs[x].rs_status.rs_name, - rs[x].rs_status.rs_owner); - } - return 0; -} - - -/** - * clear our loop detection - */ -int -dep_clear_dep_errors(dep_t **deps) -{ - dep_t *dep; - dep_node_t *dn; - int a, b; - - list_for(deps, dep, a) { - dep->d_flags &= ~(DEP_FLAG_ALWAYS | DEP_FLAG_NEVER); - - list_for(&dep->d_nodes, dn, b) { - dn->dn_traversed = 0; - dn->dn_flags = 0; - } - } - - return 0; -} - - -int -dep_clear_traversed(dep_t **deps) -{ - dep_t *dep; - dep_node_t *dn; - int a, b; - - list_for(deps, dep, a) { - list_for(&dep->d_nodes, dn, b) { - dn->dn_traversed = 0; - } - } - - return 0; -} - - -int -dep_clear_state_errors(dep_rs_t *rs, int slen) -{ - int x; - for (x = 0; x < slen; x++) - rs[x].rs_flags &= ~(RS_ILLEGAL_NODE|RS_DEAD_NODE); - return 0; -} - - -void -dep_reset(dep_t **deps, dep_rs_t *rs, int slen) -{ - dep_clear_dep_errors(deps); - dep_clear_state_errors(rs, slen); -} - - -void -dep_print_errors(dep_t **deps, dep_rs_t *rs, int slen) -{ - dep_print_dep_errors(deps); - dep_print_state_errors(rs, slen); -} - - -int -dep_graph_validate(dep_t **deps) -{ - dep_t *dep; - dep_flag_t f; - int a; - - list_for(deps, dep, a) { - - if (find_cyclic_req(dep, NULL)) { - printf("Cyclic requirement dependency in block %s\n", - dep->d_name); - dep->d_flags |= DEP_FLAG_CYCLIC; - } - - tag_colo(dep, NULL, 0); - } - - f = (DEP_FLAG_ALWAYS | DEP_FLAG_NEVER); - list_for(deps, dep, a) { - if (((dep->d_flags & f) == f) || - (dep->d_flags & DEP_FLAG_IMPOSSIBLE)) { - printf("Graph %s: colocation conflict\n", dep->d_name); - dep->d_flags |= DEP_FLAG_IMPOSSIBLE; - } - } - - return 0; -} - - -void -print_depends(FILE *fp, dep_t **deps) -{ - dep_t *dep; - int a; - - list_for(deps, dep, a) { - if (dep->d_nodes && !(dep->d_flags & DEP_FLAG_IMPLIED) && - dep->d_hits == 0) { - dep_tree_print(fp, dep, dep, 0); - fprintf(fp,"\n"); - } - } -} - - -static void -_print_depends_dot(FILE *fp, dep_t **deps) -{ - dep_t *dep; - int a; - - list_for(deps, dep, a) { - print_dep_tree_dot(fp, dep, dep, 0); - } - - dep_clear_traversed(deps); -} - - -void -print_depends_dot(FILE *fp, dep_t **deps) -{ - fprintf(fp, "digraph G {\n"); - _print_depends_dot(fp, deps); - fprintf(fp, "}\n"); -} - - -/** - * check to ensure a resource is on an allowed node. - * Note - makes no assumption about the actual resource state; it could be - * in the stopped state. - */ -int -dep_check_res_loc(dep_rs_t *state) -{ - int x; - - if (!rs_running(NULL, state, 1)) { - /* Not running = location is perfectly fine ... sort of */ - return 0; - } - - if (!state->rs_allowed || state->rs_allowed_len <= 0) - return 0; - - for (x = 0; x < state->rs_allowed_len; x++) { - if (state->rs_status.rs_owner == state->rs_allowed[x]) - return 0; - } - - /* Didn't match a legal node -> fail */ - state->rs_flags |= RS_ILLEGAL_NODE; - return 1; -} - - -static dep_t * -find_dep(dep_t **deps, char *name) -{ - dep_t *dep = NULL; - int a; - - if (!deps) - return NULL; - - list_for(deps, dep, a) { - if (!strcasecmp(dep->d_name, name)) - return dep; - } - - return NULL; -} - - -/** - * traverses the requirements tree looking for 'name' - * returns 1 if found, 0 if not - */ -static int -_tree_walk_req(dep_t *dep, dep_rs_t *state, dep_rs_t *sl, int slen) -{ - dep_node_t *dn; - int errors = 0, ret, a; - - if (!dep || !dep->d_nodes) - return 0; - - list_for(&dep->d_nodes, dn, a) { - - /* If we have a specified requirement... */ - ret = 0; - if (!dn->dn_traversed && - dn->dn_req != DEP_REQ_UNSPEC) { - - /* see if our child is running. If not, we're done */ - ret = rs_running(dn->dn_name, sl, slen); - - /* XXX check for req-start vs. req-always */ - if (ret <= 0) { - dn->dn_flags |= DN_BROKEN_REQ; - state->rs_flags |= RS_BROKEN; - ret = 1; - } else { - dn->dn_traversed = 1; - ret = _tree_walk_req(dn->dn_ptr, - _find_state(dn->dn_name, sl, slen), sl, slen); - dn->dn_traversed = 0; - } - - if (ret) { - errors += ret; - dn->dn_flags |= DN_BROKEN_REQ; - state->rs_flags |= RS_BROKEN; - } - } - } - - return errors; -} - -/* - * Returns nonzero if something requires this resource, 0 if not - */ -int -dep_check_requires(dep_t **deps, dep_rs_t *state, dep_rs_t *states, int slen) -{ - dep_t *dep; - int errors = 0, a; - - /* Check to see if anything depends on this (not-running) resource */ - list_for(deps, dep, a) { - errors += _tree_walk_req(dep, NULL, /*state->rs_status.rs_name,*/ - states, slen); - } - - /* Flag requirements on any broken-dep resources as broken, too... */ - dep_clear_traversed(deps); - - return errors; -} - - -/** - * Check to see if this resource is causing a conflict. It can cause a - * conflict if it is stopped but other resources depend on it. - * If it is running, it can not cause a requirement conflict, but it might - * cause a colocation conflict. - */ -static int -_dep_check_requires(dep_t **deps, dep_rs_t *state, dep_rs_t *states, int slen) -{ - /* if not running, it has no dependencies */ - if (!rs_running(NULL, state, 1)) - return 0; - - return _tree_walk_req(find_dep(deps, state->rs_status.rs_name), - state, states, slen); - - //return dep_check_requires(deps, state, states, slen); -} - -/** - * Checks the tree to see if there's a colocation requiremet on the given - * resource. Returns 1 if found, 0 if not. - * returns 1 if found, 0 if not We don't need to recurse on this one. - */ -static int -_tree_walk_colo(dep_t *dep, dep_t *start, char *name, dep_rs_t *sl, int slen) -{ - dep_node_t *dn; - dep_rs_t *state; - int errors = 0, a; - - if (dep == start) - return 0; - - if (!dep->d_nodes) - return 0; - - /* Start if this is the first call*/ - if (start == NULL) - start = dep; - - state = _find_state(dep->d_name, sl, slen); - if (!state) - return 0; - - list_for(&dep->d_nodes, dn, a) { - - /* If we have a specified requirement... */ - if (!dn->dn_traversed && - dn->dn_colo == DEP_COLO_ALWAYS) { - - if (!strcasecmp(dn->dn_name, name) && - !(dn->dn_flags & DN_BROKEN_COLO)) { - /* Broken colocation req */ - state->rs_flags |= RS_BROKEN; - dn->dn_flags |= DN_BROKEN_COLO; - ++errors; - } - dn->dn_traversed = 1; - errors += _tree_walk_colo(dn->dn_ptr, start, name, - sl, slen); - dn->dn_traversed = 0; - } - } - - return errors; -} - - -/** - * Checks the immediate children of the given dependency to see if there's a - * non-colocation requiremet on the given resource. Returns 1 if found, - * 0 if not. - */ -static int -_tree_walk_noncolo(dep_t *dep, dep_t *start, char *name, dep_rs_t *sl, - int slen) -{ - dep_node_t *dn; - dep_rs_t *state; - int errors = 0, a; - - if (dep == start) - return 0; - - if (!dep->d_nodes) - return 0; - - /* Start if this is the first call*/ - if (start == NULL) - start = dep; - - state = _find_state(dep->d_name, sl, slen); - if (!state) - return 0; - - list_for(&dep->d_nodes, dn, a) { - - /* If we have a specified requirement... */ - if (dn->dn_colo == DEP_COLO_NEVER) { - - if (!strcasecmp(dn->dn_name, name) && - !(dn->dn_flags & DN_BROKEN_COLO)) { - /* Broken noncolo req */ - state->rs_flags |= RS_BROKEN; - dn->dn_flags |= DN_BROKEN_NONCOLO; - ++errors; - } - } - } - - return errors; -} - - -int -dep_check_colo(dep_t **deps, dep_rs_t *states, int slen, - char *name, int nodeid) -{ - dep_t *dep; - int x, errors = 0; - - if (!deps) - return 0; - dep = find_dep(deps, name); - if (!dep) - return 0; - - for (x = 0; x < slen; x++) { - - if (!rs_running(NULL, &states[x], 1)) { - /* - * Non-running resources don't cause colo/noncolo - * conflicts - */ - continue; - } - - /* - * Two resources on different nodes... see if the specified - * one is causing a colocation conflict (e.g. another one - * must colocate with it) - */ - if (states[x].rs_status.rs_owner != nodeid) { - errors += _tree_walk_colo(dep, NULL, - states[x].rs_status.rs_name, states, - slen); - } - - /* - * two resources on the same node... see if the specified one - * is causing a colocation conflict (e.g. another one must - * NOT colocate with it) - */ - if (states[x].rs_status.rs_owner == nodeid) { - errors += _tree_walk_noncolo(dep, NULL, - states[x].rs_status.rs_name, - states, slen); - } - } - - dep_clear_traversed(deps); - - return errors; -} - - -/** - * Check to see if this resource is causing a colocation conflict. It can - * not cause if it is stopped. If it is running, it can cause a colocation - * conflict if something must not colocate with it. - */ -static int -_dep_check_colo(dep_t **deps, dep_rs_t *states, int slen, dep_rs_t *state) -{ - if (!rs_running(NULL, state, 1)) { - /* not running : cannot be causing a colo conflict */ - return 0; - } - - return dep_check_colo(deps, - states, - slen, - state->rs_status.rs_name, - state->rs_status.rs_owner); -} - - -int -dep_check_online(dep_rs_t *rs, int *nodes, int nlen) -{ - int x; - - if (!rs_running(NULL, rs, 1)) { - return 0; - } - for (x = 0; x < nlen; x++){ - if (rs->rs_status.rs_owner == nodes[x]) - return 0; - } - - rs->rs_flags |= RS_DEAD_NODE; - return 1; -} - - -/** - * Validate the current state of the cluster. This traverses the dependency - * graph looking for conflicts, as well as obvious errors (e.g. resource - * outside failover domain constraint, for example. - * - * @return -1 for invalid, 0 for ideal, or the # of services - * which need to be started to become ideal. - */ -int -dep_check(dep_t **deps, dep_rs_t *states, int slen, int *nodes, int nlen) -{ - int x, ret = 0, errors = 0; - - dep_clear_dep_errors(deps); - dep_clear_state_errors(states, slen); - - for (x = 0; x < slen; x++) { - - if (states[x].rs_status.rs_state == RG_STATE_STOPPED) - ++ret; - - /* - * Pass 1: Check for services started on dead nodes - */ - errors += dep_check_online(&states[x], nodes, nlen); - - /* - * Pass 2: Check obvious legal-targets for resources - * (failover domain) - */ - errors += dep_check_res_loc(&states[x]); - - /* - * Pass 3: Check to see if this resource has all of its a - * resource dependencies satisfied. - */ - errors += _dep_check_requires(deps, &states[x], states, slen); - - /* - * Pass 4: Check to see if this resource is causing a - * colocation conflict (e.g. is cohabiting with a resource - * which must run apart from it) - */ - errors += _dep_check_colo(deps, states, slen, &states[x]); - } - - if (errors) - return -errors; - - return ret; -} - - -int -dep_cluster_state_dot(FILE *fp, dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen) -{ - int x, y, z, tmp, off = 0; - char str[64]; - - fprintf(fp, "digraph G {\n"); - - /* Print out node states */ - for (x = 0; x < nlen; x++) { - fprintf(fp, "\tsubgraph cluster_%d {\n", x); - fprintf(fp, "\t\tlabel=node%d;\n", nodes[x]); - fprintf(fp, "\t\tstyle=filled;\n"); - fprintf(fp, "\t\tcolor=lightgrey;\n"); - fprintf(fp, "\t\tfontcolor=black;\n"); - fprintf(fp, "\t\tnode [style=filled, color=lightgrey, " - "fontcolor=lightgrey];\n"); - - z = 0; - - for (y = 0; y < slen; y++) { - if (rs_running(NULL, &states[y], 1) && - states[y].rs_status.rs_owner == nodes[x]) { - tmp = 0; - if (!states[y].rs_allowed_len) - tmp = 1; - else { - for (z = 0; z<states[y].rs_allowed_len; - z++) { - if (states[y].rs_allowed[z] == - states[y].rs_status.rs_owner) { - tmp = 1; - break; - } - } - } - - ++z; - - if (!tmp) { - fprintf(fp, "\t\tnode [style=filled, " - "color=\"#ff6060\", " - "shape=box, " - "fontcolor=black];\n"); - } else { - fprintf(fp, "\t\tnode [style=filled, " - "color=white, shape=box, " - "fontcolor=black];\n"); - } - - strncpy(str, states[y].rs_status.rs_name, - sizeof(str)); - _dot_clean_string(str); - fprintf(fp, "\t\t%s;\n", str); - } - } - - if (!z) { - snprintf(str, sizeof(str), "node%d", x); - fprintf(fp, "\t\t%s;\n", str); - } - fprintf(fp, "\t}\n"); - } - - /* Show all 'started' on dead node resources in a red "node" */ - off = 0; - for (x = 0; x < slen; x++) { - - if (!(states[x].rs_flags & RS_DEAD_NODE)) - continue; - - if (!off) { - off = 1; - fprintf(fp, "\tsubgraph cluster_%d {\n", nlen+1); - fprintf(fp, "\t\tlabel=Dead;\n"); - fprintf(fp, "\t\tstyle=filled;\n"); - fprintf(fp, "\t\tcolor=\"#ff6060\";\n"); - fprintf(fp, "\t\tfontcolor=black;\n"); - fprintf(fp, "\t\tnode [color=white, style=filled, " - "shape=box, fontcolor=black];\n"); - } - - strncpy(str, states[x].rs_status.rs_name, sizeof(str)); - _dot_clean_string(str); - fprintf(fp, "\t\t%s;\n", str); - } - - if (off) - fprintf(fp, "\t}\n"); - - /* Show all 'stopped' in a 'stopped' "node" */ - fprintf(fp, "\tsubgraph cluster_%d {\n", nlen+2); - fprintf(fp, "\t\tstyle=filled;\n"); - fprintf(fp, "\t\tcolor=\"#60ff60\";\n"); - fprintf(fp, "\t\tfontcolor=black;\n"); - fprintf(fp, "\t\tlabel=Stopped;\n"); - fprintf(fp, "\t\tnode [color=white, style=filled, shape=box, " - "fontcolor=black];\n"); - - z = 0; - for (x = 0; x < slen; x++) { - - if (states[x].rs_status.rs_state != RG_STATE_STOPPED) - continue; - - strncpy(str, states[x].rs_status.rs_name, sizeof(str)); - _dot_clean_string(str); - - ++z; - fprintf(fp, "\t\t%s;\n", str); - } - - if (!z) { - fprintf(fp, "\t\tnode [style=filled, color=\"#60ff60\", " - "fontcolor=\"#60ff60\"];\n"); - fprintf(fp, "\t\tStopped;\n"); - } - - fprintf(fp, "\t}\n"); - - /* Show all 'disabled' in a 'disabled' "node" */ - fprintf(fp, "\tsubgraph cluster_%d {\n", nlen+3); - fprintf(fp, "\t\tlabel=Disabled;\n"); - fprintf(fp, "\t\tstyle=filled;\n"); - fprintf(fp, "\t\tcolor=\"#6060ff\";\n"); - fprintf(fp, "\t\tfontcolor=black;\n"); - fprintf(fp, "\t\tnode [color=white, style=filled, shape=box, " - "fontcolor=black];\n"); - - z = 0; - for (x = 0; x < slen; x++) { - - if (states[x].rs_status.rs_state != RG_STATE_DISABLED) - continue; - - ++z; - strncpy(str, states[x].rs_status.rs_name, sizeof(str)); - _dot_clean_string(str); - fprintf(fp, "\t\t%s;\n", str); - } - - if (!z) { - fprintf(fp, "\t\tnode [style=filled, color=\"#6060ff\", " - "fontcolor=\"#6060ff\"];\n"); - fprintf(fp, "\t\tDisabled;\n"); - } - - fprintf(fp, "\t}\n"); - - _print_depends_dot(fp, deps); - - fprintf(fp, "}\n"); - - return 0; -} - - -int -dep_cluster_state(FILE *fp, dep_t **deps, dep_rs_t *states, int slen, - int *nodes, int nlen) -{ - int x, y, z, tmp, off = 0; - - /* Print out node states */ - for (x = 0; x < nlen; x++) { - fprintf(fp, "Node %d\n", nodes[x]); - - for (y = 0; y < slen; y++) { - if (rs_running(NULL, &states[y], 1) && - states[y].rs_status.rs_owner == nodes[x]) { - tmp = 0; - if (!states[y].rs_allowed_len) - tmp = 1; - else { - for (z = 0; z<states[y].rs_allowed_len; - z++) { - if (states[y].rs_allowed[z] == - states[y].rs_status.rs_owner) { - tmp = 1; - break; - } - } - } - - if (!tmp) { - fprintf(fp, "\t[ILLEGAL] "); - } else { - fprintf(fp, "\t"); - } - - fprintf(fp, "%s\n", - states[y].rs_status.rs_name); - } - } - fprintf(fp, "\n"); - } - - /* Show all 'started' on dead node resources in a red "node" */ - off = 0; - for (x = 0; x < slen; x++) { - - if (!(states[x].rs_flags & RS_DEAD_NODE)) - continue; - - if (!off) { - off = 1; - fprintf(fp, "Resources on dead nodes:\n"); - } - - fprintf(fp, "\t%s\n", states[x].rs_status.rs_name); - } - - if (off) - fprintf(fp, "\n"); - - /* Show all 'stopped' in a 'stopped' "node" */ - fprintf(fp, "Stopped resources:\n"); - - z = 0; - for (x = 0; x < slen; x++) { - - if (states[x].rs_status.rs_state != RG_STATE_STOPPED) - continue; - - fprintf(fp, "\t%s;\n", states[x].rs_status.rs_name); - } - - fprintf(fp, "\n"); - - /* Show all 'disabled' */ - fprintf(fp, "Disabled resources:\n"); - - z = 0; - for (x = 0; x < slen; x++) { - - if (states[x].rs_status.rs_state != RG_STATE_DISABLED) - continue; - - fprintf(fp, "\t%s;\n", states[x].rs_status.rs_name); - } - - fprintf(fp, "\n"); - - return 0; -} - -/** - Gets an attribute of a resource group. - - @param res Resource - @param property Name of property to check for - @param ret Preallocated return buffer - @param len Length of buffer pointed to by ret - @return 0 on success, -1 on failure. - */ -int -res_property(resource_t *res, char *property, char *ret, size_t len) -{ - int x = 0; - - if (!res) - return -1; - - for (; res->r_attrs[x].ra_name; x++) { - if (strcasecmp(res->r_attrs[x].ra_name, property)) - continue; - strncpy(ret, res->r_attrs[x].ra_value, len); - return 0; - } - - return 1; -} - - -static void -_set_allowed(dep_rs_t *state, fod_t *domain, int *nodes, int nlen) -{ - fod_node_t *fdn; - int cnt = 0, allowed = 0, x, y, z, tmp; - - if (!domain) { - state->rs_allowed = malloc(sizeof(int)*nlen); - state->rs_allowed_len = nlen; - - if (!state->rs_allowed) - return; - memcpy(state->rs_allowed, nodes, sizeof(int)*nlen); - return; - } - - if (domain->fd_flags & FOD_RESTRICTED) { - list_for(&domain->fd_nodes, fdn, allowed); - } else { - allowed = nlen; - } - - state->rs_allowed = malloc(sizeof(int)*allowed); - state->rs_allowed_len = allowed; - state->rs_flags = 0; - - if (!state->rs_allowed) - return; - - memset(state->rs_allowed, 0, sizeof(int)*allowed); - - cnt = 0; - /* Failover domain prios are 1..100 */ - if (!(domain->fd_flags & FOD_ORDERED)) { - - /* Non-prio failover domain */ - list_for(&domain->fd_nodes, fdn, x) { - state->rs_allowed[cnt++] = fdn->fdn_nodeid; - } - } else { - for (x = 0; x <= 100; x++) { - list_for(&domain->fd_nodes, fdn, y) { - if (fdn->fdn_prio != x) - continue; - state->rs_allowed[cnt++] = fdn->fdn_nodeid; - } - } - - state->rs_flags |= RS_ORDERED; - - if (!(domain->fd_flags & FOD_NOFAILBACK)) - state->rs_flags |= RS_FAILBACK; - } - - if (domain->fd_flags & FOD_RESTRICTED) - return; - - /* allowed == nlen */ - /* find missing nodes and fill them in */ - for (x = 0; x < allowed; x++) { - if (state->rs_allowed[x] != 0) - continue; - for (y = 0; y < nlen; y++) { - - tmp = 0; - for (z = 0; z < x; z++) { - if (nodes[y] == state->rs_allowed[z]) { - tmp = 1; - break; - } - } - - if (!tmp) { - state->rs_allowed[x] = nodes[y]; - } - } - } -} - - -dep_rs_t * -dep_rstate_alloc(resource_node_t **restree, fod_t **domains, int *nodes, - int nlen, int *rs_cnt) -{ - dep_rs_t *rstates; - resource_node_t *rn; - int tl_res_count = 0, x; - char dom[64]; - fod_t *fod; - - list_for(restree, rn, tl_res_count); - - rstates = malloc(sizeof(dep_rs_t) * tl_res_count); - if (!rstates) - return NULL; - - memset(rstates, 0, (sizeof(dep_rs_t) * tl_res_count)); - - list_for(restree, rn, x) { - snprintf(rstates[x].rs_status.rs_name, - sizeof(rstates[x].rs_status.rs_name), - "%s:%s", rn->rn_resource->r_rule->rr_type, - rn->rn_resource->r_attrs[0].ra_value); - - rstates[x].rs_status.rs_last_owner = 0; - rstates[x].rs_status.rs_owner = 0; - rstates[x].rs_status.rs_state = RG_STATE_STOPPED; - - fod = NULL; - if (!res_property(rn->rn_resource, "domain", dom, - sizeof(dom))) { - - fod = fod_find_domain(domains, dom); - } - _set_allowed(&rstates[x], fod, nodes, nlen); - } - - *rs_cnt = tl_res_count; - - return rstates; -} - - -void -dep_rstate_free(dep_rs_t *states, int slen) -{ - int x; - - if (!states) - return; - if (!slen) - return; - - for (x = 0; x < slen; x++) { - if (states[x].rs_allowed && states[x].rs_allowed_len) { - free(states[x].rs_allowed); - states[x].rs_allowed = NULL; - states[x].rs_allowed_len = 0; - } - } - - free(states); -} - - -dep_rs_t * -dep_rstate_dup(dep_rs_t *states, int slen) -{ - dep_rs_t *states_new; - int x; - - while ((states_new = malloc(sizeof(dep_rs_t) * slen)) == NULL) - usleep(10000); - - memcpy(states_new, states, sizeof(dep_rs_t) * slen); - - for (x = 0; x < slen; x++) { - if (!states[x].rs_allowed || !states[x].rs_allowed_len) { - states_new[x].rs_allowed = NULL; - continue; - } - - while ((states_new[x].rs_allowed = - malloc(sizeof(int) * states[x].rs_allowed_len))==NULL) - usleep(10000); - - memcpy(states_new[x].rs_allowed, - states[x].rs_allowed, - sizeof(int) * states[x].rs_allowed_len); - } - - return states_new; -} - - -/** - * copy everything from src into dest except for the allowed pointer arrays - */ -void -dep_rstate_copy(dep_rs_t *dest, dep_rs_t *src, int slen) -{ - int x, *ap; - - for (x = 0; x < slen; x ++) { - ap = dest[x].rs_allowed; - memcpy(&dest[x], &src[x], sizeof(dep_rs_t)); - dest[x].rs_allowed = ap; - } -} - - -static int -dep_srt_cmp(dep_t *l, dep_rs_t *ls, dep_t *r, dep_rs_t *rs) -{ - - if (ls->rs_status.rs_state == RG_STATE_STOPPED && - rs->rs_status.rs_state != RG_STATE_STOPPED) - return 1; - - if (ls->rs_status.rs_state != RG_STATE_STOPPED && - rs->rs_status.rs_state == RG_STATE_STOPPED) - return -1; - - if (ls->rs_status.rs_state != RG_STATE_STOPPED && - rs->rs_status.rs_state != RG_STATE_STOPPED) { - - if (!l && r) - return -1; - if (r && !l) - return 1; - if (!r && !l) - return 0; - - /* running resource */ - /* - * Left is greater if the hits exceed, or left's - * hits are zero - */ - if (l->d_hits == 0 && r->d_hits != 0) - return -1; - if (l->d_hits != 0 && r->d_hits == 0) - return 1; - - /* Otherwise, more hits, the farther away */ - if (l->d_hits > r->d_hits) - return -1; - if (l->d_hits < r->d_hits) - return 1; - return 0; - } - - /* both states are stopped */ - if (!l && r) - return 1; - if (l && !r) - return -1; - if (!r && !l) - return 0; - if (l->d_deps > r->d_deps) - return -1; - if (l->d_deps < r->d_deps) - return 1; - if (l->d_hits > r->d_hits) - return -1; - if (l->d_hits < r->d_hits) - return 1; - return 0; -} - - -void -dep_rstate_sort(dep_t **deps, dep_rs_t *states, int slen) -{ - dep_t *xd, *yd; - int x, y; - dep_rs_t tmp; - - /* brute force sort */ - for (x = 0; x < slen; x++) { - for (y = 0; y < x; y++) { - xd = find_dep(deps, states[x].rs_status.rs_name); - yd = find_dep(deps, states[y].rs_status.rs_name); - - if (dep_srt_cmp(yd, &states[y], xd, &states[x]) < 0) { - memcpy(&tmp, &states[y], sizeof(dep_rs_t)); - memcpy(&states[y], &states[x], - sizeof(dep_rs_t)); - memcpy(&states[x], &tmp, sizeof(dep_rs_t)); - } - } - } -} - - -static inline int -_alter_state_start(dep_t **deps, dep_rs_t *state, int newowner) -{ - /* Try starting a resource */ - if (state->rs_flags & RS_BEEN_STARTED) - return 0; - - /* we just stopped this on this node */ - if (state->rs_status.rs_last_owner == newowner) - return 0; - - state->rs_status.rs_state = RG_STATE_STARTED; - state->rs_status.rs_owner = newowner; - - /* - * Optimization: don't allow start+stop+start. - * of the same resource, unless it was in an - * error state. - */ - state->rs_flags |= (RS_BEEN_STARTED | RS_BEEN_STOPPED); - - return 1; -} - - -static inline int -_alter_state_stop(dep_t **deps, dep_rs_t *state) -{ - dep_t *dep; - dep_node_t *dn; - int x; - - if (state->rs_flags & RS_BEEN_STOPPED) - return 0; - - dep = find_dep(deps, state->rs_status.rs_name); - if (!dep) { - printf("Dependency missing for %s\n", - state->rs_status.rs_name); - return 0; - } - -#if 0 - if (dep->d_hits == 0) { - /* If nothing depends on this resource, stopping it is - * pointless - */ - return 0; - } -#endif - - state->rs_status.rs_state = RG_STATE_STOPPED; - state->rs_status.rs_last_owner = state->rs_status.rs_owner; - state->rs_status.rs_owner = 0; - state->rs_flags |= RS_BEEN_STOPPED; - - /* We can clear the state now. Set the last owner to nobody */ - if (state->rs_flags & (RS_ILLEGAL_NODE | - RS_DEAD_NODE )) { - state->rs_status.rs_last_owner = 0; - state->rs_flags &= ~(RS_ILLEGAL_NODE | RS_DEAD_NODE); - return 1; - } - - /* - * If we stopped it because of a broken dependency, then we can - * restart it on the same node. - */ - list_for(&dep->d_nodes, dn, x) { - if (dn->dn_flags & (DN_BROKEN_COLO | - DN_BROKEN_REQ | - DN_BROKEN_NONCOLO)) { - state->rs_status.rs_last_owner = 0; - return 1; - } - } - - return 1; -} - - -static inline int -_alter_state(dep_t **deps, dep_rs_t *state, dep_op_t *op) -{ - if (!op) { - printf("No operation\n"); - return 0; - } - - if (op->do_op == RG_START) - return _alter_state_start(deps, state, op->do_nodeid); - return _alter_state_stop(deps, state); -} - - -static int * -build_try_indices(struct _try *tries, int try_cnt, int idx_cnt) -{ - int *indices, x, y; - /* Build our indices according to score */ - - while ((indices = malloc(sizeof(int)*idx_cnt)) == 0) - usleep(10000); - y = 0; - for (x = 0; x < try_cnt; x++) { - if (!tries[x].ops) - continue; - indices[y] = x; - ++y; - } - - return indices; -} - - -static void -nuke_op_list(dep_op_t **ops) -{ - dep_op_t *op; - - while ((op = *ops) != NULL) { - list_remove(ops, op); - free(op); - } -} - - -static void -sort_try_indices(struct _try *tries, int *indices, int idx_cnt, - dep_rs_t *states, int slen) -{ - int x, y, z, swp; - dep_rs_t *cstate; - - /* - * Got our list of indices into our 'tries' branch array, - * now sort. Brutish sort.. Really should take into account error - * states.; e.g. 0 1 2 3 4 5 -1 -2 -3... - */ - for (x = 0; x < idx_cnt; x++) { - for (y = 0; y < x; y++) { - - if (tries[indices[x]].score < tries[indices[y]].score){ - swp = indices[x]; - indices[x] = indices[y]; - indices[y] = swp; - } - - if (tries[indices[x]].score != tries[indices[y]].score) - continue; - - /* See if we're ordered */ - cstate = NULL; - for (z = 0; z < slen; z++) { - if (!strcmp(tries[indices[y]].ops->do_res, - states[z].rs_status.rs_name)) { - cstate = &states[z]; - break; - } - } - - if (!cstate || !(cstate->rs_flags & RS_ORDERED)) - continue; - - swp = 0; - for (z = 0; z < cstate->rs_allowed_len; z++) { - if (tries[indices[x]].ops->do_nodeid == - cstate->rs_allowed[z]) { - swp = 1; - break; - } else if (tries[indices[y]].ops->do_nodeid == - cstate->rs_allowed[z]) { - break; - } - } - - if (!swp) - continue; - - swp = indices[x]; - indices[x] = indices[y]; - indices[y] = swp; - } - } -} - - -static void -free_try_list(struct _try *tries, int len) -{ - int x; - - /* Clean up all remaining branch lists */ - for (x = 0; x < len; x++) { - if (!tries[x].ops) - continue; - nuke_op_list(&(tries[x].ops)); - } - - /* Clean up branch list array */ - free(tries); -} - - -static int -check_online(int n, int *nodes, int nlen, int *nidx) -{ - for (*nidx = 0; *nidx < nlen; (*nidx)++) - if (n == nodes[*nidx]) - return nodes[*nidx]; - return -1; -} - - -static void -insert_try(struct _try *tries, int idx, dep_op_t *op, int score, int iter) -{ - dep_op_t *newop; - - while ((newop = malloc(sizeof(dep_op_t))) == NULL) - usleep(10000); - memcpy(newop, op, sizeof(dep_op_t)); - newop->do_iter = iter; - list_insert(&(tries[idx].ops), newop); - tries[idx].score = score; -} - - -/** - * Calculate all of the possible branches from this point. - * Returns the number of possible branches. - */ -static int -build_all_possible_tries(dep_t **deps, dep_rs_t *states_cpy, int slen, - int *nodes, int nlen, int start_score, - struct _try *tries, int iter, int depth) -{ - int x, y, nidx, err; - dep_rs_t tmp; - dep_op_t op; - int idx_cnt = 0; - - for (x = 0; x < slen; x++) { - - /* Immutable resources can't be moved */ - if (states_cpy[x].rs_flags & RS_IMMUTABLE) - continue; - - /* can't bother with non-running resources */ - if (states_cpy[x].rs_status.rs_state == RG_STATE_DISABLED || - states_cpy[x].rs_status.rs_state == RG_STATE_FAILED) - continue; - - /* - * see if this set has already tried to manipulate this - * service - */ - if ((states_cpy[x].rs_flags & - (RS_BEEN_STARTED|RS_BEEN_STOPPED)) == - (RS_BEEN_STARTED|RS_BEEN_STOPPED)) - continue; - - /* - * Since we are operating on the same allowed list (and - * will not be freeing tmp), it's ok to just use memcpy here. - */ - memcpy(&tmp, &states_cpy[x], sizeof(tmp)); - - op.do_op = RG_START; /* XXX the loop below must happen - at least once...*/ - - /* try for each nodeid that's a legal target */ - for (y = 0; (op.do_op == RG_START) && - y < states_cpy[x].rs_allowed_len; y++) { - - memcpy(&states_cpy[x], &tmp, sizeof(tmp)); - /* - * Find next node online in our allowed list - * nidx is the offset into the online nodes array - * where this node was found - since the online list - * of nodes might be smaller than the allowed list - * for the resource, we need to keep track of it for - * later. - * - * XXX Since we sort later in the alg., we can probably - * reverse these loops to get rid of nidx. - */ - if ((err = check_online(states_cpy[x].rs_allowed[y], - nodes, nlen, &nidx)) < 0) - continue; - - /* Reset flags, etc. */ - memset(&op, 0, sizeof(dep_op_t)); - - if (rs_running(NULL, &states_cpy[x], 1)) { - - /* Try stopping a resource */ - op.do_op = RG_STOP; - strncpy(op.do_res, - states_cpy[x].rs_status.rs_name, - sizeof(op.do_res)); - /*printf("stop %s %d %d %d ", op.do_res, - depth, iter, start_score);*/ - - } else if (states_cpy[x].rs_status.rs_state == - RG_STATE_STOPPED && - start_score >= 0) { - - /* Try starting a resource. We can only - * do this after we clear the errors (e.g. stop) - * resources */ - op.do_op = RG_START; - op.do_nodeid = err; - strncpy(op.do_res, - states_cpy[x].rs_status.rs_name, - sizeof(op.do_res)); - /*printf("start %s %d %d %d ", op.do_res, - depth, iter, start_score);*/ - } else { - /* Other states = can't do anything */ - continue; - } - - /* - * Try to apply our operation. If it was an invalid, - * operation, we just move on - */ - if (_alter_state(deps, &states_cpy[x], &op) == 0) - continue; - - /* Check each possible move at this level */ - err = dep_check(deps, states_cpy, slen, nodes, nlen); - //printf(" [score: %d]\n", err); - - /* - * Make sure the operation does not introduce an - * error - */ - if ((start_score < 0 && err <= start_score) || - (start_score >= 0 && err < 0)) { - /* - * Introduce new error = bad; drop this - * operation. - */ - /* - printf("%s of %s introduced new err %d %d\n", - op.do_op==RG_START?"start":"stop", - op.do_res, - start_score, err); - */ - continue; - } - - /* No new error - this op is a valid thing to do */ - /* Insert the op on to the try list and move on */ - insert_try(tries, x * nlen + nidx, &op, err, iter); - - /* - * Keep track of how many places we actually - * found a possible branch for returning - */ - ++idx_cnt; - } - memcpy(&states_cpy[x], &tmp, sizeof(tmp)); - } - - return idx_cnt; -} - - -/** - * Breadth-first-search. - */ -static int -_dep_calc_trans(dep_t **deps, dep_rs_t *states, int slen, int *nodes, int nlen, - int depth, int errors, dep_op_t **oplist, int *iter) -{ - int x, y, err; - struct _try *tries; - dep_rs_t *states_cpy; - dep_op_t *newop; - int best_idx = -1, best_score, start_score; - int *indices = NULL, idx_cnt = 0; - - x = dep_check(deps, states, slen, nodes, nlen); - /* Ideal? */ - if (x == 0) - return 0; - /* Introduced a new error? */ - if ((*iter) && errors < 0 && x <= errors) - return x; - - /* Went from sub-optimal to outright broken? */ - if (errors > 0 && x < 0) - return x; - - /* - * Impossible to try branch more than 2*slen times: we can only - * on the outside stop/start every resource in the cluster. - */ - if (depth > (2*slen)) - return errors; - - /* Set up */ - best_score = start_score = x; - ++(*iter); - /* - printf("[%d] start depth %d errors %d init %d\n", - *iter, depth, errors, start_score); - */ - - while ((tries = malloc(sizeof(*tries) * slen * nlen)) == NULL) - usleep(10000); - memset(tries, 0, sizeof(*tries) * slen * nlen); - - /* Copy our states (don't alter parent's states) */ - states_cpy = dep_rstate_dup(states, slen); - - /* Find all possible things to try */ - idx_cnt = build_all_possible_tries(deps, states_cpy, slen, nodes, nlen, - start_score, tries, *iter, depth); - - /* Build our indices into an array */ - indices = build_try_indices(tries, nlen*slen, idx_cnt); - - /* Sort array indices */ - sort_try_indices(tries, indices, idx_cnt, states_cpy, slen); - - /* - * Now, do a recurse on the tree in order of best-score-first... - * (that's why we sorted above) - */ - dep_rstate_copy(states_cpy, states, slen); - for (x = 0; x < idx_cnt; x++) { - - /* state index = tries_index/node count len */ - y = indices[x] / nlen; - - /* Back this up for later */ - dep_rstate_copy(&states_cpy[y], &states[y], 1); - - /* Flip our state. */ - if (_alter_state(deps, &states_cpy[y], - tries[indices[x]].ops) == 0) { - /* :( */ - printf("Error: Logic error\n"); - continue; - } - - /* Recurse */ - err = _dep_calc_trans(deps, states_cpy, slen, nodes, nlen, - depth + 1, start_score, - &(tries[indices[x]].ops), iter); - - //dep_rstate_copy(&states_cpy[y], &states[y], 1); - - /* Store the score for branching on this operation */ - tries[indices[x]].score = err; - - /* ... and the depth. XXX not done yet; someday, we should - * select the shortest path... - tries[indices[x]].depth = 0; - list_for_count(&tries[indices[x]].ops, newop, - tries[indices[x]].depth); - */ - - /* Keep track of our best score */ - if ((best_score < 0 && err > best_score) || - (best_score >= 0 && err >= 0 && err < best_score)) { - best_idx = indices[x]; - best_score = err; - } - } - - /* Free our index array; we don't need it anymore */ - free(indices); - - /* We don't need our temporary space anymore */ - dep_rstate_free(states_cpy, slen); - - if ((errors < 0 && best_score < errors) || - (errors >= 0 && best_score > errors)) { - /* No good branch to take from here */ - best_idx = -1; - best_score = start_score; - } - - /* Append the so-called best list on to our passed-in list of - * operations (this goes on tries[...] above) */ - if (best_idx != -1) { - while ((newop = tries[best_idx].ops) != NULL) { - list_remove(&(tries[best_idx].ops), newop); - list_insert(oplist, newop); - } - - /* Get the best score */ - best_score = tries[best_idx].score; - } - - free_try_list(tries, nlen * slen); - - /* - printf("[%d] end start score: %d, bestscore: %d depth: %d\n", *iter, - start_score, best_score, depth); - */ - - return best_score; -} - - -int -dep_calc_trans(dep_t **deps, dep_rs_t *_states, int slen, - int *nodes, int nlen, dep_op_t **op_list, int *iter) -{ - int x, my_i, ops = 0, err = 0; - dep_op_t *newop; - dep_rs_t *states = NULL; - - if (iter) - *iter = 0; - else { - my_i = 0; - iter = &my_i; - } - - x = dep_check(deps, _states, slen, nodes, nlen); - if (x == 0) - return 0; - - states = dep_rstate_dup(_states, slen); - for (x = 0; x < slen; x++) { - if (states[x].rs_flags & (RS_DEAD_NODE|RS_ILLEGAL_NODE)) { - states[x].rs_status.rs_state = RG_STATE_STOPPED; - while ((newop = malloc(sizeof(*newop))) == NULL) - sleep(1); - memset(newop, 0, sizeof(*newop)); - newop->do_op = RG_STOP; - strncpy(newop->do_res, states[x].rs_status.rs_name, - sizeof(newop->do_res)); - list_insert(op_list, newop); - ++ops; - } - } - - /* - * Sort: - * low... - * (a) stopped resources which are not depended on (starting these - * will not affect any other resources) - * (b) stopped resources which are depended on - where the # of - * deps is increasing - * (c) started resources w/ deps, ordered from lowest to highest - * (d) started resources w/ no deps (transitioning these will have - * -no- effect.) - * ... high - */ - dep_rstate_sort(deps, states, slen); - err = dep_check(deps, states, slen, nodes, nlen); - if (err) { - err = _dep_calc_trans(deps, states, slen, nodes, nlen, 0, - err, op_list, iter); - } - - dep_rstate_free(states, slen); - return err; -} - - -int -dep_apply_trans(dep_t **deps, dep_rs_t *states, int slen, dep_op_t **op_list) -{ - dep_op_t *op; - int ops = 0, x; - - list_for(op_list, op, ops) { - for (x = 0; x < slen; x++) { - if (strcasecmp(op->do_res, states[x].rs_status.rs_name)) - continue; - if (op->do_op == RG_START) { - printf("Start %s on %d [%d]\n", - op->do_res, op->do_nodeid, op->do_iter); - states[x].rs_status.rs_state = RG_STATE_STARTED; - states[x].rs_status.rs_owner = op->do_nodeid; - } else { - printf("Stop %s [%d]\n", op->do_res, - op->do_iter); - states[x].rs_status.rs_state = RG_STATE_STOPPED; - states[x].rs_status.rs_owner = 0; - states[x].rs_flags &= ~(RS_ILLEGAL_NODE| - RS_DEAD_NODE); - } - } - } - - printf("Applied %d operations\n", ops); - - return 0; -} - - -void -reverse_list(dep_op_t **oplist) -{ - dep_op_t *new_ol = NULL; - dep_op_t *op; - - if (!*oplist) - return; - - while ((op = *oplist)) { - list_remove(oplist, op); - list_prepend(&new_ol, op); - } - - *oplist = new_ol; -} - - -void -insert_after_stops(dep_op_t **oplist, dep_op_t *newop) -{ - dep_op_t *new_ol = NULL; - dep_op_t *op; - - if (!*oplist) - return; - - while ((op = *oplist) && op->do_op == RG_STOP) { - list_remove(oplist, op); - list_insert(&new_ol, op); - } - - list_insert(&new_ol, newop); - - while ((op = *oplist)) { - list_remove(oplist, op); - list_insert(&new_ol, op); - } - - *oplist = new_ol; -} - - -/** - * Generate the list of operations which would satisfy a requested (user) - * operation (e.g. start, relocate, disable) - */ -int -dep_check_operation(char *res, int operation, int target, - dep_t **deps, dep_rs_t *_states, - int slen, int *nodes, int nlen, dep_op_t **oplist) -{ - int ret = -1; - dep_rs_t *state = NULL, *states = NULL; - dep_op_t *newop = NULL; - int start_score, score; - - states = dep_rstate_dup(_states, slen); - start_score = dep_check(deps, _states, slen, nodes, nlen); - - /* Find the state dealing with */ - if (!(state = _find_state(res, states, slen))) { - printf("No record of that service...\n"); - dep_rstate_free(states, slen); - return -1; - } - - switch(operation) { - case RG_DISABLE: - case RG_STOP: - case RG_START: - while ((newop = malloc(sizeof(dep_op_t))) == NULL) - usleep(10000); - memset(newop, 0, sizeof(dep_op_t)); - - /* Set it up */ - strncpy(newop->do_res, res, sizeof(newop->do_res)); - newop->do_op = operation; - newop->do_nodeid = target; - - if (_alter_state(deps, state, newop) == 0) - break; - - state->rs_flags |= RS_IMMUTABLE; - - start_score = dep_check(deps, states, slen, nodes, nlen); - score = dep_calc_trans(deps, states, slen, nodes, nlen, - oplist, NULL); - if (start_score < 0 && score <= start_score) - break; - - /* Reverse the list if we breake dependencies */ - if (operation == RG_STOP || operation == RG_DISABLE) { - /* Append the operation */ - reverse_list(oplist); - list_insert(oplist, newop); - } else { - /* append after stops... */ - insert_after_stops(oplist, newop); - } - - ret = 0; /* Woot */ - break; - case RG_RELOCATE: - if (dep_check_operation(res, RG_STOP, -1, deps, states, slen, nodes, - nlen, oplist) < 0) - break; - if (dep_check_operation(res, RG_START, target, deps, states, slen, - nodes, nlen, oplist) < 0) - break; - ret = 0; /* Woot */ - break; - case RG_MIGRATE: - default: - break; - } - - /* Ret will be -1 unless we succeeded */ - if (ret < 0) { - if (newop) - free(newop); - - while ((newop = *oplist)) { - list_remove(oplist, newop); - free(newop); - } - } - - if (states) - dep_rstate_free(states, slen); - return ret; -} diff --git a/rgmanager/src/daemons/dtest.c b/rgmanager/src/daemons/dtest.c deleted file mode 100644 index d554939..0000000 --- a/rgmanager/src/daemons/dtest.c +++ /dev/null @@ -1,810 +0,0 @@ -#include <libxml/parser.h> -#include <libxml/xmlmemory.h> -#include <libxml/xpath.h> -#include <stdlib.h> -#include <stdio.h> -#include <restart_counter.h> -#include <resgroup.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <list.h> -#include <reslist.h> -#include <pthread.h> -#include <depends.h> -#include <ccs.h> -#include <readline/readline.h> -#include <readline/history.h> - - - -#ifndef NO_CCS -#error "Can not be built with CCS support." -#endif - -#ifdef NO_CCS -#define ccs_get(fd, query, ret) conf_get(query, ret) -#endif - -void malloc_stats(void); - - -resource_rule_t *rules = NULL; -resource_t *resources = NULL; -resource_node_t *restree = NULL; -dep_t *depends = NULL; -dep_rs_t *resource_states = NULL; -int resource_state_count = 0; -fod_t *domains = NULL; -int *nodes_all = NULL; -int nodes_all_count = 0; -int *nodes_online = NULL; -int nodes_online_count = 0; - - -void -visualize_state(char *png_viewer) -{ - char cmd[1024]; - char tf_dot[128]; - char tf_png[128]; - FILE *fp; - int fd, x; - - snprintf(tf_dot, sizeof(tf_dot), "/tmp/dtest.dot.XXXXXX"); - fd = mkstemp(tf_dot); - if (fd < 0) { - printf("Couldn't create temporary file: %s\n", strerror(errno)); - return; - } - - fp = fdopen(fd, "w+"); - if (!fp) { - printf("Couldn't init temporary file: %s\n", strerror(errno)); - return; - } - - x = dep_check(&depends, resource_states, - resource_state_count, nodes_online, - nodes_online_count); - printf("State score: %d\n", x); - dep_cluster_state_dot(fp, &depends, resource_states, - resource_state_count, nodes_online, - nodes_online_count); - - fclose(fp); - close(fd); - - snprintf(tf_png, sizeof(tf_png), "/tmp/dtest.png.XXXXXX"); - fd = mkstemp(tf_png); - if (fd < 0) { - printf("Couldn't init temporary file: %s\n", strerror(errno)); - return; - } - - close(fd); - - snprintf(cmd, sizeof(cmd), "dot -Tpng -o %s %s", tf_png, tf_dot); - if (system(cmd) != 0) { - printf("Error: system('%s') failed\n", cmd); - return; - } - - snprintf(cmd, sizeof(cmd), "%s %s", png_viewer, tf_png); - if (system(cmd) != 0) { - printf("Error: system('%s') failed\n", cmd); - return; - } - - unlink(tf_png); - unlink(tf_dot); -} - - -int -vis_dep_apply_trans(dep_op_t **op_list, char *pngviewer) -{ - dep_op_t *op; - int x; - int ops = 0; - dep_rs_t *states = resource_states; - int slen = resource_state_count; - - visualize_state(pngviewer); - - list_do(op_list, op) { - - ++ops; - - for (x = 0; x < slen; x++) { - if (strcasecmp(op->do_res, states[x].rs_status.rs_name)) - continue; - if (op->do_op == RG_START) { - printf("Start %s on %d\n", op->do_res, op->do_nodeid); - states[x].rs_status.rs_state = RG_STATE_STARTED; - states[x].rs_status.rs_owner = op->do_nodeid; - } else { - printf("Stop %s\n", op->do_res); - states[x].rs_status.rs_state = RG_STATE_STOPPED; - states[x].rs_status.rs_owner = 0; - states[x].rs_flags &= ~(RS_ILLEGAL_NODE| - RS_DEAD_NODE); - } - break; - } - - visualize_state(pngviewer); - - } while (!list_done(op_list, op)); - - printf("Applied %d operations\n", ops); - - return 0; -} - -void -print_help(void) -{ - printf("nodes view all nodes\n"); - printf("online [id1 id2...|none] set or view online nodes\n"); - printf("res [resource] view a resource state (or all)\n"); - printf("start <res> <id> start res on id\n"); - printf("dep [res] print dependency tree(s)\n"); - printf("stop <res1> [res2...] stop res\n"); - printf("disable <res1> [res2...] disable res\n"); - printf("check check cluster state against deps\n"); - printf("calc calculate transition to valid state\n"); - printf("apply [pngviewer] Apply previous transition list\n"); - printf(" If pngviewer is specified, send\n"); - printf(" graphviz & bring up viewer\n"); - printf("state [pngviewer] dump cluster state in DOT format\n"); - printf(" If pngviewer is specified, send\n"); - printf(" graphviz & bring up viewer\n"); - printf("quit, exit exit\n"); -} - - -void -show_rs_t(dep_rs_t *rs) -{ - int *allowed, cnt, x; - - printf("Resource %s\n State: %s\n Owner: %d\n", - rs->rs_status.rs_name, - rg_state_str(rs->rs_status.rs_state), - rs->rs_status.rs_owner); - - if (rs->rs_allowed) { - allowed = rs->rs_allowed; - cnt = rs->rs_allowed_len; - } else { - printf(" Allowed Nodes = [ all ]\n"); - return; - } - - printf(" Allowed Nodes = [ "); - - for (x = 0; x < cnt; x++) { - printf("%d ", allowed[x]); - } - printf("]\n"); -} - - -int -show_resources(char *name) -{ - int x, found = 0; - - for (x = 0; x < resource_state_count; x++) { - if (!name || !strcmp(name, - resource_states[x].rs_status.rs_name)) { - found = 1; - - show_rs_t(&resource_states[x]); - } - - if (!name) - printf("\n"); - } - - return !found; -} - - -void -show_calc_result(int final_score, dep_op_t **ops, int iter) -{ - int x = 0; - dep_op_t *op; - - list_do(ops, op) { - ++x; - if (op->do_op == RG_START) { - printf("Start %s on %d [%d]\n", op->do_res, op->do_nodeid, op->do_iter); - } else { - printf("Stop %s [%d]\n", op->do_res, op->do_iter); - } - } while (!list_done(ops, op)); - - if (iter >= 0) - printf("%d operations reduced in %d iterations; final score = %d\n", x, iter, - final_score); - else - printf("%d operations\n", x); -} - - - -dep_rs_t * -get_rs_byname(char *name) -{ - int x, found = 0; - - if (!name) - return NULL; - - for (x = 0; x < resource_state_count; x++) { - if (!name || !strcmp(name, - resource_states[x].rs_status.rs_name)) { - found = 1; - - return &resource_states[x]; - } - - } - - return NULL; -} - - - -void -dtest_shell(void) -{ - resource_t *res; - char name[64]; - char *cmd = NULL; - int done = 0; - char *save, *curr, *tmp; - int cnt, err; - int *nodes; - int x; - dep_rs_t *rs; - dep_t *depcpy; - dep_op_t *ops = NULL, *op; - - nodes = malloc(sizeof(int)*nodes_all_count); - // FIXME: handle failed malloc - - while (!done) { - - if (cmd) - free(cmd); - cmd = readline("> "); - if (!cmd || !strlen(cmd)) { - printf("\n"); - } - if (!cmd) { - break; - } - - /* - if (cmd && cmd[0]) - add_history(cmd); - */ - - if (!cmd[0]) - continue; - - curr = strtok_r(cmd, " ", &save); - err = 0; - - if (!strcmp(curr, "online")) { - cnt = 0; - err = 0; - while ((curr = strtok_r(NULL, " ", &save))) { - nodes[cnt] = atoi(curr); - if (nodes[cnt] <= 0) { - printf("Error: Node '%s' invalid\n", - curr); - err = 1; - break; - } - - err = 1; - for (x = 0; x < nodes_all_count; x++) { - if (nodes_all[x] == nodes[cnt]) { - err = 0; - break; - } - } - ++cnt; - } - - if (cnt && !err) { - if (nodes_online) - free(nodes_online); - - nodes_online = malloc(sizeof(int) * cnt); - // FIXME: handle failed malloc - - for (x = 0; x < cnt; x++) - nodes_online[x] = nodes[x]; - nodes_online_count = cnt; - } - - if (!err) { - printf("Online = [ "); - for (x = 0; x < nodes_online_count; x++) { - printf("%d ", nodes_online[x]); - } - printf("]\n"); - } - } else if (!strcmp(curr, "start")) { - - curr = strtok_r(NULL, " ", &save); - - if (!curr) { - printf("usage: start <resource> <nodeid>" - " [test]\n"); - continue; - } - - if (!strchr(curr,':')) { - snprintf(name, sizeof(name), "service:%s", - curr); - curr = name; - } - - rs = get_rs_byname(curr); - if (!rs) { - printf("Error: Resource '%s' not found\n", curr); - ++err; - } - - curr = strtok_r(NULL, " ", &save); - cnt = 0; - if (!curr) { - printf("Error: No node ID specified\n"); - ++err; - } else { - cnt = atoi(curr); - x = 0; - if (cnt <= 0) { - printf("Error: Node '%s' invalid\n", - curr); - ++err; - } else { - for (x = 0; x < nodes_online_count; x++) { - if (nodes_online[x] == cnt) { - x = -1; - break; - } - } - } - - if (x != -1) { - printf("Error: Node '%s' not online\n", - curr); - ++err; - } - } - - if (err) - continue; - - curr = strtok_r(NULL, " ", &save); - if (curr) { - if (strcmp(curr, "test")) - printf("Error: start ... %s\n", curr); - - while ((op = ops)) { - list_remove(&ops, op); - free(op); - } - /* -int -dep_check_operation(char *res, int operation, int target, - dep_t **deps, dep_rs_t *_states, - int slen, int *nodes, int nlen, dep_op_t **oplist) - */ - if (dep_check_operation(rs->rs_status.rs_name, - RG_START, - cnt, - &depends, - resource_states, - resource_state_count, - nodes_online, - nodes_online_count, - &ops) < 0) { - printf("No, thanks.\n"); - } else - show_calc_result(0, &ops, 0); - continue; - } - - - rs->rs_status.rs_owner = cnt; - rs->rs_status.rs_state = RG_STATE_STARTED; - printf("%s is started on %d\n", rs->rs_status.rs_name, - cnt); - - } else if (!strcmp(curr, "domains")) { - print_domains(&domains); - - } else if (!strcmp(curr, "calc")) { - - while ((op = ops)) { - list_remove(&ops, op); - free(op); - } - - err = dep_calc_trans(&depends, resource_states, - resource_state_count, - nodes_online, nodes_online_count, - &ops, &x); - show_calc_result(err, &ops, x); - - } else if (!strcmp(curr, "apply")) { - - curr = strtok_r(NULL, " ", &save); - dep_check(&depends, resource_states, - resource_state_count, nodes_online, - nodes_online_count); - if (!curr) { - dep_apply_trans(&depends, resource_states, - resource_state_count, - &ops); - } else { - vis_dep_apply_trans(&ops, curr); - } - - while ((op = ops)) { - list_remove(&ops, op); - free(op); - } - } else if (!strcmp(curr, "state")) { - - x = dep_check(&depends, resource_states, - resource_state_count, - nodes_online, nodes_online_count); - - if (x < 0) { - printf("Cluster state is invalid (%d errors)\n", - -x); - dep_print_errors(&depends, - resource_states, - resource_state_count); - } else if (x > 0) { - printf("Cluster state is valid, " - "but not ideal (%d stopped)\n",x); - } else { - printf("Cluster state is ideal\n"); - } - - curr = strtok_r(NULL, " ", &save); - if (!curr) { - dep_cluster_state(stdout, &depends, - resource_states, - resource_state_count, nodes_online, - nodes_online_count); - } else { - visualize_state(curr); - } - - dep_reset(&depends, resource_states, - resource_state_count); - - } else if (!strcmp(curr, "reslist")) { - list_do(&resources, res) { - print_resource(res); - } while (!list_done(&resources, res)); - - } else if (!strcmp(curr, "nodes")) { - - printf("Nodes = [ "); - for (x = 0; x < nodes_all_count; x++) { - printf("%d ", nodes_all[x]); - } - printf("]\n"); - } else if (!strcmp(curr, "stop") || !strcmp(curr, "disable")) { - - tmp = curr; - - curr = strtok_r(NULL, " ", &save); - - if (!curr) { - printf("usage: %s <resource>\n", tmp); - continue; - } - #if 0 - do { - if (!strchr(curr,':')) { - snprintf(name, sizeof(name), "service:%s", - curr); - curr = name; - } - rs = get_rs_byname(curr); - if (!rs) { - printf("Error: Resource '%s' not found\n",curr); - break; - } - - rs->rs_status.rs_owner = 0; - if (!strcmp(cmd, "stop")) { - rs->rs_status.rs_state = RG_STATE_STOPPED; - printf("%s is stopped\n", - rs->rs_status.rs_name); - } else { - rs->rs_status.rs_state = RG_STATE_DISABLED; - printf("%s is disabled\n", - rs->rs_status.rs_name); - } - curr = strtok_r(NULL, " ", &save); - } while (curr); - - curr = strtok_r(NULL, " ", &save); - - if (!curr) { - printf("usage: start <resource> <nodeid>" - " [test]\n"); - continue; - } - #endif - - if (!strchr(curr,':')) { - snprintf(name, sizeof(name), "service:%s", - curr); - curr = name; - } - - rs = get_rs_byname(curr); - if (!rs) { - printf("Error: Resource '%s' not found\n", curr); - ++err; - } - - if (err) - continue; - - curr = strtok_r(NULL, " ", &save); - if (curr) { - if (strcmp(curr, "test")) - printf("Error: stop ... %s\n", curr); - - while ((op = ops)) { - list_remove(&ops, op); - free(op); - } - - if(dep_check_operation(rs->rs_status.rs_name, - !strcmp(tmp,"stop")?RG_STOP:RG_DISABLE, - -1, - &depends, - resource_states, - resource_state_count, - nodes_online, - nodes_online_count, - &ops) < 0) { - printf("No.\n"); - } else - show_calc_result(0, &ops, 0); - continue; - } - - rs->rs_status.rs_owner = 0; - if (!strcmp(cmd, "stop")) { - rs->rs_status.rs_state = RG_STATE_STOPPED; - printf("%s is stopped\n", - rs->rs_status.rs_name); - } else { - rs->rs_status.rs_state = RG_STATE_DISABLED; - printf("%s is disabled\n", - rs->rs_status.rs_name); - } - - - } else if (!strcmp(curr, "res")) { - - curr = strtok_r(NULL, " ", &save); - - if (curr && !strchr(curr,':')) { - snprintf(name, sizeof(name), "service:%s", - curr); - curr = name; - } - err = show_resources(curr); - if (err) { - printf("Error: Invalid resource '%s'", curr); - } - - } else if (!strcmp(curr, "dep")) { - - curr = strtok_r(NULL, " ", &save); - - if (!curr) { - print_depends(stdout, &depends); - continue; - } - - if (!strcmp(curr, "dot")) { - print_depends_dot(stdout, &depends); - continue; - } else if (!strcmp(curr, "copy")) { - printf("Copying tree..."); - depcpy = NULL; - dep_tree_dup(&depcpy, &depends); - printf("Done\n"); - print_depends(stdout, &depcpy); - deconstruct_depends(&depcpy); - depcpy = NULL; - } else { - printf("Error: Invalid command 'dep %s'\n", - curr); - } - - } else if (!strcmp(curr, "check")) { - dep_reset(&depends, resource_states, - resource_state_count); - - x = dep_check(&depends, resource_states, - resource_state_count, - nodes_online, nodes_online_count); - - if (x < 0) { - printf("Cluster state is invalid (%d errors)\n", - -x); - dep_print_errors(&depends, - resource_states, - resource_state_count); - dep_reset(&depends, resource_states, - resource_state_count); - } else if (x > 0) { - printf("Cluster state is valid, " - "but not ideal (%d stopped)\n",x); - } else { - printf("Cluster state is ideal\n"); - } - } else if (!strcmp(curr, "?") || !strcmp(curr,"help")) { - print_help(); - } else if (!strcmp(curr, "quit") || !strcmp(curr,"exit")) { - done = 1; - } else if (!strcmp(curr, "mem")) { - - tmp = curr; - curr = strtok_r(NULL, " ", &save); - if (!curr) { - malloc_stats(); - continue; - } - - printf("Unknown command '%s %s'\n", tmp , curr); - } else { - printf("Unknown command '%s'\n", curr); - } - } - if (cmd) - free(cmd); -} - - -int * -load_node_ids(int ccsfd, int *count) -{ - int ncount, x; - int *nodes; - char *val; - char xpath[256]; - - for (ncount = 1; ; ncount++) { - snprintf(xpath, sizeof(xpath), - "/cluster/clusternodes/clusternode[%d]/@nodeid", - ncount); - - if (ccs_get(ccsfd, xpath, &val)!=0) { - --ncount; - break; - } - } - - if (!ncount) - return NULL; - - nodes = malloc(sizeof(int) * ncount); - if (!nodes) { - fprintf(stderr, "out of memory?\n"); - return NULL; - } - - for (x = 1; x <= ncount; x++) { - snprintf(xpath, sizeof(xpath), - "/cluster/clusternodes/clusternode[%d]/@nodeid", x); - - if (ccs_get(ccsfd, xpath, &val)!=0) { - fprintf(stderr, - "Code path error: # of nodes changed\n"); - free(nodes); - return NULL; - } - - nodes[x-1] = atoi(val); - free(val); - } - - *count = ncount; - return nodes; -} - - -int -main(int argc, char **argv) -{ - int ccsfd, ret = 0; - char *agentpath; - char *config; - - if (argc < 3) { - printf("usage: %s <agentpath> <config>\n", argv[0]); - return -1; - } - - agentpath = argv[1]; - config = argv[2]; - - conf_setconfig(config); - - ccsfd = ccs_lock(); - if (ccsfd < 0) { - printf("Error parsing %s\n", argv[1]); - return -1; - } - - load_resource_rules(agentpath, &rules); - construct_domains(ccsfd, &domains); - load_resources(ccsfd, &resources, &rules); - build_resource_tree(ccsfd, &restree, &rules, &resources); - construct_depends(ccsfd, &depends); - - if (argc >= 4) { - if (!strcmp(argv[3], "dot")) { - print_depends_dot(stdout, &depends); - } else { - fprintf(stderr,"Invalid command: %s\n", argv[3]); - ret = 1; - } - goto out; - } - - nodes_all = load_node_ids(ccsfd, &nodes_all_count); - - ccs_unlock(ccsfd); - - printf("Nodes = [ "); - for (ret = 0; ret < nodes_all_count; ret++) { - printf("%d ", nodes_all[ret]); - } - printf("]\n"); - - if ((resource_states = dep_rstate_alloc(&restree, &domains, - nodes_all, - nodes_all_count, - &resource_state_count)) == NULL) { - printf("oops\n"); - return -1; - } - - /* Ok! We have it all! */ - dtest_shell(); - -out: - - deconstruct_depends(&depends); - destroy_resource_tree(&restree); - destroy_resources(&resources); - deconstruct_domains(&domains); - destroy_resource_rules(&rules); - - return ret; -} - - diff --git a/rgmanager/src/daemons/test.c b/rgmanager/src/daemons/test.c index 8b6b441..f981424 100644 --- a/rgmanager/src/daemons/test.c +++ b/rgmanager/src/daemons/test.c @@ -11,7 +11,6 @@ #include <reslist.h> #include <pthread.h> #include <libgen.h> -#include <depends.h> #include <event.h> #ifndef NO_CCS @@ -111,37 +110,9 @@ rules_func(int __attribute__((unused)) argc, int -deps_func(int argc, char**argv) -{ - dep_t *depends = NULL; - int ccsfd; - - conf_setconfig(argv[1]); - ccsfd = ccs_lock(); - if (ccsfd < 0) { - printf("Error parsing %s\n", argv[1]); - goto out; - } - - construct_depends(ccsfd, &depends); - if (depends) { - print_depends(stdout, &depends); - } - - deconstruct_depends(&depends); - -out: - ccs_unlock(ccsfd); - return 0; -} - - - -int test_func(int argc, char **argv) { fod_t *domains = NULL; - dep_t *depends = NULL; resource_rule_t *rulelist = NULL, *currule; resource_t *reslist = NULL, *curres; resource_node_t *tree = NULL, *tmp, *rn = NULL; @@ -160,7 +131,6 @@ test_func(int argc, char **argv) load_resource_rules(agentpath, &rulelist); construct_domains(ccsfd, &domains); construct_events(ccsfd, &events); - construct_depends(ccsfd, &depends); load_resources(ccsfd, &reslist, &rulelist); build_resource_tree(ccsfd, &tree, &rulelist, &reslist); @@ -196,11 +166,6 @@ test_func(int argc, char **argv) print_domains(&domains); } - if (depends) { - printf("=== Dependencies ===\n"); - print_depends(stdout, &depends); - } - if (events) { printf("=== Event Triggers ===\n"); print_events(events); @@ -275,7 +240,6 @@ test_func(int argc, char **argv) } out: - deconstruct_depends(&depends); deconstruct_events(&events); deconstruct_domains(&domains); destroy_resource_tree(&tree); @@ -446,10 +410,6 @@ main(int argc, char **argv) shift(); ret = test_func(argc, argv); goto out; - } else if (!strcmp(argv[1], "depends")) { - shift(); - ret = deps_func(argc, argv); - goto out; } else if (!strcmp(argv[1], "noop")) { shift(); _no_op_mode(1);
reply other threads:[~2009-06-22 13:33 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20090622133232.79ECE1201EF@lists.fedorahosted.org \ --to=lon@fedoraproject.org \ --cc=cluster-cvs-relay@redhat.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).