kubernetes-fluent-client 3.1.1 → 3.1.3
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/.husky/pre-commit +1 -0
- package/.lintstagedrc.json +5 -0
- package/dist/fluent/types.d.ts +14 -0
- package/dist/fluent/types.d.ts.map +1 -1
- package/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +121 -71
- package/package.json +8 -5
- package/src/fluent/types.ts +16 -0
- package/src/fluent/watch.ts +136 -81
- package/dist/fetch.test.d.ts +0 -2
- package/dist/fetch.test.d.ts.map +0 -1
- package/dist/fetch.test.js +0 -97
- package/dist/fileSystem.test.d.ts +0 -2
- package/dist/fileSystem.test.d.ts.map +0 -1
- package/dist/fileSystem.test.js +0 -75
- package/dist/fluent/http2-watch.spec.d.ts +0 -2
- package/dist/fluent/http2-watch.spec.d.ts.map +0 -1
- package/dist/fluent/http2-watch.spec.js +0 -284
- package/dist/fluent/index.test.d.ts +0 -2
- package/dist/fluent/index.test.d.ts.map +0 -1
- package/dist/fluent/index.test.js +0 -193
- package/dist/fluent/utils.test.d.ts +0 -2
- package/dist/fluent/utils.test.d.ts.map +0 -1
- package/dist/fluent/utils.test.js +0 -215
- package/dist/fluent/watch.spec.d.ts +0 -2
- package/dist/fluent/watch.spec.d.ts.map +0 -1
- package/dist/fluent/watch.spec.js +0 -261
- package/dist/generate.test.d.ts +0 -2
- package/dist/generate.test.d.ts.map +0 -1
- package/dist/generate.test.js +0 -320
- package/dist/helpers.test.d.ts +0 -2
- package/dist/helpers.test.d.ts.map +0 -1
- package/dist/helpers.test.js +0 -37
- package/dist/kinds.test.d.ts +0 -2
- package/dist/kinds.test.d.ts.map +0 -1
- package/dist/kinds.test.js +0 -155
- package/dist/postProcessing.test.d.ts +0 -2
- package/dist/postProcessing.test.d.ts.map +0 -1
- package/dist/postProcessing.test.js +0 -550
- package/e2e/cli.e2e.test.ts +0 -127
- package/e2e/crds/policyreports.default.expected/policyreport-v1alpha1.ts +0 -332
- package/e2e/crds/policyreports.default.expected/policyreport-v1alpha2.ts +0 -360
- package/e2e/crds/policyreports.default.expected/policyreport-v1beta1.ts +0 -360
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha1.ts +0 -331
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha2.ts +0 -360
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1beta1.ts +0 -360
- package/e2e/crds/test.yaml/policyreports.test.yaml +0 -1008
- package/e2e/crds/test.yaml/uds-podmonitors.test.yaml +0 -1245
- package/e2e/crds/uds-podmonitors.default.expected/podmonitor-v1.ts +0 -1333
- package/e2e/crds/uds-podmonitors.no.post.expected/podmonitor-v1.ts +0 -1360
- package/src/fetch.test.ts +0 -115
- package/src/fileSystem.test.ts +0 -67
- package/src/fluent/http2-watch.spec.ts +0 -335
- package/src/fluent/index.test.ts +0 -268
- package/src/fluent/utils.test.ts +0 -276
- package/src/fluent/watch.spec.ts +0 -299
- package/src/generate.test.ts +0 -399
- package/src/helpers.test.ts +0 -42
- package/src/kinds.test.ts +0 -166
- package/src/postProcessing.test.ts +0 -742
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx lint-staged --verbose
|
package/dist/fluent/types.d.ts
CHANGED
|
@@ -3,6 +3,20 @@ import { Operation } from "fast-json-patch";
|
|
|
3
3
|
import type { PartialDeep } from "type-fest";
|
|
4
4
|
import { GenericClass, GroupVersionKind } from "../types";
|
|
5
5
|
import { WatchCfg, Watcher } from "./watch";
|
|
6
|
+
import https from "https";
|
|
7
|
+
import { SecureClientSessionOptions } from "http2";
|
|
8
|
+
/**
|
|
9
|
+
* Agent options for the the http2Watch
|
|
10
|
+
*/
|
|
11
|
+
export type AgentOptions = Pick<SecureClientSessionOptions, "ca" | "cert" | "key" | "rejectUnauthorized">;
|
|
12
|
+
/**
|
|
13
|
+
* Options for the http2Watch
|
|
14
|
+
*/
|
|
15
|
+
export interface Options {
|
|
16
|
+
agent?: https.Agent & {
|
|
17
|
+
options?: AgentOptions;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
6
20
|
/**
|
|
7
21
|
* The Phase matched when using the K8s Watch API.
|
|
8
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,EAAE,YAAY,EAAwB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,EAAE,YAAY,EAAwB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,WAAW,EAAqC,MAAM,SAAS,CAAC;AAIlF,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,mCAAmC;IACnC,IAAI,SAAS;IACb,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;IACvC,kCAAkC;IAClC,IAAI,SAAS;IACb,2BAA2B;IAC3B,UAAU,eAAe;IACzB,mBAAmB;IACnB,UAAU,eAAe;IACzB,qCAAqC;IACrC,wBAAwB,6BAA6B;IACrD,iCAAiC;IACjC,eAAe,oBAAoB;CACpC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,+HAA+H;IAC/H,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+FAA+F;IAC/F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wHAAwH;IACxH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAKF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IA0BzC,YAAY,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IAgB9B;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IA6CzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAU9C,gGAAgG;IACzF,KAAK;IAOZ;;;;;OAKG;IACI,UAAU;IAWjB;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAqfF"}
|
package/dist/fluent/watch.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
6
|
};
|
|
7
|
+
var _a;
|
|
7
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
9
|
exports.Watcher = exports.WatchEvent = void 0;
|
|
9
10
|
const byline_1 = __importDefault(require("byline"));
|
|
@@ -382,6 +383,41 @@ class Watcher {
|
|
|
382
383
|
void this.#errHandler(e);
|
|
383
384
|
}
|
|
384
385
|
};
|
|
386
|
+
// Configure the agent options for the HTTP/2 client
|
|
387
|
+
static #getAgentOptions(opts) {
|
|
388
|
+
if (opts.agent && opts.agent instanceof https_1.default.Agent) {
|
|
389
|
+
return {
|
|
390
|
+
key: opts.agent.options.key,
|
|
391
|
+
cert: opts.agent.options.cert,
|
|
392
|
+
ca: opts.agent.options.ca,
|
|
393
|
+
rejectUnauthorized: false,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
// Create an HTTP/2 client
|
|
399
|
+
static #createHttp2Client(origin, agentOptions) {
|
|
400
|
+
return http2_1.default.connect(origin, {
|
|
401
|
+
ca: agentOptions?.ca,
|
|
402
|
+
cert: agentOptions?.cert,
|
|
403
|
+
key: agentOptions?.key,
|
|
404
|
+
rejectUnauthorized: agentOptions?.rejectUnauthorized,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
// Generate the request headers for the HTTP/2 request
|
|
408
|
+
#generateRequestHeaders = async (url) => {
|
|
409
|
+
const token = await this.#getToken();
|
|
410
|
+
const headers = {
|
|
411
|
+
":method": "GET",
|
|
412
|
+
":path": url.pathname + url.search,
|
|
413
|
+
"content-type": "application/json",
|
|
414
|
+
"user-agent": "kubernetes-fluent-client",
|
|
415
|
+
};
|
|
416
|
+
if (token) {
|
|
417
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
418
|
+
}
|
|
419
|
+
return headers;
|
|
420
|
+
};
|
|
385
421
|
/**
|
|
386
422
|
* Watch for changes to the resource.
|
|
387
423
|
*/
|
|
@@ -391,79 +427,24 @@ class Watcher {
|
|
|
391
427
|
await this.#list();
|
|
392
428
|
// Build the URL and request options
|
|
393
429
|
const { opts, url } = await this.#buildURL(true, this.#resourceVersion);
|
|
394
|
-
|
|
395
|
-
if (opts.agent && opts.agent instanceof https_1.default.Agent) {
|
|
396
|
-
agentOptions = {
|
|
397
|
-
key: opts.agent.options.key,
|
|
398
|
-
cert: opts.agent.options.cert,
|
|
399
|
-
ca: opts.agent.options.ca,
|
|
400
|
-
rejectUnauthorized: false,
|
|
401
|
-
};
|
|
402
|
-
}
|
|
430
|
+
const agentOptions = _a.#getAgentOptions(opts);
|
|
403
431
|
// HTTP/2 client connection setup
|
|
404
|
-
const client =
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
432
|
+
const client = _a.#createHttp2Client(url.origin, agentOptions);
|
|
433
|
+
// Handle client connection errors
|
|
434
|
+
client.on("error", err => {
|
|
435
|
+
this.#events.emit(WatchEvent.NETWORK_ERROR, err);
|
|
436
|
+
this.#cleanupAndReconnect(client, err);
|
|
409
437
|
});
|
|
410
438
|
// Set up headers for the HTTP/2 request
|
|
411
|
-
const
|
|
412
|
-
const headers = {
|
|
413
|
-
":method": "GET",
|
|
414
|
-
":path": url.pathname + url.search,
|
|
415
|
-
"content-type": "application/json",
|
|
416
|
-
"user-agent": "kubernetes-fluent-client",
|
|
417
|
-
};
|
|
418
|
-
if (token) {
|
|
419
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
420
|
-
}
|
|
439
|
+
const headers = await this.#generateRequestHeaders(url);
|
|
421
440
|
// Make the HTTP/2 request
|
|
422
441
|
const req = client.request(headers);
|
|
423
442
|
req.setEncoding("utf8");
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
this.#pendingReconnect = false;
|
|
430
|
-
this.#events.emit(WatchEvent.CONNECT, url.pathname);
|
|
431
|
-
// Reset the retry count
|
|
432
|
-
this.#resyncFailureCount = 0;
|
|
433
|
-
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
434
|
-
req.on("data", async (chunk) => {
|
|
435
|
-
try {
|
|
436
|
-
buffer += chunk;
|
|
437
|
-
const lines = buffer.split("\n");
|
|
438
|
-
// Avoid Watch event data_error received. Unexpected end of JSON input.
|
|
439
|
-
buffer = lines.pop();
|
|
440
|
-
for (const line of lines) {
|
|
441
|
-
await this.#processLine(line, this.#process);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
catch (err) {
|
|
445
|
-
void this.#errHandler(err);
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
req.on("end", () => {
|
|
449
|
-
client.close();
|
|
450
|
-
this.#streamCleanup();
|
|
451
|
-
});
|
|
452
|
-
req.on("close", () => {
|
|
453
|
-
client.close();
|
|
454
|
-
this.#streamCleanup();
|
|
455
|
-
});
|
|
456
|
-
req.on("error", err => {
|
|
457
|
-
void this.#errHandler(err);
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
const statusMessage = headers[":status-text"] || "Unknown";
|
|
462
|
-
throw new Error(`watch connect failed: ${statusCode} ${statusMessage}`);
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
req.on("error", err => {
|
|
466
|
-
void this.#errHandler(err);
|
|
443
|
+
// Handler events for the HTTP/2 request
|
|
444
|
+
this.#handleHttp2Request(req, client);
|
|
445
|
+
// Handle abort signal
|
|
446
|
+
this.#abortController.signal.addEventListener("abort", () => {
|
|
447
|
+
this.#streamCleanup(client);
|
|
467
448
|
});
|
|
468
449
|
}
|
|
469
450
|
catch (e) {
|
|
@@ -495,6 +476,9 @@ class Watcher {
|
|
|
495
476
|
this.#pendingReconnect = true;
|
|
496
477
|
this.#events.emit(WatchEvent.RECONNECT, this.#resyncFailureCount);
|
|
497
478
|
this.#streamCleanup();
|
|
479
|
+
if (this.#useHTTP2) {
|
|
480
|
+
this.#cleanupAndReconnect();
|
|
481
|
+
}
|
|
498
482
|
if (!this.#useHTTP2) {
|
|
499
483
|
void this.#watch();
|
|
500
484
|
}
|
|
@@ -518,6 +502,7 @@ class Watcher {
|
|
|
518
502
|
clearInterval(this.$relistTimer);
|
|
519
503
|
clearInterval(this.#resyncTimer);
|
|
520
504
|
this.#streamCleanup();
|
|
505
|
+
this.#scheduleReconnect();
|
|
521
506
|
this.#events.emit(WatchEvent.ABORT, err);
|
|
522
507
|
return;
|
|
523
508
|
case "TooOld":
|
|
@@ -532,15 +517,80 @@ class Watcher {
|
|
|
532
517
|
// Force a resync
|
|
533
518
|
this.#lastSeenTime = OVERRIDE;
|
|
534
519
|
};
|
|
535
|
-
/**
|
|
536
|
-
|
|
520
|
+
/**
|
|
521
|
+
*
|
|
522
|
+
* @param req - the request stream
|
|
523
|
+
* @param client - the client session
|
|
524
|
+
*/
|
|
525
|
+
#handleHttp2Request(req, client) {
|
|
526
|
+
let buffer = "";
|
|
527
|
+
req.on("response", headers => {
|
|
528
|
+
const statusCode = headers[":status"];
|
|
529
|
+
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
530
|
+
this.#onWatchConnected();
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
this.#cleanupAndReconnect(client, new Error(`watch connect failed: ${statusCode}`));
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
req.on("data", chunk => {
|
|
537
|
+
buffer += chunk;
|
|
538
|
+
const lines = buffer.split("\n");
|
|
539
|
+
buffer = lines.pop() || ""; // Keep any incomplete line for the next chunk
|
|
540
|
+
lines.forEach(line => {
|
|
541
|
+
void this.#processLine(line, this.#process);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
req.on("end", () => this.#cleanupAndReconnect(client));
|
|
545
|
+
req.on("close", () => this.#cleanupAndReconnect(client));
|
|
546
|
+
req.on("error", error => this.#errHandler(error));
|
|
547
|
+
}
|
|
548
|
+
/** Schedules a reconnect with a delay to prevent rapid reconnections. */
|
|
549
|
+
#scheduleReconnect() {
|
|
550
|
+
const jitter = Math.floor(Math.random() * 1000);
|
|
551
|
+
const delay = (this.#watchCfg.resyncDelaySec ?? 5) * 1000 + jitter;
|
|
552
|
+
setTimeout(() => {
|
|
553
|
+
this.#events.emit(WatchEvent.RECONNECT, this.#resyncFailureCount);
|
|
554
|
+
void this.#http2Watch();
|
|
555
|
+
}, delay);
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Handle a successful connection to the watch.
|
|
559
|
+
*/
|
|
560
|
+
#onWatchConnected() {
|
|
561
|
+
this.#pendingReconnect = false;
|
|
562
|
+
this.#events.emit(WatchEvent.CONNECT);
|
|
563
|
+
// Reset the retry count
|
|
564
|
+
this.#resyncFailureCount = 0;
|
|
565
|
+
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Cleanup the stream and listeners.
|
|
569
|
+
*
|
|
570
|
+
* @param client - the client session
|
|
571
|
+
*/
|
|
572
|
+
#streamCleanup = (client) => {
|
|
537
573
|
if (this.#stream) {
|
|
538
574
|
this.#stream.removeAllListeners();
|
|
539
575
|
this.#stream.destroy();
|
|
540
576
|
}
|
|
541
|
-
if (
|
|
542
|
-
|
|
577
|
+
if (client) {
|
|
578
|
+
client.close();
|
|
543
579
|
}
|
|
544
580
|
};
|
|
581
|
+
/**
|
|
582
|
+
* Cleanup the stream and listeners and reconnect.
|
|
583
|
+
*
|
|
584
|
+
* @param client - the client session
|
|
585
|
+
* @param error - the error that occurred
|
|
586
|
+
*/
|
|
587
|
+
#cleanupAndReconnect(client, error) {
|
|
588
|
+
this.#streamCleanup(client);
|
|
589
|
+
if (error) {
|
|
590
|
+
void this.#errHandler(error);
|
|
591
|
+
}
|
|
592
|
+
this.#scheduleReconnect();
|
|
593
|
+
}
|
|
545
594
|
}
|
|
546
595
|
exports.Watcher = Watcher;
|
|
596
|
+
_a = Watcher;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kubernetes-fluent-client",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "A @kubernetes/client-node fluent API wrapper that leverages K8s Server Side Apply.",
|
|
5
5
|
"bin": "./dist/cli.js",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"test": "jest src --coverage",
|
|
13
13
|
"test:e2e": "jest e2e",
|
|
14
14
|
"format:check": "eslint src && prettier . --check",
|
|
15
|
-
"format:fix": "eslint --fix src && prettier . --write"
|
|
15
|
+
"format:fix": "eslint --fix src && prettier . --write",
|
|
16
|
+
"prepare": "if [ \"$NODE_ENV\" != 'production' ]; then husky; fi"
|
|
16
17
|
},
|
|
17
18
|
"engines": {
|
|
18
19
|
"node": ">=18.0.0"
|
|
@@ -53,10 +54,12 @@
|
|
|
53
54
|
"@types/readable-stream": "4.0.15",
|
|
54
55
|
"@types/urijs": "^1.19.25",
|
|
55
56
|
"@types/yargs": "17.0.33",
|
|
56
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
57
|
-
"@typescript-eslint/parser": "8.
|
|
58
|
-
"eslint-plugin-jsdoc": "50.4.
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "8.10.0",
|
|
58
|
+
"@typescript-eslint/parser": "8.10.0",
|
|
59
|
+
"eslint-plugin-jsdoc": "50.4.3",
|
|
60
|
+
"husky": "^8.0.0",
|
|
59
61
|
"jest": "29.7.0",
|
|
62
|
+
"lint-staged": "^15.2.10",
|
|
60
63
|
"nock": "13.5.5",
|
|
61
64
|
"prettier": "3.3.3",
|
|
62
65
|
"semantic-release": "24.1.2",
|
package/src/fluent/types.ts
CHANGED
|
@@ -7,6 +7,22 @@ import type { PartialDeep } from "type-fest";
|
|
|
7
7
|
|
|
8
8
|
import { GenericClass, GroupVersionKind } from "../types";
|
|
9
9
|
import { WatchCfg, Watcher } from "./watch";
|
|
10
|
+
import https from "https";
|
|
11
|
+
import { SecureClientSessionOptions } from "http2";
|
|
12
|
+
/**
|
|
13
|
+
* Agent options for the the http2Watch
|
|
14
|
+
*/
|
|
15
|
+
export type AgentOptions = Pick<
|
|
16
|
+
SecureClientSessionOptions,
|
|
17
|
+
"ca" | "cert" | "key" | "rejectUnauthorized"
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for the http2Watch
|
|
22
|
+
*/
|
|
23
|
+
export interface Options {
|
|
24
|
+
agent?: https.Agent & { options?: AgentOptions };
|
|
25
|
+
}
|
|
10
26
|
|
|
11
27
|
/**
|
|
12
28
|
* The Phase matched when using the K8s Watch API.
|
package/src/fluent/watch.ts
CHANGED
|
@@ -9,7 +9,7 @@ import http2 from "http2";
|
|
|
9
9
|
import fetch from "node-fetch";
|
|
10
10
|
import { fetch as wrappedFetch } from "../fetch";
|
|
11
11
|
import { GenericClass, KubernetesListObject } from "../types";
|
|
12
|
-
import { Filters, WatchAction, WatchPhase } from "./types";
|
|
12
|
+
import { Filters, WatchAction, WatchPhase, Options, AgentOptions } from "./types";
|
|
13
13
|
import { k8sCfg, pathBuilder } from "./utils";
|
|
14
14
|
import fs from "fs";
|
|
15
15
|
|
|
@@ -469,6 +469,44 @@ export class Watcher<T extends GenericClass> {
|
|
|
469
469
|
}
|
|
470
470
|
};
|
|
471
471
|
|
|
472
|
+
// Configure the agent options for the HTTP/2 client
|
|
473
|
+
static #getAgentOptions(opts: Options) {
|
|
474
|
+
if (opts.agent && opts.agent instanceof https.Agent) {
|
|
475
|
+
return {
|
|
476
|
+
key: opts.agent.options.key,
|
|
477
|
+
cert: opts.agent.options.cert,
|
|
478
|
+
ca: opts.agent.options.ca,
|
|
479
|
+
rejectUnauthorized: false,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return undefined;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Create an HTTP/2 client
|
|
486
|
+
static #createHttp2Client(origin: string, agentOptions?: AgentOptions) {
|
|
487
|
+
return http2.connect(origin, {
|
|
488
|
+
ca: agentOptions?.ca,
|
|
489
|
+
cert: agentOptions?.cert,
|
|
490
|
+
key: agentOptions?.key,
|
|
491
|
+
rejectUnauthorized: agentOptions?.rejectUnauthorized,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Generate the request headers for the HTTP/2 request
|
|
496
|
+
#generateRequestHeaders = async (url: URL) => {
|
|
497
|
+
const token = await this.#getToken();
|
|
498
|
+
const headers: Record<string, string> = {
|
|
499
|
+
":method": "GET",
|
|
500
|
+
":path": url.pathname + url.search,
|
|
501
|
+
"content-type": "application/json",
|
|
502
|
+
"user-agent": "kubernetes-fluent-client",
|
|
503
|
+
};
|
|
504
|
+
if (token) {
|
|
505
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
506
|
+
}
|
|
507
|
+
return headers;
|
|
508
|
+
};
|
|
509
|
+
|
|
472
510
|
/**
|
|
473
511
|
* Watch for changes to the resource.
|
|
474
512
|
*/
|
|
@@ -479,92 +517,30 @@ export class Watcher<T extends GenericClass> {
|
|
|
479
517
|
|
|
480
518
|
// Build the URL and request options
|
|
481
519
|
const { opts, url } = await this.#buildURL(true, this.#resourceVersion);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (opts.agent && opts.agent instanceof https.Agent) {
|
|
485
|
-
agentOptions = {
|
|
486
|
-
key: opts.agent.options.key,
|
|
487
|
-
cert: opts.agent.options.cert,
|
|
488
|
-
ca: opts.agent.options.ca,
|
|
489
|
-
rejectUnauthorized: false,
|
|
490
|
-
};
|
|
491
|
-
}
|
|
520
|
+
const agentOptions = Watcher.#getAgentOptions(opts as Options);
|
|
492
521
|
|
|
493
522
|
// HTTP/2 client connection setup
|
|
494
|
-
const client =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
523
|
+
const client = Watcher.#createHttp2Client(url.origin, agentOptions);
|
|
524
|
+
|
|
525
|
+
// Handle client connection errors
|
|
526
|
+
client.on("error", err => {
|
|
527
|
+
this.#events.emit(WatchEvent.NETWORK_ERROR, err);
|
|
528
|
+
this.#cleanupAndReconnect(client, err);
|
|
499
529
|
});
|
|
500
530
|
|
|
501
531
|
// Set up headers for the HTTP/2 request
|
|
502
|
-
const
|
|
503
|
-
const headers: Record<string, string> = {
|
|
504
|
-
":method": "GET",
|
|
505
|
-
":path": url.pathname + url.search,
|
|
506
|
-
"content-type": "application/json",
|
|
507
|
-
"user-agent": "kubernetes-fluent-client",
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
if (token) {
|
|
511
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
512
|
-
}
|
|
532
|
+
const headers = await this.#generateRequestHeaders(url);
|
|
513
533
|
|
|
514
534
|
// Make the HTTP/2 request
|
|
515
535
|
const req = client.request(headers);
|
|
516
|
-
|
|
517
536
|
req.setEncoding("utf8");
|
|
518
537
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
526
|
-
this.#pendingReconnect = false;
|
|
527
|
-
this.#events.emit(WatchEvent.CONNECT, url.pathname);
|
|
528
|
-
|
|
529
|
-
// Reset the retry count
|
|
530
|
-
this.#resyncFailureCount = 0;
|
|
531
|
-
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
532
|
-
|
|
533
|
-
req.on("data", async chunk => {
|
|
534
|
-
try {
|
|
535
|
-
buffer += chunk;
|
|
536
|
-
const lines = buffer.split("\n");
|
|
537
|
-
// Avoid Watch event data_error received. Unexpected end of JSON input.
|
|
538
|
-
buffer = lines.pop()!;
|
|
539
|
-
|
|
540
|
-
for (const line of lines) {
|
|
541
|
-
await this.#processLine(line, this.#process);
|
|
542
|
-
}
|
|
543
|
-
} catch (err) {
|
|
544
|
-
void this.#errHandler(err);
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
req.on("end", () => {
|
|
549
|
-
client.close();
|
|
550
|
-
this.#streamCleanup();
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
req.on("close", () => {
|
|
554
|
-
client.close();
|
|
555
|
-
this.#streamCleanup();
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
req.on("error", err => {
|
|
559
|
-
void this.#errHandler(err);
|
|
560
|
-
});
|
|
561
|
-
} else {
|
|
562
|
-
const statusMessage = headers[":status-text"] || "Unknown";
|
|
563
|
-
throw new Error(`watch connect failed: ${statusCode} ${statusMessage}`);
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
req.on("error", err => {
|
|
567
|
-
void this.#errHandler(err);
|
|
538
|
+
// Handler events for the HTTP/2 request
|
|
539
|
+
this.#handleHttp2Request(req, client);
|
|
540
|
+
|
|
541
|
+
// Handle abort signal
|
|
542
|
+
this.#abortController.signal.addEventListener("abort", () => {
|
|
543
|
+
this.#streamCleanup(client);
|
|
568
544
|
});
|
|
569
545
|
} catch (e) {
|
|
570
546
|
void this.#errHandler(e);
|
|
@@ -602,6 +578,10 @@ export class Watcher<T extends GenericClass> {
|
|
|
602
578
|
this.#events.emit(WatchEvent.RECONNECT, this.#resyncFailureCount);
|
|
603
579
|
this.#streamCleanup();
|
|
604
580
|
|
|
581
|
+
if (this.#useHTTP2) {
|
|
582
|
+
this.#cleanupAndReconnect();
|
|
583
|
+
}
|
|
584
|
+
|
|
605
585
|
if (!this.#useHTTP2) {
|
|
606
586
|
void this.#watch();
|
|
607
587
|
}
|
|
@@ -628,6 +608,7 @@ export class Watcher<T extends GenericClass> {
|
|
|
628
608
|
clearInterval(this.$relistTimer);
|
|
629
609
|
clearInterval(this.#resyncTimer);
|
|
630
610
|
this.#streamCleanup();
|
|
611
|
+
this.#scheduleReconnect();
|
|
631
612
|
this.#events.emit(WatchEvent.ABORT, err);
|
|
632
613
|
return;
|
|
633
614
|
|
|
@@ -645,15 +626,89 @@ export class Watcher<T extends GenericClass> {
|
|
|
645
626
|
// Force a resync
|
|
646
627
|
this.#lastSeenTime = OVERRIDE;
|
|
647
628
|
};
|
|
629
|
+
/**
|
|
630
|
+
*
|
|
631
|
+
* @param req - the request stream
|
|
632
|
+
* @param client - the client session
|
|
633
|
+
*/
|
|
634
|
+
#handleHttp2Request(req: http2.ClientHttp2Stream, client: http2.ClientHttp2Session) {
|
|
635
|
+
let buffer = "";
|
|
636
|
+
|
|
637
|
+
req.on("response", headers => {
|
|
638
|
+
const statusCode = headers[":status"];
|
|
639
|
+
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
640
|
+
this.#onWatchConnected();
|
|
641
|
+
} else {
|
|
642
|
+
this.#cleanupAndReconnect(client, new Error(`watch connect failed: ${statusCode}`));
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
req.on("data", chunk => {
|
|
647
|
+
buffer += chunk;
|
|
648
|
+
const lines = buffer.split("\n");
|
|
649
|
+
buffer = lines.pop() || ""; // Keep any incomplete line for the next chunk
|
|
650
|
+
|
|
651
|
+
lines.forEach(line => {
|
|
652
|
+
void this.#processLine(line, this.#process);
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
req.on("end", () => this.#cleanupAndReconnect(client));
|
|
657
|
+
req.on("close", () => this.#cleanupAndReconnect(client));
|
|
658
|
+
req.on("error", error => this.#errHandler(error));
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/** Schedules a reconnect with a delay to prevent rapid reconnections. */
|
|
662
|
+
#scheduleReconnect() {
|
|
663
|
+
const jitter = Math.floor(Math.random() * 1000);
|
|
664
|
+
const delay = (this.#watchCfg.resyncDelaySec ?? 5) * 1000 + jitter;
|
|
648
665
|
|
|
649
|
-
|
|
650
|
-
|
|
666
|
+
setTimeout(() => {
|
|
667
|
+
this.#events.emit(WatchEvent.RECONNECT, this.#resyncFailureCount);
|
|
668
|
+
void this.#http2Watch();
|
|
669
|
+
}, delay);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Handle a successful connection to the watch.
|
|
674
|
+
*/
|
|
675
|
+
#onWatchConnected() {
|
|
676
|
+
this.#pendingReconnect = false;
|
|
677
|
+
this.#events.emit(WatchEvent.CONNECT);
|
|
678
|
+
|
|
679
|
+
// Reset the retry count
|
|
680
|
+
this.#resyncFailureCount = 0;
|
|
681
|
+
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Cleanup the stream and listeners.
|
|
686
|
+
*
|
|
687
|
+
* @param client - the client session
|
|
688
|
+
*/
|
|
689
|
+
#streamCleanup = (client?: http2.ClientHttp2Session) => {
|
|
651
690
|
if (this.#stream) {
|
|
652
691
|
this.#stream.removeAllListeners();
|
|
653
692
|
this.#stream.destroy();
|
|
654
693
|
}
|
|
655
|
-
if (
|
|
656
|
-
|
|
694
|
+
if (client) {
|
|
695
|
+
client.close();
|
|
657
696
|
}
|
|
658
697
|
};
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Cleanup the stream and listeners and reconnect.
|
|
701
|
+
*
|
|
702
|
+
* @param client - the client session
|
|
703
|
+
* @param error - the error that occurred
|
|
704
|
+
*/
|
|
705
|
+
#cleanupAndReconnect(client?: http2.ClientHttp2Session, error?: Error) {
|
|
706
|
+
this.#streamCleanup(client);
|
|
707
|
+
|
|
708
|
+
if (error) {
|
|
709
|
+
void this.#errHandler(error);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
this.#scheduleReconnect();
|
|
713
|
+
}
|
|
659
714
|
}
|
package/dist/fetch.test.d.ts
DELETED
package/dist/fetch.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.test.d.ts","sourceRoot":"","sources":["../src/fetch.test.ts"],"names":[],"mappings":""}
|