1import {dialog, invoke} from "@tauri-apps/api"; 2import JSON2XML from "./json2xml" 3import {OpenDialogOptions} from "@tauri-apps/api/dialog"; 4import _ from "lodash"; 5import {vueUtils} from "@lljj/vue3-form-naive"; 6 7function all(arr: boolean[]): boolean { 8 return arr.every(element => element === true); 9} 10 11function count(source, target) { 12 return (source.match(new RegExp(target, 'g')) || []).length; 13} 14 15 16declare global { 17 interface Window { 18 configurator: Configurator; 19 getSchemaData: () => any; 20 getCurrentScenarioData: () => any; 21 getBoardData: () => any; 22 pyodide: { 23 pyimport: (name: string) => { main: (...any) => any }, 24 runPython: (code: string) => string 25 }; 26 } 27} 28 29enum HistoryTypeEnum { 30 WorkingFolder, 31 Board, 32 Scenario 33} 34 35export type HistoryTypes = keyof typeof HistoryTypeEnum; 36 37 38enum PolicyTypeEnum { 39 Unified, 40 Code, 41 Data 42} 43 44type PolicyType = keyof typeof PolicyTypeEnum 45 46type Policy = { 47 VM: string, 48 VCPU: number, 49 TYPE: PolicyType, 50 CLOS_MASK: string 51} 52 53type CATDBRecord = { 54 CACHE_LEVEL: number, 55 CACHE_ID: string, 56 META: { vmid: number }, 57 VM: string, 58 VCPU: number, 59 TYPE: PolicyType, 60 CLOS_MASK: string 61} 62 63type CATUIDataObject = { 64 errorMsg: string, 65 regions: { 66 level: number, 67 id: string, 68 capacity_mask_length: number, 69 type: string, 70 cache_size: number, 71 processors: number[], 72 data: { 73 RTCore: Policy[], 74 Standard: Policy[], 75 VCAT: Policy[], 76 }, 77 }[], 78 summary: { 79 [CATRegionLevel: string]: { 80 count: number, 81 [CATRegionID: string]: number 82 } 83 } 84} 85 86 87type vmID = number; 88 89class CAT { 90 private scenario: any; 91 private schemaData: any; 92 private CAT_REGION_INFO: any; 93 94 private switches: { 95 RDT_ENABLED: boolean, 96 CDP_ENABLED: boolean, 97 VCAT_ENABLED: boolean 98 }; 99 100 private preLaunchedVMCPUs: string[]; 101 private serviceVM: any; 102 private serviceVMCPUs: string[]; 103 104 public CATDB: CATDBRecord[]; 105 private vmIDs: { [vmName: string]: vmID }; 106 107 hexToRange(hexValue, maxValue) { 108 let str_bin = Number.parseInt(hexValue).toString(2); 109 let block_length = str_bin.length; 110 let block_enabled_length = count(str_bin, "1"); 111 112 let start: number 113 let end: number 114 115 if (block_length > maxValue) { 116 if (block_enabled_length >= maxValue) { 117 str_bin = "1".repeat(maxValue); 118 } else { 119 str_bin = "0".repeat(maxValue - block_enabled_length) + "1".repeat(block_enabled_length); 120 } 121 } else { 122 if (block_length < maxValue) { 123 str_bin = "0".repeat(maxValue - block_length) + str_bin; 124 } 125 } 126 127 start = str_bin.indexOf("1") !== -1 ? str_bin.indexOf("1") : 0; 128 end = start + count(str_bin, "1"); 129 130 return [start, end] 131 } 132 133 rangeToHex(value, max) { 134 let newHexValue = '0'.repeat(value[0]) + '1'.repeat(value[1] - value[0]) + '0'.repeat(max - value[1]) 135 newHexValue = (parseInt(newHexValue, 2).toString(16)) 136 let zeroPadding = '0'.repeat(Number.parseInt('1'.repeat(max), 2).toString(16).length - newHexValue.length) 137 newHexValue = '0x' + zeroPadding + newHexValue; 138 return newHexValue; 139 } 140 141 formDataProxy(name, data = null, update = false) { 142 let path = { 143 'RDT_ENABLED': 'FEATURES.RDT.RDT_ENABLED', 144 'CDP_ENABLED': 'FEATURES.RDT.CDP_ENABLED', 145 'VCAT_ENABLED': 'FEATURES.RDT.VCAT_ENABLED', 146 }[name] 147 148 // check parent node exists 149 let oldValue = vueUtils.getPathVal(this.scenario.hv, path); 150 if (oldValue === undefined) { 151 let t = path.split('.'); 152 let parentPath = t.splice(0, t.length - 1).join('.'); 153 if (!vueUtils.getPathVal(this.scenario.hv, parentPath)) { 154 vueUtils.setPathVal(this.scenario.hv, parentPath, {}); 155 } 156 // set to checkbox default value 157 vueUtils.setPathVal(this.scenario.hv, path, 'n'); 158 } 159 // if data is not empty, set value 160 if (data !== null) { 161 vueUtils.setPathVal(this.scenario.hv, path, data) 162 163 // if data is not empty, set value as expected and update CAT_INFO 164 if (update) { 165 switch (name) { 166 case 'RDT_ENABLED': 167 if (data === 'n') { 168 this.formDataProxy('CDP_ENABLED', 'n'); 169 this.formDataProxy('VCAT_ENABLED', 'n'); 170 } 171 break; 172 case 'CDP_ENABLED': 173 if (data === 'y') { 174 this.formDataProxy('RDT_ENABLED', 'y'); 175 this.formDataProxy('VCAT_ENABLED', 'n'); 176 } 177 break; 178 case 'VCAT_ENABLED': 179 if (data === 'y') { 180 this.formDataProxy('RDT_ENABLED', 'y'); 181 this.formDataProxy('CDP_ENABLED', 'n'); 182 } 183 break; 184 } 185 } 186 } 187 let result: string; 188 // @ts-ignore 189 result = vueUtils.getPathVal(this.scenario.hv, path); 190 if (typeof result !== 'string') { 191 console.log(`Unexpected result of ${name}: `, result) 192 } 193 return result 194 } 195 196 197 scenarioLoaded() { 198 // get CAT schema && scenario data 199 this.schemaData = window.getSchemaData(); 200 this.scenario = window.getCurrentScenarioData(); 201 this.vmIDs = this.getVMIDs() 202 // get cat scenario data 203 this.CATDB = this.getCATDataFromScenario(); 204 } 205 206 getScenarioDataFromCAT() { 207 let CATUIData = this.getCATUIData(); 208 let ScenarioCATData: { 209 CACHE_ALLOCATION: { 210 CACHE_ID: string, 211 CACHE_LEVEL: number, 212 POLICY: Policy[] 213 }[] 214 } 215 if (CATUIData.regions.length === 0) { 216 return null; 217 } 218 ScenarioCATData = {CACHE_ALLOCATION: []} 219 for (const region of CATUIData.regions) { 220 let policies: Policy[] = region.data.RTCore.concat(region.data.Standard, region.data.VCAT); 221 ScenarioCATData.CACHE_ALLOCATION.push({ 222 CACHE_ID: region.id, 223 CACHE_LEVEL: region.level, 224 POLICY: policies 225 }) 226 } 227 return ScenarioCATData; 228 } 229 230 231 getCATUIData(): CATUIDataObject { 232 // get CAT schema && scenario && board basic data 233 this.schemaData = window.getSchemaData(); 234 this.scenario = window.getCurrentScenarioData(); 235 this.CAT_REGION_INFO = window.getBoardData().CAT_INFO; 236 237 // check scenario data is empty 238 // usually, this happens when user has no scenario loaded, then import a board 239 if (!this.scenario.hv) { 240 return null; 241 } 242 243 244 // get switches status from scenario 245 // @ts-ignore 246 this.switches = new Proxy({}, { 247 get: (target: {}, switchName: string | symbol): any => { 248 return this.formDataProxy(switchName) === 'y' 249 }, 250 set: (target: {}, switchName: string | symbol, value: boolean): boolean => { 251 return this.formDataProxy(switchName, value ? 'y' : 'n', true) === 'y'; 252 } 253 }) 254 255 256 // if no CAT REGION INFO from board xml, 257 // means this board(or CPU) not support CAT, or all support CAT region only have one CPU core 258 if (this.CAT_REGION_INFO.length === 0) { 259 let errorMsg = `This board(or CPU) doesn't support CAT which means there is no any CAT capability.</br>There is no Cache Region was shared which means \"all support CAT region only have one CPU core\".`; 260 console.log(errorMsg); 261 return { 262 errorMsg, 263 regions: [], 264 summary: {} 265 }; 266 } 267 268 // correct switches and return rdt_enabled result 269 if (!this.correctSwitches()) { 270 return { 271 errorMsg: '', 272 regions: [], 273 summary: {} 274 } 275 } 276 277 278 // CPU affinity data checks 279 // If error, only show error message 280 let errorMsg = this.checkCPUAffinity() 281 282 283 // get CPU data 284 this.preLaunchedVMCPUs = this.getPreLaunchedVMCPUs(); 285 this.serviceVM = this.getServiceVM(); 286 this.serviceVMCPUs = this.getServiceVMVCPUs() 287 this.vmIDs = this.getVMIDs() 288 289 290 let CATUIData: CATUIDataObject = { 291 errorMsg, regions: [], summary: {} 292 }; 293 // mapping CAT region info 294 this.CAT_REGION_INFO.map(region => { 295 let regionData = _.cloneDeep(region); 296 if (!CATUIData.summary.hasOwnProperty(regionData.level)) { 297 CATUIData.summary[regionData.level] = {count: 0} 298 } 299 CATUIData.summary[regionData.level].count++; 300 CATUIData.summary[regionData.level][regionData.id] = CATUIData.summary[regionData.level].count; 301 302 regionData['data'] = { 303 RTCore: this.getRTCoreData(regionData), 304 Standard: this.getStandardData(regionData), 305 VCAT: this.getVCATData(regionData) 306 } 307 CATUIData.regions.push(regionData); 308 }) 309 310 311 return CATUIData 312 } 313 314 haveCPUAffinity(vmConfig) { 315 if (vmConfig.load_order === 'SERVICE_VM') { 316 return false 317 } 318 return ( 319 vmConfig.hasOwnProperty('cpu_affinity') && 320 vmConfig.cpu_affinity.hasOwnProperty('pcpu') && 321 _.isArray(vmConfig.cpu_affinity.pcpu) 322 ) 323 } 324 325 checkCPUAffinity() { 326 // check cpu affinity 327 let errMsg = ['CPU affinity is not set for the following VMs:']; 328 let result = all(this.scenario.vm.map(vmConfig => { 329 if (vmConfig.load_order === 'SERVICE_VM') { 330 return true 331 } 332 let haveCPUAffinitySetting = this.haveCPUAffinity(vmConfig); 333 if (!haveCPUAffinitySetting) { 334 errMsg.push(`VM ${vmConfig.name} has no CPU affinity setting`); 335 } 336 return haveCPUAffinitySetting; 337 })) 338 if (result) { 339 return ''; 340 } 341 errMsg.push('Please set CPU affinity for all VMs'); 342 return errMsg.join('\n') 343 } 344 345 correctSwitches() { 346 if (this.switches.RDT_ENABLED) { 347 if (this.switches.CDP_ENABLED) { 348 if (this.switches.VCAT_ENABLED) { 349 this.switches.VCAT_ENABLED = false 350 } 351 } 352 } else if (this.switches.VCAT_ENABLED) { 353 if (!this.switches.RDT_ENABLED) { 354 this.switches.RDT_ENABLED = true 355 } 356 } 357 return this.switches.RDT_ENABLED 358 } 359 360 getPreLaunchedVMCPUs() { 361 let preLaunchedVMCPUs = []; 362 363 this.scenario.vm.map(vmConfig => { 364 if (vmConfig.load_order === 'PRE_LAUNCHED_VM' && this.haveCPUAffinity(vmConfig)) { 365 let vmCPUIDs = vmConfig.cpu_affinity.pcpu.map(pcpu => { 366 return pcpu.pcpu_id; 367 }) 368 preLaunchedVMCPUs.concat(vmCPUIDs) 369 } 370 }) 371 372 return preLaunchedVMCPUs; 373 } 374 375 newPolicy(CACHE_ID, CACHE_LEVEL, vmConfig, VCPU, TYPE: PolicyType, maxLength): Policy { 376 let originPolicy = { 377 VM: vmConfig.name, 378 VCPU, TYPE, 379 CLOS_MASK: this.getCLOSMask(CACHE_ID, CACHE_LEVEL, vmConfig['@id'], vmConfig.name, VCPU, TYPE, maxLength) 380 } 381 return new Proxy(originPolicy, { 382 set: (target, key, value) => { 383 target[key] = value; 384 if (key === 'CLOS_MASK') { 385 console.log(`${CACHE_ID} ${CACHE_LEVEL} ${vmConfig.name} ${VCPU} ${TYPE} CLOS_MASK: ${value}`); 386 this.setCLOSMask(CACHE_ID, CACHE_LEVEL, vmConfig['@id'], vmConfig.name, VCPU, TYPE, value); 387 } 388 return true; 389 } 390 }) 391 } 392 393 selectCATData(CACHE_ID, CACHE_LEVEL, vmID, vmName, VCPU, TYPE: PolicyType) { 394 for (let i = 0; i < this.CATDB.length; i++) { 395 let CATData = this.CATDB[i]; 396 if ( 397 CATData.CACHE_ID === CACHE_ID && CATData.CACHE_LEVEL === CACHE_LEVEL && 398 CATData.META.vmid === vmID && CATData.VCPU === VCPU && CATData.TYPE === TYPE 399 ) { 400 return CATData 401 } 402 } 403 return false; 404 } 405 406 setCLOSMask(CACHE_ID, CACHE_LEVEL, vmID, vmName, VCPU, TYPE: PolicyType, CLOS_MASK: string) { 407 let CATData = this.selectCATData(CACHE_ID, CACHE_LEVEL, vmID, vmName, VCPU, TYPE); 408 if (CATData !== false) { 409 CATData.CLOS_MASK = CLOS_MASK; 410 return true; 411 } 412 413 this.CATDB.push({ 414 META: {vmid: vmID}, 415 CACHE_ID, CACHE_LEVEL, 416 CLOS_MASK, 417 VM: vmName, VCPU, TYPE, 418 }) 419 return true; 420 } 421 422 getCLOSMask(CACHE_ID, CACHE_LEVEL, vmID, vmName, VCPU, TYPE: PolicyType, maxLength: number) { 423 let CATData = this.selectCATData(CACHE_ID, CACHE_LEVEL, vmID, vmName, VCPU, TYPE); 424 let CLOS_MASK 425 if (CATData !== false) { 426 CLOS_MASK = CATData.CLOS_MASK; 427 // ensure CLOS_MASK length is shorter or equal to maxLength 428 CLOS_MASK = this.rangeToHex(this.hexToRange(CLOS_MASK, maxLength), maxLength); 429 return CLOS_MASK; 430 } else CLOS_MASK = "0x" + parseInt('1'.repeat(maxLength), 2).toString(16) 431 this.CATDB.push({ 432 META: {vmid: vmID}, 433 CACHE_ID, CACHE_LEVEL, 434 CLOS_MASK, 435 VM: vmName, VCPU, TYPE, 436 }) 437 return CLOS_MASK; 438 } 439 440 getRTCoreData(regionData): Policy[] { 441 let RTCoreData: Policy[] = []; 442 this.scenario.vm.map(vmConfig => { 443 if (vmConfig.vm_type === 'RTVM' && this.haveCPUAffinity(vmConfig)) { 444 vmConfig.cpu_affinity.pcpu.map( 445 (pcpu, index) => { 446 if ( 447 regionData.processors.indexOf(pcpu.pcpu_id) !== -1 && 448 pcpu.hasOwnProperty('real_time_vcpu') && 449 pcpu.real_time_vcpu === 'y' 450 ) { 451 if (!this.switches.CDP_ENABLED) { 452 RTCoreData.push(this.newPolicy(regionData.id, regionData.level, vmConfig, index, 'Unified', regionData.capacity_mask_length)) 453 } else { 454 RTCoreData.push(this.newPolicy(regionData.id, regionData.level, vmConfig, index, 'Code', regionData.capacity_mask_length)) 455 RTCoreData.push(this.newPolicy(regionData.id, regionData.level, vmConfig, index, 'Data', regionData.capacity_mask_length)) 456 } 457 } 458 } 459 ) 460 } 461 }) 462 463 _.sortBy(RTCoreData, ['VM', 'VCPU', 'TYPE']); 464 465 return RTCoreData; 466 } 467 468 469 getStandardData(regionData): Policy[] { 470 let StandardData: Policy[] = []; 471 this.scenario.vm.map(vmConfig => { 472 if (this.haveCPUAffinity(vmConfig)) { 473 vmConfig.cpu_affinity.pcpu.map( 474 (pcpu, index) => { 475 if (regionData.processors.indexOf(pcpu.pcpu_id) !== -1) { 476 if (!pcpu.hasOwnProperty('real_time_vcpu') || 477 (pcpu.real_time_vcpu === 'n') || 478 (pcpu.real_time_vcpu === 'y' && vmConfig.vm_type !== 'RTVM') 479 ) { 480 if (!this.switches.CDP_ENABLED) { 481 StandardData.push(this.newPolicy( regionData.id, regionData.level,vmConfig, index, 'Unified', regionData.capacity_mask_length)) 482 } else { 483 StandardData.push(this.newPolicy(regionData.id, regionData.level, vmConfig, index, "Code", regionData.capacity_mask_length)) 484 StandardData.push(this.newPolicy( regionData.id, regionData.level,vmConfig, index, "Data", regionData.capacity_mask_length)) 485 } 486 } 487 } 488 }) 489 } 490 }) 491 492 // add service vm policy 493 StandardData = StandardData.concat( 494 this.getServiceData(regionData), 495 ) 496 497 _.sortBy(StandardData, ['VM', 'VCPU', 'TYPE']); 498 return StandardData; 499 } 500 501 getServiceData(regionData): Policy[] { 502 let ServiceData: Policy[] = []; 503 504 this.serviceVMCPUs.map((pcpuID, index) => { 505 if (regionData.processors.indexOf(pcpuID) !== -1) { 506 if (!this.switches.CDP_ENABLED) { 507 ServiceData.push(this.newPolicy(regionData.id, regionData.level, this.serviceVM, index, "Unified", regionData.capacity_mask_length)) 508 } else { 509 ServiceData.push(this.newPolicy(regionData.id, regionData.level, this.serviceVM, index, "Code", regionData.capacity_mask_length)) 510 ServiceData.push(this.newPolicy(regionData.id, regionData.level, this.serviceVM, index, "Data", regionData.capacity_mask_length)) 511 } 512 } 513 }) 514 return ServiceData; 515 } 516 517 getVCATData(regionData): Policy[] { 518 let VCATData: Policy[] = []; 519 // VCAT is only available for CPU 0 520 if (this.switches.VCAT_ENABLED && regionData.processors.indexOf(0) !== -1) { 521 this.scenario.vm.map(vmConfig => { 522 if ( 523 this.haveCPUAffinity(vmConfig) && 524 vmConfig.hasOwnProperty('virtual_cat_support') && 525 vmConfig.virtual_cat_support === "y" 526 ) { 527 VCATData.push( 528 this.newPolicy(regionData.id, regionData.level, vmConfig, 0, "Unified", vmConfig.virtual_cat_number) 529 ) 530 } 531 }) 532 } 533 _.sortBy(VCATData, ['VM']); 534 return VCATData; 535 } 536 537 private getServiceVM() { 538 let serviceVM = null; 539 this.scenario.vm.map(vmConfig => { 540 if (vmConfig.load_order === 'SERVICE_VM') { 541 serviceVM = vmConfig; 542 } 543 }) 544 return serviceVM; 545 } 546 547 private getServiceVMVCPUs() { 548 let serviceVMCPUs = []; 549 if (this.serviceVM !== null) { 550 // noinspection JSUnresolvedVariable 551 this.schemaData.HV.BasicConfigType.definitions.CPUAffinityConfiguration.properties.pcpu_id.enum.map((pcpu_id) => { 552 // if pcpu_id in preLaunchedVMCPUIDs, it's used by pre launched vm, we need skip it 553 if (this.preLaunchedVMCPUs.indexOf(pcpu_id) !== -1) { 554 return; 555 } 556 serviceVMCPUs.push(pcpu_id); 557 }) 558 } 559 return serviceVMCPUs; 560 } 561 562 563 private getCATDataFromScenario() { 564 let hv = this.scenario.hv; 565 566 let scenarioCATData: CATDBRecord[] = [] 567 // noinspection JSUnresolvedVariable 568 if ( 569 hv !== null && 570 hv.hasOwnProperty('CACHE_REGION') 571 ) { 572 let cacheRegion = hv.CACHE_REGION 573 if (cacheRegion !== null && cacheRegion.hasOwnProperty('CACHE_ALLOCATION') && 574 _.isArray(cacheRegion.CACHE_ALLOCATION)) { 575 // noinspection JSUnresolvedVariable 576 577 cacheRegion.CACHE_ALLOCATION.map((cache_allocation) => { 578 if ( 579 cache_allocation.hasOwnProperty('POLICY') && 580 cache_allocation.POLICY.length > 0 581 ) { 582 cache_allocation.POLICY.map(policy => { 583 scenarioCATData.push({ 584 CACHE_ID: cache_allocation.CACHE_ID, 585 CACHE_LEVEL: cache_allocation.CACHE_LEVEL, 586 CLOS_MASK: policy.CLOS_MASK, 587 META: {vmid: this.vmIDs[policy.VM]}, 588 TYPE: policy.TYPE, 589 VCPU: policy.VCPU, 590 VM: policy.VM 591 }) 592 }) 593 } 594 595 }) 596 597 } 598 } 599 return scenarioCATData 600 } 601 602 private getVMIDs(): { [vmName: string]: vmID } { 603 let vmIDs = {} 604 this.scenario.vm.map(vmConfig => { 605 vmIDs[vmConfig.name] = vmConfig['@id'] 606 }) 607 return vmIDs 608 } 609} 610 611class PythonObject { 612 api(scriptName, output_format, ...params) { 613 let pythonFunction = window.pyodide.pyimport(`configurator.pyodide.${scriptName}`); 614 let result = pythonFunction.main(...params); 615 if (output_format === 'json') { 616 return JSON.parse(result); 617 } else { 618 return result; 619 } 620 } 621 622 loadBoard(boardXMLText, path) { 623 return this.api('loadBoard', 'json', boardXMLText, path) 624 625 } 626 627 loadScenario(scenarioXMLText) { 628 return this.api('loadScenario', 'json', scenarioXMLText) 629 } 630 631 validateBoardStructure(boardXMLText) { 632 return this.api('validateBoardStructure', 'plaintext', boardXMLText) 633 } 634 635 validateScenarioStructure(scenarioXMLText) { 636 return this.api('validateScenarioStructure', 'plaintext', scenarioXMLText) 637 } 638 639 validateScenario(boardXMLText, scenarioXMLText) { 640 return this.api('validateScenario', 'json', boardXMLText, scenarioXMLText) 641 } 642 643 generateLaunchScript(boardXMLText, scenarioXMLText) { 644 return this.api('generateLaunchScript', 'json', boardXMLText, scenarioXMLText) 645 } 646 647 populateDefaultValues(scenarioXMLText) { 648 return this.api('populateDefaultValues', 'json', scenarioXMLText) 649 } 650 651 generateConfigSummary(boardXMLText, scenarioXMLText) { 652 return this.api('generateConfigSummary', 'plaintext', boardXMLText, scenarioXMLText) 653 } 654 655 updateSchema(boardXMLText, scenarioXMLText) { 656 return this.api('updateSchema', 'plaintext', boardXMLText, scenarioXMLText) 657 } 658} 659 660class Configurator { 661 public pythonObject: PythonObject; 662 public cat: CAT; 663 664 constructor() { 665 this.pythonObject = new PythonObject() 666 this.cat = new CAT() 667 } 668 669 getHistory(historyType: HistoryTypes): Promise<String[] | []> { 670 return invoke("get_history", {historyType}) 671 .then((historyJsonText) => { 672 if (typeof historyJsonText === "string") { 673 return JSON.parse(historyJsonText); 674 } 675 return []; 676 }) 677 } 678 679 addHistory(historyType: HistoryTypes, historyPath: string) { 680 return invoke("add_history", {historyType, historyPath}) 681 } 682 683 openDialog(options: OpenDialogOptions) { 684 return dialog.open(options) 685 } 686 687 readFile(filePath: string): Promise<String> { 688 return invoke("acrn_read", {filePath}) 689 } 690 691 writeFile(filePath: string, contents: string) { 692 return invoke("acrn_write", {filePath, contents}) 693 } 694 695 isFile(filePath: string): Promise<Boolean> { 696 return invoke("acrn_is_file", {path: filePath}) 697 } 698 699 readDir(path: string, recursive: Boolean) { 700 return invoke('acrn_read_dir', {path, recursive}) 701 } 702 703 creatDir(path: string, recursive = true) { 704 return invoke('acrn_create_dir', {path, recursive}) 705 } 706 707 removeDir(path: string) { 708 return invoke('acrn_remove_dir', {path}) 709 } 710 711 removeFile(path: string) { 712 return invoke('acrn_remove_file', {path}) 713 } 714 715 runPython(code: string, isJSON = false): string | Object { 716 let result = window.pyodide.runPython(code); 717 if (isJSON) { 718 result = JSON.parse(result) 719 } 720 return result 721 } 722 723 loadBoard(path: string) { 724 return this.readFile(path) 725 .then((fileContent) => { 726 let syntactical_errors = this.pythonObject.validateBoardStructure(fileContent); 727 if (syntactical_errors !== "") { 728 throw Error("The file has broken structure."); 729 } 730 return this.pythonObject.loadBoard(fileContent, path); 731 }) 732 } 733 734 loadScenario(path: string): Object { 735 return this.readFile(path).then((fileContent) => { 736 let syntactical_errors = this.pythonObject.validateScenarioStructure(fileContent); 737 if (syntactical_errors !== "") { 738 throw Error("The loaded file does not look like a valid ACRN scenario XML.\n\n" + 739 "If that file is used with ACRN 2.x, try upgrading it following the instructions at https://projectacrn.github.io/latest/tutorials/upgrading_configuration.html.\n"); 740 } 741 return this.pythonObject.loadScenario(fileContent) 742 }) 743 } 744 745 newVM(vmid, load_order) { 746 let newVMData = { 747 '@id': vmid, 748 load_order: load_order, 749 name: `VM${vmid}`, 750 cpu_affinity: null 751 } 752 if (load_order !== 'SERVICE_VM') { 753 newVMData['cpu_affinity'] = { 754 pcpu: [ 755 { 756 pcpu_id: null, 757 real_time_vcpu: 'n' 758 } 759 ] 760 } 761 } 762 return newVMData 763 } 764 765 createNewScenario(pre, service, post) { 766 let newScenario = { 767 hv: {}, 768 vm: [] 769 } 770 let vmid = 0 771 let vmNums = {'PRE_LAUNCHED_VM': pre, 'SERVICE_VM': service, 'POST_LAUNCHED_VM': post} 772 for (let key in vmNums) { 773 for (let i = 0; i < vmNums[key]; i++) { 774 newScenario.vm.push(this.newVM(vmid, key)) 775 vmid++; 776 } 777 } 778 return newScenario; 779 } 780 781 convertScenarioToXML(scenarioData: Object) { 782 let json2xml = new JSON2XML(); 783 return json2xml.convert(scenarioData) 784 } 785 786} 787 788let configurator = new Configurator() 789 790window.configurator = configurator 791export default configurator 792