3232import org .slf4j .Logger ;
3333import org .slf4j .LoggerFactory ;
3434
35+ import io .fabric8 .kubernetes .api .model .ContainerStatus ;
3536import io .fabric8 .kubernetes .api .model .HasMetadata ;
37+ import io .fabric8 .kubernetes .api .model .Pod ;
38+ import io .fabric8 .kubernetes .api .model .apps .Deployment ;
3639import io .fabric8 .kubernetes .api .model .rbac .ClusterRoleBinding ;
3740import io .fabric8 .kubernetes .client .KubernetesClient ;
3841import io .fabric8 .kubernetes .client .KubernetesClientBuilder ;
42+ import io .fabric8 .kubernetes .client .KubernetesClientTimeoutException ;
3943
4044public class ClusterDeployedOperatorExtension extends AbstractOperatorExtension {
4145
@@ -139,9 +143,14 @@ protected void before(ExtensionContext context) {
139143 });
140144
141145 kubernetesClient .resourceList (operatorDeployment ).inNamespace (namespace ).createOrReplace ();
142- kubernetesClient
143- .resourceList (operatorDeployment )
144- .waitUntilReady (operatorDeploymentTimeout .toMillis (), TimeUnit .MILLISECONDS );
146+ try {
147+ kubernetesClient
148+ .resourceList (operatorDeployment )
149+ .waitUntilReady (operatorDeploymentTimeout .toMillis (), TimeUnit .MILLISECONDS );
150+ } catch (KubernetesClientTimeoutException e ) {
151+ logDiagnosticInfo (kubernetesClient );
152+ throw e ;
153+ }
145154 LOGGER .debug ("Operator resources deployed." );
146155 }
147156
@@ -153,6 +162,125 @@ protected void deleteOperator() {
153162 .delete ();
154163 }
155164
165+ private void logDiagnosticInfo (KubernetesClient kubernetesClient ) {
166+ LOGGER .error (
167+ "Operator deployment timed out after {} seconds in namespace: {}" ,
168+ operatorDeploymentTimeout .getSeconds (),
169+ namespace );
170+ try {
171+ // Log deployment status
172+ var deployments =
173+ kubernetesClient .apps ().deployments ().inNamespace (namespace ).list ().getItems ();
174+ for (Deployment deployment : deployments ) {
175+ var status = deployment .getStatus ();
176+ LOGGER .error (
177+ "Deployment '{}': replicas={}, readyReplicas={}, availableReplicas={},"
178+ + " unavailableReplicas={}, conditions={}" ,
179+ deployment .getMetadata ().getName (),
180+ status != null ? status .getReplicas () : "null" ,
181+ status != null ? status .getReadyReplicas () : "null" ,
182+ status != null ? status .getAvailableReplicas () : "null" ,
183+ status != null ? status .getUnavailableReplicas () : "null" ,
184+ status != null ? status .getConditions () : "null" );
185+ }
186+
187+ // Log pod status and container details
188+ var pods = kubernetesClient .pods ().inNamespace (namespace ).list ().getItems ();
189+ for (Pod pod : pods ) {
190+ var podStatus = pod .getStatus ();
191+ LOGGER .error (
192+ "Pod '{}': phase={}, reason={}, message={}" ,
193+ pod .getMetadata ().getName (),
194+ podStatus != null ? podStatus .getPhase () : "null" ,
195+ podStatus != null ? podStatus .getReason () : "null" ,
196+ podStatus != null ? podStatus .getMessage () : "null" );
197+
198+ if (podStatus != null && podStatus .getContainerStatuses () != null ) {
199+ for (ContainerStatus cs : podStatus .getContainerStatuses ()) {
200+ LOGGER .error (
201+ " Container '{}': ready={}, restartCount={}, state={}" ,
202+ cs .getName (),
203+ cs .getReady (),
204+ cs .getRestartCount (),
205+ cs .getState ());
206+ }
207+ }
208+ if (podStatus != null && podStatus .getInitContainerStatuses () != null ) {
209+ for (ContainerStatus cs : podStatus .getInitContainerStatuses ()) {
210+ LOGGER .error (
211+ " InitContainer '{}': ready={}, restartCount={}, state={}" ,
212+ cs .getName (),
213+ cs .getReady (),
214+ cs .getRestartCount (),
215+ cs .getState ());
216+ }
217+ }
218+
219+ // Log pod events
220+ var events =
221+ kubernetesClient
222+ .v1 ()
223+ .events ()
224+ .inNamespace (namespace )
225+ .withField ("involvedObject.name" , pod .getMetadata ().getName ())
226+ .list ()
227+ .getItems ();
228+ for (var event : events ) {
229+ LOGGER .error (
230+ " Event: type={}, reason={}, message={}" ,
231+ event .getType (),
232+ event .getReason (),
233+ event .getMessage ());
234+ }
235+
236+ // Try to get container logs
237+ try {
238+ String logs =
239+ kubernetesClient
240+ .pods ()
241+ .inNamespace (namespace )
242+ .withName (pod .getMetadata ().getName ())
243+ .tailingLines (50 )
244+ .getLog ();
245+ if (logs != null && !logs .isEmpty ()) {
246+ LOGGER .error (" Logs for pod '{}':\n {}" , pod .getMetadata ().getName (), logs );
247+ }
248+ } catch (Exception logEx ) {
249+ LOGGER .error (
250+ " Could not retrieve logs for pod '{}'" , pod .getMetadata ().getName (), logEx );
251+ }
252+ }
253+
254+ if (pods .isEmpty ()) {
255+ LOGGER .error (
256+ "No pods found in namespace '{}'. The deployment may have failed to"
257+ + " create pods. Check if the image exists and is pullable." ,
258+ namespace );
259+
260+ // Log deployment events when no pods exist
261+ for (Deployment deployment : deployments ) {
262+ var events =
263+ kubernetesClient
264+ .v1 ()
265+ .events ()
266+ .inNamespace (namespace )
267+ .withField ("involvedObject.name" , deployment .getMetadata ().getName ())
268+ .list ()
269+ .getItems ();
270+ for (var event : events ) {
271+ LOGGER .error (
272+ " Deployment event: type={}, reason={}, message={}" ,
273+ event .getType (),
274+ event .getReason (),
275+ event .getMessage ());
276+ }
277+ }
278+ }
279+ } catch (Exception diagEx ) {
280+ LOGGER .error ("Failed to collect diagnostic info: {}" , diagEx .getMessage (), diagEx );
281+ }
282+ }
283+
156284 public static class Builder extends AbstractBuilder <Builder > {
157285 private final List <HasMetadata > operatorDeployment ;
158286 private Duration deploymentTimeout ;
0 commit comments