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
//! Isothrum's compiler: a project as drawn in the editor (a [`Topology`]: machines, the LANs drawn
//! around them, and the cables between their ports) becomes an Isoloom spec, in the format Isoloom
//! reads (`isoloom.yml`, version 1).
//!
//! - **Machines.** A container node is a custom app from its image (`app.image`), kept running
//! idle with its own `command` when the image runs nothing of its own; a Cisco node is an
//! appliance (`app.appliance`). A VM node is its OS (`os`), set up by its provisioning steps
//! (`app.steps`), or the OS alone: each target decides how to deliver it.
//! - **Ports** are named (`ssh`, `http`, `port-8000`, `dns-udp`), each with its `protocol`.
//! - **Networks.** A LAN (an area drawn on the canvas, a VLAN in practice) is an Isoloom network
//! with its own block; each machine on it gets an address there, the next free one unless it
//! asks for one. A cable between two machines is its own point-to-point network (a /29 cut from
//! `10.200.0.0/16`, the two ends on its first two usable addresses). A switch's VLANs nest
//! under a network named after the switch.
//! - **Routing.** An automatic router lets the networks it joins reach each other (`reach`, both
//! ways); a Cisco router is its LANs' gateway.
//!
//! Every compiled spec is read back by Isoloom's parser before it is returned, so what the
//! compiler hands out is a spec Isoloom reads. Whether the project is valid as a whole (an unattached
//! machine, overlapping blocks) is Isoloom's validation to say.
//!
//! A Windows machine's own steps are PowerShell scripts: the Ansible playbooks drawn on one run
//! from Isoloom's controller (`provision:`), as Isoloom's own Windows examples do.
//!
//! The project's own files come with the spec ([`Compiled::files`], as [`ProjectFile`]s): the appliances'
//! configurations, and a starter for each provisioning step to edit, so a downloaded project runs as
//! is.
//!
//! The modules follow [`compile`]: the drawing as read (`topology`); its `machines` and their
//! `ports`; the playbooks Isoloom's `controller` runs; the `lans` and their addresses, the
//! `cables`, the `routers` and the switches' `vlans`; the spec as it is built (`draft`) and
//! written (`document`). `project` and `starters` are the project's own files; `error` is what a
//! drawing can get wrong.
//!
//! ```
//! let topology: isothrum_compiler::Topology = serde_json::from_str(
//! r#"{
//! "name": "pair",
//! "networks": { "office": { "cidr": "10.10.1.0/24" } },
//! "nodes": {
//! "web": { "kind": { "container": { "image": "nginx:1.27-alpine" } },
//! "services": [{ "port": 80, "protocol": "http" }], "networks": { "office": null } },
//! "user": { "kind": { "vm": { "os": "debian@12" } }, "access": true, "networks": { "office": null } }
//! }
//! }"#,
//! )?;
//! let compiled = isothrum_compiler::compile(&topology)?;
//! assert!(compiled.yaml().contains("app:\n image: nginx:1.27-alpine"));
//! assert!(compiled.yaml().contains("ports:\n http:\n port: 80\n protocol: http"));
//! assert_eq!(compiled.spec().machines["user"].os.map(|os| os.to_string()).as_deref(), Some("debian@12"));
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
pub use ;
pub use ;
pub use ProjectFile;
pub use ;