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

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