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

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