xref: /DragonReach/src/unit/service/mod.rs (revision af4e087250481d24f7a6ee7057d648c56a4753e3)
1 use super::{BaseUnit, Unit};
2 use crate::error::runtime_error::RuntimeError;
3 use crate::error::{parse_error::ParseError, parse_error::ParseErrorType};
4 use crate::executor::service_executor::ServiceExecutor;
5 use crate::executor::ExitStatus;
6 
7 use crate::parse::parse_service::ServiceParser;
8 use crate::parse::parse_util::UnitParseUtil;
9 use crate::parse::{Segment, SERVICE_UNIT_ATTR_TABLE};
10 use crate::task::cmdtask::CmdTask;
11 
12 use std::string::{String, ToString};
13 
14 use std::vec::Vec;
15 #[derive(Clone, Debug)]
16 pub struct ServiceUnit {
17     unit_base: BaseUnit,
18     service_part: ServicePart,
19 }
20 
21 impl Default for ServiceUnit {
22     fn default() -> Self {
23         let mut sp = ServicePart::default();
24         sp.working_directory = String::from("/");
25         Self {
26             unit_base: BaseUnit::default(),
27             service_part: sp,
28         }
29     }
30 }
31 
32 #[derive(Debug, Clone, Copy)]
33 pub enum ServiceType {
34     Simple,
35     Forking,
36     OneShot,
37     Dbus,
38     Notify,
39     Idle,
40 }
41 
42 impl Default for ServiceType {
43     fn default() -> Self {
44         ServiceType::Simple
45     }
46 }
47 
48 #[derive(Debug, Clone, Copy, PartialEq)]
49 pub enum RestartOption {
50     AlwaysRestart, //总是重启
51     OnSuccess,     //在该服务正常退出时
52     OnFailure,     //在该服务启动失败时
53     OnAbnormal,    //在该服务以非0错误码退出时
54     OnAbort,       //在该服务显示退出时(通过DragonReach手动退出)
55     OnWatchdog,    //定时观测进程无响应时(当前未实现)
56     None,          //不重启
57 }
58 
59 impl Default for RestartOption {
60     fn default() -> Self {
61         Self::None
62     }
63 }
64 
65 impl RestartOption {
66     pub fn is_restart(&self, exit_status: &ExitStatus) -> bool {
67         if *self == Self::AlwaysRestart {
68             return true;
69         }
70 
71         match (*self, *exit_status) {
72             (Self::OnSuccess, ExitStatus::Success) => {
73                 return true;
74             }
75             (Self::OnAbnormal, ExitStatus::Abnormal) => {
76                 return true;
77             }
78             (Self::OnAbort, ExitStatus::Abort) => {
79                 return true;
80             }
81             (Self::OnFailure, ExitStatus::Failure) => {
82                 return true;
83             }
84             (Self::OnWatchdog, ExitStatus::Watchdog) => {
85                 return true;
86             }
87             _ => {
88                 return false;
89             }
90         }
91     }
92 }
93 
94 #[derive(Debug, Clone, Copy)]
95 pub enum MountFlag {
96     Shared,
97     Slave,
98     Private,
99 }
100 
101 impl Default for MountFlag {
102     fn default() -> Self {
103         Self::Private
104     }
105 }
106 
107 #[allow(dead_code)]
108 #[derive(Default, Debug, Clone)]
109 pub struct ServicePart {
110     //生命周期相关
111     service_type: ServiceType,
112     ///
113     remain_after_exit: bool,
114     exec_start: CmdTask,
115     exec_start_pre: Vec<CmdTask>,
116     exec_start_pos: Vec<CmdTask>,
117     exec_reload: Vec<CmdTask>,
118     exec_stop: Vec<CmdTask>,
119     exec_stop_post: Vec<CmdTask>,
120     restart_sec: u64,
121     restart: RestartOption,
122     timeout_start_sec: u64,
123     timeout_stop_sec: u64,
124     //上下文配置相关
125     environment: Vec<(String, String)>,
126     nice: i8,
127     working_directory: String,
128     root_directory: String,
129     user: String,
130     group: String,
131     mount_flags: MountFlag,
132     //LimitCPU / LimitSTACK / LimitNOFILE / LimitNPROC 等,后续支持再添加
133 }
134 
135 impl Unit for ServiceUnit {
136     fn as_any(&self) -> &dyn core::any::Any {
137         self
138     }
139 
140     fn from_path(path: &str) -> Result<usize, ParseError>
141     where
142         Self: Sized,
143     {
144         return ServiceParser::parse(path);
145     }
146 
147     fn set_attr(&mut self, segment: Segment, attr: &str, val: &str) -> Result<(), ParseError> {
148         if segment != Segment::Service {
149             return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
150         }
151         let attr_type = SERVICE_UNIT_ATTR_TABLE.get(attr).ok_or(ParseError::new(
152             ParseErrorType::EINVAL,
153             String::new(),
154             0,
155         ));
156         return self.service_part.set_attr(attr_type.unwrap(), val);
157     }
158 
159     fn set_unit_base(&mut self, base: BaseUnit) {
160         self.unit_base = base;
161     }
162 
163     fn unit_type(&self) -> super::UnitType {
164         return self.unit_base.unit_type;
165     }
166 
167     fn unit_base(&self) -> &BaseUnit {
168         return &self.unit_base;
169     }
170 
171     fn unit_id(&self) -> usize {
172         return self.unit_base.unit_id;
173     }
174 
175     fn run(&mut self) -> Result<(), RuntimeError> {
176         self.exec()
177     }
178 
179     fn unit_base_mut(&mut self) -> &mut BaseUnit {
180         return &mut self.unit_base;
181     }
182 
183     fn after_exit(&mut self, exit_status: ExitStatus) {
184         ServiceExecutor::after_exit(self, exit_status);
185     }
186 
187     fn init(&mut self) {
188         let part = &mut self.service_part;
189         for cmd in part.exec_reload.iter_mut() {
190             cmd.dir = part.working_directory.to_string();
191             cmd.envs = part.environment.clone();
192         }
193         part.exec_start.dir = part.working_directory.to_string();
194         part.exec_start.envs = part.environment.clone();
195         for cmd in part.exec_start_pos.iter_mut() {
196             cmd.dir = part.working_directory.to_string();
197             cmd.envs = part.environment.clone();
198         }
199         for cmd in part.exec_start_pre.iter_mut() {
200             cmd.dir = part.working_directory.to_string();
201             cmd.envs = part.environment.clone();
202         }
203         for cmd in part.exec_stop.iter_mut() {
204             cmd.dir = part.working_directory.to_string();
205             cmd.envs = part.environment.clone();
206         }
207         for cmd in part.exec_stop_post.iter_mut() {
208             cmd.dir = part.working_directory.to_string();
209             cmd.envs = part.environment.clone();
210         }
211     }
212 
213     fn as_mut_any(&mut self) -> &mut dyn std::any::Any {
214         self
215     }
216 
217     fn exit(&mut self) {
218         ServiceExecutor::exit(self);
219     }
220 
221     fn restart(&mut self) -> Result<(), RuntimeError> {
222         return ServiceExecutor::restart(self);
223     }
224 }
225 
226 impl ServiceUnit {
227     pub fn unit_base(&self) -> &BaseUnit {
228         return &self.unit_base;
229     }
230 
231     pub fn service_part(&self) -> &ServicePart {
232         return &self.service_part;
233     }
234 
235     pub fn mut_service_part(&mut self) -> &mut ServicePart {
236         return &mut self.service_part;
237     }
238 
239     fn exec(&mut self) -> Result<(), RuntimeError> {
240         ServiceExecutor::exec(self)
241     }
242 }
243 
244 unsafe impl Sync for ServiceUnit {}
245 
246 unsafe impl Send for ServiceUnit {}
247 
248 pub enum ServiceUnitAttr {
249     None,
250     //Service段
251     //定义启动时的进程行为
252     Type,
253     //
254     RemainAfterExit,
255     //启动命令
256     ExecStart,
257     //启动当前服务之前执行的命令
258     ExecStartPre,
259     //启动当前服务之后执行的命令
260     ExecStartPos,
261     //重启当前服务时执行的命令
262     ExecReload,
263     //停止当前服务时执行的命令
264     ExecStop,
265     //停止当其服务之后执行的命令
266     ExecStopPost,
267     //自动重启当前服务间隔的秒数
268     RestartSec,
269     //定义何种情况 Systemd 会自动重启当前服务
270     Restart,
271     //启动服务时等待的秒数
272     TimeoutStartSec,
273     //停止服务时的等待秒数,如果超过这个时间仍然没有停止,应该使用 SIGKILL 信号强行杀死服务的进程
274     TimeoutStopSec,
275     //为服务指定环境变量
276     Environment,
277     //指定加载一个包含服务所需的环境变量的列表的文件,文件中的每一行都是一个环境变量的定义
278     EnvironmentFile,
279     //服务的进程优先级,值越小优先级越高,默认为 0。其中 -20 为最高优先级,19 为最低优先级
280     Nice,
281     //指定服务的工作目录
282     WorkingDirectory,
283     //指定服务进程的根目录(/ 目录)。如果配置了这个参数,服务将无法访问指定目录以外的任何文件
284     RootDirectory,
285     //指定运行服务的用户
286     User,
287     //指定运行服务的用户组
288     Group,
289     //服务的 Mount Namespace 配置,会影响进程上下文中挂载点的信息
290     MountFlags,
291 }
292 
293 #[allow(dead_code)]
294 impl ServicePart {
295     pub fn set_attr(&'_ mut self, attr: &ServiceUnitAttr, val: &str) -> Result<(), ParseError> {
296         match attr {
297             ServiceUnitAttr::Type => match val {
298                 "simple" => self.service_type = ServiceType::Simple,
299                 "forking" => self.service_type = ServiceType::Forking,
300                 "oneshot" => self.service_type = ServiceType::OneShot,
301                 "dbus" => self.service_type = ServiceType::Dbus,
302                 "notify" => self.service_type = ServiceType::Notify,
303                 "idle" => self.service_type = ServiceType::Idle,
304                 _ => {
305                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
306                 }
307             },
308             ServiceUnitAttr::RemainAfterExit => {
309                 self.remain_after_exit = UnitParseUtil::parse_boolean(val)?
310             }
311             ServiceUnitAttr::ExecStart => {
312                 self.exec_start = UnitParseUtil::parse_cmd_task(val)?[0].clone();
313             }
314             ServiceUnitAttr::ExecStartPre => {
315                 self.exec_start_pre
316                     .extend(UnitParseUtil::parse_cmd_task(val)?);
317             }
318             ServiceUnitAttr::ExecStartPos => {
319                 self.exec_start_pos
320                     .extend(UnitParseUtil::parse_cmd_task(val)?);
321             }
322             ServiceUnitAttr::ExecReload => {
323                 self.exec_reload.extend(UnitParseUtil::parse_cmd_task(val)?);
324             }
325             ServiceUnitAttr::ExecStopPost => {
326                 self.exec_stop_post
327                     .extend(UnitParseUtil::parse_cmd_task(val)?);
328             }
329             ServiceUnitAttr::ExecStop => {
330                 self.exec_stop.extend(UnitParseUtil::parse_cmd_task(val)?);
331             }
332             ServiceUnitAttr::RestartSec => self.restart_sec = UnitParseUtil::parse_sec(val)?,
333             ServiceUnitAttr::Restart => match val {
334                 "always" => self.restart = RestartOption::AlwaysRestart,
335                 "on-success" => self.restart = RestartOption::OnSuccess,
336                 "on-failure" => self.restart = RestartOption::OnFailure,
337                 "on-abnormal" => self.restart = RestartOption::OnAbnormal,
338                 "on-abort" => self.restart = RestartOption::OnAbort,
339                 "on-watchdog" => self.restart = RestartOption::OnWatchdog,
340                 _ => {
341                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
342                 }
343             },
344             ServiceUnitAttr::TimeoutStartSec => {
345                 self.timeout_start_sec = UnitParseUtil::parse_sec(val)?
346             }
347             ServiceUnitAttr::TimeoutStopSec => {
348                 self.timeout_stop_sec = UnitParseUtil::parse_sec(val)?
349             }
350             ServiceUnitAttr::Environment => {
351                 self.environment.push(UnitParseUtil::parse_env(val)?);
352             }
353             ServiceUnitAttr::EnvironmentFile => {
354                 if !UnitParseUtil::is_valid_file(val) {
355                     return Err(ParseError::new(ParseErrorType::EFILE, String::new(), 0));
356                 }
357                 self.environment
358                     .extend(UnitParseUtil::parse_environment_file(val)?);
359             }
360             ServiceUnitAttr::Nice => {
361                 self.nice = UnitParseUtil::parse_nice(val)?;
362             }
363             ServiceUnitAttr::WorkingDirectory => {
364                 if !UnitParseUtil::is_dir(val) {
365                     return Err(ParseError::new(ParseErrorType::ENODIR, String::new(), 0));
366                 }
367                 self.working_directory = String::from(val);
368             }
369             ServiceUnitAttr::User => {
370                 //TODO: 检查系统是否存在这个用户
371                 self.user = String::from(val);
372             }
373             ServiceUnitAttr::Group => {
374                 //TODO: 检查系统是否存在该用户组
375                 self.group = String::from(val);
376             }
377             ServiceUnitAttr::MountFlags => match val {
378                 "shared" => self.mount_flags = MountFlag::Shared,
379                 "slave" => self.mount_flags = MountFlag::Slave,
380                 "private" => self.mount_flags = MountFlag::Private,
381                 _ => {
382                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
383                 }
384             },
385             _ => {
386                 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
387             }
388         }
389         return Ok(());
390     }
391 
392     // 生命周期相关
393     pub fn service_type(&self) -> &ServiceType {
394         &self.service_type
395     }
396 
397     pub fn remain_after_exit(&self) -> bool {
398         self.remain_after_exit
399     }
400 
401     pub fn exec_start(&self) -> &CmdTask {
402         &self.exec_start
403     }
404 
405     pub fn exec_start_pre(&self) -> &Vec<CmdTask> {
406         &self.exec_start_pre
407     }
408 
409     pub fn exec_start_pos(&self) -> &Vec<CmdTask> {
410         &self.exec_start_pos
411     }
412 
413     pub fn exec_reload(&self) -> &Vec<CmdTask> {
414         &self.exec_reload
415     }
416 
417     pub fn exec_stop(&self) -> &Vec<CmdTask> {
418         &self.exec_stop
419     }
420 
421     pub fn exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
422         &mut self.exec_stop_post
423     }
424 
425     pub fn mut_exec_start_pre(&mut self) -> &mut Vec<CmdTask> {
426         &mut self.exec_start_pre
427     }
428 
429     pub fn mut_exec_start_pos(&mut self) -> &mut Vec<CmdTask> {
430         &mut self.exec_start_pos
431     }
432 
433     pub fn mut_exec_reload(&mut self) -> &mut Vec<CmdTask> {
434         &mut self.exec_reload
435     }
436 
437     pub fn mut_exec_stop(&mut self) -> &mut Vec<CmdTask> {
438         &mut self.exec_stop
439     }
440 
441     pub fn mut_exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
442         &mut self.exec_stop_post
443     }
444 
445     pub fn restart_sec(&self) -> u64 {
446         self.restart_sec
447     }
448 
449     pub fn restart(&self) -> &RestartOption {
450         &self.restart
451     }
452 
453     pub fn timeout_start_sec(&self) -> u64 {
454         self.timeout_start_sec
455     }
456 
457     pub fn timeout_stop_sec(&self) -> u64 {
458         self.timeout_stop_sec
459     }
460 
461     // 上下文配置相关
462     pub fn environment(&self) -> &[(String, String)] {
463         &self.environment
464     }
465 
466     pub fn nice(&self) -> i8 {
467         self.nice
468     }
469 
470     pub fn working_directory(&self) -> &str {
471         &self.working_directory
472     }
473 
474     pub fn root_directory(&self) -> &str {
475         &self.root_directory
476     }
477 
478     pub fn user(&self) -> &str {
479         &self.user
480     }
481 
482     pub fn group(&self) -> &str {
483         &self.group
484     }
485 
486     pub fn mount_flags(&self) -> &MountFlag {
487         &self.mount_flags
488     }
489 }
490