1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! What a run gives back (the entry URL, addresses, credentials), and the checks that prove it
//! behaves as its spec says.
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::names::{Identifier, Name, PortName, SnakeName};
use crate::step::Step;
use crate::template::Template;
/// What the embedder does with an output.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum OutputRole {
/// Where to start: the Open button.
Entry,
/// The lab host's login.
Ssh,
/// An address.
Address,
/// A credential.
Credential,
/// Anything else worth showing.
Info,
}
/// Where an output's value comes from.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
pub enum OutputSource {
/// The host port a machine's port got.
PublishedPort {
/// The machine.
machine: Name,
/// The port's name.
port: PortName,
},
/// A Terraform output of the module.
TerraformOutput {
/// The output's name.
name: Identifier,
/// The value when the state has none.
#[serde(default, skip_serializing_if = "Option::is_none")]
default: Option<String>,
},
/// A value known when the files were generated.
Static {
/// The value.
value: String,
},
}
/// A value the run gives back.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Output {
/// Its name (`${outputs.<name>}`).
pub name: SnakeName,
/// What it is, for the reader.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// What the embedder does with it.
pub role: OutputRole,
/// Masked in every event and log line, and never substituted in the message.
pub sensitive: bool,
/// How the value is shown, `${value}` being the raw one (`http://127.0.0.1:${value}/`).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub format: Option<Template>,
/// Where the value comes from.
pub from: OutputSource,
}
/// The line protocol check runners print.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub enum CheckProtocol {
/// `isoloom-check: PASS <name>`, `isoloom-check: FAIL <name>: <reason>`,
/// `isoloom-check: END <p> passed, <f> failed`, matched anywhere in a line (a Vagrant or
/// Compose prefix before it); the runner exits 0 only without a failure.
#[serde(rename = "isoloom-check/1")]
V1,
}
/// What a check probes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum CheckKind {
/// An HTTP request.
Http,
/// A TCP connection.
Tcp,
/// A script from the project.
Script,
/// A command inside a machine.
Exec,
/// An Ansible playbook from the project, run from the controller.
Playbook,
}
/// One check a runner reports.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Check {
/// The name the runner reports it by.
pub name: String,
/// What it probes.
pub kind: CheckKind,
/// How long the runner retries it before it fails (the spec's `wait`), in seconds.
pub wait_s: u32,
/// Derived from the spec (reachability, no internet); skipped with `ISOLOOM_DERIVED=0`.
pub derived: bool,
}
/// One check runner: where it runs, what it reports, the step that runs it.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CheckRunner {
/// Its id.
pub id: Name,
/// Where it runs, for the report: `from the environment's networks`, `from web`, `inside web`.
pub from: String,
/// What it reports, in order. A check its runner never reported counts as failed.
pub checks: Vec<Check>,
/// Its `timeout_s` covers every check's `wait_s` plus a margin: a runner never stops before
/// its slowest check could pass.
pub step: Step,
/// Clean-up after the runner ran out of time (its one-off container outlives the killed CLI).
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub on_timeout: Vec<Step>,
}
/// The lab's checks, run by the runners Isoloom generated.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Checks {
/// The line protocol the runners print.
pub protocol: CheckProtocol,
/// Run before the runners (the access stand-ins; waking the controller).
#[serde(default)]
pub setup: Vec<Step>,
/// The runners, in order.
pub runners: Vec<CheckRunner>,
/// Run after the runners, whatever happened.
#[serde(default)]
pub teardown: Vec<Step>,
}