package daemon import ( "context" "errors" "banger/internal/api" "banger/internal/model" "banger/internal/system" ) func (d *Daemon) SetVM(ctx context.Context, params api.VMSetParams) (model.VMRecord, error) { return d.withVMLockByRef(ctx, params.IDOrName, func(vm model.VMRecord) (model.VMRecord, error) { return d.setVMLocked(ctx, vm, params) }) } func (d *Daemon) setVMLocked(ctx context.Context, current model.VMRecord, params api.VMSetParams) (vm model.VMRecord, err error) { vm = current op := d.beginOperation("vm.set", "vm_ref", vm.ID) defer func() { if err != nil { op.fail(err, vmLogAttrs(vm)...) return } op.done(vmLogAttrs(vm)...) }() running := d.vmAlive(vm) if params.VCPUCount != nil { if err := validateOptionalPositiveSetting("vcpu", params.VCPUCount); err != nil { return model.VMRecord{}, err } if running { return model.VMRecord{}, errors.New("vcpu changes require the VM to be stopped") } op.stage("update_vcpu", "vcpu_count", *params.VCPUCount) vm.Spec.VCPUCount = *params.VCPUCount } if params.MemoryMiB != nil { if err := validateOptionalPositiveSetting("memory", params.MemoryMiB); err != nil { return model.VMRecord{}, err } if running { return model.VMRecord{}, errors.New("memory changes require the VM to be stopped") } op.stage("update_memory", "memory_mib", *params.MemoryMiB) vm.Spec.MemoryMiB = *params.MemoryMiB } if params.WorkDiskSize != "" { size, err := model.ParseSize(params.WorkDiskSize) if err != nil { return model.VMRecord{}, err } if running { return model.VMRecord{}, errors.New("disk changes require the VM to be stopped") } if size < vm.Spec.WorkDiskSizeBytes { return model.VMRecord{}, errors.New("disk size can only grow") } if size > vm.Spec.WorkDiskSizeBytes { if exists(vm.Runtime.WorkDiskPath) { op.stage("resize_work_disk", "from_bytes", vm.Spec.WorkDiskSizeBytes, "to_bytes", size) if err := d.validateWorkDiskResizePrereqs(); err != nil { return model.VMRecord{}, err } if err := system.ResizeExt4Image(ctx, d.runner, vm.Runtime.WorkDiskPath, size); err != nil { return model.VMRecord{}, err } } vm.Spec.WorkDiskSizeBytes = size } } if params.NATEnabled != nil { op.stage("update_nat", "nat_enabled", *params.NATEnabled) vm.Spec.NATEnabled = *params.NATEnabled } if running { if err := d.applyCapabilityConfigChanges(ctx, current, vm); err != nil { return model.VMRecord{}, err } } system.TouchNow(&vm) if err := d.store.UpsertVM(ctx, vm); err != nil { return model.VMRecord{}, err } return vm, nil }