swapnode.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "thirdparty.h"
  15. #include "jlib.hpp"
  16. #include "jfile.hpp"
  17. #include "jptree.hpp"
  18. #include "jprop.hpp"
  19. #include "jmisc.hpp"
  20. #include "jargv.hpp"
  21. #include "mpbase.hpp"
  22. #include "daclient.hpp"
  23. #include "dadfs.hpp"
  24. #include "dafdesc.hpp"
  25. #include "dasds.hpp"
  26. #include "danqs.hpp"
  27. #include "dalienv.hpp"
  28. #include "rmtfile.hpp"
  29. #include "rmtsmtp.hpp"
  30. #include "dautils.hpp"
  31. #include "workunit.hpp"
  32. #include "swapnodelib.hpp"
  33. struct DaliClient
  34. {
  35. DaliClient(const char* daliserver): serverGroup(createIGroup(daliserver, DALI_SERVER_PORT))
  36. {
  37. if (!serverGroup)
  38. throw MakeStringException(0, "Could not instantiate IGroup");
  39. if (!initClientProcess(serverGroup,DCR_Util))
  40. throw MakeStringException(0, "Could not initializing client process");
  41. setPasswordsFromSDS();
  42. }
  43. ~DaliClient()
  44. {
  45. clearPasswordsFromSDS();
  46. closedownClientProcess();
  47. }
  48. Owned<IGroup> serverGroup;
  49. };
  50. void usage()
  51. {
  52. fprintf(stderr,"Usage: swapnode swap <dali> <thor-cluster> <oldip> <newip>\n");
  53. fprintf(stderr," or: swapnode auto [-dryrun] <dali> <thor-cluster>\n");
  54. fprintf(stderr," or: swapnode reset <dali> <thor-cluster> -- resets group used by <thor-cluster> to match environment\n");
  55. fprintf(stderr," or: swapnode resetspares <dali> <thor-cluster> -- resets spare group used by <thor-cluster> to match environment\n");
  56. fprintf(stderr," or: swapnode addspares <dali> <thor-cluster> <spares> -- adds <spares> to spare group used by <thor-cluster>\n");
  57. fprintf(stderr," or: swapnode removespares <dali> <thor-cluster> <spares> -- removes <spares> to spare group used by <thor-cluster>\n");
  58. fprintf(stderr," or: swapnode history <dali> <thor-cluster> [<days>] -- list swap history \n");
  59. fprintf(stderr," or: swapnode history <dali> <thor-cluster> [<days>] 2> outfile.csv -- save swap history \n");
  60. fprintf(stderr," or: swapnode resethistory <dali> <thor-cluster> -- reset swap history \n");
  61. fprintf(stderr," or: swapnode swapped <dali> <thor-cluster> [<days>] -- list currently swapped nodes\n");
  62. fprintf(stderr," or: swapnode email <dali> <thor-cluster> [swapped|history] -- tests email\n");
  63. fprintf(stderr,"NB: if '-dryrun' specified after 'auto' then only displays what *would* be swapped\n");
  64. exit(1);
  65. }
  66. #define SDS_LOCK_TIMEOUT 30000
  67. int main(int argc, const char *argv[])
  68. {
  69. InitModuleObjects();
  70. int ret = 0;
  71. bool dryRun = false;
  72. bool offline = false;
  73. StringAttr daliServer, envPath;
  74. enum CmdType { cmd_none, cmd_swap, cmd_auto, cmd_history, cmd_email, cmd_swapped, cmd_reset, cmd_resetspares, cmd_addspares, cmd_removespares, cmd_resethistory };
  75. CmdType cmd = cmd_none;
  76. ArgvIterator iter(argc, argv);
  77. try
  78. {
  79. bool stop=false;
  80. StringArray params;
  81. for (; !ret&&!iter.done(); iter.next())
  82. {
  83. const char *arg = iter.query();
  84. if ('-' == *arg)
  85. {
  86. bool value;
  87. if (iter.matchFlag(value, "-dryrun"))
  88. dryRun = value;
  89. else if (iter.matchFlag(value, "-offline"))
  90. offline = value;
  91. else
  92. {
  93. PROGLOG("Unknown option");
  94. ret = 2;
  95. usage();
  96. break;
  97. }
  98. }
  99. else
  100. {
  101. switch (cmd)
  102. {
  103. case cmd_none:
  104. if (strieq("swap", arg))
  105. cmd = cmd_swap;
  106. else if (strieq("auto", arg))
  107. cmd = cmd_auto;
  108. else if (strieq("history", arg))
  109. cmd = cmd_history;
  110. else if (strieq("email", arg))
  111. cmd = cmd_email;
  112. else if (strieq("swapped", arg))
  113. cmd = cmd_swapped;
  114. else if (strieq("reset", arg))
  115. cmd = cmd_reset;
  116. else if (strieq("resetspares", arg))
  117. cmd = cmd_resetspares;
  118. else if (strieq("addspares", arg))
  119. cmd = cmd_addspares;
  120. else if (strieq("removespares", arg))
  121. cmd = cmd_removespares;
  122. else if (strieq("resethistory", arg))
  123. cmd = cmd_resethistory;
  124. else
  125. {
  126. PROGLOG("Unknown command");
  127. usage();
  128. ret = 2;
  129. }
  130. break;
  131. default:
  132. params.append(iter.query());
  133. break;
  134. }
  135. }
  136. }
  137. unsigned requiredParams=UINT_MAX;
  138. switch (cmd)
  139. {
  140. case cmd_swap:
  141. requiredParams = 4;
  142. break;
  143. case cmd_addspares:
  144. case cmd_removespares:
  145. requiredParams = 3;
  146. break;
  147. case cmd_auto:
  148. case cmd_history:
  149. case cmd_email:
  150. case cmd_swapped:
  151. case cmd_reset:
  152. case cmd_resetspares:
  153. case cmd_resethistory:
  154. requiredParams = 2;
  155. break;
  156. }
  157. if (params.ordinality() < requiredParams)
  158. {
  159. usage();
  160. ret = 2;
  161. }
  162. else
  163. {
  164. StringAttr daliServer = params.item(0);
  165. StringAttr clusterName = params.item(1);
  166. DaliClient dclient(daliServer);
  167. StringBuffer logname;
  168. splitFilename(argv[0], NULL, NULL, &logname, NULL);
  169. addFileTimestamp(logname, true);
  170. logname.append(".log");
  171. StringBuffer lf;
  172. openLogFile(lf, logname.str(),0,false,true);
  173. queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_prefix);
  174. Owned<IRemoteConnection> conn = querySDS().connect("/Environment", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  175. IPropertyTree *environment = conn->queryRoot();
  176. StringBuffer xpath("Software/ThorCluster[@name=\"");
  177. xpath.append(clusterName).append("\"]");
  178. IPropertyTree *cluster = environment->queryPropTree(xpath.str());
  179. if (!cluster)
  180. {
  181. PROGLOG("Unknown cluster: %s", clusterName.get());
  182. ret = 3;
  183. }
  184. if (!ret)
  185. {
  186. Owned<IPropertyTree> options = createPTreeFromIPT(cluster);
  187. conn.clear();
  188. if (options&&options->getPropBool("@enableSysLog",true))
  189. UseSysLogForOperatorMessages();
  190. switch (cmd)
  191. {
  192. case cmd_auto:
  193. {
  194. if (!autoSwapNode(clusterName, dryRun))
  195. ret = 3;
  196. break;
  197. }
  198. case cmd_swap:
  199. {
  200. const char *oldip=params.item(2);
  201. const char *newip=params.item(3);
  202. if (!swapNode(clusterName, oldip, newip))
  203. ret = 3;
  204. break;
  205. }
  206. case cmd_history:
  207. case cmd_swapped:
  208. case cmd_email:
  209. {
  210. unsigned days = params.isItem(2) ? atoi(params.item(2)) : 0; // for history or swapped
  211. switch (cmd)
  212. {
  213. case cmd_history:
  214. swapNodeHistory(clusterName, days, NULL);
  215. break;
  216. case cmd_swapped:
  217. swappedList(clusterName, days, NULL);
  218. break;
  219. case cmd_email:
  220. {
  221. bool sendSwapped = false;
  222. bool sendHistory = false;
  223. if (params.isItem(2))
  224. {
  225. if (strieq("swapped", params.item(2)))
  226. sendSwapped = true;
  227. else if (strieq("history", params.item(2)))
  228. sendHistory = true;
  229. }
  230. emailSwap(clusterName, NULL, true, sendSwapped, sendHistory);
  231. break;
  232. }
  233. }
  234. break;
  235. }
  236. case cmd_reset:
  237. case cmd_resetspares:
  238. {
  239. StringBuffer response;
  240. if (!resetClusterGroup(clusterName, "ThorCluster", cmd==cmd_resetspares, response))
  241. {
  242. WARNLOG("%s", response.str());
  243. ret = 3;
  244. }
  245. break;
  246. }
  247. case cmd_addspares:
  248. case cmd_removespares:
  249. {
  250. SocketEndpointArray allEps;
  251. unsigned p=2;
  252. do
  253. {
  254. const char *ipOrRange = params.item(p);
  255. SocketEndpointArray epa;
  256. epa.fromText(ipOrRange, 0);
  257. ForEachItemIn(e, epa)
  258. allEps.append(epa.item(e));
  259. p++;
  260. }
  261. while (p<params.ordinality());
  262. StringBuffer response;
  263. bool res;
  264. if (cmd == cmd_addspares)
  265. res = addClusterSpares(clusterName, "ThorCluster", allEps, response);
  266. else
  267. res = removeClusterSpares(clusterName, "ThorCluster", allEps, response);
  268. if (!res)
  269. {
  270. WARNLOG("%s", response.str());
  271. ret = 3;
  272. }
  273. break;
  274. }
  275. case cmd_resethistory:
  276. {
  277. Owned<IRemoteConnection> conn = querySDS().connect("/SwapNode", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  278. if (conn)
  279. {
  280. StringBuffer groupName;
  281. getClusterGroupName(*options, groupName);
  282. VStringBuffer xpath("Thor[@group=\"%s\"]", groupName.str());
  283. if (conn->queryRoot()->removeProp(xpath.str()))
  284. PROGLOG("SwapNode info for cluster %s removed", clusterName.get());
  285. else
  286. PROGLOG("SwapNode info for cluster %s not found", clusterName.get());
  287. }
  288. break;
  289. }
  290. }
  291. }
  292. }
  293. UseSysLogForOperatorMessages(false);
  294. }
  295. catch (IException *e) {
  296. EXCLOG(e,"SWAPNODE");
  297. e->Release();
  298. ret = -1;
  299. }
  300. ExitModuleObjects();
  301. return ret;
  302. }