From 3f2449f3d89ddd23a0785872a1e1f5acabe6531e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 26 Jul 2023 09:20:53 +0800 Subject: [PATCH 1/8] packaging: install tzdata-java on centos7/centos8 (#7768) When install cloudstack on latest rocky8 server with java-11-openjdk-11.0.20.0.8-2.el8.x86_64, management server cannot be started due to error ``` Caused by: java.lang.Error: java.io.FileNotFoundException: /usr/lib/jvm/java-11-openjdk-11.0.20.0.8-2.el8.x86_64/lib/tzdb.dat (No such file or directory) ``` It is because the package `tzdata-java` is not automatically installed. (It was installed with java-11-openjdk-11.0.18.0.10-2.el8_7.x86_64, but not with latest java-11-openjdk-11.0.20.0.8-2.el8.x86_64) --- packaging/centos7/cloud.spec | 3 +++ packaging/centos8/cloud.spec | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index 44dc06d1849..c6ae6a63ae5 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -61,6 +61,7 @@ intelligent IaaS cloud implementation. %package management Summary: CloudStack management server UI Requires: java-11-openjdk +Requires: tzdata-java Requires: python Requires: python3 Requires: bash @@ -107,6 +108,7 @@ The Apache CloudStack files shared between agent and management server Summary: CloudStack Agent for KVM hypervisors Requires: openssh-clients Requires: java-11-openjdk +Requires: tzdata-java Requires: %{name}-common = %{_ver} Requires: libvirt Requires: bridge-utils @@ -142,6 +144,7 @@ The CloudStack baremetal agent %package usage Summary: CloudStack Usage calculation server Requires: java-11-openjdk +Requires: tzdata-java Group: System Environment/Libraries %description usage The CloudStack usage calculation service diff --git a/packaging/centos8/cloud.spec b/packaging/centos8/cloud.spec index f2b020518db..a6b148afbe9 100644 --- a/packaging/centos8/cloud.spec +++ b/packaging/centos8/cloud.spec @@ -53,6 +53,7 @@ intelligent IaaS cloud implementation. %package management Summary: CloudStack management server UI Requires: java-11-openjdk +Requires: tzdata-java Requires: python3 Requires: bash Requires: gawk @@ -98,6 +99,7 @@ The Apache CloudStack files shared between agent and management server Summary: CloudStack Agent for KVM hypervisors Requires: (openssh-clients or openssh) Requires: java-11-openjdk +Requires: tzdata-java Requires: %{name}-common = %{_ver} Requires: libvirt Requires: ebtables @@ -134,6 +136,7 @@ The CloudStack baremetal agent %package usage Summary: CloudStack Usage calculation server Requires: java-11-openjdk +Requires: tzdata-java Group: System Environment/Libraries %description usage The CloudStack usage calculation service From cdf01879ec3c0f05de2d711776a2570b80efb507 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 26 Jul 2023 18:29:45 +0800 Subject: [PATCH 2/8] ui: fix 404 error when list volumes of system vms (#7772) This PR fixes #7662 --- ui/src/views/AutogenView.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index cf552e2ede4..4bd291b97a1 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -769,6 +769,10 @@ export default { this.dataView = false } + if (this.dataView && ['Admin'].includes(this.$store.getters.userInfo.roletype) && this.routeName === 'volume') { + params.listsystemvms = true + } + if ('listview' in this.$refs && this.$refs.listview) { this.$refs.listview.resetSelection() } From 01e5c25523abae42727294c299b41d20a99e71ec Mon Sep 17 00:00:00 2001 From: dahn Date: Thu, 27 Jul 2023 15:03:12 +0200 Subject: [PATCH 3/8] search in (too) large result sets (#7766) Co-authored-by: Pearl Dsilva --- ui/src/components/view/SearchView.vue | 114 +++++++++++++++----------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/ui/src/components/view/SearchView.vue b/ui/src/components/view/SearchView.vue index 680d5521d49..190db440fd1 100644 --- a/ui/src/components/view/SearchView.vue +++ b/ui/src/components/view/SearchView.vue @@ -65,7 +65,8 @@ :filterOption="(input, option) => { return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 }" - :loading="field.loading"> + :loading="field.loading" + @input="onchange($event, field.name)"> { @@ -291,14 +295,9 @@ export default { }) arrayField.push(item) }) - - const promises = [] - let zoneIndex = -1 - let domainIndex = -1 - let podIndex = -1 - let clusterIndex = -1 - let groupIndex = -1 - + return arrayField + }, + fetchStaticFieldData (arrayField) { if (arrayField.includes('type')) { if (this.$route.path === '/guestnetwork' || this.$route.path.includes('/guestnetwork/')) { const typeIndex = this.fields.findIndex(item => item.name === 'type') @@ -322,36 +321,6 @@ export default { this.fields[levelIndex].loading = false } - if (arrayField.includes('zoneid')) { - zoneIndex = this.fields.findIndex(item => item.name === 'zoneid') - this.fields[zoneIndex].loading = true - promises.push(await this.fetchZones()) - } - - if (arrayField.includes('domainid')) { - domainIndex = this.fields.findIndex(item => item.name === 'domainid') - this.fields[domainIndex].loading = true - promises.push(await this.fetchDomains()) - } - - if (arrayField.includes('podid')) { - podIndex = this.fields.findIndex(item => item.name === 'podid') - this.fields[podIndex].loading = true - promises.push(await this.fetchPods()) - } - - if (arrayField.includes('clusterid')) { - clusterIndex = this.fields.findIndex(item => item.name === 'clusterid') - this.fields[clusterIndex].loading = true - promises.push(await this.fetchClusters()) - } - - if (arrayField.includes('groupid')) { - groupIndex = this.fields.findIndex(item => item.name === 'groupid') - this.fields[groupIndex].loading = true - promises.push(await this.fetchInstanceGroups()) - } - if (arrayField.includes('entitytype')) { const entityTypeIndex = this.fields.findIndex(item => item.name === 'entitytype') this.fields[entityTypeIndex].loading = true @@ -374,6 +343,44 @@ export default { ] this.fields[resourceTypeIndex].loading = false } + }, + async fetchDynamicFieldData (arrayField, searchKeyword) { + const promises = [] + let zoneIndex = -1 + let domainIndex = -1 + let podIndex = -1 + let clusterIndex = -1 + let groupIndex = -1 + + if (arrayField.includes('zoneid')) { + zoneIndex = this.fields.findIndex(item => item.name === 'zoneid') + this.fields[zoneIndex].loading = true + promises.push(await this.fetchZones(searchKeyword)) + } + + if (arrayField.includes('domainid')) { + domainIndex = this.fields.findIndex(item => item.name === 'domainid') + this.fields[domainIndex].loading = true + promises.push(await this.fetchDomains(searchKeyword)) + } + + if (arrayField.includes('podid')) { + podIndex = this.fields.findIndex(item => item.name === 'podid') + this.fields[podIndex].loading = true + promises.push(await this.fetchPods(searchKeyword)) + } + + if (arrayField.includes('clusterid')) { + clusterIndex = this.fields.findIndex(item => item.name === 'clusterid') + this.fields[clusterIndex].loading = true + promises.push(await this.fetchClusters(searchKeyword)) + } + + if (arrayField.includes('groupid')) { + groupIndex = this.fields.findIndex(item => item.name === 'groupid') + this.fields[groupIndex].loading = true + promises.push(await this.fetchInstanceGroups(searchKeyword)) + } Promise.all(promises).then(response => { if (zoneIndex > -1) { @@ -425,6 +432,13 @@ export default { this.fillFormFieldValues() }) }, + initFormFieldData () { + const arrayField = this.initFields() + + this.fetchStaticFieldData(arrayField) + + this.fetchDynamicFieldData(arrayField) + }, sortArray (data, key = 'name') { return data.sort(function (a, b) { if (a[key] < b[key]) { return -1 } @@ -447,9 +461,9 @@ export default { this.inputKey = this.fieldValues['tags[0].key'] || null this.inputValue = this.fieldValues['tags[0].value'] || null }, - fetchZones () { + fetchZones (searchKeyword) { return new Promise((resolve, reject) => { - api('listZones', { showicon: true }).then(json => { + api('listZones', { showicon: true, keyword: searchKeyword }).then(json => { const zones = json.listzonesresponse.zone resolve({ type: 'zoneid', @@ -460,9 +474,9 @@ export default { }) }) }, - fetchDomains () { + fetchDomains (searchKeyword) { return new Promise((resolve, reject) => { - api('listDomains', { listAll: true, showicon: true }).then(json => { + api('listDomains', { listAll: true, showicon: true, keyword: searchKeyword }).then(json => { const domain = json.listdomainsresponse.domain resolve({ type: 'domainid', @@ -473,9 +487,9 @@ export default { }) }) }, - fetchPods () { + fetchPods (searchKeyword) { return new Promise((resolve, reject) => { - api('listPods').then(json => { + api('listPods', { keyword: searchKeyword }).then(json => { const pods = json.listpodsresponse.pod resolve({ type: 'podid', @@ -486,9 +500,9 @@ export default { }) }) }, - fetchClusters () { + fetchClusters (searchKeyword) { return new Promise((resolve, reject) => { - api('listClusters').then(json => { + api('listClusters', { keyword: searchKeyword }).then(json => { const clusters = json.listclustersresponse.cluster resolve({ type: 'clusterid', @@ -499,9 +513,9 @@ export default { }) }) }, - fetchInstanceGroups () { + fetchInstanceGroups (searchKeyword) { return new Promise((resolve, reject) => { - api('listInstanceGroups', { listAll: true }).then(json => { + api('listInstanceGroups', { listAll: true, keyword: searchKeyword }).then(json => { const instancegroups = json.listinstancegroupsresponse.instancegroup resolve({ type: 'groupid', From d9588822828630e69e3babec904a5809454602cb Mon Sep 17 00:00:00 2001 From: dahn Date: Fri, 28 Jul 2023 05:16:33 +0200 Subject: [PATCH 4/8] server: get id from persisted object ReservationVO (#7785) --- .../main/java/com/cloud/resourcelimit/CheckedReservation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java b/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java index d0c20a3a7af..5650af15339 100644 --- a/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java +++ b/server/src/main/java/com/cloud/resourcelimit/CheckedReservation.java @@ -76,7 +76,7 @@ public class CheckedReservation implements AutoCloseable, ResourceReservation { resourceLimitService.checkResourceLimit(account,resourceType,amount); ReservationVO reservationVO = new ReservationVO(account.getAccountId(), account.getDomainId(), resourceType, amount); this.reservation = reservationDao.persist(reservationVO); - CallContext.current().putContextParameter(getContextParameterKey(), reservationVO.getId()); + CallContext.current().putContextParameter(getContextParameterKey(), reservation.getId()); } catch (NullPointerException npe) { throw new CloudRuntimeException("not enough means to check limits", npe); } finally { From d89d40595cb12b8ec09febc4a2a6248a780bdc73 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 28 Jul 2023 16:27:44 +0800 Subject: [PATCH 5/8] cloudutils: fix adding rocky9 host failure due to missing /etc/sysconfig/libvirtd (#7779) --- python/lib/cloudutils/configFileOps.py | 64 +++++++++++++------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/python/lib/cloudutils/configFileOps.py b/python/lib/cloudutils/configFileOps.py index 698f2b31a3a..41e9c7a1e8e 100644 --- a/python/lib/cloudutils/configFileOps.py +++ b/python/lib/cloudutils/configFileOps.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. import re +import os import tempfile import shutil from .utilities import bash @@ -59,39 +60,42 @@ class configFileOps: return "" def save(self): - fp = open(self.fileName, "r") newLines = [] - for line in fp.readlines(): - matched = False - for entry in self.entries: - if entry.op == "add": - if entry.separator == "=": - matchString = "^\ *" + entry.name + ".*" - elif entry.separator == " ": - matchString = "^\ *" + entry.name + "\ *" + entry.value - else: - if entry.separator == "=": - matchString = "^\ *" + entry.name + "\ *=\ *" + entry.value + if os.path.exists(self.fileName) and os.path.isfile(self.fileName): + fp = open(self.fileName, "r") + for line in fp.readlines(): + matched = False + for entry in self.entries: + if entry.op == "add": + if entry.separator == "=": + matchString = "^\ *" + entry.name + ".*" + elif entry.separator == " ": + matchString = "^\ *" + entry.name + "\ *" + entry.value else: - matchString = "^\ *" + entry.name + "\ *" + entry.value + if entry.separator == "=": + matchString = "^\ *" + entry.name + "\ *=\ *" + entry.value + else: + matchString = "^\ *" + entry.name + "\ *" + entry.value - match = re.match(matchString, line) - if match is not None: - if entry.op == "add" and entry.separator == "=": - newline = "\n" + entry.name + "=" + entry.value + "\n" - entry.setState("set") - newLines.append(newline) - self.backups.append([line, newline]) - matched = True - break - elif entry.op == "rm": - entry.setState("set") - self.backups.append([line, None]) - matched = True - break + match = re.match(matchString, line) + if match is not None: + if entry.op == "add" and entry.separator == "=": + newline = "\n" + entry.name + "=" + entry.value + "\n" + entry.setState("set") + newLines.append(newline) + self.backups.append([line, newline]) + matched = True + break + elif entry.op == "rm": + entry.setState("set") + self.backups.append([line, None]) + matched = True + break - if not matched: - newLines.append(line) + if not matched: + newLines.append(line) + + fp.close() for entry in self.entries: if entry.getState() != "set": @@ -101,8 +105,6 @@ class configFileOps: self.backups.append([None, newline]) entry.setState("set") - fp.close() - open(self.fileName, "w").writelines(newLines) def replace_line(self, startswith,stanza,always_add=False): From f4a4417e4c7befd8e9dccdf9226b066b01cb01d1 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 28 Jul 2023 17:05:44 +0800 Subject: [PATCH 6/8] pom.xml: add property project.systemvm.template.location (#7706) * pom.xml: add property project.systemvm.template.location * pom.xml: update project.systemvm.template.location --- engine/schema/pom.xml | 12 ++++++------ pom.xml | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml index da40a524c9b..cad7a0a8b66 100644 --- a/engine/schema/pom.xml +++ b/engine/schema/pom.xml @@ -122,7 +122,7 @@ wget - https://download.cloudstack.org/systemvm/${cs.version}/md5sum.txt + ${project.systemvm.template.location}/${cs.version}/md5sum.txt ${basedir}/dist/systemvm-templates/ true true @@ -181,7 +181,7 @@ true - https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-kvm.qcow2.bz2 + ${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-kvm.qcow2.bz2 ${basedir}/dist/systemvm-templates/ ${kvm.checksum} @@ -217,7 +217,7 @@ true - https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-vmware.ova + ${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-vmware.ova ${basedir}/dist/systemvm-templates/ ${vmware.checksum} @@ -253,7 +253,7 @@ true - https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-xen.vhd.bz2 + ${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-xen.vhd.bz2 ${basedir}/dist/systemvm-templates/ ${xen.checksum} @@ -289,7 +289,7 @@ true - https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-ovm.raw.bz2 + ${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-ovm.raw.bz2 ${basedir}/dist/systemvm-templates/ ${ovm.checksum} @@ -325,7 +325,7 @@ true - https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-hyperv.vhd.zip + ${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-hyperv.vhd.zip ${basedir}/dist/systemvm-templates/ ${hyperv.checksum} diff --git a/pom.xml b/pom.xml index 824ab363bb4..f9be3ab98a2 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ UTF-8 UTF-8 + https://download.cloudstack.org/systemvm 4.18.0.0 apache https://sonarcloud.io From d127d7939de92ecf3514128207baab36364e51d1 Mon Sep 17 00:00:00 2001 From: dahn Date: Fri, 28 Jul 2023 11:23:30 +0200 Subject: [PATCH 7/8] KVM: fix SSVM starting when overprovisioning memory (#7663) --- .../resource/LibvirtComputingResource.java | 9 ++++- .../hypervisor/kvm/resource/LibvirtVMDef.java | 4 +- .../LibvirtComputingResourceTest.java | 2 +- .../kvm/resource/LibvirtVMDefTest.java | 38 +++++++++---------- .../java/com/cloud/hypervisor/KVMGuru.java | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 3f711fa9b80..39f30b6e934 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -2780,10 +2780,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv grd.setMemBalloning(!_noMemBalloon); - Long maxRam = ByteScaleUtils.bytesToKibibytes(vmTO.getMaxRam()); + long maxRam = ByteScaleUtils.bytesToKibibytes(vmTO.getMaxRam()); + long currRam = vmTO.getType() == VirtualMachine.Type.User ? getCurrentMemAccordingToMemBallooning(vmTO, maxRam) : maxRam; + + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("memory values for VM %s are %d/%d",vmTO.getName(),maxRam, currRam)); + } grd.setMemorySize(maxRam); - grd.setCurrentMem(getCurrentMemAccordingToMemBallooning(vmTO, maxRam)); + grd.setCurrentMem(currRam); int vcpus = vmTO.getCpus(); Integer maxVcpus = vmTO.getVcpuMaxLimit(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index b739c0ee0ab..720c48096ef 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -282,7 +282,7 @@ public class LibvirtVMDef { @Override public String toString() { StringBuilder response = new StringBuilder(); - response.append(String.format("%s\n", this.currentMemory)); + response.append(String.format("%s\n", this.memory)); response.append(String.format("%s\n", this.currentMemory)); if (this.memory > this.currentMemory) { @@ -1238,7 +1238,7 @@ public class LibvirtVMDef { @Override public String toString() { StringBuilder memBalloonBuilder = new StringBuilder(); - memBalloonBuilder.append("\n"); + memBalloonBuilder.append("\n"); if (StringUtils.isNotBlank(memBalloonStatsPeriod)) { memBalloonBuilder.append("\n"); } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index ffe20b4ad30..58682b2663c 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -760,7 +760,7 @@ public class LibvirtComputingResourceTest { private void verifyMemory(VirtualMachineTO to, Document domainDoc, String minRam) { assertXpath(domainDoc, "/domain/maxMemory/text()", String.valueOf( to.getMaxRam() / 1024 )); - assertXpath(domainDoc, "/domain/memory/text()",minRam); + assertXpath(domainDoc, "/domain/currentMemory/text()",minRam); assertXpath(domainDoc, "/domain/cpu/numa/cell/@memory", minRam); assertXpath(domainDoc, "/domain/currentMemory/text()", minRam); } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java index ec59265c832..4379ede8293 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java @@ -214,11 +214,11 @@ public class LibvirtVMDefTest extends TestCase { assertEquals(bus, disk.getBusType()); assertEquals(DiskDef.DeviceType.DISK, disk.getDeviceType()); - String xmlDef = disk.toString(); + String resultingXml = disk.toString(); String expectedXml = "\n\n" + "\n\n\n"; - assertEquals(xmlDef, expectedXml); + assertEquals(expectedXml, resultingXml); } @Test @@ -236,7 +236,7 @@ public class LibvirtVMDefTest extends TestCase { "\n" + "\n" + "\n"; - assertEquals(disk.toString(), expectedXML); + assertEquals(expectedXML, disk.toString()); } @Test @@ -346,7 +346,7 @@ public class LibvirtVMDefTest extends TestCase { LibvirtVMDef.setGlobalQemuVersion(2006000L); LibvirtVMDef.setGlobalLibvirtVersion(9008L); - String xmlDef = disk.toString(); + String resultingXml = disk.toString(); String expectedXml = "\n\n" + "\n\n" + "\n"+bytesReadRate+"\n"+bytesWriteRate+"\n" + @@ -356,29 +356,29 @@ public class LibvirtVMDefTest extends TestCase { ""+bytesReadRateMaxLength+"\n"+bytesWriteRateMaxLength+"\n" + ""+iopsReadRateMaxLength+"\n"+iopsWriteRateMaxLength+"\n\n\n"; - assertEquals(xmlDef, expectedXml); + assertEquals(expectedXml, resultingXml); } @Test public void memBalloonDefTestNone() { - String expectedXml = "\n"; + String expectedXml = "\n"; MemBalloonDef memBalloonDef = new MemBalloonDef(); memBalloonDef.defNoneMemBalloon(); - String xmlDef = memBalloonDef.toString(); + String resultingXml = memBalloonDef.toString(); - assertEquals(xmlDef, expectedXml); + assertEquals(expectedXml, resultingXml); } @Test public void memBalloonDefTestVirtio() { - String expectedXml = "\n\n"; + String expectedXml = "\n\n"; MemBalloonDef memBalloonDef = new MemBalloonDef(); memBalloonDef.defVirtioMemBalloon("60"); - String xmlDef = memBalloonDef.toString(); + String resultingXml = memBalloonDef.toString(); - assertEquals(xmlDef, expectedXml); + assertEquals(expectedXml, resultingXml); } @Test @@ -413,11 +413,11 @@ public class LibvirtVMDefTest extends TestCase { int bytes = 2048; LibvirtVMDef.RngDef def = new LibvirtVMDef.RngDef(path, backendModel, bytes, period); - assertEquals(def.getPath(), path); - assertEquals(def.getRngBackendModel(), backendModel); - assertEquals(def.getRngModel(), LibvirtVMDef.RngDef.RngModel.VIRTIO); - assertEquals(def.getRngRateBytes(), bytes); - assertEquals(def.getRngRatePeriod(), period); + assertEquals(path, def.getPath()); + assertEquals(backendModel, def.getRngBackendModel()); + assertEquals(LibvirtVMDef.RngDef.RngModel.VIRTIO, def.getRngModel()); + assertEquals(bytes, def.getRngRateBytes()); + assertEquals(period, def.getRngRatePeriod()); } @Test @@ -441,8 +441,8 @@ public class LibvirtVMDefTest extends TestCase { LibvirtVMDef.WatchDogDef.WatchDogAction action = LibvirtVMDef.WatchDogDef.WatchDogAction.RESET; LibvirtVMDef.WatchDogDef def = new LibvirtVMDef.WatchDogDef(action, model); - assertEquals(def.getModel(), model); - assertEquals(def.getAction(), action); + assertEquals(model, def.getModel()); + assertEquals(action, def.getAction()); } @Test @@ -453,6 +453,6 @@ public class LibvirtVMDefTest extends TestCase { "
\n" + "\n" + "\n"; - assertEquals(str, expected); + assertEquals(expected, str); } } diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index f0ccffbc719..7c02d95f3eb 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -213,7 +213,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru { Integer maxHostCpuCore = max.second(); long minMemory = virtualMachineTo.getMinRam(); - Long maxMemory = minMemory; + Long maxMemory = virtualMachineTo.getMaxRam(); int minCpuCores = virtualMachineTo.getCpus(); Integer maxCpuCores = minCpuCores; From a2eb10304f274a82fff38fe7258976350f23d921 Mon Sep 17 00:00:00 2001 From: dahn Date: Mon, 31 Jul 2023 07:30:24 +0200 Subject: [PATCH 8/8] UI: Filter templates by zone and hypervisor type when reinstall a VM (#7739) --- ui/src/config/section/compute.js | 8 +++++ ui/src/views/AutogenView.vue | 52 +++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index 5393e8bd43e..6aa2beff643 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -164,6 +164,14 @@ export default { message: 'message.reinstall.vm', dataView: true, args: ['virtualmachineid', 'templateid'], + filters: (record) => { + var filters = {} + var filterParams = {} + filterParams.hypervisortype = record.hypervisor + filterParams.zoneid = record.zoneid + filters.templateid = filterParams + return filters + }, show: (record) => { return ['Running', 'Stopped'].includes(record.state) }, mapping: { virtualmachineid: { diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 4bd291b97a1..c8e931b6be0 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -1034,7 +1034,6 @@ export default { this.setModalWidthByScreen() }, execAction (action, isGroupAction) { - const self = this this.formRef = ref() this.form = reactive({}) this.rules = reactive({}) @@ -1072,6 +1071,7 @@ export default { return 0 }) this.currentAction.paramFields = [] + this.currentAction.paramFilters = [] if ('message' in action) { var message = action.message if (typeof action.message === 'function') { @@ -1079,6 +1079,29 @@ export default { } action.message = message } + + this.getArgs(action, isGroupAction, paramFields) + this.getFilters(action, isGroupAction, paramFields) + this.getFirstIndexFocus() + + this.showAction = true + const listIconForFillValues = ['copy-outlined', 'CopyOutlined', 'edit-outlined', 'EditOutlined', 'share-alt-outlined', 'ShareAltOutlined'] + for (const param of this.currentAction.paramFields) { + if (param.type === 'list' && ['tags', 'hosttags', 'storagetags', 'files'].includes(param.name)) { + param.type = 'string' + } + this.setRules(param) + if (param.type === 'uuid' || param.type === 'list' || param.name === 'account' || (this.currentAction.mapping && param.name in this.currentAction.mapping)) { + this.listUuidOpts(param, this.currentAction.paramFilters[param.name]) + } + } + this.actionLoading = false + if (action.dataView && listIconForFillValues.includes(action.icon)) { + this.fillEditFormFieldValues() + } + }, + getArgs (action, isGroupAction, paramFields) { + const self = this if ('args' in action) { var args = action.args if (typeof action.args === 'function') { @@ -1100,22 +1123,14 @@ export default { }) } } - this.getFirstIndexFocus() - - this.showAction = true - const listIconForFillValues = ['copy-outlined', 'CopyOutlined', 'edit-outlined', 'EditOutlined', 'share-alt-outlined', 'ShareAltOutlined'] - for (const param of this.currentAction.paramFields) { - if (param.type === 'list' && ['tags', 'hosttags', 'storagetags', 'files'].includes(param.name)) { - param.type = 'string' + }, + getFilters (action, isGroupAction, paramFields) { + if ('filters' in action) { + var filters = action.filters + if (typeof action.filters === 'function') { + filters = action.filters(action.resource, this.$store.getters, isGroupAction) } - this.setRules(param) - if (param.type === 'uuid' || param.type === 'list' || param.name === 'account' || (this.currentAction.mapping && param.name in this.currentAction.mapping)) { - this.listUuidOpts(param) - } - } - this.actionLoading = false - if (action.dataView && listIconForFillValues.includes(action.icon)) { - this.fillEditFormFieldValues() + this.currentAction.paramFilters = filters } }, getFirstIndexFocus () { @@ -1128,13 +1143,16 @@ export default { } } }, - listUuidOpts (param) { + listUuidOpts (param, filters) { if (this.currentAction.mapping && param.name in this.currentAction.mapping && !this.currentAction.mapping[param.name].api) { return } var paramName = param.name var extractedParamName = paramName.replace('ids', '').replace('id', '').toLowerCase() var params = { listall: true } + for (const filter in filters) { + params[filter] = filters[filter] + } const possibleName = 'list' + extractedParamName + 's' var showIcon = false if (this.$showIcon(extractedParamName)) {