1use serde_json::json;
5
6use super::Running;
7use super::operation::Done;
8use super::up::ready_run;
9use crate::Result;
10use crate::checks::{self, CheckReport};
11use crate::error::Error;
12use crate::events::{Emitter, Events};
13use crate::executor::{Cx, run_steps};
14use crate::hooks::Edge;
15use crate::options::RunOptions;
16use crate::params::params_for_existing;
17use crate::secrets::sensitive_values;
18use crate::state::{Op, Park, RunState};
19use crate::status::{MachineState, Started, any_target_running};
20use crate::store::RunRecord;
21use crate::{ready, tools};
22
23impl Running<'_> {
24 pub async fn down(&self, opts: &RunOptions, events: &dyn Events) -> Result<()> {
31 let opts = &self.connected(opts);
32 let mask = sensitive_values(self.manifest(), &opts.secrets);
33 self.operate(Op::Down, events, mask, async |e: &Emitter<'_>| {
34 let (mut record, mut cx) = self.existing(opts, e).await?;
35 self.hooks(&cx, Edge::BeforeDown, &[]).await;
36 self.begin(&mut record, Op::Down)?;
37 run_steps(&mut cx, "lifecycle.down", self.manifest().lifecycle.down.as_slice()).await?;
38 self.driver.after_down(&cx)?;
39 crate::executor::state_files::forget(&cx)?;
40 self.forget_seal()?;
41 crate::archive::forget(&cx)?;
42 Ok(Done {
43 value: (),
44 ok: true,
45 data: json!({ "state": RunState::Absent }),
46 state: Some(RunState::Absent),
47 })
48 })
49 .await
50 }
51
52 pub async fn park(&self, mode: Park, events: &dyn Events) -> Result<()> {
59 let opts = self.connected(&RunOptions::default());
60 let mask = sensitive_values(self.manifest(), &opts.secrets);
61 self.operate(Op::Park, events, mask, async |e: &Emitter<'_>| {
62 let park = self.manifest().lifecycle.park.as_ref();
63 let steps = park.and_then(|p| if mode == Park::Pause { p.pause.as_ref() } else { p.shutdown.as_ref() });
64 let steps = steps.ok_or_else(|| Error::NotParkable {
65 run: self.name().to_string(),
66 mode: mode.as_str(),
67 })?;
68 let (mut record, mut cx) = self.existing(&opts, e).await?;
69 if !self.exists(&mut cx).await? {
70 return Err(Error::NotRunning { run: self.name().to_string() });
71 }
72 self.hooks(&cx, Edge::BeforePark, &[]).await;
73 self.begin(&mut record, Op::Park)?;
74 run_steps(&mut cx, "lifecycle.park", steps).await?;
75 Ok(Done {
76 value: (),
77 ok: true,
78 data: json!({ "state": RunState::Parked }),
79 state: Some(RunState::Parked),
80 })
81 })
82 .await
83 }
84
85 pub async fn resume(&self, opts: &RunOptions, events: &dyn Events) -> Result<Started> {
92 let opts = &self.connected(opts);
93 let mask = sensitive_values(self.manifest(), &opts.secrets);
94 self.operate(Op::Resume, events, mask, async |e: &Emitter<'_>| self.resume_work(opts, e, true).await)
95 .await
96 }
97
98 pub(crate) async fn resume_work(&self, opts: &RunOptions, events: &Emitter<'_>, probe: bool) -> Result<Done<Started>> {
100 let (mut record, mut cx) = self.existing(opts, events).await?;
101 if probe {
102 tools::probe(&cx).await?;
103 }
104 if !self.exists(&mut cx).await? {
105 record.state = RunState::Absent;
107 self.runner.store.save(&record)?;
108 return Err(Error::NothingToResume { run: self.name().to_string() });
109 }
110 self.begin(&mut record, Op::Resume)?;
111 run_steps(&mut cx, "lifecycle.resume", &self.manifest().lifecycle.resume).await?;
112 ready::check(&mut cx, None).await?;
113 let (outputs, message) = self.finish(&mut cx, Edge::AfterResume).await?;
114 record.state = RunState::Ready;
115 Ok(ready_run(record, outputs, message))
116 }
117
118 pub async fn check(&self, opts: &RunOptions, events: &dyn Events) -> Result<CheckReport> {
125 let opts = &self.connected(opts);
126 let mask = sensitive_values(self.manifest(), &opts.secrets);
127 self.operate(Op::Check, events, mask, async |e: &Emitter<'_>| {
128 let (_, mut cx) = self.existing(opts, e).await?;
129 let observed = self.observe(&mut cx).await?;
130 if !any_target_running(&observed.machines) {
131 return Err(Error::NotRunning { run: self.name().to_string() });
132 }
133 self.bind_observed(&mut cx, observed);
135 let report = checks::run(&mut cx).await?;
136 let data = json!({ "passed": report.results.iter().filter(|r| r.ok).count(), "failed": report.results.iter().filter(|r| !r.ok).count(), "unfinished": report.unfinished });
137 Ok(Done { ok: report.ok, value: report, data, state: None })
138 })
139 .await
140 }
141
142 pub async fn provision(&self, machine: Option<&str>, opts: &RunOptions, events: &dyn Events) -> Result<()> {
152 let opts = &self.connected(opts);
153 let mask = sensitive_values(self.manifest(), &opts.secrets);
154 self.operate(Op::Provision, events, mask, async |e: &Emitter<'_>| {
155 let provision = self.manifest().lifecycle.provision.as_ref().ok_or_else(|| Error::Unsupported {
156 what: "provisioning this run (its manifest has no provision steps)".into(),
157 })?;
158 let (_, mut cx) = self.existing(opts, e).await?;
159 if let Some(m) = machine {
160 if !self
161 .manifest()
162 .machines
163 .iter()
164 .any(|x| x.name.as_str() == m && x.role == isoloom_manifest::Role::Target)
165 {
166 return Err(Error::MachineUnknown {
167 run: self.name().to_string(),
168 machine: m.to_owned(),
169 });
170 }
171 cx.vars.set_machine(m);
172 }
173 if !any_target_running(&self.observe(&mut cx).await?.machines) {
174 return Err(Error::NotRunning { run: self.name().to_string() });
175 }
176 let (list, steps) = match machine {
177 Some(_) => ("lifecycle.provision.machine", &provision.machine),
178 None => ("lifecycle.provision.all", &provision.all),
179 };
180 run_steps(&mut cx, list, steps).await?;
181 Ok(Done {
182 value: (),
183 ok: true,
184 data: json!({ "machine": machine }),
185 state: None,
186 })
187 })
188 .await
189 }
190
191 pub(crate) async fn existing<'a>(&'a self, opts: &'a RunOptions, events: &'a Emitter<'a>) -> Result<(RunRecord, Cx<'a>)> {
194 let record = self.record_or_fresh()?;
195 self.refuse_elsewhere(&record, opts.host_label.as_deref())?;
196 let recorded = (record.started_at.is_some()).then_some(&record.params);
197 let provider = record.provider.clone().or_else(|| opts.provider.clone());
198 let params = params_for_existing(self.manifest(), recorded, &opts.params, &self.scope(provider.clone()))?;
199 if crate::ssh::needed(self.manifest()) {
202 crate::ssh::ensure_key(self.runner.config.processes.as_ref(), &self.runner.config.home).await?;
203 }
204 let mut cx = self.acting(self.cx(params, &opts.secrets, events, provider)?)?;
205 Self::bind_record(&mut cx, &record);
206 self.driver.prepare(&cx)?;
207 crate::executor::state_files::write(&cx, false)?;
208 self.relay(&mut cx).await?;
209 Ok((record, cx))
210 }
211
212 async fn exists(&self, cx: &mut Cx<'_>) -> Result<bool> {
214 Ok(self.observe(cx).await?.machines.iter().any(|m| m.state != MachineState::Absent))
215 }
216}