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