summaryrefslogtreecommitdiffstats
path: root/lib/common/agents.c
blob: d2066c0299a9e580262fd434c990a5dccaa6ebb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * Copyright 2004-2021 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_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_STONITH_PROVIDES,
                         PCMK_STONITH_STONITH_TIMEOUT, NULL)) {
        return true;
    }
    if (!pcmk__starts_with(param, "pcmk_")) { // Short-circuit common case
        return false;
    }
    if (pcmk__str_any_of(param,
                         PCMK_STONITH_ACTION_LIMIT,
                         PCMK_STONITH_DELAY_BASE,
                         PCMK_STONITH_DELAY_MAX,
                         PCMK_STONITH_HOST_ARGUMENT,
                         PCMK_STONITH_HOST_CHECK,
                         PCMK_STONITH_HOST_LIST,
                         PCMK_STONITH_HOST_MAP,
                         NULL)) {
        return true;
    }
    param = strchr(param + 5, '_'); // Skip past "pcmk_ACTION"
    return pcmk__str_any_of(param, "_action", "_timeout", "_retries", NULL);
}

// Deprecated functions kept only for backward API compatibility
// LCOV_EXCL_START

#include <crm/common/agents_compat.h>

bool
crm_provider_required(const char *standard)
{
    return pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
}

// LCOV_EXCL_STOP
// End deprecated API