Skip to content

fix: grain up handles existing/stale daemon correctly - #12

Merged
cxdy merged 3 commits into
mainfrom
fix/grain-up-stale-daemon
Jul 27, 2026
Merged

fix: grain up handles existing/stale daemon correctly#12
cxdy merged 3 commits into
mainfrom
fix/grain-up-stale-daemon

Conversation

@cxdy

@cxdy cxdy commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

grain up could print success while an old daemon still owned the socket/API, or after a new child failed to bind. Users saw daemon not up right after a successful-looking grain up.

Changes

  • Detect already-healthy daemon → print already up
  • Refuse second start if pid is live but unhealthy
  • Clean stale pid/socket before start
  • Wait for healthz or child exit (no false success)
  • Setsid on background daemon
  • Harder grain down cleanup

Test plan

  • go test ./internal/cli/
  • On Linux: leave a stray grain up --fg, run grain up → should say already up or tell you to grain down
  • Kill daemon uncleanly, leave socket; grain up should clean and start

Previously grain up always spawned a new process and treated any existing
socket as success, so a leftover grain up --fg could hold the API port
while a second up reported a dead pid. Now:

- healthy daemon → "already up" (no second process)
- live pid but unhealthy → error pointing at grain down
- dead pid / orphan socket → cleaned before start
- background start waits for healthz or child exit (no false success)
- Setsid so shell Ctrl+C does not signal the daemon
- grain down cleans stale files and SIGKILLs if needed
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

Coverage (lines): 74% ❌ — minimum 75%

commit 4971a9a · 9383/12627 lines · cmd/* and tray excluded

Coverage report by file (74% overall — click to expand)
File Coverage Missing
All files 74%
internal/cli/uninstall.go 22% 31-37 45-49 51-57 59-67 69-78 80-82 85-92 95-114 116 118-122 133-135 137-139 144-153 15…
internal/netutil/port.go 45% 11-13 16-18
internal/agent/dial.go 46% 44-46 61-63 77-78 83 85-102 106-113
internal/sshkey/sshkey.go 53% 18-20 33-35 38-44 46-48 50-52
internal/hypervisor/disk_local.go 56% 38-40 45-47 52-54 56-60 62-69 73-76 78-80 96-98 112-114 123
internal/cloudinit/seed.go 57% 46-48 51-53 57-65 77-89 101-103
internal/cli/fs.go 63% 52-54 56-58 60-62 85-101 123-125 127-129 131-133 144-153 175-177 179-181 183-185 191-19…
internal/cli/stats.go 64% 19-21 23-25 27-29 40-42
internal/cli/cp.go 64% 58-60 62-64 72-74 80-82 88 136-139 141-143 145 155-157 169-171 179-181 188-190 200-202 …
internal/cli/tray.go 65% 26-43 58-62
internal/cli/root.go 65% 135-137 144-147 157-159 167-169 182 185-190 194-204 206 208-210 223-225 241-247 249-252…
internal/hypervisor/firecracker.go 66% 139-141 153-163 165-170 173 177-202 204-210 213-236 239-243 246-247 250-251 253-257 262…
internal/api/client.go 67% 46-48 66-68 70-72 74-76 79-81 87-89 97-99 101-103 105-107 111-113 154-156 169-171 173-1…
internal/cli/secret.go 69% 43-45 47-49 52-54 56-58 66-68 103-105 107-109 112-114 120-122 140-142 144-146 149-154 1…
internal/agent/client.go 69% 55-57 59-61 77-79 102-104 123-125 127-129 132-134 155-157 164-172 176-178 180-182 221-2…
client/client.go 70% 96-98 105-107 122-124 126-128 143-145 147-149 164-166 186-188 190-192 194-196 199-201 2…
internal/cli/proxy.go 70% 43-45 79-86 88-99 101-105 107 109-114 116 129-131 133-135 141-143 155-159 164 174-176 1…
internal/cli/image_doctor.go 71% 34-38 53-58 62-71 74-76 102-104 139-141 150-152 157 161-163 174-176 181-187 190-192 203…
internal/proxy/store.go 73% 34-36 61 64-66 73-75 77-79 88-90 110-112 121-123 165 168-171 177-179 181-183 192-194 19…
internal/store/store.go 73% 21-23 39-41 43-45 47-49 61 74-78 107-109
internal/image/catalog.go 74% 69-79 119-132
internal/agent/server.go 74% 91-93 95-97 103 204-206 293-299 332-334 338-341 343-346 388-397 409-421 471-474 476-479…
internal/cli/fwd.go 76% 46-48 127-129 131-133 136-138 143-145 149-151 189-192 207-209 211-213 221-226 233-235 2…
internal/presets/presets.go 76% 31-33 40-42 45-46 49-50 62-64
internal/secrets/store.go 76% 58-60 84-88 101 119-121 148-150 153-159 171-173 197-203 217-219 235 247-249 259 273-275…
internal/cli/logs.go 77% 37-39 44-46 52 55-59 84-86 104-109 113 123 127-128 141-143 158-160 182 209-211 219-221
internal/api/api.go 77% 112-115 215-219 228-251 273-275 398-401 412-415 427-429 437-439 500-503 512-514 519-522…
internal/manager/manager.go 78% 86-88 183-185 201-205 207-209 215-217 238-240 252-258 263-268 380-382 430-432 440-442 4…
internal/hypervisor/qemu.go 78% 33-35 50-52 66-68 72-74 79-81 88-90 95-97 155-162 168-170 174-184 186-189 196-198 202-2…
internal/cli/progress.go 78% 43-49 51-54 63-65 103-111 113-116 131-133 195-197
internal/image/pull.go 78% 106-108 136 157-159 170-172 175-177 188-190 201-205 214-218 220-223 237-239 262-264 267…
internal/proxy/server.go 79% 65-67 114-118 124-127 168-170 173-175 178-181 191-194 198-202 205-208 222-224 227-233 2…
internal/hypervisor/virtiofs.go 80% 28-30 32-34 64-66 104-106 111-114 119-121 126-129 170-172 190-192 199-201
internal/cli/volume.go 82% 24-29
internal/daemon/daemon.go 82% 27-29 57-60 88-90 98-100 105-107
internal/guest/sshwait.go 83% 32-34 39-41 58
internal/hypervisor/fsdev.go 83% 34-40
internal/agent/stats.go 83% 62-64 71-73 80-82 116-118 125-127
internal/hypervisor/qmp.go 84% 50-52 62-69 93-95 97-99
internal/cli/act.go 87% 97-99 101-103 112-116 119-121 143-145 150-152 166-168 209-211 218-220 254-256 337-339
internal/guest/agentdeploy.go 87% 59-61 65-67 75-77
internal/hypervisor/transport.go 91% 69-71
internal/agent/binary.go 91% 58-59 65-66
internal/hostbin/hostbin.go 91% 28-30
internal/config/config.go 92% 306-308 326-328 344-346 385 396-398 426-428 435-437
internal/cli/preset.go 92% 36-38
internal/hypervisor/netdev.go 93% 43-45
internal/cli/agent_dial.go 95% 44-48 150 159
internal/cli/client.go 95% 39-41
internal/cloudinit/merge.go 96% 124-126 180-182 238-240
internal/cli/profile.go 97% 28-30
internal/hypervisor/mock.go 97% 161-163

cxdy added 2 commits July 27, 2026 03:01
Stop the local daemon, remove the CLI binary, and optionally purge the
data directory with --purge (-y skips the prompt). Default keeps VMs
and images; always drops the installer agent cache and runtime files.
Same-repo PRs already post coverage from ci.yml and never upload the
coverage-report artifact. The workflow_run job still ran for every PR
and failed with "Artifact not found". Gate on head_repository != base
and use the compact coverage-pr-comment.sh script for fork posts too.
@cxdy
cxdy merged commit 0e5a52d into main Jul 27, 2026
1 check passed
@cxdy
cxdy deleted the fix/grain-up-stale-daemon branch July 27, 2026 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant