swarmctl: --swarm works after the subcommand, takes a bare domain, and login defaults to the host's swarm
`swarmctl login --swarm X` failed with "unexpected argument", and `login --help` listed no `--swarm`: the flag was only accepted before the verb. `--swarm` and `--ca-file` are now global, so they parse on either side of the subcommand and show in every subcommand's help. `--swarm` / `SWARMCTL_SWARM` accept a bare domain and prepend `https://`. A value with a scheme is parsed as before, so `http://` is still refused. On a swarm-controller host, the swarmctl wrapper sets `SWARMCTL_LOGIN_DEFAULT_SWARM=https://<swarm.domain>` (`--set-default`). Only `login` reads it, after `--swarm` and `SWARMCTL_SWARM`. The wrapper does not set `SWARMCTL_SWARM`: that would send every socket verb (agent create, schedule, inference, forge) through the gateway and make each need a login. Other verbs resolve exactly as before. No CA file is wired. The only CA material the module names is the controller's assembled trust bundle (system CAs plus the hive anchor). `--ca-file` hands every certificate in it to rustls-platform-verifier as an extra root, and that fails the whole client on any one it cannot parse, so pointing it at the system CAs is a risk nothing here can test. The controller daemon trusts the same CA through `SSL_CERT_FILE`, which skips unparsable certificates; using that for swarmctl is left open. Machines that are not swarm-controller hosts (an operator laptop) get no default; that case waits on an answer in the issue. Fixes #5239
This commit is contained in:
parent
62e45df88c
commit
7d95973d83
6 changed files with 176 additions and 15 deletions
|
|
@ -44,9 +44,15 @@ pub(crate) struct Swarm {
|
|||
}
|
||||
|
||||
impl Swarm {
|
||||
/// `url` with no scheme is taken as a bare domain, under `https://`.
|
||||
pub(crate) fn parse(url: &str, ca_file: Option<PathBuf>, state_dir: PathBuf) -> Result<Self> {
|
||||
let full = if url.contains("://") {
|
||||
url.to_owned()
|
||||
} else {
|
||||
format!("https://{url}")
|
||||
};
|
||||
let parsed =
|
||||
url::Url::parse(url).with_context(|| format!("--swarm {url:?} is not a URL"))?;
|
||||
url::Url::parse(&full).with_context(|| format!("--swarm {url:?} is not a URL"))?;
|
||||
if parsed.scheme() != "https" || parsed.host_str().is_none() {
|
||||
bail!("--swarm {url:?} must be an https:// URL naming the swarm's domain");
|
||||
}
|
||||
|
|
@ -382,6 +388,21 @@ mod tests {
|
|||
assert!(Swarm::parse("http://swarm.example.test", None, "/s".into()).is_err());
|
||||
}
|
||||
|
||||
/// A port is no scheme: `host:8443` would otherwise parse as a URL whose
|
||||
/// scheme is `host`.
|
||||
#[test]
|
||||
fn a_bare_domain_is_taken_as_https() {
|
||||
let origin = |url| Swarm::parse(url, None, "/s".into()).expect("parses").origin;
|
||||
assert_eq!(
|
||||
origin("swarm.example.test").as_str(),
|
||||
"https://swarm.example.test/"
|
||||
);
|
||||
assert_eq!(
|
||||
origin("swarm.example.test:8443").as_str(),
|
||||
"https://swarm.example.test:8443/"
|
||||
);
|
||||
}
|
||||
|
||||
/// authelia's token endpoint and the gateway's `/api/`, as far as these
|
||||
/// tests need them: a refresh rotates both tokens, a used refresh token
|
||||
/// revokes the login (as authelia does), and `/api/` admits only the
|
||||
|
|
|
|||
Loading…
Reference in a new issue