Skip to main content

isoloom_spec/
syntax.rs

1//! The spec as an author writes it, version 1: one declaration per machine. A machine is `os`
2//! plus a catalogue `service:` or a custom `app:` (or the OS alone); per-target facts live in a
3//! top-level `overrides:`. Parsed once into types that can't hold an invalid state, with every
4//! problem coded and placed ([`Problem`]). The plan lowers it into [`crate::model`], the form
5//! the backends read, once per target.
6
7mod app;
8mod check;
9mod files;
10mod forms;
11mod hardware;
12mod inputs;
13mod machine;
14mod mistake;
15mod names;
16mod old_keys;
17mod os;
18mod overrides;
19mod parse;
20pub mod placeholder;
21mod ports;
22mod problem;
23mod process;
24mod shared;
25mod spans;
26mod step;
27mod warning;
28
29pub use app::{App, ApplianceRecipe, Build, Recipe};
30pub use check::{Unresolved, check, placeholder_problems};
31pub use files::{File, FileSource, Mode};
32pub use forms::{Form, NoForm, container as container_form, reboots, vm as vm_form};
33pub use hardware::{Hardware, Tpm};
34pub use inputs::{Input, Inputs};
35pub use machine::{Kind, Machine, Octets, Services};
36pub use names::{InputName, PortName, ServiceRef, Version};
37pub use os::OsRef;
38pub use overrides::{
39    CloudMachine, CloudOverrides, DockerNetwork, DockerOverrides, EsxiOverrides, ExternalMachine, ExternalNetwork, ExternalOverrides, ExternalVolume,
40    KubernetesOverrides, Overrides, ProviderBoxes, ProxmoxMachine, ProxmoxOverrides, ProxmoxVolume, VagrantBox, VagrantMachine, VagrantOverrides,
41};
42pub use parse::parse;
43pub use ports::{Port, PortProtocol, Publish};
44pub use problem::{Code, FieldPath, Problem, Problems, Span, closest};
45pub use process::{Command, EnvValue, HealthPage, HealthProbe, Healthcheck, PortRef};
46pub use shared::{Group, Shared};
47pub use spans::Spans;
48pub use step::{
49    AbsPath, AptWord, Argv, CommandStep, Copy, FileState, FileStep, Firewall, FirewallPort, GroupName, GroupStep, Guard, HttpsUrl, Invocation, Package,
50    PackageName, PackageVersion, Password, ProjectPath, Repository, RepositoryKey, RepositoryName, Service, Sha256, Step, Template, UnitName, UserName,
51    UserStep,
52};
53pub use warning::Warning;
54
55use indexmap::IndexMap;
56use schemars::JsonSchema;
57
58use crate::model::{Check, CloudServices, Constraints, Controller, EnvironmentDns, Network, Provision, Reach, SecretSource, SharedVolume, Target, Tool};
59
60/// An environment spec, as written. Field order is kept (machines start in the order written).
61#[derive(Debug, Clone, PartialEq, Default, JsonSchema)]
62pub struct Spec {
63    /// The version of the `isoloom.yml` format the file is written in: `1`.
64    pub version: Version,
65    /// The environment's id, in kebab case (`supplier-portal`): it names its containers, VMs,
66    /// networks and cloud resources.
67    pub name: String,
68    /// The environment's networks, by name: each an address block the machines on it share.
69    #[schemars(default)]
70    pub networks: IndexMap<String, Network>,
71    /// Allowed traffic between networks; everything else between networks is blocked.
72    #[schemars(default)]
73    pub reach: Vec<Reach>,
74    /// The environment's names in a private DNS zone: off unless `private: true`.
75    pub dns: Option<EnvironmentDns>,
76    /// Values given at each start (a flag, a launch token): a list of names, or a map of name to
77    /// `{ sensitive, description }`. An input is sensitive unless it says otherwise: it reaches a
78    /// machine as a file (`files: [{ path, input }]`), never as an environment variable.
79    #[schemars(default)]
80    pub inputs: Inputs,
81    /// Secrets, by kebab-case name: the store each value is read from at each start (`env`,
82    /// `file`, `vault`, `sops`). A machine gets one as a file (`files: [{ path, secret }]`).
83    #[schemars(default)]
84    pub secrets: IndexMap<String, SecretSource>,
85    /// Volumes shared between machines, by name: `{ owner, persistent }`.
86    #[schemars(default)]
87    pub volumes: IndexMap<String, SharedVolume>,
88    /// The environment's machines, by name, started in the order written (after their
89    /// `depends_on`).
90    #[schemars(default)]
91    pub machines: IndexMap<String, Machine>,
92    /// Machine fields every machine shares (a machine's own value wins).
93    pub common: Option<Shared>,
94    /// Named sets of machines sharing fields, also Ansible inventory groups and `overrides` keys.
95    #[schemars(default)]
96    pub groups: IndexMap<String, Group>,
97    /// The environment's own Ansible, run from Isoloom's Linux controller once every machine is
98    /// up.
99    #[schemars(default)]
100    pub provision: Vec<Provision>,
101    /// The controller added for `provision:` and playbook checks: `{ resources, keep_running }`.
102    pub controller: Option<Controller>,
103    /// Black-box checks that prove the behaviour on every target.
104    #[schemars(default)]
105    pub checks: Vec<Check>,
106    /// Shown once the environment is up, in Markdown, with `{{ path }}` placeholders:
107    /// `machines.<m>.ports.<name>.port`, `.published`, `.url`, `machines.<m>.addresses.<network>`
108    /// and `cloud.outputs.<name>`, each checked at validation.
109    pub message: Option<String>,
110    /// Per-target facts with no portable meaning, by target (`docker`, `vagrant`, `proxmox`,
111    /// `aws`, ...).
112    #[schemars(default)]
113    pub overrides: Overrides,
114    /// Observers beside the environment, on every network: a toolbox (`shell`), or any container
115    /// image.
116    #[schemars(default)]
117    pub tools: IndexMap<String, Tool>,
118    /// Narrows the targets the machines' forms allow.
119    pub targets: Option<Vec<Target>>,
120    /// What the place it runs in imposes: an HTTP proxy, registry and package mirrors, time
121    /// servers.
122    pub constraints: Option<Constraints>,
123    /// An environment of cloud services rather than machines: a Terraform module applied into
124    /// the user's own cloud account.
125    pub cloud: Option<CloudServices>,
126    /// Base machine name → its clones, for machines that had a `count`. Filled when parsing.
127    #[schemars(skip)]
128    pub clones: IndexMap<String, Vec<String>>,
129    /// Where each field is written, for the problems found after parsing.
130    #[schemars(skip)]
131    pub spans: Spans,
132}