/*
* Copyright 2004-2020 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 <crm_internal.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <crm/crm.h>
#include <crm/common/util.h>
/*!
* \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;
} 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 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_SYSTEMD)
|| !strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE)
|| !strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB)
|| !strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART)) {
/* Since service can map to LSB, systemd, or upstart, these should
* have identical capabilities
*/
return pcmk_ra_cap_status;
} else if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
return pcmk_ra_cap_params;
}
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_MASTER:
remapped_rc = PCMK_OCF_RUNNING_MASTER;
break;
default:
break;
}
return remapped_rc;
}
char *
crm_generate_ra_key(const char *standard, const char *provider,
const char *type)
{
if (!standard && !provider && !type) {
return NULL;
}
return crm_strdup_printf("%s%s%s:%s",
(standard? standard : ""),
(provider? ":" : ""), (provider? provider : ""),
(type? 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;
}
// Deprecated functions kept only for backward API compatibility
bool crm_provider_required(const char *standard);
/*!
* \deprecated
* \brief Check whether a resource standard requires a provider to be specified
*
* \param[in] standard Standard name
*
* \return TRUE if standard requires a provider, FALSE otherwise
*/
bool
crm_provider_required(const char *standard)
{
return pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
}