Skip to content

Commit b2e4acd

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 e8c73dd commit b2e4acd

File tree

1 file changed

+23
-16
lines changed

1 file changed

+23
-16
lines changed

pkg/rancher-desktop/backend/steve.ts

Lines changed: 23 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,31 @@ export class Steve {
139141
}
140142

141143
/**
142-
* Check if Steve is accepting connections on its HTTPS port.
144+
* Check if Steve is serving HTTP requests. A raw TCP connect is not
145+
* sufficient because Steve accepts connections before it finishes
146+
* initializing its API controllers. Uses the HTTP port to avoid
147+
* certificate validation issues with Steve's self-signed TLS cert.
143148
*/
144149
private isPortReady(): Promise<boolean> {
145150
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);
151+
const req = http.request({
152+
hostname: '127.0.0.1',
153+
port: this.httpPort,
154+
path: '/v1',
155+
method: 'GET',
156+
timeout: 1000,
157+
agent: false,
158+
}, (res) => {
159+
res.resume();
160+
resolve(res.statusCode !== undefined && res.statusCode < 500);
156161
});
157-
socket.once('timeout', () => {
158-
socket.destroy();
162+
163+
req.on('error', () => resolve(false));
164+
req.on('timeout', () => {
165+
req.destroy();
159166
resolve(false);
160167
});
161-
socket.connect(this.httpsPort, '127.0.0.1');
168+
req.end();
162169
});
163170
}
164171

0 commit comments

Comments
 (0)