Skip to content

Commit b69b292

Browse files
committed
Check Steve HTTP readiness instead of raw TCP connectivity
isPortReady() used a raw TCP connect to determine when Steve was ready. Steve accepts TCP connections several seconds before it finishes initializing its API controllers, so the dashboard button was enabled too early. Make an actual HTTP request to /v1 instead, using Steve's HTTP port to avoid certificate validation issues with its self-signed TLS cert. Signed-off-by: Jan Dubois <jan.dubois@suse.com>
1 parent ba16a03 commit b69b292

File tree

1 file changed

+25
-16
lines changed

1 file changed

+25
-16
lines changed

pkg/rancher-desktop/backend/steve.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChildProcess, spawn } from 'child_process';
2-
import net from 'net';
2+
import http from 'http';
33
import os from 'os';
44
import path from 'path';
55
import { setTimeout } from 'timers/promises';
@@ -19,6 +19,7 @@ export class Steve {
1919

2020
private isRunning: boolean;
2121
private httpsPort = 0;
22+
private httpPort = 0;
2223

2324
private constructor() {
2425
this.isRunning = false;
@@ -52,6 +53,7 @@ export class Steve {
5253
}
5354

5455
this.httpsPort = httpsPort;
56+
this.httpPort = httpPort;
5557

5658
const osSpecificName = /^win/i.test(os.platform()) ? 'steve.exe' : 'steve';
5759
const stevePath = path.join(paths.resources, os.platform(), 'internal', osSpecificName);
@@ -115,7 +117,7 @@ export class Steve {
115117
}
116118

117119
/**
118-
* Wait for Steve to be ready to accept connections.
120+
* Wait for Steve to be ready to serve API requests.
119121
*/
120122
private async waitForReady(): Promise<void> {
121123
const maxAttempts = 60;
@@ -139,26 +141,33 @@ export class Steve {
139141
}
140142

141143
/**
142-
* Check if Steve is accepting connections on its HTTPS port.
144+
* Check if Steve has finished initializing its API controllers.
145+
* Steve accepts HTTP connections and responds to /v1 before its
146+
* controllers have discovered all resource schemas from the K8s
147+
* API server. The dashboard fails if schemas are incomplete, so
148+
* we probe a core resource endpoint that returns 404 until the
149+
* schema controller has registered it.
143150
*/
144151
private isPortReady(): Promise<boolean> {
145152
return new Promise((resolve) => {
146-
const socket = new net.Socket();
147-
148-
socket.setTimeout(1000);
149-
socket.once('connect', () => {
150-
socket.destroy();
151-
resolve(true);
152-
});
153-
socket.once('error', () => {
154-
socket.destroy();
155-
resolve(false);
153+
const req = http.request({
154+
hostname: '127.0.0.1',
155+
port: this.httpPort,
156+
path: '/v1/namespaces',
157+
method: 'GET',
158+
timeout: 1000,
159+
agent: false,
160+
}, (res) => {
161+
res.resume();
162+
resolve(res.statusCode === 200);
156163
});
157-
socket.once('timeout', () => {
158-
socket.destroy();
164+
165+
req.on('error', () => resolve(false));
166+
req.on('timeout', () => {
167+
req.destroy();
159168
resolve(false);
160169
});
161-
socket.connect(this.httpsPort, '127.0.0.1');
170+
req.end();
162171
});
163172
}
164173

0 commit comments

Comments
 (0)