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