xref: /DragonReach/src/unit/service/mod.rs (revision 76992bdb7f9f450492cb23e443efb1a716e86958)
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 mut_unit_base(&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 
222 impl ServiceUnit {
223     pub fn unit_base(&self) -> &BaseUnit {
224         return &self.unit_base;
225     }
226 
227     pub fn service_part(&self) -> &ServicePart {
228         return &self.service_part;
229     }
230 
231     pub fn mut_service_part(&mut self) -> &mut ServicePart {
232         return &mut self.service_part;
233     }
234 
235     fn exec(&mut self) -> Result<(), RuntimeError> {
236         ServiceExecutor::exec(self)
237     }
238 }
239 
240 unsafe impl Sync for ServiceUnit {}
241 
242 unsafe impl Send for ServiceUnit {}
243 
244 pub enum ServiceUnitAttr {
245     None,
246     //Service段
247     //定义启动时的进程行为
248     Type,
249     //
250     RemainAfterExit,
251     //启动命令
252     ExecStart,
253     //启动当前服务之前执行的命令
254     ExecStartPre,
255     //启动当前服务之后执行的命令
256     ExecStartPos,
257     //重启当前服务时执行的命令
258     ExecReload,
259     //停止当前服务时执行的命令
260     ExecStop,
261     //停止当其服务之后执行的命令
262     ExecStopPost,
263     //自动重启当前服务间隔的秒数
264     RestartSec,
265     //定义何种情况 Systemd 会自动重启当前服务
266     Restart,
267     //启动服务时等待的秒数
268     TimeoutStartSec,
269     //停止服务时的等待秒数,如果超过这个时间仍然没有停止,应该使用 SIGKILL 信号强行杀死服务的进程
270     TimeoutStopSec,
271     //为服务指定环境变量
272     Environment,
273     //指定加载一个包含服务所需的环境变量的列表的文件,文件中的每一行都是一个环境变量的定义
274     EnvironmentFile,
275     //服务的进程优先级,值越小优先级越高,默认为 0。其中 -20 为最高优先级,19 为最低优先级
276     Nice,
277     //指定服务的工作目录
278     WorkingDirectory,
279     //指定服务进程的根目录(/ 目录)。如果配置了这个参数,服务将无法访问指定目录以外的任何文件
280     RootDirectory,
281     //指定运行服务的用户
282     User,
283     //指定运行服务的用户组
284     Group,
285     //服务的 Mount Namespace 配置,会影响进程上下文中挂载点的信息
286     MountFlags,
287 }
288 
289 #[allow(dead_code)]
290 impl ServicePart {
291     pub fn set_attr(&'_ mut self, attr: &ServiceUnitAttr, val: &str) -> Result<(), ParseError> {
292         match attr {
293             ServiceUnitAttr::Type => match val {
294                 "simple" => self.service_type = ServiceType::Simple,
295                 "forking" => self.service_type = ServiceType::Forking,
296                 "oneshot" => self.service_type = ServiceType::OneShot,
297                 "dbus" => self.service_type = ServiceType::Dbus,
298                 "notify" => self.service_type = ServiceType::Notify,
299                 "idle" => self.service_type = ServiceType::Idle,
300                 _ => {
301                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
302                 }
303             },
304             ServiceUnitAttr::RemainAfterExit => {
305                 self.remain_after_exit = UnitParseUtil::parse_boolean(val)?
306             }
307             ServiceUnitAttr::ExecStart => {
308                 self.exec_start = UnitParseUtil::parse_cmd_task(val)?[0].clone();
309             }
310             ServiceUnitAttr::ExecStartPre => {
311                 self.exec_start_pre
312                     .extend(UnitParseUtil::parse_cmd_task(val)?);
313             }
314             ServiceUnitAttr::ExecStartPos => {
315                 self.exec_start_pos
316                     .extend(UnitParseUtil::parse_cmd_task(val)?);
317             }
318             ServiceUnitAttr::ExecReload => {
319                 self.exec_reload.extend(UnitParseUtil::parse_cmd_task(val)?);
320             }
321             ServiceUnitAttr::ExecStopPost => {
322                 self.exec_stop_post
323                     .extend(UnitParseUtil::parse_cmd_task(val)?);
324             }
325             ServiceUnitAttr::ExecStop => {
326                 self.exec_stop.extend(UnitParseUtil::parse_cmd_task(val)?);
327             }
328             ServiceUnitAttr::RestartSec => self.restart_sec = UnitParseUtil::parse_sec(val)?,
329             ServiceUnitAttr::Restart => match val {
330                 "always" => self.restart = RestartOption::AlwaysRestart,
331                 "on-success" => self.restart = RestartOption::OnSuccess,
332                 "on-failure" => self.restart = RestartOption::OnFailure,
333                 "on-abnormal" => self.restart = RestartOption::OnAbnormal,
334                 "on-abort" => self.restart = RestartOption::OnAbort,
335                 "on-watchdog" => self.restart = RestartOption::OnWatchdog,
336                 _ => {
337                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
338                 }
339             },
340             ServiceUnitAttr::TimeoutStartSec => {
341                 self.timeout_start_sec = UnitParseUtil::parse_sec(val)?
342             }
343             ServiceUnitAttr::TimeoutStopSec => {
344                 self.timeout_stop_sec = UnitParseUtil::parse_sec(val)?
345             }
346             ServiceUnitAttr::Environment => {
347                 self.environment.push(UnitParseUtil::parse_env(val)?);
348             }
349             ServiceUnitAttr::EnvironmentFile => {
350                 if !UnitParseUtil::is_valid_file(val) {
351                     return Err(ParseError::new(ParseErrorType::EFILE, String::new(), 0));
352                 }
353                 self.environment
354                     .extend(UnitParseUtil::parse_environment_file(val)?);
355             }
356             ServiceUnitAttr::Nice => {
357                 self.nice = UnitParseUtil::parse_nice(val)?;
358             }
359             ServiceUnitAttr::WorkingDirectory => {
360                 if !UnitParseUtil::is_dir(val) {
361                     return Err(ParseError::new(ParseErrorType::ENODIR, String::new(), 0));
362                 }
363                 self.working_directory = String::from(val);
364             }
365             ServiceUnitAttr::User => {
366                 //TODO: 检查系统是否存在这个用户
367                 self.user = String::from(val);
368             }
369             ServiceUnitAttr::Group => {
370                 //TODO: 检查系统是否存在该用户组
371                 self.group = String::from(val);
372             }
373             ServiceUnitAttr::MountFlags => match val {
374                 "shared" => self.mount_flags = MountFlag::Shared,
375                 "slave" => self.mount_flags = MountFlag::Slave,
376                 "private" => self.mount_flags = MountFlag::Private,
377                 _ => {
378                     return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
379                 }
380             },
381             _ => {
382                 return Err(ParseError::new(ParseErrorType::EINVAL, String::new(), 0));
383             }
384         }
385         return Ok(());
386     }
387 
388     // 生命周期相关
389     pub fn service_type(&self) -> &ServiceType {
390         &self.service_type
391     }
392 
393     pub fn remain_after_exit(&self) -> bool {
394         self.remain_after_exit
395     }
396 
397     pub fn exec_start(&self) -> &CmdTask {
398         &self.exec_start
399     }
400 
401     pub fn exec_start_pre(&self) -> &Vec<CmdTask> {
402         &self.exec_start_pre
403     }
404 
405     pub fn exec_start_pos(&self) -> &Vec<CmdTask> {
406         &self.exec_start_pos
407     }
408 
409     pub fn exec_reload(&self) -> &Vec<CmdTask> {
410         &self.exec_reload
411     }
412 
413     pub fn exec_stop(&self) -> &Vec<CmdTask> {
414         &self.exec_stop
415     }
416 
417     pub fn exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
418         &mut self.exec_stop_post
419     }
420 
421     pub fn mut_exec_start_pre(&mut self) -> &mut Vec<CmdTask> {
422         &mut self.exec_start_pre
423     }
424 
425     pub fn mut_exec_start_pos(&mut self) -> &mut Vec<CmdTask> {
426         &mut self.exec_start_pos
427     }
428 
429     pub fn mut_exec_reload(&mut self) -> &mut Vec<CmdTask> {
430         &mut self.exec_reload
431     }
432 
433     pub fn mut_exec_stop(&mut self) -> &mut Vec<CmdTask> {
434         &mut self.exec_stop
435     }
436 
437     pub fn mut_exec_stop_post(&mut self) -> &mut Vec<CmdTask> {
438         &mut self.exec_stop_post
439     }
440 
441     pub fn restart_sec(&self) -> u64 {
442         self.restart_sec
443     }
444 
445     pub fn restart(&self) -> &RestartOption {
446         &self.restart
447     }
448 
449     pub fn timeout_start_sec(&self) -> u64 {
450         self.timeout_start_sec
451     }
452 
453     pub fn timeout_stop_sec(&self) -> u64 {
454         self.timeout_stop_sec
455     }
456 
457     // 上下文配置相关
458     pub fn environment(&self) -> &[(String, String)] {
459         &self.environment
460     }
461 
462     pub fn nice(&self) -> i8 {
463         self.nice
464     }
465 
466     pub fn working_directory(&self) -> &str {
467         &self.working_directory
468     }
469 
470     pub fn root_directory(&self) -> &str {
471         &self.root_directory
472     }
473 
474     pub fn user(&self) -> &str {
475         &self.user
476     }
477 
478     pub fn group(&self) -> &str {
479         &self.group
480     }
481 
482     pub fn mount_flags(&self) -> &MountFlag {
483         &self.mount_flags
484     }
485 }
486