mirror of https://github.com/apache/cloudstack.git
Merge branch '4.22'
This commit is contained in:
commit
420bf6dff8
|
|
@ -1216,6 +1216,7 @@ public class ApiConstants {
|
||||||
public static final String DOCKER_REGISTRY_EMAIL = "dockerregistryemail";
|
public static final String DOCKER_REGISTRY_EMAIL = "dockerregistryemail";
|
||||||
public static final String ISO_NAME = "isoname";
|
public static final String ISO_NAME = "isoname";
|
||||||
public static final String ISO_STATE = "isostate";
|
public static final String ISO_STATE = "isostate";
|
||||||
|
public static final String ISO_URL = "isourl";
|
||||||
public static final String SEMANTIC_VERSION = "semanticversion";
|
public static final String SEMANTIC_VERSION = "semanticversion";
|
||||||
public static final String KUBERNETES_VERSION_ID = "kubernetesversionid";
|
public static final String KUBERNETES_VERSION_ID = "kubernetesversionid";
|
||||||
public static final String KUBERNETES_VERSION_NAME = "kubernetesversionname";
|
public static final String KUBERNETES_VERSION_NAME = "kubernetesversionname";
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
final String target = command.getDestinationIp();
|
final String target = command.getDestinationIp();
|
||||||
xmlDesc = dm.getXMLDesc(xmlFlag);
|
xmlDesc = dm.getXMLDesc(xmlFlag);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("VM [%s] with XML configuration [%s] will be migrated to host [%s].", vmName, xmlDesc, target));
|
logger.debug("VM {} with XML configuration {} will be migrated to host {}.", vmName, maskSensitiveInfoInXML(xmlDesc), target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the VNC password in case the length is greater than 8 characters
|
// Limit the VNC password in case the length is greater than 8 characters
|
||||||
|
|
@ -178,7 +178,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
logger.debug(String.format("Editing mount path of ISO from %s to %s", oldIsoVolumePath, newIsoVolumePath));
|
logger.debug(String.format("Editing mount path of ISO from %s to %s", oldIsoVolumePath, newIsoVolumePath));
|
||||||
xmlDesc = replaceDiskSourceFile(xmlDesc, newIsoVolumePath, vmName);
|
xmlDesc = replaceDiskSourceFile(xmlDesc, newIsoVolumePath, vmName);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Replaced disk mount point [%s] with [%s] in Instance [%s] XML configuration. New XML configuration is [%s].", oldIsoVolumePath, newIsoVolumePath, vmName, xmlDesc));
|
logger.debug("Replaced disk mount point {} with {} in Instance {} XML configuration. New XML configuration is {}.", oldIsoVolumePath, newIsoVolumePath, vmName, maskSensitiveInfoInXML(xmlDesc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,11 +209,11 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
|
|
||||||
if (migrateStorage) {
|
if (migrateStorage) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Changing VM [%s] volumes during migration to host: [%s].", vmName, target));
|
logger.debug("Changing VM {} volumes during migration to host: {}.", vmName, target);
|
||||||
}
|
}
|
||||||
xmlDesc = replaceStorage(xmlDesc, mapMigrateStorage, migrateStorageManaged);
|
xmlDesc = replaceStorage(xmlDesc, mapMigrateStorage, migrateStorageManaged);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Changed VM [%s] XML configuration of used storage. New XML configuration is [%s].", vmName, xmlDesc));
|
logger.debug("Changed VM {} XML configuration of used storage. New XML configuration is {}.", vmName, maskSensitiveInfoInXML(xmlDesc));
|
||||||
}
|
}
|
||||||
migrateDiskLabels = getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
|
migrateDiskLabels = getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
|
||||||
}
|
}
|
||||||
|
|
@ -221,11 +221,11 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
Map<String, DpdkTO> dpdkPortsMapping = command.getDpdkInterfaceMapping();
|
Map<String, DpdkTO> dpdkPortsMapping = command.getDpdkInterfaceMapping();
|
||||||
if (MapUtils.isNotEmpty(dpdkPortsMapping)) {
|
if (MapUtils.isNotEmpty(dpdkPortsMapping)) {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace(String.format("Changing VM [%s] DPDK interfaces during migration to host: [%s].", vmName, target));
|
logger.trace("Changing VM {} DPDK interfaces during migration to host: {}.", vmName, target);
|
||||||
}
|
}
|
||||||
xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping);
|
xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Changed VM [%s] XML configuration of DPDK interfaces. New XML configuration is [%s].", vmName, xmlDesc));
|
logger.debug("Changed VM {} XML configuration of DPDK interfaces. New XML configuration is {}.", vmName, maskSensitiveInfoInXML(xmlDesc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,7 +240,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
}
|
}
|
||||||
|
|
||||||
//run migration in thread so we can monitor it
|
//run migration in thread so we can monitor it
|
||||||
logger.info(String.format("Starting live migration of instance [%s] to destination host [%s] having the final XML configuration: [%s].", vmName, dconn.getURI(), xmlDesc));
|
logger.info("Starting live migration of instance {} to destination host {} having the final XML configuration: {}.", vmName, dconn.getURI(), maskSensitiveInfoInXML(xmlDesc));
|
||||||
final ExecutorService executor = Executors.newFixedThreadPool(1);
|
final ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||||
boolean migrateNonSharedInc = command.isMigrateNonSharedInc() && !migrateStorageManaged;
|
boolean migrateNonSharedInc = command.isMigrateNonSharedInc() && !migrateStorageManaged;
|
||||||
|
|
||||||
|
|
@ -256,20 +256,21 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
final Future<Domain> migrateThread = executor.submit(worker);
|
final Future<Domain> migrateThread = executor.submit(worker);
|
||||||
executor.shutdown();
|
executor.shutdown();
|
||||||
long sleeptime = 0;
|
long sleeptime = 0;
|
||||||
|
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
|
||||||
|
boolean isMigrateDowntimeSet = false;
|
||||||
|
|
||||||
while (!executor.isTerminated()) {
|
while (!executor.isTerminated()) {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
sleeptime += 100;
|
sleeptime += 100;
|
||||||
if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
|
if (!isMigrateDowntimeSet && migrateDowntime > 0 && sleeptime >= 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
|
||||||
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
|
try {
|
||||||
if (migrateDowntime > 0 ) {
|
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
|
||||||
try {
|
if (setDowntime == 0 ) {
|
||||||
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
|
isMigrateDowntimeSet = true;
|
||||||
if (setDowntime == 0 ) {
|
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
|
||||||
logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
|
|
||||||
}
|
|
||||||
} catch (final LibvirtException e) {
|
|
||||||
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
} catch (final LibvirtException e) {
|
||||||
|
logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sleeptime % 1000 == 0) {
|
if (sleeptime % 1000 == 0) {
|
||||||
|
|
@ -287,7 +288,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
} catch (final LibvirtException e) {
|
} catch (final LibvirtException e) {
|
||||||
logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
|
logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
|
||||||
}
|
}
|
||||||
if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) {
|
if (state != null && (state == DomainState.VIR_DOMAIN_RUNNING || state == DomainState.VIR_DOMAIN_PAUSED)) {
|
||||||
try {
|
try {
|
||||||
DomainJobInfo job = dm.getJobInfo();
|
DomainJobInfo job = dm.getJobInfo();
|
||||||
logger.warn("Aborting migration of VM {} with domain job [{}] due to timeout after {} seconds. " +
|
logger.warn("Aborting migration of VM {} with domain job [{}] due to timeout after {} seconds. " +
|
||||||
|
|
@ -334,6 +335,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName));
|
logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName));
|
||||||
}
|
}
|
||||||
|
resumeDomainIfPaused(destDomain, vmName);
|
||||||
deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks);
|
deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks);
|
||||||
libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks);
|
libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks);
|
||||||
}
|
}
|
||||||
|
|
@ -408,6 +410,28 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
return new MigrateAnswer(command, result == null, result, null);
|
return new MigrateAnswer(command, result == null, result, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DomainState getDestDomainState(Domain destDomain, String vmName) {
|
||||||
|
DomainState dmState = null;
|
||||||
|
try {
|
||||||
|
dmState = destDomain.getInfo().state;
|
||||||
|
} catch (final LibvirtException e) {
|
||||||
|
logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return dmState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resumeDomainIfPaused(Domain destDomain, String vmName) {
|
||||||
|
DomainState dmState = getDestDomainState(destDomain, vmName);
|
||||||
|
if (dmState == DomainState.VIR_DOMAIN_PAUSED) {
|
||||||
|
logger.info("Resuming VM " + vmName + " on destination after migration");
|
||||||
|
try {
|
||||||
|
destDomain.resume();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage.
|
* Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage.
|
||||||
* @param diskDefinitions list of all the disksDefinitions of the VM.
|
* @param diskDefinitions list of all the disksDefinitions of the VM.
|
||||||
|
|
@ -715,9 +739,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
graphElem = graphElem.replaceAll("passwd='([^\\s]+)'", "passwd='" + vncPassword + "'");
|
graphElem = graphElem.replaceAll("passwd='([^\\s]+)'", "passwd='" + vncPassword + "'");
|
||||||
}
|
}
|
||||||
xmlDesc = xmlDesc.replaceAll(GRAPHICS_ELEM_START + CONTENTS_WILDCARD + GRAPHICS_ELEM_END, graphElem);
|
xmlDesc = xmlDesc.replaceAll(GRAPHICS_ELEM_START + CONTENTS_WILDCARD + GRAPHICS_ELEM_END, graphElem);
|
||||||
if (logger.isDebugEnabled()) {
|
logger.debug("Replaced the VNC IP address {} with {} in VM {}.", maskSensitiveInfoInXML(originalGraphElem), maskSensitiveInfoInXML(graphElem), vmName);
|
||||||
logger.debug(String.format("Replaced the VNC IP address [%s] with [%s] in VM [%s].", originalGraphElem, graphElem, vmName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return xmlDesc;
|
return xmlDesc;
|
||||||
|
|
@ -1036,4 +1058,10 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String maskSensitiveInfoInXML(String xmlDesc) {
|
||||||
|
if (xmlDesc == null) return null;
|
||||||
|
return xmlDesc.replaceAll("(graphics\\s+[^>]*type=['\"]vnc['\"][^>]*passwd=['\"])([^'\"]*)(['\"])",
|
||||||
|
"$1*****$3");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,9 @@ public final class LibvirtStartCommandWrapper extends CommandWrapper<StartComman
|
||||||
}
|
}
|
||||||
|
|
||||||
libvirtComputingResource.createVifs(vmSpec, vm);
|
libvirtComputingResource.createVifs(vmSpec, vm);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("starting " + vmName + ": " + vm.toString());
|
logger.debug("Starting {} : {}", vmName, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(vm.toString()));
|
||||||
|
}
|
||||||
String vmInitialSpecification = vm.toString();
|
String vmInitialSpecification = vm.toString();
|
||||||
String vmFinalSpecification = performXmlTransformHook(vmInitialSpecification, libvirtComputingResource);
|
String vmFinalSpecification = performXmlTransformHook(vmInitialSpecification, libvirtComputingResource);
|
||||||
libvirtComputingResource.startVM(conn, vmName, vmFinalSpecification);
|
libvirtComputingResource.startVM(conn, vmName, vmFinalSpecification);
|
||||||
|
|
|
||||||
|
|
@ -658,7 +658,7 @@ public class LibvirtMigrateCommandWrapperTest {
|
||||||
@Test
|
@Test
|
||||||
public void testReplaceIpForVNCInDescFile() {
|
public void testReplaceIpForVNCInDescFile() {
|
||||||
final String targetIp = "192.168.22.21";
|
final String targetIp = "192.168.22.21";
|
||||||
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, null, "");
|
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, "vncSecretPwd", "");
|
||||||
assertEquals("transformation does not live up to expectation:\n" + result, targetfile, result);
|
assertEquals("transformation does not live up to expectation:\n" + result, targetfile, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1089,6 +1089,30 @@ public class LibvirtMigrateCommandWrapperTest {
|
||||||
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
|
Assert.assertTrue(finalXml.contains(newIsoVolumePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaskVncPwdDomain() {
|
||||||
|
// Test case 1: Single quotes
|
||||||
|
String xml1 = "<graphics type='vnc' port='5900' passwd='secret123'/>";
|
||||||
|
String expected1 = "<graphics type='vnc' port='5900' passwd='*****'/>";
|
||||||
|
assertEquals(expected1, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml1));
|
||||||
|
|
||||||
|
// Test case 2: Double quotes
|
||||||
|
String xml2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"mypassword\"/>";
|
||||||
|
String expected2 = "<graphics type=\"vnc\" port=\"5901\" passwd=\"*****\"/>";
|
||||||
|
assertEquals(expected2, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml2));
|
||||||
|
|
||||||
|
// Test case 3: Non-VNC graphics (should remain unchanged)
|
||||||
|
String xml3 = "<graphics type='spice' port='5902' passwd='notvnc'/>";
|
||||||
|
assertEquals(xml3, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml3));
|
||||||
|
|
||||||
|
// Test case 4: Multiple VNC entries in one string
|
||||||
|
String xml4 = "<graphics type='vnc' port='5900' passwd='a'/>\n" +
|
||||||
|
"<graphics type='vnc' port='5901' passwd='b'/>";
|
||||||
|
String expected4 = "<graphics type='vnc' port='5900' passwd='*****'/>\n" +
|
||||||
|
"<graphics type='vnc' port='5901' passwd='*****'/>";
|
||||||
|
assertEquals(expected4, LibvirtMigrateCommandWrapper.maskSensitiveInfoInXML(xml4));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateGpuDevicesIfNeededTestNoGpuDevice() throws Exception {
|
public void updateGpuDevicesIfNeededTestNoGpuDevice() throws Exception {
|
||||||
Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
|
Mockito.doReturn(virtualMachineTOMock).when(migrateCommandMock).getVirtualMachine();
|
||||||
|
|
|
||||||
|
|
@ -1383,8 +1383,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
||||||
}
|
}
|
||||||
|
|
||||||
totalAdditionalVms += additional;
|
totalAdditionalVms += additional;
|
||||||
long effectiveCpu = (long) so.getCpu() * so.getSpeed();
|
totalAdditionalCpuUnits += so.getCpu() * additional;
|
||||||
totalAdditionalCpuUnits += effectiveCpu * additional;
|
|
||||||
totalAdditionalRamMb += so.getRamSize() * additional;
|
totalAdditionalRamMb += so.getRamSize() * additional;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||||
import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse;
|
import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.cloud.api.query.dao.TemplateJoinDao;
|
import com.cloud.api.query.dao.TemplateJoinDao;
|
||||||
|
|
@ -57,6 +60,7 @@ import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.storage.dao.VMTemplateZoneDao;
|
import com.cloud.storage.dao.VMTemplateZoneDao;
|
||||||
import com.cloud.template.TemplateApiService;
|
import com.cloud.template.TemplateApiService;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.ComponentContext;
|
import com.cloud.utils.component.ComponentContext;
|
||||||
|
|
@ -84,12 +88,14 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
@Inject
|
@Inject
|
||||||
private DataCenterDao dataCenterDao;
|
private DataCenterDao dataCenterDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
private ImageStoreDao imageStoreDao;
|
||||||
|
@Inject
|
||||||
private TemplateApiService templateService;
|
private TemplateApiService templateService;
|
||||||
|
|
||||||
public static final String MINIMUN_AUTOSCALER_SUPPORTED_VERSION = "1.15.0";
|
public static final String MINIMUN_AUTOSCALER_SUPPORTED_VERSION = "1.15.0";
|
||||||
|
|
||||||
protected void updateTemplateDetailsInKubernetesSupportedVersionResponse(
|
protected void updateTemplateDetailsInKubernetesSupportedVersionResponse(
|
||||||
final KubernetesSupportedVersion kubernetesSupportedVersion, KubernetesSupportedVersionResponse response) {
|
final KubernetesSupportedVersion kubernetesSupportedVersion, KubernetesSupportedVersionResponse response, boolean isRootAdmin) {
|
||||||
TemplateJoinVO template = templateJoinDao.findById(kubernetesSupportedVersion.getIsoId());
|
TemplateJoinVO template = templateJoinDao.findById(kubernetesSupportedVersion.getIsoId());
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -99,11 +105,14 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
if (template.getState() != null) {
|
if (template.getState() != null) {
|
||||||
response.setIsoState(template.getState().toString());
|
response.setIsoState(template.getState().toString());
|
||||||
}
|
}
|
||||||
|
if (isRootAdmin) {
|
||||||
|
response.setIsoUrl(template.getUrl());
|
||||||
|
}
|
||||||
response.setIsoArch(template.getArch().getType());
|
response.setIsoArch(template.getArch().getType());
|
||||||
response.setDirectDownload(template.isDirectDownload());
|
response.setDirectDownload(template.isDirectDownload());
|
||||||
}
|
}
|
||||||
|
|
||||||
private KubernetesSupportedVersionResponse createKubernetesSupportedVersionResponse(final KubernetesSupportedVersion kubernetesSupportedVersion) {
|
private KubernetesSupportedVersionResponse createKubernetesSupportedVersionResponse(final KubernetesSupportedVersion kubernetesSupportedVersion, boolean isRootAdmin) {
|
||||||
KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse();
|
KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse();
|
||||||
response.setObjectName("kubernetessupportedversion");
|
response.setObjectName("kubernetessupportedversion");
|
||||||
response.setId(kubernetesSupportedVersion.getUuid());
|
response.setId(kubernetesSupportedVersion.getUuid());
|
||||||
|
|
@ -122,7 +131,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
response.setSupportsHA(compareSemanticVersions(kubernetesSupportedVersion.getSemanticVersion(),
|
response.setSupportsHA(compareSemanticVersions(kubernetesSupportedVersion.getSemanticVersion(),
|
||||||
KubernetesClusterService.MIN_KUBERNETES_VERSION_HA_SUPPORT)>=0);
|
KubernetesClusterService.MIN_KUBERNETES_VERSION_HA_SUPPORT)>=0);
|
||||||
response.setSupportsAutoscaling(versionSupportsAutoscaling(kubernetesSupportedVersion));
|
response.setSupportsAutoscaling(versionSupportsAutoscaling(kubernetesSupportedVersion));
|
||||||
updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, response);
|
updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, response, isRootAdmin);
|
||||||
response.setCreated(kubernetesSupportedVersion.getCreated());
|
response.setCreated(kubernetesSupportedVersion.getCreated());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
@ -130,8 +139,11 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
private ListResponse<KubernetesSupportedVersionResponse> createKubernetesSupportedVersionListResponse(
|
private ListResponse<KubernetesSupportedVersionResponse> createKubernetesSupportedVersionListResponse(
|
||||||
List<KubernetesSupportedVersionVO> versions, Integer count) {
|
List<KubernetesSupportedVersionVO> versions, Integer count) {
|
||||||
List<KubernetesSupportedVersionResponse> responseList = new ArrayList<>();
|
List<KubernetesSupportedVersionResponse> responseList = new ArrayList<>();
|
||||||
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
|
boolean isRootAdmin = accountManager.isRootAdmin(caller.getId());
|
||||||
|
|
||||||
for (KubernetesSupportedVersionVO version : versions) {
|
for (KubernetesSupportedVersionVO version : versions) {
|
||||||
responseList.add(createKubernetesSupportedVersionResponse(version));
|
responseList.add(createKubernetesSupportedVersionResponse(version, isRootAdmin));
|
||||||
}
|
}
|
||||||
ListResponse<KubernetesSupportedVersionResponse> response = new ListResponse<>();
|
ListResponse<KubernetesSupportedVersionResponse> response = new ListResponse<>();
|
||||||
response.setResponses(responseList, count);
|
response.setResponses(responseList, count);
|
||||||
|
|
@ -347,6 +359,32 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
return createKubernetesSupportedVersionListResponse(versions, versionsAndCount.second());
|
return createKubernetesSupportedVersionListResponse(versions, versionsAndCount.second());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateImageStoreForZone(Long zoneId, boolean directDownload) {
|
||||||
|
if (directDownload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (zoneId != null) {
|
||||||
|
List<ImageStoreVO> imageStores = imageStoreDao.listStoresByZoneId(zoneId);
|
||||||
|
if (CollectionUtils.isEmpty(imageStores)) {
|
||||||
|
DataCenterVO zone = dataCenterDao.findById(zoneId);
|
||||||
|
String zoneName = zone != null ? zone.getName() : String.valueOf(zoneId);
|
||||||
|
throw new InvalidParameterValueException(String.format("Unable to register Kubernetes version ISO. No image store available in zone: %s", zoneName));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<DataCenterVO> zones = dataCenterDao.listAllZones();
|
||||||
|
List<String> zonesWithoutStorage = new ArrayList<>();
|
||||||
|
for (DataCenterVO zone : zones) {
|
||||||
|
List<ImageStoreVO> imageStores = imageStoreDao.listStoresByZoneId(zone.getId());
|
||||||
|
if (CollectionUtils.isEmpty(imageStores)) {
|
||||||
|
zonesWithoutStorage.add(zone.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!zonesWithoutStorage.isEmpty()) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Unable to register Kubernetes version ISO for all zones. The following zones have no image store: %s", String.join(", ", zonesWithoutStorage)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateKubernetesSupportedVersion(Long zoneId, String semanticVersion, Integer minimumCpu,
|
private void validateKubernetesSupportedVersion(Long zoneId, String semanticVersion, Integer minimumCpu,
|
||||||
Integer minimumRamSize, boolean isDirectDownload) {
|
Integer minimumRamSize, boolean isDirectDownload) {
|
||||||
if (minimumCpu == null || minimumCpu < KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU) {
|
if (minimumCpu == null || minimumCpu < KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU) {
|
||||||
|
|
@ -398,6 +436,8 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateImageStoreForZone(zoneId, isDirectDownload);
|
||||||
|
|
||||||
VMTemplateVO template = null;
|
VMTemplateVO template = null;
|
||||||
try {
|
try {
|
||||||
VirtualMachineTemplate vmTemplate = registerKubernetesVersionIso(zoneId, name, isoUrl, isoChecksum, isDirectDownload, arch);
|
VirtualMachineTemplate vmTemplate = registerKubernetesVersionIso(zoneId, name, isoUrl, isoChecksum, isDirectDownload, arch);
|
||||||
|
|
@ -411,7 +451,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
supportedVersionVO = kubernetesSupportedVersionDao.persist(supportedVersionVO);
|
supportedVersionVO = kubernetesSupportedVersionDao.persist(supportedVersionVO);
|
||||||
CallContext.current().putContextParameter(KubernetesSupportedVersion.class, supportedVersionVO.getUuid());
|
CallContext.current().putContextParameter(KubernetesSupportedVersion.class, supportedVersionVO.getUuid());
|
||||||
|
|
||||||
return createKubernetesSupportedVersionResponse(supportedVersionVO);
|
return createKubernetesSupportedVersionResponse(supportedVersionVO, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -496,7 +536,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
||||||
}
|
}
|
||||||
version = kubernetesSupportedVersionDao.findById(versionId);
|
version = kubernetesSupportedVersionDao.findById(versionId);
|
||||||
}
|
}
|
||||||
return createKubernetesSupportedVersionResponse(version);
|
return createKubernetesSupportedVersionResponse(version, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ public class KubernetesSupportedVersionResponse extends BaseResponse {
|
||||||
@Param(description = "The name of the binaries ISO for Kubernetes supported version")
|
@Param(description = "The name of the binaries ISO for Kubernetes supported version")
|
||||||
private String isoName;
|
private String isoName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ISO_URL)
|
||||||
|
@Param(description = "the URL of the binaries ISO for Kubernetes supported version")
|
||||||
|
private String isoUrl;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.ISO_STATE)
|
@SerializedName(ApiConstants.ISO_STATE)
|
||||||
@Param(description = "The state of the binaries ISO for Kubernetes supported version")
|
@Param(description = "The state of the binaries ISO for Kubernetes supported version")
|
||||||
private String isoState;
|
private String isoState;
|
||||||
|
|
@ -134,6 +138,14 @@ public class KubernetesSupportedVersionResponse extends BaseResponse {
|
||||||
this.isoName = isoName;
|
this.isoName = isoName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getIsoUrl() {
|
||||||
|
return isoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsoUrl(String isoUrl) {
|
||||||
|
this.isoUrl = isoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public String getIsoState() {
|
public String getIsoState() {
|
||||||
return isoState;
|
return isoState;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,15 @@
|
||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.kubernetes.version;
|
package com.cloud.kubernetes.version;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse;
|
import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
@ -32,6 +37,9 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import com.cloud.api.query.dao.TemplateJoinDao;
|
import com.cloud.api.query.dao.TemplateJoinDao;
|
||||||
import com.cloud.api.query.vo.TemplateJoinVO;
|
import com.cloud.api.query.vo.TemplateJoinVO;
|
||||||
import com.cloud.cpu.CPU;
|
import com.cloud.cpu.CPU;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class KubernetesVersionManagerImplTest {
|
public class KubernetesVersionManagerImplTest {
|
||||||
|
|
@ -39,6 +47,12 @@ public class KubernetesVersionManagerImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
TemplateJoinDao templateJoinDao;
|
TemplateJoinDao templateJoinDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
ImageStoreDao imageStoreDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DataCenterDao dataCenterDao;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
KubernetesVersionManagerImpl kubernetesVersionManager = new KubernetesVersionManagerImpl();
|
KubernetesVersionManagerImpl kubernetesVersionManager = new KubernetesVersionManagerImpl();
|
||||||
|
|
||||||
|
|
@ -48,7 +62,7 @@ public class KubernetesVersionManagerImplTest {
|
||||||
Mockito.when(kubernetesSupportedVersion.getIsoId()).thenReturn(1L);
|
Mockito.when(kubernetesSupportedVersion.getIsoId()).thenReturn(1L);
|
||||||
KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse();
|
KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse();
|
||||||
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
||||||
response);
|
response, true);
|
||||||
Assert.assertNull(ReflectionTestUtils.getField(response, "isoId"));
|
Assert.assertNull(ReflectionTestUtils.getField(response, "isoId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,13 +77,71 @@ public class KubernetesVersionManagerImplTest {
|
||||||
Mockito.when(templateJoinVO.getUuid()).thenReturn(uuid);
|
Mockito.when(templateJoinVO.getUuid()).thenReturn(uuid);
|
||||||
Mockito.when(templateJoinDao.findById(1L)).thenReturn(templateJoinVO);
|
Mockito.when(templateJoinDao.findById(1L)).thenReturn(templateJoinVO);
|
||||||
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
||||||
response);
|
response, true);
|
||||||
Assert.assertEquals(uuid, ReflectionTestUtils.getField(response, "isoId"));
|
Assert.assertEquals(uuid, ReflectionTestUtils.getField(response, "isoId"));
|
||||||
Assert.assertNull(ReflectionTestUtils.getField(response, "isoState"));
|
Assert.assertNull(ReflectionTestUtils.getField(response, "isoState"));
|
||||||
ObjectInDataStoreStateMachine.State state = ObjectInDataStoreStateMachine.State.Ready;
|
ObjectInDataStoreStateMachine.State state = ObjectInDataStoreStateMachine.State.Ready;
|
||||||
Mockito.when(templateJoinVO.getState()).thenReturn(state);
|
Mockito.when(templateJoinVO.getState()).thenReturn(state);
|
||||||
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion,
|
||||||
response);
|
response, true);
|
||||||
Assert.assertEquals(state.toString(), ReflectionTestUtils.getField(response, "isoState"));
|
Assert.assertEquals(state.toString(), ReflectionTestUtils.getField(response, "isoState"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateImageStoreForZoneWithDirectDownload() {
|
||||||
|
ReflectionTestUtils.invokeMethod(kubernetesVersionManager, "validateImageStoreForZone", 1L, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateImageStoreForZoneWithValidZone() {
|
||||||
|
Long zoneId = 1L;
|
||||||
|
List<ImageStoreVO> imageStores = Collections.singletonList(Mockito.mock(ImageStoreVO.class));
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(zoneId)).thenReturn(imageStores);
|
||||||
|
|
||||||
|
ReflectionTestUtils.invokeMethod(kubernetesVersionManager, "validateImageStoreForZone", zoneId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateImageStoreForZoneWithNoImageStore() {
|
||||||
|
Long zoneId = 1L;
|
||||||
|
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
|
||||||
|
Mockito.when(zone.getName()).thenReturn("test-zone");
|
||||||
|
Mockito.when(dataCenterDao.findById(zoneId)).thenReturn(zone);
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(zoneId)).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
ReflectionTestUtils.invokeMethod(kubernetesVersionManager, "validateImageStoreForZone", zoneId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateImageStoreForAllZonesWithAllValid() {
|
||||||
|
DataCenterVO zone1 = Mockito.mock(DataCenterVO.class);
|
||||||
|
Mockito.when(zone1.getId()).thenReturn(1L);
|
||||||
|
DataCenterVO zone2 = Mockito.mock(DataCenterVO.class);
|
||||||
|
Mockito.when(zone2.getId()).thenReturn(2L);
|
||||||
|
List<DataCenterVO> zones = Arrays.asList(zone1, zone2);
|
||||||
|
Mockito.when(dataCenterDao.listAllZones()).thenReturn(zones);
|
||||||
|
|
||||||
|
List<ImageStoreVO> imageStores = Collections.singletonList(Mockito.mock(ImageStoreVO.class));
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(1L)).thenReturn(imageStores);
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(2L)).thenReturn(imageStores);
|
||||||
|
|
||||||
|
ReflectionTestUtils.invokeMethod(kubernetesVersionManager, "validateImageStoreForZone", (Long) null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateImageStoreForAllZonesWithSomeMissingStorage() {
|
||||||
|
DataCenterVO zone1 = Mockito.mock(DataCenterVO.class);
|
||||||
|
Mockito.when(zone1.getId()).thenReturn(1L);
|
||||||
|
DataCenterVO zone2 = Mockito.mock(DataCenterVO.class);
|
||||||
|
Mockito.when(zone2.getId()).thenReturn(2L);
|
||||||
|
Mockito.when(zone2.getName()).thenReturn("zone-without-storage");
|
||||||
|
List<DataCenterVO> zones = Arrays.asList(zone1, zone2);
|
||||||
|
Mockito.when(dataCenterDao.listAllZones()).thenReturn(zones);
|
||||||
|
|
||||||
|
List<ImageStoreVO> imageStores = Collections.singletonList(Mockito.mock(ImageStoreVO.class));
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(1L)).thenReturn(imageStores);
|
||||||
|
Mockito.when(imageStoreDao.listStoresByZoneId(2L)).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
ReflectionTestUtils.invokeMethod(kubernetesVersionManager, "validateImageStoreForZone", (Long) null, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
package com.cloud.kubernetes.version;
|
package com.cloud.kubernetes.version;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
@ -25,6 +28,11 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.cloud.cpu.CPU;
|
import com.cloud.cpu.CPU;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
|
import com.cloud.user.AccountVO;
|
||||||
|
import com.cloud.user.User;
|
||||||
|
import com.cloud.user.UserVO;
|
||||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd;
|
import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.DeleteKubernetesSupportedVersionCmd;
|
import org.apache.cloudstack.api.command.admin.kubernetes.version.DeleteKubernetesSupportedVersionCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.UpdateKubernetesSupportedVersionCmd;
|
import org.apache.cloudstack.api.command.admin.kubernetes.version.UpdateKubernetesSupportedVersionCmd;
|
||||||
|
|
@ -63,11 +71,6 @@ import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.template.TemplateApiService;
|
import com.cloud.template.TemplateApiService;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.user.Account;
|
|
||||||
import com.cloud.user.AccountManager;
|
|
||||||
import com.cloud.user.AccountVO;
|
|
||||||
import com.cloud.user.User;
|
|
||||||
import com.cloud.user.UserVO;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.ComponentContext;
|
import com.cloud.utils.component.ComponentContext;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
|
|
@ -75,6 +78,9 @@ import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class KubernetesVersionServiceTest {
|
public class KubernetesVersionServiceTest {
|
||||||
|
|
||||||
|
|
@ -94,7 +100,11 @@ public class KubernetesVersionServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
private DataCenterDao dataCenterDao;
|
private DataCenterDao dataCenterDao;
|
||||||
@Mock
|
@Mock
|
||||||
|
private ImageStoreDao imageStoreDao;
|
||||||
|
@Mock
|
||||||
private TemplateApiService templateService;
|
private TemplateApiService templateService;
|
||||||
|
@Mock
|
||||||
|
private Account accountMock;
|
||||||
|
|
||||||
AutoCloseable closeable;
|
AutoCloseable closeable;
|
||||||
|
|
||||||
|
|
@ -123,7 +133,12 @@ public class KubernetesVersionServiceTest {
|
||||||
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
|
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
|
||||||
when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
|
when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
|
||||||
|
|
||||||
|
List<ImageStoreVO> imageStores = new ArrayList<>();
|
||||||
|
imageStores.add(Mockito.mock(ImageStoreVO.class));
|
||||||
|
when(imageStoreDao.listStoresByZoneId(Mockito.anyLong())).thenReturn(imageStores);
|
||||||
|
|
||||||
TemplateJoinVO templateJoinVO = Mockito.mock(TemplateJoinVO.class);
|
TemplateJoinVO templateJoinVO = Mockito.mock(TemplateJoinVO.class);
|
||||||
|
when(templateJoinVO.getUrl()).thenReturn("https://download.cloudstack.com");
|
||||||
when(templateJoinVO.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
|
when(templateJoinVO.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
when(templateJoinVO.getArch()).thenReturn(CPU.CPUArch.getDefault());
|
when(templateJoinVO.getArch()).thenReturn(CPU.CPUArch.getDefault());
|
||||||
when(templateJoinDao.findById(Mockito.anyLong())).thenReturn(templateJoinVO);
|
when(templateJoinDao.findById(Mockito.anyLong())).thenReturn(templateJoinVO);
|
||||||
|
|
@ -140,19 +155,66 @@ public class KubernetesVersionServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void listKubernetesSupportedVersionsTest() {
|
public void listKubernetesSupportedVersionsTest() {
|
||||||
ListKubernetesSupportedVersionsCmd cmd = Mockito.mock(ListKubernetesSupportedVersionsCmd.class);
|
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||||
List<KubernetesSupportedVersionVO> versionVOs = new ArrayList<>();
|
try (MockedStatic<CallContext> callContextMockedStatic = Mockito.mockStatic(CallContext.class)) {
|
||||||
KubernetesSupportedVersionVO versionVO = Mockito.mock(KubernetesSupportedVersionVO.class);
|
callContextMockedStatic.when(CallContext::current).thenReturn(callContextMock);
|
||||||
when(versionVO.getSemanticVersion()).thenReturn(KubernetesVersionService.MIN_KUBERNETES_VERSION);
|
final SearchCriteria<KubernetesSupportedVersionVO> versionSearchCriteria = Mockito.mock(SearchCriteria.class);
|
||||||
versionVOs.add(versionVO);
|
when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||||
when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(versionVO);
|
ListKubernetesSupportedVersionsCmd cmd = Mockito.mock(ListKubernetesSupportedVersionsCmd.class);
|
||||||
when(kubernetesSupportedVersionDao.searchAndCount(Mockito.any(SearchCriteria.class),
|
List<KubernetesSupportedVersionVO> versionVOs = new ArrayList<>();
|
||||||
Mockito.any(Filter.class))).thenReturn(new Pair<>(versionVOs, versionVOs.size()));
|
KubernetesSupportedVersionVO versionVO = Mockito.mock(KubernetesSupportedVersionVO.class);
|
||||||
ListResponse<KubernetesSupportedVersionResponse> versionsResponse =
|
when(versionVO.getSemanticVersion()).thenReturn(KubernetesVersionService.MIN_KUBERNETES_VERSION);
|
||||||
kubernetesVersionService.listKubernetesSupportedVersions(cmd);
|
versionVOs.add(versionVO);
|
||||||
Assert.assertEquals(versionVOs.size(), versionsResponse.getCount().intValue());
|
when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(versionVO);
|
||||||
Assert.assertTrue(CollectionUtils.isNotEmpty(versionsResponse.getResponses()));
|
when(kubernetesSupportedVersionDao.searchAndCount(Mockito.any(), Mockito.any(Filter.class)))
|
||||||
Assert.assertEquals(versionVOs.size(), versionsResponse.getResponses().size());
|
.thenReturn(new Pair<>(versionVOs, versionVOs.size()));
|
||||||
|
ListResponse<KubernetesSupportedVersionResponse> versionsResponse =
|
||||||
|
kubernetesVersionService.listKubernetesSupportedVersions(cmd);
|
||||||
|
Assert.assertEquals(versionVOs.size(), versionsResponse.getCount().intValue());
|
||||||
|
Assert.assertTrue(CollectionUtils.isNotEmpty(versionsResponse.getResponses()));
|
||||||
|
Assert.assertEquals(versionVOs.size(), versionsResponse.getResponses().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listKubernetesSupportedVersionsTestWhenAdmin() {
|
||||||
|
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||||
|
try (MockedStatic<CallContext> callContextMockedStatic = Mockito.mockStatic(CallContext.class)) {
|
||||||
|
callContextMockedStatic.when(CallContext::current).thenReturn(callContextMock);
|
||||||
|
ListKubernetesSupportedVersionsCmd cmd = Mockito.mock(ListKubernetesSupportedVersionsCmd.class);
|
||||||
|
List<KubernetesSupportedVersionVO> versionVOs = new ArrayList<>();
|
||||||
|
KubernetesSupportedVersionVO versionVO = Mockito.mock(KubernetesSupportedVersionVO.class);
|
||||||
|
when(versionVO.getSemanticVersion()).thenReturn(KubernetesVersionService.MIN_KUBERNETES_VERSION);
|
||||||
|
versionVOs.add(versionVO);
|
||||||
|
when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||||
|
when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(versionVO);
|
||||||
|
when(kubernetesSupportedVersionDao.searchAndCount(Mockito.any(), Mockito.any(Filter.class)))
|
||||||
|
.thenReturn(new Pair<>(versionVOs, versionVOs.size()));
|
||||||
|
when(accountManager.isRootAdmin(anyLong())).thenReturn(true);
|
||||||
|
ListResponse<KubernetesSupportedVersionResponse> response = kubernetesVersionService.listKubernetesSupportedVersions(cmd);
|
||||||
|
assertNotNull(response.getResponses().get(0).getIsoUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listKubernetesSupportedVersionsTestWhenOtherUser() {
|
||||||
|
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||||
|
try (MockedStatic<CallContext> callContextMockedStatic = Mockito.mockStatic(CallContext.class)) {
|
||||||
|
callContextMockedStatic.when(CallContext::current).thenReturn(callContextMock);
|
||||||
|
ListKubernetesSupportedVersionsCmd cmd = Mockito.mock(ListKubernetesSupportedVersionsCmd.class);
|
||||||
|
List<KubernetesSupportedVersionVO> versionVOs = new ArrayList<>();
|
||||||
|
KubernetesSupportedVersionVO versionVO = Mockito.mock(KubernetesSupportedVersionVO.class);
|
||||||
|
when(versionVO.getSemanticVersion()).thenReturn(KubernetesVersionService.MIN_KUBERNETES_VERSION);
|
||||||
|
versionVOs.add(versionVO);
|
||||||
|
when(callContextMock.getCallingAccount()).thenReturn(accountMock);
|
||||||
|
when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(versionVO);
|
||||||
|
when(kubernetesSupportedVersionDao.searchAndCount(Mockito.any(), Mockito.any(Filter.class)))
|
||||||
|
.thenReturn(new Pair<>(versionVOs, versionVOs.size()));
|
||||||
|
when(accountManager.isRootAdmin(anyLong())).thenReturn(false);
|
||||||
|
when(accountMock.getId()).thenReturn(2L);
|
||||||
|
ListResponse<KubernetesSupportedVersionResponse> response = kubernetesVersionService.listKubernetesSupportedVersions(cmd);
|
||||||
|
assertNull(response.getResponses().get(0).getIsoUrl());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = InvalidParameterValueException.class)
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
|
@ -224,7 +286,6 @@ public class KubernetesVersionServiceTest {
|
||||||
mockedComponentContext.when(() -> ComponentContext.inject(Mockito.any(RegisterIsoCmd.class))).thenReturn(
|
mockedComponentContext.when(() -> ComponentContext.inject(Mockito.any(RegisterIsoCmd.class))).thenReturn(
|
||||||
new RegisterIsoCmd());
|
new RegisterIsoCmd());
|
||||||
mockedCallContext.when(CallContext::current).thenReturn(callContext);
|
mockedCallContext.when(CallContext::current).thenReturn(callContext);
|
||||||
|
|
||||||
when(templateService.registerIso(Mockito.any(RegisterIsoCmd.class))).thenReturn(
|
when(templateService.registerIso(Mockito.any(RegisterIsoCmd.class))).thenReturn(
|
||||||
Mockito.mock(VirtualMachineTemplate.class));
|
Mockito.mock(VirtualMachineTemplate.class));
|
||||||
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
|
VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
|
||||||
|
|
|
||||||
|
|
@ -1801,14 +1801,18 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||||
|
|
||||||
protected String getStoragePoolNonDestroyedVolumesLog(long storagePoolId) {
|
protected String getStoragePoolNonDestroyedVolumesLog(long storagePoolId) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
List<VolumeVO> nonDestroyedVols = volumeDao.findByPoolId(storagePoolId, null).stream().filter(vol -> vol.getState() != Volume.State.Destroy).collect(Collectors.toList());
|
List<VolumeVO> nonDestroyedVols = volumeDao.findByPoolId(storagePoolId, null);
|
||||||
VMInstanceVO volInstance;
|
VMInstanceVO volInstance;
|
||||||
List<String> logMessageInfo = new ArrayList<>();
|
List<String> logMessageInfo = new ArrayList<>();
|
||||||
|
|
||||||
sb.append("[");
|
sb.append("[");
|
||||||
for (VolumeVO vol : nonDestroyedVols) {
|
for (VolumeVO vol : nonDestroyedVols) {
|
||||||
volInstance = _vmInstanceDao.findById(vol.getInstanceId());
|
volInstance = _vmInstanceDao.findById(vol.getInstanceId());
|
||||||
logMessageInfo.add(String.format("Volume [%s] (attached to VM [%s])", vol.getUuid(), volInstance.getUuid()));
|
if (volInstance != null) {
|
||||||
|
logMessageInfo.add(String.format("Volume [%s] (attached to VM [%s])", vol.getUuid(), volInstance.getUuid()));
|
||||||
|
} else {
|
||||||
|
logMessageInfo.add(String.format("Volume [%s]", vol.getUuid()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sb.append(String.join(", ", logMessageInfo));
|
sb.append(String.join(", ", logMessageInfo));
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import com.cloud.exception.StorageConflictException;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import com.cloud.utils.Profiler;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||||
|
|
@ -200,12 +201,13 @@ public class StoragePoolMonitor implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean processDisconnect(long agentId, Status state) {
|
public boolean processDisconnect(long agentId, Status state) {
|
||||||
return processDisconnect(agentId, null, null, state);
|
return processDisconnect(agentId, null, null, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean processDisconnect(long agentId, String uuid, String name, Status state) {
|
public boolean processDisconnect(long agentId, String uuid, String name, Status state) {
|
||||||
|
logger.debug("Starting disconnect for Agent [id: {}, uuid: {}, name: {}]", agentId, uuid, name);
|
||||||
Host host = _storageManager.getHost(agentId);
|
Host host = _storageManager.getHost(agentId);
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
logger.warn("Agent [id: {}, uuid: {}, name: {}] not found, not disconnecting pools", agentId, uuid, name);
|
logger.warn("Agent [id: {}, uuid: {}, name: {}] not found, not disconnecting pools", agentId, uuid, name);
|
||||||
|
|
@ -213,38 +215,52 @@ public class StoragePoolMonitor implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host.getType() != Host.Type.Routing) {
|
if (host.getType() != Host.Type.Routing) {
|
||||||
|
logger.debug("Host [id: {}, uuid: {}, name: {}] is not of type {}, skip", agentId, uuid, name, Host.Type.Routing);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("Looking for connected Storage Pools for Host [id: {}, uuid: {}, name: {}]", agentId, uuid, name);
|
||||||
List<StoragePoolHostVO> storagePoolHosts = _storageManager.findStoragePoolsConnectedToHost(host.getId());
|
List<StoragePoolHostVO> storagePoolHosts = _storageManager.findStoragePoolsConnectedToHost(host.getId());
|
||||||
if (storagePoolHosts == null) {
|
if (storagePoolHosts == null) {
|
||||||
if (logger.isTraceEnabled()) {
|
logger.debug("No pools to disconnect for host: {}", host);
|
||||||
logger.trace("No pools to disconnect for host: {}", host);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("Found {} pools to disconnect for host: {}", storagePoolHosts.size(), host);
|
||||||
boolean disconnectResult = true;
|
boolean disconnectResult = true;
|
||||||
for (StoragePoolHostVO storagePoolHost : storagePoolHosts) {
|
int storagePoolHostsSize = storagePoolHosts.size();
|
||||||
|
for (int i = 0; i < storagePoolHostsSize; i++) {
|
||||||
|
StoragePoolHostVO storagePoolHost = storagePoolHosts.get(i);
|
||||||
|
logger.debug("Processing disconnect from Storage Pool {} ({} of {}) for host: {}", storagePoolHost.getPoolId(), i, storagePoolHostsSize, host);
|
||||||
StoragePoolVO pool = _poolDao.findById(storagePoolHost.getPoolId());
|
StoragePoolVO pool = _poolDao.findById(storagePoolHost.getPoolId());
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
|
logger.debug("No Storage Pool found with id {} ({} of {}) for host: {}", storagePoolHost.getPoolId(), i, storagePoolHostsSize, host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pool.isShared()) {
|
if (!pool.isShared()) {
|
||||||
|
logger.debug("Storage Pool {} ({}) ({} of {}) is not shared for host: {}, ignore disconnect", pool.getName(), pool.getUuid(), i, storagePoolHostsSize, host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle only PowerFlex pool for now, not to impact other pools behavior
|
// Handle only PowerFlex pool for now, not to impact other pools behavior
|
||||||
if (pool.getPoolType() != StoragePoolType.PowerFlex) {
|
if (pool.getPoolType() != StoragePoolType.PowerFlex) {
|
||||||
|
logger.debug("Storage Pool {} ({}) ({} of {}) is not of type {} for host: {}, ignore disconnect", pool.getName(), pool.getUuid(), i, storagePoolHostsSize, pool.getPoolType(), host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("Sending disconnect to Storage Pool {} ({}) ({} of {}) for host: {}", pool.getName(), pool.getUuid(), i, storagePoolHostsSize, host);
|
||||||
|
Profiler disconnectProfiler = new Profiler();
|
||||||
try {
|
try {
|
||||||
|
disconnectProfiler.start();
|
||||||
_storageManager.disconnectHostFromSharedPool(host, pool);
|
_storageManager.disconnectHostFromSharedPool(host, pool);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Unable to disconnect host {} from storage pool {} due to {}", host, pool, e.toString());
|
logger.error("Unable to disconnect host {} from storage pool {} due to {}", host, pool, e.toString());
|
||||||
disconnectResult = false;
|
disconnectResult = false;
|
||||||
|
} finally {
|
||||||
|
disconnectProfiler.stop();
|
||||||
|
long disconnectDuration = disconnectProfiler.getDurationInMillis() / 1000;
|
||||||
|
logger.debug("Finished disconnect with result {} from Storage Pool {} ({}) ({} of {}) for host: {}, duration: {} secs", disconnectResult, pool.getName(), pool.getUuid(), i, storagePoolHostsSize, host, disconnectDuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1229,8 +1229,10 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar
|
||||||
if (dc.getDns2() != null) {
|
if (dc.getDns2() != null) {
|
||||||
buf.append(" dns2=").append(dc.getDns2());
|
buf.append(" dns2=").append(dc.getDns2());
|
||||||
}
|
}
|
||||||
String nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStores.get(0).getId()) : null;
|
String nfsVersion = imageStoreDetailsUtil.getNfsVersion(secStores.get(0).getId());
|
||||||
buf.append(" nfsVersion=").append(nfsVersion);
|
if (StringUtils.isNotBlank(nfsVersion)) {
|
||||||
|
buf.append(" nfsVersion=").append(nfsVersion);
|
||||||
|
}
|
||||||
buf.append(" keystore_password=").append(VirtualMachineGuru.getEncodedString(PasswordGenerator.generateRandomPassword(16)));
|
buf.append(" keystore_password=").append(VirtualMachineGuru.getEncodedString(PasswordGenerator.generateRandomPassword(16)));
|
||||||
|
|
||||||
if (SystemVmEnableUserData.valueIn(dc.getId())) {
|
if (SystemVmEnableUserData.valueIn(dc.getId())) {
|
||||||
|
|
|
||||||
|
|
@ -1382,6 +1382,7 @@
|
||||||
"label.isoname": "Attached ISO",
|
"label.isoname": "Attached ISO",
|
||||||
"label.isos": "ISOs",
|
"label.isos": "ISOs",
|
||||||
"label.isostate": "ISO state",
|
"label.isostate": "ISO state",
|
||||||
|
"label.isourl": "ISO URL",
|
||||||
"label.ispersistent": "Persistent ",
|
"label.ispersistent": "Persistent ",
|
||||||
"label.ispublic": "Public",
|
"label.ispublic": "Public",
|
||||||
"label.isready": "Ready",
|
"label.isready": "Ready",
|
||||||
|
|
|
||||||
|
|
@ -881,6 +881,7 @@
|
||||||
"label.isoname": "Imagem ISO plugada",
|
"label.isoname": "Imagem ISO plugada",
|
||||||
"label.isos": "ISOs",
|
"label.isos": "ISOs",
|
||||||
"label.isostate": "Estado da ISO",
|
"label.isostate": "Estado da ISO",
|
||||||
|
"label.isourl": "URL da ISO",
|
||||||
"label.ispersistent": "Persistente",
|
"label.ispersistent": "Persistente",
|
||||||
"label.ispublic": "P\u00fablico",
|
"label.ispublic": "P\u00fablico",
|
||||||
"label.isready": "Pronto",
|
"label.isready": "Pronto",
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,9 @@ export default {
|
||||||
details: () => {
|
details: () => {
|
||||||
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'arch', 'format', 'externalprovisioner', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'arch', 'format', 'externalprovisioner', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
||||||
'crossZones', 'templatetype', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
'crossZones', 'templatetype', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
||||||
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'forcks']
|
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url', 'forcks']
|
||||||
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
||||||
fields.push('templatetag', 'templatetype', 'url')
|
fields.push('templatetag', 'templatetype')
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
},
|
},
|
||||||
|
|
@ -373,7 +373,7 @@ export default {
|
||||||
permission: ['listKubernetesSupportedVersions'],
|
permission: ['listKubernetesSupportedVersions'],
|
||||||
searchFilters: ['zoneid', 'minimumsemanticversion', 'arch'],
|
searchFilters: ['zoneid', 'minimumsemanticversion', 'arch'],
|
||||||
columns: ['name', 'state', 'semanticversion', 'isostate', 'mincpunumber', 'minmemory', 'arch', 'zonename'],
|
columns: ['name', 'state', 'semanticversion', 'isostate', 'mincpunumber', 'minmemory', 'arch', 'zonename'],
|
||||||
details: ['name', 'semanticversion', 'supportsautoscaling', 'zoneid', 'zonename', 'isoid', 'isoname', 'isostate', 'arch', 'mincpunumber', 'minmemory', 'supportsha', 'state', 'created'],
|
details: ['name', 'semanticversion', 'supportsautoscaling', 'zoneid', 'zonename', 'isoid', 'isoname', 'isostate', 'arch', 'mincpunumber', 'minmemory', 'supportsha', 'state', 'created', 'isourl'],
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
name: 'details',
|
name: 'details',
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ export default {
|
||||||
postAPI('forgotPassword', loginParams)
|
postAPI('forgotPassword', loginParams)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.$message.success(this.$t('message.forgot.password.success'))
|
this.$message.success(this.$t('message.forgot.password.success'))
|
||||||
this.$router.push({ path: '/login' }).catch(() => {})
|
this.$router.replace({ path: '/user/login' })
|
||||||
})
|
})
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue