blob: 9b556b4de13e4f9083ad644a8393d3b14952197e [file] [log] [blame]
/*****************************************************************************\
* cred.c - Slurm job and sbcast credential functions
*****************************************************************************
* Copyright (C) 2002-2007 The Regents of the University of California.
* Copyright (C) 2008-2010 Lawrence Livermore National Security.
* Copyright (C) SchedMD LLC.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Morris Jette <jette1@llnl.gov>.
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include "config.h"
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/time.h>
#include "slurm/slurm_errno.h"
#include "src/common/bitstring.h"
#include "src/common/group_cache.h"
#include "src/common/identity.h"
#include "src/common/job_resources.h"
#include "src/common/list.h"
#include "src/common/log.h"
#include "src/common/macros.h"
#include "src/common/plugin.h"
#include "src/common/plugrack.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_protocol_pack.h"
#include "src/common/slurm_time.h"
#include "src/common/uid.h"
#include "src/common/xassert.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/interfaces/cred.h"
#include "src/interfaces/gres.h"
#include "src/interfaces/switch.h"
typedef struct {
slurm_cred_t *(*cred_create) (slurm_cred_arg_t *cred_arg,
bool sign_it,
uint16_t protocol_version);
slurm_cred_t *(*cred_unpack) (buf_t *buffer,
uint16_t protocol_version);
char *(*create_net_cred) (void *addrs,
uint16_t protocol_version);
void *(*extract_net_cred) (char *net_cred,
uint16_t protocol_version);
sbcast_cred_t *(*sbcast_create) (sbcast_cred_arg_t *cred,
uint16_t protocol_version);
sbcast_cred_t *(*sbcast_unpack) (buf_t *buffer, bool verify,
uint16_t protocol_version);
} slurm_cred_ops_t;
/*
* These strings must be in the same order as the fields declared
* for slurm_cred_ops_t.
*/
static const char *syms[] = {
"cred_p_create",
"cred_p_unpack",
"cred_p_create_net_cred",
"cred_p_extract_net_cred",
"sbcast_p_create",
"sbcast_p_unpack",
};
static slurm_cred_ops_t ops;
static plugin_context_t *g_context = NULL;
static pthread_mutex_t g_context_lock = PTHREAD_MUTEX_INITIALIZER;
static time_t cred_restart_time = (time_t) 0;
static int cred_expire = DEFAULT_EXPIRATION_WINDOW;
static bool enable_nss_slurm = false;
static bool enable_send_gids = true;
/* Initialize the plugin. */
extern int cred_g_init(void)
{
char *tok;
char *plugin_type = "cred";
int retval = SLURM_SUCCESS;
char *type = NULL;
/*
* Avoid issues with configless if Slurm was built without MUNGE,
* as the process that fetches the configs will still trigger
* slurm_init(), which will default to cred/munge, which will
* then fail to initialize as the plugin will be missing.
*/
if (getenv("SLURM_CONFIG_FETCH")) {
xfree(slurm_conf.cred_type);
goto done;
}
/* 123456789012 */
if ((tok = xstrstr(slurm_conf.authinfo, "cred_expire="))) {
cred_expire = atoi(tok + 12);
if (cred_expire < 5) {
error("AuthInfo=cred_expire=%d invalid", cred_expire);
cred_expire = DEFAULT_EXPIRATION_WINDOW;
}
}
if (xstrcasestr(slurm_conf.launch_params, "enable_nss_slurm"))
enable_nss_slurm = true;
else if (xstrcasestr(slurm_conf.launch_params, "disable_send_gids"))
enable_send_gids = false;
/* allow the bare plugin name. also handle slurm type quirks */
type = slurm_conf.cred_type;
if (!xstrncmp(type, "auth/", 5) || !xstrncmp(type, "cred/", 5))
type += 5;
if (!xstrcmp(type, "slurm"))
type = xstrdup("auth/slurm");
else
type = xstrdup_printf("cred/%s", type);
slurm_mutex_lock(&g_context_lock);
if (cred_restart_time == (time_t) 0)
cred_restart_time = time(NULL);
if (g_context)
goto done;
g_context = plugin_context_create(plugin_type, type,
(void **) &ops, syms, sizeof(syms));
if (!g_context) {
error("cannot create %s context for %s",
plugin_type, slurm_conf.cred_type);
retval = SLURM_ERROR;
goto done;
}
done:
slurm_mutex_unlock(&g_context_lock);
xfree(type);
return(retval);
}
/* Terminate the plugin and release all memory. */
extern int cred_g_fini(void)
{
int rc;
if (!g_context)
return SLURM_SUCCESS;
rc = plugin_context_destroy(g_context);
g_context = NULL;
return rc;
}
extern int cred_expiration(void)
{
return cred_expire;
}
extern slurm_cred_t *slurm_cred_create(slurm_cred_arg_t *arg, bool sign_it,
uint16_t protocol_version)
{
slurm_cred_t *cred = NULL;
int i = 0, sock_recs = 0;
bool release_id = false;
identity_t fake_id = { .uid = arg->uid, .gid = arg->gid, .fake = true };
xassert(arg);
xassert(g_context);
if (arg->uid == SLURM_AUTH_NOBODY) {
error("%s: refusing to create job %u credential for invalid user nobody",
__func__, arg->step_id.job_id);
return NULL;
}
if (arg->gid == SLURM_AUTH_NOBODY) {
error("%s: refusing to create job %u credential for invalid group nobody",
__func__, arg->step_id.job_id);
return NULL;
}
if (arg->sock_core_rep_count) {
for (i = 0; i < arg->job_nhosts; i++) {
sock_recs += arg->sock_core_rep_count[i];
if (sock_recs >= arg->job_nhosts)
break;
}
i++;
}
arg->core_array_size = i;
if (!arg->id && (enable_nss_slurm || enable_send_gids)) {
release_id = true;
if (!(arg->id = fetch_identity(arg->uid, arg->gid,
enable_nss_slurm))) {
error("%s: fetch_identity() failed", __func__);
return NULL;
}
} else if (!arg->id) {
arg->id = &fake_id;
}
identity_debug2(arg->id, __func__);
cred = (*(ops.cred_create))(arg, sign_it, protocol_version);
/* Release any values populated through _fill_cred_gids(). */
if (release_id)
FREE_NULL_IDENTITY(arg->id);
return cred;
}
extern slurm_cred_t *slurm_cred_faker(slurm_cred_arg_t *arg)
{
/*
* Force this on to ensure pw_name, ngid, gids are all populated.
*/
enable_send_gids = true;
return slurm_cred_create(arg, true, SLURM_PROTOCOL_VERSION);
}
extern void slurm_cred_free_args(slurm_cred_arg_t *arg)
{
if (!arg)
return;
FREE_NULL_IDENTITY(arg->id);
FREE_NULL_BITMAP(arg->job_core_bitmap);
FREE_NULL_BITMAP(arg->step_core_bitmap);
xfree(arg->cores_per_socket);
xfree(arg->cpu_array);
xfree(arg->cpu_array_reps);
FREE_NULL_LIST(arg->job_gres_list);
FREE_NULL_LIST(arg->step_gres_list);
xfree(arg->step_hostlist);
xfree(arg->job_account);
xfree(arg->job_alias_list);
xfree(arg->job_comment);
xfree(arg->job_constraints);
xfree(arg->job_licenses);
xfree(arg->job_hostlist);
xfree(arg->sock_core_rep_count);
xfree(arg->sockets_per_node);
xfree(arg->job_mem_alloc);
xfree(arg->job_mem_alloc_rep_count);
xfree(arg->job_node_addrs);
xfree(arg->job_partition);
xfree(arg->job_reservation);
xfree(arg->job_std_err);
xfree(arg->job_std_in);
xfree(arg->job_std_out);
xfree(arg->step_mem_alloc);
xfree(arg->step_mem_alloc_rep_count);
switch_g_free_stepinfo(arg->switch_step);
xfree(arg);
}
extern void slurm_cred_unlock_args(slurm_cred_t *cred)
{
slurm_rwlock_unlock(&cred->mutex);
}
/*
* Caller *must* release lock.
*/
extern slurm_cred_arg_t *slurm_cred_get_args(slurm_cred_t *cred)
{
xassert(cred);
slurm_rwlock_rdlock(&cred->mutex);
return cred->arg;
}
extern void *slurm_cred_get(slurm_cred_t *cred,
cred_data_enum_t cred_data_type)
{
void *rc = NULL;
xassert(cred);
slurm_rwlock_rdlock(&cred->mutex);
if (!cred->arg) {
slurm_rwlock_unlock(&cred->mutex);
return NULL;
}
switch (cred_data_type) {
case CRED_DATA_JOB_GRES_LIST:
rc = (void *) cred->arg->job_gres_list;
break;
case CRED_DATA_JOB_ALIAS_LIST:
rc = (void *) cred->arg->job_alias_list;
break;
case CRED_DATA_JOB_NODE_ADDRS:
rc = (void *) cred->arg->job_node_addrs;
break;
case CRED_DATA_STEP_GRES_LIST:
rc = (void *) cred->arg->step_gres_list;
break;
default:
error("%s: Invalid arg type requested (%d)", __func__,
cred_data_type);
}
slurm_rwlock_unlock(&cred->mutex);
return rc;
}
/*
* Returns NULL on error.
*
* On success, returns a pointer to the arg structure within the credential.
* Caller *must* release the lock.
*/
extern slurm_cred_arg_t *slurm_cred_verify(slurm_cred_t *cred)
{
time_t now = time(NULL);
int errnum;
xassert(cred);
xassert(g_context);
slurm_rwlock_rdlock(&cred->mutex);
xassert(cred->magic == CRED_MAGIC);
/* NOTE: the verification checks that the credential was
* created by SlurmUser or root */
if (!cred->verified) {
errno = ESLURMD_INVALID_JOB_CREDENTIAL;
goto error;
}
if (now > (cred->ctime + cred_expire)) {
errno = ESLURMD_CREDENTIAL_EXPIRED;
goto error;
}
/* coverity[missing_unlock] */
return cred->arg;
error:
errnum = errno;
slurm_rwlock_unlock(&cred->mutex);
errno = errnum;
return NULL;
}
extern void slurm_cred_destroy(slurm_cred_t *cred)
{
if (cred == NULL)
return;
xassert(cred->magic == CRED_MAGIC);
slurm_rwlock_wrlock(&cred->mutex);
slurm_cred_free_args(cred->arg);
FREE_NULL_BUFFER(cred->buffer);
xfree(cred->signature);
cred->magic = ~CRED_MAGIC;
slurm_rwlock_unlock(&cred->mutex);
slurm_rwlock_destroy(&cred->mutex);
xfree(cred);
}
extern char *slurm_cred_get_signature(slurm_cred_t *cred)
{
char *sig = NULL;
xassert(cred);
slurm_rwlock_rdlock(&cred->mutex);
sig = xstrdup(cred->signature);
slurm_rwlock_unlock(&cred->mutex);
return sig;
}
extern void slurm_cred_get_mem(slurm_cred_t *credential, char *node_name,
const char *func_name,
uint64_t *job_mem_limit,
uint64_t *step_mem_limit)
{
slurm_cred_arg_t *cred = credential->arg;
int rep_idx = -1;
int node_id = -1;
/*
* Batch steps only have the job_hostlist set and will always be 0 here.
*/
if (cred->step_id.step_id == SLURM_BATCH_SCRIPT) {
rep_idx = 0;
} else if ((node_id =
nodelist_find(cred->job_hostlist, node_name)) >= 0) {
rep_idx = slurm_get_rep_count_inx(cred->job_mem_alloc_rep_count,
cred->job_mem_alloc_size,
node_id);
} else {
error("Unable to find %s in job hostlist: `%s'",
node_name, cred->job_hostlist);
}
if (rep_idx < 0)
error("%s: node_id=%d, not found in job_mem_alloc_rep_count requested job memory not reset.",
func_name, node_id);
else
*job_mem_limit = cred->job_mem_alloc[rep_idx];
if (!step_mem_limit) {
log_flag(CPU_BIND, "%s: Memory extracted from credential for %ps job_mem_limit= %"PRIu64,
func_name, &cred->step_id, *job_mem_limit);
return;
}
if (cred->step_mem_alloc) {
rep_idx = -1;
if ((node_id =
nodelist_find(cred->step_hostlist, node_name)) >= 0) {
rep_idx = slurm_get_rep_count_inx(
cred->step_mem_alloc_rep_count,
cred->step_mem_alloc_size,
node_id);
} else {
error("Unable to find %s in step hostlist: `%s'",
node_name, cred->step_hostlist);
}
if (rep_idx < 0)
error("%s: node_id=%d, not found in step_mem_alloc_rep_count",
func_name, node_id);
else
*step_mem_limit = cred->step_mem_alloc[rep_idx];
}
/*
* If we are not set or we were sent 0 go with the job_mem_limit value.
*/
if (!(*step_mem_limit))
*step_mem_limit = *job_mem_limit;
log_flag(CPU_BIND, "Memory extracted from credential for %ps job_mem_limit=%"PRIu64" step_mem_limit=%"PRIu64,
&cred->step_id, *job_mem_limit, *step_mem_limit);
}
/* Convert bitmap to string representation with brackets removed */
static char *_core_format(bitstr_t *core_bitmap)
{
char str[1024], *bracket_ptr;
bit_fmt(str, sizeof(str), core_bitmap);
if (str[0] != '[')
return xstrdup(str);
/* strip off brackets */
bracket_ptr = strchr(str, ']');
if (bracket_ptr)
bracket_ptr[0] = '\0';
return xstrdup(str+1);
}
/*
* Retrieve the set of cores that were allocated to the job and step then
* format them in the List Format (e.g., "0-2,7,12-14"). Also return
* job and step's memory limit.
*
* NOTE: caller must xfree the returned strings.
*/
extern void format_core_allocs(slurm_cred_t *credential, char *node_name,
uint16_t cpus, char **job_alloc_cores,
char **step_alloc_cores, uint64_t *job_mem_limit,
uint64_t *step_mem_limit)
{
slurm_cred_arg_t *cred = credential->arg;
bitstr_t *job_core_bitmap, *step_core_bitmap;
hostlist_t *hset = NULL;
int host_index = -1;
uint32_t i, j, i_first_bit=0, i_last_bit=0;
xassert(cred);
xassert(job_alloc_cores);
xassert(step_alloc_cores);
if (!(hset = hostlist_create(cred->job_hostlist))) {
error("Unable to create job hostlist: `%s'",
cred->job_hostlist);
return;
}
host_index = hostlist_find(hset, node_name);
if ((host_index < 0) || (host_index >= cred->job_nhosts)) {
error("Invalid host_index %d for job %u",
host_index, cred->step_id.job_id);
error("Host %s not in hostlist %s",
node_name, cred->job_hostlist);
hostlist_destroy(hset);
return;
}
host_index++; /* change from 0-origin to 1-origin */
for (i=0; host_index; i++) {
if (host_index > cred->sock_core_rep_count[i]) {
i_first_bit += cred->sockets_per_node[i] *
cred->cores_per_socket[i] *
cred->sock_core_rep_count[i];
host_index -= cred->sock_core_rep_count[i];
} else {
i_first_bit += cred->sockets_per_node[i] *
cred->cores_per_socket[i] *
(host_index - 1);
i_last_bit = i_first_bit +
cred->sockets_per_node[i] *
cred->cores_per_socket[i];
break;
}
}
job_core_bitmap = bit_alloc(i_last_bit - i_first_bit);
step_core_bitmap = bit_alloc(i_last_bit - i_first_bit);
for (i = i_first_bit, j = 0; i < i_last_bit; i++, j++) {
if (bit_test(cred->job_core_bitmap, i))
bit_set(job_core_bitmap, j);
if (bit_test(cred->step_core_bitmap, i))
bit_set(step_core_bitmap, j);
}
slurm_cred_get_mem(credential, node_name, __func__, job_mem_limit,
step_mem_limit);
*job_alloc_cores = _core_format(job_core_bitmap);
*step_alloc_cores = _core_format(step_core_bitmap);
FREE_NULL_BITMAP(job_core_bitmap);
FREE_NULL_BITMAP(step_core_bitmap);
hostlist_destroy(hset);
}
/*
* Retrieve the job and step generic resources (gres) allocate to this job
* on this node.
*
* NOTE: Caller must destroy the returned lists
*/
extern void get_cred_gres(slurm_cred_t *credential, char *node_name,
list_t **job_gres_list, list_t **step_gres_list)
{
slurm_cred_arg_t *cred = credential->arg;
hostlist_t *hset = NULL;
int host_index = -1;
xassert(cred);
xassert(job_gres_list);
xassert(step_gres_list);
FREE_NULL_LIST(*job_gres_list);
FREE_NULL_LIST(*step_gres_list);
if ((cred->job_gres_list == NULL) && (cred->step_gres_list == NULL))
return;
if (!(hset = hostlist_create(cred->job_hostlist))) {
error("Unable to create job hostlist: `%s'",
cred->job_hostlist);
return;
}
host_index = hostlist_find(hset, node_name);
hostlist_destroy(hset);
if ((host_index < 0) || (host_index >= cred->job_nhosts)) {
error("Invalid host_index %d for job %u",
host_index, cred->step_id.job_id);
error("Host %s not in credential hostlist %s",
node_name, cred->job_hostlist);
return;
}
*job_gres_list = gres_job_state_extract(cred->job_gres_list,
host_index);
*step_gres_list = gres_step_state_extract(cred->step_gres_list,
host_index);
return;
}
extern void slurm_cred_pack(slurm_cred_t *cred, buf_t *buffer,
uint16_t protocol_version)
{
xassert(cred);
xassert(cred->magic == CRED_MAGIC);
slurm_rwlock_rdlock(&cred->mutex);
xassert(cred->buffer);
xassert(cred->buf_version == protocol_version);
packbuf(cred->buffer, buffer);
slurm_rwlock_unlock(&cred->mutex);
}
extern slurm_cred_t *slurm_cred_unpack(buf_t *buffer, uint16_t protocol_version)
{
return (*(ops.cred_unpack))(buffer, protocol_version);
}
extern slurm_cred_t *slurm_cred_alloc(bool alloc_arg)
{
slurm_cred_t *cred = xmalloc(sizeof(*cred));
/* Contents initialized to zero */
slurm_rwlock_init(&cred->mutex);
if (alloc_arg) {
cred->arg = xmalloc(sizeof(slurm_cred_arg_t));
cred->arg->uid = SLURM_AUTH_NOBODY;
cred->arg->gid = SLURM_AUTH_NOBODY;
}
cred->verified = false;
cred->magic = CRED_MAGIC;
return cred;
}
/*****************************************************************************\
***************** SBCAST CREDENTIAL FUNCTIONS ******************
\*****************************************************************************/
/* Create an sbcast credential for the specified job and nodes
* including digital signature.
* RET the sbcast credential or NULL on error */
extern sbcast_cred_t *create_sbcast_cred(sbcast_cred_arg_t *arg,
uid_t uid, gid_t gid,
uint16_t protocol_version)
{
sbcast_cred_t *sbcast_cred;
bool release_id = false;
identity_t fake_id = { .uid = uid, .gid = gid, .fake = true };
xassert(g_context);
if (!arg->id && enable_send_gids) {
release_id = true;
if (!(arg->id = fetch_identity(uid, gid, false))) {
error("%s: fetch_identity() failed", __func__);
return NULL;
}
} else if (!arg->id) {
arg->id = &fake_id;
}
if (!(sbcast_cred = (*(ops.sbcast_create))(arg, protocol_version)))
error("%s: failed to create sbcast credential", __func__);
if (release_id)
FREE_NULL_IDENTITY(arg->id);
return sbcast_cred;
}
/* Delete an sbcast credential created using create_sbcast_cred() or
* unpack_sbcast_cred() */
extern void delete_sbcast_cred(sbcast_cred_t *sbcast_cred)
{
if (!sbcast_cred)
return;
FREE_NULL_IDENTITY(sbcast_cred->arg.id);
xfree(sbcast_cred->arg.nodes);
FREE_NULL_BUFFER(sbcast_cred->buffer);
xfree(sbcast_cred->signature);
xfree(sbcast_cred);
}
/* Pack an sbcast credential into a buffer including the digital signature */
extern void pack_sbcast_cred(sbcast_cred_t *sbcast_cred, buf_t *buffer,
uint16_t protocol_version)
{
xassert(sbcast_cred);
if (sbcast_cred->buffer) {
/* already includes signature */
packbuf(sbcast_cred->buffer, buffer);
} else {
/* credential only uses signature */
packstr(sbcast_cred->signature, buffer);
}
}
extern sbcast_cred_t *unpack_sbcast_cred(buf_t *buffer, void *msg,
uint16_t protocol_version)
{
file_bcast_msg_t *bmsg = msg;
bool verify = false;
if (bmsg && (bmsg->block_no == 1) && !(bmsg->flags & FILE_BCAST_SO))
verify = true;
return (*(ops.sbcast_unpack))(buffer, verify, protocol_version);
}
extern void print_sbcast_cred(sbcast_cred_t *sbcast_cred)
{
info("Sbcast_cred: JobId %u", sbcast_cred->arg.job_id);
info("Sbcast_cred: HetJobId %u", sbcast_cred->arg.het_job_id);
info("Sbcast_cred: StepId %u", sbcast_cred->arg.step_id);
info("Sbcast_cred: Nodes %s", sbcast_cred->arg.nodes);
info("Sbcast_cred: ctime %s", slurm_ctime2(&sbcast_cred->ctime));
info("Sbcast_cred: Expire %s", slurm_ctime2(&sbcast_cred->arg.expiration));
}
extern char *create_net_cred(void *addrs, uint16_t protocol_version)
{
xassert(g_context);
if (!addrs) {
error("%s: addrs not provided", __func__);
return NULL;
}
return (*(ops.create_net_cred))(addrs, protocol_version);
}
extern void *extract_net_cred(char *net_cred, uint16_t protocol_version)
{
xassert(g_context);
if (!net_cred) {
error("%s: net_cred not provided", __func__);
return NULL;
}
return (*(ops.extract_net_cred))(net_cred, protocol_version);
}
extern void setup_cred_arg(slurm_cred_arg_t *cred_arg, job_record_t *job_ptr)
{
memset(cred_arg, 0, sizeof(slurm_cred_arg_t));
cred_arg->id = job_ptr->id;
cred_arg->gid = job_ptr->group_id;
cred_arg->job_account = job_ptr->account;
cred_arg->job_alias_list = job_ptr->alias_list;
cred_arg->job_comment = job_ptr->comment;
cred_arg->job_end_time = job_ptr->end_time;
cred_arg->job_extra = job_ptr->extra;
cred_arg->job_gres_list = job_ptr->gres_list_alloc;
cred_arg->job_licenses = job_ptr->licenses;
cred_arg->job_node_addrs = job_ptr->node_addrs;
cred_arg->job_reservation = job_ptr->resv_name;
cred_arg->job_restart_cnt = job_ptr->restart_cnt;
cred_arg->job_selinux_context = job_ptr->selinux_context;
cred_arg->job_start_time = job_ptr->start_time;
cred_arg->uid = job_ptr->user_id;
if (job_ptr->details) {
cred_arg->job_constraints = job_ptr->details->features_use;
cred_arg->job_core_spec = job_ptr->details->core_spec;
cred_arg->job_ntasks = job_ptr->details->num_tasks;
cred_arg->job_oversubscribe = get_job_share_value(job_ptr);
cred_arg->job_std_err = job_ptr->details->std_err;
cred_arg->job_std_in = job_ptr->details->std_in;
cred_arg->job_std_out = job_ptr->details->std_out;
cred_arg->job_x11 = job_ptr->details->x11;
}
if (job_ptr->job_resrcs) {
job_resources_t *resrcs = job_ptr->job_resrcs;
cred_arg->cores_per_socket = resrcs->cores_per_socket;
cred_arg->cpu_array_count = resrcs->cpu_array_cnt;
cred_arg->cpu_array = resrcs->cpu_array_value;
cred_arg->cpu_array_reps = resrcs->cpu_array_reps;
cred_arg->job_core_bitmap = resrcs->core_bitmap;
cred_arg->job_hostlist = resrcs->nodes;
cred_arg->job_nhosts = resrcs->nhosts;
cred_arg->sock_core_rep_count = resrcs->sock_core_rep_count;
cred_arg->sockets_per_node = resrcs->sockets_per_node;
}
if (job_ptr->part_ptr)
cred_arg->job_partition = job_ptr->part_ptr->name;
}