xref: /DragonReach/src/executor/service_executor/mod.rs (revision ea330323f68db57353801959d67cbd8e0031aa18)
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, print, println};
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::Enabled {
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                 println!("Service running...");
73                 //修改service状态
74                 service.mut_unit_base().set_state(UnitState::Enabled);
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::kill_running(*bind);
174         }
175 
176         //判断是否需要restart,需要则再次启动服务
177         if service.service_part().restart().is_restart(&exit_status) {
178             let ns = service.service_part().restart_sec();
179             let binds = service.unit_base().unit_part().be_binded_by();
180             let binds = Vec::from(binds);
181             let id = service.unit_id();
182             if ns > 0 {
183                 let cmds = service.service_part().exec_reload().clone();
184                 TimerManager::push_timer(
185                     Duration::from_nanos(ns),
186                     move || {
187                         for cmd in &cmds {
188                             cmd.no_spawn()?;
189                         }
190                         Executor::exec(id)?;
191                         for bind in &binds {
192                             Executor::exec(*bind)?
193                         }
194                         Ok(())
195                     },
196                     service.unit_id(),
197                 )
198             } else {
199                 let _ = Self::exec_reload(service);
200                 let _ = Executor::exec(id);
201             }
202             return;
203         }
204 
205         //如果该进程标记了RemainAfterExit,则将其加入特殊标记表
206         if service.service_part().remain_after_exit() {
207             UnitManager::push_flag_running(service.unit_id());
208             return;
209         }
210 
211         //停止服务后设置Unit状态
212         service.mut_unit_base().set_state(UnitState::Disabled);
213     }
214 
215     /// ## 显示退出Service
216     pub fn exit(service: &mut ServiceUnit) {
217         // TODO: 打印日志
218         let _ = Self::exec_stop(service);
219 
220         let ns = service.service_part().timeout_stop_sec();
221         let id = service.unit_id();
222         if ns != 0 {
223             // 计时器触发后若服务还未停止,则kill掉进程
224             TimerManager::push_timer(
225                 Duration::from_nanos(ns),
226                 move || {
227                     if UnitManager::is_running_unit(&id) {
228                         UnitManager::kill_running(id);
229                     }
230                     Ok(())
231                 },
232                 service.unit_id(),
233             )
234         }
235     }
236 }
237