root/lib/services/upstart.c

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

DEFINITIONS

This source file includes following definitions.
  1. services__upstart_prepare
  2. services__upstart2ocf
  3. upstart_init
  4. upstart_cleanup
  5. object_path_for_job
  6. fix
  7. fix_upstart_name
  8. upstart_job_listall
  9. upstart_job_exists
  10. get_first_instance
  11. parse_status_result
  12. upstart_job_metadata
  13. set_result_from_method_error
  14. job_method_complete
  15. services__execute_upstart

   1 /*
   2  * Original copyright 2010 Senko Rasic <senko.rasic@dobarkod.hr>
   3  *                         and Ante Karamatic <ivoks@init.hr>
   4  * Later changes copyright 2012-2023 the Pacemaker project contributors
   5  *
   6  * The version control history for this file may have further details.
   7  *
   8  * This source code is licensed under the GNU Lesser General Public License
   9  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  10  */
  11 
  12 #include <crm_internal.h>
  13 
  14 #include <stdio.h>
  15 
  16 #include <crm/crm.h>
  17 #include <crm/services.h>
  18 #include <crm/common/mainloop.h>
  19 
  20 #include <services_private.h>
  21 #include <upstart.h>
  22 #include <dbus/dbus.h>
  23 #include <pcmk-dbus.h>
  24 
  25 #include <glib.h>
  26 #include <gio/gio.h>
  27 
  28 #define BUS_NAME "com.ubuntu.Upstart"
  29 #define BUS_PATH "/com/ubuntu/Upstart"
  30 
  31 #define UPSTART_06_API     BUS_NAME"0_6"
  32 #define UPSTART_JOB_IFACE  UPSTART_06_API".Job"
  33 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
  34 
  35 /*
  36   http://upstart.ubuntu.com/wiki/DBusInterface
  37 */
  38 static DBusConnection *upstart_proxy = NULL;
  39 
  40 /*!
  41  * \internal
  42  * \brief Prepare an Upstart action
  43  *
  44  * \param[in,out] op  Action to prepare
  45  *
  46  * \return Standard Pacemaker return code
  47  */
  48 int
  49 services__upstart_prepare(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51     op->opaque->exec = strdup("upstart-dbus");
  52     if (op->opaque->exec == NULL) {
  53         return ENOMEM;
  54     }
  55     return pcmk_rc_ok;
  56 }
  57 
  58 /*!
  59  * \internal
  60  * \brief Map a Upstart result to a standard OCF result
  61  *
  62  * \param[in] exit_status  Upstart result
  63  *
  64  * \return Standard OCF result
  65  */
  66 enum ocf_exitcode
  67 services__upstart2ocf(int exit_status)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     // This library uses OCF codes for Upstart actions
  70     return (enum ocf_exitcode) exit_status;
  71 }
  72 
  73 static gboolean
  74 upstart_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76     static int need_init = 1;
  77 
  78     if (need_init) {
  79         need_init = 0;
  80         upstart_proxy = pcmk_dbus_connect();
  81     }
  82     if (upstart_proxy == NULL) {
  83         return FALSE;
  84     }
  85     return TRUE;
  86 }
  87 
  88 void
  89 upstart_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     if (upstart_proxy) {
  92         pcmk_dbus_disconnect(upstart_proxy);
  93         upstart_proxy = NULL;
  94     }
  95 }
  96 
  97 /*!
  98  * \internal
  99  * \brief Get the DBus object path corresponding to a job name
 100  *
 101  * \param[in]  arg_name  Name of job to get path for
 102  * \param[out] path      If not NULL, where to store DBus object path
 103  * \param[in]  timeout   Give up after this many seconds
 104  *
 105  * \return true if object path was found, false otherwise
 106  * \note The caller is responsible for freeing *path if it is non-NULL.
 107  */
 108 static bool
 109 object_path_for_job(const gchar *arg_name, char **path, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     /*
 112         com.ubuntu.Upstart0_6.GetJobByName (in String name, out ObjectPath job)
 113     */
 114     DBusError error;
 115     DBusMessage *msg;
 116     DBusMessage *reply = NULL;
 117     bool rc = false;
 118 
 119     if (path != NULL) {
 120         *path = NULL;
 121     }
 122 
 123     if (!upstart_init()) {
 124         return false;
 125     }
 126     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 127                                        BUS_PATH, // object to call on
 128                                        UPSTART_06_API,  // interface to call on
 129                                        "GetJobByName"); // method name
 130 
 131     dbus_error_init(&error);
 132     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &arg_name,
 133                                             DBUS_TYPE_INVALID));
 134     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout);
 135     dbus_message_unref(msg);
 136 
 137     if (dbus_error_is_set(&error)) {
 138         crm_err("Could not get DBus object path for %s: %s",
 139                 arg_name, error.message);
 140         dbus_error_free(&error);
 141 
 142     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 143                                      __func__, __LINE__)) {
 144         crm_err("Could not get DBus object path for %s: Invalid return type",
 145                 arg_name);
 146 
 147     } else {
 148         if (path != NULL) {
 149             dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, path,
 150                                   DBUS_TYPE_INVALID);
 151             if (*path != NULL) {
 152                 *path = strdup(*path);
 153             }
 154         }
 155         rc = true;
 156     }
 157 
 158     if (reply != NULL) {
 159         dbus_message_unref(reply);
 160     }
 161     return rc;
 162 }
 163 
 164 static void
 165 fix(char *input, const char *search, char replace)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     char *match = NULL;
 168     int shuffle = strlen(search) - 1;
 169 
 170     while (TRUE) {
 171         int len, lpc;
 172 
 173         match = strstr(input, search);
 174         if (match == NULL) {
 175             break;
 176         }
 177         crm_trace("Found: %s", match);
 178         match[0] = replace;
 179         len = strlen(match) - shuffle;
 180         for (lpc = 1; lpc <= len; lpc++) {
 181             match[lpc] = match[lpc + shuffle];
 182         }
 183     }
 184 }
 185 
 186 static char *
 187 fix_upstart_name(const char *input)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189     char *output = strdup(input);
 190 
 191     fix(output, "_2b", '+');
 192     fix(output, "_2c", ',');
 193     fix(output, "_2d", '-');
 194     fix(output, "_2e", '.');
 195     fix(output, "_40", '@');
 196     fix(output, "_5f", '_');
 197     return output;
 198 }
 199 
 200 GList *
 201 upstart_job_listall(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     GList *units = NULL;
 204     DBusMessageIter args;
 205     DBusMessageIter unit;
 206     DBusMessage *msg = NULL;
 207     DBusMessage *reply = NULL;
 208     const char *method = "GetAllJobs";
 209     DBusError error;
 210     int lpc = 0;
 211 
 212     if (upstart_init() == FALSE) {
 213         return NULL;
 214     }
 215 
 216 /*
 217   com.ubuntu.Upstart0_6.GetAllJobs (out <Array of ObjectPath> jobs)
 218 */
 219 
 220     dbus_error_init(&error);
 221     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 222                                        BUS_PATH, // object to call on
 223                                        UPSTART_06_API, // interface to call on
 224                                        method); // method name
 225     CRM_ASSERT(msg != NULL);
 226 
 227     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, DBUS_TIMEOUT_USE_DEFAULT);
 228     dbus_message_unref(msg);
 229 
 230     if (dbus_error_is_set(&error)) {
 231         crm_err("Call to %s failed: %s", method, error.message);
 232         dbus_error_free(&error);
 233         return NULL;
 234 
 235     } else if (!dbus_message_iter_init(reply, &args)) {
 236         crm_err("Call to %s failed: Message has no arguments", method);
 237         dbus_message_unref(reply);
 238         return NULL;
 239     }
 240 
 241     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __func__, __LINE__)) {
 242         crm_err("Call to %s failed: Message has invalid arguments", method);
 243         dbus_message_unref(reply);
 244         return NULL;
 245     }
 246 
 247     dbus_message_iter_recurse(&args, &unit);
 248     while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
 249         DBusBasicValue value;
 250         const char *job = NULL;
 251         char *path = NULL;
 252 
 253         if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __func__, __LINE__)) {
 254             crm_warn("Skipping Upstart reply argument with unexpected type");
 255             continue;
 256         }
 257 
 258         dbus_message_iter_get_basic(&unit, &value);
 259 
 260         if(value.str) {
 261             int llpc = 0;
 262             path = value.str;
 263             job = value.str;
 264             while (path[llpc] != 0) {
 265                 if (path[llpc] == '/') {
 266                     job = path + llpc + 1;
 267                 }
 268                 llpc++;
 269             }
 270             lpc++;
 271             crm_trace("%s -> %s", path, job);
 272             units = g_list_append(units, fix_upstart_name(job));
 273         }
 274         dbus_message_iter_next (&unit);
 275     }
 276 
 277     dbus_message_unref(reply);
 278     crm_trace("Found %d upstart jobs", lpc);
 279     return units;
 280 }
 281 
 282 gboolean
 283 upstart_job_exists(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285     return object_path_for_job(name, NULL, DBUS_TIMEOUT_USE_DEFAULT);
 286 }
 287 
 288 static char *
 289 get_first_instance(const gchar * job, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291     char *instance = NULL;
 292     const char *method = "GetAllInstances";
 293     DBusError error;
 294     DBusMessage *msg;
 295     DBusMessage *reply;
 296     DBusMessageIter args;
 297     DBusMessageIter unit;
 298 
 299     dbus_error_init(&error);
 300     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 301                                        job, // object to call on
 302                                        UPSTART_JOB_IFACE, // interface to call on
 303                                        method); // method name
 304     CRM_ASSERT(msg != NULL);
 305 
 306     dbus_message_append_args(msg, DBUS_TYPE_INVALID);
 307     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout);
 308     dbus_message_unref(msg);
 309 
 310     if (dbus_error_is_set(&error)) {
 311         crm_info("Call to %s failed: %s", method, error.message);
 312         dbus_error_free(&error);
 313         goto done;
 314 
 315     } else if(reply == NULL) {
 316         crm_info("Call to %s failed: no reply", method);
 317         goto done;
 318 
 319     } else if (!dbus_message_iter_init(reply, &args)) {
 320         crm_info("Call to %s failed: Message has no arguments", method);
 321         goto done;
 322     }
 323 
 324     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __func__, __LINE__)) {
 325         crm_info("Call to %s failed: Message has invalid arguments", method);
 326         goto done;
 327     }
 328 
 329     dbus_message_iter_recurse(&args, &unit);
 330     if(pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __func__, __LINE__)) {
 331         DBusBasicValue value;
 332 
 333         dbus_message_iter_get_basic(&unit, &value);
 334 
 335         if(value.str) {
 336             instance = strdup(value.str);
 337             crm_trace("Result: %s", instance);
 338         }
 339     }
 340 
 341   done:
 342     if(reply) {
 343         dbus_message_unref(reply);
 344     }
 345     return instance;
 346 }
 347 
 348 /*!
 349  * \internal
 350  * \brief Parse result of Upstart status check
 351  *
 352  * \param[in] name          DBus interface name for property that was checked
 353  * \param[in] state         Property value
 354  * \param[in,out] userdata  Status action that check was done for
 355  */
 356 static void
 357 parse_status_result(const char *name, const char *state, void *userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359     svc_action_t *op = userdata;
 360 
 361     if (pcmk__str_eq(state, "running", pcmk__str_none)) {
 362         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 363     } else {
 364         services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE, state);
 365     }
 366 
 367     if (!(op->synchronous)) {
 368         services_set_op_pending(op, NULL);
 369         services__finalize_async_op(op);
 370     }
 371 }
 372 
 373 #define METADATA_FORMAT                                                     \
 374     "<?xml version=\"1.0\"?>\n"                                             \
 375     "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"                   \
 376     "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
 377     "  <version>1.1</version>\n"                                            \
 378     "  <longdesc lang=\"en\">\n"                                            \
 379     "    Upstart agent for controlling the system %s service\n"             \
 380     "  </longdesc>\n"                                                       \
 381     "  <shortdesc lang=\"en\">Upstart job for %s</shortdesc>\n"             \
 382     "  <parameters/>\n"                                                     \
 383     "  <actions>\n"                                                         \
 384     "    <action name=\"start\"     timeout=\"15\" />\n"                    \
 385     "    <action name=\"stop\"      timeout=\"15\" />\n"                    \
 386     "    <action name=\"status\"    timeout=\"15\" />\n"                    \
 387     "    <action name=\"restart\"   timeout=\"15\" />\n"                    \
 388     "    <action name=\"monitor\"   timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n" \
 389     "    <action name=\"meta-data\" timeout=\"5\" />\n"                     \
 390     "  </actions>\n"                                                        \
 391     "  <special tag=\"upstart\"/>\n"                                        \
 392     "</resource-agent>\n"
 393 
 394 static char *
 395 upstart_job_metadata(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397     return crm_strdup_printf(METADATA_FORMAT, name, name, name);
 398 }
 399 
 400 /*!
 401  * \internal
 402  * \brief Set an action result based on a method error
 403  *
 404  * \param[in,out] op     Action to set result for
 405  * \param[in]     error  Method error
 406  */
 407 static void
 408 set_result_from_method_error(svc_action_t *op, const DBusError *error)
     /* [previous][next][first][last][top][bottom][index][help] */
 409 {
 410     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 411                          "Unable to invoke Upstart DBus method");
 412 
 413     if (strstr(error->name, UPSTART_06_API ".Error.UnknownInstance")) {
 414 
 415         if (pcmk__str_eq(op->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
 416             crm_trace("Masking stop failure (%s) for %s "
 417                       "because unknown service can be considered stopped",
 418                       error->name, pcmk__s(op->rsc, "unknown resource"));
 419             services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 420             return;
 421         }
 422 
 423         services__set_result(op, PCMK_OCF_NOT_INSTALLED,
 424                              PCMK_EXEC_NOT_INSTALLED, "Upstart job not found");
 425 
 426     } else if (pcmk__str_eq(op->action, PCMK_ACTION_START, pcmk__str_casei)
 427                && strstr(error->name, UPSTART_06_API ".Error.AlreadyStarted")) {
 428         crm_trace("Masking start failure (%s) for %s "
 429                   "because already started resource is OK",
 430                   error->name, pcmk__s(op->rsc, "unknown resource"));
 431         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 432         return;
 433     }
 434 
 435     crm_info("DBus request for %s of Upstart job %s for resource %s failed: %s",
 436              op->action, op->agent, pcmk__s(op->rsc, "with unknown name"),
 437              error->message);
 438 }
 439 
 440 /*!
 441  * \internal
 442  * \brief Process the completion of an asynchronous job start, stop, or restart
 443  *
 444  * \param[in,out] pending    If not NULL, DBus call associated with request
 445  * \param[in,out] user_data  Action that was executed
 446  */
 447 static void
 448 job_method_complete(DBusPendingCall *pending, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 449 {
 450     DBusError error;
 451     DBusMessage *reply = NULL;
 452     svc_action_t *op = user_data;
 453 
 454     // Grab the reply
 455     if (pending != NULL) {
 456         reply = dbus_pending_call_steal_reply(pending);
 457     }
 458 
 459     // Determine result
 460     dbus_error_init(&error);
 461     if (pcmk_dbus_find_error(pending, reply, &error)) {
 462         set_result_from_method_error(op, &error);
 463         dbus_error_free(&error);
 464 
 465     } else if (pcmk__str_eq(op->action, PCMK_ACTION_STOP, pcmk__str_none)) {
 466         // Call has no return value
 467         crm_debug("DBus request for stop of %s succeeded",
 468                   pcmk__s(op->rsc, "unknown resource"));
 469         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 470 
 471     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 472                                      __func__, __LINE__)) {
 473         crm_info("DBus request for %s of %s succeeded but "
 474                  "return type was unexpected", op->action,
 475                  pcmk__s(op->rsc, "unknown resource"));
 476         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 477 
 478     } else {
 479         const char *path = NULL;
 480 
 481         dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 482                               DBUS_TYPE_INVALID);
 483         crm_debug("DBus request for %s of %s using %s succeeded",
 484                   op->action, pcmk__s(op->rsc, "unknown resource"), path);
 485         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 486     }
 487 
 488     // The call is no longer pending
 489     CRM_LOG_ASSERT(pending == op->opaque->pending);
 490     services_set_op_pending(op, NULL);
 491 
 492     // Finalize action
 493     services__finalize_async_op(op);
 494     if (reply != NULL) {
 495         dbus_message_unref(reply);
 496     }
 497 }
 498 
 499 /*!
 500  * \internal
 501  * \brief Execute an Upstart action
 502  *
 503  * \param[in,out] op  Action to execute
 504  *
 505  * \return Standard Pacemaker return code
 506  * \retval EBUSY          Recurring operation could not be initiated
 507  * \retval pcmk_rc_error  Synchronous action failed
 508  * \retval pcmk_rc_ok     Synchronous action succeeded, or asynchronous action
 509  *                        should not be freed (because it's pending or because
 510  *                        it failed to execute and was already freed)
 511  *
 512  * \note If the return value for an asynchronous action is not pcmk_rc_ok, the
 513  *       caller is responsible for freeing the action.
 514  */
 515 int
 516 services__execute_upstart(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518     char *job = NULL;
 519     int arg_wait = TRUE;
 520     const char *arg_env = "pacemaker=1";
 521     const char *action = op->action;
 522 
 523     DBusError error;
 524     DBusMessage *msg = NULL;
 525     DBusMessage *reply = NULL;
 526     DBusMessageIter iter, array_iter;
 527 
 528     CRM_ASSERT(op != NULL);
 529 
 530     if ((op->action == NULL) || (op->agent == NULL)) {
 531         services__set_result(op, PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL,
 532                              "Bug in action caller");
 533         goto cleanup;
 534     }
 535 
 536     if (!upstart_init()) {
 537         services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 538                              "No DBus connection");
 539         goto cleanup;
 540     }
 541 
 542     if (pcmk__str_eq(op->action, PCMK_ACTION_META_DATA, pcmk__str_casei)) {
 543         op->stdout_data = upstart_job_metadata(op->agent);
 544         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 545         goto cleanup;
 546     }
 547 
 548     if (!object_path_for_job(op->agent, &job, op->timeout)) {
 549         if (pcmk__str_eq(action, PCMK_ACTION_STOP, pcmk__str_none)) {
 550             services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 551         } else {
 552             services__set_result(op, PCMK_OCF_NOT_INSTALLED,
 553                                  PCMK_EXEC_NOT_INSTALLED,
 554                                  "Upstart job not found");
 555         }
 556         goto cleanup;
 557     }
 558 
 559     if (job == NULL) {
 560         // Shouldn't normally be possible -- maybe a memory error
 561         op->rc = PCMK_OCF_UNKNOWN_ERROR;
 562         op->status = PCMK_EXEC_ERROR;
 563         goto cleanup;
 564     }
 565 
 566     if (pcmk__strcase_any_of(op->action, PCMK_ACTION_MONITOR,
 567                              PCMK_ACTION_STATUS, NULL)) {
 568         DBusPendingCall *pending = NULL;
 569         char *state = NULL;
 570         char *path = get_first_instance(job, op->timeout);
 571 
 572         services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE,
 573                              "No Upstart job instances found");
 574         if (path == NULL) {
 575             goto cleanup;
 576         }
 577         state = pcmk_dbus_get_property(upstart_proxy, BUS_NAME, path,
 578                                        UPSTART_06_API ".Instance", "state",
 579                                        op->synchronous? NULL : parse_status_result,
 580                                        op,
 581                                        op->synchronous? NULL : &pending,
 582                                        op->timeout);
 583         free(path);
 584 
 585         if (op->synchronous) {
 586             parse_status_result("state", state, op);
 587             free(state);
 588 
 589         } else if (pending == NULL) {
 590             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 591                                  "Could not get job state from DBus");
 592 
 593         } else { // Successfully initiated async op
 594             free(job);
 595             services_set_op_pending(op, pending);
 596             services_add_inflight_op(op);
 597             return pcmk_rc_ok;
 598         }
 599 
 600         goto cleanup;
 601 
 602     } else if (pcmk__str_eq(action, PCMK_ACTION_START, pcmk__str_none)) {
 603         action = "Start";
 604 
 605     } else if (pcmk__str_eq(action, PCMK_ACTION_STOP, pcmk__str_none)) {
 606         action = "Stop";
 607 
 608     } else if (pcmk__str_eq(action, "restart", pcmk__str_none)) {
 609         action = "Restart";
 610 
 611     } else {
 612         services__set_result(op, PCMK_OCF_UNIMPLEMENT_FEATURE,
 613                              PCMK_EXEC_ERROR_HARD,
 614                              "Action not implemented for Upstart resources");
 615         goto cleanup;
 616     }
 617 
 618     // Initialize rc/status in case called functions don't set them
 619     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_DONE,
 620                          "Bug in service library");
 621 
 622     crm_debug("Calling %s for %s on %s",
 623               action, pcmk__s(op->rsc, "unknown resource"), job);
 624 
 625     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 626                                        job, // object to call on
 627                                        UPSTART_JOB_IFACE, // interface to call on
 628                                        action); // method name
 629     CRM_ASSERT(msg != NULL);
 630 
 631     dbus_message_iter_init_append (msg, &iter);
 632     CRM_LOG_ASSERT(dbus_message_iter_open_container(&iter,
 633                                                     DBUS_TYPE_ARRAY,
 634                                                     DBUS_TYPE_STRING_AS_STRING,
 635                                                     &array_iter));
 636     CRM_LOG_ASSERT(dbus_message_iter_append_basic(&array_iter,
 637                                                   DBUS_TYPE_STRING, &arg_env));
 638     CRM_LOG_ASSERT(dbus_message_iter_close_container(&iter, &array_iter));
 639     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg_wait,
 640                                             DBUS_TYPE_INVALID));
 641 
 642     if (!(op->synchronous)) {
 643         DBusPendingCall *pending = pcmk_dbus_send(msg, upstart_proxy,
 644                                                   job_method_complete, op,
 645                                                   op->timeout);
 646 
 647         if (pending == NULL) {
 648             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 649                                  "Unable to send DBus message");
 650             goto cleanup;
 651 
 652         } else { // Successfully initiated async op
 653             free(job);
 654             services_set_op_pending(op, pending);
 655             services_add_inflight_op(op);
 656             return pcmk_rc_ok;
 657         }
 658     }
 659 
 660     // Synchronous call
 661 
 662     dbus_error_init(&error);
 663     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, op->timeout);
 664 
 665     if (dbus_error_is_set(&error)) {
 666         set_result_from_method_error(op, &error);
 667         dbus_error_free(&error);
 668 
 669     } else if (pcmk__str_eq(op->action, PCMK_ACTION_STOP, pcmk__str_none)) {
 670         // DBus call does not return a value
 671         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 672 
 673     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 674                                      __func__, __LINE__)) {
 675         crm_info("Call to %s passed but return type was unexpected",
 676                  op->action);
 677         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 678 
 679     } else {
 680         const char *path = NULL;
 681 
 682         dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 683                               DBUS_TYPE_INVALID);
 684         crm_debug("Call to %s passed: %s", op->action, path);
 685         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 686     }
 687 
 688 cleanup:
 689     free(job);
 690     if (msg != NULL) {
 691         dbus_message_unref(msg);
 692     }
 693     if (reply != NULL) {
 694         dbus_message_unref(reply);
 695     }
 696 
 697     if (op->synchronous) {
 698         return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
 699     } else {
 700         return services__finalize_async_op(op);
 701     }
 702 }

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