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