UNPKG

10.3 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11var __importDefault = (this && this.__importDefault) || function (mod) {
12 return (mod && mod.__esModule) ? mod : { "default": mod };
13};
14Object.defineProperty(exports, "__esModule", { value: true });
15const request_1 = __importDefault(require("request"));
16const label_1 = require("./label");
17const meta_1 = require("./types/meta");
18const debug = require("debug")("kubernetes:client");
19exports.patchKindStrategicMergePatch = "application/stategic-merge-patch+json";
20exports.patchKindMergePatch = "application/merge-patch+json";
21exports.patchKindJSONPatch = "application/json-patch+json";
22const joinURL = (left, right) => (left + "/" + right).replace(/([^:])(\/\/)/g, "$1/");
23class KubernetesRESTClient {
24 constructor(config) {
25 this.config = config;
26 }
27 request(url, body, method = "POST", additionalOptions = {}) {
28 const absoluteURL = joinURL(this.config.apiServerURL, url);
29 return new Promise((res, rej) => {
30 let opts = {
31 method,
32 url: absoluteURL,
33 json: true,
34 };
35 if (body) {
36 opts.json = body;
37 }
38 opts = this.config.mapRequestOptions(opts);
39 if (additionalOptions.headers) {
40 additionalOptions.headers = Object.assign(Object.assign({}, (opts.headers || {})), additionalOptions.headers);
41 }
42 opts = Object.assign(Object.assign({}, opts), additionalOptions);
43 debug(`executing ${method} request on ${opts.url}`);
44 request_1.default(opts, (err, response, responseBody) => {
45 if (err) {
46 rej(err);
47 return;
48 }
49 if (meta_1.isStatus(responseBody) && responseBody.status === "Failure") {
50 rej(new Error(responseBody.message));
51 return;
52 }
53 debug(`${method} request on ${opts.url} succeeded with status ${response.statusCode}: ${responseBody}`);
54 res(responseBody);
55 });
56 });
57 }
58 post(url, body) {
59 return this.request(url, body, "POST");
60 }
61 put(url, body) {
62 return this.request(url, body, "PUT");
63 }
64 patch(url, body, patchKind) {
65 return this.request(url, body, "PATCH", { headers: {
66 "Content-Type": patchKind,
67 } });
68 }
69 delete(url, deleteOptions, queryParams = {}, body) {
70 const opts = {};
71 opts.qs = queryParams;
72 if (deleteOptions && deleteOptions.labelSelector) {
73 opts.qs.labelSelector = label_1.selectorToQueryString(deleteOptions.labelSelector);
74 }
75 if (deleteOptions && deleteOptions.fieldSelector) {
76 opts.qs.fieldSelector = label_1.selectorToQueryString(deleteOptions.fieldSelector);
77 }
78 return this.request(url, body, "DELETE", opts);
79 }
80 watch(url, onUpdate, onError, watchOpts = {}) {
81 const absoluteURL = joinURL(this.config.apiServerURL, url);
82 let opts = {
83 url: absoluteURL,
84 qs: { watch: "true" },
85 };
86 if (watchOpts.labelSelector) {
87 opts.qs.labelSelector = label_1.selectorToQueryString(watchOpts.labelSelector);
88 }
89 if (watchOpts.fieldSelector) {
90 opts.qs.fieldSelector = label_1.selectorToQueryString(watchOpts.fieldSelector);
91 }
92 if (watchOpts.resourceVersion) {
93 opts.qs.resourceVersion = watchOpts.resourceVersion;
94 }
95 opts = this.config.mapRequestOptions(opts);
96 let lastVersion = watchOpts.resourceVersion || 0;
97 debug(`executing WATCH request on ${absoluteURL} (starting revision ${lastVersion})`);
98 return new Promise((res, rej) => {
99 const req = request_1.default(opts, (err, response, bodyString) => __awaiter(this, void 0, void 0, function* () {
100 if (err) {
101 rej(err);
102 return;
103 }
104 debug(`%o request on %o completed with status %o: %O`, "WATCH", opts.url, response.statusCode, bodyString);
105 if (response.statusCode && response.statusCode >= 400) {
106 if (response.statusCode === 410) {
107 debug(`last known resource has expired -- resync required`);
108 res({ resourceVersion: lastVersion, resyncRequired: true });
109 return;
110 }
111 rej(new Error("Unexpected status code: " + response.statusCode));
112 return;
113 }
114 if (bodyString.length === 0) {
115 debug(`WATCH request on ${url} returned empty response`);
116 res({ resourceVersion: lastVersion });
117 return;
118 }
119 let body;
120 try {
121 body = JSON.parse(bodyString);
122 }
123 catch (err) {
124 const bodyLines = bodyString.split("\n");
125 for (const line of bodyLines) {
126 if (line === "") {
127 continue;
128 }
129 try {
130 const parsedLine = JSON.parse(line);
131 if (parsedLine.type === "ADDED" || parsedLine.type === "MODIFIED" || parsedLine.type === "DELETED") {
132 const resourceVersion = parseInt(parsedLine.object.metadata.resourceVersion || "0", 10);
133 if (resourceVersion > lastVersion) {
134 debug(`watch: emitting missed ${parsedLine.type} event for ${parsedLine.object.metadata.name}`);
135 lastVersion = resourceVersion;
136 yield onUpdate(parsedLine);
137 }
138 }
139 }
140 catch (err) {
141 debug(`watch: could not parse JSON line '${line}'`);
142 rej(err);
143 return;
144 }
145 }
146 res({ resourceVersion: lastVersion });
147 return;
148 }
149 if (meta_1.isStatus(body) && body.status === "Failure") {
150 debug(`watch: failed with status %O`, body);
151 rej(body.message);
152 return;
153 }
154 res({ resourceVersion: lastVersion });
155 }));
156 let buffer = "";
157 req.on("data", (chunk) => __awaiter(this, void 0, void 0, function* () {
158 if (chunk instanceof Buffer) {
159 chunk = chunk.toString("utf-8");
160 }
161 debug("WATCH request on %o received %d bytes of data", opts.url, chunk.length);
162 buffer += chunk;
163 try {
164 const obj = JSON.parse(buffer);
165 buffer = "";
166 const resourceVersion = obj.object.metadata.resourceVersion ? parseInt(obj.object.metadata.resourceVersion, 10) : -1;
167 if (resourceVersion > lastVersion) {
168 debug(`watch: emitting ${obj.type} event for ${obj.object.metadata.name}`);
169 lastVersion = resourceVersion;
170 yield onUpdate(obj);
171 }
172 }
173 catch (err) {
174 onError(err);
175 }
176 }));
177 });
178 }
179 get(url, listOptions = {}) {
180 const absoluteURL = joinURL(this.config.apiServerURL, url);
181 const { labelSelector, fieldSelector } = listOptions;
182 return new Promise((res, rej) => {
183 let opts = {
184 url: absoluteURL,
185 qs: {},
186 };
187 if (labelSelector) {
188 opts.qs.labelSelector = label_1.selectorToQueryString(labelSelector);
189 }
190 if (fieldSelector) {
191 opts.qs.fieldSelector = label_1.selectorToQueryString(fieldSelector);
192 }
193 opts = this.config.mapRequestOptions(opts);
194 debug(`executing GET request on ${opts.url}`);
195 request_1.default(opts, (err, response, body) => {
196 if (err) {
197 rej(err);
198 return;
199 }
200 if (response.statusCode === 404) {
201 debug(`GET request on %o failed with status %o`, opts.url, response.statusCode);
202 res(undefined);
203 return;
204 }
205 try {
206 body = JSON.parse(body);
207 }
208 catch (err) {
209 rej(err);
210 return;
211 }
212 if (meta_1.isStatus(body) && body.status === "Failure") {
213 if (body.code === 404) {
214 res(undefined);
215 return;
216 }
217 debug(`executing GET request on %o failed. response body: %O`, response.statusCode, body);
218 rej(new Error(body.message));
219 return;
220 }
221 debug(`GET request on %o succeeded with status %o: %O`, opts.url, response.statusCode, body);
222 res(body);
223 });
224 });
225 }
226}
227exports.KubernetesRESTClient = KubernetesRESTClient;
228//# sourceMappingURL=client.js.map
\No newline at end of file