diff --git a/lib/common/agents.c b/lib/common/agents.c index c86a5abafe..a704ae7bc6 100644 --- a/lib/common/agents.c +++ b/lib/common/agents.c @@ -1,193 +1,192 @@ /* * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include // g_str_has_prefix() #include #include /*! * \brief Get capabilities of a resource agent standard * * \param[in] standard Standard name * * \return Bitmask of enum pcmk_ra_caps values */ uint32_t pcmk_get_ra_caps(const char *standard) { /* @COMPAT This should probably be case-sensitive, but isn't, * for backward compatibility. */ if (standard == NULL) { return pcmk_ra_cap_none; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF)) { return pcmk_ra_cap_provider | pcmk_ra_cap_params | pcmk_ra_cap_unique | pcmk_ra_cap_promotable | pcmk_ra_cap_cli_exec; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_STONITH)) { /* @COMPAT Stonith resources can't really be unique clones, but we've * allowed it in the past and have it in some scheduler regression tests * (which were likely never used as real configurations). * * @TODO Remove pcmk_ra_cap_unique at the next major schema version * bump, with a transform to remove PCMK_META_GLOBALLY_UNIQUE from the * config. */ return pcmk_ra_cap_params | pcmk_ra_cap_unique | pcmk_ra_cap_stdin | pcmk_ra_cap_fence_params; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB)) { return pcmk_ra_cap_status | pcmk_ra_cap_cli_exec; } else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) || !strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE)) { return pcmk_ra_cap_status; } return pcmk_ra_cap_none; } int pcmk__effective_rc(int rc) { int remapped_rc = rc; switch (rc) { case PCMK_OCF_DEGRADED: remapped_rc = PCMK_OCF_OK; break; case PCMK_OCF_DEGRADED_PROMOTED: remapped_rc = PCMK_OCF_RUNNING_PROMOTED; break; default: break; } return remapped_rc; } char * crm_generate_ra_key(const char *standard, const char *provider, const char *type) { bool std_empty = pcmk__str_empty(standard); bool prov_empty = pcmk__str_empty(provider); bool ty_empty = pcmk__str_empty(type); if (std_empty || ty_empty) { return NULL; } return crm_strdup_printf("%s%s%s:%s", standard, (prov_empty ? "" : ":"), (prov_empty ? "" : provider), type); } /*! * \brief Parse a "standard[:provider]:type" agent specification * * \param[in] spec Agent specification * \param[out] standard Newly allocated memory containing agent standard (or NULL) * \param[out] provider Newly allocated memory containing agent provider (or NULL) * \param[put] type Newly allocated memory containing agent type (or NULL) * * \return pcmk_ok if the string could be parsed, -EINVAL otherwise * * \note It is acceptable for the type to contain a ':' if the standard supports * that. For example, systemd supports the form "systemd:UNIT@A:B". * \note It is the caller's responsibility to free the returned values. */ int crm_parse_agent_spec(const char *spec, char **standard, char **provider, char **type) { char *colon; CRM_CHECK(spec && standard && provider && type, return -EINVAL); *standard = NULL; *provider = NULL; *type = NULL; colon = strchr(spec, ':'); if ((colon == NULL) || (colon == spec)) { return -EINVAL; } *standard = strndup(spec, colon - spec); spec = colon + 1; if (pcmk_is_set(pcmk_get_ra_caps(*standard), pcmk_ra_cap_provider)) { colon = strchr(spec, ':'); if ((colon == NULL) || (colon == spec)) { free(*standard); return -EINVAL; } *provider = strndup(spec, colon - spec); spec = colon + 1; } if (*spec == '\0') { free(*standard); free(*provider); return -EINVAL; } *type = strdup(spec); return pcmk_ok; } /*! * \brief Check whether a given stonith parameter is handled by Pacemaker * * Return true if a given string is the name of one of the special resource * instance attributes interpreted directly by Pacemaker for stonith-class * resources. * * \param[in] param Parameter name to check * * \return true if \p param is a special fencing parameter */ bool pcmk_stonith_param(const char *param) { if (param == NULL) { return false; } - if (pcmk__str_any_of(param, PCMK_FENCING_PROVIDES, - PCMK_STONITH_STONITH_TIMEOUT, NULL)) { + if (pcmk__str_eq(param, PCMK_FENCING_PROVIDES, pcmk__str_none)) { return true; } if (!g_str_has_prefix(param, "pcmk_")) { // Short-circuit common case return false; } if (pcmk__str_any_of(param, PCMK_FENCING_ACTION_LIMIT, PCMK_FENCING_DELAY_BASE, PCMK_FENCING_DELAY_MAX, PCMK_FENCING_HOST_ARGUMENT, PCMK_FENCING_HOST_CHECK, PCMK_FENCING_HOST_LIST, PCMK_FENCING_HOST_MAP, NULL)) { return true; } param = strchr(param + 5, '_'); // Skip past "pcmk_ACTION" return pcmk__str_any_of(param, "_action", "_timeout", "_retries", NULL); } diff --git a/lib/common/tests/agents/pcmk_stonith_param_test.c b/lib/common/tests/agents/pcmk_stonith_param_test.c index 32858d5eb4..7532af5a33 100644 --- a/lib/common/tests/agents/pcmk_stonith_param_test.c +++ b/lib/common/tests/agents/pcmk_stonith_param_test.c @@ -1,50 +1,49 @@ /* * Copyright 2020-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include static void is_stonith_param(void **state) { assert_false(pcmk_stonith_param(NULL)); assert_false(pcmk_stonith_param("")); assert_false(pcmk_stonith_param("unrecognized")); assert_false(pcmk_stonith_param("pcmk_unrecognized")); assert_false(pcmk_stonith_param("x" PCMK_FENCING_ACTION_LIMIT)); assert_false(pcmk_stonith_param(PCMK_FENCING_ACTION_LIMIT "x")); assert_true(pcmk_stonith_param(PCMK_FENCING_ACTION_LIMIT)); assert_true(pcmk_stonith_param(PCMK_FENCING_DELAY_BASE)); assert_true(pcmk_stonith_param(PCMK_FENCING_DELAY_MAX)); assert_true(pcmk_stonith_param(PCMK_FENCING_HOST_ARGUMENT)); assert_true(pcmk_stonith_param(PCMK_FENCING_HOST_CHECK)); assert_true(pcmk_stonith_param(PCMK_FENCING_HOST_LIST)); assert_true(pcmk_stonith_param(PCMK_FENCING_HOST_MAP)); assert_true(pcmk_stonith_param(PCMK_FENCING_PROVIDES)); - assert_true(pcmk_stonith_param(PCMK_STONITH_STONITH_TIMEOUT)); } static void is_stonith_action_param(void **state) { /* Currently, the function accepts any string not containing underbars as * the action name, so we do not need to verify particular action names. */ assert_false(pcmk_stonith_param("pcmk_on_unrecognized")); assert_true(pcmk_stonith_param("pcmk_on_action")); assert_true(pcmk_stonith_param("pcmk_on_timeout")); assert_true(pcmk_stonith_param("pcmk_on_retries")); } PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(is_stonith_param), cmocka_unit_test(is_stonith_action_param))