/*------------------------------------------------------------------------- * * gtm_cmd.c * * GTM command module of Postgres-XC configuration and operation tool. * * Copyright (c) 2013 Postgres-XC Development Group * *------------------------------------------------------------------------- */ /* * This module provides various gtm-related pgxc_operation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "pgxc_ctl.h" #include "do_command.h" #include "variables.h" #include "varnames.h" #include "pgxc_ctl_log.h" #include "config.h" #include "do_shell.h" #include "utils.h" #include "gtm_cmd.h" #include "monitor.h" static char date[MAXTOKEN + 1]; /* ====================================================================================== * * GTM Staff * * ======================================================================================= */ /* * Init gtm master ----------------------------------------------------------------- */ cmd_t* prepare_initGtmMaster(void) { cmd_t *cmdInitGtmMaster, *cmdGtmConf, *cmdGxid; char date[MAXTOKEN + 1]; FILE* f = NULL; char** fileList = NULL; /* Kill current gtm, bild work directory and run initgtm */ cmdInitGtmMaster = initCmd(sval(VAR_gtmMasterServer)); snprintf(newCommand(cmdInitGtmMaster), MAXLINE, "killall -u %s -9 gs_gtm; rm -rf %s; mkdir -p %s;gs_initgtm -Z gtm -D %s", sval(VAR_pgxcUser), sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir)); /* Then prepare gtm.conf file */ /* Prepare local Stdin */ appendCmdEl(cmdInitGtmMaster, (cmdGtmConf = initCmd(sval(VAR_gtmMasterServer)))); if ((f = prepareLocalStdin(newFilename(cmdGtmConf->localStdin), MAXPATH, NULL)) == NULL) { cleanCmd(cmdInitGtmMaster); return (NULL); } fprintf(f, "#===============================================\n" "# Added at initialization, %s\n" "listen_addresses = '*'\n", timeStampString(date, MAXTOKEN)); if (!is_none(sval(VAR_gtmExtraConfig))) AddMember(fileList, sval(VAR_gtmExtraConfig)); if (!is_none(sval(VAR_gtmMasterSpecificExtraConfig))) AddMember(fileList, sval(VAR_gtmMasterSpecificExtraConfig)); appendFiles(f, fileList); CleanArray(fileList); fprintf(f, "port = %s\n" "nodename = '%s'\n" "startup = ACT\n" "# End of addition\n", sval(VAR_gtmMasterPort), sval(VAR_gtmName)); fclose(f); /* other options */ snprintf(newCommand(cmdGtmConf), MAXLINE, "cat >> %s/gtm.conf", sval(VAR_gtmMasterDir)); /* Setup GTM with appropriate GXID value */ appendCmdEl(cmdGtmConf, (cmdGxid = initCmd(sval(VAR_gtmMasterServer)))); snprintf(newCommand(cmdGxid), MAXLINE, "(gs_gtm -x 2000 -D %s &); sleep 1; gtm_ctl stop -Z gtm -D %s", sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir)); return cmdInitGtmMaster; } int init_gtm_master(void) { int rc; cmdList_t* cmdList = NULL; elog(INFO, "Initialize GTM master\n"); cmdList = initCmdList(); /* Kill current gtm, build work directory and run initgtm */ addCmd(cmdList, prepare_initGtmMaster()); rc = doCmdList(cmdList); cleanCmdList(cmdList); elog(INFO, "Done.\n"); return (rc); } /* * Add gtm slave: to be used after all the configuration is done. * * This function only maintains internal configuration, updte configuration file, * and make backup if configured. You should run init_gtm_slave and stat_gtm_slave * separately. */ int add_gtmSlave(char* name, char* host, int port, char* dir) { char port_s[MAXTOKEN + 1]; char date[MAXTOKEN + 1]; FILE* f = NULL; int rc; if (isVarYes(VAR_gtmSlave)) { elog(ERROR, "ERROR: GTM slave is already configured.\n"); return 1; } if (is_none(host)) { elog(ERROR, "ERROR: Cannot add gtm slave with the name \"none\".\n"); return 1; } if (is_none(dir)) { elog(ERROR, "ERROR: Cannot add gtm slave with the directory \"none\".\n"); return 1; } if (checkSpecificResourceConflict(name, host, port, dir, TRUE)) { elog(ERROR, "ERROR: New specified name:%s, host:%s, port:%d and dir:\"%s\" conflicts with existing node.\n", name, host, port, dir); return 1; } assign_sval(VAR_gtmSlave, Strdup("y")); assign_sval(VAR_gtmSlaveServer, Strdup(host)); snprintf(port_s, MAXTOKEN, "%d", port); assign_sval(VAR_gtmSlavePort, Strdup(port_s)); assign_sval(VAR_gtmSlaveDir, Strdup(dir)); makeServerList(); if ((f = fopen(pgxc_ctl_config_path, "a")) == NULL) { /* Should it be panic? */ elog(ERROR, "ERROR: cannot open configuration file \"%s\", %s\n", pgxc_ctl_config_path, strerror(errno)); return 1; } fprintf(f, "#===================================================\n" "# pgxc configuration file updated due to GTM slave addition\n" "# %s\n", timeStampString(date, MAXTOKEN + 1)); fprintSval(f, VAR_gtmSlave); fprintSval(f, VAR_gtmSlaveServer); fprintSval(f, VAR_gtmSlavePort); fprintSval(f, VAR_gtmSlaveDir); fprintf(f, "%s", "#----End of reconfiguration -------------------------\n"); fclose(f); backup_configuration(); if ((rc = init_gtm_slave()) != 0) return rc; return (start_gtm_slave()); } int remove_gtmSlave(bool clean_opt) { FILE* f = NULL; /* Check if gtm_slave is configured */ if (!isVarYes(VAR_gtmSlave) || !sval(VAR_gtmSlaveServer) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured.\n"); return 1; } /* Check if gtm_slave is not running */ if (!do_gtm_ping(sval(VAR_gtmSlaveServer), atoi(sval(VAR_gtmSlavePort)))) { elog(ERROR, "ERROR: GTM slave is now running. Cannot remove it.\n"); return 1; } elog(NOTICE, "Removing gtm slave.\n"); /* Clean */ if (clean_opt) clean_gtm_slave(); /* Reconfigure */ reset_var(VAR_gtmSlave); assign_sval(VAR_gtmSlave, Strdup("n")); reset_var(VAR_gtmSlaveServer); assign_sval(VAR_gtmSlaveServer, Strdup("none")); reset_var(VAR_gtmSlavePort); assign_sval(VAR_gtmSlavePort, Strdup("-1")); reset_var(VAR_gtmSlaveDir); assign_sval(VAR_gtmSlaveDir, Strdup("none")); /* Write the configuration file and bakup it */ if ((f = fopen(pgxc_ctl_config_path, "a")) == NULL) { /* Should it be panic? */ elog(ERROR, "ERROR: cannot open configuration file \"%s\", %s\n", pgxc_ctl_config_path, strerror(errno)); return 1; } fprintf(f, "#===================================================\n" "# pgxc configuration file updated due to GTM slave removal\n" "# %s\n", timeStampString(date, MAXTOKEN + 1)); fprintSval(f, VAR_gtmSlave); fprintSval(f, VAR_gtmSlaveServer); fprintSval(f, VAR_gtmSlavePort); fprintSval(f, VAR_gtmSlaveDir); fprintf(f, "%s", "#----End of reconfiguration -------------------------\n"); fclose(f); backup_configuration(); elog(NOTICE, "Done.\n"); return 0; } /* * Init gtm slave ------------------------------------------------------------- */ /* * Assumes Gtm Slave is configured. * Caller should check this. */ cmd_t* prepare_initGtmSlave(void) { char date[MAXTOKEN + 1]; cmd_t *cmdInitGtm, *cmdGtmConf; FILE* f = NULL; char** fileList = NULL; if (!isVarYes(VAR_gtmSlave) || (sval(VAR_gtmSlaveServer) == NULL) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured.\n"); return (NULL); } /* Kill current gtm, build work directory and run initgtm */ cmdInitGtm = initCmd(sval(VAR_gtmSlaveServer)); snprintf(newCommand(cmdInitGtm), MAXLINE, "killall -u %s -9 gs_gtm; rm -rf %s; mkdir -p %s; gs_initgtm -Z gtm -D %s", sval(VAR_pgxcUser), sval(VAR_gtmSlaveDir), sval(VAR_gtmSlaveDir), sval(VAR_gtmSlaveDir)); /* Prepare gtm.conf file */ /* Prepare local Stdin */ appendCmdEl(cmdInitGtm, (cmdGtmConf = initCmd(sval(VAR_gtmSlaveServer)))); snprintf(newCommand(cmdGtmConf), MAXLINE, "cat >> %s/gtm.conf", sval(VAR_gtmSlaveDir)); if ((f = prepareLocalStdin(newFilename(cmdGtmConf->localStdin), MAXPATH, NULL)) == NULL) { cleanCmd(cmdInitGtm); return (NULL); } fprintf(f, "#===============================================\n" "# Added at initialization, %s\n" "listen_addresses = '*'\n", timeStampString(date, MAXPATH + 1)); if (!is_none(sval(VAR_gtmExtraConfig))) AddMember(fileList, sval(VAR_gtmExtraConfig)); if (!is_none(sval(VAR_gtmMasterSpecificExtraConfig))) AddMember(fileList, sval(VAR_gtmMasterSpecificExtraConfig)); appendFiles(f, fileList); CleanArray(fileList); fprintf(f, "port = %s\n" "nodename = '%s'\n" "startup = STANDBY\n" "active_host = '%s'\n" "active_port = %d\n" "# End of addition\n", sval(VAR_gtmSlavePort), sval(VAR_gtmName), sval(VAR_gtmMasterServer), atoi(sval(VAR_gtmMasterPort))); fclose(f); return (cmdInitGtm); } int init_gtm_slave(void) { cmdList_t* cmdList = NULL; cmd_t* cmdInitGtm = NULL; int rc; elog(INFO, "Initialize GTM slave\n"); cmdList = initCmdList(); if ((cmdInitGtm = prepare_initGtmSlave())) { addCmd(cmdList, cmdInitGtm); /* Do all the commands and clean */ rc = doCmdList(cmdList); cleanCmdList(cmdList); elog(INFO, "Done.\n"); return (rc); } return 1; } /* * Start gtm master ----------------------------------------------------- */ cmd_t* prepare_startGtmMaster(void) { cmd_t* cmdGtmCtl = NULL; cmdGtmCtl = initCmd(sval(VAR_gtmMasterServer)); snprintf(newCommand(cmdGtmCtl), MAXLINE, "gtm_ctl stop -Z gtm -D %s;" "rm -f %s/register.node;" "gtm_ctl start -Z gtm -D %s", sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir)); return cmdGtmCtl; } int start_gtm_master(void) { cmdList_t* cmdList = NULL; int rc; elog(INFO, "Start GTM master\n"); cmdList = initCmdList(); addCmd(cmdList, prepare_startGtmMaster()); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } /* * Start gtm slave ---------------------------------------------------- */ cmd_t* prepare_startGtmSlave(void) { cmd_t* cmdGtmCtl = NULL; if (!isVarYes(VAR_gtmSlave) || (sval(VAR_gtmSlaveServer) == NULL) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured.\n"); return (NULL); } cmdGtmCtl = initCmd(sval(VAR_gtmSlaveServer)); snprintf(newCommand(cmdGtmCtl), MAXLINE, "gtm_ctl stop -Z gtm -D %s;" "rm -rf %s/register.node;" "gtm_ctl start -Z gtm -D %s", sval(VAR_gtmSlaveDir), sval(VAR_gtmSlaveDir), sval(VAR_gtmSlaveDir)); return (cmdGtmCtl); } int start_gtm_slave(void) { cmdList_t* cmdList = NULL; cmd_t* cmd = NULL; int rc; elog(INFO, "Start GTM slave"); cmdList = initCmdList(); if ((cmd = prepare_startGtmSlave())) { addCmd(cmdList, cmd); rc = doCmdList(cmdList); cleanCmdList(cmdList); elog(INFO, "Done.\n"); return (rc); } return 1; } /* * Stop gtm master --------------------------------------------------------- */ cmd_t* prepare_stopGtmMaster(void) { cmd_t* cmdGtmCtl = NULL; cmdGtmCtl = initCmd(sval(VAR_gtmMasterServer)); snprintf(newCommand(cmdGtmCtl), MAXLINE, "gtm_ctl stop -Z gtm -D %s", sval(VAR_gtmMasterDir)); return (cmdGtmCtl); } int stop_gtm_master(void) { cmdList_t* cmdList = NULL; int rc; elog(INFO, "Stop GTM master\n"); cmdList = initCmdList(); addCmd(cmdList, prepare_stopGtmMaster()); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } /* * Stop gtm slave --------------------------------------------------------------- */ cmd_t* prepare_stopGtmSlave(void) { cmd_t* cmdGtmCtl = NULL; if (!isVarYes(VAR_gtmSlave) || (sval(VAR_gtmSlaveServer) == NULL) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured.\n"); return (NULL); } cmdGtmCtl = initCmd(sval(VAR_gtmSlaveServer)); snprintf(newCommand(cmdGtmCtl), MAXLINE, "gtm_ctl stop -Z gtm -D %s", sval(VAR_gtmSlaveDir)); return (cmdGtmCtl); } int stop_gtm_slave(void) { cmdList_t* cmdList = NULL; cmd_t* cmd = NULL; int rc; elog(INFO, "Stop GTM slave\n"); cmdList = initCmdList(); if ((cmd = prepare_stopGtmSlave())) { addCmd(cmdList, cmd); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } return 1; } /* * Kill gtm master ----------------------------------------------------- * * You should not kill gtm master in this way. This may discard the latest * gtm status. This is just in case. You must try to stop gtm master * gracefully. */ cmd_t* prepare_killGtmMaster(void) { cmd_t* cmdKill = NULL; pid_t gtmPid; cmdKill = initCmd(sval(VAR_gtmMasterServer)); gtmPid = get_gtm_pid(sval(VAR_gtmMasterServer), sval(VAR_gtmMasterDir)); if (gtmPid > 0) snprintf(newCommand(cmdKill), MAXLINE, "kill -9 %d; rm -rf /tmp/.s.'*'%d'*' %s/gtm.pid", gtmPid, atoi(sval(VAR_gtmMasterPort)), sval(VAR_gtmMasterDir)); else snprintf(newCommand(cmdKill), MAXLINE, "killall -u %s -9 gs_gtm; rm -rf /tmp/.s.'*'%d'*' %s/gtm.pid", sval(VAR_pgxcUser), atoi(sval(VAR_gtmMasterPort)), sval(VAR_gtmMasterDir)); return (cmdKill); } int kill_gtm_master(void) { cmdList_t* cmdList = NULL; cmd_t* cmd_killGtmMaster = NULL; int rc; elog(INFO, "Kill GTM master\n"); cmdList = initCmdList(); if ((cmd_killGtmMaster = prepare_killGtmMaster())) { addCmd(cmdList, cmd_killGtmMaster); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } return 1; } /* * Kill gtm slave -------------------------------------------------------- * * GTM slave has no significant informaion to carry over. But it is a good * habit to stop gtm slave gracefully with stop command. */ cmd_t* prepare_killGtmSlave(void) { cmd_t* cmdKill = NULL; pid_t gtmPid; if (!isVarYes(VAR_gtmSlave) || (sval(VAR_gtmSlaveServer) == NULL) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured.\n"); return (NULL); } cmdKill = initCmd(sval(VAR_gtmSlaveServer)); gtmPid = get_gtm_pid(sval(VAR_gtmSlaveServer), sval(VAR_gtmSlaveDir)); if (gtmPid > 0) snprintf(newCommand(cmdKill), MAXLINE, "kill -9 %d; rm -rf /tmp/.s.'*'%d'*' %s/gtm.pid", gtmPid, atoi(sval(VAR_gtmSlavePort)), sval(VAR_gtmSlaveDir)); else snprintf(newCommand(cmdKill), MAXLINE, "killall -u %s -9 gs_gtm; rm -rf /tmp/.s.'*'%d'*' %s/gtm.pid", sval(VAR_pgxcUser), atoi(sval(VAR_gtmSlavePort)), sval(VAR_gtmSlaveDir)); return (cmdKill); } int kill_gtm_slave(void) { cmdList_t* cmdList = NULL; cmd_t* cmdKill = NULL; int rc; elog(INFO, "Kill GTM slave\n"); cmdList = initCmdList(); if ((cmdKill = prepare_killGtmSlave())) { addCmd(cmdList, cmdKill); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } else return 1; } /* * Failover the gtm ------------------------------------------------------ */ int failover_gtm(void) { char date[MAXTOKEN + 1]; char* stdIn = NULL; int rc; FILE* f = NULL; elog(INFO, "Failover gtm\n"); if (!isVarYes(VAR_gtmSlave) || (sval(VAR_gtmSlaveServer) == NULL) || is_none(sval(VAR_gtmSlaveServer))) { elog(ERROR, "ERROR: GTM slave is not configured. Cannot failover.\n"); return (1); } if (do_gtm_ping(sval(VAR_gtmSlaveServer), atoi(sval(VAR_gtmSlavePort))) != 0) { elog(ERROR, "ERROR: GTM slave is not running\n"); return (1); } /* Promote the slave */ elog(NOTICE, "Running \"gtm_ctl promote -Z gtm -D %s\"\n", sval(VAR_gtmSlaveDir)); rc = doImmediate(sval(VAR_gtmSlaveServer), NULL, "gtm_ctl promote -Z gtm -D %s", sval(VAR_gtmSlaveDir)); if (WEXITSTATUS(rc) != 0) { elog( ERROR, "ERROR: could not promote gtm (host:%s, dir:%s)\n", sval(VAR_gtmSlaveServer), sval(VAR_gtmSlaveDir)); return 1; } /* Configure promoted gtm */ if ((f = prepareLocalStdin(newFilename(stdIn), MAXPATH, NULL)) == NULL) return (1); fprintf(f, "#===================================================\n" "# Updated due to GTM failover\n" "# %s\n" "startup = ACT\n" "#----End of reconfiguration -------------------------\n", timeStampString(date, MAXTOKEN + 1)); fclose(f); elog(NOTICE, "Updating gtm.conf at %s:%s\n", sval(VAR_gtmSlaveServer), sval(VAR_gtmSlaveDir)); rc = doImmediate(sval(VAR_gtmSlaveServer), stdIn, "cat >> %s/gtm.conf", sval(VAR_gtmSlaveDir)); if (WEXITSTATUS(rc) != 0) { elog(ERROR, "ERROR: could not update gtm.conf (host: %s, dir:%s)\n", sval(VAR_gtmSlaveServer), sval(VAR_gtmSlaveDir)); return 1; } /* Update and backup configuration file */ if ((f = prepareLocalStdin(stdIn, MAXPATH, NULL)) == NULL) return (1); fprintf(f, "#===================================================\n" "# pgxc configuration file updated due to GTM failover\n" "# %s\n" "gtmMasterServer=%s\n" "gtmMasterPort=%s\n" "gtmMasterDir=%s\n" "gtmSlave=n\n" "gtmSlaveServer=none\n" "gtmSlavePort=0\n" "gtmSlaveDir=none\n" "#----End of reconfiguration -------------------------\n", timeStampString(date, MAXTOKEN + 1), sval(VAR_gtmSlaveServer), sval(VAR_gtmSlavePort), sval(VAR_gtmSlaveDir)); fclose(f); rc = doImmediate(NULL, stdIn, "cat >> %s", pgxc_ctl_config_path); if (WEXITSTATUS(rc) != 0) { elog(ERROR, "ERROR: could not update gtm.conf (host: %s, dir:%s)\n", sval(VAR_gtmSlaveServer), sval(VAR_gtmSlaveDir)); return 1; } freeAndReset(stdIn); backup_configuration(); /* Reconfigure myself */ assign_val(VAR_gtmMasterServer, VAR_gtmSlaveServer); reset_var(VAR_gtmSlaveServer); assign_val(VAR_gtmMasterPort, VAR_gtmSlavePort); reset_var(VAR_gtmSlavePort); assign_val(VAR_gtmMasterDir, VAR_gtmSlaveDir); reset_var(VAR_gtmSlaveDir); assign_sval(VAR_gtmSlaveServer, "none"); assign_sval(VAR_gtmSlavePort, "0"); assign_sval(VAR_gtmSlaveDir, "none"); assign_sval(VAR_gtmSlave, "n"); return 0; } /* * Clean gtm master resources -- directory and socket -------------------------- */ cmd_t* prepare_cleanGtmMaster(void) { cmd_t* cmd = NULL; /* Remote work dir and clean the socket */ cmd = initCmd(sval(VAR_gtmMasterServer)); snprintf(newCommand(cmd), MAXLINE, "rm -rf %s; mkdir -p %s; chmod 0700 %s;rm -f /tmp/.s.*%d*", sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir), sval(VAR_gtmMasterDir), atoi(VAR_gtmMasterPort)); return cmd; } int clean_gtm_master(void) { cmdList_t* cmdList = NULL; int rc; elog(INFO, "Clearing gtm master directory and socket.\n"); cmdList = initCmdList(); addCmd(cmdList, prepare_cleanGtmMaster()); rc = doCmdList(cmdList); cleanCmdList(cmdList); return (rc); } /* * Clean gtm master resources -- direcotry and socket -------------------------- */ /* * Null will be retruend if gtm slave is not configured. * Be careful. If you configure gtm slave and gtm master on a same server, * bott slave amd master process will be killed. */ cmd_t* prepare_cleanGtmSlave(void) { cmd_t* cmd = NULL; if (!isVarYes(VAR_gtmSlave) || is_none(VAR_gtmSlaveServer)) return (NULL); cmd = initCmd(sval(VAR_gtmSlaveServer)); snprintf(newCommand(cmd), MAXLINE, "rm -rf %s; mkdir -p %s; chmod 0700 %s;rm -f /tmp/.s.*%d*", sval(VAR_gtmSlaveDir), sval(VAR_gtmSlaveDir), sval(VAR_gtmMasterDir), atoi(VAR_gtmSlavePort)); return cmd; } int clean_gtm_slave(void) { cmdList_t* cmdList = NULL; int rc; elog(NOTICE, "Clearing gtm slave resources.\n"); if (!isVarYes(VAR_gtmSlave) || is_none(VAR_gtmSlaveServer)) { elog(ERROR, "ERROR: gtm slave is not configured.\n"); return 1; } cmdList = initCmdList(); addCmd(cmdList, prepare_cleanGtmSlave()); rc = doCmdList(cmdList); cleanCmdList(cmdList); elog(NOTICE, "Done.\n"); return (rc); } /* * ================================================================================== * * Gtm Proxy Staff * * ================================================================================== */ /* * Add gtm proxy: to be used after all the configuration is done. * * This function only maintains internal configuration, updte configuration file, * and make backup if configured. You should run init and start it separately. */ int add_gtmProxy(char* name, char* host, int port, char* dir) { char port_s[MAXTOKEN + 1]; char date[MAXTOKEN + 1]; FILE* f = NULL; char** nodelist = NULL; int rc; if (is_none(host)) { elog(ERROR, "ERROR: Cannot add gtm proxy with the name \"none\".\n"); return 1; } if (is_none(dir)) { elog(ERROR, "ERROR: Cannot add gtm proxy with the directory \"none\".\n"); return 1; } if (checkSpecificResourceConflict(name, host, port, dir, TRUE)) { elog(ERROR, "ERROR: New specified name:%s, host:%s, port:%d and dir:\"%s\" conflicts with existing node.\n", name, host, port, dir); return 1; } if (!isVarYes(VAR_gtmProxy)) { assign_sval(VAR_gtmProxy, Strdup("y")); reset_var(VAR_gtmProxyNames); } add_val(find_var(VAR_gtmProxyNames), Strdup(name)); add_val(find_var(VAR_gtmProxyServers), Strdup(host)); snprintf(port_s, MAXTOKEN, "%d", port); add_val(find_var(VAR_gtmProxyPorts), Strdup(port_s)); add_val(find_var(VAR_gtmProxyDirs), Strdup(dir)); add_val(find_var(VAR_gtmPxySpecificExtraConfig), Strdup("none")); makeServerList(); if ((f = fopen(pgxc_ctl_config_path, "a")) == NULL) { /* Should it be panic? */ elog(ERROR, "ERROR: cannot open configuration file \"%s\", %s\n", pgxc_ctl_config_path, strerror(errno)); return 1; } fprintf(f, "#===================================================\n" "# pgxc configuration file updated due to GTM proxy (%s) addition\n" "# %s\n", name, timeStampString(date, MAXTOKEN + 1)); fprintSval(f, VAR_gtmProxy); fprintAval(f, VAR_gtmProxyNames); fprintAval(f, VAR_gtmProxyServers); fprintAval(f, VAR_gtmProxyPorts); fprintAval(f, VAR_gtmProxyDirs); fprintAval(f, VAR_gtmPxySpecificExtraConfig); fprintf(f, "%s", "#----End of reconfiguration -------------------------\n"); fclose(f); AddMember(nodelist, name); init_gtm_proxy(nodelist); rc = start_gtm_proxy(nodelist); CleanArray(nodelist); return rc; } int remove_gtmProxy(char* name, bool clean_opt) { FILE* f = NULL; int idx; /* Check if gtm proxy exists */ if ((idx = gtmProxyIdx(name)) < 0) { elog(ERROR, "ERROR: %s is not a gtm proxy.\n", name); return 1; } /* Check if it is in use */ if (ifExists(VAR_coordMasterServers, aval(VAR_gtmProxyServers)[idx]) || ifExists(VAR_coordSlaveServers, aval(VAR_gtmProxyServers)[idx]) || ifExists(VAR_datanodeMasterServers, aval(VAR_gtmProxyServers)[idx]) || ifExists(VAR_datanodeSlaveServers, aval(VAR_gtmProxyServers)[idx])) { elog(ERROR, "ERROR: GTM Proxy %s is in use\n", name); return 1; } elog(NOTICE, "NOTICE: removing gtm_proxy %s\n", name); /* Clean */ if (clean_opt) { char** nodelist = NULL; elog(NOTICE, "NOTICE: cleaning target resources.\n"); AddMember(nodelist, name); clean_gtm_proxy(nodelist); CleanArray(nodelist); } /* Reconfigure */ var_assign(&aval(VAR_gtmProxyNames)[idx], Strdup("none")); var_assign(&aval(VAR_gtmProxyServers)[idx], Strdup("none")); var_assign(&aval(VAR_gtmProxyPorts)[idx], Strdup("-1")); var_assign(&aval(VAR_gtmProxyDirs)[idx], Strdup("none")); handle_no_slaves(); makeServerList(); /* Update configuration file and backup it */ if ((f = fopen(pgxc_ctl_config_path, "a")) == NULL) { /* Should it be panic? */ elog(ERROR, "ERROR: cannot open configuration file \"%s\", %s\n", pgxc_ctl_config_path, strerror(errno)); return 1; } fprintf(f, "#===================================================\n" "# pgxc configuration file updated due to GTM proxy addition\n" "# %s\n" "%s=%s\n" /* gtmProxy */ "%s=( %s )\n" /* gtmProxyNames */ "%s=( %s )\n" /* gtmProxyServers */ "%s=( %s )\n" /* gtmProxyPorts */ "%s=( %s )\n" /* gtmProxyDirs */ "#----End of reconfiguration -------------------------\n", timeStampString(date, MAXTOKEN + 1), VAR_gtmProxy, sval(VAR_gtmProxy), VAR_gtmProxyNames, listValue(VAR_gtmProxyNames), VAR_gtmProxyServers, listValue(VAR_gtmProxyServers), VAR_gtmProxyPorts, listValue(VAR_gtmProxyPorts), VAR_gtmProxyDirs, listValue(VAR_gtmProxyDirs)); fclose(f); backup_configuration(); elog(NOTICE, "Done.\n"); return 0; } /* * Does not check if node name is valid. */ cmd_t* prepare_initGtmProxy(char* nodeName) { cmd_t *cmdInitGtm, *cmdGtmProxyConf; int idx; FILE* f = NULL; char timestamp[MAXTOKEN + 1]; char** fileList = NULL; if ((idx = gtmProxyIdx(nodeName)) < 0) { elog(ERROR, "ERROR: Specified name %s is not GTM Proxy configuration.\n", nodeName); return NULL; } /* Build directory and run initgtm */ cmdInitGtm = initCmd(aval(VAR_gtmProxyServers)[idx]); snprintf(newCommand(cmdInitGtm), MAXLINE, "killall -u %s -9 gtm_proxy;" "rm -rf %s;" "mkdir -p %s;" "gs_initgtm -Z gtm_proxy -D %s", sval(VAR_pgxcUser), aval(VAR_gtmProxyDirs)[idx], aval(VAR_gtmProxyDirs)[idx], aval(VAR_gtmProxyDirs)[idx]); /* Configure gtm_proxy.conf */ appendCmdEl(cmdInitGtm, (cmdGtmProxyConf = initCmd(aval(VAR_gtmProxyServers)[idx]))); if ((f = prepareLocalStdin(newFilename(cmdGtmProxyConf->localStdin), MAXPATH, NULL)) == NULL) { cleanCmd(cmdInitGtm); return NULL; } fprintf(f, "#===========================\n" "# Added at initialization, %s\n" "listen_addresses = '*'\n" "worker_threads = 1\n" "gtm_connect_retry_interval = 1\n", timeStampString(timestamp, MAXTOKEN)); ; if (!is_none(sval(VAR_gtmPxyExtraConfig))) AddMember(fileList, sval(VAR_gtmPxyExtraConfig)); if (!is_none(aval(VAR_gtmPxySpecificExtraConfig)[idx])) AddMember(fileList, aval(VAR_gtmPxySpecificExtraConfig)[idx]); appendFiles(f, fileList); CleanArray(fileList); fprintf(f, "nodename = '%s'\n" "port = %s\n" "gtm_host = '%s'\n" "gtm_port = %s\n" "# End of addition\n", aval(VAR_gtmProxyNames)[idx], aval(VAR_gtmProxyPorts)[idx], sval(VAR_gtmMasterServer), sval(VAR_gtmMasterPort)); fclose(f); snprintf(newCommand(cmdGtmProxyConf), MAXLINE, "cat >> %s/gtm_proxy.conf", aval(VAR_gtmProxyDirs)[idx]); return (cmdInitGtm); } /* * Initialize gtm proxy ------------------------------------------------------- */ int init_gtm_proxy(char** nodeList) { char** actualNodeList; int ii; int rc; cmdList_t* cmdList = NULL; cmd_t* cmdInitGtmPxy = NULL; if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "ERROR: GTM Proxy is not configured.\n"); return 1; } actualNodeList = makeActualNodeList(nodeList); /* Init and run initgtm */ cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { elog(NOTICE, "Initializing gtm proxy %s.\n", actualNodeList[ii]); if ((cmdInitGtmPxy = prepare_initGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmdInitGtmPxy); else elog(WARNING, "WARNING: %s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); elog(NOTICE, "Done.\n"); return (rc); } int init_gtm_proxy_all(void) { elog(NOTICE, "Initialize all the gtm proxies.\n"); if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "ERROR: GTM Proxy is not configured.\n"); return (1); } return (init_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * Start gtm proxy ----------------------------------------------------------- */ cmd_t* prepare_startGtmProxy(char* nodeName) { cmd_t* cmd = NULL; int idx; if ((idx = gtmProxyIdx(nodeName)) < 0) { elog(ERROR, "ERROR: Specified name %s is not GTM Proxy\n", nodeName); return (NULL); } cmd = initCmd(aval(VAR_gtmProxyServers)[idx]); snprintf(newCommand(cmd), MAXLINE, "killall -u %s -9 gtm_proxy;" "gtm_ctl start -Z gtm_proxy -D %s", sval(VAR_pgxcUser), aval(VAR_gtmProxyDirs)[idx]); return (cmd); } int start_gtm_proxy(char** nodeList) { char** actualNodeList; int ii; int rc; cmdList_t* cmdList = NULL; if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "ERROR: GTM Proxy is not configured.\n"); return (1); } actualNodeList = makeActualNodeList(nodeList); /* Init and run initgtm */ cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { cmd_t* cmd = NULL; elog(NOTICE, "Starting gtm proxy %s.\n", actualNodeList[ii]); if ((cmd = prepare_startGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmd); else elog(WARNING, "WARNING: %s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); elog(NOTICE, "Done.\n"); return (rc); } int start_gtm_proxy_all(void) { elog(NOTICE, "Starting all the gtm proxies.\n"); return (start_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * Stop gtm proxy ------------------------------------------------------------- */ cmd_t* prepare_stopGtmProxy(char* nodeName) { cmd_t* cmd = NULL; int idx; if ((idx = gtmProxyIdx(nodeName)) < 0) { elog(ERROR, "ERROR: Specified name %s is not GTM Proxy\n", nodeName); return NULL; } cmd = initCmd(aval(VAR_gtmProxyServers)[idx]); snprintf(newCommand(cmd), MAXLINE, "gtm_ctl stop -Z gtm_proxy -D %s", aval(VAR_gtmProxyDirs)[idx]); return (cmd); } int stop_gtm_proxy(char** nodeList) { char** actualNodeList; int ii; int rc; cmdList_t* cmdList = NULL; if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "ERROR: GTM Proxy is not configured.\n"); return (1); } actualNodeList = makeActualNodeList(nodeList); /* Init and run initgtm */ cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { cmd_t* cmd = NULL; elog(NOTICE, "Stopping gtm proxy %s.\n", actualNodeList[ii]); if ((cmd = prepare_stopGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmd); else elog(WARNING, "WARNING: %s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); elog(NOTICE, "Done.\n"); return (rc); } int stop_gtm_proxy_all(void) { elog(NOTICE, "Stopping all the gtm proxies.\n"); return (stop_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * Kill gtm proxy ------------------------------------------------------------------- * * Although gtm proxy does not have significant resources to carry over to the next * run, it is a good habit to stop gtm proxy with stop command gracefully. */ cmd_t* prepare_killGtmProxy(char* nodeName) { cmd_t* cmd = NULL; int idx; pid_t gtmPxyPid; if ((idx = gtmProxyIdx(nodeName)) < 0) { elog(ERROR, "ERROR: Specified name %s is not GTM Proxy\n", nodeName); return NULL; } cmd = initCmd(aval(VAR_gtmProxyServers)[idx]); gtmPxyPid = get_gtmProxy_pid(aval(VAR_gtmProxyServers)[idx], aval(VAR_gtmProxyDirs)[idx]); if (gtmPxyPid > 0) snprintf(newCommand(cmd), MAXLINE, "kill -9 %d; rm -rf /tmp/.s.'*'%d'*' %s/gtm_proxy.pid", gtmPxyPid, atoi(aval(VAR_gtmProxyPorts)[idx]), aval(VAR_gtmProxyDirs)[idx]); else snprintf(newCommand(cmd), MAXLINE, "killall -u %s -9 gs_gtm; rm -rf /tmp/.s.'*'%d'*' %s/gtm_proxy.pid", sval(VAR_pgxcUser), atoi(aval(VAR_gtmProxyPorts)[idx]), aval(VAR_gtmProxyDirs)[idx]); return (cmd); } int kill_gtm_proxy(char** nodeList) { char** actualNodeList; int ii; int rc; cmdList_t* cmdList = NULL; if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "ERROR: GTM Proxy is not configured.\n"); return (1); } actualNodeList = makeActualNodeList(nodeList); /* Init and run initgtm */ cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { cmd_t* cmd = NULL; elog(NOTICE, "Killing process of gtm proxy %s.\n", actualNodeList[ii]); if ((cmd = prepare_killGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmd); else elog(WARNING, "WARNING: %s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); return (rc); } int kill_gtm_proxy_all(void) { elog(NOTICE, "Killing all the gtm proxy processes.\n"); return (kill_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * Reconnect to the current GTM master -------------------------------------------------- * * When failed over, the current Master must have been updated. * Remember to update gtm_proxy configuration file so that it * connects to the new master at the next start. * Please note that we assume GTM has already been failed over. * First argument is gtm_proxy nodename */ cmd_t* prepare_reconnectGtmProxy(char* nodeName) { cmd_t *cmdGtmCtl, *cmdGtmProxyConf; int idx; FILE* f = NULL; char date[MAXTOKEN + 1]; if ((idx = gtmProxyIdx(nodeName)) < 0) { elog(ERROR, "ERROR: Specified name %s is not GTM Proxy\n", nodeName); return (NULL); } /* gtm_ctl reconnect */ cmdGtmCtl = initCmd(aval(VAR_gtmProxyServers)[idx]); snprintf(newCommand(cmdGtmCtl), MAXLINE, "gtm_ctl reconnect -Z gtm_proxy -D %s -o \\\"-s %s -t %s\\\"", aval(VAR_gtmProxyDirs)[idx], sval(VAR_gtmMasterServer), sval(VAR_gtmMasterPort)); /* gtm_proxy.conf */ appendCmdEl(cmdGtmCtl, (cmdGtmProxyConf = initCmd(aval(VAR_gtmProxyServers)[idx]))); if ((f = prepareLocalStdin(newFilename(cmdGtmProxyConf->localStdin), MAXPATH, NULL)) == NULL) { cleanCmd(cmdGtmCtl); return (NULL); } fprintf(f, "#===================================================\n" "# Updated due to GTM Proxy reconnect\n" "# %s\n" "gtm_host = '%s'\n" "gtm_port = %s\n" "#----End of reconfiguration -------------------------\n", timeStampString(date, MAXTOKEN), sval(VAR_gtmMasterServer), sval(VAR_gtmMasterPort)); fclose(f); snprintf(newCommand(cmdGtmProxyConf), MAXLINE, "cat >> %s/gtm_proxy.conf", aval(VAR_gtmProxyDirs)[idx]); return (cmdGtmCtl); } int reconnect_gtm_proxy(char** nodeList) { char** actualNodeList; int ii; int rc; cmdList_t* cmdList = NULL; if (!isVarYes(VAR_gtmProxy)) { elog(ERROR, "GTM Proxy is not configured.\n"); return (1); } actualNodeList = makeActualNodeList(nodeList); /* Init and run initgtm */ cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { cmd_t* cmd = NULL; elog(NOTICE, "Reconnecting gtm proxy %s.\n", actualNodeList[ii]); if ((cmd = prepare_reconnectGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmd); else elog(WARNING, "WARNING: %s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); elog(NOTICE, "Done.\n"); return (rc); } int reconnect_gtm_proxy_all(void) { elog(NOTICE, "Reconnecting all the gtm proxies to the new one.\n"); return (reconnect_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * Cleanup -- nodeName must be valid. Instead, NULL will bereturned. */ cmd_t* prepare_cleanGtmProxy(char* nodeName) { cmd_t* cmd = NULL; int idx; if ((idx = gtmProxyIdx(nodeName)) < 0) return NULL; cmd = initCmd(aval(VAR_gtmProxyServers)[idx]); snprintf(newCommand(cmd), MAXLINE, "rm -rf %s; mkdir -p %s; chmod 0700 %s;rm -f /tmp/.s.*%d*", aval(VAR_gtmProxyDirs)[idx], aval(VAR_gtmProxyDirs)[idx], aval(VAR_gtmProxyDirs)[idx], atoi(aval(VAR_gtmProxyPorts)[idx])); return cmd; } int clean_gtm_proxy(char** nodeList) { char** actualNodeList; cmdList_t* cmdList = NULL; cmd_t* cmd = NULL; int ii; int rc; actualNodeList = makeActualNodeList(nodeList); cmdList = initCmdList(); for (ii = 0; actualNodeList[ii]; ii++) { elog(NOTICE, "Clearing resources for gtm_proxy %s.\n", actualNodeList[ii]); if ((cmd = prepare_cleanGtmProxy(actualNodeList[ii]))) addCmd(cmdList, cmd); else elog(WARNING, "%s is not a gtm proxy.\n", actualNodeList[ii]); } rc = doCmdList(cmdList); cleanCmdList(cmdList); CleanArray(actualNodeList); elog(NOTICE, "Done.\n"); return (rc); } int clean_gtm_proxy_all(void) { elog(NOTICE, "Clearing all the gtm_proxy resources.\n"); return (clean_gtm_proxy(aval(VAR_gtmProxyNames))); } /* * configuration -------------------------------------------------------------------- */ int show_config_gtmMaster(int flag, char* hostname) { char lineBuf[MAXLINE + 1]; char editBuf[MAXPATH + 1]; lineBuf[0] = 0; if (flag) strncat(lineBuf, "GTM Master: ", MAXLINE); if (hostname) { snprintf(editBuf, MAXPATH, "host: %s", hostname); strncat(lineBuf, editBuf, MAXLINE); } if (flag || hostname) strncat(lineBuf, "\n", MAXLINE); lockLogFile(); if (lineBuf[0]) elog(NOTICE, "%s", lineBuf); print_simple_node_info(sval(VAR_gtmName), sval(VAR_gtmMasterPort), sval(VAR_gtmMasterDir), sval(VAR_gtmExtraConfig), sval(VAR_gtmMasterSpecificExtraConfig)); unlockLogFile(); return 0; } int show_config_gtmSlave(int flag, char* hostname) { char lineBuf[MAXLINE + 1]; char editBuf[MAXPATH + 1]; if (!isVarYes(VAR_gtmSlave) || is_none(VAR_gtmSlaveServer)) { elog(ERROR, "ERROR: gtm slave is not configured.\n"); return 0; } lineBuf[0] = 0; if (flag) strncat(lineBuf, "GTM Slave: ", MAXLINE); if (hostname) { snprintf(editBuf, MAXPATH, "host: %s", hostname); strncat(lineBuf, editBuf, MAXLINE); } if (flag || hostname) strncat(lineBuf, "\n", MAXLINE); lockLogFile(); elog(NOTICE, "%s", lineBuf); print_simple_node_info(sval(VAR_gtmName), sval(VAR_gtmSlavePort), sval(VAR_gtmSlaveDir), sval(VAR_gtmExtraConfig), sval(VAR_gtmSlaveSpecificExtraConfig)); unlockLogFile(); return 0; } int show_config_gtmProxies(char** nameList) { int ii; lockLogFile(); for (ii = 0; nameList[ii]; ii++) show_config_gtmProxy(TRUE, ii, aval(VAR_gtmProxyServers)[ii]); unlockLogFile(); return 0; } int show_config_gtmProxy(int flag, int idx, char* hostname) { char lineBuf[MAXLINE + 1]; char editBuf[MAXPATH + 1]; lineBuf[0] = 0; if (flag) strncat(lineBuf, "GTM Proxy: ", MAXLINE); if (hostname) { snprintf(editBuf, MAXPATH, "host: %s", hostname); strncat(lineBuf, editBuf, MAXLINE); } if (flag || hostname) strncat(lineBuf, "\n", MAXLINE); lockLogFile(); if (lineBuf[0]) elog(NOTICE, "%s", lineBuf); print_simple_node_info(aval(VAR_gtmProxyNames)[idx], aval(VAR_gtmProxyPorts)[idx], aval(VAR_gtmProxyDirs)[idx], sval(VAR_gtmPxyExtraConfig), aval(VAR_gtmPxySpecificExtraConfig)[idx]); unlockLogFile(); return 0; }