Skip to content

Commit 6cdbbd7

Browse files
committed
fix missing vhost dir no error
1 parent 897a16c commit 6cdbbd7

3 files changed

Lines changed: 86 additions & 2 deletions

File tree

docs/config-reference.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,21 @@
33
Fluxheim config is TOML. Unknown fields are rejected, so misspelled settings
44
fail during `--check-config` instead of being ignored.
55

6-
Validate a config before running it:
6+
Inspect a config before running it:
77

88
```bash
99
fluxheim --check-config --config path/to/fluxheim.toml
1010
```
1111

12+
For deployment preflight, use `--validate-config`. This performs the same
13+
static validation and also builds the runtime proxy state, so missing static
14+
web roots and other startup-blocking filesystem issues fail before systemd
15+
starts the service:
16+
17+
```bash
18+
fluxheim --validate-config --config /etc/fluxheim/fluxheim.toml
19+
```
20+
1221
For split config directories, Fluxheim reads `*.toml` files in sorted order:
1322

1423
```bash

src/cli.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ where
109109
}
110110

111111
if cli.validate_config {
112+
validate_runtime_config(&config)?;
112113
return Ok(());
113114
}
114115

@@ -119,6 +120,17 @@ where
119120
crate::runtime::run(config)
120121
}
121122

123+
#[cfg(feature = "proxy")]
124+
fn validate_runtime_config(config: &Config) -> Result<(), Box<dyn Error + Send + Sync>> {
125+
crate::proxy::FluxProxy::from_config(config)?;
126+
Ok(())
127+
}
128+
129+
#[cfg(not(feature = "proxy"))]
130+
fn validate_runtime_config(_config: &Config) -> Result<(), Box<dyn Error + Send + Sync>> {
131+
Ok(())
132+
}
133+
122134
fn run_command(
123135
command: &CliCommand,
124136
config_path: Option<&std::path::Path>,
@@ -299,6 +311,23 @@ mod tests {
299311
.unwrap();
300312
}
301313

314+
#[test]
315+
fn validate_config_rejects_missing_static_root() {
316+
let dir = TestDir::new("cli-validate-missing-root");
317+
let missing_root = safe_child_path(&dir.path, "missing-site");
318+
let config = dir.web_config("fluxheim.toml", "example", "example.test", &missing_root);
319+
320+
let error = run_from_args([
321+
"fluxheim",
322+
"--config",
323+
config.to_str().unwrap(),
324+
"--validate-config",
325+
])
326+
.unwrap_err();
327+
328+
assert!(error.to_string().contains("web root does not exist"));
329+
}
330+
302331
#[test]
303332
fn snapshot_command_creates_store_snapshot() {
304333
let dir = TestDir::new("cli-snapshot-command");
@@ -417,6 +446,26 @@ mod tests {
417446
path
418447
}
419448

449+
fn web_config(&self, name: &str, vhost_name: &str, host: &str, root: &Path) -> PathBuf {
450+
let path = safe_child_path(&self.path, name);
451+
fs::write(
452+
&path,
453+
format!(
454+
r#"
455+
[[vhosts]]
456+
name = "{vhost_name}"
457+
hosts = ["{host}"]
458+
459+
[vhosts.web]
460+
root = "{}"
461+
"#,
462+
root.display()
463+
),
464+
)
465+
.expect("write config");
466+
path
467+
}
468+
420469
fn minimal_config(&self, name: &str, listen: &str) -> PathBuf {
421470
let path = safe_child_path(&self.path, name);
422471
fs::write(

src/web.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,16 @@ impl StaticFileServer {
5050
));
5151
}
5252

53-
let root_metadata = std::fs::symlink_metadata(root)?;
53+
let root_metadata = match std::fs::symlink_metadata(root) {
54+
Ok(metadata) => metadata,
55+
Err(error) if error.kind() == io::ErrorKind::NotFound => {
56+
return Err(io::Error::new(
57+
io::ErrorKind::InvalidInput,
58+
format!("web root does not exist: {}", root.display()),
59+
));
60+
}
61+
Err(error) => return Err(error),
62+
};
5463
if root_metadata.file_type().is_symlink() || !root_metadata.is_dir() {
5564
return Err(io::Error::new(
5665
io::ErrorKind::InvalidInput,
@@ -1141,6 +1150,23 @@ mod tests {
11411150
let _ = fs::remove_file(root);
11421151
}
11431152

1153+
#[test]
1154+
fn rejects_missing_static_root() {
1155+
let root = unique_temp_path("web-root-missing");
1156+
1157+
let error = StaticFileServer::from_config(&WebConfig {
1158+
root: Some(root.clone()),
1159+
index_files: vec!["index.html".to_owned()],
1160+
deny_dotfiles: true,
1161+
..WebConfig::default()
1162+
})
1163+
.unwrap_err();
1164+
1165+
assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
1166+
assert!(error.to_string().contains("web root does not exist"));
1167+
assert!(error.to_string().contains(&root.display().to_string()));
1168+
}
1169+
11441170
#[cfg(unix)]
11451171
#[test]
11461172
fn rejects_static_root_below_symlinked_directory() {

0 commit comments

Comments
 (0)