github.com/hernad/nomad@v1.6.112/ui/mirage/scenarios/default.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 import { assign } from '@ember/polyfills'; 7 import config from 'nomad-ui/config/environment'; 8 import * as topoScenarios from './topo'; 9 import * as sysbatchScenarios from './sysbatch'; 10 import { pickOne } from '../utils'; 11 import faker from 'nomad-ui/mirage/faker'; 12 13 const withNamespaces = getConfigValue('mirageWithNamespaces', false); 14 const withTokens = getConfigValue('mirageWithTokens', true); 15 const withRegions = getConfigValue('mirageWithRegions', false); 16 17 export const allScenarios = { 18 smallCluster, 19 mediumCluster, 20 largeCluster, 21 massiveCluster, 22 allJobTypes, 23 allNodeTypes, 24 everyFeature, 25 emptyCluster, 26 variableTestCluster, 27 servicesTestCluster, 28 policiesTestCluster, 29 ...topoScenarios, 30 ...sysbatchScenarios, 31 }; 32 33 export const scenario = 34 getScenarioQueryParameter() || 35 getConfigValue('mirageScenario', 'emptyCluster'); 36 37 export default function (server) { 38 const activeScenario = allScenarios[scenario]; 39 if (!activeScenario) { 40 throw new Error( 41 `Selected Mirage scenario does not exist.\n\n${scenario} not in list: \n\n\t${Object.keys( 42 allScenarios 43 ).join('\n\t')}` 44 ); 45 } 46 47 // Make sure built-in node pools exist. 48 createBuiltInNodePools(server); 49 if (withNamespaces) createNamespaces(server); 50 if (withTokens) createTokens(server); 51 if (withRegions) createRegions(server); 52 53 activeScenario(server); 54 } 55 56 // Scenarios 57 58 function smallCluster(server) { 59 faker.seed(1); 60 server.create('feature', { name: 'Dynamic Application Sizing' }); 61 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 62 server.createList('node-pool', 2); 63 server.createList('node', 5); 64 server.create( 65 'node', 66 { 67 name: 'node-with-meta', 68 meta: { foo: 'bar', baz: 'qux' }, 69 }, 70 'withMeta' 71 ); 72 server.createList('job', 1, { createRecommendations: true }); 73 server.create('job', { 74 withGroupServices: true, 75 withTaskServices: true, 76 name: 'Service-haver', 77 id: 'service-haver', 78 namespaceId: 'default', 79 }); 80 server.create('job', { 81 createAllocations: true, 82 groupTaskCount: 150, 83 shallow: true, 84 allocStatusDistribution: { 85 running: 0.5, 86 failed: 0.05, 87 unknown: 0.2, 88 lost: 0.1, 89 complete: 0.1, 90 pending: 0.05, 91 }, 92 name: 'mixed-alloc-job', 93 id: 'mixed-alloc-job', 94 namespaceId: 'default', 95 type: 'service', 96 activeDeployment: true, 97 }); 98 99 //#region Active Deployment 100 101 const activelyDeployingJobGroups = 2; 102 const activelyDeployingTasksPerGroup = 100; 103 104 const activelyDeployingJob = server.create('job', { 105 createAllocations: true, 106 groupTaskCount: activelyDeployingTasksPerGroup, 107 shallow: true, 108 resourceSpec: Array(activelyDeployingJobGroups).fill(['M: 257, C: 500']), 109 noDeployments: true, // manually created below 110 activeDeployment: true, 111 allocStatusDistribution: { 112 running: 0.6, 113 failed: 0.05, 114 unknown: 0.05, 115 lost: 0, 116 complete: 0, 117 pending: 0.3, 118 }, 119 name: 'actively-deploying-job', 120 id: 'actively-deploying-job', 121 namespaceId: 'default', 122 type: 'service', 123 }); 124 125 server.create('deployment', false, 'active', { 126 jobId: activelyDeployingJob.id, 127 groupDesiredTotal: activelyDeployingTasksPerGroup, 128 versionNumber: 1, 129 status: 'running', 130 }); 131 server.createList('allocation', 25, { 132 jobId: activelyDeployingJob.id, 133 jobVersion: 0, 134 clientStatus: 'running', 135 }); 136 137 // Manipulate the above job to show a nice distribution of running, canary, etc. allocs 138 let activelyDeployingJobAllocs = server.schema.allocations 139 .all() 140 .filter((a) => a.jobId === activelyDeployingJob.id); 141 activelyDeployingJobAllocs.models 142 .filter((a) => a.clientStatus === 'running') 143 .slice(0, 10) 144 .forEach((a) => 145 a.update({ deploymentStatus: { Healthy: false, Canary: true } }) 146 ); 147 activelyDeployingJobAllocs.models 148 .filter((a) => a.clientStatus === 'running') 149 .slice(10, 20) 150 .forEach((a) => 151 a.update({ deploymentStatus: { Healthy: true, Canary: true } }) 152 ); 153 activelyDeployingJobAllocs.models 154 .filter((a) => a.clientStatus === 'running') 155 .slice(20, 65) 156 .forEach((a) => 157 a.update({ deploymentStatus: { Healthy: true, Canary: false } }) 158 ); 159 activelyDeployingJobAllocs.models 160 .filter((a) => a.clientStatus === 'pending') 161 .slice(0, 10) 162 .forEach((a) => 163 a.update({ deploymentStatus: { Healthy: true, Canary: true } }) 164 ); 165 activelyDeployingJobAllocs.models 166 .filter((a) => a.clientStatus === 'failed') 167 .slice(0, 5) 168 .forEach((a) => 169 a.update({ deploymentStatus: { Healthy: true, Canary: false } }) 170 ); 171 172 //#endregion Active Deployment 173 174 server.create('job', { 175 name: 'hcl-definition-job', 176 id: 'display-hcl', 177 namespaceId: 'default', 178 }); 179 server.createList('allocFile', 5); 180 server.create('allocFile', 'dir', { depth: 2 }); 181 server.createList('csi-plugin', 2); 182 server.createList('variable', 3); 183 184 const variableLinkedJob = server.db.jobs[0]; 185 const variableLinkedGroup = server.db.taskGroups.findBy({ 186 jobId: variableLinkedJob.id, 187 }); 188 const variableLinkedTask = server.db.tasks.findBy({ 189 taskGroupId: variableLinkedGroup.id, 190 }); 191 [ 192 'a/b/c/foo0', 193 'a/b/c/bar1', 194 'a/b/c/d/e/foo2', 195 'a/b/c/d/e/bar3', 196 'a/b/c/d/e/f/foo4', 197 'a/b/c/d/e/f/g/foo5', 198 'a/b/c/x/y/z/foo6', 199 'a/b/c/x/y/z/bar7', 200 'a/b/c/x/y/z/baz8', 201 'w/x/y/foo9', 202 'w/x/y/z/foo10', 203 'w/x/y/z/bar11', 204 'just some arbitrary file', 205 'another arbitrary file', 206 'another arbitrary file again', 207 ].forEach((path) => server.create('variable', { id: path })); 208 209 server.create('variable', { 210 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}/${variableLinkedTask.name}`, 211 namespace: variableLinkedJob.namespace, 212 }); 213 214 server.create('variable', { 215 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}`, 216 namespace: variableLinkedJob.namespace, 217 }); 218 219 server.create('variable', { 220 id: `nomad/jobs/${variableLinkedJob.id}`, 221 namespace: variableLinkedJob.namespace, 222 }); 223 224 const newJobName = 'new-job'; 225 const newJobTaskGroupName = 'redis'; 226 const jsonJob = (overrides) => { 227 return JSON.stringify( 228 assign( 229 {}, 230 { 231 Name: newJobName, 232 Namespace: 'default', 233 Datacenters: ['dc1'], 234 Priority: 50, 235 TaskGroups: [ 236 { 237 Name: newJobTaskGroupName, 238 Tasks: [ 239 { 240 Name: 'redis', 241 Driver: 'docker', 242 }, 243 ], 244 }, 245 ], 246 }, 247 overrides 248 ), 249 null, 250 2 251 ); 252 }; 253 254 server.create('variable', { 255 id: `nomad/job-templates/foo-bar`, 256 namespace: 'namespace-2', 257 Items: { 258 description: 'a description', 259 template: jsonJob(), 260 }, 261 }); 262 263 server.create('variable', { 264 id: `nomad/job-templates/baz-qud`, 265 namespace: 'default', 266 Items: { 267 description: 'another different description', 268 template: jsonJob(), 269 }, 270 }); 271 272 server.create('variable', { 273 id: 'Auto-conflicting Variable', 274 namespace: 'default', 275 }); 276 277 // #region evaluations 278 279 // Branching: a single eval that relates to N-1 mutually-unrelated evals 280 const NUM_BRANCHING_EVALUATIONS = 3; 281 Array(NUM_BRANCHING_EVALUATIONS) 282 .fill() 283 .map((_, i) => { 284 return { 285 evaluation: server.create('evaluation', { 286 id: `branching_${i}`, 287 previousEval: i > 0 ? `branching_0` : '', 288 jobID: pickOne(server.db.jobs).id, 289 }), 290 291 evaluationStub: server.create('evaluation-stub', { 292 id: `branching_${i}`, 293 previousEval: i > 0 ? `branching_0` : '', 294 status: 'failed', 295 }), 296 }; 297 }) 298 .map((x, i, all) => { 299 x.evaluation.update({ 300 relatedEvals: 301 i === 0 302 ? all.filter((_, j) => j !== 0).map((e) => e.evaluation) 303 : all.filter((_, j) => j !== i).map((e) => e.evaluation), 304 }); 305 return x; 306 }); 307 308 // Linear: a long line of N related evaluations 309 const NUM_LINEAR_EVALUATIONS = 20; 310 Array(NUM_LINEAR_EVALUATIONS) 311 .fill() 312 .map((_, i) => { 313 return { 314 evaluation: server.create('evaluation', { 315 id: `linear_${i}`, 316 previousEval: i > 0 ? `linear_${i - 1}` : '', 317 jobID: pickOne(server.db.jobs).id, 318 }), 319 320 evaluationStub: server.create('evaluation-stub', { 321 id: `linear_${i}`, 322 previousEval: i > 0 ? `linear_${i - 1}` : '', 323 nextEval: `linear_${i + 1}`, 324 status: 'failed', 325 }), 326 }; 327 }) 328 .map((x, i, all) => { 329 x.evaluation.update({ 330 relatedEvals: all.filter((_, j) => i !== j).map((e) => e.evaluation), 331 }); 332 return x; 333 }); 334 335 // #endregion evaluations 336 337 const csiAllocations = server.createList('allocation', 5); 338 const volumes = server.schema.csiVolumes.all().models; 339 csiAllocations.forEach((alloc) => { 340 const volume = pickOne(volumes); 341 volume.writeAllocs.add(alloc); 342 volume.readAllocs.add(alloc); 343 volume.save(); 344 }); 345 346 server.create('auth-method', { name: 'vault' }); 347 server.create('auth-method', { name: 'auth0' }); 348 server.create('auth-method', { name: 'cognito' }); 349 server.create('auth-method', { name: 'JWT-Local', type: 'JWT' }); 350 } 351 352 function mediumCluster(server) { 353 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 354 server.createList('node-pool', 5); 355 server.createList('node', 50); 356 server.createList('job', 25); 357 } 358 359 function variableTestCluster(server) { 360 faker.seed(1); 361 createTokens(server); 362 createNamespaces(server); 363 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 364 server.createList('node-pool', 3); 365 server.createList('node', 5); 366 server.createList('job', 3); 367 server.createList('variable', 3); 368 // server.createList('allocFile', 5); 369 // server.create('allocFile', 'dir', { depth: 2 }); 370 // server.createList('csi-plugin', 2); 371 372 const variableLinkedJob = server.db.jobs[0]; 373 const variableLinkedGroup = server.db.taskGroups.findBy({ 374 jobId: variableLinkedJob.id, 375 }); 376 const variableLinkedTask = server.db.tasks.findBy({ 377 taskGroupId: variableLinkedGroup.id, 378 }); 379 [ 380 'a/b/c/foo0', 381 'a/b/c/bar1', 382 'a/b/c/d/e/foo2', 383 'a/b/c/d/e/bar3', 384 'a/b/c/d/e/f/foo4', 385 'a/b/c/d/e/f/g/foo5', 386 'a/b/c/x/y/z/foo6', 387 'a/b/c/x/y/z/bar7', 388 'a/b/c/x/y/z/baz8', 389 'w/x/y/foo9', 390 'w/x/y/z/foo10', 391 'w/x/y/z/bar11', 392 ].forEach((path) => server.create('variable', { id: path })); 393 394 server.create('variable', { 395 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}/${variableLinkedTask.name}`, 396 namespace: variableLinkedJob.namespace, 397 }); 398 399 server.create('variable', { 400 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}`, 401 namespace: variableLinkedJob.namespace, 402 }); 403 404 server.create('variable', { 405 id: `nomad/jobs/${variableLinkedJob.id}`, 406 namespace: variableLinkedJob.namespace, 407 }); 408 409 server.create('variable', { 410 id: 'just some arbitrary file', 411 namespace: 'namespace-2', 412 }); 413 414 server.create('variable', { 415 id: 'another arbitrary file', 416 namespace: 'namespace-2', 417 }); 418 419 server.create('variable', { 420 id: 'another arbitrary file again', 421 namespace: 'namespace-2', 422 }); 423 424 server.create('variable', { 425 id: 'Auto-conflicting Variable', 426 namespace: 'default', 427 }); 428 } 429 430 function policiesTestCluster(server) { 431 faker.seed(1); 432 createTokens(server); 433 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 434 } 435 436 function servicesTestCluster(server) { 437 faker.seed(1); 438 server.create('feature', { name: 'Dynamic Application Sizing' }); 439 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 440 server.createList('node-pool', 3); 441 server.createList('node', 5); 442 server.createList('job', 1, { createRecommendations: true }); 443 server.create('job', { 444 withGroupServices: true, 445 withTaskServices: true, 446 name: 'Service-haver', 447 id: 'service-haver', 448 namespaceId: 'default', 449 }); 450 server.createList('allocFile', 5); 451 server.create('allocFile', 'dir', { depth: 2 }); 452 server.createList('csi-plugin', 2); 453 server.createList('variable', 3); 454 455 const variableLinkedJob = server.db.jobs[0]; 456 const variableLinkedGroup = server.db.taskGroups.findBy({ 457 jobId: variableLinkedJob.id, 458 }); 459 const variableLinkedTask = server.db.tasks.findBy({ 460 taskGroupId: variableLinkedGroup.id, 461 }); 462 [ 463 'a/b/c/foo0', 464 'a/b/c/bar1', 465 'a/b/c/d/e/foo2', 466 'a/b/c/d/e/bar3', 467 'a/b/c/d/e/f/foo4', 468 'a/b/c/d/e/f/g/foo5', 469 'a/b/c/x/y/z/foo6', 470 'a/b/c/x/y/z/bar7', 471 'a/b/c/x/y/z/baz8', 472 'w/x/y/foo9', 473 'w/x/y/z/foo10', 474 'w/x/y/z/bar11', 475 'just some arbitrary file', 476 'another arbitrary file', 477 'another arbitrary file again', 478 ].forEach((path) => server.create('variable', { id: path })); 479 480 server.create('variable', { 481 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}/${variableLinkedTask.name}`, 482 namespace: variableLinkedJob.namespace, 483 }); 484 485 server.create('variable', { 486 id: `nomad/jobs/${variableLinkedJob.id}/${variableLinkedGroup.name}`, 487 namespace: variableLinkedJob.namespace, 488 }); 489 490 server.create('variable', { 491 id: `nomad/jobs/${variableLinkedJob.id}`, 492 namespace: variableLinkedJob.namespace, 493 }); 494 495 server.create('variable', { 496 id: 'Auto-conflicting Variable', 497 namespace: 'default', 498 }); 499 500 // #region evaluations 501 502 // Branching: a single eval that relates to N-1 mutually-unrelated evals 503 const NUM_BRANCHING_EVALUATIONS = 3; 504 Array(NUM_BRANCHING_EVALUATIONS) 505 .fill() 506 .map((_, i) => { 507 return { 508 evaluation: server.create('evaluation', { 509 id: `branching_${i}`, 510 previousEval: i > 0 ? `branching_0` : '', 511 jobID: pickOne(server.db.jobs).id, 512 }), 513 514 evaluationStub: server.create('evaluation-stub', { 515 id: `branching_${i}`, 516 previousEval: i > 0 ? `branching_0` : '', 517 status: 'failed', 518 }), 519 }; 520 }) 521 .map((x, i, all) => { 522 x.evaluation.update({ 523 relatedEvals: 524 i === 0 525 ? all.filter((_, j) => j !== 0).map((e) => e.evaluation) 526 : all.filter((_, j) => j !== i).map((e) => e.evaluation), 527 }); 528 return x; 529 }); 530 531 // Linear: a long line of N related evaluations 532 const NUM_LINEAR_EVALUATIONS = 20; 533 Array(NUM_LINEAR_EVALUATIONS) 534 .fill() 535 .map((_, i) => { 536 return { 537 evaluation: server.create('evaluation', { 538 id: `linear_${i}`, 539 previousEval: i > 0 ? `linear_${i - 1}` : '', 540 jobID: pickOne(server.db.jobs).id, 541 }), 542 543 evaluationStub: server.create('evaluation-stub', { 544 id: `linear_${i}`, 545 previousEval: i > 0 ? `linear_${i - 1}` : '', 546 nextEval: `linear_${i + 1}`, 547 status: 'failed', 548 }), 549 }; 550 }) 551 .map((x, i, all) => { 552 x.evaluation.update({ 553 relatedEvals: all.filter((_, j) => i !== j).map((e) => e.evaluation), 554 }); 555 return x; 556 }); 557 558 // #endregion evaluations 559 560 const csiAllocations = server.createList('allocation', 5); 561 const volumes = server.schema.csiVolumes.all().models; 562 csiAllocations.forEach((alloc) => { 563 const volume = pickOne(volumes); 564 volume.writeAllocs.add(alloc); 565 volume.readAllocs.add(alloc); 566 volume.save(); 567 }); 568 } 569 570 // Due to Mirage performance, large cluster scenarios will be slow 571 function largeCluster(server) { 572 server.createList('agent', 5); 573 server.createList('node-pool', 10); 574 server.createList('node', 1000); 575 server.createList('job', 100); 576 } 577 578 function massiveCluster(server) { 579 server.createList('agent', 7); 580 server.createList('node-pool', 100); 581 server.createList('node', 5000); 582 server.createList('job', 2000); 583 } 584 585 function allJobTypes(server) { 586 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 587 server.createList('node', 5); 588 589 server.create('job', { type: 'service' }); 590 server.create('job', { type: 'batch' }); 591 server.create('job', { type: 'system' }); 592 server.create('job', 'periodic'); 593 server.create('job', 'parameterized'); 594 server.create('job', 'periodicSysbatch'); 595 server.create('job', 'parameterizedSysbatch'); 596 server.create('job', { failedPlacements: true }); 597 } 598 599 function allNodeTypes(server) { 600 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 601 602 server.create('node'); 603 server.create('node', 'forceIPv4'); 604 server.create('node', 'draining'); 605 server.create('node', 'forcedDraining'); 606 server.create('node', 'noDeadlineDraining'); 607 server.create('node', 'withMeta'); 608 609 server.createList('job', 3); 610 } 611 612 function everyFeature(server) { 613 server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); 614 server.createList('node-pool', 3); 615 616 server.create('node', 'forceIPv4'); 617 server.create('node', 'draining'); 618 server.create('node', 'forcedDraining'); 619 server.create('node', 'noDeadlineDraining'); 620 server.create('node', 'withMeta'); 621 622 const job1 = server.create('job', { 623 type: 'service', 624 activeDeployment: true, 625 namespaceId: 'default', 626 createAllocations: false, 627 }); 628 server.create('job', { 629 type: 'batch', 630 failedPlacements: true, 631 namespaceId: 'default', 632 }); 633 server.create('job', { type: 'system', namespaceId: 'default' }); 634 server.create('job', 'periodic', { namespaceId: 'default' }); 635 server.create('job', 'parameterized', { namespaceId: 'default' }); 636 637 server.create('allocation', 'rescheduled', { jobId: job1.id }); 638 server.create('allocation', 'preempter', { jobId: job1.id }); 639 server.create('allocation', 'preempted', { jobId: job1.id }); 640 } 641 642 function emptyCluster(server) { 643 server.create('agent'); 644 server.create('node'); 645 } 646 647 // Behaviors 648 649 function createBuiltInNodePools(server) { 650 server.create('node-pool', { name: 'default' }); 651 server.create('node-pool', { name: 'all' }); 652 } 653 654 function createTokens(server) { 655 server.createList('token', 3); 656 server.create('token', { 657 name: 'Secure McVariables', 658 id: '53cur3-v4r14bl35', 659 }); 660 server.create('token', { 661 name: "Safe O'Constants", 662 id: 'f3w3r-53cur3-v4r14bl35', 663 }); 664 server.create('token', { 665 name: 'Lazarus MacMarbh', 666 id: '3XP1R35-1N-3L3V3N-M1NU735', 667 }); 668 logTokens(server); 669 } 670 671 function createNamespaces(server) { 672 server.createList('namespace', 3); 673 } 674 675 function createRegions(server) { 676 ['americas', 'europe', 'asia', 'some-long-name-just-to-test'].forEach( 677 (id) => { 678 server.create('region', { id }); 679 } 680 ); 681 } 682 683 /* eslint-disable */ 684 function logTokens(server) { 685 console.log('TOKENS:'); 686 server.db.tokens.forEach((token) => { 687 console.log(` 688 Name: ${token.name} 689 Secret: ${token.secretId} 690 Accessor: ${token.accessorId} 691 692 `); 693 }); 694 695 console.log( 696 'Alternatively, log in with a JWT. If it ends with `management`, you have full access. If it ends with `bad`, you`ll get an error. Otherwise, you`ll get a token with limited access.' 697 ); 698 console.log('====================================='); 699 } 700 701 function getConfigValue(variableName, defaultValue) { 702 const value = config.APP[variableName]; 703 if (value !== undefined) return value; 704 705 console.warn( 706 `No ENV.APP value set for "${variableName}". Defaulting to "${defaultValue}". To set a custom value, modify config/environment.js` 707 ); 708 return defaultValue; 709 } 710 711 function getScenarioQueryParameter() { 712 const params = new URLSearchParams(window.location.search); 713 return params.get('mirage-scenario'); 714 } 715 /* eslint-enable */