@@ -95,6 +95,25 @@ func (hp *HostPortStrategy) Timeout() *time.Duration {
9595 return hp .timeout
9696}
9797
98+ // detectInternalPort returns the lowest internal port that is currently bound.
99+ // If no internal port is found, it returns the zero nat.Port value which
100+ // can be checked against an empty string.
101+ func (hp * HostPortStrategy ) detectInternalPort (ctx context.Context , target StrategyTarget ) (nat.Port , error ) {
102+ var internalPort nat.Port
103+ inspect , err := target .Inspect (ctx )
104+ if err != nil {
105+ return internalPort , fmt .Errorf ("inspect: %w" , err )
106+ }
107+
108+ for port := range inspect .NetworkSettings .Ports {
109+ if internalPort == "" || port .Int () < internalPort .Int () {
110+ internalPort = port
111+ }
112+ }
113+
114+ return internalPort , nil
115+ }
116+
98117// WaitUntilReady implements Strategy.WaitUntilReady
99118func (hp * HostPortStrategy ) WaitUntilReady (ctx context.Context , target StrategyTarget ) error {
100119 timeout := defaultStartupTimeout ()
@@ -113,26 +132,34 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
113132 waitInterval := hp .PollInterval
114133
115134 internalPort := hp .Port
135+ i := 0
116136 if internalPort == "" {
117- inspect , err := target .Inspect (ctx )
137+ // Port is not specified, so we need to detect it.
138+ internalPort , err = hp .detectInternalPort (ctx , target )
118139 if err != nil {
119- return err
140+ return fmt . Errorf ( "detect internal port: %w" , err )
120141 }
121142
122- for port := range inspect .NetworkSettings .Ports {
123- if internalPort == "" || port .Int () < internalPort .Int () {
124- internalPort = port
143+ for internalPort == "" {
144+ select {
145+ case <- ctx .Done ():
146+ return fmt .Errorf ("detect internal port: retries: %d, last err: %w, ctx err: %w" , i , err , ctx .Err ())
147+ case <- time .After (waitInterval ):
148+ if err := checkTarget (ctx , target ); err != nil {
149+ return fmt .Errorf ("detect internal port: check target: retries: %d, last err: %w" , i , err )
150+ }
151+
152+ internalPort , err = hp .detectInternalPort (ctx , target )
153+ if err != nil {
154+ return fmt .Errorf ("detect internal port: %w" , err )
155+ }
125156 }
126157 }
127158 }
128159
129- if internalPort == "" {
130- return errors .New ("no port to wait for" )
131- }
132-
133160 var port nat.Port
134161 port , err = target .MappedPort (ctx , internalPort )
135- i : = 0
162+ i = 0
136163
137164 for port == "" {
138165 i ++
@@ -142,7 +169,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
142169 return fmt .Errorf ("mapped port: retries: %d, port: %q, last err: %w, ctx err: %w" , i , port , err , ctx .Err ())
143170 case <- time .After (waitInterval ):
144171 if err := checkTarget (ctx , target ); err != nil {
145- return fmt .Errorf ("check target: retries: %d, port: %q, last err: %w" , i , port , err )
172+ return fmt .Errorf ("mapped port: check target: retries: %d, port: %q, last err: %w" , i , port , err )
146173 }
147174 port , err = target .MappedPort (ctx , internalPort )
148175 if err != nil {
0 commit comments