-
Notifications
You must be signed in to change notification settings - Fork 318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NAS-128601 / 25.04 / Fixes the process to assign GPUs to VMs when creating or editing #10838
Changes from 9 commits
82b1d3e
dea62f4
356a387
897156c
48870e7
ac61d17
c95f3c4
22fcb21
13185c2
c86dc6c
085932b
332cb92
b4b175b
7674566
0bdb8a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
import { | ||
ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, | ||
signal, | ||
} from '@angular/core'; | ||
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; | ||
import { MatButton } from '@angular/material/button'; | ||
import { MatCard, MatCardContent } from '@angular/material/card'; | ||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; | ||
import { TranslateService, TranslateModule } from '@ngx-translate/core'; | ||
import { | ||
Observable, forkJoin, map, of, switchMap, | ||
Observable, forkJoin, of, switchMap, | ||
tap, | ||
} from 'rxjs'; | ||
import { MiB } from 'app/constants/bytes.constant'; | ||
import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; | ||
|
@@ -18,6 +20,7 @@ import { | |
import { choicesToOptions } from 'app/helpers/operators/options.operators'; | ||
import { mapToOptions } from 'app/helpers/options.helper'; | ||
import { helptextVmWizard } from 'app/helptext/vm/vm-wizard/vm-wizard'; | ||
import { Option } from 'app/interfaces/option.interface'; | ||
import { VirtualMachine, VirtualMachineUpdate } from 'app/interfaces/virtual-machine.interface'; | ||
import { VmPciPassthroughDevice } from 'app/interfaces/vm-device.interface'; | ||
import { DialogService } from 'app/modules/dialog/dialog.service'; | ||
|
@@ -96,12 +99,16 @@ export class VmEditFormComponent implements OnInit { | |
gpus: [[] as string[], [], [this.gpuValidator.validateGpu]], | ||
}); | ||
|
||
private readonly gpuOptions = signal<Option[]>([]); | ||
isLoading = false; | ||
timeOptions$ = of(mapToOptions(vmTimeNames, this.translate)); | ||
bootloaderOptions$ = this.ws.call('vm.bootloader_options').pipe(choicesToOptions()); | ||
cpuModeOptions$ = of(mapToOptions(vmCpuModeLabels, this.translate)); | ||
cpuModelOptions$ = this.ws.call('vm.cpu_model_choices').pipe(choicesToOptions()); | ||
gpuOptions$ = this.gpuService.getGpuOptions(); | ||
gpuOptions$ = this.ws.call('system.advanced.get_gpu_pci_choices').pipe( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
choicesToOptions(true), | ||
tap((options) => this.gpuOptions.set(options)), | ||
); | ||
|
||
readonly helptext = helptextVmWizard; | ||
|
||
|
@@ -163,20 +170,14 @@ export class VmEditFormComponent implements OnInit { | |
} | ||
|
||
const gpusIds = this.form.value.gpus; | ||
|
||
const pciIdsRequests$ = gpusIds.map((gpu) => { | ||
return this.ws.call('vm.device.get_pci_ids_for_gpu_isolation', [gpu]); | ||
}); | ||
|
||
let updateVmRequest$: Observable<unknown>; | ||
|
||
if (pciIdsRequests$.length) { | ||
updateVmRequest$ = forkJoin(pciIdsRequests$).pipe( | ||
map((pciIds) => pciIds.flat()), | ||
switchMap((pciIds) => forkJoin([ | ||
if (gpusIds.length) { | ||
updateVmRequest$ = this.ws.call('system.advanced.update_gpu_pci_ids', [gpusIds]).pipe( | ||
switchMap(() => forkJoin([ | ||
this.ws.call('vm.update', [this.existingVm.id, vmPayload as VirtualMachineUpdate]), | ||
this.vmGpuService.updateVmGpus(this.existingVm, gpusIds.concat(pciIds)), | ||
this.gpuService.addIsolatedGpuPciIds(gpusIds.concat(pciIds)), | ||
this.vmGpuService.updateVmGpus(this.existingVm, gpusIds), | ||
this.gpuService.addIsolatedGpuPciIds(gpusIds), | ||
])), | ||
); | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ import { pick } from 'lodash-es'; | |
import { | ||
forkJoin, Observable, of, switchMap, | ||
} from 'rxjs'; | ||
import { catchError, defaultIfEmpty, map } from 'rxjs/operators'; | ||
import { catchError, defaultIfEmpty } from 'rxjs/operators'; | ||
import { GiB, MiB } from 'app/constants/bytes.constant'; | ||
import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; | ||
import { Role } from 'app/enums/role.enum'; | ||
|
@@ -285,17 +285,14 @@ export class VmWizardComponent implements OnInit { | |
private getGpuRequests(vm: VirtualMachine): Observable<unknown> { | ||
const gpusIds = this.gpuForm.gpus as unknown as string[]; | ||
|
||
const pciIdsRequests$ = gpusIds.map((gpu) => { | ||
return this.ws.call('vm.device.get_pci_ids_for_gpu_isolation', [gpu]); | ||
}); | ||
|
||
return forkJoin(pciIdsRequests$).pipe( | ||
return this.ws.call('system.advanced.update_gpu_pci_ids', [gpusIds]).pipe().pipe( | ||
defaultIfEmpty([]), | ||
map((pciIds) => pciIds.flat()), | ||
switchMap((pciIds) => forkJoin([ | ||
this.vmGpuService.updateVmGpus(vm, gpusIds.concat(pciIds)), | ||
this.gpuService.addIsolatedGpuPciIds(gpusIds.concat(pciIds)), | ||
])), | ||
switchMap(() => { | ||
return forkJoin([ | ||
this.vmGpuService.updateVmGpus(vm, gpusIds), | ||
this.gpuService.addIsolatedGpuPciIds(gpusIds), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So you call |
||
]); | ||
}), | ||
); | ||
} | ||
|
||
|
Unchanged files with check annotations Beta
}); | ||
// TODO: Broken after package update. Actually functionality is working. | ||
it.skip('inserts a suggestion when Enter is pressed', async () => { | ||
await searchHarness.setValue('User'); | ||
await (await searchHarness.getInputArea()).sendKeys(TestKey.ENTER); |
}); | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call | ||
it.skip('shows a list of previous versions for an installed app to roll back to', async () => { | ||
const versionSelect = await loader.getHarness(IxSelectHarness); | ||
const options = await versionSelect.getOptionLabels(); | ||
}); | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call | ||
it.skip('rolls back app when form is submitted', async () => { | ||
const form = await loader.getHarness(IxFormHarness); | ||
await form.fillForm({ | ||
Version: '0.9.8', |
expect(spectator.query('span')).toHaveText('Deploying'); | ||
}); | ||
it.skip('checks state for stopping app', () => { | ||
setupTest( | ||
{ state: AppState.Running } as App, | ||
); |
import { ShellDetailsType } from 'app/pages/apps/enum/shell-details-type.enum'; | ||
// TODO: | ||
describe.skip('ShellDetailsDialogComponent', () => { | ||
let spectator: Spectator<ShellDetailsDialogComponent>; | ||
let loader: HarnessLoader; | ||
let form: IxFormHarness; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is obscure. It's better to create a new function for this local to vms module, like in GpuService.