root/daemons/controld/controld_metadata.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ra_param_free
  2. metadata_free
  3. metadata_cache_new
  4. metadata_cache_free
  5. metadata_cache_reset
  6. valid_version_format
  7. metadata_cache_fini
  8. ra_version_from_xml
  9. ra_param_from_xml
  10. metadata_cache_update
  11. metadata_cache_get

   1 /*
   2  * Copyright 2017-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <glib.h>
  14 #include <regex.h>
  15 
  16 #include <crm/crm.h>
  17 #include <crm/lrmd.h>
  18 
  19 #include <pacemaker-controld.h>
  20 
  21 #if ENABLE_VERSIONED_ATTRS
  22 static regex_t *version_format_regex = NULL;
  23 #endif
  24 
  25 static void
  26 ra_param_free(void *param)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     if (param) {
  29         struct ra_param_s *p = (struct ra_param_s *) param;
  30 
  31         if (p->rap_name) {
  32             free(p->rap_name);
  33         }
  34         free(param);
  35     }
  36 }
  37 
  38 static void
  39 metadata_free(void *metadata)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41     if (metadata) {
  42         struct ra_metadata_s *md = (struct ra_metadata_s *) metadata;
  43 
  44         if (md->ra_version) {
  45             free(md->ra_version);
  46         }
  47         g_list_free_full(md->ra_params, ra_param_free);
  48         free(metadata);
  49     }
  50 }
  51 
  52 GHashTable *
  53 metadata_cache_new()
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55     return g_hash_table_new_full(crm_str_hash, g_str_equal, free,
  56                                  metadata_free);
  57 }
  58 
  59 void
  60 metadata_cache_free(GHashTable *mdc)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62     if (mdc) {
  63         crm_trace("Destroying metadata cache with %d members", g_hash_table_size(mdc));
  64         g_hash_table_destroy(mdc);
  65     }
  66 }
  67 
  68 void
  69 metadata_cache_reset(GHashTable *mdc)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     if (mdc) {
  72         crm_trace("Resetting metadata cache with %d members",
  73                   g_hash_table_size(mdc));
  74         g_hash_table_remove_all(mdc);
  75     }
  76 }
  77 
  78 #if ENABLE_VERSIONED_ATTRS
  79 static gboolean
  80 valid_version_format(const char *version)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82     if (version == NULL) {
  83         return FALSE;
  84     }
  85 
  86     if (version_format_regex == NULL) {
  87         /* The OCF standard allows free-form versioning, but for our purposes of
  88          * versioned resource and operation attributes, we constrain it to
  89          * dot-separated numbers. Agents are still free to use other schemes,
  90          * but we can't determine attributes based on them.
  91          */
  92         const char *regex_string = "^[[:digit:]]+([.][[:digit:]]+)*$";
  93 
  94         version_format_regex = calloc(1, sizeof(regex_t));
  95         regcomp(version_format_regex, regex_string, REG_EXTENDED | REG_NOSUB);
  96 
  97         /* If our regex doesn't compile, it's a bug on our side, so CRM_CHECK()
  98          * will give us a core dump to catch it. Pretend the version is OK
  99          * because we don't want our mistake to break versioned attributes
 100          * (which should only ever happen in a development branch anyway).
 101          */
 102         CRM_CHECK(version_format_regex != NULL, return TRUE);
 103     }
 104 
 105     return regexec(version_format_regex, version, 0, NULL, 0) == 0;
 106 }
 107 #endif
 108 
 109 void
 110 metadata_cache_fini()
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112 #if ENABLE_VERSIONED_ATTRS
 113     if (version_format_regex) {
 114         regfree(version_format_regex);
 115         free(version_format_regex);
 116         version_format_regex = NULL;
 117     }
 118 #endif
 119 }
 120 
 121 #if ENABLE_VERSIONED_ATTRS
 122 static char *
 123 ra_version_from_xml(xmlNode *metadata_xml, const lrmd_rsc_info_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     const char *version = crm_element_value(metadata_xml, XML_ATTR_VERSION);
 126 
 127     if (version == NULL) {
 128         crm_debug("Metadata for %s:%s:%s does not specify a version",
 129                   rsc->standard, rsc->provider, rsc->type);
 130         version = PCMK_DEFAULT_AGENT_VERSION;
 131 
 132     } else if (!valid_version_format(version)) {
 133         crm_notice("%s:%s:%s metadata version has unrecognized format",
 134                   rsc->standard, rsc->provider, rsc->type);
 135         version = PCMK_DEFAULT_AGENT_VERSION;
 136 
 137     } else {
 138         crm_debug("Metadata for %s:%s:%s has version %s",
 139                   rsc->standard, rsc->provider, rsc->type, version);
 140     }
 141     return strdup(version);
 142 }
 143 #endif
 144 
 145 static struct ra_param_s *
 146 ra_param_from_xml(xmlNode *param_xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148     const char *param_name = crm_element_value(param_xml, "name");
 149     const char *value;
 150     struct ra_param_s *p;
 151 
 152     p = calloc(1, sizeof(struct ra_param_s));
 153     if (p == NULL) {
 154         crm_crit("Could not allocate memory for resource metadata");
 155         return NULL;
 156     }
 157 
 158     p->rap_name = strdup(param_name);
 159     if (p->rap_name == NULL) {
 160         crm_crit("Could not allocate memory for resource metadata");
 161         free(p);
 162         return NULL;
 163     }
 164 
 165     value = crm_element_value(param_xml, "unique");
 166     if (crm_is_true(value)) {
 167         controld_set_ra_param_flags(p, ra_param_unique);
 168     }
 169 
 170     value = crm_element_value(param_xml, "private");
 171     if (crm_is_true(value)) {
 172         controld_set_ra_param_flags(p, ra_param_private);
 173     }
 174     return p;
 175 }
 176 
 177 struct ra_metadata_s *
 178 metadata_cache_update(GHashTable *mdc, lrmd_rsc_info_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 179                       const char *metadata_str)
 180 {
 181     char *key = NULL;
 182     xmlNode *metadata = NULL;
 183     xmlNode *match = NULL;
 184     struct ra_metadata_s *md = NULL;
 185 
 186     CRM_CHECK(mdc && rsc && metadata_str, return NULL);
 187 
 188     key = crm_generate_ra_key(rsc->standard, rsc->provider, rsc->type);
 189     if (!key) {
 190         crm_crit("Could not allocate memory for resource metadata");
 191         goto err;
 192     }
 193 
 194     metadata = string2xml(metadata_str);
 195     if (!metadata) {
 196         crm_err("Metadata for %s:%s:%s is not valid XML",
 197                 rsc->standard, rsc->provider, rsc->type);
 198         goto err;
 199     }
 200 
 201     md = calloc(1, sizeof(struct ra_metadata_s));
 202     if (md == NULL) {
 203         crm_crit("Could not allocate memory for resource metadata");
 204         goto err;
 205     }
 206 
 207 #if ENABLE_VERSIONED_ATTRS
 208     md->ra_version = ra_version_from_xml(metadata, rsc);
 209 #endif
 210 
 211     // Check supported actions
 212     match = first_named_child(metadata, "actions");
 213     for (match = first_named_child(match, "action"); match != NULL;
 214          match = crm_next_same_xml(match)) {
 215 
 216         const char *action_name = crm_element_value(match, "name");
 217 
 218         if (pcmk__str_eq(action_name, "reload", pcmk__str_casei)) {
 219             controld_set_ra_flags(md, key, ra_supports_reload);
 220             break; // since this is the only action we currently care about
 221         }
 222     }
 223 
 224     // Build a parameter list
 225     match = first_named_child(metadata, "parameters");
 226     for (match = first_named_child(match, "parameter"); match != NULL;
 227          match = crm_next_same_xml(match)) {
 228 
 229         const char *param_name = crm_element_value(match, "name");
 230 
 231         if (param_name == NULL) {
 232             crm_warn("Metadata for %s:%s:%s has parameter without a name",
 233                      rsc->standard, rsc->provider, rsc->type);
 234         } else {
 235             struct ra_param_s *p = ra_param_from_xml(match);
 236 
 237             if (p == NULL) {
 238                 goto err;
 239             }
 240             if (pcmk_is_set(p->rap_flags, ra_param_private)) {
 241                 controld_set_ra_flags(md, key, ra_uses_private);
 242             }
 243             md->ra_params = g_list_prepend(md->ra_params, p);
 244         }
 245     }
 246 
 247     g_hash_table_replace(mdc, key, md);
 248     free_xml(metadata);
 249     return md;
 250 
 251 err:
 252     free(key);
 253     free_xml(metadata);
 254     metadata_free(md);
 255     return NULL;
 256 }
 257 
 258 struct ra_metadata_s *
 259 metadata_cache_get(GHashTable *mdc, lrmd_rsc_info_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 260 {
 261     char *key = NULL;
 262     struct ra_metadata_s *metadata = NULL;
 263 
 264     CRM_CHECK(mdc && rsc, return NULL);
 265     key = crm_generate_ra_key(rsc->standard, rsc->provider, rsc->type);
 266     if (key) {
 267         metadata = g_hash_table_lookup(mdc, key);
 268         free(key);
 269     }
 270     return metadata;
 271 }

/* [previous][next][first][last][top][bottom][index][help] */