Skip to main content

isoloom_plan/configure/
resources.rs

1//! The resources of a resolved recipe: each step of the model with nothing left to resolve. A
2//! step that needs no resolving (a file, a user, a command) is its authored type, so the model
3//! has one definition of it; the others carry what their machine's OS and ports make of them.
4
5use std::num::NonZeroU16;
6
7use isoloom_spec::model::Protocol;
8use isoloom_spec::syntax::{AbsPath, AptWord, Argv, HttpsUrl, ProjectPath, RepositoryKey, RepositoryName, UnitName, UserName};
9
10/// A package to install, its version pinned when given (an entry's always is, from `lock.yml`).
11pub type PinnedPackage = isoloom_spec::syntax::Package;
12/// A project file or folder copied as it is.
13pub type CopyPlan = isoloom_spec::syntax::Copy;
14/// A folder, a removal, a link or a pinned download.
15pub type FilePlan = isoloom_spec::syntax::FileStep;
16/// A project file whose placeholders [`super::fill`] fills in, placed in the machine.
17pub type TemplatePlan = isoloom_spec::syntax::Template;
18/// A local user (its literal password hashed when rendered for Linux).
19pub type UserPlan = isoloom_spec::syntax::UserStep;
20/// A local group.
21pub type GroupPlan = isoloom_spec::syntax::GroupStep;
22/// A command run once, behind its guard.
23pub type CommandPlan = isoloom_spec::syntax::CommandStep;
24
25/// One resource of a recipe, in the order the recipe lists it: no renderer reorders, groups or
26/// parallelizes them.
27#[derive(Debug, Clone, PartialEq, Eq)]
28#[non_exhaustive]
29pub enum Resource {
30    /// A vendor's package repository.
31    Repository(RepositoryPlan),
32    /// Packages, installed together.
33    Packages(Vec<PinnedPackage>),
34    /// A project file or folder.
35    Copy(CopyPlan),
36    /// A folder, a removal, a link or a download.
37    File(FilePlan),
38    /// A template, filled in at generation.
39    Template(TemplatePlan),
40    /// A user.
41    User(UserPlan),
42    /// A group.
43    Group(GroupPlan),
44    /// A daemon.
45    Service(ServicePlan),
46    /// A command, behind its guard.
47    Command(CommandPlan),
48    /// Ports opened in the OS's firewall.
49    Firewall(Vec<PortSpec>),
50    /// A project script.
51    Run(RunPlan),
52    /// A restart.
53    Reboot,
54    /// An Ansible playbook of the project.
55    Playbook(ProjectPath),
56}
57
58impl Resource {
59    /// The step kind it comes from, as written (`repository`, `run`).
60    #[must_use]
61    pub fn kind(&self) -> &'static str {
62        match self {
63            Resource::Repository(_) => "repository",
64            Resource::Packages(_) => "packages",
65            Resource::Copy(_) => "copy",
66            Resource::File(_) => "file",
67            Resource::Template(_) => "template",
68            Resource::User(_) => "user",
69            Resource::Group(_) => "group",
70            Resource::Service(_) => "service",
71            Resource::Command(_) => "command",
72            Resource::Firewall(_) => "firewall",
73            Resource::Run(_) => "run",
74            Resource::Reboot => "reboot",
75            Resource::Playbook(_) => "playbook",
76        }
77    }
78}
79
80/// The package manager a repository is added to: the OS family's.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
82#[non_exhaustive]
83pub enum RepositoryKind {
84    /// A deb822 source and its keyring (Debian's family).
85    Apt,
86    /// A `.repo` file and its key (Red Hat's family).
87    Rpm,
88    /// A `repositories` line and its key (Alpine).
89    Apk,
90}
91
92/// A repository, its suite and components resolved (apt's) and its key pinned.
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct RepositoryPlan {
95    /// Its name: it names the source and key files.
96    pub name: RepositoryName,
97    /// The package manager it is added to.
98    pub kind: RepositoryKind,
99    /// Its address.
100    pub url: HttpsUrl,
101    /// Its signing key, pinned by SHA-256.
102    pub key: RepositoryKey,
103    /// The suite (apt: the step's, else the OS's codename).
104    pub suite: Option<AptWord>,
105    /// The components (apt: the step's, else `main`; empty for the others).
106    pub components: Vec<AptWord>,
107    /// Its priority over the OS's own packages.
108    pub priority: Option<i32>,
109}
110
111/// A daemon, its unit resolved for the family.
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct ServicePlan {
114    /// The unit, as the family names it (`ssh` on Debian for the table's `ssh`, `sshd` on Rocky).
115    pub unit: UnitName,
116    /// Where its unit comes from.
117    pub source: ServiceSource,
118    /// Started at boot and now (else disabled and stopped).
119    pub enabled: bool,
120}
121
122/// Where a service's unit comes from.
123#[derive(Debug, Clone, PartialEq, Eq)]
124#[non_exhaustive]
125pub enum ServiceSource {
126    /// A package installs it.
127    Package,
128    /// Isoloom defines it from the step's `run`.
129    Defined {
130        /// What runs, in the foreground.
131        run: Argv,
132        /// The user it runs as (root when `None`).
133        user: Option<UserName>,
134        /// The folder it runs in.
135        cwd: Option<AbsPath>,
136    },
137}
138
139/// A port, by number and transport.
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141pub struct PortSpec {
142    /// The number.
143    pub port: NonZeroU16,
144    /// The transport.
145    pub protocol: Protocol,
146}
147
148/// A project script, and the shell that runs it.
149#[derive(Debug, Clone, PartialEq, Eq)]
150pub struct RunPlan {
151    /// The script.
152    pub script: ProjectPath,
153    /// A path whose existence means it already ran.
154    pub creates: Option<AbsPath>,
155    /// What runs it.
156    pub shell: Shell,
157}
158
159/// What runs a script.
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
161#[non_exhaustive]
162pub enum Shell {
163    /// `sh` (Linux).
164    Posix,
165    /// PowerShell (Windows).
166    PowerShell,
167}