Skip to content

Commit 01770b6

Browse files
committed
Merge branch 'master' into fs2
2 parents b99c909 + 8881d59 commit 01770b6

File tree

5 files changed

+115
-92
lines changed

5 files changed

+115
-92
lines changed

src/packages/frontend/jupyter/browser-actions.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,7 @@ export class JupyterActions extends JupyterActions0 {
153153
}
154154
});
155155

156-
// Put an entry in the project log once the jupyter notebook gets opened.
157-
// NOTE: Obviously, the project does NOT need to put entries in the log.
158-
this.syncdb.once("change", () =>
159-
this.redux?.getProjectActions(this.project_id).log_opened_time(this.path),
160-
);
156+
this.initOpenLog();
161157

162158
// project doesn't care about cursors, but browser clients do:
163159
this.syncdb.on("cursor_activity", this.syncdb_cursor_activity);
@@ -176,6 +172,23 @@ export class JupyterActions extends JupyterActions0 {
176172
}
177173
}
178174

175+
initOpenLog = () => {
176+
// Put an entry in the project log once the jupyter notebook gets opened and
177+
// shows cells.
178+
const reportOpened = () => {
179+
if (this._state == "closed") {
180+
return;
181+
}
182+
if (this.syncdb.get_one({ type: "cell" }) != null) {
183+
this.redux
184+
?.getProjectActions(this.project_id)
185+
.log_opened_time(this.path);
186+
this.syncdb.removeListener("change", reportOpened);
187+
}
188+
};
189+
this.syncdb.on("change", reportOpened);
190+
};
191+
179192
initUsageInfo = async () => {
180193
while (this._state != "closed") {
181194
try {

src/packages/server/conat/socketio/dns-scan-k8s-api.ts

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,91 @@
1-
import * as fs from "fs";
1+
import { readFile } from "fs/promises";
22
import * as https from "https";
33

44
// Define the options interface for type safety
55
interface ListPodsOptions {
66
labelSelector?: string; // e.g. "app=foo,env=prod"
77
}
88

9-
const NAMESPACE: string = fs
10-
.readFileSync(
11-
"/var/run/secrets/kubernetes.io/serviceaccount/namespace",
12-
"utf8",
13-
)
14-
.trim();
15-
const CA: Buffer = fs.readFileSync(
16-
"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
17-
);
9+
let NAMESPACE: string | null = null;
10+
let CA: Buffer | null = null;
1811

1912
async function listPods(options: ListPodsOptions = {}): Promise<any> {
13+
let token: string;
2014
try {
21-
// Read service account details, token could be rotated
22-
const token = fs
23-
.readFileSync(
15+
NAMESPACE =
16+
NAMESPACE ??
17+
(
18+
await readFile(
19+
"/var/run/secrets/kubernetes.io/serviceaccount/namespace",
20+
"utf8",
21+
)
22+
).trim();
23+
CA =
24+
CA ??
25+
(await readFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"));
26+
27+
// Read service account details, token could be rotated, so read every time
28+
token = (
29+
await readFile(
2430
"/var/run/secrets/kubernetes.io/serviceaccount/token",
2531
"utf8",
2632
)
27-
.trim();
33+
).trim();
34+
} catch (err) {
35+
throw new Error(`Failed to read service account files: ${err}`);
36+
}
2837

29-
// Base API path
30-
let path = `/api/v1/namespaces/${NAMESPACE}/pods`;
38+
// Base API path
39+
let path = `/api/v1/namespaces/${NAMESPACE}/pods`;
3140

32-
const queryParams: string[] = [];
33-
if (options.labelSelector) {
34-
queryParams.push(
35-
`labelSelector=${encodeURIComponent(options.labelSelector)}`,
36-
);
37-
}
41+
const queryParams: string[] = [];
42+
if (options.labelSelector) {
43+
queryParams.push(
44+
`labelSelector=${encodeURIComponent(options.labelSelector)}`,
45+
);
46+
}
3847

39-
if (queryParams.length > 0) {
40-
path += `?${queryParams.join("&")}`;
41-
}
48+
if (queryParams.length > 0) {
49+
path += `?${queryParams.join("&")}`;
50+
}
4251

43-
const query: https.RequestOptions = {
44-
hostname: "kubernetes.default.svc",
45-
path,
46-
method: "GET",
47-
headers: {
48-
Authorization: `Bearer ${token}`,
49-
Accept: "application/json",
50-
},
51-
ca: [CA],
52-
};
52+
const query: https.RequestOptions = {
53+
hostname: "kubernetes.default.svc",
54+
path,
55+
method: "GET",
56+
headers: {
57+
Authorization: `Bearer ${token}`,
58+
Accept: "application/json",
59+
},
60+
ca: [CA],
61+
};
5362

54-
return new Promise((resolve, reject) => {
55-
const req = https.request(query, (res) => {
56-
let data = "";
57-
res.on("data", (chunk) => {
58-
data += chunk;
59-
});
60-
res.on("end", () => {
61-
if (res.statusCode !== 200) {
62-
reject(
63-
new Error(
64-
`K8S API request failed. status=${res.statusCode}: ${data}`,
65-
),
66-
);
67-
} else {
68-
try {
69-
resolve(JSON.parse(data));
70-
} catch (parseError) {
71-
reject(parseError);
72-
}
63+
return new Promise((resolve, reject) => {
64+
const req = https.request(query, (res) => {
65+
let data = "";
66+
res.on("data", (chunk) => {
67+
data += chunk;
68+
});
69+
res.on("end", () => {
70+
if (res.statusCode !== 200) {
71+
reject(
72+
new Error(
73+
`K8S API request failed. status=${res.statusCode}: ${data}`,
74+
),
75+
);
76+
} else {
77+
try {
78+
resolve(JSON.parse(data));
79+
} catch (parseError) {
80+
reject(parseError);
7381
}
74-
});
82+
}
7583
});
76-
77-
req.on("error", (error) => reject(error));
78-
req.end();
7984
});
80-
} catch (error) {
81-
throw new Error(
82-
`Failed to read service account files: ${(error as Error).message}`,
83-
);
84-
}
85+
86+
req.on("error", (error) => reject(error));
87+
req.end();
88+
});
8589
}
8690

8791
export async function getAddressesFromK8sApi(): Promise<

src/packages/server/projects/control/single-user.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,20 @@ This is useful for:
1414
- development of cocalc from inside of a CoCalc project
1515
- non-collaborative use of cocalc on your own
1616
laptop, e.g., when you're on an airplane.
17-
18-
17+
18+
1919
DEVELOPMENT:
2020
2121
2222
~/cocalc/src/packages/server/projects/control$ COCALC_MODE='single-user' node
2323
Welcome to Node.js v20.19.1.
2424
Type ".help" for more information.
25-
> a = require('@cocalc/server/projects/control');
25+
> a = require('@cocalc/server/projects/control');
2626
> p = a.getProject('8a840733-93b6-415c-83d4-7e5712a6266b')
2727
> await p.start()
2828
*/
2929

30-
import { kill } from "process";
31-
30+
import { kill } from "node:process";
3231
import getLogger from "@cocalc/backend/logger";
3332
import {
3433
BaseProject,
@@ -153,16 +152,26 @@ class Project extends BaseProject {
153152
try {
154153
this.stateChanging = { state: "stopping" };
155154
await this.saveStateToDatabase(this.stateChanging);
156-
try {
157-
const pid = await getProjectPID(this.HOME);
158-
logger.debug(`stop: sending kill -${pid}`);
159-
kill(-pid);
160-
} catch (err) {
161-
// expected exception if no pid
162-
logger.debug(`stop: kill err ${err}`);
163-
}
155+
const pid = await getProjectPID(this.HOME);
156+
const killProject = () => {
157+
try {
158+
logger.debug(`stop: sending kill -${pid}`);
159+
kill(-pid, "SIGKILL");
160+
} catch (err) {
161+
// expected exception if no pid
162+
logger.debug(`stop: kill err ${err}`);
163+
}
164+
};
165+
killProject();
164166
await this.wait({
165-
until: async () => !(await isProjectRunning(this.HOME)),
167+
until: async () => {
168+
if (await isProjectRunning(this.HOME)) {
169+
killProject();
170+
return false;
171+
} else {
172+
return true;
173+
}
174+
},
166175
maxTime: MAX_STOP_TIME_MS,
167176
});
168177
await deleteProjectSecretToken(this.project_id);

src/packages/sync/editor/generic/sync-doc.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,14 +1027,11 @@ export class SyncDoc extends EventEmitter {
10271027
this.assert_table_is_ready("syncstring");
10281028
this.dbg("set_initialized")({ error, read_only, size });
10291029
const init = { time: this.client.server_time(), size, error };
1030-
for (let i = 0; i < 3; i++) {
1031-
await this.set_syncstring_table({
1032-
init,
1033-
read_only,
1034-
last_active: this.client.server_time(),
1035-
});
1036-
await delay(1000);
1037-
}
1030+
await this.set_syncstring_table({
1031+
init,
1032+
read_only,
1033+
last_active: this.client.server_time(),
1034+
});
10381035
};
10391036

10401037
/* List of logical timestamps of the versions of this string in the sync
@@ -1463,7 +1460,7 @@ export class SyncDoc extends EventEmitter {
14631460
log("update interest");
14641461
this.initInterestLoop();
14651462

1466-
log("ensure syncstring exists in database (if not using NATS)");
1463+
log("ensure syncstring exists");
14671464
this.assert_not_closed("initAll -- before ensuring syncstring exists");
14681465
await this.ensure_syncstring_exists_in_db();
14691466

src/packages/util/smc-version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
/* autogenerated by the update_version script */
2-
exports.version=1752418521;
2+
exports.version=1752527312;

0 commit comments

Comments
 (0)