Skip to content

Commit eeaed19

Browse files
committed
ui: keep root disk size when the same template is selected again
The image selection list emits the selected template twice when it auto-selects one: once for the row click and once when the selected prop comes back. Each call resets the template state and drops form.rootdisksize. The root DiskSizeSelection only re-emits its value when minrootdisksize changes, and it does not change for the same template, so the size is never set again. When the first compute offering is auto-selected and links a disk offering with a custom size, deployVirtualMachine is then sent without rootdisksize and fails with error 431. Keep the root disk size when the selected template does not change. Fixes: #14524
1 parent d02adcd commit eeaed19

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

‎ui/src/views/compute/DeployVM.vue‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,12 +2037,17 @@ export default {
20372037
},
20382038
updateFieldValue (name, value) {
20392039
if (name === 'templateid') {
2040+
// DiskSizeSelection only re-emits the size when minrootdisksize changes, so keep it for the same template
2041+
const rootDiskSize = this.form.templateid === value ? this.form.rootdisksize : undefined
20402042
this.imageType = 'templateid'
20412043
this.form.templateid = value
20422044
this.form.isoid = null
20432045
this.form.volumeid = null
20442046
this.form.snapshotid = null
20452047
this.resetFromTemplateConfiguration()
2048+
if (rootDiskSize) {
2049+
this.form.rootdisksize = rootDiskSize
2050+
}
20462051
let template = ''
20472052
for (const entry of Object.values(this.options.templates)) {
20482053
template = entry?.template.find(option => option.id === value) || null
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
import DeployVM from '@/views/compute/DeployVM'
19+
20+
jest.mock('@views/compute/wizard/OwnershipSelection', () => ({}), { virtual: true })
21+
jest.mock('@views/compute/wizard/DeployButtons', () => ({}), { virtual: true })
22+
jest.mock('@views/compute/wizard/ZoneBlockRadioGroupSelect', () => ({}), { virtual: true })
23+
jest.mock('@views/compute/wizard/ComputeOfferingSelection', () => ({}), { virtual: true })
24+
jest.mock('@views/compute/wizard/ComputeSelection', () => ({}), { virtual: true })
25+
jest.mock('@views/compute/wizard/DiskOfferingSelection', () => ({}), { virtual: true })
26+
jest.mock('@views/compute/wizard/DiskSizeSelection', () => ({}), { virtual: true })
27+
jest.mock('@views/compute/wizard/MultiDiskSelection', () => ({}), { virtual: true })
28+
jest.mock('@views/compute/wizard/TemplateIsoSelection', () => ({}), { virtual: true })
29+
jest.mock('@views/compute/wizard/OsBasedImageSelection', () => ({}), { virtual: true })
30+
jest.mock('@views/compute/wizard/AffinityGroupSelection', () => ({}), { virtual: true })
31+
jest.mock('@views/compute/wizard/NetworkSelection', () => ({}), { virtual: true })
32+
jest.mock('@views/compute/wizard/NetworkConfiguration', () => ({}), { virtual: true })
33+
jest.mock('@views/compute/wizard/SshKeyPairSelection', () => ({}), { virtual: true })
34+
jest.mock('@views/compute/wizard/UserDataSelection', () => ({}), { virtual: true })
35+
jest.mock('@views/compute/wizard/SecurityGroupSelection', () => ({}), { virtual: true })
36+
jest.mock('@views/compute/wizard/DeployInstanceBackupSelection', () => ({}), { virtual: true })
37+
38+
const createContext = (form) => {
39+
const template = { id: 'template-1', details: {}, hypervisor: 'KVM', size: 8 * 1024 * 1024 * 1024 }
40+
return {
41+
form,
42+
instanceConfig: form,
43+
options: { bootModes: [], templates: { featured: { template: [template] } } },
44+
params: { serviceOfferings: { options: {} } },
45+
dataPreFill: { minrootdisksize: 8 },
46+
deleteFrom: DeployVM.methods.deleteFrom,
47+
resetFromTemplateConfiguration: DeployVM.methods.resetFromTemplateConfiguration,
48+
handleSearchFilter: jest.fn(),
49+
fetchBootModes: jest.fn(),
50+
resetTemplateAssociatedResources: jest.fn(),
51+
updateTemplateLinkedUserData: jest.fn(),
52+
updateTemplateParameters: jest.fn()
53+
}
54+
}
55+
56+
describe('DeployVM root disk size on template selection', () => {
57+
it('keeps the root disk size when the same template is selected again', () => {
58+
const context = createContext({ templateid: 'template-1', rootdisksize: 8 })
59+
60+
DeployVM.methods.updateFieldValue.call(context, 'templateid', 'template-1')
61+
62+
expect(context.form.rootdisksize).toBe(8)
63+
})
64+
65+
it('clears the root disk size when another template is selected', () => {
66+
const context = createContext({ templateid: 'template-0', rootdisksize: 20 })
67+
68+
DeployVM.methods.updateFieldValue.call(context, 'templateid', 'template-1')
69+
70+
expect(context.form.rootdisksize).toBeUndefined()
71+
})
72+
})

0 commit comments

Comments
 (0)