Skip to content

Commit 51ddcdf

Browse files
committed
Add boot state markers: ssh-ready and boot-done
The boot scripts must terminate an existing user session after /etc/environment has been updated to make sure the user session (which may linger) has the updated values. This reset will break the SSH control path, breaking sshfs mounts, so the hostagent must wait until the instance is "ss-ready" for persistent connections. A similar "boot-done" status check is added as a "final" requirement so that `limactl start` doesn't return until all the boot scripts have finished. Signed-off-by: Jan Dubois <[email protected]>
1 parent fad4325 commit 51ddcdf

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

Diff for: pkg/cidata/cidata.TEMPLATE.d/boot.sh

+4
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,9 @@ if [ -d "${LIMA_CIDATA_MNT}"/provision.user ]; then
5959
done
6060
fi
6161

62+
# Signal that provisioning is done. The instance-id in the meta-data file changes on every boot,
63+
# so any copy from a previous boot cycle will have different content.
64+
cp "${LIMA_CIDATA_MNT}"/meta-data /etc/lima-boot-done
65+
6266
INFO "Exiting with code $CODE"
6367
exit "$CODE"

Diff for: pkg/cidata/cidata.TEMPLATE.d/boot/07-etc-environment.sh

+7
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@ cat "${LIMA_CIDATA_MNT}/etc_environment" >>/etc/environment
1616
if command -v loginctl >/dev/null 2>&1; then
1717
loginctl terminate-user "${LIMA_CIDATA_USER}" || true
1818
fi
19+
20+
# Make sure the guestagent socket from a previous boot is removed before we open the "lima-ssh-ready" gate.
21+
rm -f /run/lima-guest-agent.sock
22+
23+
# Signal that provisioning is done. The instance-id in the meta-data file changes on every boot,
24+
# so any copy from a previous boot cycle will have different content.
25+
cp "${LIMA_CIDATA_MNT}"/meta-data /etc/lima-ssh-ready

Diff for: pkg/hostagent/hostagent.go

+3
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ func (a *HostAgent) startHostAgentRoutines(ctx context.Context) error {
388388
if err := a.waitForRequirements(ctx, "optional", a.optionalRequirements()); err != nil {
389389
mErr = multierror.Append(mErr, err)
390390
}
391+
if err := a.waitForRequirements(ctx, "final", a.finalRequirements()); err != nil {
392+
mErr = multierror.Append(mErr, err)
393+
}
391394
return mErr
392395
}
393396

Diff for: pkg/hostagent/requirements.go

+42-5
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,33 @@ type requirement struct {
6060

6161
func (a *HostAgent) essentialRequirements() []requirement {
6262
req := make([]requirement, 0)
63-
req = append(req, requirement{
64-
description: "ssh",
65-
script: `#!/bin/bash
63+
req = append(req,
64+
requirement{
65+
description: "ssh",
66+
script: `#!/bin/bash
6667
true
6768
`,
68-
debugHint: `Failed to SSH into the guest.
69+
debugHint: `Failed to SSH into the guest.
6970
Make sure that the YAML field "ssh.localPort" is not used by other processes on the host.
7071
If any private key under ~/.ssh is protected with a passphrase, you need to have ssh-agent to be running.
7172
`,
72-
})
73+
},
74+
requirement{
75+
description: "user session is ready for ssh",
76+
script: `#!/bin/bash
77+
set -eux -o pipefail
78+
if ! timeout 30s bash -c "until sudo diff -q /etc/lima-ssh-ready /mnt/lima-cidata/meta-data 2>/dev/null; do sleep 3; done"; then
79+
echo >&2 "not ready to start persistent ssh session"
80+
exit 1
81+
fi
82+
`,
83+
debugHint: `The boot sequence will terminate any existing user session after updating
84+
/etc/environment to make sure the session includes the new values.
85+
Terminating the session will break the persistent SSH tunnel, so
86+
it must not be created until the session reset is done.
87+
`,
88+
})
89+
7390
if len(a.y.Mounts) > 0 {
7491
req = append(req, requirement{
7592
description: "sshfs binary to be installed",
@@ -164,3 +181,23 @@ Also see "/var/log/cloud-init-output.log" in the guest.
164181
}
165182
return req
166183
}
184+
185+
func (a *HostAgent) finalRequirements() []requirement {
186+
req := make([]requirement, 0)
187+
req = append(req,
188+
requirement{
189+
description: "boot scripts must have finished",
190+
script: `#!/bin/bash
191+
set -eux -o pipefail
192+
if ! timeout 30s bash -c "until sudo diff -q /etc/lima-boot-done /mnt/lima-cidata/meta-data 2>/dev/null; do sleep 3; done"; then
193+
echo >&2 "boot scripts have not finished"
194+
exit 1
195+
fi
196+
`,
197+
debugHint: `All boot scripts, provisioning scripts, and readiness probes must
198+
finish before the instance is considered "ready".
199+
Check "/var/log/cloud-init-output.log" in the guest to see where the process is blocked!
200+
`,
201+
})
202+
return req
203+
}

0 commit comments

Comments
 (0)