14 #include <sys/types.h> 39 static int operations = 0;
40 static GHashTable *recurring_actions = NULL;
44 static GList *blocked_ops = NULL;
47 static GList *inflight_ops = NULL;
49 static void handle_blocked_ops(
void);
55 action, interval, timeout, NULL, 0);
59 services__lsb_agent_path(
const char *agent)
61 return (*agent ==
'/')? strdup(agent)
66 services__lsb_agent_exists(
const char *agent)
70 char *path = services__lsb_agent_path(agent);
72 rc = (stat(path, &st) == 0);
96 if (services__lsb_agent_exists(agent)) {
115 init_recurring_actions(
void)
117 if (recurring_actions == NULL) {
118 recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
131 static inline gboolean
136 && (g_list_find(inflight_ops, op) != NULL);
152 expand_resource_class(
const char *rsc,
const char *standard,
const char *agent)
154 char *expanded_class = NULL;
160 crm_debug(
"Found %s agent %s for %s", found_class, agent, rsc);
161 expanded_class = strdup(found_class);
163 crm_info(
"Assuming resource class lsb for agent %s for %s",
168 expanded_class = strdup(standard);
171 return expanded_class;
176 const char *agent,
const char *action,
int interval,
int timeout,
186 if (crm_strlen_zero(name)) {
187 crm_err(
"Cannot create operation without resource name");
191 if (crm_strlen_zero(standard)) {
192 crm_err(
"Cannot create operation for %s without resource class", name);
197 crm_err(
"Cannot create OCF operation for %s without provider", name);
201 if (crm_strlen_zero(agent)) {
202 crm_err(
"Cannot create operation for %s without agent name", name);
206 if (crm_strlen_zero(action)) {
207 crm_err(
"Cannot create operation for %s without operation name", name);
217 op->
rsc = strdup(name);
220 op->
standard = expand_resource_class(name, standard, agent);
221 op->
agent = strdup(agent);
233 op->
action = strdup(action);
241 crm_err(
"Internal error: cannot create agent path");
252 #if SUPPORT_HEARTBEAT 259 if (op->
agent[0] ==
'/') {
263 }
else if (asprintf(&op->
opaque->
exec,
"%s/%s", HB_RA_DIR, op->
agent) == -1) {
264 crm_err(
"Internal error: cannot create agent path");
273 for (index = 1; index <=
MAX_ARGC - 3; index++ ) {
274 snprintf(buf_tmp,
sizeof(buf_tmp),
"%d", index);
275 value_tmp = g_hash_table_lookup(params, buf_tmp);
276 if (value_tmp == NULL) {
281 op->
opaque->
args[param_num++] = strdup(value_tmp);
302 if (op->
agent[0] ==
'/') {
308 crm_err(
"Internal error: cannot create agent path");
317 op->
opaque->
args[index] = strdup(
"--version");
324 static int args_size =
sizeof(op->
opaque->
args) /
sizeof(
char *);
326 g_hash_table_iter_init(&iter, params);
328 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
329 index <= args_size - 3) {
331 char *long_opt = NULL;
338 long_opt = calloc(1, len);
339 sprintf(long_opt,
"--%s", key);
340 long_opt[len - 1] = 0;
356 g_hash_table_destroy(params);
362 g_hash_table_destroy(params);
373 unsigned int cur_arg;
375 op = calloc(1,
sizeof(*op));
381 for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
382 op->
opaque->
args[cur_arg] = strdup(args[cur_arg - 1]);
385 crm_err(
"svc_action_t args list not long enough for '%s' execution request.", exec);
409 GHashTable *params,
int sequence,
void *cb_data)
415 action->
id = strdup(
id);
440 CRM_CHECK((op != NULL) && (user != NULL),
return -EINVAL);
445 set_alert_env(gpointer key, gpointer value, gpointer user_data)
450 rc =
setenv(key, value, 1);
457 (
char*)key, (value? (
char*)value :
""));
459 crm_trace(
"setenv %s=%s", (
char*)key, (value? (
char*)value :
""));
464 unset_alert_env(gpointer key, gpointer value, gpointer user_data)
466 if (unsetenv(key) < 0) {
487 gboolean responsible;
492 g_hash_table_foreach(action->
params, set_alert_env, NULL);
496 g_hash_table_foreach(action->
params, unset_alert_env, NULL);
510 services_set_op_pending(
svc_action_t *op, DBusPendingCall *pending)
512 if (op->
opaque->pending && (op->
opaque->pending != pending)) {
518 dbus_pending_call_unref(op->
opaque->pending);
520 op->
opaque->pending = pending;
522 crm_trace(
"Updated pending %s DBus call (%p)", op->
id, pending);
537 if(op->
opaque->timerid != 0) {
539 g_source_remove(op->
opaque->timerid);
545 if(dbus_pending_call_get_completed(op->
opaque->pending)) {
548 dbus_pending_call_cancel(op->
opaque->pending);
549 dbus_pending_call_unref(op->
opaque->pending);
550 op->
opaque->pending = NULL;
578 CRM_CHECK(g_list_find(inflight_ops, op) == NULL,
return);
579 CRM_CHECK(g_list_find(blocked_ops, op) == NULL,
return);
581 || (g_hash_table_lookup(recurring_actions, op->
id) == NULL),
610 g_hash_table_destroy(op->
params);
622 if (recurring_actions) {
623 g_hash_table_remove(recurring_actions, op->
id);
646 gboolean cancelled = FALSE;
651 init_recurring_actions();
652 op = g_hash_table_lookup(recurring_actions,
id);
670 crm_info(
"Terminating in-flight op %s (pid %d) early because it was cancelled",
673 if (cancelled == FALSE) {
674 crm_err(
"Termination of %s (pid %d) failed",
id, op->
pid);
684 if (inflight_systemd_or_upstart(op)) {
685 crm_info(
"Will cancel %s op %s when in-flight instance completes",
697 blocked_ops = g_list_remove(blocked_ops, op);
712 init_recurring_actions();
713 op = g_hash_table_lookup(recurring_actions,
id);
721 if (op->
pid || inflight_systemd_or_upstart(op)) {
748 dup = g_hash_table_lookup(recurring_actions, op->
id);
750 if (dup && (dup != op)) {
773 inline static gboolean
808 inflight_ops = g_list_append(inflight_ops, op);
822 inflight_ops = g_list_remove(inflight_ops, op);
823 blocked_ops = g_list_remove(blocked_ops, op);
826 handle_blocked_ops();
833 if (action_callback) {
838 init_recurring_actions();
839 if (handle_duplicate_recurring(op) == TRUE) {
844 g_hash_table_replace(recurring_actions, op->
id, op);
848 blocked_ops = g_list_append(blocked_ops, op);
852 return action_exec_helper(op);
856 static gboolean processing_blocked_ops = FALSE;
864 for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
875 handle_blocked_ops(
void)
877 GList *executed_ops = NULL;
880 gboolean res = FALSE;
882 if (processing_blocked_ops) {
887 processing_blocked_ops = TRUE;
891 for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
896 executed_ops = g_list_append(executed_ops, op);
897 res = action_exec_helper(op);
906 for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
908 blocked_ops = g_list_remove(blocked_ops, op);
910 g_list_free(executed_ops);
912 processing_blocked_ops = FALSE;
915 #define lsb_metadata_template \ 916 "<?xml version='1.0'?>\n" \ 917 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" \ 918 "<resource-agent name='%s' version='" PCMK_DEFAULT_AGENT_VERSION "'>\n" \ 919 " <version>1.0</version>\n" \ 920 " <longdesc lang='en'>\n" \ 923 " <shortdesc lang='en'>%s</shortdesc>\n" \ 927 " <action name='meta-data' timeout='5' />\n" \ 928 " <action name='start' timeout='15' />\n" \ 929 " <action name='stop' timeout='15' />\n" \ 930 " <action name='status' timeout='15' />\n" \ 931 " <action name='restart' timeout='15' />\n" \ 932 " <action name='force-reload' timeout='15' />\n" \ 933 " <action name='monitor' timeout='15' interval='15' />\n" \ 935 " <special tag='LSB'>\n" \ 936 " <Provides>%s</Provides>\n" \ 937 " <Required-Start>%s</Required-Start>\n" \ 938 " <Required-Stop>%s</Required-Stop>\n" \ 939 " <Should-Start>%s</Should-Start>\n" \ 940 " <Should-Stop>%s</Should-Stop>\n" \ 941 " <Default-Start>%s</Default-Start>\n" \ 942 " <Default-Stop>%s</Default-Stop>\n" \ 944 "</resource-agent>\n" 949 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO" 950 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO" 951 #define PROVIDES "# Provides:" 952 #define REQ_START "# Required-Start:" 953 #define REQ_STOP "# Required-Stop:" 954 #define SHLD_START "# Should-Start:" 955 #define SHLD_STOP "# Should-Stop:" 956 #define DFLT_START "# Default-Start:" 957 #define DFLT_STOP "# Default-Stop:" 958 #define SHORT_DSCR "# Short-Description:" 959 #define DESCRIPTION "# Description:" 961 #define lsb_meta_helper_free_value(m) \ 979 static inline gboolean
980 lsb_meta_helper_get_value(
const char *line,
char **value,
const char *prefix)
983 *value = (
char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
989 #define DESC_MAX 2048 992 lsb_get_metadata(
const char *
type,
char **output)
994 char ra_pathname[PATH_MAX] = { 0, };
996 char buffer[1024] = { 0, };
997 char *provides = NULL;
998 char *req_start = NULL;
999 char *req_stop = NULL;
1000 char *shld_start = NULL;
1001 char *shld_stop = NULL;
1002 char *dflt_start = NULL;
1003 char *dflt_stop = NULL;
1004 char *s_dscrpt = NULL;
1005 char *xml_l_dscrpt = NULL;
1007 bool in_header = FALSE;
1008 char description[
DESC_MAX] = { 0, };
1010 if (type[0] ==
'/') {
1011 snprintf(ra_pathname,
sizeof(ra_pathname),
"%s", type);
1013 snprintf(ra_pathname,
sizeof(ra_pathname),
"%s/%s",
1017 crm_trace(
"Looking into %s", ra_pathname);
1018 fp = fopen(ra_pathname,
"r");
1024 while (fgets(buffer,
sizeof(buffer), fp)) {
1036 if (lsb_meta_helper_get_value(buffer, &provides,
PROVIDES)) {
1039 if (lsb_meta_helper_get_value(buffer, &req_start,
REQ_START)) {
1042 if (lsb_meta_helper_get_value(buffer, &req_stop,
REQ_STOP)) {
1045 if (lsb_meta_helper_get_value(buffer, &shld_start,
SHLD_START)) {
1048 if (lsb_meta_helper_get_value(buffer, &shld_stop,
SHLD_STOP)) {
1051 if (lsb_meta_helper_get_value(buffer, &dflt_start,
DFLT_START)) {
1054 if (lsb_meta_helper_get_value(buffer, &dflt_stop,
DFLT_STOP)) {
1057 if (lsb_meta_helper_get_value(buffer, &s_dscrpt,
SHORT_DSCR)) {
1064 bool processed_line = TRUE;
1067 offset += snprintf(description,
DESC_MAX,
"%s",
1072 while (fgets(buffer,
sizeof(buffer), fp)) {
1078 offset += snprintf(description + offset,
DESC_MAX - offset,
1084 processed_line = FALSE;
1090 xml_l_dscrpt = (
char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
1092 if (processed_line) {
1102 if (buffer[0] !=
'#') {
1109 (xml_l_dscrpt? xml_l_dscrpt : type),
1110 (s_dscrpt? s_dscrpt : type),
1111 (provides? provides :
""),
1112 (req_start? req_start :
""),
1113 (req_stop? req_stop :
""),
1114 (shld_start? shld_start :
""),
1115 (shld_stop? shld_stop :
""),
1116 (dflt_start? dflt_start :
""),
1117 (dflt_stop? dflt_stop :
""));
1129 crm_trace(
"Created fake metadata: %llu",
1130 (
unsigned long long) strlen(*output));
1136 nagios_get_metadata(
const char *
type,
char **output)
1139 FILE *file_strm = NULL;
1140 int start = 0, length = 0, read_len = 0;
1144 file_strm = fopen(metadata_file,
"r");
1145 if (file_strm == NULL) {
1146 crm_err(
"Metadata file %s does not exist", metadata_file);
1147 free(metadata_file);
1152 start = ftell(file_strm);
1153 fseek(file_strm, 0L, SEEK_END);
1154 length = ftell(file_strm);
1155 fseek(file_strm, 0L, start);
1161 crm_info(
"%s was not valid", metadata_file);
1167 crm_trace(
"Reading %d bytes from file", length);
1168 *output = calloc(1, (length + 1));
1169 read_len = fread(*output, 1, length, file_strm);
1170 if (read_len != length) {
1171 crm_err(
"Calculated and read bytes differ: %d vs. %d",
1180 free(metadata_file);
1185 #if SUPPORT_HEARTBEAT 1201 static const char hb_metadata_template[] =
1202 "<?xml version='1.0'?>\n" 1203 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" 1205 "<version>1.0</version>\n" 1206 "<longdesc lang='en'>\n" 1209 "<shortdesc lang='en'>%s</shortdesc>\n" 1211 "<parameter name='1' unique='1' required='0'>\n" 1212 "<longdesc lang='en'>\n" 1213 "This argument will be passed as the first argument to the " 1214 "heartbeat resource agent (assuming it supports one)\n" 1216 "<shortdesc lang='en'>argv[1]</shortdesc>\n" 1217 "<content type='string' default=' ' />\n" 1219 "<parameter name='2' unique='1' required='0'>\n" 1220 "<longdesc lang='en'>\n" 1221 "This argument will be passed as the second argument to the " 1222 "heartbeat resource agent (assuming it supports one)\n" 1224 "<shortdesc lang='en'>argv[2]</shortdesc>\n" 1225 "<content type='string' default=' ' />\n" 1227 "<parameter name='3' unique='1' required='0'>\n" 1228 "<longdesc lang='en'>\n" 1229 "This argument will be passed as the third argument to the " 1230 "heartbeat resource agent (assuming it supports one)\n" 1232 "<shortdesc lang='en'>argv[3]</shortdesc>\n" 1233 "<content type='string' default=' ' />\n" 1235 "<parameter name='4' unique='1' required='0'>\n" 1236 "<longdesc lang='en'>\n" 1237 "This argument will be passed as the fourth argument to the " 1238 "heartbeat resource agent (assuming it supports one)\n" 1240 "<shortdesc lang='en'>argv[4]</shortdesc>\n" 1241 "<content type='string' default=' ' />\n" 1243 "<parameter name='5' unique='1' required='0'>\n" 1244 "<longdesc lang='en'>\n" 1245 "This argument will be passed as the fifth argument to the " 1246 "heartbeat resource agent (assuming it supports one)\n" 1248 "<shortdesc lang='en'>argv[5]</shortdesc>\n" 1249 "<content type='string' default=' ' />\n" 1253 "<action name='start' timeout='15' />\n" 1254 "<action name='stop' timeout='15' />\n" 1255 "<action name='status' timeout='15' />\n" 1256 "<action name='monitor' timeout='15' interval='15' start-delay='15' />\n" 1257 "<action name='meta-data' timeout='5' />\n" 1259 "<special tag='heartbeat'>\n" 1261 "</resource-agent>\n";
1264 heartbeat_get_metadata(
const char *type,
char **output)
1267 crm_trace(
"Created fake metadata: %llu",
1268 (
unsigned long long) strlen(*output));
1276 const char *
class = op->standard;
1278 if (op->
agent == NULL) {
1279 crm_err(
"meta-data requested without specifying agent");
1283 if (
class == NULL) {
1284 crm_err(
"meta-data requested for agent %s without specifying class",
1293 if (
class == NULL) {
1294 crm_err(
"meta-data requested for %s, but could not determine class",
1309 #if SUPPORT_HEARTBEAT 1315 return action_exec_helper(op);
1338 rc = action_get_metadata(op);
1340 rc = action_exec_helper(op);
1365 #if SUPPORT_HEARTBEAT 1367 resources_os_list_hb_agents(
void)
1376 GList *standards = NULL;
1377 GList *agents = NULL;
1386 standards = g_list_append(standards,
1388 g_list_free_full(agents, free);
1395 standards = g_list_append(standards,
1397 g_list_free_full(agents, free);
1404 standards = g_list_append(standards,
1406 g_list_free_full(agents, free);
1410 #if SUPPORT_HEARTBEAT 1430 if ((standard == NULL)
1437 if (standard == NULL) {
1441 result = g_list_concat(tmp1, tmp2);
1448 result = g_list_concat(tmp1, tmp2);
1456 result = g_list_concat(tmp1, tmp2);
1466 #if SUPPORT_HEARTBEAT 1468 return resources_os_list_hb_agents();
gboolean services_action_cancel(const char *name, const char *action, int interval)
Cancel a recurring action.
#define CRM_CHECK(expr, failure_action)
#define lsb_metadata_template
void(* callback)(svc_action_t *op)
GList * resources_list_providers(const char *standard)
Get a list of providers.
gboolean upstart_job_exists(const char *name)
gboolean mainloop_child_kill(pid_t pid)
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
#define PCMK_RESOURCE_CLASS_SYSTEMD
gboolean recurring_action_timer(gpointer data)
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
gboolean services_os_action_execute(svc_action_t *op)
G_GNUC_INTERNAL GList * resources_os_list_nagios_agents(void)
gboolean upstart_job_exec(svc_action_t *op)
gboolean is_op_blocked(const char *rsc)
Wrappers for and extensions to glib mainloop.
bool crm_starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
GList * resources_os_list_lsb_agents(void)
enum svc_action_flags flags
#define crm_warn(fmt, args...)
GList * services_list(void)
#define PCMK_RESOURCE_CLASS_OCF
gboolean cancel_recurring_action(svc_action_t *op)
svc_action_private_t * opaque
GList * upstart_job_listall(void)
#define crm_debug(fmt, args...)
gboolean operation_finalize(svc_action_t *op)
svc_action_t * services_alert_create(const char *id, const char *exec, int timeout, GHashTable *params, int sequence, void *cb_data)
Create an alert agent action.
gboolean systemd_unit_exists(const char *name)
#define PCMK_RESOURCE_CLASS_SERVICE
#define LSB_INITSCRIPT_INFOEND_TAG
#define crm_trace(fmt, args...)
int setenv(const char *name, const char *value, int why)
gboolean services_alert_async(svc_action_t *action, void(*cb)(svc_action_t *op))
Execute an alert agent action.
#define LSB_INITSCRIPT_INFOBEGIN_TAG
gboolean services_action_sync(svc_action_t *op)
#define SUPPORT_HEARTBEAT
gboolean services_action_kick(const char *name, const char *action, int interval)
GList * systemd_unit_listall(void)
const char * resources_find_service_class(const char *agent)
Find first service class that can provide a specified agent.
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
void services_add_inflight_op(svc_action_t *op)
GList * resources_list_standards(void)
void services_untrack_op(svc_action_t *op)
GList * get_directory_list(const char *root, gboolean files, gboolean executable)
Get a list of files or directories in a given path.
#define PCMK_RESOURCE_CLASS_NAGIOS
#define PCMK_RESOURCE_CLASS_LSB
#define crm_perror(level, fmt, args...)
Log a system error message.
#define NAGIOS_PLUGIN_DIR
#define crm_err(fmt, args...)
#define PCMK_RESOURCE_CLASS_UPSTART
#define PCMK_RESOURCE_CLASS_HB
int services_action_user(svc_action_t *op, const char *user)
Set the user and group that an action will execute as.
#define PCMK_DEFAULT_AGENT_VERSION
mainloop_io_t * stdout_gsource
#define XML_ATTR_CRM_VERSION
void mainloop_del_fd(mainloop_io_t *client)
void services_action_cleanup(svc_action_t *op)
bool crm_provider_required(const char *standard)
Check whether a resource standard requires a provider to be specified.
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Generate an operation key.
#define safe_str_eq(a, b)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
void services_action_free(svc_action_t *op)
gboolean systemd_unit_exec(svc_action_t *op)
#define crm_info(fmt, args...)
#define NAGIOS_METADATA_DIR
svc_action_t * services_action_create(const char *name, const char *action, int interval, int timeout)
enum crm_ais_msg_types type
#define lsb_meta_helper_free_value(m)