root/lrmd/remote_ctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. client_exit
  2. client_shutdown
  3. read_events
  4. timeout_err
  5. connection_events
  6. try_connect
  7. client_start
  8. ctl_remote_proxy_cb
  9. main

   1 /*
   2  * Copyright (c) 2015 David Vossel <davidvossel@gmail.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  * 
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  *
  18  */
  19 
  20 #include <crm_internal.h>
  21 
  22 #include <glib.h>
  23 #include <unistd.h>
  24 
  25 #include <crm/crm.h>
  26 #include <crm/msg_xml.h>
  27 #include <crm/services.h>
  28 #include <crm/common/mainloop.h>
  29 
  30 #include <crm/pengine/status.h>
  31 #include <crm/cib.h>
  32 #include <crm/lrmd.h>
  33 
  34 extern GHashTable *proxy_table;
  35 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
  36 
  37 /* *INDENT-OFF* */
  38 static struct crm_option long_options[] = {
  39     {"help",             0, 0, '?'},
  40     {"verbose",          0, 0, 'V', "\t\tPrint out logs and events to screen"},
  41     {"quiet",            0, 0, 'Q', "\t\tSuppress all output to screen"},
  42     {"tls",              1, 0, 'S', "\t\tSet tls host to contact"},
  43     {"tls-port",         1, 0, 'p', "\t\tUse custom tls port"},
  44     {"node",             1, 0, 'n', "\tNode name to use for ipc proxy"},
  45     {"api-call",         1, 0, 'c', "\tDirectly relates to lrmd api functions"},
  46     {"-spacer-",         1, 0, '-', "\nParameters for api-call option"},
  47     {"action",           1, 0, 'a'},
  48     {"rsc-id",           1, 0, 'r'},
  49     {"provider",         1, 0, 'P'},
  50     {"class",            1, 0, 'C'},
  51     {"type",             1, 0, 'T'},
  52     {"timeout",          1, 0, 't'},
  53     {"param-key",        1, 0, 'k'},
  54     {"param-val",        1, 0, 'v'},
  55     
  56     {"-spacer-",         1, 0, '-'},
  57     {0, 0, 0, 0}
  58 };
  59 /* *INDENT-ON* */
  60 
  61 static int wait_poke = 0;
  62 static int exec_call_id = 0;
  63 static gboolean client_start(gpointer user_data);
  64 static void try_connect(void);
  65 
  66 static struct {
  67     int verbose;
  68     int quiet;
  69     int print;
  70     int interval;
  71     int timeout;
  72     int port;
  73     const char *node_name;
  74     const char *api_call;
  75     const char *rsc_id;
  76     const char *provider;
  77     const char *class;
  78     const char *type;
  79     const char *action;
  80     const char *listen;
  81     const char *tls_host;
  82     lrmd_key_value_t *params;
  83 } options;
  84 
  85 GMainLoop *mainloop = NULL;
  86 lrmd_t *lrmd_conn = NULL;
  87 
  88 static void
  89 client_exit(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     lrmd_api_delete(lrmd_conn);
  92     if (proxy_table) {
  93         g_hash_table_destroy(proxy_table); proxy_table = NULL;
  94     }
  95     exit(rc);
  96 }
  97 
  98 static void
  99 client_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101     lrmd_api_delete(lrmd_conn);
 102     lrmd_conn = NULL;
 103 }
 104 
 105 static void
 106 read_events(lrmd_event_data_t * event)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108     if (wait_poke && event->type == lrmd_event_poke) {
 109         client_exit(PCMK_OCF_OK);
 110     }
 111     if ((event->call_id == exec_call_id) && (event->type == lrmd_event_exec_complete)) {
 112         if (event->output) {
 113             crm_info("%s", event->output);
 114         }
 115         if (event->exit_reason) {
 116             fprintf(stderr, "%s%s\n", PCMK_OCF_REASON_PREFIX, event->exit_reason);
 117         }
 118         client_exit(event->rc);
 119     }
 120 }
 121 
 122 static gboolean
 123 timeout_err(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     crm_err("timed out in remote_client");
 126     client_exit(PCMK_OCF_TIMEOUT);
 127 
 128     return FALSE;
 129 }
 130 
 131 static void
 132 connection_events(lrmd_event_data_t * event)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     int rc = event->connection_rc;
 135 
 136     if (event->type != lrmd_event_connect) {
 137         /* ignore */
 138         return;
 139     }
 140 
 141     if (!rc) {
 142         client_start(NULL);
 143         return;
 144     } else {
 145         sleep(1);
 146         try_connect();
 147     }
 148 }
 149 
 150 static void
 151 try_connect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153     int tries = 10;
 154     static int num_tries = 0;
 155     int rc = 0;
 156 
 157     lrmd_conn->cmds->set_callback(lrmd_conn, connection_events);
 158     for (; num_tries < tries; num_tries++) {
 159         rc = lrmd_conn->cmds->connect_async(lrmd_conn, "lrmd", 10000);
 160 
 161         if (!rc) {
 162             num_tries++;
 163             return;             /* we'll hear back in async callback */
 164         }
 165         sleep(1);
 166     }
 167 
 168     crm_err("Failed to connect to pacemaker remote.");
 169     client_exit(PCMK_OCF_UNKNOWN_ERROR);
 170 }
 171 
 172 static gboolean
 173 client_start(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175     int rc = 0;
 176 
 177     if (!lrmd_conn->cmds->is_connected(lrmd_conn)) {
 178         try_connect();
 179         /* async connect -- this function will get called back into */
 180         return 0;
 181     }
 182 
 183     lrmd_conn->cmds->set_callback(lrmd_conn, read_events);
 184 
 185 
 186     if (safe_str_eq(options.api_call, "ipc_debug")) {
 187         /* Do nothing, leave connection up just for debugging ipc proxy */
 188         return 0;
 189     }
 190     if (options.timeout) {
 191         g_timeout_add(options.timeout, timeout_err, NULL);
 192     }
 193 
 194     if (safe_str_eq(options.api_call, "metadata")) {
 195         char *output = NULL;
 196 
 197         /* This is broken when the agent is installed only in the
 198          * remote environment and not on the cluster node handling the proxy.
 199          */
 200         rc = lrmd_conn->cmds->get_metadata(lrmd_conn,
 201                                            options.class,
 202                                            options.provider, options.type, &output, 0);
 203         if (rc == pcmk_ok) {
 204             printf("%s", output);
 205             free(output);
 206             client_exit(PCMK_OCF_OK);
 207         }
 208         client_exit(PCMK_OCF_UNKNOWN_ERROR);
 209 
 210     } else if (safe_str_eq(options.api_call, "poke")) {
 211         rc = lrmd_conn->cmds->poke_connection(lrmd_conn);
 212         if (rc != pcmk_ok) {
 213             client_exit(PCMK_OCF_UNKNOWN_ERROR);
 214         }
 215         wait_poke = 1;
 216 
 217     } else {
 218         lrmd_rsc_info_t *rsc_info = NULL;
 219 
 220         rsc_info = lrmd_conn->cmds->get_rsc_info(lrmd_conn, options.rsc_id, 0);
 221         if (rsc_info == NULL) {
 222             rc = lrmd_conn->cmds->register_rsc(lrmd_conn, options.rsc_id,
 223                                                options.class, options.provider, options.type, 0);
 224 
 225             if (rc != 0){
 226                 crm_err("failed to register resource %s with pacemaker_remote. rc: %d", options.rsc_id, rc);
 227                 client_exit(1);
 228             }
 229         }
 230         lrmd_free_rsc_info(rsc_info);
 231 
 232         rc = lrmd_conn->cmds->exec(lrmd_conn,
 233                                    options.rsc_id,
 234                                    options.action,
 235                                    NULL,
 236                                    options.interval,
 237                                    options.timeout,
 238                                    0, 0, options.params);
 239 
 240         if (rc > 0) {
 241             exec_call_id = rc;
 242         } else {
 243             crm_err("execution of rsc %s failed. rc = %d", options.rsc_id, rc);
 244             client_exit(PCMK_OCF_UNKNOWN_ERROR);
 245         }
 246     }
 247 
 248     return 0;
 249 }
 250 
 251 static void
 252 ctl_remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254     const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
 255     const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
 256 
 257     if (safe_str_eq(op, LRMD_IPC_OP_NEW)) {
 258         const char *channel = crm_element_value(msg, F_LRMD_IPC_IPC_SERVER);
 259 
 260         static struct ipc_client_callbacks proxy_callbacks = {
 261             .dispatch = remote_proxy_dispatch,
 262             .destroy = remote_proxy_disconnected
 263         };
 264 
 265         remote_proxy_new(lrmd, &proxy_callbacks, options.node_name, session, channel);
 266 
 267     } else {
 268         remote_proxy_cb(lrmd, options.node_name, msg);
 269     }
 270 }
 271 
 272 int
 273 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275     int option_index = 0;
 276     int argerr = 0;
 277     int flag;
 278     char *key = NULL;
 279     char *val = NULL;
 280     gboolean use_tls = FALSE;
 281     crm_trigger_t *trig;
 282 
 283     crm_set_options(NULL, "mode [options]", long_options,
 284                     "Inject commands into the lrmd and watch for events\n");
 285 
 286     while (1) {
 287         flag = crm_get_option(argc, argv, &option_index);
 288         if (flag == -1)
 289             break;
 290 
 291         switch (flag) {
 292             case '?':
 293                 crm_help(flag, EX_OK);
 294                 break;
 295             case 'V':
 296                 options.verbose = 1;
 297                 break;
 298             case 'Q':
 299                 options.quiet = 1;
 300                 options.verbose = 0;
 301                 break;
 302             case 'n':
 303                 options.node_name = optarg;
 304                 break;
 305             case 'c':
 306                 options.api_call = optarg;
 307                 break;
 308             case 'a':
 309                 options.action = optarg;
 310                 break;
 311             case 'r':
 312                 options.rsc_id = optarg;
 313                 break;
 314             case 'P':
 315                 options.provider = optarg;
 316                 break;
 317             case 'C':
 318                 options.class = optarg;
 319                 break;
 320             case 'T':
 321                 options.type = optarg;
 322                 break;
 323             case 't':
 324                 if(optarg) {
 325                     options.timeout = atoi(optarg);
 326                 }
 327                 break;
 328             case 'k':
 329                 key = optarg;
 330                 if (key && val) {
 331                     options.params = lrmd_key_value_add(options.params, key, val);
 332                     key = val = NULL;
 333                 }
 334                 break;
 335             case 'v':
 336                 val = optarg;
 337                 if (key && val) {
 338                     options.params = lrmd_key_value_add(options.params, key, val);
 339                     key = val = NULL;
 340                 }
 341                 break;
 342             case 'S':
 343                 options.tls_host = optarg;
 344                 use_tls = TRUE;
 345                 break;
 346             case 'p':
 347                 if(optarg) {
 348                     options.port = atoi(optarg);
 349                 }
 350                 use_tls = TRUE;
 351                 break;
 352             default:
 353                 ++argerr;
 354                 break;
 355         }
 356     }
 357 
 358     if (argerr) {
 359         crm_help('?', EX_USAGE);
 360     }
 361     if (optind > argc) {
 362         ++argerr;
 363     }
 364     crm_log_init("remote_client", LOG_INFO, FALSE, options.verbose ? TRUE : FALSE, argc, argv, FALSE);
 365 
 366     /* if we can't perform an api_call or listen for events, 
 367      * there is nothing to do */
 368     if (!options.api_call ) {
 369         crm_err("Nothing to be done.  Please specify 'api-call'");
 370         return PCMK_OCF_UNKNOWN_ERROR;
 371     }
 372 
 373     if (!options.timeout ) {
 374         options.timeout = 20000;
 375     }
 376 
 377     if (use_tls) {
 378         if (options.node_name == NULL) {
 379             crm_err("\"node\" option required when tls is in use.");
 380             return PCMK_OCF_UNKNOWN_ERROR;
 381         }
 382         proxy_table =
 383             g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, NULL, remote_proxy_free);
 384         lrmd_conn = lrmd_remote_api_new(NULL, options.tls_host ? options.tls_host : "localhost", options.port);
 385         lrmd_internal_set_proxy_callback(lrmd_conn, NULL,  ctl_remote_proxy_cb);
 386     } else {
 387         lrmd_conn = lrmd_api_new();
 388     }
 389     trig = mainloop_add_trigger(G_PRIORITY_HIGH, client_start, NULL);
 390     mainloop_set_trigger(trig);
 391     mainloop_add_signal(SIGTERM, client_shutdown);
 392 
 393     mainloop = g_main_new(FALSE);
 394     g_main_run(mainloop);
 395 
 396     client_exit(0);
 397     return 0;
 398 }

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