querysub 0.313.0 → 0.314.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/-e-certs/EdgeCertController.ts +16 -77
- package/src/-e-certs/certAuthority.ts +6 -0
- package/src/deployManager/components/ServiceDetailPage.tsx +1 -1
- package/src/deployManager/setupMachineMain.ts +8 -1
- package/src/diagnostics/NodeViewer.tsx +2 -2
- package/src/diagnostics/logs/FastArchiveAppendable.ts +31 -22
- package/src/diagnostics/logs/FastArchiveViewer.tsx +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +3 -1
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ import { magenta, yellow } from "socket-function/src/formatting/logColors";
|
|
|
28
28
|
import { timeInMinute, timeInSecond } from "socket-function/src/misc";
|
|
29
29
|
import { nodeDiscoveryShutdown } from "../-f-node-discovery/NodeDiscovery";
|
|
30
30
|
import { shutdown } from "../diagnostics/periodic";
|
|
31
|
+
import { formatDateTime } from "socket-function/src/formatting/format";
|
|
31
32
|
|
|
32
33
|
let publicPort = -1;
|
|
33
34
|
|
|
@@ -65,6 +66,8 @@ export async function getSNICerts(config: {
|
|
|
65
66
|
},
|
|
66
67
|
};
|
|
67
68
|
|
|
69
|
+
await publishEdgeDomain();
|
|
70
|
+
|
|
68
71
|
return certs;
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -93,7 +96,7 @@ const certUpdateLoop = lazy(() => {
|
|
|
93
96
|
logErrors((async () => {
|
|
94
97
|
let firstLoop = true;
|
|
95
98
|
while (true) {
|
|
96
|
-
let curCert = await
|
|
99
|
+
let curCert = await getHTTPSKeyCert(getDomain());
|
|
97
100
|
if (!curCert) {
|
|
98
101
|
throw new Error(`Internal error, certUpdateLoop called before lastPromise was set`);
|
|
99
102
|
}
|
|
@@ -102,14 +105,9 @@ const certUpdateLoop = lazy(() => {
|
|
|
102
105
|
let expirationTime = +new Date(certObj.validity.notAfter);
|
|
103
106
|
let createTime = +new Date(certObj.validity.notBefore);
|
|
104
107
|
|
|
105
|
-
// If 75% of the lifetime has passed,
|
|
108
|
+
// If 75% of the lifetime has passed, getHTTPSKeyCert should have updated it, so wait until that, then get the new cert, and update our watchers (which should be the servers).
|
|
106
109
|
let renewDate = createTime + (expirationTime - createTime) * 0.75;
|
|
107
110
|
let timeToExpire = renewDate - Date.now();
|
|
108
|
-
if (timeToExpire < 0) {
|
|
109
|
-
console.log(`HTTPS certificate is looking too old. Renewing from remote.`);
|
|
110
|
-
getCertFromRemote = createGetCertFromRemote();
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
111
|
|
|
114
112
|
if (!firstLoop) {
|
|
115
113
|
for (let callback of callbacks) {
|
|
@@ -118,43 +116,19 @@ const certUpdateLoop = lazy(() => {
|
|
|
118
116
|
}
|
|
119
117
|
firstLoop = false;
|
|
120
118
|
|
|
119
|
+
if (timeToExpire < 0) {
|
|
120
|
+
console.warn(`getHTTPSKeyCert gave as an almost expired. It is not supposed to do this. It should have updated it by now... Expires on ${formatDateTime(expirationTime)}`);
|
|
121
|
+
timeToExpire = timeInMinute * 15;
|
|
122
|
+
}
|
|
121
123
|
// Max timeout a signed integer, but lower is fine too
|
|
122
|
-
timeToExpire = Math.min(timeToExpire, 2 ** 30);
|
|
123
|
-
console.log(`Certicates up to date, renewing on ${new Date(Date.now() + timeToExpire)}`);
|
|
124
|
+
timeToExpire = Math.min(Math.floor(timeToExpire), 2 ** 30);
|
|
124
125
|
await delay(timeToExpire);
|
|
125
|
-
console.log(`Woke up to
|
|
126
|
+
console.log(`Woke up to propagate new certs`);
|
|
126
127
|
}
|
|
127
128
|
})());
|
|
128
129
|
});
|
|
129
130
|
|
|
130
|
-
function createGetCertFromRemote() {
|
|
131
|
-
return lazy(async () => {
|
|
132
|
-
return backoffRetryLoop(async () => {
|
|
133
|
-
// Skip the remote call if we have DNS write permissions, to
|
|
134
|
-
// make bootstrapping easier.
|
|
135
|
-
if (await hasDNSWritePermissions()) {
|
|
136
|
-
let ip = SocketFunction.mountedIP;
|
|
137
|
-
if (ip === "0.0.0.0") {
|
|
138
|
-
ip = await getExternalIP();
|
|
139
|
-
}
|
|
140
|
-
return await getHTTPSKeyCertInner(ip);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
let edgeNodeId = await getControllerNodeId(EdgeCertController);
|
|
144
|
-
if (!edgeNodeId) {
|
|
145
|
-
throw new Error("No EdgeCertController found");
|
|
146
|
-
}
|
|
147
|
-
return await EdgeCertController.nodes[edgeNodeId].getHTTPSKeyCert();
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
let getCertFromRemote = createGetCertFromRemote();
|
|
152
131
|
|
|
153
|
-
// NOTE: Only works if the machine is already listening. Needed for some special websocket
|
|
154
|
-
// stuff related to debugging.
|
|
155
|
-
export function debugGetRawEdgeCert() {
|
|
156
|
-
return getCertFromRemote();
|
|
157
|
-
}
|
|
158
132
|
|
|
159
133
|
let callbacks: ((newCertPair: { cert: string; key: string }) => void)[] = [];
|
|
160
134
|
async function EdgeCertController_watchHTTPSKeyCert(
|
|
@@ -163,7 +137,7 @@ async function EdgeCertController_watchHTTPSKeyCert(
|
|
|
163
137
|
certUpdateLoop();
|
|
164
138
|
|
|
165
139
|
callbacks.push(callback);
|
|
166
|
-
let certPair = await
|
|
140
|
+
let certPair = await getHTTPSKeyCert(getDomain());
|
|
167
141
|
callback(certPair);
|
|
168
142
|
}
|
|
169
143
|
|
|
@@ -228,24 +202,11 @@ async function checkEdgeDomainsAlive() {
|
|
|
228
202
|
}
|
|
229
203
|
}
|
|
230
204
|
|
|
231
|
-
async function
|
|
232
|
-
let
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// Get expiration date
|
|
237
|
-
let expirationTime = +new Date(certObj.validity.notAfter);
|
|
238
|
-
let createTime = +new Date(certObj.validity.notBefore);
|
|
239
|
-
|
|
240
|
-
// If 50% of the lifetime has passed, renew the cert
|
|
241
|
-
let renewDate = createTime + (expirationTime - createTime) * 0.5;
|
|
242
|
-
if (renewDate < Date.now()) {
|
|
243
|
-
console.log(`HTTPS certificate is looking too old, forcefully renewing`);
|
|
244
|
-
getHTTPSKeyCert.clear(getDomain());
|
|
245
|
-
getBaseCert = createGetBaseCert();
|
|
246
|
-
cert = await getBaseCert();
|
|
205
|
+
async function publishEdgeDomain() {
|
|
206
|
+
let callerIP = SocketFunction.mountedIP;
|
|
207
|
+
if (callerIP === "0.0.0.0") {
|
|
208
|
+
callerIP = await getExternalIP();
|
|
247
209
|
}
|
|
248
|
-
|
|
249
210
|
// IMPORTANT! We have to set our A record AFTER we create our cert, otherwise we might wait a while
|
|
250
211
|
// with our A record public while we create our cert.
|
|
251
212
|
runEdgeDomainAliveLoop();
|
|
@@ -296,27 +257,5 @@ async function getHTTPSKeyCertInner(callerIP: string) {
|
|
|
296
257
|
console.error(`Error updating DNS records, continuing without updating them`, e);
|
|
297
258
|
}
|
|
298
259
|
}
|
|
299
|
-
|
|
300
|
-
return cert;
|
|
301
260
|
}
|
|
302
261
|
|
|
303
|
-
class EdgeCertControllerBase {
|
|
304
|
-
public async getHTTPSKeyCert() {
|
|
305
|
-
// Ensure the a record is subscribed
|
|
306
|
-
const caller = SocketFunction.getCaller();
|
|
307
|
-
let callerIP = getNodeIdIP(caller.nodeId);
|
|
308
|
-
return await getHTTPSKeyCertInner(callerIP);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const EdgeCertController = SocketFunction.register(
|
|
314
|
-
"EdgeCertController-694c925b-fb10-4656-aed0-b53a48ded548",
|
|
315
|
-
new EdgeCertControllerBase(),
|
|
316
|
-
() => ({
|
|
317
|
-
getHTTPSKeyCert: {},
|
|
318
|
-
}),
|
|
319
|
-
() => ({
|
|
320
|
-
hooks: [requiresNetworkTrustHook],
|
|
321
|
-
})
|
|
322
|
-
);
|
|
@@ -40,6 +40,12 @@ export const getHTTPSKeyCert = cache(async (domain: string): Promise<{ key: stri
|
|
|
40
40
|
console.log(magenta(`Renewing domain ${domain} (renew target is ${formatDateTime(renewDate)}).`));
|
|
41
41
|
keyCert = undefined;
|
|
42
42
|
}
|
|
43
|
+
let timeUntilRenew = renewDate - Date.now();
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
console.log(magenta(`Clearing getHTTPSKeyCert to try to renew ${domain} (renew target is ${formatDateTime(renewDate)}).`));
|
|
46
|
+
getHTTPSKeyCert.clear(domain);
|
|
47
|
+
void getHTTPSKeyCert(domain);
|
|
48
|
+
}, Math.min(Math.floor(timeUntilRenew * 1.1), 2 ** 30));
|
|
43
49
|
} else {
|
|
44
50
|
console.log(magenta(`No cert found for domain ${domain}, generating shortly.`));
|
|
45
51
|
}
|
|
@@ -338,7 +338,7 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
338
338
|
|
|
339
339
|
<ATag values={[
|
|
340
340
|
managementPageURL.getOverride("LogViewer2"),
|
|
341
|
-
filterParam.getOverride(`
|
|
341
|
+
filterParam.getOverride(`__machineId = ${machineId}`),
|
|
342
342
|
]}>
|
|
343
343
|
Machine Logs
|
|
344
344
|
</ATag>
|
|
@@ -171,7 +171,9 @@ async function main() {
|
|
|
171
171
|
// Get RAM amount to calculate appropriate swap size
|
|
172
172
|
const memInfo = await runPromise(`ssh ${sshRemote} "free -m | grep Mem"`);
|
|
173
173
|
const ramMB = parseInt(memInfo.split(/\s+/)[1]);
|
|
174
|
-
if (swapTotal
|
|
174
|
+
if (Number.isNaN(swapTotal) || Number.isNaN(ramMB)) {
|
|
175
|
+
console.error(`Error getting swap or memory info, swapInfo: ${swapInfo}, memInfo: ${memInfo}`);
|
|
176
|
+
} else if (swapTotal > 0) {
|
|
175
177
|
console.log(`✅ Swap already configured: ${swapTotal}MB SWAP vs ${ramMB}MB REAL MEMORY`);
|
|
176
178
|
} else {
|
|
177
179
|
// Calculate swap size based on RAM:
|
|
@@ -213,6 +215,11 @@ async function main() {
|
|
|
213
215
|
|
|
214
216
|
console.log("Setting up machine:", sshRemote);
|
|
215
217
|
|
|
218
|
+
// 0. Update apt
|
|
219
|
+
console.log("Updating apt...");
|
|
220
|
+
await runPromise(`ssh ${sshRemote} "sudo apt update"`);
|
|
221
|
+
console.log("✅ Apt updated");
|
|
222
|
+
|
|
216
223
|
// 1. Copy backblaze file to remote server (~/backblaze.json)
|
|
217
224
|
console.log("Copying backblaze credentials...");
|
|
218
225
|
if (fs.existsSync(backblazePath)) {
|
|
@@ -23,7 +23,6 @@ import { ValueAuditController } from "../../src/5-diagnostics/memoryValueAudit";
|
|
|
23
23
|
import { getExternalIP } from "../../src/misc/networking";
|
|
24
24
|
import dns from "dns";
|
|
25
25
|
import { getNodeIdDomain, getNodeIdIP } from "socket-function/src/nodeCache";
|
|
26
|
-
import { debugGetRawEdgeCert } from "../../src/-e-certs/EdgeCertController";
|
|
27
26
|
import ws from "ws";
|
|
28
27
|
import https from "https";
|
|
29
28
|
import debugbreak from "debugbreak";
|
|
@@ -38,6 +37,7 @@ import { ATag } from "../library-components/ATag";
|
|
|
38
37
|
import { getSyncedController } from "../library-components/SyncedController";
|
|
39
38
|
import child_process from "child_process";
|
|
40
39
|
import { filterParam } from "./logs/FastArchiveViewer";
|
|
40
|
+
import { getHTTPSKeyCert } from "../-e-certs/certAuthority";
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
type NodeData = {
|
|
@@ -431,7 +431,7 @@ class NodeViewerControllerBase {
|
|
|
431
431
|
});
|
|
432
432
|
|
|
433
433
|
let baseNodeIP = getNodeIdIP(nodeId);
|
|
434
|
-
let cert = await
|
|
434
|
+
let cert = await getHTTPSKeyCert(getDomain());
|
|
435
435
|
|
|
436
436
|
const child = child_process.spawn("node", [
|
|
437
437
|
"-e",
|
|
@@ -110,6 +110,14 @@ export function getFileTimeStamp(path: string): number {
|
|
|
110
110
|
return new Date(dateStr).getTime();
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
|
|
114
|
+
// NOTE: Global, to prevent hot reloading, or redundant FastArchiveAppendable, from breaking things.
|
|
115
|
+
const appendableSerialLock = (globalThis as any).appendableSerialLock ?? runInSerial(async (fnc: () => Promise<void>) => {
|
|
116
|
+
await fnc();
|
|
117
|
+
});
|
|
118
|
+
(globalThis as any).appendableSerialLock = appendableSerialLock;
|
|
119
|
+
|
|
120
|
+
|
|
113
121
|
export class FastArchiveAppendable<Datum> {
|
|
114
122
|
private lastSizeWarningTime = 0;
|
|
115
123
|
|
|
@@ -181,14 +189,10 @@ export class FastArchiveAppendable<Datum> {
|
|
|
181
189
|
}
|
|
182
190
|
}
|
|
183
191
|
|
|
184
|
-
private serialLock = runInSerial(async (fnc: () => Promise<void>) => {
|
|
185
|
-
await fnc();
|
|
186
|
-
});
|
|
187
|
-
|
|
188
192
|
// NOTE: This is disk writing, which should be fast, but if it's slow we might be able to remove the measureWrap (as technically spending 50% of our time writing to the disk is fine, and won't lag anything).
|
|
189
193
|
@measureFnc
|
|
190
194
|
public async flushNow(now = Date.now()) {
|
|
191
|
-
await
|
|
195
|
+
await appendableSerialLock(async () => {
|
|
192
196
|
// 2025-09-06T07
|
|
193
197
|
let hourFile = new Date(now).toISOString().slice(0, 13) + ".log";
|
|
194
198
|
let localCacheFolder = this.getLocalPathRoot() + getOwnThreadId() + "/";
|
|
@@ -259,13 +263,15 @@ export class FastArchiveAppendable<Datum> {
|
|
|
259
263
|
|
|
260
264
|
public static getBackblazePath(config: { fileName: string; threadId: string }): string {
|
|
261
265
|
// 2025-09-06T07
|
|
262
|
-
let
|
|
266
|
+
let mainName = config.fileName.replace(/\.log$/, "");
|
|
267
|
+
let [year, month, day, hour] = mainName.split(/[-T:]/);
|
|
263
268
|
return `${year}/${month}/${day}/${hour}/${config.threadId}.log`;
|
|
264
269
|
}
|
|
265
270
|
|
|
266
271
|
public async moveLogsToBackblaze() {
|
|
267
|
-
await
|
|
272
|
+
await appendableSerialLock(async () => {
|
|
268
273
|
let rootCacheFolder = this.getLocalPathRoot();
|
|
274
|
+
console.log(magenta(`Moving old logs to Backblaze from ${rootCacheFolder}`));
|
|
269
275
|
|
|
270
276
|
let archives = this.getArchives();
|
|
271
277
|
async function moveLogsForFolder(threadId: string) {
|
|
@@ -274,22 +280,25 @@ export class FastArchiveAppendable<Datum> {
|
|
|
274
280
|
let files = await fs.promises.readdir(threadDir);
|
|
275
281
|
for (let file of files) {
|
|
276
282
|
if (file === "heartbeat") continue;
|
|
277
|
-
// 2025-09-06T07
|
|
278
283
|
let fullPath = threadDir + file;
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
284
|
+
try {
|
|
285
|
+
// We could use modified time here? Although, this is nice if we move files around, and then manually have them moved, although even then... this could cause problem be tripping while we are copying the file, so... maybe this is just wrong?
|
|
286
|
+
let timeStamp = getFileTimeStamp(fullPath);
|
|
287
|
+
if (timeStamp > Date.now() - UPLOAD_THRESHOLD) continue;
|
|
288
|
+
|
|
289
|
+
// NOTE: Because we use the same target path, if multiple services do this at the same time it's fine. Not great, but... fine.
|
|
290
|
+
let backblazePath = FastArchiveAppendable.getBackblazePath({ fileName: file, threadId });
|
|
291
|
+
console.log(magenta(`Moving ${fullPath} to Backblaze as ${backblazePath}`));
|
|
292
|
+
|
|
293
|
+
let data = await measureBlock(async () => fs.promises.readFile(fullPath), "FastArchiveAppendable|readBeforeUploading");
|
|
294
|
+
let compressed = await measureBlock(async () => Zip.gzip(data), "FastArchiveAppendable|compress");
|
|
295
|
+
console.log(`Uploading ${formatNumber(data.length)}B (compressed to ${formatNumber(compressed.length)}B) logs to ${backblazePath} from ${fullPath}`);
|
|
296
|
+
await archives.set(backblazePath, compressed);
|
|
297
|
+
await fs.promises.unlink(fullPath);
|
|
298
|
+
} catch (e: any) {
|
|
299
|
+
// Just skip it, if the first file in the directory is broken we don't want to never move any files
|
|
300
|
+
console.error(`Error moving log file ${fullPath}: ${e.stack}`);
|
|
301
|
+
}
|
|
293
302
|
}
|
|
294
303
|
}
|
|
295
304
|
|
|
@@ -553,7 +553,7 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
553
553
|
</div>
|
|
554
554
|
</div>
|
|
555
555
|
|
|
556
|
-
<div className={css.vbox(12).fillWidth}>
|
|
556
|
+
<div className={css.vbox(12).fillWidth.paddingBottom(20)}>
|
|
557
557
|
<InputLabelURL
|
|
558
558
|
label={
|
|
559
559
|
<div className={css.hbox(10)}>
|
|
@@ -6,7 +6,9 @@ Very small amount of data
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
4) Setup new hetnzer server
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
yarn setup-machine 176.9.2.136
|
|
11
|
+
|
|
10
12
|
5) Update all services, and move them to that machine
|
|
11
13
|
5) Verify the hezner server can run the site well
|
|
12
14
|
6) Take down our digital ocean server
|