Skip to content

Commit 24e9a1b

Browse files
committed
Steve: Fix healthcheck
When we request Steve at the HTTP port, if HTTPS is enabled, it just tries to redirect us to the HTTPS port instead. Therefore we should just disable the HTTP port completely (we never use it, and we do not expect external users); instead, we try the HTTPS port for the health check. Signed-off-by: Mark Yen <mark.yen@suse.com>
1 parent b69b292 commit 24e9a1b

File tree

2 files changed

+45
-26
lines changed

2 files changed

+45
-26
lines changed

background.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,10 @@ Electron.app.whenReady().then(async() => {
228228
// Check for required OS versions and features
229229
await checkPrerequisites();
230230

231-
DashboardServer.getInstance().init();
232-
233231
await setupNetworking();
234232

233+
DashboardServer.getInstance().init();
234+
235235
try {
236236
deploymentProfiles = await readDeploymentProfiles();
237237
} catch (ex: any) {
@@ -1277,12 +1277,14 @@ function newK8sManager() {
12771277

12781278
if (enabledK8s) {
12791279
try {
1280-
const [steveHttpsPort, steveHttpPort] = await getAvailablePorts(2);
1281-
1282-
console.log(`Steve ports: HTTPS=${ steveHttpsPort } HTTP=${ steveHttpPort }`);
1283-
await Steve.getInstance().start(steveHttpsPort, steveHttpPort);
1284-
DashboardServer.getInstance().setStevePort(steveHttpsPort); // recreate proxy middleware
1285-
setSteveCertPort(steveHttpsPort); // update certificate-error allowed URLs
1280+
const [stevePort] = await getAvailablePorts(1);
1281+
1282+
console.log(`Steve HTTPS port: ${ stevePort }`);
1283+
// Set the Steve HTTPS port for certificate checking before setting
1284+
// up Steve itself.
1285+
setSteveCertPort(stevePort);
1286+
await Steve.getInstance().start(stevePort);
1287+
DashboardServer.getInstance().setStevePort(stevePort); // recreate proxy middleware
12861288
} catch (ex) {
12871289
console.error('Failed to start Steve:', ex);
12881290
}

pkg/rancher-desktop/backend/steve.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { ChildProcess, spawn } from 'child_process';
2-
import http from 'http';
32
import os from 'os';
43
import path from 'path';
54
import { setTimeout } from 'timers/promises';
65

6+
import Electron from 'electron';
7+
78
import K3sHelper from '@pkg/backend/k3sHelper';
89
import Logging from '@pkg/utils/logging';
910
import paths from '@pkg/utils/paths';
@@ -19,7 +20,6 @@ export class Steve {
1920

2021
private isRunning: boolean;
2122
private httpsPort = 0;
22-
private httpPort = 0;
2323

2424
private constructor() {
2525
this.isRunning = false;
@@ -41,9 +41,8 @@ export class Steve {
4141
* @description Starts the Steve API if one is not already running.
4242
* Returns only after Steve is ready to accept connections.
4343
* @param httpsPort The HTTPS port for Steve to listen on.
44-
* @param httpPort The HTTP port for Steve to listen on.
4544
*/
46-
public async start(httpsPort: number, httpPort: number) {
45+
public async start(httpsPort: number) {
4746
const { pid } = this.process || { };
4847

4948
if (this.isRunning && pid) {
@@ -53,7 +52,6 @@ export class Steve {
5352
}
5453

5554
this.httpsPort = httpsPort;
56-
this.httpPort = httpPort;
5755

5856
const osSpecificName = /^win/i.test(os.platform()) ? 'steve.exe' : 'steve';
5957
const stevePath = path.join(paths.resources, os.platform(), 'internal', osSpecificName);
@@ -76,7 +74,7 @@ export class Steve {
7674
'--https-listen-port',
7775
String(httpsPort),
7876
'--http-listen-port',
79-
String(httpPort),
77+
'0', // Disable HTTP support; it does not work correctly anyway.
8078
],
8179
{ env },
8280
);
@@ -129,7 +127,7 @@ export class Steve {
129127
}
130128

131129
if (await this.isPortReady()) {
132-
console.debug(`Steve is ready after ${ attempt } attempt(s)`);
130+
console.debug(`Steve is ready after ${ attempt } / ${ maxAttempts } attempt(s)`);
133131

134132
return;
135133
}
@@ -149,24 +147,43 @@ export class Steve {
149147
* schema controller has registered it.
150148
*/
151149
private isPortReady(): Promise<boolean> {
150+
// Steve's HTTP port just redirects to HTTPS, so we might as well go to the
151+
// HTTPS port directly. We will need to ignore certificate errors; however,
152+
// neither the NodeJS stack nor Electron.net.request() would pass through
153+
// the `Electron.app.on('certificate-error', ...)` handler, so we cannot use
154+
// the normal certificate handling for this health check. Instead, we
155+
// create a temporary session with a certificate verify proc that ignores
156+
// errors, and use that session for the health check request.
152157
return new Promise((resolve) => {
153-
const req = http.request({
158+
const session = Electron.session.fromPartition('steve-healthcheck', { cache: false });
159+
160+
session.setCertificateVerifyProc((request, callback) => {
161+
if (request.hostname === '127.0.0.1') {
162+
// We do not have any more information to narrow down the certificate;
163+
// given that we're doing this in a private partition, it should be
164+
// safe to allow all localhost certificates. In particular, we do not
165+
// get access to the port number, and all the Steve certificates have
166+
// generic fields (e.g. subject).
167+
callback(0);
168+
} else {
169+
// Unexpected request; not sure how this could happen in a new session,
170+
// but we can at least pretend to do the right thing.
171+
callback(-3); // Use Chromium's default verification.
172+
}
173+
});
174+
175+
const req = Electron.net.request({
176+
protocol: 'https:',
154177
hostname: '127.0.0.1',
155-
port: this.httpPort,
178+
port: this.httpsPort,
156179
path: '/v1/namespaces',
157180
method: 'GET',
158-
timeout: 1000,
159-
agent: false,
160-
}, (res) => {
161-
res.resume();
162-
resolve(res.statusCode === 200);
181+
redirect: 'error',
182+
session,
163183
});
164184

185+
req.on('response', (res) => resolve(res.statusCode === 200));
165186
req.on('error', () => resolve(false));
166-
req.on('timeout', () => {
167-
req.destroy();
168-
resolve(false);
169-
});
170187
req.end();
171188
});
172189
}

0 commit comments

Comments
 (0)