forked from openpbs/openpbs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pbs_python_svr_internal.c
12650 lines (11095 loc) · 355 KB
/
pbs_python_svr_internal.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 1994-2020 Altair Engineering, Inc.
* For more information, contact Altair at www.altair.com.
*
* This file is part of both the OpenPBS software ("OpenPBS")
* and the PBS Professional ("PBS Pro") software.
*
* Open Source License Information:
*
* OpenPBS is free software. You can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* OpenPBS is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Commercial License Information:
*
* PBS Pro is commercially licensed software that shares a common core with
* the OpenPBS software. For a copy of the commercial license terms and
* conditions, go to: (http://www.pbspro.com/agreement.html) or contact the
* Altair Legal Department.
*
* Altair's dual-license business model allows companies, individuals, and
* organizations to create proprietary derivative works of OpenPBS and
* distribute them - whether embedded or bundled with other software -
* under a commercial license agreement.
*
* Use of Altair's trademarks, including but not limited to "PBS™",
* "OpenPBS®", "PBS Professional®", and "PBS Pro™" and Altair's logos is
* subject to Altair's trademark licensing policies.
*/
/**
* @file pbs_python_svr_internal.c
* @brief
* This are the internal helper functions that depend on a lot of PBS
* Server Data structures.
*
*/
#include <pbs_config.h> /* the master config generated by configure */
#include <pbs_python_private.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <memory.h>
#include <stdlib.h>
#include <libpbs.h>
#include <pbs_ifl.h>
#include <errno.h>
#include <string.h>
#include <list_link.h>
#include <log.h>
#include <attribute.h>
#include <resource.h>
#include <server_limits.h>
#include <server.h>
#include <job.h>
#include <reservation.h>
#include <queue.h>
#include <pbs_error.h>
#include <batch_request.h>
#include <provision.h>
#include "hook.h"
#include "pbs_nodes.h"
#include "cmds.h"
#include "svrfunc.h"
#include "pbs_ecl.h"
#include "placementsets.h"
#include "pbs_reliable.h"
/* ----- GLOBALS ----- */
/* pipe-separated string lists */
#define runjob_modifiable_jobattrs ATTR_h "|" ATTR_a "|" ATTR_project "|" ATTR_e "|" ATTR_o "|" ATTR_l "|" ATTR_v "|" ATTR_depend "|" ATTR_create_resv_from_job
#define runjob_modifiable_vnattrs ATTR_NODE_state
#define FMT_RUNJOB_ERRMSG "Can only set job's (%s) attribute, or a vnode's (%s) attribute under RUNJOB event - got <%s>"
extern attribute_def que_attr_def[];
extern resource_def *svr_resc_def; /* the resource def structure */
extern int svr_resc_size; /* static + dynamic */
extern int svr_resc_unk; /* the last one */
extern char server_name[];
extern char server_host[];
extern struct python_interpreter_data svr_interp_data;
extern pbs_list_head svr_queues; /* list of queues */
extern pbs_list_head svr_alljobs; /* list of all jobs in server */
extern pbs_list_head svr_allresvs; /* all reservations in server */
extern char *msg_man_set;
extern char *path_hooks_workdir;
/* Global symbols */
extern char *vnode_state_to_str(int state_bit);
extern char *vnode_sharing_to_str(enum vnode_sharing share);
extern char *vnode_ntype_to_str(int vntype);
extern int str_to_vnode_state(char *vnstate);
extern enum vnode_sharing str_to_vnode_sharing(char *vn_str);
extern int str_to_vnode_ntype(char *vntype);
extern u_Long pps_size_to_kbytes(PyObject *l);
extern PyObject * svrattrl_list_to_pyobject(pbs_list_head *);
extern PyObject * svrattrl_to_server_attribute(svrattrl *);
/* A dictionary for quick access to the pbs.v1 EMBEDDED_EXTENSION_TYPES */
static
PyObject *PBS_PythonTypes = NULL; /* A dictionary maintaing name and type */
/*
* BEGIN Quick Access Types Table
* The below code is a convenience scheme, not really needed as they are
* available in the PBS_PythonTypes dict. But, since we do this for every
* aggregate type, comes in handy.
*/
typedef struct _pbs_python_types_entry {
char *t_key; /* The key in EXPORTED TYPES DICTIONARY */
PyObject *t_class; /* The actual type or class */
} pbs_python_types_entry;
#define PP_DESC_IDX 0
#define PP_GENERIC_IDX 1
#define PP_SIZE_IDX 2
#define PP_TIME_IDX 3
#define PP_ACL_IDX 4
#define PP_BOOL_IDX 5
#define PP_JOB_IDX 6
#define PP_QUE_IDX 7
#define PP_SVR_IDX 8
#define PP_RESV_IDX 9
#define PP_EVENT_IDX 10
#define PP_RESC_IDX 11
#define PP_ARST_IDX 12
#define PP_INT_IDX 13
#define PP_STR_IDX 14
#define PP_FLOAT_IDX 15
#define PP_EVENT_ERR_IDX 16
#define PP_UNSET_ATTR_NAME_ERR_IDX 17
#define PP_BADATTR_VTYPE_ERR_IDX 18
#define PP_BADATTR_VALUE_ERR_IDX 19
#define PP_UNSET_RESC_NAME_ERR_IDX 20
#define PP_BAD_RESC_VTYPE_ERR_IDX 21
#define PP_BAD_RESC_VALUE_ERR_IDX 22
#define PP_PBS_ITER_IDX 23
#define PP_VNODE_IDX 24
#define PP_ENTITY_IDX 25
#define PP_ENV_IDX 26
#define PP_MANAGEMENT_IDX 27
#define PP_SERVER_ATTRIBUTE_IDX 28
pbs_python_types_entry pbs_python_types_table [] = {
{PY_TYPE_ATTR_DESCRIPTOR, NULL}, /* 0 Always first */
{PY_TYPE_GENERIC, NULL},
{PY_TYPE_SIZE, NULL},
{PY_TYPE_TIME, NULL},
{PY_TYPE_ACL, NULL},
{PY_TYPE_BOOL, NULL},
{PY_TYPE_JOB, NULL},
{PY_TYPE_QUEUE, NULL},
{PY_TYPE_SERVER, NULL},
{PY_TYPE_RESV, NULL},
{PY_TYPE_EVENT, NULL}, /* 10 */
{PY_TYPE_RESOURCE, NULL},
{PY_TYPE_LIST, NULL},
{PY_TYPE_INT, NULL},
{PY_TYPE_STR, NULL},
{PY_TYPE_FLOAT, NULL}, /* 15 */
{PY_ERROR_EVENT_INCOMPATIBLE, NULL}, /* 16 */
{PY_ERROR_EVENT_UNSET_ATTRIBUTE, NULL}, /* 17 */
{PY_ERROR_BAD_ATTRIBUTE_VALUE_TYPE, NULL}, /* 18 */
{PY_ERROR_BAD_ATTRIBUTE_VALUE, NULL}, /* 19 */
{PY_ERROR_UNSET_RESOURCE, NULL}, /* 20 */
{PY_ERROR_BAD_RESOURCE_VALUE_TYPE, NULL}, /* 21 */
{PY_ERROR_BAD_RESOURCE_VALUE, NULL}, /* 22 */
{PY_TYPE_PBS_ITER, NULL}, /* 23 */
{PY_TYPE_VNODE, NULL}, /* 24 */
{PY_TYPE_ENTITY, NULL}, /* 25 */
{PY_TYPE_ENV, NULL}, /* 26 */
{PY_TYPE_MANAGEMENT, NULL}, /* 27 */
{PY_TYPE_SERVER_ATTRIBUTE, NULL}, /* 28 */
/* ADD ENTRIES ONLY BELOW, OR CHANGE THE PP_XXX_IDX above the table */
{NULL, NULL} /* sentinel */
};
typedef struct _pbs_iter_item {
PyObject *py_iter; /* *the* iterator */
void *data; /* arbitrary pbs data */
int data_index; /* index of data to some table */
pbs_list_link all_iters;
} pbs_iter_item;
static pbs_list_head pbs_iter_list; /* list of PBS iterators */
typedef struct _vnode_set_req {
char vnode_name[PBS_MAXNODENAME+1];
pbs_list_head rq_attr; /* list of attributes to set */
pbs_list_link all_reqs;
} vnode_set_req;
static pbs_list_head pbs_vnode_set_list; /* list of vnode set requests */
/**
* @brief
* The pbs_resource_value structure holds the cached resource values for
* Python py_resource object.
*
* @param[in] py_resource - the Python pbs_resource object that will later
* be set with values in 'value_list'.
* @param[in] py_resource_str_value - a Python string object representing
* the values in 'value_list'.
* @param[in] attr_def_p - the resource definition for the resource list
* represented by 'py_resource'.
* @param[in] value_list - list of values cached for the 'py_resource' object
* @param[in] all_resc - links various pbs_resource_value structures.
*/
typedef struct _pbs_resource_value {
PyObject *py_resource;
PyObject *py_resource_str_value;
attribute_def *attr_def_p; /* corresponding resource definition */
pbs_list_head value_list; /* resource values to set */
pbs_list_link all_rescs;
} pbs_resource_value;
static pbs_list_head pbs_resource_value_list; /* list of resource */
/* values to instantiate */
static PyObject *PyPbsV1Module_Obj = NULL; /* pbs.v1 module object */
/* an array holding all the vnode attribute descriptors (python pointers) */
static PyObject **py_vnode_attr_types = NULL;
/* an array holding all the resv attribute descriptors (python pointers) */
static PyObject **py_resv_attr_types = NULL;
/* an array holding all the server attribute descriptors (python pointers) */
static PyObject **py_svr_attr_types = NULL;
/* an array holding all the job attribute descriptors (python pointers) */
static PyObject **py_job_attr_types = NULL;
/* an array holding all the queue attribute descriptors (python pointers) */
static PyObject **py_que_attr_types = NULL;
/* an array of python objects holding all the resources (python pointers)*/
static PyObject **py_svr_resc_types = NULL;
/* The function object that instantiates/populates a PBS object using */
static PyObject *py_pbs_statobj = NULL;
/* This is the current hook event object */
static PyObject *py_hook_pbsevent = NULL;
/* This is the cached local/server object */
static PyObject *py_hook_pbsserver = NULL;
/* An array of cached Python queue objects managed by the current server */
static PyObject **py_hook_pbsque = NULL;
static int py_hook_pbsque_max = 0; /* Max # of entries in py_hook_pbsque */
static int hook_pbsevent_accept = TRUE; /* flag to accept/reject event */
static int hook_pbsevent_stop_processing = FALSE; /* flag to stop */
/* processing event */
/* parameters */
static char hook_pbsevent_reject_msg[HOOK_MSG_SIZE];
static int hook_set_mode = C_MODE; /* in C_MODE, can set*/
/* anything */
static int hook_reboot_host = FALSE; /* flag to reboot host or not */
static int hook_reboot_host_cmd[HOOK_BUF_SIZE]; /* cmdline to use */
/* to reboot host */
/* as alternate to */
/* reboot() call */
static int hook_scheduler_restart_cycle = FALSE; /* flag to tell local */
/* server to tell the */
/* scheduler to */
/* restart sched cycle*/
/*
* The following limit and counter declarations are intended
* to reduce the amount of memory consumed by the Python
* interpreter so that the server process does not become
* bloated. Python is able to garbage collect builtin
* types (e.g. string, dict, etc.), but the PBS types are
* not created such that their memory can be released.
*/
/* Max hook events to service before restarting the interpreter */
#define PBS_PYTHON_RESTART_MAX_HOOKS 100
/* Max objects created before restarting the interpreter */
#define PBS_PYTHON_RESTART_MAX_OBJECTS 1000
/* Minimum interval between interpreter restarts */
#define PBS_PYTHON_RESTART_MIN_INTERVAL 30
/* count of Python objects created */
static long object_counter = 0;
typedef struct hook_debug_t {
FILE *input_fp;
char input_file[MAXPATHLEN+1];
FILE *output_fp;
char output_file[MAXPATHLEN+1];
FILE *data_fp;
char data_file[MAXPATHLEN+1];
char objname[HOOK_BUF_SIZE+1];
} hook_debug_t;
static int use_static_data = 0; /* use static server-related data */
static hook_debug_t hook_debug;
static pbs_list_head *server_data;
typedef struct server_jobs_t {
pbs_list_head *data;
pbs_list_head *ids;
} server_jobs_t;
static server_jobs_t server_jobs;
typedef struct server_queues_t {
pbs_list_head *data;
pbs_list_head *names;
} server_queues_t;
static server_queues_t server_queues;
typedef struct server_resvs_t {
pbs_list_head *data;
pbs_list_head *resvids;
} server_resvs_t;
static server_resvs_t server_resvs;
typedef struct server_vnodes_t {
pbs_list_head *data;
pbs_list_head *names;
} server_vnodes_t;
static server_vnodes_t server_vnodes;
/**
* @brief
* This is a function that logs the contents of the list
* headed by 'phead'.
*
* @param[in] head_str - some string that gets printed spearheading the list.
* @param[in] phead - header of the list to be printed.
*
* @return void
*
*/
void
print_svrattrl_list(char *head_str, pbs_list_head *phead)
{
svrattrl *plist = NULL;
int i;
if ((head_str == NULL) || (phead == NULL)) {
return;
}
if (!will_log_event(PBSEVENT_DEBUG3))
return;
plist = (svrattrl *)GET_NEXT(*phead);
i = 0;
log_event(PBSEVENT_DEBUG3, PBS_EVENTCLASS_HOOK, LOG_INFO, __func__, head_str);
while (plist) {
snprintf(log_buffer, LOG_BUF_SIZE-1,
#ifdef NAS /* localmod 005 */
"al_name=%s al_resc=%s al_value=%s al_flags=%ld",
plist->al_name, plist->al_resc?plist->al_resc:"null",
plist->al_value, (long)plist->al_flags);
#else
"al_name=%s al_resc=%s al_value=%s al_flags=%d",
plist->al_name, plist->al_resc?plist->al_resc:"null",
plist->al_value, plist->al_flags);
#endif /* localmod 005 */
log_buffer[LOG_BUF_SIZE-1] = '\0';
log_event(PBSEVENT_DEBUG3, PBS_EVENTCLASS_HOOK, LOG_INFO, __func__,
log_buffer);
plist = (svrattrl *)GET_NEXT(plist->al_link);
i++;
}
}
/**
* @brief
* This is a stub function that should be implemented to add any additional
* elements to the global namespace dict.
*
* @param[in] globals - python object indicating reference to globals of a module
*
* @return int
* @retval 0 success
* @retval -1 error
*
*/
int
pbs_python_setup_namespace_dict(PyObject *globals)
{
#if 0 /* enable later */
/*
* First, insert our module object pbs.v1 as pbs so the hook scripts
* can access all the globals
*/
/* I believe our design REQUIRES hook write to issue a "import pbs" */
if ((PyDict_SetItemString(globals, "pbs", PyPbsV1Module_Obj) == -1)) {
goto ERROR_EXIT;
}
return 0;
ERROR_EXIT:
pbs_python_write_error_to_log("pbs_python_setup_namespace_dict");
return -1;
#endif
return 0;
}
/**
* @brief
* The C routine that will instantiate a PbsAttributeDescriptor
* class (see src/modules/_base_types.py), which wraps a
* PBS attribute into a descriptor.
*
* @param[in] klass-the class attribute being wrapped into a data descriptor.
* @param[in] name - name of a PBS attribute.
* @param[in] default_value - given to the PBS attribute.
* @param[in] val_klass - the class/object type of the attribute's value.
* @param[in] resc_attr - if the attribute being wrapped is a pbs_resource,
* then this is the name of its parent.
* For example: name="ncpus", resc_attr="Resource_List"
* @param[in] is_entity - if the attribute being wrapped is also an
* entity type.
* For example: name="ncpus", resc_attr="max_run_res",
* is_entity=1.
* @return int
* @retval -1 Failed to create descriptor.
* @retval 0 Successfully created descriptor.
* @retval 1 Descriptor already present.
*
*/
static int
_pps_getset_descriptor_object(PyObject *klass,
const char *name,
PyObject *default_value,
PyObject *val_klass,
const char *resc_attr,
int is_entity)
{
/* this is for constructor call , see _base_types.py */
static char *kwds[] = {"cls", "name", "default_value", "value_type",
"resc_attr", "is_entity"};
PyObject *py_descr_class = NULL;
PyObject *py_descr_args = PyTuple_New(0);
PyObject *py_descr_kwds = NULL;
PyObject *py_attr_descr = NULL;
/* check we creation of tuple failed */
if (!(py_descr_args)) {
goto ERROR_EXIT;
}
/* check whether the attribute descriptor is already present */
if (PyObject_HasAttrString(klass, name)) {
Py_CLEAR(py_descr_args);
return 1;
}
py_descr_class = pbs_python_types_table[PP_DESC_IDX].t_class;
/* good, build the arument list NEW ref
* class, name, default_value, value_class
*/
if (resc_attr) { /* ok we are creating a attribute for a resource */
py_descr_kwds = Py_BuildValue("{s:O, s:s, s:O, s:(O), s:s, s:i}",
kwds[0], klass,
kwds[1], name,
kwds[2], default_value,
kwds[3], val_klass,
kwds[4], resc_attr,
kwds[5], is_entity
);
} else {
py_descr_kwds = Py_BuildValue("{s:O, s:s, s:O, s:(O), s:i}",
kwds[0], klass,
kwds[1], name,
kwds[2], default_value,
kwds[3], val_klass,
kwds[5], is_entity
);
}
if (!py_descr_kwds) {
goto ERROR_EXIT;
}
py_attr_descr = PyObject_Call(py_descr_class, py_descr_args, py_descr_kwds);
if (!py_attr_descr) {
goto ERROR_EXIT;
}
Py_CLEAR(py_descr_args);
Py_CLEAR(py_descr_kwds);
/* now set the class attribute */
if ((PyObject_SetAttrString(klass, name, py_attr_descr) == -1)) {
goto ERROR_EXIT;
}
/* we don't need the descriptor any more */
Py_CLEAR(py_attr_descr);
return 0;
ERROR_EXIT:
pbs_python_write_error_to_log(__func__);
Py_CLEAR(py_descr_args);
Py_CLEAR(py_descr_kwds);
Py_CLEAR(py_attr_descr);
return -1;
}
/*
* pbs_python_get_python_type:
* This is the bulk where all the magic happens regarding the mapping from
* PBS to python types.
*
* returns:
* - A Borrowed Reference.
*/
/* TODO
* -big assumption, hopefully the DURATION/TIME encoding routine is
* not overloaded.
* -Make sure all types are there
*/
#define TYPE_DURATION(p) (((p) == encode_time) )
#define TYPE_SIZE(p) (((p) == ATR_TYPE_SIZE) )
#define TYPE_ACL(p) (((p) == ATR_TYPE_ACL) )
#define TYPE_BOOL(p) (((p) == ATR_TYPE_BOOL) )
#define TYPE_ARST(p) (((p) == ATR_TYPE_ARST) )
#define TYPE_RESC(p) (((p) == ATR_TYPE_RESC) )
#define TYPE_INT(p) ( ( ((p) == ATR_TYPE_LONG) || \
((p) == ATR_TYPE_SHORT) || \
((p) == ATR_TYPE_CHAR) ) )
#define TYPE_STR(p) ( ((p) == ATR_TYPE_STR) || \
((p) == ATR_TYPE_JINFOP) )
#define TYPE_FLOAT(p) (((p) == ATR_TYPE_FLOAT) )
#define TYPE_ENTITY(p) (((p) == ATR_TYPE_ENTITY) )
#define ATTR_IS_RESC(a) ( TYPE_RESC((a)->at_type) || \
( TYPE_ENTITY((a)->at_type) && \
((a)->at_decode == decode_entlim_res) ) )
/*
* TODO
* - It is possible to combine pbs_python_setup_resc_get_value_type
* and pbs_python_setup_attr_get_value_type into a macro.
*/
/*
* NO exception raised
*/
/**
* @brief
* given the resource definition return the corresponding python type.
*
* @param[in] resc_def_p - pointer to resource_def indicating resource list
*
* @return pointer PyObject
* @retval resource table success
* @retval return generic failure
*
*/
static PyObject *
pbs_python_setup_resc_get_value_type(resource_def *resc_def_p)
{
PyObject *py_tmp = NULL; /* return value */
/* check if we are special aka check PBS_PythonTypes first */
py_tmp = PyDict_GetItemString(PBS_PythonTypes, resc_def_p->rs_name);
if (py_tmp)
return py_tmp; /* cool, we are special */
/* careful long is overloadded so duration comes first */
if (TYPE_DURATION(resc_def_p->rs_encode)) /* check for time type */
return pbs_python_types_table[PP_TIME_IDX].t_class;
if (TYPE_SIZE(resc_def_p->rs_type)) /* check for SIZE type */
return pbs_python_types_table[PP_SIZE_IDX].t_class;
if (TYPE_ACL(resc_def_p->rs_type)) /* check for ACL type */
return pbs_python_types_table[PP_ACL_IDX].t_class;
if (TYPE_BOOL(resc_def_p->rs_type)) /* check for BOOL type */
return pbs_python_types_table[PP_BOOL_IDX].t_class;
if (TYPE_ARST(resc_def_p->rs_type)) /* check for list of strings */
return pbs_python_types_table[PP_ARST_IDX].t_class;
if (TYPE_INT(resc_def_p->rs_type)) /* check for int,long,short type */
return pbs_python_types_table[PP_INT_IDX].t_class;
if (TYPE_STR(resc_def_p->rs_type)) /* check for str type */
return pbs_python_types_table[PP_STR_IDX].t_class;
if (TYPE_FLOAT(resc_def_p->rs_type)) /* check for float type */
return pbs_python_types_table[PP_FLOAT_IDX].t_class;
if (TYPE_ENTITY(resc_def_p->rs_type)) /* check for entity type */
return pbs_python_types_table[PP_ENTITY_IDX].t_class;
/* all else fails return generic */
return pbs_python_types_table[PP_GENERIC_IDX].t_class;
}
/**
* @brief
* Given an attribute defintion, return the corresponding Python type.
*
* @param[in] attr_def_p - an attribute_def type.
* @param[in] py_type - a python type in string: "job", "server",
* "queue", "resv", or "vnode".
* @return PyObject *
*/
static PyObject *
pbs_python_setup_attr_get_value_type(attribute_def *attr_def_p, char *py_type)
{
PyObject *py_tmp = NULL; /* return value */
/* check if we are special aka check PBS_PythonTypes first */
if ((strcmp(py_type, PY_TYPE_VNODE) != 0) ||
(strcmp(attr_def_p->at_name, ATTR_p) != 0)) {
/* Only get the type from PBS_PythonTypes if not the vnode's Priority */
/* attribute which is treated as a Python int instead of the */
/* pbs.priority type mapped in PBS_Python_Types. */
py_tmp = PyDict_GetItemString(PBS_PythonTypes, attr_def_p->at_name);
if (py_tmp)
return py_tmp; /* cool, we are special */
}
/* careful long is overloadded so duration comes first */
if (TYPE_DURATION(attr_def_p->at_encode)) /* check for time type */
return pbs_python_types_table[PP_TIME_IDX].t_class;
if (ATTR_IS_RESC(attr_def_p))
return pbs_python_types_table[PP_RESC_IDX].t_class;
if (TYPE_SIZE(attr_def_p->at_type)) /* check for SIZE type */
return pbs_python_types_table[PP_SIZE_IDX].t_class;
if (TYPE_ACL(attr_def_p->at_type)) /* check for ACL type */
return pbs_python_types_table[PP_ACL_IDX].t_class;
if (TYPE_BOOL(attr_def_p->at_type)) /* check for BOOL type */
return pbs_python_types_table[PP_BOOL_IDX].t_class;
if (TYPE_ARST(attr_def_p->at_type)) /* check for list of strings */
return pbs_python_types_table[PP_ARST_IDX].t_class;
if (TYPE_INT(attr_def_p->at_type)) /* check for int,long,short */
return pbs_python_types_table[PP_INT_IDX].t_class;
if (TYPE_STR(attr_def_p->at_type)) /* check for str type */
return pbs_python_types_table[PP_STR_IDX].t_class;
if (TYPE_FLOAT(attr_def_p->at_type)) /* check for float type */
return pbs_python_types_table[PP_FLOAT_IDX].t_class;
if (TYPE_ENTITY(attr_def_p->at_type)) /* check for entity type */
return pbs_python_types_table[PP_ENTITY_IDX].t_class;
/* all else fails return generic */
return pbs_python_types_table[PP_GENERIC_IDX].t_class;
}
/**
* @brief
* pbs_python_free_py_types_array
* This frees up the global arrays
*
* @param[in] py_types_array - address reference to globals
*
* @return Void
*/
void
pbs_python_free_py_types_array(PyObject ***py_types_array)
{
PyObject **py_array_tmp = *py_types_array;
PyObject *py_tmp = NULL;
if (*py_types_array) {
while ((py_tmp = *py_array_tmp)) {
Py_CLEAR(py_tmp);
py_array_tmp++;
}
}
PyMem_Free(*py_types_array);
*py_types_array = NULL; /* since we might be called again */
return;
}
/**
* @brief
* makes a call to given python object klass and maskes default value
*
* @param[in] klass - function
* @param[in] args - arguments for function
*
* @return PyObject *
*
*/
PyObject *
pbs_python_make_default_value(PyObject *klass, PyObject *args)
{
PyObject *py_default_value;
py_default_value = PyObject_Call(klass, args, NULL);
if (!py_default_value) {
goto ERROR_EXIT;
}
return py_default_value;
ERROR_EXIT:
pbs_python_write_error_to_log("could not make default value");
return NULL;
}
/**
* @brief
* Routine that actualizes *all* the attributes for a Python vnode object.
*
* @par Functionality:
* This takes input from node_attr_def[] and svr_resc_defm[] tables.
* Each attribute is setup as a descriptor for finer granularity of
* control.
*
* @return int
* @retval 0 : Successful execution of this function, with internal
* 'py_vnode_attr_types' list populated.
* @retval -1 " On failutre to populate 'py_vnode_attr_types' list.
*/
int
pbs_python_setup_vnode_class_attributes(void)
{
int i = 0;
attribute_def *attr_def_p = NULL; /* convenience pointer */
PyObject *py_pbs_vnode_klass = pbs_python_types_table[PP_VNODE_IDX].t_class;
PyObject *py_value_type = NULL;
PyObject *py_default_value = NULL;
PyObject *py_default_args = NULL;
int num_entry = ND_ATR_LAST+1; /* 1 for sentinel */
int te;
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("BEGIN setting up all vnode attributes %s", "");
else
DEBUG2_ARG1("BEGIN setting up all vnode attributes %s", "");
py_vnode_attr_types = PyMem_New(PyObject *, num_entry);
if (py_vnode_attr_types == NULL)
goto ERROR_EXIT;
memset(py_vnode_attr_types, 0, sizeof(PyObject *) * num_entry);
/* ok now set all the node_attr_def types known to the server */
attr_def_p = node_attr_def;
for (i = 0; i < ND_ATR_LAST; i++) {
/* get the value type for this attribute */
py_value_type = pbs_python_setup_attr_get_value_type(attr_def_p,
PY_TYPE_VNODE);
/* create a brand new default value from value type */
if (ATTR_IS_RESC(attr_def_p)) {
py_default_args = Py_BuildValue("(s)", attr_def_p->at_name);
if (py_default_args == NULL) {
log_err(-1, attr_def_p->at_name, "could not build args for default value");
continue;
}
py_default_value = pbs_python_make_default_value(py_value_type, py_default_args);
Py_DECREF(py_default_args);
if (py_default_value == NULL) {
log_err(-1, attr_def_p->at_name, "could not set default value");
continue;
}
te = TYPE_ENTITY(attr_def_p->at_type);
} else {
py_default_value = Py_None;
te = 0;
}
if (_pps_getset_descriptor_object(py_pbs_vnode_klass,
attr_def_p->at_name,
py_default_value,
py_value_type, NULL, te) == -1)
goto ERROR_EXIT;
Py_INCREF(py_value_type);
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
py_vnode_attr_types[i] = py_value_type;
attr_def_p++;
}
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("DONE setting up all vnode attributes, number set <%d>", i);
else
DEBUG2_ARG1("DONE setting up all vnode attributes, number set <%d>", i);
return 0;
ERROR_EXIT:
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
snprintf(log_buffer, LOG_BUF_SIZE-1,
"could not set attribute <%s> for vnode python class", attr_def_p->at_name);
log_buffer[LOG_BUF_SIZE-1] = '\0';
log_err(-1, __func__, log_buffer);
return -1;
}
/**
* @brief
* pbs_python_setup_resv_class_attributes
* routine that sets up *all* the attributes for a Python server Object
* mapping directly to PBS Job object (struct job)
*
* @return int
* @retval -1 : failure
* @retval 0 : success
*/
int
pbs_python_setup_resv_class_attributes(void)
{
int i = 0;
attribute_def *attr_def_p = NULL; /* convenience pointer */
PyObject *py_pbs_resv_klass = pbs_python_types_table[PP_RESV_IDX].t_class;
PyObject *py_value_type = NULL;
PyObject *py_default_value = NULL;
PyObject *py_default_args = NULL;
int num_entry = RESV_ATR_LAST+1; /* 1 for sentinel */
int te;
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("BEGIN setting up all reservation attributes %s", "");
else
DEBUG2_ARG1("BEGIN setting up all reservation attributes %s", "");
py_resv_attr_types = PyMem_New(PyObject *, num_entry);
if (!py_resv_attr_types) { goto ERROR_EXIT;}
memset(py_resv_attr_types, 0, sizeof(PyObject *) * num_entry);
/* ok now set all the resv_attr_def types known to the server */
attr_def_p = resv_attr_def;
for (i = 0; i < RESV_ATR_LAST; i++) {
/* get the value type for this attribute */
py_value_type = pbs_python_setup_attr_get_value_type(attr_def_p,
PY_TYPE_RESV);
/* create a brand new default value from value type */
if (ATTR_IS_RESC(attr_def_p)) {
py_default_args = Py_BuildValue("(s)", attr_def_p->at_name);
if (!py_default_args) {
/* TODO, continuing instead of fatal error */
log_err(-1, attr_def_p->at_name, "could not build args for default value");
continue;
}
py_default_value = pbs_python_make_default_value(py_value_type, py_default_args);
Py_DECREF(py_default_args);
if (!py_default_value) {
/* TODO, continuing instead of fatal error */
log_err(-1, attr_def_p->at_name, "could not set default value");
continue;
}
te = TYPE_ENTITY(attr_def_p->at_type);
} else {
py_default_value = Py_None;
te = 0;
}
if (_pps_getset_descriptor_object(py_pbs_resv_klass,
attr_def_p->at_name,
py_default_value,
py_value_type, NULL, te) == -1)
goto ERROR_EXIT;
Py_INCREF(py_value_type);
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
py_resv_attr_types[i] = py_value_type;
attr_def_p++;
}
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("DONE setting up all reservation attributes, number set <%d>", i);
else
DEBUG2_ARG1("DONE setting up all reservation attributes, number set <%d>", i);
return 0;
ERROR_EXIT:
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
snprintf(log_buffer, LOG_BUF_SIZE-1,
"could not set attribute <%s> for reservation python class", attr_def_p->at_name);
log_buffer[LOG_BUF_SIZE-1] = '\0';
log_err(-1, __func__, log_buffer);
return -1;
}
/**
* @brief
* pbs_python_setup_svr_class_attributes
* routine that sets up *all* the attributes for a Python server Object
* mapping directly to PBS Job object (struct job)
*
* @return int
* @retval -1 : failure
* @retval 0 : success
*/
int
pbs_python_setup_server_class_attributes(void)
{
int i = 0;
attribute_def *attr_def_p = NULL; /* convenience pointer */
PyObject *py_pbs_svr_klass = pbs_python_types_table[PP_SVR_IDX].t_class;
PyObject *py_value_type = NULL;
PyObject *py_default_value = NULL;
PyObject *py_default_args = NULL;
int num_entry = SVR_ATR_LAST+1; /* 1 for sentinel */
int te;
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("BEGIN setting up all server attributes %s", "");
else
DEBUG2_ARG1("BEGIN setting up all server attributes %s", "");
py_svr_attr_types = PyMem_New(PyObject *, num_entry);
if (!py_svr_attr_types) { goto ERROR_EXIT;}
memset(py_svr_attr_types, 0, sizeof(PyObject *) * num_entry);
/* ok now set all the svr_attr_def types known to the server */
attr_def_p = svr_attr_def;
for (i = 0; i < SVR_ATR_LAST; i++) {
/* get the value type for this attribute */
py_value_type = pbs_python_setup_attr_get_value_type(attr_def_p,
PY_TYPE_SERVER);
/* create a brand new default value from value type */
if (ATTR_IS_RESC(attr_def_p)) {
py_default_args = Py_BuildValue("(s)", attr_def_p->at_name);
if (!py_default_args) {
/* TODO, continuing instead of fatal error */
log_err(-1, attr_def_p->at_name, "could not build args for default value");
continue;
}
py_default_value = pbs_python_make_default_value(py_value_type, py_default_args);
Py_DECREF(py_default_args);
if (!py_default_value) {
/* TODO, continuing instead of fatal error */
log_err(-1, attr_def_p->at_name, "could not set default value");
continue;
}
te = TYPE_ENTITY(attr_def_p->at_type);
} else {
py_default_value = Py_None;
te = 0;
}
if (_pps_getset_descriptor_object(py_pbs_svr_klass,
attr_def_p->at_name,
py_default_value,
py_value_type, NULL, te) == -1)
goto ERROR_EXIT;
Py_INCREF(py_value_type);
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
py_svr_attr_types[i] = py_value_type;
attr_def_p++;
}
if (IS_PBS_PYTHON_CMD(pbs_python_daemon_name))
DEBUG3_ARG1("DONE setting up all server attributes, number set <%d>", i);
else
DEBUG2_ARG1("DONE setting up all server attributes, number set <%d>", i);
return 0;
ERROR_EXIT:
if (py_default_value != Py_None)
Py_CLEAR(py_default_value);
snprintf(log_buffer, LOG_BUF_SIZE-1,
"could not set attribute <%s> for <server> python class", attr_def_p->at_name);
log_buffer[LOG_BUF_SIZE-1] = '\0';
log_err(-1, __func__, log_buffer);
return -1;
}
/**
* @brief
* pbs_python_setup_job_class_attributes
* routine that sets up *all* the attributes for a Python Job Object
* mapping directly to PBS Job object (struct job)
*
* @return int
* @retval -1 : failure
* @retval 0 : success
*/