mirror of https://github.com/apache/cloudstack.git
Merge release branch 4.18 to main
* 4.18: UI: Filter templates by zone and hypervisor type when reinstall a VM (#7739) KVM: fix SSVM starting when overprovisioning memory (#7663) pom.xml: add property project.systemvm.template.location (#7706) cloudutils: fix adding rocky9 host failure due to missing /etc/sysconfig/libvirtd (#7779) server: get id from persisted object ReservationVO (#7785) search in (too) large result sets (#7766) ui: fix 404 error when list volumes of system vms (#7772) packaging: install tzdata-java on centos7/centos8 (#7768)
This commit is contained in:
commit
d51d8a4a13
|
|
@ -122,7 +122,7 @@
|
|||
<goal>wget</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/md5sum.txt</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/md5sum.txt</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<skipCache>true</skipCache>
|
||||
<overwrite>true</overwrite>
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<checkSignature>true</checkSignature>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-kvm.qcow2.bz2</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-kvm.qcow2.bz2</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<md5>${kvm.checksum}</md5>
|
||||
</configuration>
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<checkSignature>true</checkSignature>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-vmware.ova</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-vmware.ova</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<md5>${vmware.checksum}</md5>
|
||||
</configuration>
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<checkSignature>true</checkSignature>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-xen.vhd.bz2</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-xen.vhd.bz2</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<md5>${xen.checksum}</md5>
|
||||
</configuration>
|
||||
|
|
@ -289,7 +289,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<checkSignature>true</checkSignature>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-ovm.raw.bz2</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-ovm.raw.bz2</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<md5>${ovm.checksum}</md5>
|
||||
</configuration>
|
||||
|
|
@ -325,7 +325,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<checkSignature>true</checkSignature>
|
||||
<url>https://download.cloudstack.org/systemvm/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-hyperv.vhd.zip</url>
|
||||
<url>${project.systemvm.template.location}/${cs.version}/systemvmtemplate-${cs.version}.${patch.version}-hyperv.vhd.zip</url>
|
||||
<outputDirectory>${basedir}/dist/systemvm-templates/</outputDirectory>
|
||||
<md5>${hyperv.checksum}</md5>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2791,10 +2791,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();
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ public class LibvirtVMDef {
|
|||
@Override
|
||||
public String toString() {
|
||||
StringBuilder response = new StringBuilder();
|
||||
response.append(String.format("<memory>%s</memory>\n", this.currentMemory));
|
||||
response.append(String.format("<memory>%s</memory>\n", this.memory));
|
||||
response.append(String.format("<currentMemory>%s</currentMemory>\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("<memballoon model='" + memBalloonModel + "'>\n");
|
||||
memBalloonBuilder.append("<memballoon model='" + memBalloonModel + "' autodeflate='on'>\n");
|
||||
if (StringUtils.isNotBlank(memBalloonStatsPeriod)) {
|
||||
memBalloonBuilder.append("<stats period='" + memBalloonStatsPeriod +"'/>\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,11 +266,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 = "<disk device='disk' type='file'>\n<driver name='qemu' type='" + type.toString() + "' cache='" + cacheMode.toString() + "' />\n" +
|
||||
"<source file='" + filePath + "'/>\n<target dev='" + diskLabel + "' bus='" + bus.toString() + "'/>\n</disk>\n";
|
||||
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
assertEquals(expectedXml, resultingXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -288,7 +288,7 @@ public class LibvirtVMDefTest extends TestCase {
|
|||
"<secret type='passphrase' uuid='" + passphraseUuid + "' />\n" +
|
||||
"</encryption>\n" +
|
||||
"</disk>\n";
|
||||
assertEquals(disk.toString(), expectedXML);
|
||||
assertEquals(expectedXML, disk.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -398,7 +398,7 @@ public class LibvirtVMDefTest extends TestCase {
|
|||
LibvirtVMDef.setGlobalQemuVersion(2006000L);
|
||||
LibvirtVMDef.setGlobalLibvirtVersion(9008L);
|
||||
|
||||
String xmlDef = disk.toString();
|
||||
String resultingXml = disk.toString();
|
||||
String expectedXml = "<disk device='disk' type='file'>\n<driver name='qemu' type='" + type.toString() + "' cache='none' />\n" +
|
||||
"<source file='" + filePath + "'/>\n<target dev='" + diskLabel + "' bus='" + bus.toString() + "'/>\n" +
|
||||
"<iotune>\n<read_bytes_sec>"+bytesReadRate+"</read_bytes_sec>\n<write_bytes_sec>"+bytesWriteRate+"</write_bytes_sec>\n" +
|
||||
|
|
@ -408,29 +408,29 @@ public class LibvirtVMDefTest extends TestCase {
|
|||
"<read_bytes_sec_max_length>"+bytesReadRateMaxLength+"</read_bytes_sec_max_length>\n<write_bytes_sec_max_length>"+bytesWriteRateMaxLength+"</write_bytes_sec_max_length>\n" +
|
||||
"<read_iops_sec_max_length>"+iopsReadRateMaxLength+"</read_iops_sec_max_length>\n<write_iops_sec_max_length>"+iopsWriteRateMaxLength+"</write_iops_sec_max_length>\n</iotune>\n</disk>\n";
|
||||
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
assertEquals(expectedXml, resultingXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memBalloonDefTestNone() {
|
||||
String expectedXml = "<memballoon model='none'>\n</memballoon>";
|
||||
String expectedXml = "<memballoon model='none' autodeflate='on'>\n</memballoon>";
|
||||
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 = "<memballoon model='virtio'>\n<stats period='60'/>\n</memballoon>";
|
||||
String expectedXml = "<memballoon model='virtio' autodeflate='on'>\n<stats period='60'/>\n</memballoon>";
|
||||
MemBalloonDef memBalloonDef = new MemBalloonDef();
|
||||
memBalloonDef.defVirtioMemBalloon("60");
|
||||
|
||||
String xmlDef = memBalloonDef.toString();
|
||||
String resultingXml = memBalloonDef.toString();
|
||||
|
||||
assertEquals(xmlDef, expectedXml);
|
||||
assertEquals(expectedXml, resultingXml);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -465,11 +465,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
|
||||
|
|
@ -493,8 +493,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
|
||||
|
|
@ -505,6 +505,6 @@ public class LibvirtVMDefTest extends TestCase {
|
|||
"<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>\n" +
|
||||
"<driver queues='4'/>\n" +
|
||||
"</controller>\n";
|
||||
assertEquals(str, expected);
|
||||
assertEquals(expected, str);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
pom.xml
1
pom.xml
|
|
@ -49,6 +49,7 @@
|
|||
<!-- keep in alphabetic order -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<project.systemvm.template.location>https://download.cloudstack.org/systemvm</project.systemvm.template.location>
|
||||
<project.systemvm.template.version>4.18.0.0</project.systemvm.template.version>
|
||||
<sonar.organization>apache</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)">
|
||||
<a-select-option
|
||||
v-for="(opt, idx) in field.opts"
|
||||
:key="idx"
|
||||
|
|
@ -236,6 +237,9 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
onchange: async function (event, fieldname) {
|
||||
this.fetchDynamicFieldData(fieldname, event.target.value)
|
||||
},
|
||||
onVisibleForm () {
|
||||
this.visibleFilter = !this.visibleFilter
|
||||
if (!this.visibleFilter) return
|
||||
|
|
@ -254,7 +258,7 @@ export default {
|
|||
}
|
||||
return this.$t('label.' + fieldName)
|
||||
},
|
||||
async initFormFieldData () {
|
||||
initFields () {
|
||||
const arrayField = []
|
||||
this.fields = []
|
||||
this.searchFilters.forEach(item => {
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -794,6 +794,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()
|
||||
}
|
||||
|
|
@ -1047,7 +1051,6 @@ export default {
|
|||
this.setModalWidthByScreen()
|
||||
},
|
||||
execAction (action, isGroupAction) {
|
||||
const self = this
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
this.rules = reactive({})
|
||||
|
|
@ -1085,6 +1088,7 @@ export default {
|
|||
return 0
|
||||
})
|
||||
this.currentAction.paramFields = []
|
||||
this.currentAction.paramFilters = []
|
||||
if ('message' in action) {
|
||||
var message = action.message
|
||||
if (typeof action.message === 'function') {
|
||||
|
|
@ -1092,6 +1096,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') {
|
||||
|
|
@ -1121,22 +1148,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 () {
|
||||
|
|
@ -1149,13 +1168,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)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue