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