From 1d906c77c791b975dfbf9a5f21064d5697fce4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCttler?= Date: Tue, 26 May 2026 12:27:47 +0200 Subject: [PATCH 1/4] Add pass-1 all-disk health check to check-bm-server Run smartctl -H on every disk visible in rescue (not just rootDeviceHints) during the first pass only, so secondary drives and other attached disks are validated without slowing down the second reliability pass. Co-Authored-By: Claude Sonnet 4.6 --- internal/cmd/check_bm_server.go | 1 + internal/provisioncheck/check-all-disks.sh | 55 +++++++++++++++++++ internal/provisioncheck/provisioncheck.go | 61 ++++++++++++++++++++-- 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 internal/provisioncheck/check-all-disks.sh diff --git a/internal/cmd/check_bm_server.go b/internal/cmd/check_bm_server.go index c8a9a54..f5c8b90 100644 --- a/internal/cmd/check_bm_server.go +++ b/internal/cmd/check_bm_server.go @@ -53,6 +53,7 @@ target server.`, flags.DurationVar(&cfg.Timeouts.ActivateRescue, "timeout-activate-rescue", provisioncheck.DefaultActivateRescueTimeout, "Timeout for activating rescue boot") flags.DurationVar(&cfg.Timeouts.RebootToRescue, "timeout-reboot-rescue", provisioncheck.DefaultRebootToRescueTimeout, "Timeout for requesting reboot to rescue") flags.DurationVar(&cfg.Timeouts.WaitForRescue, "timeout-wait-rescue", provisioncheck.DefaultWaitForRescueTimeout, "Timeout for waiting until rescue SSH is reachable") + flags.DurationVar(&cfg.Timeouts.CheckAllDisksHealth, "timeout-check-all-disks", provisioncheck.DefaultCheckAllDisksHealthTimeout, "Timeout for checking health of all disks in rescue (pass 1 only)") flags.DurationVar(&cfg.Timeouts.CheckDiskInRescue, "timeout-check-disk-rescue", provisioncheck.DefaultCheckDiskInRescueTimeout, "Timeout for checking target disks in rescue") flags.DurationVar(&cfg.Timeouts.InstallUbuntu, "timeout-install", provisioncheck.DefaultInstallUbuntuTimeout, "Timeout for one Ubuntu install step") flags.DurationVar(&cfg.Timeouts.RebootToOS, "timeout-reboot-os", provisioncheck.DefaultRebootToOSTimeout, "Timeout for rebooting into installed OS") diff --git a/internal/provisioncheck/check-all-disks.sh b/internal/provisioncheck/check-all-disks.sh new file mode 100644 index 0000000..b0530f0 --- /dev/null +++ b/internal/provisioncheck/check-all-disks.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# Copyright 2026 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -Eeuo pipefail + +# In the rescue system smartctl is always available. This is just needed if the +# script gets executed by hand (outside caph). +if ! type smartctl >/dev/null 2>&1; then + apt-get update -qq + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq smartmontools +fi + +mapfile -t devices < <(lsblk --nodeps --noheadings -o NAME,TYPE | awk '$2=="disk"{print $1}') + +if [ ${#devices[@]} -eq 0 ]; then + echo "ERROR: no disk devices found by lsblk" + exit 1 +fi + +result=$(mktemp) +trap 'rm -f "$result"' EXIT + +for dev in "${devices[@]}"; do + echo "Checking /dev/$dev" + { smartctl -H "/dev/$dev" || true; } \ + | { grep -vP '^(smartctl \d+\.\d+.*|Copyright|=+ START OF)' || true; } \ + | { grep -v '^$' || true; } \ + | { sed "s#^#/dev/$dev: #" || true; } \ + >> "$result" +done + +errors=$(grep -v PASSED "$result" || true) +if [ -n "$errors" ]; then + echo "check-all-disks FAILED" + echo "$errors" + exit 1 +fi + +echo "check-all-disks PASSED. All disks look healthy." +echo +cat "$result" +exit 0 diff --git a/internal/provisioncheck/provisioncheck.go b/internal/provisioncheck/provisioncheck.go index 27927c5..a183074 100644 --- a/internal/provisioncheck/provisioncheck.go +++ b/internal/provisioncheck/provisioncheck.go @@ -21,6 +21,7 @@ limitations under the License. package provisioncheck import ( + _ "embed" "bufio" "bytes" "context" @@ -63,6 +64,8 @@ const ( DefaultRebootToRescueTimeout = 45 * time.Second // DefaultWaitForRescueTimeout is the default timeout for waiting until rescue SSH is reachable. DefaultWaitForRescueTimeout = 8 * time.Minute + // DefaultCheckAllDisksHealthTimeout is the default timeout for the all-disk health check in rescue. + DefaultCheckAllDisksHealthTimeout = 3 * time.Minute // DefaultCheckDiskInRescueTimeout is the default timeout for smartctl disk checks in rescue. DefaultCheckDiskInRescueTimeout = 1 * time.Minute // DefaultInstallUbuntuTimeout is the default timeout for one installimage run. @@ -84,8 +87,9 @@ type Timeouts struct { FetchServerDetails time.Duration ActivateRescue time.Duration RebootToRescue time.Duration - WaitForRescue time.Duration - CheckDiskInRescue time.Duration + WaitForRescue time.Duration + CheckAllDisksHealth time.Duration + CheckDiskInRescue time.Duration InstallUbuntu time.Duration RebootToOS time.Duration WaitForOS time.Duration @@ -114,8 +118,9 @@ func DefaultConfig() Config { FetchServerDetails: DefaultFetchServerDetailsTimeout, ActivateRescue: DefaultActivateRescueTimeout, RebootToRescue: DefaultRebootToRescueTimeout, - WaitForRescue: DefaultWaitForRescueTimeout, - CheckDiskInRescue: DefaultCheckDiskInRescueTimeout, + WaitForRescue: DefaultWaitForRescueTimeout, + CheckAllDisksHealth: DefaultCheckAllDisksHealthTimeout, + CheckDiskInRescue: DefaultCheckDiskInRescueTimeout, InstallUbuntu: DefaultInstallUbuntuTimeout, RebootToOS: DefaultRebootToOSTimeout, WaitForOS: DefaultWaitForOSTimeout, @@ -159,6 +164,9 @@ func (cfg Config) withDefaults() Config { if cfg.Timeouts.WaitForRescue == 0 { cfg.Timeouts.WaitForRescue = defaults.Timeouts.WaitForRescue } + if cfg.Timeouts.CheckAllDisksHealth == 0 { + cfg.Timeouts.CheckAllDisksHealth = defaults.Timeouts.CheckAllDisksHealth + } if cfg.Timeouts.CheckDiskInRescue == 0 { cfg.Timeouts.CheckDiskInRescue = defaults.Timeouts.CheckDiskInRescue } @@ -210,6 +218,9 @@ func (cfg Config) Validate() error { if err := validateTimeout("--timeout-wait-rescue", cfg.Timeouts.WaitForRescue); err != nil { return err } + if err := validateTimeout("--timeout-check-all-disks", cfg.Timeouts.CheckAllDisksHealth); err != nil { + return err + } if err := validateTimeout("--timeout-check-disk-rescue", cfg.Timeouts.CheckDiskInRescue); err != nil { return err } @@ -459,6 +470,17 @@ func (r *runner) cycle(ctx context.Context, pass int) error { return err } + if pass == 1 { + err = r.runStep(ctx, "pass-1-check-all-disks-health", r.cfg.Timeouts.CheckAllDisksHealth, + func(stepCtx context.Context, progress stepProgress) error { + ssh := r.newRescueSSHClient() + return r.checkAllDisksHealth(stepCtx, ssh, progress) + }) + if err != nil { + return err + } + } + err = r.runStep(ctx, fmt.Sprintf("pass-%d-check-disk-in-rescue", pass), r.cfg.Timeouts.CheckDiskInRescue, func(stepCtx context.Context, progress stepProgress) error { ssh := r.newRescueSSHClient() @@ -640,6 +662,37 @@ func (r *runner) checkDiskInRescue(ctx context.Context, ssh sshclient.Client, pr return nil } +//go:embed check-all-disks.sh +var checkAllDisksScript string + +func (r *runner) checkAllDisksHealth(ctx context.Context, ssh sshclient.Client, progress stepProgress) error { + tmpFile, err := os.CreateTemp("", "check-all-disks-*.sh") + if err != nil { + return fmt.Errorf("create temp script: %w", err) + } + tmpPath := tmpFile.Name() + defer func() { + // #nosec G703 -- tmpPath is generated by os.CreateTemp and stays within the local temp dir. + _ = os.Remove(tmpPath) + }() + if _, err = tmpFile.WriteString(checkAllDisksScript); err != nil { + return fmt.Errorf("write temp script: %w", err) + } + if err = tmpFile.Close(); err != nil { + return fmt.Errorf("close temp script: %w", err) + } + + exitStatus, output, err := ssh.ExecutePreProvisionCommand(ctx, tmpPath) + if err != nil { + return fmt.Errorf("check-all-disks ssh error: %w", err) + } + if exitStatus != 0 { + return fmt.Errorf("check-all-disks failed (exit %d):\n%s", exitStatus, output) + } + progress("check-all-disks ok: %s", strings.TrimSpace(output)) + return nil +} + func collectInstallLogs(ctx context.Context, ssh sshclient.Client) (string, error) { script := `#!/bin/bash set +e From fa1d225d279b2e1fadf40fbe0d0438634a34bd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCttler?= Date: Tue, 26 May 2026 13:48:54 +0200 Subject: [PATCH 2/4] Add pass-1 all-disk health check to check-bm-server Run smartctl -H on every disk in rescue (pass 1 only) by enumerating all disk WWNs via GetHardwareDetailsStorage() and reusing CAPH's existing check-disk.sh via ssh.CheckDisk(). Removes the redundant pass-N-check-disk-in-rescue step that only checked rootDeviceHints disks. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 1 + internal/cmd/check_bm_server.go | 1 - internal/provisioncheck/check-all-disks.sh | 55 --------------- internal/provisioncheck/provisioncheck.go | 78 ++++++---------------- 4 files changed, 23 insertions(+), 112 deletions(-) delete mode 100644 internal/provisioncheck/check-all-disks.sh diff --git a/README.md b/README.md index 248a8c6..dcf96d5 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Flags: --name string HetznerBareMetalHost metadata.name. Optional if YAML contains exactly one host --poll-interval duration Polling interval for wait steps (default 10s) --timeout-activate-rescue duration Timeout for activating rescue boot (default 45s) + --timeout-check-all-disks duration Timeout for checking health of all disks in rescue (pass 1 only) (default 3m0s) --timeout-check-disk-rescue duration Timeout for checking target disks in rescue (default 1m0s) --timeout-ensure-ssh-key duration Timeout for ensuring SSH key in Robot (default 1m0s) --timeout-fetch-server duration Timeout for fetching server details from Robot (default 30s) diff --git a/internal/cmd/check_bm_server.go b/internal/cmd/check_bm_server.go index f5c8b90..a77d549 100644 --- a/internal/cmd/check_bm_server.go +++ b/internal/cmd/check_bm_server.go @@ -54,7 +54,6 @@ target server.`, flags.DurationVar(&cfg.Timeouts.RebootToRescue, "timeout-reboot-rescue", provisioncheck.DefaultRebootToRescueTimeout, "Timeout for requesting reboot to rescue") flags.DurationVar(&cfg.Timeouts.WaitForRescue, "timeout-wait-rescue", provisioncheck.DefaultWaitForRescueTimeout, "Timeout for waiting until rescue SSH is reachable") flags.DurationVar(&cfg.Timeouts.CheckAllDisksHealth, "timeout-check-all-disks", provisioncheck.DefaultCheckAllDisksHealthTimeout, "Timeout for checking health of all disks in rescue (pass 1 only)") - flags.DurationVar(&cfg.Timeouts.CheckDiskInRescue, "timeout-check-disk-rescue", provisioncheck.DefaultCheckDiskInRescueTimeout, "Timeout for checking target disks in rescue") flags.DurationVar(&cfg.Timeouts.InstallUbuntu, "timeout-install", provisioncheck.DefaultInstallUbuntuTimeout, "Timeout for one Ubuntu install step") flags.DurationVar(&cfg.Timeouts.RebootToOS, "timeout-reboot-os", provisioncheck.DefaultRebootToOSTimeout, "Timeout for rebooting into installed OS") flags.DurationVar(&cfg.Timeouts.WaitForOS, "timeout-wait-os", provisioncheck.DefaultWaitForOSTimeout, "Timeout for waiting until installed OS is reachable") diff --git a/internal/provisioncheck/check-all-disks.sh b/internal/provisioncheck/check-all-disks.sh deleted file mode 100644 index b0530f0..0000000 --- a/internal/provisioncheck/check-all-disks.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -# Copyright 2026 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -Eeuo pipefail - -# In the rescue system smartctl is always available. This is just needed if the -# script gets executed by hand (outside caph). -if ! type smartctl >/dev/null 2>&1; then - apt-get update -qq - DEBIAN_FRONTEND=noninteractive apt-get install -y -qq smartmontools -fi - -mapfile -t devices < <(lsblk --nodeps --noheadings -o NAME,TYPE | awk '$2=="disk"{print $1}') - -if [ ${#devices[@]} -eq 0 ]; then - echo "ERROR: no disk devices found by lsblk" - exit 1 -fi - -result=$(mktemp) -trap 'rm -f "$result"' EXIT - -for dev in "${devices[@]}"; do - echo "Checking /dev/$dev" - { smartctl -H "/dev/$dev" || true; } \ - | { grep -vP '^(smartctl \d+\.\d+.*|Copyright|=+ START OF)' || true; } \ - | { grep -v '^$' || true; } \ - | { sed "s#^#/dev/$dev: #" || true; } \ - >> "$result" -done - -errors=$(grep -v PASSED "$result" || true) -if [ -n "$errors" ]; then - echo "check-all-disks FAILED" - echo "$errors" - exit 1 -fi - -echo "check-all-disks PASSED. All disks look healthy." -echo -cat "$result" -exit 0 diff --git a/internal/provisioncheck/provisioncheck.go b/internal/provisioncheck/provisioncheck.go index a183074..6db0ccb 100644 --- a/internal/provisioncheck/provisioncheck.go +++ b/internal/provisioncheck/provisioncheck.go @@ -21,7 +21,6 @@ limitations under the License. package provisioncheck import ( - _ "embed" "bufio" "bytes" "context" @@ -66,8 +65,6 @@ const ( DefaultWaitForRescueTimeout = 8 * time.Minute // DefaultCheckAllDisksHealthTimeout is the default timeout for the all-disk health check in rescue. DefaultCheckAllDisksHealthTimeout = 3 * time.Minute - // DefaultCheckDiskInRescueTimeout is the default timeout for smartctl disk checks in rescue. - DefaultCheckDiskInRescueTimeout = 1 * time.Minute // DefaultInstallUbuntuTimeout is the default timeout for one installimage run. DefaultInstallUbuntuTimeout = 9 * time.Minute // DefaultRebootToOSTimeout is the default timeout for rebooting into the installed OS. @@ -88,8 +85,7 @@ type Timeouts struct { ActivateRescue time.Duration RebootToRescue time.Duration WaitForRescue time.Duration - CheckAllDisksHealth time.Duration - CheckDiskInRescue time.Duration + CheckAllDisksHealth time.Duration InstallUbuntu time.Duration RebootToOS time.Duration WaitForOS time.Duration @@ -120,7 +116,6 @@ func DefaultConfig() Config { RebootToRescue: DefaultRebootToRescueTimeout, WaitForRescue: DefaultWaitForRescueTimeout, CheckAllDisksHealth: DefaultCheckAllDisksHealthTimeout, - CheckDiskInRescue: DefaultCheckDiskInRescueTimeout, InstallUbuntu: DefaultInstallUbuntuTimeout, RebootToOS: DefaultRebootToOSTimeout, WaitForOS: DefaultWaitForOSTimeout, @@ -167,9 +162,6 @@ func (cfg Config) withDefaults() Config { if cfg.Timeouts.CheckAllDisksHealth == 0 { cfg.Timeouts.CheckAllDisksHealth = defaults.Timeouts.CheckAllDisksHealth } - if cfg.Timeouts.CheckDiskInRescue == 0 { - cfg.Timeouts.CheckDiskInRescue = defaults.Timeouts.CheckDiskInRescue - } if cfg.Timeouts.InstallUbuntu == 0 { cfg.Timeouts.InstallUbuntu = defaults.Timeouts.InstallUbuntu } @@ -221,9 +213,6 @@ func (cfg Config) Validate() error { if err := validateTimeout("--timeout-check-all-disks", cfg.Timeouts.CheckAllDisksHealth); err != nil { return err } - if err := validateTimeout("--timeout-check-disk-rescue", cfg.Timeouts.CheckDiskInRescue); err != nil { - return err - } if err := validateTimeout("--timeout-install", cfg.Timeouts.InstallUbuntu); err != nil { return err } @@ -481,15 +470,6 @@ func (r *runner) cycle(ctx context.Context, pass int) error { } } - err = r.runStep(ctx, fmt.Sprintf("pass-%d-check-disk-in-rescue", pass), r.cfg.Timeouts.CheckDiskInRescue, - func(stepCtx context.Context, progress stepProgress) error { - ssh := r.newRescueSSHClient() - return r.checkDiskInRescue(stepCtx, ssh, progress) - }) - if err != nil { - return err - } - err = r.runStep(ctx, fmt.Sprintf("pass-%d-install-ubuntu-24.04", pass), r.cfg.Timeouts.InstallUbuntu, func(stepCtx context.Context, progress stepProgress) error { ssh := r.newRescueSSHClient() @@ -647,49 +627,35 @@ func (r *runner) runInstall(ctx context.Context, ssh sshclient.Client, progress }) } -func (r *runner) checkDiskInRescue(ctx context.Context, ssh sshclient.Client, progress stepProgress) error { - rootWWNs := r.host.Spec.RootDeviceHints.ListOfWWN() - if len(rootWWNs) == 0 { - return errors.New("rootDeviceHints are required in the input HBMH") +func (r *runner) checkAllDisksHealth(ctx context.Context, ssh sshclient.Client, progress stepProgress) error { + out := ssh.GetHardwareDetailsStorage() + if out.Err != nil { + return fmt.Errorf("get storage details: %w", out.Err) } - - diskInfo, err := ssh.CheckDisk(ctx, rootWWNs) - if err != nil { - return fmt.Errorf("check-disk failed: %w", err) + if strings.TrimSpace(out.StdOut) == "" { + return errors.New("storage output is empty") } - progress("check-disk ok: %s", strings.TrimSpace(diskInfo)) - return nil -} - -//go:embed check-all-disks.sh -var checkAllDisksScript string - -func (r *runner) checkAllDisksHealth(ctx context.Context, ssh sshclient.Client, progress stepProgress) error { - tmpFile, err := os.CreateTemp("", "check-all-disks-*.sh") - if err != nil { - return fmt.Errorf("create temp script: %w", err) - } - tmpPath := tmpFile.Name() - defer func() { - // #nosec G703 -- tmpPath is generated by os.CreateTemp and stays within the local temp dir. - _ = os.Remove(tmpPath) - }() - if _, err = tmpFile.WriteString(checkAllDisksScript); err != nil { - return fmt.Errorf("write temp script: %w", err) + var allWWNs []string + for _, line := range strings.Split(strings.TrimSpace(out.StdOut), "\n") { + var s storageDetails + if err := json.Unmarshal([]byte(validJSONFromSSHOutput(line)), &s); err != nil { + return fmt.Errorf("parse lsblk line %q: %w", line, err) + } + if s.Type == "disk" && normalizeWWN(s.WWN) != "" { + allWWNs = append(allWWNs, s.WWN) + } } - if err = tmpFile.Close(); err != nil { - return fmt.Errorf("close temp script: %w", err) + + if len(allWWNs) == 0 { + return errors.New("no disk WWNs found — cannot run all-disk health check") } - exitStatus, output, err := ssh.ExecutePreProvisionCommand(ctx, tmpPath) + diskInfo, err := ssh.CheckDisk(ctx, allWWNs) if err != nil { - return fmt.Errorf("check-all-disks ssh error: %w", err) - } - if exitStatus != 0 { - return fmt.Errorf("check-all-disks failed (exit %d):\n%s", exitStatus, output) + return fmt.Errorf("check-all-disks failed: %w", err) } - progress("check-all-disks ok: %s", strings.TrimSpace(output)) + progress("check-all-disks ok:\n%s", strings.TrimSpace(diskInfo)) return nil } From 2f4f27f6394634a2e1b0de8a1b0a6cd7dc73f0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCttler?= Date: Tue, 26 May 2026 16:42:54 +0200 Subject: [PATCH 3/4] go generate... --- README.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index dcf96d5..f5eb72e 100644 --- a/README.md +++ b/README.md @@ -80,22 +80,21 @@ Examples: --name bm-e2e-1731561 Flags: - --force Skip the destructive-action confirmation prompt - -h, --help help for check-bm-server - --image-path string Installimage IMAGE path for operating system inside the Hetzner rescue system (default "/root/.oldroot/nfs/images/Ubuntu-2404-noble-amd64-base.tar.gz") - --name string HetznerBareMetalHost metadata.name. Optional if YAML contains exactly one host - --poll-interval duration Polling interval for wait steps (default 10s) - --timeout-activate-rescue duration Timeout for activating rescue boot (default 45s) - --timeout-check-all-disks duration Timeout for checking health of all disks in rescue (pass 1 only) (default 3m0s) - --timeout-check-disk-rescue duration Timeout for checking target disks in rescue (default 1m0s) - --timeout-ensure-ssh-key duration Timeout for ensuring SSH key in Robot (default 1m0s) - --timeout-fetch-server duration Timeout for fetching server details from Robot (default 30s) - --timeout-install duration Timeout for one Ubuntu install step (default 9m0s) - --timeout-load-input duration Timeout for input parsing + env loading (default 30s) - --timeout-reboot-os duration Timeout for rebooting into installed OS (default 45s) - --timeout-reboot-rescue duration Timeout for requesting reboot to rescue (default 45s) - --timeout-wait-os duration Timeout for waiting until installed OS is reachable (default 6m0s) - --timeout-wait-rescue duration Timeout for waiting until rescue SSH is reachable (default 8m0s) + --force Skip the destructive-action confirmation prompt + -h, --help help for check-bm-server + --image-path string Installimage IMAGE path for operating system inside the Hetzner rescue system (default "/root/.oldroot/nfs/images/Ubuntu-2404-noble-amd64-base.tar.gz") + --name string HetznerBareMetalHost metadata.name. Optional if YAML contains exactly one host + --poll-interval duration Polling interval for wait steps (default 10s) + --timeout-activate-rescue duration Timeout for activating rescue boot (default 45s) + --timeout-check-all-disks duration Timeout for checking health of all disks in rescue (pass 1 only) (default 3m0s) + --timeout-ensure-ssh-key duration Timeout for ensuring SSH key in Robot (default 1m0s) + --timeout-fetch-server duration Timeout for fetching server details from Robot (default 30s) + --timeout-install duration Timeout for one Ubuntu install step (default 9m0s) + --timeout-load-input duration Timeout for input parsing + env loading (default 30s) + --timeout-reboot-os duration Timeout for rebooting into installed OS (default 45s) + --timeout-reboot-rescue duration Timeout for requesting reboot to rescue (default 45s) + --timeout-wait-os duration Timeout for waiting until installed OS is reachable (default 6m0s) + --timeout-wait-rescue duration Timeout for waiting until rescue SSH is reachable (default 8m0s) ``` ### `caphcli create-host-yaml --help` From 34054dffbe8574b4b28ae856b10ed9cc0e06dfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCttler?= Date: Tue, 26 May 2026 17:09:10 +0200 Subject: [PATCH 4/4] Fix gofmt alignment in Timeouts struct Co-Authored-By: Claude Sonnet 4.6 --- internal/provisioncheck/provisioncheck.go | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/internal/provisioncheck/provisioncheck.go b/internal/provisioncheck/provisioncheck.go index 6db0ccb..9dff180 100644 --- a/internal/provisioncheck/provisioncheck.go +++ b/internal/provisioncheck/provisioncheck.go @@ -79,16 +79,16 @@ const ( // Timeouts contains per-step timeouts for the provision check workflow. type Timeouts struct { - LoadInput time.Duration - EnsureSSHKey time.Duration - FetchServerDetails time.Duration - ActivateRescue time.Duration - RebootToRescue time.Duration - WaitForRescue time.Duration + LoadInput time.Duration + EnsureSSHKey time.Duration + FetchServerDetails time.Duration + ActivateRescue time.Duration + RebootToRescue time.Duration + WaitForRescue time.Duration CheckAllDisksHealth time.Duration - InstallUbuntu time.Duration - RebootToOS time.Duration - WaitForOS time.Duration + InstallUbuntu time.Duration + RebootToOS time.Duration + WaitForOS time.Duration } // Config configures the provision check run. @@ -109,16 +109,16 @@ func DefaultConfig() Config { ImagePath: DefaultUbuntu2404ImagePath, PollInterval: DefaultPollInterval, Timeouts: Timeouts{ - LoadInput: DefaultLoadInputTimeout, - EnsureSSHKey: DefaultEnsureSSHKeyTimeout, - FetchServerDetails: DefaultFetchServerDetailsTimeout, - ActivateRescue: DefaultActivateRescueTimeout, - RebootToRescue: DefaultRebootToRescueTimeout, + LoadInput: DefaultLoadInputTimeout, + EnsureSSHKey: DefaultEnsureSSHKeyTimeout, + FetchServerDetails: DefaultFetchServerDetailsTimeout, + ActivateRescue: DefaultActivateRescueTimeout, + RebootToRescue: DefaultRebootToRescueTimeout, WaitForRescue: DefaultWaitForRescueTimeout, CheckAllDisksHealth: DefaultCheckAllDisksHealthTimeout, - InstallUbuntu: DefaultInstallUbuntuTimeout, - RebootToOS: DefaultRebootToOSTimeout, - WaitForOS: DefaultWaitForOSTimeout, + InstallUbuntu: DefaultInstallUbuntuTimeout, + RebootToOS: DefaultRebootToOSTimeout, + WaitForOS: DefaultWaitForOSTimeout, }, Input: os.Stdin, Output: os.Stdout,