PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/plugins/accounting_storage/common/common_as.c

https://github.com/cfenoy/slurm
C | 846 lines | 648 code | 76 blank | 122 comment | 169 complexity | 8d851cde15f95e23747ccdca6ff4d1df MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*****************************************************************************\
  2. * common_as.c - common functions for accounting storage
  3. *
  4. * $Id: common_as.c 13061 2008-01-22 21:23:56Z da $
  5. *****************************************************************************
  6. * Copyright (C) 2004-2007 The Regents of the University of California.
  7. * Copyright (C) 2008-2010 Lawrence Livermore National Security.
  8. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  9. * Written by Danny Auble <da@llnl.gov>
  10. *
  11. * This file is part of SLURM, a resource management program.
  12. * For details, see <http://www.schedmd.com/slurmdocs/>.
  13. * Please also read the included file: DISCLAIMER.
  14. *
  15. * SLURM is free software; you can redistribute it and/or modify it under
  16. * the terms of the GNU General Public License as published by the Free
  17. * Software Foundation; either version 2 of the License, or (at your option)
  18. * any later version.
  19. *
  20. * In addition, as a special exception, the copyright holders give permission
  21. * to link the code of portions of this program with the OpenSSL library under
  22. * certain conditions as described in each individual source file, and
  23. * distribute linked combinations including the two. You must obey the GNU
  24. * General Public License in all respects for all of the code used other than
  25. * OpenSSL. If you modify file(s) with this exception, you may extend this
  26. * exception to your version of the file(s), but you are not obligated to do
  27. * so. If you do not wish to do so, delete this exception statement from your
  28. * version. If you delete this exception statement from all source files in
  29. * the program, then also delete it here.
  30. *
  31. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  32. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  33. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  34. * details.
  35. *
  36. * You should have received a copy of the GNU General Public License along
  37. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  38. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  39. \*****************************************************************************/
  40. #include <strings.h>
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <unistd.h>
  44. #include <fcntl.h>
  45. #include "src/common/slurmdbd_defs.h"
  46. #include "src/common/slurm_auth.h"
  47. #include "src/common/xstring.h"
  48. #include "src/common/env.h"
  49. #include "src/slurmdbd/read_config.h"
  50. #include "common_as.h"
  51. extern char *assoc_hour_table;
  52. extern char *assoc_day_table;
  53. extern char *assoc_month_table;
  54. extern char *cluster_hour_table;
  55. extern char *cluster_day_table;
  56. extern char *cluster_month_table;
  57. extern char *wckey_hour_table;
  58. extern char *wckey_day_table;
  59. extern char *wckey_month_table;
  60. /*
  61. * We want SLURMDB_MODIFY_ASSOC always to be the last
  62. */
  63. static int _sort_update_object_dec(slurmdb_update_object_t *object_a,
  64. slurmdb_update_object_t *object_b)
  65. {
  66. if ((object_a->type == SLURMDB_MODIFY_ASSOC)
  67. && (object_b->type != SLURMDB_MODIFY_ASSOC))
  68. return 1;
  69. else if((object_b->type == SLURMDB_MODIFY_ASSOC)
  70. && (object_a->type != SLURMDB_MODIFY_ASSOC))
  71. return -1;
  72. return 0;
  73. }
  74. static void _dump_slurmdb_assoc_records(List assoc_list)
  75. {
  76. slurmdb_association_rec_t *assoc = NULL;
  77. ListIterator itr = NULL;
  78. itr = list_iterator_create(assoc_list);
  79. while((assoc = list_next(itr))) {
  80. debug("\t\tid=%d", assoc->id);
  81. }
  82. list_iterator_destroy(itr);
  83. }
  84. /*
  85. * addto_update_list - add object updated to list
  86. * IN/OUT update_list: list of updated objects
  87. * IN type: update type
  88. * IN object: object updated
  89. * RET: error code
  90. *
  91. * NOTE: This function will take the object given and free it later so it
  92. * needed to be removed from a list if in one before.
  93. */
  94. extern int addto_update_list(List update_list, slurmdb_update_type_t type,
  95. void *object)
  96. {
  97. slurmdb_update_object_t *update_object = NULL;
  98. slurmdb_association_rec_t *assoc = object;
  99. slurmdb_qos_rec_t *qos = object;
  100. ListIterator itr = NULL;
  101. if(!update_list) {
  102. error("no update list given");
  103. return SLURM_ERROR;
  104. }
  105. itr = list_iterator_create(update_list);
  106. while((update_object = list_next(itr))) {
  107. if(update_object->type == type)
  108. break;
  109. }
  110. list_iterator_destroy(itr);
  111. if(update_object) {
  112. /* here we prepend primarly for remove association
  113. since parents need to be removed last, and they are
  114. removed first in the calling code */
  115. list_prepend(update_object->objects, object);
  116. return SLURM_SUCCESS;
  117. }
  118. update_object = xmalloc(sizeof(slurmdb_update_object_t));
  119. list_append(update_list, update_object);
  120. update_object->type = type;
  121. list_sort(update_list, (ListCmpF)_sort_update_object_dec);
  122. switch(type) {
  123. case SLURMDB_MODIFY_USER:
  124. case SLURMDB_ADD_USER:
  125. case SLURMDB_REMOVE_USER:
  126. case SLURMDB_ADD_COORD:
  127. case SLURMDB_REMOVE_COORD:
  128. update_object->objects = list_create(slurmdb_destroy_user_rec);
  129. break;
  130. case SLURMDB_ADD_ASSOC:
  131. /* We are going to send these to the slurmctld's so
  132. lets set up the correct limits to INIFINITE instead
  133. of NO_VAL */
  134. if(assoc->grp_cpu_mins == (uint64_t)NO_VAL)
  135. assoc->grp_cpu_mins = (uint64_t)INFINITE;
  136. if(assoc->grp_cpu_run_mins == (uint64_t)NO_VAL)
  137. assoc->grp_cpu_run_mins = (uint64_t)INFINITE;
  138. if(assoc->grp_cpus == NO_VAL)
  139. assoc->grp_cpus = INFINITE;
  140. if(assoc->grp_jobs == NO_VAL)
  141. assoc->grp_jobs = INFINITE;
  142. if(assoc->grp_mem == NO_VAL)
  143. assoc->grp_mem = INFINITE;
  144. if(assoc->grp_nodes == NO_VAL)
  145. assoc->grp_nodes = INFINITE;
  146. if(assoc->grp_submit_jobs == NO_VAL)
  147. assoc->grp_submit_jobs = INFINITE;
  148. if(assoc->grp_wall == NO_VAL)
  149. assoc->grp_wall = INFINITE;
  150. if(assoc->max_cpu_mins_pj == (uint64_t)NO_VAL)
  151. assoc->max_cpu_mins_pj = (uint64_t)INFINITE;
  152. if(assoc->max_cpu_run_mins == (uint64_t)NO_VAL)
  153. assoc->max_cpu_run_mins = (uint64_t)INFINITE;
  154. if(assoc->max_cpus_pj == NO_VAL)
  155. assoc->max_cpus_pj = INFINITE;
  156. if(assoc->max_jobs == NO_VAL)
  157. assoc->max_jobs = INFINITE;
  158. if(assoc->max_nodes_pj == NO_VAL)
  159. assoc->max_nodes_pj = INFINITE;
  160. if(assoc->max_submit_jobs == NO_VAL)
  161. assoc->max_submit_jobs = INFINITE;
  162. if(assoc->max_wall_pj == NO_VAL)
  163. assoc->max_wall_pj = INFINITE;
  164. case SLURMDB_MODIFY_ASSOC:
  165. case SLURMDB_REMOVE_ASSOC:
  166. xassert(((slurmdb_association_rec_t *)object)->cluster);
  167. update_object->objects = list_create(
  168. slurmdb_destroy_association_rec);
  169. break;
  170. case SLURMDB_ADD_QOS:
  171. /* We are going to send these to the slurmctld's so
  172. lets set up the correct limits to INIFINITE instead
  173. of NO_VAL */
  174. if(qos->grp_cpu_mins == (uint64_t)NO_VAL)
  175. qos->grp_cpu_mins = (uint64_t)INFINITE;
  176. if(qos->grp_cpu_run_mins == (uint64_t)NO_VAL)
  177. qos->grp_cpu_run_mins = (uint64_t)INFINITE;
  178. if(qos->grp_cpus == NO_VAL)
  179. qos->grp_cpus = INFINITE;
  180. if(qos->grp_jobs == NO_VAL)
  181. qos->grp_jobs = INFINITE;
  182. if(qos->grp_mem == NO_VAL)
  183. qos->grp_mem = INFINITE;
  184. if(qos->grp_nodes == NO_VAL)
  185. qos->grp_nodes = INFINITE;
  186. if(qos->grp_submit_jobs == NO_VAL)
  187. qos->grp_submit_jobs = INFINITE;
  188. if(qos->grp_wall == NO_VAL)
  189. qos->grp_wall = INFINITE;
  190. if(qos->max_cpu_mins_pj == (uint64_t)NO_VAL)
  191. qos->max_cpu_mins_pj = (uint64_t)INFINITE;
  192. if(qos->max_cpu_run_mins_pu == (uint64_t)NO_VAL)
  193. qos->max_cpu_run_mins_pu = (uint64_t)INFINITE;
  194. if(qos->max_cpus_pj == NO_VAL)
  195. qos->max_cpus_pj = INFINITE;
  196. if(qos->max_cpus_pu == NO_VAL)
  197. qos->max_cpus_pu = INFINITE;
  198. if(qos->max_jobs_pu == NO_VAL)
  199. qos->max_jobs_pu = INFINITE;
  200. if(qos->max_nodes_pj == NO_VAL)
  201. qos->max_nodes_pj = INFINITE;
  202. if(qos->max_nodes_pu == NO_VAL)
  203. qos->max_nodes_pu = INFINITE;
  204. if(qos->max_submit_jobs_pu == NO_VAL)
  205. qos->max_submit_jobs_pu = INFINITE;
  206. if(qos->max_wall_pj == NO_VAL)
  207. qos->max_wall_pj = INFINITE;
  208. case SLURMDB_MODIFY_QOS:
  209. case SLURMDB_REMOVE_QOS:
  210. update_object->objects = list_create(
  211. slurmdb_destroy_qos_rec);
  212. break;
  213. case SLURMDB_ADD_WCKEY:
  214. case SLURMDB_MODIFY_WCKEY:
  215. case SLURMDB_REMOVE_WCKEY:
  216. xassert(((slurmdb_wckey_rec_t *)object)->cluster);
  217. update_object->objects = list_create(
  218. slurmdb_destroy_wckey_rec);
  219. break;
  220. case SLURMDB_ADD_CLUSTER:
  221. case SLURMDB_REMOVE_CLUSTER:
  222. /* This should only be the name of the cluster, and is
  223. only used in the plugin for rollback purposes.
  224. */
  225. update_object->objects = list_create(slurm_destroy_char);
  226. break;
  227. case SLURMDB_UPDATE_NOTSET:
  228. default:
  229. error("unknown type set in update_object: %d", type);
  230. return SLURM_ERROR;
  231. }
  232. debug4("XXX: update object with type %d added", type);
  233. list_append(update_object->objects, object);
  234. return SLURM_SUCCESS;
  235. }
  236. /*
  237. * dump_update_list - dump contents of updates
  238. * IN update_list: updates to perform
  239. */
  240. extern void dump_update_list(List update_list)
  241. {
  242. ListIterator itr = NULL;
  243. slurmdb_update_object_t *object = NULL;
  244. debug3("========== DUMP UPDATE LIST ==========");
  245. itr = list_iterator_create(update_list);
  246. while((object = list_next(itr))) {
  247. if(!object->objects || !list_count(object->objects)) {
  248. debug3("\tUPDATE OBJECT WITH NO RECORDS, type: %d",
  249. object->type);
  250. continue;
  251. }
  252. switch(object->type) {
  253. case SLURMDB_MODIFY_USER:
  254. case SLURMDB_ADD_USER:
  255. case SLURMDB_REMOVE_USER:
  256. case SLURMDB_ADD_COORD:
  257. case SLURMDB_REMOVE_COORD:
  258. debug3("\tUSER RECORDS");
  259. break;
  260. case SLURMDB_ADD_ASSOC:
  261. case SLURMDB_MODIFY_ASSOC:
  262. case SLURMDB_REMOVE_ASSOC:
  263. debug3("\tASSOC RECORDS");
  264. _dump_slurmdb_assoc_records(object->objects);
  265. break;
  266. case SLURMDB_ADD_QOS:
  267. case SLURMDB_MODIFY_QOS:
  268. case SLURMDB_REMOVE_QOS:
  269. debug3("\tQOS RECORDS");
  270. break;
  271. case SLURMDB_ADD_WCKEY:
  272. case SLURMDB_MODIFY_WCKEY:
  273. case SLURMDB_REMOVE_WCKEY:
  274. debug3("\tWCKEY RECORDS");
  275. break;
  276. case SLURMDB_UPDATE_NOTSET:
  277. default:
  278. error("unknown type set in "
  279. "update_object: %d",
  280. object->type);
  281. break;
  282. }
  283. }
  284. list_iterator_destroy(itr);
  285. }
  286. /*
  287. * cluster_first_reg - ask for controller to send nodes in a down state
  288. * and jobs pending or running on first registration.
  289. *
  290. * IN host: controller host
  291. * IN port: controller port
  292. * IN rpc_version: controller rpc version
  293. * RET: error code
  294. */
  295. extern int cluster_first_reg(char *host, uint16_t port, uint16_t rpc_version)
  296. {
  297. slurm_addr_t ctld_address;
  298. slurm_fd_t fd;
  299. int rc = SLURM_SUCCESS;
  300. info("First time to register cluster requesting "
  301. "running jobs and system information.");
  302. slurm_set_addr_char(&ctld_address, port, host);
  303. fd = slurm_open_msg_conn(&ctld_address);
  304. if (fd < 0) {
  305. error("can not open socket back to slurmctld "
  306. "%s(%u): %m", host, port);
  307. rc = SLURM_ERROR;
  308. } else {
  309. slurm_msg_t out_msg;
  310. accounting_update_msg_t update;
  311. /* We have to put this update message here so
  312. we can tell the sender to send the correct
  313. RPC version.
  314. */
  315. memset(&update, 0, sizeof(accounting_update_msg_t));
  316. update.rpc_version = rpc_version;
  317. slurm_msg_t_init(&out_msg);
  318. out_msg.msg_type = ACCOUNTING_FIRST_REG;
  319. out_msg.flags = SLURM_GLOBAL_AUTH_KEY;
  320. out_msg.data = &update;
  321. slurm_send_node_msg(fd, &out_msg);
  322. /* We probably need to add matching recv_msg function
  323. * for an arbitray fd or should these be fire
  324. * and forget? For this, that we can probably
  325. * forget about it */
  326. slurm_close_stream(fd);
  327. }
  328. return rc;
  329. }
  330. /*
  331. * set_usage_information - set time and table information for getting usage
  332. *
  333. * OUT usage_table: which usage table to query
  334. * IN type: usage type to get
  335. * IN/OUT usage_start: start time
  336. * IN/OUT usage_end: end time
  337. * RET: error code
  338. */
  339. extern int set_usage_information(char **usage_table, slurmdbd_msg_type_t type,
  340. time_t *usage_start, time_t *usage_end)
  341. {
  342. time_t start = (*usage_start), end = (*usage_end);
  343. time_t my_time = time(NULL);
  344. struct tm start_tm;
  345. struct tm end_tm;
  346. char *my_usage_table = (*usage_table);
  347. /* Default is going to be the last day */
  348. if(!end) {
  349. if(!localtime_r(&my_time, &end_tm)) {
  350. error("Couldn't get localtime from end %ld",
  351. my_time);
  352. return SLURM_ERROR;
  353. }
  354. end_tm.tm_hour = 0;
  355. } else {
  356. if(!localtime_r(&end, &end_tm)) {
  357. error("Couldn't get localtime from user end %ld",
  358. end);
  359. return SLURM_ERROR;
  360. }
  361. }
  362. end_tm.tm_sec = 0;
  363. end_tm.tm_min = 0;
  364. end_tm.tm_isdst = -1;
  365. end = mktime(&end_tm);
  366. if(!start) {
  367. if(!localtime_r(&my_time, &start_tm)) {
  368. error("Couldn't get localtime from start %ld",
  369. my_time);
  370. return SLURM_ERROR;
  371. }
  372. start_tm.tm_hour = 0;
  373. start_tm.tm_mday--;
  374. } else {
  375. if(!localtime_r(&start, &start_tm)) {
  376. error("Couldn't get localtime from user start %ld",
  377. start);
  378. return SLURM_ERROR;
  379. }
  380. }
  381. start_tm.tm_sec = 0;
  382. start_tm.tm_min = 0;
  383. start_tm.tm_isdst = -1;
  384. start = mktime(&start_tm);
  385. if(end-start < 3600) {
  386. end = start + 3600;
  387. if(!localtime_r(&end, &end_tm)) {
  388. error("2 Couldn't get localtime from user end %ld",
  389. end);
  390. return SLURM_ERROR;
  391. }
  392. }
  393. /* check to see if we are off day boundaries or on month
  394. * boundaries other wise use the day table.
  395. */
  396. //info("%d %d %d", start_tm.tm_hour, end_tm.tm_hour, end-start);
  397. if(start_tm.tm_hour || end_tm.tm_hour || (end-start < 86400)
  398. || (end > my_time)) {
  399. switch (type) {
  400. case DBD_GET_ASSOC_USAGE:
  401. my_usage_table = assoc_hour_table;
  402. break;
  403. case DBD_GET_WCKEY_USAGE:
  404. my_usage_table = wckey_hour_table;
  405. break;
  406. case DBD_GET_CLUSTER_USAGE:
  407. my_usage_table = cluster_hour_table;
  408. break;
  409. default:
  410. error("Bad type given for hour usage %d %s", type,
  411. slurmdbd_msg_type_2_str(type, 1));
  412. break;
  413. }
  414. } else if(start_tm.tm_mday == 0 && end_tm.tm_mday == 0
  415. && (end-start > 86400)) {
  416. switch (type) {
  417. case DBD_GET_ASSOC_USAGE:
  418. my_usage_table = assoc_month_table;
  419. break;
  420. case DBD_GET_WCKEY_USAGE:
  421. my_usage_table = wckey_month_table;
  422. break;
  423. case DBD_GET_CLUSTER_USAGE:
  424. my_usage_table = cluster_month_table;
  425. break;
  426. default:
  427. error("Bad type given for month usage %d %s", type,
  428. slurmdbd_msg_type_2_str(type, 1));
  429. break;
  430. }
  431. }
  432. (*usage_start) = start;
  433. (*usage_end) = end;
  434. (*usage_table) = my_usage_table;
  435. return SLURM_SUCCESS;
  436. }
  437. /*
  438. * merge_delta_qos_list - apply delta_qos_list to qos_list
  439. *
  440. * IN/OUT qos_list: list of QOS'es
  441. * IN delta_qos_list: list of delta QOS'es
  442. */
  443. extern void merge_delta_qos_list(List qos_list, List delta_qos_list)
  444. {
  445. ListIterator curr_itr = list_iterator_create(qos_list);
  446. ListIterator new_itr = list_iterator_create(delta_qos_list);
  447. char *new_qos = NULL, *curr_qos = NULL;
  448. while((new_qos = list_next(new_itr))) {
  449. if(new_qos[0] == '-') {
  450. while((curr_qos = list_next(curr_itr))) {
  451. if(!strcmp(curr_qos, new_qos+1)) {
  452. list_delete_item(curr_itr);
  453. break;
  454. }
  455. }
  456. list_iterator_reset(curr_itr);
  457. } else if(new_qos[0] == '+') {
  458. while((curr_qos = list_next(curr_itr))) {
  459. if(!strcmp(curr_qos, new_qos+1)) {
  460. break;
  461. }
  462. }
  463. if(!curr_qos) {
  464. list_append(qos_list, xstrdup(new_qos+1));
  465. }
  466. list_iterator_reset(curr_itr);
  467. }
  468. }
  469. list_iterator_destroy(new_itr);
  470. list_iterator_destroy(curr_itr);
  471. }
  472. extern bool is_user_min_admin_level(void *db_conn, uid_t uid,
  473. slurmdb_admin_level_t min_level)
  474. {
  475. bool is_admin = 1;
  476. /* This only works when running though the slurmdbd.
  477. * THERE IS NO AUTHENTICATION WHEN RUNNNING OUT OF THE
  478. * SLURMDBD!
  479. */
  480. if(slurmdbd_conf) {
  481. /* We have to check the authentication here in the
  482. * plugin since we don't know what accounts are being
  483. * referenced until after the query.
  484. */
  485. if((uid != slurmdbd_conf->slurm_user_id && uid != 0)
  486. && assoc_mgr_get_admin_level(db_conn, uid) < min_level)
  487. is_admin = 0;
  488. }
  489. return is_admin;
  490. }
  491. extern bool is_user_coord(slurmdb_user_rec_t *user, char *account)
  492. {
  493. ListIterator itr;
  494. slurmdb_coord_rec_t *coord;
  495. xassert(user);
  496. xassert(account);
  497. if (!user->coord_accts || !list_count(user->coord_accts))
  498. return 0;
  499. itr = list_iterator_create(user->coord_accts);
  500. while((coord = list_next(itr))) {
  501. if(!strcasecmp(coord->name, account))
  502. break;
  503. }
  504. list_iterator_destroy(itr);
  505. return coord ? 1 : 0;
  506. }
  507. extern bool is_user_any_coord(void *db_conn, slurmdb_user_rec_t *user)
  508. {
  509. xassert(user);
  510. if(assoc_mgr_fill_in_user(db_conn, user, 1, NULL) != SLURM_SUCCESS) {
  511. error("couldn't get information for this user %s(%d)",
  512. user->name, user->uid);
  513. return 0;
  514. }
  515. return (user->coord_accts && list_count(user->coord_accts));
  516. }
  517. /*
  518. * acct_get_db_name - get database name of accouting storage
  519. * RET: database name, should be free-ed by caller
  520. */
  521. extern char *acct_get_db_name(void)
  522. {
  523. char *db_name = NULL;
  524. char *location = slurm_get_accounting_storage_loc();
  525. if(!location)
  526. db_name = xstrdup(DEFAULT_ACCOUNTING_DB);
  527. else {
  528. int i = 0;
  529. while(location[i]) {
  530. if(location[i] == '.' || location[i] == '/') {
  531. debug("%s doesn't look like a database "
  532. "name using %s",
  533. location, DEFAULT_ACCOUNTING_DB);
  534. break;
  535. }
  536. i++;
  537. }
  538. if(location[i]) {
  539. db_name = xstrdup(DEFAULT_ACCOUNTING_DB);
  540. xfree(location);
  541. } else
  542. db_name = location;
  543. }
  544. return db_name;
  545. }
  546. extern time_t archive_setup_end_time(time_t last_submit, uint32_t purge)
  547. {
  548. struct tm time_tm;
  549. int16_t units;
  550. if(purge == NO_VAL) {
  551. error("Invalid purge set");
  552. return 0;
  553. }
  554. units = SLURMDB_PURGE_GET_UNITS(purge);
  555. if(units < 0) {
  556. error("invalid units from purge '%d'", units);
  557. return 0;
  558. }
  559. /* use localtime to avoid any daylight savings issues */
  560. if(!localtime_r(&last_submit, &time_tm)) {
  561. error("Couldn't get localtime from first "
  562. "suspend start %ld", (long)last_submit);
  563. return 0;
  564. }
  565. time_tm.tm_sec = 0;
  566. time_tm.tm_min = 0;
  567. if(SLURMDB_PURGE_IN_HOURS(purge))
  568. time_tm.tm_hour -= units;
  569. else if(SLURMDB_PURGE_IN_DAYS(purge)) {
  570. time_tm.tm_hour = 0;
  571. time_tm.tm_mday -= units;
  572. } else if(SLURMDB_PURGE_IN_MONTHS(purge)) {
  573. time_tm.tm_hour = 0;
  574. time_tm.tm_mday = 1;
  575. time_tm.tm_mon -= units;
  576. } else {
  577. errno = EINVAL;
  578. error("No known unit given for purge, "
  579. "we are guessing mistake and returning error");
  580. return 0;
  581. }
  582. time_tm.tm_isdst = -1;
  583. return (mktime(&time_tm) - 1);
  584. }
  585. /* execute archive script */
  586. extern int archive_run_script(slurmdb_archive_cond_t *arch_cond,
  587. char *cluster_name, time_t last_submit)
  588. {
  589. char * args[] = {arch_cond->archive_script, NULL};
  590. struct stat st;
  591. char **env = NULL;
  592. time_t curr_end;
  593. if (stat(arch_cond->archive_script, &st) < 0) {
  594. errno = errno;
  595. error("archive_run_script: failed to stat %s: %m",
  596. arch_cond->archive_script);
  597. return SLURM_ERROR;
  598. }
  599. if (!(st.st_mode & S_IFREG)) {
  600. errno = EACCES;
  601. error("archive_run_script: %s isn't a regular file",
  602. arch_cond->archive_script);
  603. return SLURM_ERROR;
  604. }
  605. if (access(arch_cond->archive_script, X_OK) < 0) {
  606. errno = EACCES;
  607. error("archive_run_script: %s is not executable",
  608. arch_cond->archive_script);
  609. return SLURM_ERROR;
  610. }
  611. env = env_array_create();
  612. env_array_append_fmt(&env, "SLURM_ARCHIVE_CLUSTER", "%s",
  613. cluster_name);
  614. if(arch_cond->purge_event != NO_VAL) {
  615. if(!(curr_end = archive_setup_end_time(
  616. last_submit, arch_cond->purge_event))) {
  617. error("Parsing purge events failed");
  618. return SLURM_ERROR;
  619. }
  620. env_array_append_fmt(&env, "SLURM_ARCHIVE_EVENTS", "%u",
  621. SLURMDB_PURGE_ARCHIVE_SET(
  622. arch_cond->purge_event));
  623. env_array_append_fmt(&env, "SLURM_ARCHIVE_LAST_EVENT", "%ld",
  624. (long)curr_end);
  625. }
  626. if(arch_cond->purge_job != NO_VAL) {
  627. if(!(curr_end = archive_setup_end_time(
  628. last_submit, arch_cond->purge_job))) {
  629. error("Parsing purge job failed");
  630. return SLURM_ERROR;
  631. }
  632. env_array_append_fmt(&env, "SLURM_ARCHIVE_JOBS", "%u",
  633. SLURMDB_PURGE_ARCHIVE_SET(
  634. arch_cond->purge_job));
  635. env_array_append_fmt(&env, "SLURM_ARCHIVE_LAST_JOB", "%ld",
  636. (long)curr_end);
  637. }
  638. if(arch_cond->purge_step != NO_VAL) {
  639. if(!(curr_end = archive_setup_end_time(
  640. last_submit, arch_cond->purge_step))) {
  641. error("Parsing purge step");
  642. return SLURM_ERROR;
  643. }
  644. env_array_append_fmt(&env, "SLURM_ARCHIVE_STEPS", "%u",
  645. SLURMDB_PURGE_ARCHIVE_SET(
  646. arch_cond->purge_step));
  647. env_array_append_fmt(&env, "SLURM_ARCHIVE_LAST_STEP", "%ld",
  648. (long)curr_end);
  649. }
  650. if(arch_cond->purge_suspend != NO_VAL) {
  651. if(!(curr_end = archive_setup_end_time(
  652. last_submit, arch_cond->purge_suspend))) {
  653. error("Parsing purge suspend");
  654. return SLURM_ERROR;
  655. }
  656. env_array_append_fmt(&env, "SLURM_ARCHIVE_SUSPEND", "%u",
  657. SLURMDB_PURGE_ARCHIVE_SET(
  658. arch_cond->purge_suspend));
  659. env_array_append_fmt(&env, "SLURM_ARCHIVE_LAST_SUSPEND", "%ld",
  660. (long)curr_end);
  661. }
  662. #ifdef _PATH_STDPATH
  663. env_array_append (&env, "PATH", _PATH_STDPATH);
  664. #else
  665. env_array_append (&env, "PATH", "/bin:/usr/bin");
  666. #endif
  667. execve(arch_cond->archive_script, args, env);
  668. env_array_free(env);
  669. return SLURM_SUCCESS;
  670. }
  671. static char *_make_archive_name(time_t period_start, time_t period_end,
  672. char *cluster_name, char *arch_dir,
  673. char *arch_type, uint32_t archive_period)
  674. {
  675. struct tm time_tm;
  676. char start_char[32];
  677. char end_char[32];
  678. localtime_r((time_t *)&period_start, &time_tm);
  679. time_tm.tm_sec = 0;
  680. time_tm.tm_min = 0;
  681. /* set up the start time based off the period we are purging */
  682. if(SLURMDB_PURGE_IN_HOURS(archive_period)) {
  683. } else if(SLURMDB_PURGE_IN_DAYS(archive_period)) {
  684. time_tm.tm_hour = 0;
  685. } else {
  686. time_tm.tm_hour = 0;
  687. time_tm.tm_mday = 1;
  688. }
  689. snprintf(start_char, sizeof(start_char),
  690. "%4.4u-%2.2u-%2.2u"
  691. "T%2.2u:%2.2u:%2.2u",
  692. (time_tm.tm_year + 1900),
  693. (time_tm.tm_mon+1),
  694. time_tm.tm_mday,
  695. time_tm.tm_hour,
  696. time_tm.tm_min,
  697. time_tm.tm_sec);
  698. localtime_r((time_t *)&period_end, &time_tm);
  699. snprintf(end_char, sizeof(end_char),
  700. "%4.4u-%2.2u-%2.2u"
  701. "T%2.2u:%2.2u:%2.2u",
  702. (time_tm.tm_year + 1900),
  703. (time_tm.tm_mon+1),
  704. time_tm.tm_mday,
  705. time_tm.tm_hour,
  706. time_tm.tm_min,
  707. time_tm.tm_sec);
  708. /* write the buffer to file */
  709. return xstrdup_printf("%s/%s_%s_archive_%s_%s",
  710. arch_dir, cluster_name, arch_type,
  711. start_char, end_char);
  712. }
  713. extern int archive_write_file(Buf buffer, char *cluster_name,
  714. time_t period_start, time_t period_end,
  715. char *arch_dir, char *arch_type,
  716. uint32_t archive_period)
  717. {
  718. int fd = 0;
  719. int rc = SLURM_SUCCESS;
  720. char *old_file = NULL, *new_file = NULL, *reg_file = NULL;
  721. static int high_buffer_size = (1024 * 1024);
  722. static pthread_mutex_t local_file_lock = PTHREAD_MUTEX_INITIALIZER;
  723. xassert(buffer);
  724. slurm_mutex_lock(&local_file_lock);
  725. /* write the buffer to file */
  726. reg_file = _make_archive_name(period_start, period_end,
  727. cluster_name, arch_dir,
  728. arch_type, archive_period);
  729. debug("Storing %s archive for %s at %s",
  730. arch_type, cluster_name, reg_file);
  731. old_file = xstrdup_printf("%s.old", reg_file);
  732. new_file = xstrdup_printf("%s.new", reg_file);
  733. fd = creat(new_file, 0600);
  734. if (fd < 0) {
  735. error("Can't save archive, create file %s error %m", new_file);
  736. rc = SLURM_ERROR;
  737. } else {
  738. int pos = 0, nwrite = get_buf_offset(buffer), amount;
  739. char *data = (char *)get_buf_data(buffer);
  740. high_buffer_size = MAX(nwrite, high_buffer_size);
  741. while (nwrite > 0) {
  742. amount = write(fd, &data[pos], nwrite);
  743. if ((amount < 0) && (errno != EINTR)) {
  744. error("Error writing file %s, %m", new_file);
  745. rc = SLURM_ERROR;
  746. break;
  747. }
  748. nwrite -= amount;
  749. pos += amount;
  750. }
  751. fsync(fd);
  752. close(fd);
  753. }
  754. if (rc)
  755. (void) unlink(new_file);
  756. else { /* file shuffle */
  757. (void) unlink(old_file);
  758. if (link(reg_file, old_file))
  759. debug4("Link(%s, %s): %m", reg_file, old_file);
  760. (void) unlink(reg_file);
  761. if (link(new_file, reg_file))
  762. debug4("Link(%s, %s): %m", new_file, reg_file);
  763. (void) unlink(new_file);
  764. }
  765. xfree(old_file);
  766. xfree(reg_file);
  767. xfree(new_file);
  768. slurm_mutex_unlock(&local_file_lock);
  769. return rc;
  770. }