UNPKG

16.6 kBJavaScriptView Raw
1'use strict';
2
3const Path = require('path');
4const { expect } = require('code');
5const Hapi = require('hapi');
6const Lab = require('lab');
7const StandIn = require('stand-in');
8const CloudApiGql = require('../lib/');
9const CloudApi = require('../lib/cloudapi');
10
11
12const lab = exports.lab = Lab.script();
13const { describe, it, afterEach } = lab;
14
15
16describe('machines', () => {
17 afterEach(() => {
18 StandIn.restoreAll();
19 });
20
21 const register = {
22 plugin: CloudApiGql,
23 options: {
24 keyPath: Path.join(__dirname, 'test.key'),
25 keyId: 'test',
26 apiBaseUrl: 'http://localhost'
27 }
28 };
29
30 const machine = {
31 id: 'b6979942-7d5d-4fe6-a2ec-b812e950625a',
32 name: 'test',
33 type: 'smartmachine',
34 brand: 'joyent',
35 state: 'running',
36 image: '2b683a82-a066-11e3-97ab-2faa44701c5a',
37 ips: [
38 '10.88.88.26',
39 '192.168.128.5'
40 ],
41 memory: 128,
42 disk: 12288,
43 metadata: {
44 root_authorized_keys: '...'
45 },
46 tags: {},
47 created: '2016-01-04T12:55:50.539Z',
48 updated: '2016-01-21T08:56:59.000Z',
49 networks: [
50 'a9c130da-e3ba-40e9-8b18-112aba2d3ba7',
51 '45607081-4cd2-45c8-baf7-79da760fffaa'
52 ],
53 primaryIp: '10.88.88.26',
54 firewall_enabled: false,
55 compute_node: '564d0b8e-6099-7648-351e-877faf6c56f6',
56 package: 'sdc_128'
57 };
58
59 const metadata = {
60 foo: 'bar',
61 group: 'test',
62 credentials: {
63 root: 'boo',
64 admin: 'boo'
65 }
66 };
67
68 it('can get all machines', async () => {
69 const server = new Hapi.Server();
70 StandIn.replaceOnce(CloudApi.prototype, 'fetch', (stand) => {
71 return { payload: [machine], res: { headers: { 'x-resource-count': 10 }} };
72 });
73
74 await server.register(register);
75 await server.initialize();
76 const res = await server.inject({
77 url: '/graphql',
78 method: 'post',
79 payload: { query: 'query { machines { offset total results { id name } } }' }
80 });
81 expect(res.statusCode).to.equal(200);
82 expect(res.result.data.machines.total).to.equal(10);
83 expect(res.result.data.machines.offset).to.equal(0);
84 expect(res.result.data.machines.results.length).to.equal(1);
85 expect(res.result.data.machines.results[0].id).to.equal(machine.id);
86 expect(res.result.data.machines.results[0].name).to.equal(machine.name);
87 });
88
89 it('can get all machines with paging', async () => {
90 const server = new Hapi.Server();
91 StandIn.replaceOnce(CloudApi.prototype, 'fetch', (stand) => {
92 return { payload: [machine, machine], res: { headers: { 'x-resource-count': 10 }} };
93 });
94
95 await server.register(register);
96 await server.initialize();
97 const res = await server.inject({
98 url: '/graphql',
99 method: 'post',
100 payload: { query: 'query { machines(offset: 1 limit: 2) { offset limit total results { id name } } }' }
101 });
102 expect(res.statusCode).to.equal(200);
103 expect(res.result.data.machines.total).to.equal(10);
104 expect(res.result.data.machines.offset).to.equal(1);
105 expect(res.result.data.machines.limit).to.equal(2);
106 expect(res.result.data.machines.results.length).to.equal(2);
107 expect(res.result.data.machines.results[0].id).to.equal(machine.id);
108 expect(res.result.data.machines.results[0].name).to.equal(machine.name);
109 });
110
111 it('can get a machine', async () => {
112 const server = new Hapi.Server();
113 StandIn.replaceOnce(CloudApi.prototype, 'fetch', (stand) => {
114 return machine;
115 });
116
117 await server.register(register);
118 await server.initialize();
119 const res = await server.inject({
120 url: '/graphql',
121 method: 'post',
122 payload: { query: `query { machine(id: "${machine.id}") { id name } }` }
123 });
124 expect(res.statusCode).to.equal(200);
125 expect(res.result.data.machine.id).to.equal(machine.id);
126 expect(res.result.data.machine.name).to.equal(machine.name);
127 });
128
129 it('can get a machines metadata', async () => {
130 const server = new Hapi.Server();
131 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
132 if (stand.invocations === 1) {
133 return machine;
134 }
135
136 return metadata;
137 }, { stopAfter: 2 });
138
139 await server.register(register);
140 await server.initialize();
141 const res = await server.inject({
142 url: '/graphql',
143 method: 'post',
144 payload: { query: `query { machine(id: "${machine.id}") { id name brand state metadata { name } } }` }
145 });
146 expect(res.statusCode).to.equal(200);
147 expect(res.result.data.machine.id).to.equal(machine.id);
148 expect(res.result.data.machine.name).to.equal(machine.name);
149 expect(res.result.data.machine.metadata[0].name).to.equal(Object.keys(metadata)[0]);
150 });
151
152 it('can get a machines images', async () => {
153 const image = {
154 id: '2b683a82-a066-11e3-97ab-2faa44701c5a',
155 name: 'base',
156 version: '13.4.0',
157 os: 'smartos',
158 requirements: {},
159 type: 'zone-dataset',
160 description: 'A 32-bit SmartOS image with just essential packages installed. Ideal for users who are comfortable with setting up their own environment and tools.',
161 files: [
162 {
163 compression: 'gzip',
164 sha1: '3bebb6ae2cdb26eef20cfb30fdc4a00a059a0b7b',
165 size: 110742036
166 }
167 ],
168 tags: {
169 role: 'os',
170 group: 'base-32'
171 },
172 homepage: 'https://docs.joyent.com/images/smartos/base',
173 published_at: '2014-02-28T10:50:42Z',
174 owner: '930896af-bf8c-48d4-885c-6573a94b1853',
175 public: true,
176 state: 'active'
177 };
178
179 const server = new Hapi.Server();
180 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
181 if (stand.invocations === 1) {
182 return machine;
183 }
184
185 return image;
186 }, { stopAfter: 3 });
187
188 await server.register(register);
189 await server.initialize();
190 const res = await server.inject({
191 url: '/graphql',
192 method: 'post',
193 payload: { query: `query { machine(id: "${machine.id}") { id name image { name } } }` }
194 });
195 expect(res.statusCode).to.equal(200);
196 expect(res.result.data.machine.id).to.equal(machine.id);
197 expect(res.result.data.machine.name).to.equal(machine.name);
198 expect(res.result.data.machine.image.name).to.equal(image.name);
199 });
200
201 it('can get a machines networks', async () => {
202 const network = {
203 id: '7326787b-8039-436c-a533-5038f7280f04',
204 name: 'default',
205 public: false,
206 fabric: true,
207 gateway: '192.168.128.1',
208 internet_nat: true,
209 provision_end_ip: '192.168.131.250',
210 provision_start_ip: '192.168.128.5',
211 resolvers: [
212 '8.8.8.8',
213 '8.8.4.4'
214 ],
215 subnet: '192.168.128.0/22',
216 vlan_id: 2
217 };
218
219 const server = new Hapi.Server();
220 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
221 if (stand.invocations === 1) {
222 return machine;
223 }
224
225 return network;
226 }, { stopAfter: 3 });
227
228 await server.register(register);
229 await server.initialize();
230 const res = await server.inject({
231 url: '/graphql',
232 method: 'post',
233 payload: { query: `query { machine(id: "${machine.id}") { id name networks { name } } }` }
234 });
235 expect(res.statusCode).to.equal(200);
236 expect(res.result.data.machine.id).to.equal(machine.id);
237 expect(res.result.data.machine.name).to.equal(machine.name);
238 expect(res.result.data.machine.networks[0].name).to.equal(network.name);
239 });
240
241 it('can get a machines snapshots', async () => {
242 const snapshot = {
243 name: 'just-booted',
244 state: 'queued',
245 created: '2011-07-05T17:19:26+00:00',
246 updated: '2011-07-05T17:19:26+00:00'
247 };
248
249 const server = new Hapi.Server();
250 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
251 if (stand.invocations === 1) {
252 return machine;
253 }
254
255 return [snapshot];
256 }, { stopAfter: 2 });
257
258 await server.register(register);
259 await server.initialize();
260 const res = await server.inject({
261 url: '/graphql',
262 method: 'post',
263 payload: { query: `query { machine(id: "${machine.id}") { id name snapshots { name } } }` }
264 });
265 expect(res.statusCode).to.equal(200);
266 expect(res.result.data.machine.id).to.equal(machine.id);
267 expect(res.result.data.machine.name).to.equal(machine.name);
268 expect(res.result.data.machine.snapshots[0].name).to.equal(snapshot.name);
269 });
270
271 it('can get a machines firewall rules', async () => {
272 const firewallRule = {
273 id: '38de17c4-39e8-48c7-a168-0f58083de860',
274 rule: 'FROM vm 3d51f2d5-46f2-4da5-bb04-3238f2f64768 TO subnet 10.99.99.0/24 BLOCK tcp PORT 25',
275 enabled: true,
276 description: 'test'
277 };
278
279 const server = new Hapi.Server();
280 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
281 if (stand.invocations === 1) {
282 return machine;
283 }
284
285 return [firewallRule];
286 }, { stopAfter: 2 });
287
288 await server.register(register);
289 await server.initialize();
290 const res = await server.inject({
291 url: '/graphql',
292 method: 'post',
293 payload: { query: `query { machine(id: "${machine.id}") { id name firewall_rules { rule_str } } }` }
294 });
295 expect(res.statusCode).to.equal(200);
296 expect(res.result.data.machine.id).to.equal(machine.id);
297 expect(res.result.data.machine.name).to.equal(machine.name);
298 expect(res.result.data.machine.firewall_rules[0].rule_str).to.equal(firewallRule.rule);
299 });
300
301 it('can get a machines actions', async () => {
302 const audit = {
303 success: 'yes',
304 time: '2013-02-22T15:19:32.522Z',
305 action: 'provision',
306 caller: {
307 type: 'signature',
308 ip: '127.0.0.1',
309 keyId: '/:login/keys/:fingerprint'
310 }
311 };
312
313 const server = new Hapi.Server();
314 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
315 if (stand.invocations === 1) {
316 return machine;
317 }
318
319 return [audit];
320 }, { stopAfter: 2 });
321
322 await server.register(register);
323 await server.initialize();
324 const res = await server.inject({
325 url: '/graphql',
326 method: 'post',
327 payload: { query: `query { machine(id: "${machine.id}") { id name actions { name } } }` }
328 });
329 expect(res.statusCode).to.equal(200);
330 expect(res.result.data.machine.id).to.equal(machine.id);
331 expect(res.result.data.machine.name).to.equal(machine.name);
332 expect(res.result.data.machine.actions[0].name).to.equal(audit.action);
333 });
334
335
336 it('can stop a machine', async () => {
337 const server = new Hapi.Server();
338 StandIn.replace(CloudApi.prototype, 'fetch', (stand, path) => {
339 const updatedMachine = Object.assign({}, machine, { state: 'stopping' });
340 return updatedMachine;
341 }, { stopAfter: 2 });
342
343 await server.register(register);
344 await server.initialize();
345 const res = await server.inject({
346 url: '/graphql',
347 method: 'post',
348 payload: { query: `mutation { stopMachine(id: "${machine.id}") { id state } }` }
349 });
350
351 expect(res.statusCode).to.equal(200);
352 expect(res.result.data.stopMachine.id).to.equal(machine.id);
353 expect(res.result.data.stopMachine.state).to.equal('STOPPING');
354 });
355
356 it('can start a machine', async () => {
357 const server = new Hapi.Server();
358 StandIn.replace(CloudApi.prototype, 'fetch', (stand, path) => {
359 const updatedMachine = Object.assign({}, machine, { state: 'running' });
360 return updatedMachine;
361 }, { stopAfter: 2 });
362
363 await server.register(register);
364 await server.initialize();
365 const res = await server.inject({
366 url: '/graphql',
367 method: 'post',
368 payload: { query: `mutation { startMachine(id: "${machine.id}") { id state } }` }
369 });
370
371 expect(res.statusCode).to.equal(200);
372 expect(res.result.data.startMachine.id).to.equal(machine.id);
373 expect(res.result.data.startMachine.state).to.equal('RUNNING');
374 });
375
376 it('can reboot a machine', async () => {
377 const server = new Hapi.Server();
378 StandIn.replace(CloudApi.prototype, 'fetch', (stand, path) => {
379 const updatedMachine = Object.assign({}, machine, { state: 'stopping' });
380 return updatedMachine;
381 }, { stopAfter: 2 });
382
383 await server.register(register);
384 await server.initialize();
385 const res = await server.inject({
386 url: '/graphql',
387 method: 'post',
388 payload: { query: `mutation { rebootMachine(id: "${machine.id}") { id state } }` }
389 });
390
391 expect(res.statusCode).to.equal(200);
392 expect(res.result.data.rebootMachine.id).to.equal(machine.id);
393 expect(res.result.data.rebootMachine.state).to.equal('STOPPING');
394 });
395
396 it('can resize a machine', async () => {
397 const packageObj = {
398 id: '7b17343c-94af-6266-e0e8-893a3b9993d0',
399 name: 'sdc_128',
400 memory: 128,
401 disk: 12288,
402 swap: 256,
403 vcpus: 1,
404 lwps: 1000,
405 default: false,
406 version: '1.0.0'
407 };
408
409 const server = new Hapi.Server();
410 StandIn.replace(CloudApi.prototype, 'fetch', (stand) => {
411 if (stand.invocations === 1) {
412 return '';
413 } else if (stand.invocations === 2) {
414 return machine;
415 }
416
417 return packageObj;
418 }, { stopAfter: 3 });
419
420 await server.register(register);
421 await server.initialize();
422 const res = await server.inject({
423 url: '/graphql',
424 method: 'post',
425 payload: { query: `mutation { resizeMachine(id: "${machine.id}", package: "${packageObj.id}") { id package {id name} } }` }
426 });
427
428 expect(res.statusCode).to.equal(200);
429 expect(res.result.data.resizeMachine.id).to.equal(machine.id);
430 expect(res.result.data.resizeMachine.package.id).to.equal(packageObj.id);
431 expect(res.result.data.resizeMachine.package.name).to.equal(packageObj.name);
432 });
433
434 describe('firewalls', () => {
435 it('can enable a firewall for a machine', async () => {
436 const server = new Hapi.Server();
437 StandIn.replace(CloudApi.prototype, 'fetch', () => {
438 const result = Object.assign({}, machine, { firewall_enabled: true });
439 return result;
440 }, { stopAfter: 2 });
441
442 await server.register(register);
443 await server.initialize();
444 const res = await server.inject({
445 url: '/graphql',
446 method: 'post',
447 payload: { query: `mutation { enableMachineFirewall(id: "${machine.id}") { id firewall_enabled } }` }
448 });
449 expect(res.statusCode).to.equal(200);
450 expect(res.result.data.enableMachineFirewall.id).to.equal(machine.id);
451 expect(res.result.data.enableMachineFirewall.firewall_enabled).to.equal(true);
452 });
453
454 it('can disable a firewall for a machine', async () => {
455 const server = new Hapi.Server();
456 StandIn.replace(CloudApi.prototype, 'fetch', () => {
457 const result = Object.assign({}, machine, { firewall_enabled: false });
458 return result;
459 }, { stopAfter: 2 });
460
461 await server.register(register);
462 await server.initialize();
463 const res = await server.inject({
464 url: '/graphql',
465 method: 'post',
466 payload: { query: `mutation { disableMachineFirewall(id: "${machine.id}") { id firewall_enabled } }` }
467 });
468 expect(res.statusCode).to.equal(200);
469 expect(res.result.data.disableMachineFirewall.id).to.equal(machine.id);
470 expect(res.result.data.disableMachineFirewall.firewall_enabled).to.equal(false);
471 });
472 });
473
474 describe('metadata', () => {
475 it('can get all machine metadata', async () => {
476 const server = new Hapi.Server();
477 StandIn.replaceOnce(CloudApi.prototype, 'fetch', (stand) => {
478 return metadata;
479 });
480
481 await server.register(register);
482 await server.initialize();
483 const res = await server.inject({
484 url: '/graphql',
485 method: 'post',
486 payload: { query: `query { metadata(machine: "${machine.id}") { name value } }` }
487 });
488 expect(res.statusCode).to.equal(200);
489 expect(res.result.data.metadata.length).to.equal(3);
490 expect(res.result.data.metadata[0].name).to.equal('foo');
491 });
492
493 it('can get an individual metadata value', async () => {
494 const server = new Hapi.Server();
495 StandIn.replaceOnce(CloudApi.prototype, 'fetch', (stand) => {
496 return 'bar';
497 });
498
499 await server.register(register);
500 await server.initialize();
501 const res = await server.inject({
502 url: '/graphql',
503 method: 'post',
504 payload: { query: `query { metadataValue(machine: "${machine.id}", name: "foo") { name value } }` }
505 });
506 expect(res.statusCode).to.equal(200);
507 expect(res.result.data.metadataValue.name).to.equal('foo');
508 expect(res.result.data.metadataValue.value).to.equal('bar');
509 });
510 });
511});