container_network_probe.go RawHistoryFolder
1package domain
2
3import (
4 "fmt"
5 "strings"
6 "time"
7)
8
9// ProbeProtocol is the transport one bounded container-network readiness
10// session uses.
11type ProbeProtocol string
12
13const (
14 ProbeProtocolHTTP ProbeProtocol = "http"
15 ProbeProtocolTCP ProbeProtocol = "tcp"
16)
17
18// ContainerNetworkProbeRequest is one bounded readiness session against a
19// declared internal container port. It carries exact identity: the target
20// container, the execution start that must still be current when the
21// session completes, and the already-derived private network the helper
22// joins. Callers never pass a network they did not derive from the app
23// incarnation.
24type ContainerNetworkProbeRequest struct {
25 // TargetContainerID is the exact container to probe.
26 TargetContainerID string
27 // ExpectedStartedAt is the execution start the adapter must observe on
28 // the target before and after the session. A mismatch means the
29 // generation changed under the probe and the result is discarded.
30 ExpectedStartedAt time.Time
31 // Network is the derived private network the helper joins. It is the
32 // only network the helper is attached to.
33 Network string
34 Protocol ProbeProtocol
35 Port int
36 // Path is the origin-form request path for HTTP probes; empty for TCP.
37 Path string
38 // Timeout bounds the operational session through outcome validation.
39 // Mandatory force-removal uses its own independent bounded context.
40 Timeout time.Duration
41}
42
43// ContainerNetworkProbeResult reports one completed session.
44type ContainerNetworkProbeResult struct {
45 // Ready is true when the target accepted a 2xx/3xx HTTP status, or an
46 // accepted TCP connection.
47 Ready bool
48 // Status is the observed HTTP status code when one was read, else 0.
49 Status int
50 // Diagnostic is a bounded, non-sensitive description of an unhealthy
51 // attempt. It never carries addresses, paths, or raw command output.
52 Diagnostic string
53}
54
55// Validate checks the request shape. It rejects missing identity or
56// network, an invalid protocol, port, path, or timeout, and a path on a
57// TCP probe.
58func (r ContainerNetworkProbeRequest) Validate() error {
59 if strings.TrimSpace(r.TargetContainerID) == "" {
60 return fmt.Errorf("%w: target container id is required", ErrInvalidNetworkProbe)
61 }
62 if strings.TrimSpace(r.Network) == "" {
63 return fmt.Errorf("%w: private network is required", ErrInvalidNetworkProbe)
64 }
65 if r.ExpectedStartedAt.IsZero() {
66 // Without an execution boundary the probe could report readiness
67 // for a generation that already restarted. Fail closed.
68 return fmt.Errorf("%w: expected execution start is required", ErrInvalidNetworkProbe)
69 }
70 if r.Port < 1 || r.Port > 65535 {
71 return fmt.Errorf("%w: port must be 1-65535", ErrInvalidNetworkProbe)
72 }
73 if r.Timeout <= 0 {
74 return fmt.Errorf("%w: timeout must be positive", ErrInvalidNetworkProbe)
75 }
76 switch r.Protocol {
77 case ProbeProtocolHTTP:
78 if err := ValidateReadinessPath(r.Path); err != nil {
79 return fmt.Errorf("%w: %v", ErrInvalidNetworkProbe, err)
80 }
81 case ProbeProtocolTCP:
82 if r.Path != "" {
83 return fmt.Errorf("%w: tcp probe takes no path", ErrInvalidNetworkProbe)
84 }
85 default:
86 return fmt.Errorf("%w: protocol must be http|tcp", ErrInvalidNetworkProbe)
87 }
88 return nil
89}