1use linked_list_c::{ConstList, List};
2use log::{debug, error, info, trace, warn};
3use pbs_sys::{attrl, attropl, batch_status};
4use std::ffi::{CStr, CString};
5use std::ptr::{self, null_mut};
6
7use crate::bindings::{get_err, is_err, stat};
8use crate::helpers::{self, optstr_to_cstr};
9use crate::types::{Attribs, Attrl, Op, Server, StatResp};
10
11#[derive(PartialEq)]
12pub enum ResvModFlag {
13 Force,
14}
15
16#[derive(PartialEq)]
17pub enum ResvSubFlag {
18 Maintenance,
19}
20
21type PbsStatSignature =
23 unsafe extern "C" fn(i32, *mut i8, *mut attrl, *mut i8) -> *mut batch_status;
24
25unsafe extern "C" fn sched_stat(
27 conn: i32,
28 n: *mut i8,
29 a: *mut attrl,
30 _ex: *mut i8,
31) -> *mut batch_status {
32 stat::pbs_statsched(conn, a, n)
33}
34unsafe extern "C" fn srv_stat(
35 conn: i32,
36 n: *mut i8,
37 a: *mut attrl,
38 _ex: *mut i8,
39) -> *mut batch_status {
40 stat::pbs_statserver(conn, a, n)
41}
42impl Server {
43 pub fn stat_host(
44 &self,
45 name: &Option<String>,
46 info: Option<Attribs>,
47 ) -> Result<StatResp, String> {
48 debug!("performing a host stat");
49 self.stat(name, info, stat::pbs_stathost)
50 }
51 pub fn stat_reservation(
52 &self,
53 name: &Option<String>,
54 info: Option<Attribs>,
55 ) -> Result<StatResp, String> {
56 debug!("performing a reservation stat");
57 self.stat(name, info, stat::pbs_statresv)
58 }
59 pub fn stat_resource(
60 &self,
61 name: &Option<String>,
62 info: Option<Attribs>,
63 ) -> Result<StatResp, String> {
64 debug!("performing a resource stat");
65 self.stat(name, info, stat::pbs_statrsc)
66 }
67 pub fn stat_vnode(
68 &self,
69 name: &Option<String>,
70 info: Option<Attribs>,
71 ) -> Result<StatResp, String> {
72 debug!("performing a vnode stat");
73 self.stat(name, info, stat::pbs_statvnode)
74 }
75 pub fn stat_que(
76 &self,
77 name: &Option<String>,
78 info: Option<Attribs>,
79 ) -> Result<StatResp, String> {
80 debug!("performing a que stat");
81 self.stat(name, info, stat::pbs_statque)
82 }
83 pub fn stat_scheduler(
84 &self,
85 name: &Option<String>,
86 info: Option<Attribs>,
87 ) -> Result<StatResp, String> {
88 debug!("performing a scheduler stat");
89 self.stat(name, info, sched_stat)
90 }
91 pub fn stat_server(
92 &self,
93 name: &Option<String>,
94 info: Option<Attribs>,
95 ) -> Result<StatResp, String> {
96 debug!("performing a server stat");
97 self.stat(name, info, srv_stat)
98 }
99 pub fn stat_job(
100 &self,
101 criteria: Attribs,
102 _output: Option<Attribs>,
103 ) -> Result<StatResp, String> {
104 debug!("performing a job stat");
105 let crit: ConstList<attrl> = criteria.into();
106 trace!("calling pbs server");
112 let data = unsafe {
113 stat::pbs_selstat(
114 self.conn(),
115 crit.head() as *mut attropl,
116 null_mut(),
117 null_mut(),
118 )
119 };
120 if data.is_null() && is_err() {
121 error!("job stat request failed {}", get_err());
122 Err(get_err())
123 } else {
124 debug!("stat complete, returning list {:?}", &data);
125 Ok(data.into())
126 }
127 }
128
129 fn stat(
130 &self,
131 name: &Option<String>,
132 info: Option<Attribs>,
133 api: PbsStatSignature,
134 ) -> Result<StatResp, String> {
135 let attribs: ConstList<attrl> = if let Some(i) = info {
136 i.into()
137 } else {
138 List::new().into()
139 };
140 let n_ptr = optstr_to_cstr(name.as_deref());
141 let data = {
142 trace!("Performing stat");
143 let resp = unsafe { api(self.conn(), n_ptr, attribs.head(), null_mut()) };
144 if !n_ptr.is_null() {
145 trace!("dropping n_ptr");
146 _ = unsafe { CString::from_raw(n_ptr) };
147 }
148 if resp.is_null() && is_err() {
149 error!("stat request failed {}", get_err());
150 Err(get_err())
151 } else {
152 trace!("got good response");
153 Ok(resp)
154 }
155 }?;
156 debug!("stat complete, returning list {:?}", &data);
157 Ok(data.into())
158 }
159
160 pub fn submit_job(
161 &self,
162 attributes: Attribs,
163 script: &str,
164 queue: &str,
165 ) -> Result<String, String> {
166 trace!("Job submission, generating attributes list");
167 let attribs: ConstList<pbs_sys::attrl> = attributes.into();
168 trace!("Submitting job request");
170 let jobid = unsafe {
171 pbs_sys::pbs_submit(
172 self.conn(),
173 attribs.head() as *mut pbs_sys::attropl,
174 helpers::str_to_cstr(script),
175 helpers::str_to_cstr(queue),
176 null_mut(),
177 )
178 };
179 if !jobid.is_null() {
180 let resp = Ok(unsafe { CStr::from_ptr(jobid) }
181 .to_str()
182 .unwrap()
183 .to_string());
184 trace!("Job submitted, got resp {:?}", &resp);
185 unsafe { libc::free(jobid as *mut libc::c_void) };
186 resp
187 } else {
188 warn!("Error submitting job {}", get_err());
189 Err(get_err())
190 }
191 }
192
193 pub fn submit_resv(
194 &self,
195 attributes: Attribs,
196 flags: Vec<ResvSubFlag>,
197 ) -> Result<String, String> {
198 trace!("Reservation submission, generating attributes list");
199 let attribs: ConstList<pbs_sys::attrl> = attributes.into();
200 let extend = if flags.contains(&ResvSubFlag::Maintenance) {
201 helpers::str_to_cstr("m")
202 } else {
203 null_mut()
204 };
205 trace!("Submitting reservation request");
206 let resvid = unsafe {
209 pbs_sys::pbs_submit_resv(self.conn(), attribs.head() as *mut pbs_sys::attropl, extend)
210 };
211 if !resvid.is_null() {
212 let resp = Ok(unsafe { CStr::from_ptr(resvid) }
213 .to_str()
214 .unwrap()
215 .to_string());
216 trace!("Reservation submitted, got resp {:?}", &resp);
217 unsafe { libc::free(resvid as *mut libc::c_void) };
218 resp
219 } else {
220 warn!("Error submitting reservation {}", get_err());
221 Err(get_err())
222 }
223 }
224
225 pub fn mod_resv(
226 &self,
227 resv: &str,
228 attributes: Attribs,
229 flags: Vec<ResvModFlag>,
230 ) -> Result<String, String> {
231 trace!("Modify reservation submission, generating attributes list");
232 let attribs: ConstList<pbs_sys::attrl> = attributes.into();
233 let extend = if flags.contains(&ResvModFlag::Force) {
234 helpers::str_to_cstr("force")
235 } else {
236 null_mut()
237 };
238 trace!("Submitting reservation modification request");
239 let resvid = unsafe {
241 pbs_sys::pbs_modify_resv(
242 self.conn(),
243 helpers::str_to_cstr(resv),
244 attribs.head() as *mut pbs_sys::attropl,
245 extend,
246 )
247 };
248 if !resvid.is_null() {
249 let resp = Ok(unsafe { CStr::from_ptr(resvid) }
250 .to_str()
251 .unwrap()
252 .to_string());
253 trace!("Reservation modification submitted, got resp {:?}", &resp);
254 unsafe { libc::free(resvid as *mut libc::c_void) };
255 resp
256 } else {
257 warn!("Error submitting reservation modification {}", get_err());
258 Err(get_err())
259 }
260 }
261
262 pub fn del_job(&self, jobid: &str) -> Result<(), String> {
263 trace!("Deleting job {jobid}");
264 let resp = unsafe {
265 pbs_sys::pbs_deljob(self.conn(), helpers::str_to_cstr(jobid), ptr::null_mut())
266 };
267 if resp != 0 {
268 info!("Error deleting job {jobid}: {}", get_err());
269 return Err(get_err());
270 }
271 Ok(())
272 }
273 pub fn del_resv(&self, id: &str) -> Result<(), String> {
274 trace!("Deleting Reservation {id}");
275 let resp =
276 unsafe { pbs_sys::pbs_delresv(self.conn(), helpers::str_to_cstr(id), ptr::null_mut()) };
277 if resp != 0 {
278 info!("Error deleting Reservation {id}: {}", get_err());
279 return Err(get_err());
280 }
281 Ok(())
282 }
283 pub fn offline_vnode(&self, name: &str, comment: Option<&str>) -> Result<(), String> {
284 trace!("offlining vnode: {name}");
285 let mut new = Attribs::new();
287 new.add(
288 helpers::cstr_to_str(pbs_sys::ATTR_NODE_state.as_ptr() as *mut i8).to_string(),
289 Attrl::Value(Op::Incr("offline".to_string())),
290 );
291 if let Some(c) = comment {
292 new.add(
293 helpers::cstr_to_str(pbs_sys::ATTR_comment.as_ptr() as *mut i8).to_string(),
294 Attrl::Value(Op::Set(c.to_string())),
295 )
296 }
297 let new: ConstList<attrl> = new.into();
298 let resp = unsafe {
299 pbs_sys::pbs_manager(
300 self.conn(),
301 pbs_sys::mgr_cmd_MGR_CMD_SET,
302 pbs_sys::mgr_obj_MGR_OBJ_HOST,
303 helpers::str_to_cstr(name),
304 new.head() as *mut attropl,
305 null_mut(),
306 )
307 };
308 if resp != 0 {
309 info!("Error offlining vnode {name}: {}", get_err());
310 return Err(get_err());
311 }
312 Ok(())
313 }
314 pub fn clear_vnode(&self, name: &str, comment: Option<&str>) -> Result<(), String> {
315 trace!("clearing offline,down for vnode: {name}");
316 let mut new = Attribs::new();
318 new.add(
319 helpers::cstr_to_str(pbs_sys::ATTR_NODE_state.as_ptr() as *mut i8).to_string(),
320 Attrl::Value(Op::Decr("offline".to_string())),
321 );
322 if let Some(c) = comment {
323 new.add(
324 helpers::cstr_to_str(pbs_sys::ATTR_comment.as_ptr() as *mut i8).to_string(),
325 Attrl::Value(Op::Set(c.to_string())),
326 )
327 }
328 let new: ConstList<attrl> = new.into();
329 let resp = unsafe {
330 pbs_sys::pbs_manager(
331 self.conn(),
332 pbs_sys::mgr_cmd_MGR_CMD_SET,
333 pbs_sys::mgr_obj_MGR_OBJ_HOST,
334 helpers::str_to_cstr(name),
335 new.head() as *mut attropl,
336 null_mut(),
337 )
338 };
339 if resp != 0 {
340 info!("Error offlining vnode {name}: {}", get_err());
341 return Err(get_err());
342 }
343 Ok(())
344 }
345}