UNPKG

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