probeHealthCheck executes the health check command inside the container context
(ctx context.Context, task containerd.Task, hc *Healthcheck, processSpec *specs.Process)
| 65 | |
| 66 | // probeHealthCheck executes the health check command inside the container context |
| 67 | func probeHealthCheck(ctx context.Context, task containerd.Task, hc *Healthcheck, processSpec *specs.Process) (*HealthcheckResult, error) { |
| 68 | execID := "health-check-" + idgen.TruncateID(idgen.GenerateID()) |
| 69 | outputBuf := NewResizableBuffer(MaxOutputLen) |
| 70 | |
| 71 | process, err := task.Exec(ctx, execID, processSpec, cio.NewCreator( |
| 72 | cio.WithStreams(nil, outputBuf, outputBuf), |
| 73 | )) |
| 74 | if err != nil { |
| 75 | log.G(ctx).Debugf("failed to exec health check: %v", err) |
| 76 | return nil, fmt.Errorf("exec error: %w", err) |
| 77 | } |
| 78 | defer func() { |
| 79 | if _, err := process.Delete(ctx); err != nil { |
| 80 | log.G(ctx).WithError(err).Debug("failed to delete exec process") |
| 81 | } |
| 82 | }() |
| 83 | |
| 84 | if err := process.Start(ctx); err != nil { |
| 85 | log.G(ctx).Debugf("failed to start health check: %v", err) |
| 86 | return nil, fmt.Errorf("start error: %w", err) |
| 87 | } |
| 88 | |
| 89 | exitStatusC, err := process.Wait(ctx) |
| 90 | if err != nil { |
| 91 | return nil, fmt.Errorf("failed to wait for health check: %w", err) |
| 92 | } |
| 93 | |
| 94 | select { |
| 95 | case <-time.After(hc.Timeout): |
| 96 | _ = process.Kill(ctx, syscall.SIGKILL) |
| 97 | <-exitStatusC |
| 98 | process.IO().Wait() |
| 99 | process.IO().Close() |
| 100 | msg := fmt.Sprintf("Health check exceeded timeout (%v)", hc.Timeout) |
| 101 | if out := outputBuf.String(); len(out) > 0 { |
| 102 | msg = fmt.Sprintf("Health check exceeded timeout (%v): %s", hc.Timeout, out) |
| 103 | } |
| 104 | |
| 105 | log.G(ctx).Debugf("health check timed out: %s", msg) |
| 106 | |
| 107 | return &HealthcheckResult{ |
| 108 | ExitCode: -1, |
| 109 | Output: msg, |
| 110 | End: time.Now(), |
| 111 | }, nil |
| 112 | |
| 113 | case exitStatus := <-exitStatusC: |
| 114 | process.IO().Wait() |
| 115 | process.IO().Close() |
| 116 | code, _, _ := exitStatus.Result() |
| 117 | return &HealthcheckResult{ |
| 118 | ExitCode: int(code), |
| 119 | Output: outputBuf.String(), |
| 120 | End: time.Now(), |
| 121 | }, nil |
| 122 | } |
| 123 | } |
| 124 |
no test coverage detected
searching dependent graphs…