xref: /DragonReach/src/executor/service_executor/mod.rs (revision 2069cc0dc0984a2981454b00316ba607f88ac512)
1 use std::{
2     process::{Command, Stdio},
3     time::Duration,
4 };
5 
6 use crate::{
7     error::runtime_error::{RuntimeError, RuntimeErrorType},
8     manager::{timer_manager::TimerManager, UnitManager},
9     parse::Segment,
10     unit::{
11         service::{ServiceType, ServiceUnit},
12         Unit, UnitState,
13     },
14 };
15 
16 use super::{Executor, ExitStatus};
17 
18 pub struct ServiceExecutor;
19 
20 impl ServiceExecutor {
21     /// ## Service执行器
22     pub fn exec(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
23         // 通过服务启动类型分发
24         match *service.service_part().service_type() {
25             ServiceType::Simple => return Self::exec_simple(service),
26             ServiceType::Forking => return Self::exec_forking(service),
27             ServiceType::Dbus => return Self::exec_dbus(service),
28             ServiceType::Notify => return Self::exec_notify(service),
29             ServiceType::Idle => return Self::exec_idle(service),
30             ServiceType::OneShot => return Self::exec_one_shot(service),
31         };
32     }
33 
34     pub fn exec_simple(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
35         //处理conflict
36         let conflicts = service.unit_base().unit_part().conflicts();
37         for u in conflicts {
38             // 如果有冲突项enable的时候,该unit不能启动
39             let mutex = UnitManager::get_unit_with_id(u).unwrap();
40             let unit = mutex.lock().unwrap();
41             if *unit.unit_base().state() == UnitState::Active {
42                 eprintln!(
43                     "{}: Service startup failed: conflict unit",
44                     unit.unit_base().unit_part().description()
45                 );
46                 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
47             }
48         }
49 
50         //获取启动命令
51         let exec_start = service.service_part().exec_start();
52 
53         //TODO:设置uid与gid
54 
55         //处理ExecStartsPre,准备在服务启动前执行的命令
56         Self::exec_start_pre(service)?;
57 
58         //创建服务进程
59         //服务配置环境变量,配置工作目录
60         let proc = Command::new(&exec_start.path)
61             .args(&exec_start.cmd)
62             .current_dir(service.service_part().working_directory())
63             .envs(Vec::from(service.service_part().environment()))
64             .stderr(Stdio::inherit())
65             .stdout(Stdio::inherit())
66             .stdin(Stdio::inherit())
67             .spawn();
68 
69         match proc {
70             Ok(p) => {
71                 // TODO: 打日志
72                 //修改service状态
73                 service.unit_base_mut().set_state(UnitState::Active);
74                 //启动成功后将Child加入全局管理的进程表
75                 UnitManager::push_running(service.unit_id(), p);
76                 //执行启动后命令
77                 Self::exec_start_pos(service)?;
78             }
79             Err(err) => {
80                 eprintln!("{}: Service startup failed: {}", exec_start.path, err);
81                 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
82             }
83         }
84         Ok(())
85     }
86 
87     fn exec_dbus(_service: &ServiceUnit) -> Result<(), RuntimeError> {
88         Ok(())
89     }
90 
91     fn exec_forking(_service: &ServiceUnit) -> Result<(), RuntimeError> {
92         Ok(())
93     }
94 
95     // 此方法会改变service的启动模式为simple
96     fn exec_idle(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
97         // 将该service加入等待运行队列
98         let _ = service.set_attr(Segment::Service, "Type", "simple");
99         UnitManager::push_a_idle_service(service.unit_id());
100         Ok(())
101     }
102 
103     fn exec_notify(_service: &ServiceUnit) -> Result<(), RuntimeError> {
104         Ok(())
105     }
106 
107     fn exec_one_shot(_service: &ServiceUnit) -> Result<(), RuntimeError> {
108         Ok(())
109     }
110 
111     fn exec_start_pos(service: &ServiceUnit) -> Result<(), RuntimeError> {
112         let cmds = service.service_part().exec_start_pos();
113         for cmd in cmds {
114             cmd.spawn()?;
115         }
116         Ok(())
117     }
118 
119     fn exec_start_pre(service: &ServiceUnit) -> Result<(), RuntimeError> {
120         let cmds = service.service_part().exec_start_pre();
121         for cmd in cmds {
122             cmd.no_spawn()?;
123         }
124         Ok(())
125     }
126 
127     //显式停止时执行的命令
128     fn exec_stop(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
129         let cmds = service.service_part().exec_stop();
130         for cmd in cmds {
131             cmd.no_spawn()?;
132         }
133         Ok(())
134     }
135 
136     //停止后执行的命令
137     fn exec_stop_post(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
138         let cmds = service.mut_service_part().mut_exec_stop_post();
139         for cmd in cmds {
140             cmd.no_spawn()?;
141         }
142         Ok(())
143     }
144 
145     fn exec_reload(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
146         let cmds = service.service_part().exec_reload();
147         for cmd in cmds {
148             cmd.no_spawn()?;
149         }
150         Ok(())
151     }
152 
153     /// ## 服务退出执行的逻辑(包括自然退出及显式退出)
154     pub fn after_exit(service: &mut ServiceUnit, exit_status: ExitStatus) {
155         //TODO: 需要考虑是否需要在此处执行退出后代码,还是只需要显式退出时才执行
156         let _ = Self::exec_stop_post(service);
157 
158         // 停止被spawn的命令
159         let s_part = service.mut_service_part();
160         for cmd in s_part.mut_exec_start_pos() {
161             cmd.stop()
162         }
163         for cmd in s_part.mut_exec_start_pre() {
164             cmd.stop()
165         }
166 
167         // 取消未进行的定时器任务
168         TimerManager::cancel_timer(service.unit_id());
169 
170         // 关闭和此服务绑定的项目
171         for bind in service.unit_base().unit_part().be_binded_by() {
172             UnitManager::try_kill_running(*bind);
173         }
174 
175         //判断是否需要restart,需要则再次启动服务
176         if service.service_part().restart().is_restart(&exit_status) {
177             let _ = Self::restart(service);
178             return;
179         }
180 
181         //如果该进程标记了RemainAfterExit,则将其加入特殊标记表
182         if service.service_part().remain_after_exit() {
183             UnitManager::push_flag_running(service.unit_id());
184             return;
185         }
186 
187         //停止服务后设置Unit状态
188         service.unit_base_mut().set_state(UnitState::Inactive);
189     }
190 
191     /// ## 重启Service
192     pub fn restart(service: &mut ServiceUnit) -> Result<(), RuntimeError> {
193         let ns = service.service_part().restart_sec();
194         let binds = service.unit_base().unit_part().be_binded_by();
195         let binds = Vec::from(binds);
196         let id = service.unit_id();
197         if ns > 0 {
198             let cmds = service.service_part().exec_reload().clone();
199             TimerManager::push_timer(
200                 Duration::from_nanos(ns),
201                 move || {
202                     for cmd in &cmds {
203                         cmd.no_spawn()?;
204                     }
205                     Executor::exec(id)?;
206                     for bind in &binds {
207                         Executor::restart(*bind)?
208                     }
209                     Ok(())
210                 },
211                 service.unit_id(),
212             )
213         } else {
214             UnitManager::try_kill_running(id);
215             Self::exec_reload(service)?;
216             eprintln!("restart");
217             Self::exec(service)?;
218             for bind in &binds {
219                 Executor::restart(*bind)?;
220             }
221         }
222         Ok(())
223     }
224 
225     /// ## 显示退出Service
226     pub fn exit(service: &mut ServiceUnit) {
227         // TODO: 打印日志
228         let _ = Self::exec_stop(service);
229 
230         let ns = service.service_part().timeout_stop_sec();
231         let id = service.unit_id();
232         if ns != 0 {
233             // 计时器触发后若服务还未停止,则kill掉进程
234             TimerManager::push_timer(
235                 Duration::from_nanos(ns),
236                 move || {
237                     UnitManager::try_kill_running(id);
238                     Ok(())
239                 },
240                 service.unit_id(),
241             )
242         } else {
243             UnitManager::try_kill_running(id);
244         }
245     }
246 }
247