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
use linked_list_c::ConstList;
use log::{trace,info,warn,error};
use std::ffi::{CString,CStr};
use std::ptr::null_mut;
use pbs_sys::{attrl, attropl, batch_status};

use crate::bindings::{is_err,get_err,stat};
use crate::helpers::{self,optstr_to_cstr};
use crate::types::{Attribs,StatResp,Server};


// signature for most of the pbs_stat* functions
type PbsStatSignature = unsafe extern fn(i32, *mut i8, *mut attrl, *mut i8) -> *mut batch_status;

// hacks to make Server::stat match signature consistent across all resources
unsafe extern fn sched_stat(conn: i32, n: *mut i8, a: *mut attrl, _ex: *mut i8) -> *mut batch_status {
    stat::pbs_statsched(conn, a, n)
}
unsafe extern fn srv_stat(conn: i32, n: *mut i8, a: *mut attrl, _ex: *mut i8) -> *mut batch_status {
    stat::pbs_statserver(conn, a, n)
}
impl Server {
    pub fn stat_host(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a host stat");
        self.stat(name, info, stat::pbs_stathost)
    }
    pub fn stat_reservation(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a reservation stat");
        self.stat(name, info, stat::pbs_statresv)
    }
    pub fn stat_resource(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a resource stat");
        self.stat(name, info, stat::pbs_statrsc)
    }
    pub fn stat_vnode(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a vnode stat");
        self.stat(name, info, stat::pbs_statvnode)
    }
    pub fn stat_que(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a que stat");
        self.stat(name, info, stat::pbs_statque)
    }
    pub fn stat_scheduler(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a scheduler stat");
        self.stat(name, info, sched_stat)
    }
    pub fn stat_server(&self, name: &Option<String>, info: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a server stat");
        self.stat(name, info, srv_stat)
    }
    pub fn stat_job(&self, criteria: Attribs, _output: Option<Attribs>) -> Result<StatResp, String> {
        trace!("performing a job stat");
        let crit: ConstList<attrl> = criteria.into();
        //TODO send criteria to api
        //let out: ConstList<attrl> = output.unwrap().into();
        //todo send extend flags
        // T, t to include subjobs, job arrays are not included
        // x include finished and moved jobs
        trace!("calling pbs server");
        let data = unsafe{stat::pbs_selstat(self.conn(), crit.head() as *mut attropl, null_mut(), null_mut())};
        if data.is_null() && is_err() {
            error!("job stat request failed {}", get_err());
            Err(get_err())
        }else{
            trace!("stat complete, returning list {:?}", &data);
            Ok(data.into())
        }
    }
 
    fn stat(&self, name: &Option<String>, _info: Option<Attribs>, api: PbsStatSignature) -> Result<StatResp,String> {
        //FIXME send constraints to api
        let n_ptr = optstr_to_cstr(name.as_deref());
        let data = {
            trace!("Performing stat");
            let resp = unsafe{api(self.conn(), n_ptr, null_mut(), null_mut())};
            if !n_ptr.is_null() {
                trace!("dropping n_ptr");
                _ = unsafe{CString::from_raw(n_ptr)};
            }
            if resp.is_null() && is_err() {
                error!("stat request failed {}", get_err());
                Err(get_err())
            }else{
                trace!("got good response");
                Ok(resp)
            }
        }?;
        trace!("stat complete, returning list {:?}", &data);
        Ok(data.into())
    }

    pub fn submit(&self, attributes: Attribs, script: &str, queue: &str) -> Result<String, String> {
        trace!("Job submission, generating attributes list");
        let attribs: ConstList<pbs_sys::attrl> = attributes.into();
        //bindings::attropl and bindings::attrl are interchangable
        trace!("Submitting job request");
        let jobid = unsafe{pbs_sys::pbs_submit(self.conn(), attribs.head() as *mut pbs_sys::attropl, helpers::str_to_cstr(script), helpers::str_to_cstr(queue), null_mut())};
        if !jobid.is_null() {
            let resp = Ok(unsafe{CStr::from_ptr(jobid)}.to_str().unwrap().to_string());
            trace!("Job submitted, got resp {:?}", &resp);
            unsafe{libc::free(jobid as *mut libc::c_void)};
            resp
        } else {
            warn!("Error submitting job {}", get_err());
            Err(get_err())
        }
    }
    pub fn del_job(&self, jobid: &str, msg: Option<&str>) -> Result<(), String> {
        trace!("Deleting job {jobid}");
        let resp = unsafe{pbs_sys::pbs_deljob(self.conn(), helpers::str_to_cstr(jobid), helpers::optstr_to_cstr(msg))};
        if resp != 0 {
            info!("Error deleting job {jobid}: {}", get_err());
            return Err(get_err());
        }
        Ok(())
    }
}