clan-app: Add password input

This commit is contained in:
Qubasa
2025-09-02 13:37:12 +02:00
parent 0ac6d7be87
commit 53ce3cf53d
4 changed files with 46 additions and 5 deletions

View File

@@ -53,6 +53,7 @@ export interface InstallStoreType {
install: { install: {
targetHost: string; targetHost: string;
port?: string; port?: string;
password?: string;
machineName: string; machineName: string;
mainDisk: string; mainDisk: string;
// ...TODO Vars // ...TODO Vars

View File

@@ -54,6 +54,7 @@ const ConfigureAdressSchema = v.object({
v.transform((val) => (val === "" ? undefined : val)), v.transform((val) => (val === "" ? undefined : val)),
), ),
), ),
password: v.optional(v.string()),
}); });
type ConfigureAdressForm = v.InferInput<typeof ConfigureAdressSchema>; type ConfigureAdressForm = v.InferInput<typeof ConfigureAdressSchema>;
@@ -84,6 +85,7 @@ const ConfigureAddress = () => {
...s, ...s,
targetHost: values.targetHost, targetHost: values.targetHost,
port: values.port, port: values.port,
password: values.password,
})); }));
// Here you would typically trigger the ISO creation process // Here you would typically trigger the ISO creation process
@@ -98,12 +100,14 @@ const ConfigureAddress = () => {
const portValue = getValue(formStore, "port"); const portValue = getValue(formStore, "port");
const port = portValue ? parseInt(portValue, 10) : undefined; const port = portValue ? parseInt(portValue, 10) : undefined;
const password = getValue(formStore, "password") || undefined;
setLoading(true); setLoading(true);
const call = client.fetch("check_machine_ssh_login", { const call = client.fetch("check_machine_ssh_login", {
remote: { remote: {
address, address,
...(port && { port }), ...(port && { port }),
password: password,
ssh_options: { ssh_options: {
StrictHostKeyChecking: "no", StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null", UserKnownHostsFile: "/dev/null",
@@ -163,6 +167,24 @@ const ConfigureAddress = () => {
/> />
)} )}
</Field> </Field>
<Field name="password">
{(field, props) => (
<TextInput
{...field}
label="Password"
description="SSH password (optional)"
value={field.value}
orientation="horizontal"
validationState={
getError(formStore, "port") ? "invalid" : "valid"
}
input={{
...props,
type: "password",
}}
/>
)}
</Field>
</Fieldset> </Fieldset>
</div> </div>
} }
@@ -224,6 +246,7 @@ const CheckHardware = () => {
target_host: { target_host: {
address: store.install.targetHost, address: store.install.targetHost,
...(port && { port }), ...(port && { port }),
password: store.install.password,
ssh_options: { ssh_options: {
StrictHostKeyChecking: "no", StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null", UserKnownHostsFile: "/dev/null",
@@ -650,6 +673,7 @@ const InstallSummary = () => {
target_host: { target_host: {
address: store.install.targetHost, address: store.install.targetHost,
...(port && { port }), ...(port && { port }),
password: store.install.password,
ssh_options: { ssh_options: {
StrictHostKeyChecking: "no", StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null", UserKnownHostsFile: "/dev/null",

View File

@@ -1,5 +1,6 @@
import json import json
import logging import logging
import os
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
@@ -91,6 +92,15 @@ def run_machine_hardware_info(
str(opts.backend.config_path(machine)), str(opts.backend.config_path(machine)),
] ]
environ = os.environ.copy()
if target_host.password:
cmd += [
"--env-password",
"--ssh-option",
"IdentitiesOnly=yes",
]
environ["SSHPASS"] = target_host.password
if target_host.private_key: if target_host.private_key:
cmd += ["--ssh-option", f"IdentityFile={target_host.private_key}"] cmd += ["--ssh-option", f"IdentityFile={target_host.private_key}"]
@@ -113,7 +123,9 @@ def run_machine_hardware_info(
run( run(
cmd, cmd,
RunOpts(log=Log.BOTH, prefix=machine.name, needs_user_terminal=True), RunOpts(
log=Log.BOTH, prefix=machine.name, needs_user_terminal=True, env=environ
),
) )
print(f"Successfully generated: {hw_file}") print(f"Successfully generated: {hw_file}")

View File

@@ -122,9 +122,6 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
phases=["partitioning"], phases=["partitioning"],
) )
if target_host.password:
os.environ["SSHPASS"] = target_host.password
cmd = [ cmd = [
"nixos-anywhere", "nixos-anywhere",
"--flake", "--flake",
@@ -161,12 +158,14 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
], ],
) )
environ = os.environ.copy()
if target_host.password: if target_host.password:
cmd += [ cmd += [
"--env-password", "--env-password",
"--ssh-option", "--ssh-option",
"IdentitiesOnly=yes", "IdentitiesOnly=yes",
] ]
environ["SSHPASS"] = target_host.password
# Always set a nixos-anywhere private key to prevent failures when running # Always set a nixos-anywhere private key to prevent failures when running
# 'clan install --phases kexec' followed by 'clan install --phases disko,install,reboot'. # 'clan install --phases kexec' followed by 'clan install --phases disko,install,reboot'.
@@ -226,7 +225,12 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
notify_install_step(notification) notify_install_step(notification)
run( run(
[*cmd, "--phases", phase], [*cmd, "--phases", phase],
RunOpts(log=Log.BOTH, prefix=machine.name, needs_user_terminal=True), RunOpts(
log=Log.BOTH,
prefix=machine.name,
needs_user_terminal=True,
env=environ,
),
) )
if opts.phases: if opts.phases: