teraslice 2.17.3 → 3.0.0-dev.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/dist/src/lib/cluster/services/api.js +5 -8
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/index.js +1 -1
- package/dist/src/lib/cluster/services/cluster/index.js +0 -4
- package/dist/src/lib/cluster/services/execution.js +1 -1
- package/dist/src/lib/cluster/services/jobs.js +12 -8
- package/dist/src/lib/config/schemas/system.js +1 -1
- package/dist/src/lib/utils/api_utils.js +1 -41
- package/dist/src/lib/workers/helpers/worker-shutdown.js +4 -19
- package/dist/test/utils/api_utils-spec.js +1 -62
- package/package.json +11 -12
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/index.js +0 -192
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8s.js +0 -481
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +0 -414
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sState.js +0 -59
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/utils.js +0 -43
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8s-spec.js +0 -316
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js +0 -795
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-multicluster-spec.js +0 -67
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-spec.js +0 -84
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/utils-spec.js +0 -132
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
// You can set the following environment variable to generate more verbose debug
|
|
2
|
-
// output for nock
|
|
3
|
-
// env DEBUG='nock*' make test
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import nock from 'nock';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { debugLogger } from '@terascope/utils';
|
|
9
|
-
import { K8s } from '../../../../../../../src/lib/cluster/services/cluster/backends/kubernetes/k8s.js';
|
|
10
|
-
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
const logger = debugLogger('k8s-spec');
|
|
12
|
-
const swaggerFile = path.join(dirname, 'files', 'swagger.json');
|
|
13
|
-
const _url = 'http://mock.kube.api';
|
|
14
|
-
// const _url = 'https://192.168.99.100:8443';
|
|
15
|
-
describe('k8s', () => {
|
|
16
|
-
let k8s;
|
|
17
|
-
beforeEach(async () => {
|
|
18
|
-
nock(_url)
|
|
19
|
-
.get('/swagger.json')
|
|
20
|
-
.reply(200, fs.readFileSync(swaggerFile, 'utf-8'))
|
|
21
|
-
.get('/api/v1/namespaces')
|
|
22
|
-
.reply(200, {
|
|
23
|
-
kind: 'NamespaceList',
|
|
24
|
-
apiVersion: 'v1',
|
|
25
|
-
metadata: {
|
|
26
|
-
selfLink: '/api/v1/namespaces',
|
|
27
|
-
resourceVersion: '1961000'
|
|
28
|
-
},
|
|
29
|
-
items: [
|
|
30
|
-
{
|
|
31
|
-
metadata: {
|
|
32
|
-
name: 'default'
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
});
|
|
37
|
-
const clientConfig = {
|
|
38
|
-
url: _url,
|
|
39
|
-
auth: {
|
|
40
|
-
user: 'admin',
|
|
41
|
-
pass: 'fakepass',
|
|
42
|
-
},
|
|
43
|
-
insecureSkipTlsVerify: true,
|
|
44
|
-
};
|
|
45
|
-
k8s = new K8s(logger, clientConfig, null, 1, 1);
|
|
46
|
-
await k8s.init();
|
|
47
|
-
});
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
nock.cleanAll();
|
|
50
|
-
});
|
|
51
|
-
it('can get the "default" namespace', async () => {
|
|
52
|
-
const namespaces = await k8s.getNamespaces();
|
|
53
|
-
expect(namespaces.items[0].metadata.name).toEqual('default');
|
|
54
|
-
});
|
|
55
|
-
describe('->list', () => {
|
|
56
|
-
it('can get PodList', async () => {
|
|
57
|
-
nock(_url)
|
|
58
|
-
.get('/api/v1/namespaces/default/pods/')
|
|
59
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
60
|
-
.reply(200, { kind: 'PodList' });
|
|
61
|
-
const pods = await k8s.list('app=teraslice', 'pods');
|
|
62
|
-
expect(pods.kind).toEqual('PodList');
|
|
63
|
-
});
|
|
64
|
-
it('can get ServiceList', async () => {
|
|
65
|
-
nock(_url)
|
|
66
|
-
.get('/api/v1/namespaces/default/services/')
|
|
67
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
68
|
-
.reply(200, { kind: 'ServiceList' });
|
|
69
|
-
const pods = await k8s.list('app=teraslice', 'services');
|
|
70
|
-
expect(pods.kind).toEqual('ServiceList');
|
|
71
|
-
});
|
|
72
|
-
it('can get DeploymentList', async () => {
|
|
73
|
-
nock(_url)
|
|
74
|
-
.get('/apis/apps/v1/namespaces/default/deployments/')
|
|
75
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
76
|
-
.reply(200, { kind: 'DeploymentList' });
|
|
77
|
-
const deployments = await k8s.list('app=teraslice', 'deployments');
|
|
78
|
-
expect(deployments.kind).toEqual('DeploymentList');
|
|
79
|
-
});
|
|
80
|
-
it('can get JobList', async () => {
|
|
81
|
-
nock(_url)
|
|
82
|
-
.get('/apis/batch/v1/namespaces/default/jobs/')
|
|
83
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
84
|
-
.reply(200, { kind: 'JobList' });
|
|
85
|
-
const jobs = await k8s.list('app=teraslice', 'jobs');
|
|
86
|
-
expect(jobs.kind).toEqual('JobList');
|
|
87
|
-
});
|
|
88
|
-
it('can get ReplicaSetList', async () => {
|
|
89
|
-
nock(_url)
|
|
90
|
-
.get('/apis/apps/v1/namespaces/default/replicasets/')
|
|
91
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
92
|
-
.reply(200, { kind: 'ReplicaSetList' });
|
|
93
|
-
const jobs = await k8s.list('app=teraslice', 'replicasets');
|
|
94
|
-
expect(jobs.kind).toEqual('ReplicaSetList');
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
describe('->nonEmptyList', () => {
|
|
98
|
-
it('can get list with one item', async () => {
|
|
99
|
-
nock(_url)
|
|
100
|
-
.get('/apis/batch/v1/namespaces/default/jobs/')
|
|
101
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
102
|
-
.reply(200, { items: ['one'] });
|
|
103
|
-
const jobs = await k8s.nonEmptyList('app=teraslice', 'jobs');
|
|
104
|
-
expect(jobs.items[0]).toEqual('one');
|
|
105
|
-
});
|
|
106
|
-
it('throws with an empty list', async () => {
|
|
107
|
-
nock(_url)
|
|
108
|
-
.get('/apis/batch/v1/namespaces/default/jobs/')
|
|
109
|
-
.query({ labelSelector: 'app=teraslice' })
|
|
110
|
-
.reply(200, { items: [] });
|
|
111
|
-
await expect(k8s.nonEmptyList('app=teraslice', 'jobs'))
|
|
112
|
-
.rejects.toThrow('Teraslice jobs matching the following selector was not found: app=teraslice (retriable)');
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
describe('->post', () => {
|
|
116
|
-
it('can post a service', async () => {
|
|
117
|
-
nock(_url, { encodedQueryParams: true })
|
|
118
|
-
.post('/api/v1/namespaces/default/services')
|
|
119
|
-
.reply(201, { kind: 'Service' });
|
|
120
|
-
const response = await k8s.post({ kind: 'Service' }, 'service');
|
|
121
|
-
expect(response.kind).toEqual('Service');
|
|
122
|
-
});
|
|
123
|
-
it('can post a deployment', async () => {
|
|
124
|
-
nock(_url, { encodedQueryParams: true })
|
|
125
|
-
.post('/apis/apps/v1/namespaces/default/deployments')
|
|
126
|
-
.reply(201, { kind: 'Deployment' });
|
|
127
|
-
const response = await k8s.post({ kind: 'Deployment' }, 'deployment');
|
|
128
|
-
expect(response.kind).toEqual('Deployment');
|
|
129
|
-
});
|
|
130
|
-
it('can post a job', async () => {
|
|
131
|
-
nock(_url, { encodedQueryParams: true })
|
|
132
|
-
.post('/apis/batch/v1/namespaces/default/jobs')
|
|
133
|
-
.reply(201, { kind: 'Job' });
|
|
134
|
-
const response = await k8s.post({ kind: 'Job' }, 'job');
|
|
135
|
-
expect(response.kind).toEqual('Job');
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
describe('->patch', () => {
|
|
139
|
-
beforeEach(() => {
|
|
140
|
-
nock(_url, { encodedQueryParams: true })
|
|
141
|
-
.patch('/apis/apps/v1/namespaces/default/deployments/test1')
|
|
142
|
-
.reply(204, {});
|
|
143
|
-
});
|
|
144
|
-
it('can patch a deployment by name', async () => {
|
|
145
|
-
const response = await k8s.patch({ name: 'testName' }, 'test1');
|
|
146
|
-
expect(response).toEqual({});
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
describe('->delete', () => {
|
|
150
|
-
it('will throw if name is undefined', async () => {
|
|
151
|
-
await expect(k8s.delete(undefined, 'deployments'))
|
|
152
|
-
.rejects.toThrow('Name of resource to delete must be specified. Received: "undefined".');
|
|
153
|
-
});
|
|
154
|
-
it('will throw if name is an empty string', async () => {
|
|
155
|
-
await expect(k8s.delete('', 'deployments'))
|
|
156
|
-
.rejects.toThrow('Name of resource to delete must be specified. Received: "".');
|
|
157
|
-
});
|
|
158
|
-
it('can delete a deployment by name', async () => {
|
|
159
|
-
nock(_url)
|
|
160
|
-
.delete('/apis/apps/v1/namespaces/default/deployments/test1')
|
|
161
|
-
.reply(200, {});
|
|
162
|
-
const response = await k8s.delete('test1', 'deployments');
|
|
163
|
-
expect(response).toEqual({});
|
|
164
|
-
});
|
|
165
|
-
it('can delete a service by name', async () => {
|
|
166
|
-
nock(_url)
|
|
167
|
-
.delete('/api/v1/namespaces/default/services/test1')
|
|
168
|
-
.reply(200, {});
|
|
169
|
-
const response = await k8s.delete('test1', 'services');
|
|
170
|
-
expect(response).toEqual({});
|
|
171
|
-
});
|
|
172
|
-
it('can delete a job by name', async () => {
|
|
173
|
-
nock(_url)
|
|
174
|
-
.delete('/apis/batch/v1/namespaces/default/jobs/test1')
|
|
175
|
-
.reply(200, {});
|
|
176
|
-
const response = await k8s.delete('test1', 'jobs');
|
|
177
|
-
expect(response).toEqual({});
|
|
178
|
-
});
|
|
179
|
-
it('can delete a pod by name', async () => {
|
|
180
|
-
nock(_url)
|
|
181
|
-
.delete('/api/v1/namespaces/default/pods/test1')
|
|
182
|
-
.reply(200, {});
|
|
183
|
-
const response = await k8s.delete('test1', 'pods');
|
|
184
|
-
expect(response).toEqual({});
|
|
185
|
-
});
|
|
186
|
-
it('can delete a replicaset by name', async () => {
|
|
187
|
-
nock(_url)
|
|
188
|
-
.delete('/apis/apps/v1/namespaces/default/replicasets/test1')
|
|
189
|
-
.reply(200, {});
|
|
190
|
-
const response = await k8s.delete('test1', 'replicasets');
|
|
191
|
-
expect(response).toEqual({});
|
|
192
|
-
});
|
|
193
|
-
it('will throw on a reponse code >= 400, excluding 404', async () => {
|
|
194
|
-
nock(_url)
|
|
195
|
-
.delete('/api/v1/namespaces/default/pods/bad-response')
|
|
196
|
-
.replyWithError({ statusCode: 400 })
|
|
197
|
-
.delete('/api/v1/namespaces/default/pods/bad-response')
|
|
198
|
-
.replyWithError({ statusCode: 400 })
|
|
199
|
-
.delete('/api/v1/namespaces/default/pods/bad-response')
|
|
200
|
-
.replyWithError({ statusCode: 400 });
|
|
201
|
-
await expect(k8s.delete('bad-response', 'pods'))
|
|
202
|
-
.rejects.toThrow('Request k8s.delete with name: bad-response failed with: TSError: Unexpected response code (400), when deleting name: bad-response');
|
|
203
|
-
});
|
|
204
|
-
it('will succeed on a 404 response code', async () => {
|
|
205
|
-
const notFoundResponse = {
|
|
206
|
-
body: {
|
|
207
|
-
kind: 'Status',
|
|
208
|
-
apiVersion: 'v1',
|
|
209
|
-
metadata: {},
|
|
210
|
-
status: 'Failure',
|
|
211
|
-
message: 'pods "non-existent" not found',
|
|
212
|
-
reason: 'NotFound',
|
|
213
|
-
details: { name: 'non-existent', kind: 'pods' },
|
|
214
|
-
code: 404
|
|
215
|
-
},
|
|
216
|
-
statusCode: 404
|
|
217
|
-
};
|
|
218
|
-
nock(_url)
|
|
219
|
-
.delete('/api/v1/namespaces/default/pods/non-existent')
|
|
220
|
-
.replyWithError(notFoundResponse);
|
|
221
|
-
const response = await k8s.delete('non-existent', 'pods');
|
|
222
|
-
expect(response).toEqual(notFoundResponse.body);
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
describe('->_deletObjByExId', () => {
|
|
226
|
-
it('will throw if name is undefined', async () => {
|
|
227
|
-
nock(_url)
|
|
228
|
-
.get('/apis/batch/v1/namespaces/default/jobs/')
|
|
229
|
-
.query({ labelSelector: /app\.kubernetes\.io\/component=execution_controller,teraslice\.terascope\.io\/exId=.*/ })
|
|
230
|
-
.reply(200, {
|
|
231
|
-
kind: 'JobList',
|
|
232
|
-
items: [
|
|
233
|
-
{ metadata: { name: undefined } }
|
|
234
|
-
]
|
|
235
|
-
});
|
|
236
|
-
await expect(k8s._deleteObjByExId('no-name', 'execution_controller', 'jobs'))
|
|
237
|
-
.rejects.toThrow('Cannot delete jobs for ExId: no-name by name because it has no name');
|
|
238
|
-
});
|
|
239
|
-
it('can delete a single object', async () => {
|
|
240
|
-
nock(_url)
|
|
241
|
-
.get('/apis/batch/v1/namespaces/default/jobs/')
|
|
242
|
-
.query({ labelSelector: /app\.kubernetes\.io\/component=execution_controller,teraslice\.terascope\.io\/exId=.*/ })
|
|
243
|
-
.reply(200, {
|
|
244
|
-
kind: 'JobList',
|
|
245
|
-
items: [
|
|
246
|
-
{ metadata: { name: 'testJob1' } }
|
|
247
|
-
]
|
|
248
|
-
});
|
|
249
|
-
nock(_url)
|
|
250
|
-
.delete('/apis/batch/v1/namespaces/default/jobs/testJob1')
|
|
251
|
-
.reply(200, {});
|
|
252
|
-
const response = await k8s._deleteObjByExId('testJob1', 'execution_controller', 'jobs');
|
|
253
|
-
expect(response).toEqual([{}]);
|
|
254
|
-
});
|
|
255
|
-
it('can delete a multiple objects', async () => {
|
|
256
|
-
nock(_url)
|
|
257
|
-
.get('/api/v1/namespaces/default/pods/')
|
|
258
|
-
.query({ labelSelector: /app\.kubernetes\.io\/component=worker,teraslice\.terascope\.io\/exId=.*/ })
|
|
259
|
-
.reply(200, {
|
|
260
|
-
kind: 'PodList',
|
|
261
|
-
items: [
|
|
262
|
-
{ metadata: { name: 'testPod1' } },
|
|
263
|
-
{ metadata: { name: 'testPod2' } }
|
|
264
|
-
]
|
|
265
|
-
})
|
|
266
|
-
.delete('/api/v1/namespaces/default/pods/testPod1')
|
|
267
|
-
.reply(200, {})
|
|
268
|
-
.delete('/api/v1/namespaces/default/pods/testPod2')
|
|
269
|
-
.reply(200, {});
|
|
270
|
-
const response = await k8s._deleteObjByExId('testPods', 'worker', 'pods');
|
|
271
|
-
expect(response).toEqual([{}, {}]);
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
describe('->scaleExecution', () => {
|
|
275
|
-
let scope;
|
|
276
|
-
beforeEach(() => {
|
|
277
|
-
scope = nock(_url)
|
|
278
|
-
.get('/apis/apps/v1/namespaces/default/deployments/')
|
|
279
|
-
.query({ labelSelector: /app\.kubernetes\.io\/component=worker,teraslice\.terascope\.io\/exId=.*/ })
|
|
280
|
-
.reply(200, {
|
|
281
|
-
kind: 'DeploymentList',
|
|
282
|
-
items: [
|
|
283
|
-
{ spec: { replicas: 5 }, metadata: { name: 'dname' } }
|
|
284
|
-
]
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
it('can set nodes to a deployment to 2', async () => {
|
|
288
|
-
scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
|
|
289
|
-
spec: {
|
|
290
|
-
replicas: 2,
|
|
291
|
-
}
|
|
292
|
-
}).reply(200, (uri, requestBody) => requestBody);
|
|
293
|
-
const response = await k8s.scaleExecution('abcde1234', 2, 'set');
|
|
294
|
-
expect(response.spec.replicas).toEqual(2);
|
|
295
|
-
});
|
|
296
|
-
it('can add 2 nodes to a deployment with 5 to get 7', async () => {
|
|
297
|
-
scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
|
|
298
|
-
spec: {
|
|
299
|
-
replicas: 7,
|
|
300
|
-
}
|
|
301
|
-
}).reply(200, (uri, requestBody) => requestBody);
|
|
302
|
-
const response = await k8s.scaleExecution('abcde1234', 2, 'add');
|
|
303
|
-
expect(response.spec.replicas).toEqual(7);
|
|
304
|
-
});
|
|
305
|
-
it('can remove 2 nodes from a deployment with 5 to get 3', async () => {
|
|
306
|
-
scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
|
|
307
|
-
spec: {
|
|
308
|
-
replicas: 3,
|
|
309
|
-
}
|
|
310
|
-
}).reply(200, (uri, requestBody) => requestBody);
|
|
311
|
-
const response = await k8s.scaleExecution('abcde1234', 2, 'remove');
|
|
312
|
-
expect(response.spec.replicas).toEqual(3);
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
//# sourceMappingURL=k8s-spec.js.map
|