mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Merge remote-tracking branch 'apache/4.20'
This commit is contained in:
		
						commit
						8089d32740
					
				| @ -209,4 +209,9 @@ public class CreateSnapshotFromVMSnapshotCmd extends BaseAsyncCreateCmd { | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Long getApiResourceId() { | ||||
|         return getEntityId(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -188,6 +188,21 @@ public class BridgeVifDriver extends VifDriverBase { | ||||
|         return vNetId != null && protocol != null && !vNetId.equalsIgnoreCase("untagged"); | ||||
|     } | ||||
| 
 | ||||
|     protected String createStorageVnetBridgeIfNeeded(NicTO nic, String trafficLabel, | ||||
|                  String storageBrName) throws InternalErrorException { | ||||
|         if (!Networks.BroadcastDomainType.Storage.equals(nic.getBroadcastType()) || nic.getBroadcastUri() == null) { | ||||
|             return storageBrName; | ||||
|         } | ||||
|         String vNetId = Networks.BroadcastDomainType.getValue(nic.getBroadcastUri()); | ||||
|         String protocol = Networks.BroadcastDomainType.Vlan.scheme(); | ||||
|         if (!isValidProtocolAndVnetId(vNetId, protocol))  { | ||||
|             return storageBrName; | ||||
|         } | ||||
|         logger.debug(String.format("creating a vNet dev and bridge for %s traffic per traffic label %s", | ||||
|                 Networks.TrafficType.Storage.name(), trafficLabel)); | ||||
|         return createVnetBr(vNetId, storageBrName, protocol); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LibvirtVMDef.InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException { | ||||
| 
 | ||||
| @ -254,15 +269,7 @@ public class BridgeVifDriver extends VifDriverBase { | ||||
|             intf.defBridgeNet(_bridges.get("private"), null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter)); | ||||
|         } else if (nic.getType() == Networks.TrafficType.Storage) { | ||||
|             String storageBrName = nic.getName() == null ? _bridges.get("private") : nic.getName(); | ||||
|             if (nic.getBroadcastType() == Networks.BroadcastDomainType.Storage) { | ||||
|                 vNetId = Networks.BroadcastDomainType.getValue(nic.getBroadcastUri()); | ||||
|                 protocol = Networks.BroadcastDomainType.Vlan.scheme(); | ||||
|             } | ||||
|             if (isValidProtocolAndVnetId(vNetId, protocol))  { | ||||
|                 logger.debug(String.format("creating a vNet dev and bridge for %s traffic per traffic label %s", | ||||
|                         Networks.TrafficType.Storage.name(), trafficLabel)); | ||||
|                 storageBrName = createVnetBr(vNetId, storageBrName, protocol); | ||||
|             } | ||||
|             storageBrName = createStorageVnetBridgeIfNeeded(nic, trafficLabel, storageBrName); | ||||
|             intf.defBridgeNet(storageBrName, null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter)); | ||||
|         } | ||||
|         if (nic.getPxeDisable()) { | ||||
| @ -295,7 +302,7 @@ public class BridgeVifDriver extends VifDriverBase { | ||||
|         return "brvx-" + vnetId; | ||||
|     } | ||||
| 
 | ||||
|     private String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException { | ||||
|     protected String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException { | ||||
|         String nic = _pifs.get(pifKey); | ||||
|         if (nic == null || isVxlanOrNetris(protocol)) { | ||||
|             // if not found in bridge map, maybe traffic label refers to pif already? | ||||
|  | ||||
| @ -48,6 +48,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef; | ||||
| 
 | ||||
| public class LibvirtDomainXMLParser { | ||||
|     protected Logger logger = LogManager.getLogger(getClass()); | ||||
| @ -63,6 +64,8 @@ public class LibvirtDomainXMLParser { | ||||
|     private LibvirtVMDef.CpuTuneDef cpuTuneDef; | ||||
|     private LibvirtVMDef.CpuModeDef cpuModeDef; | ||||
|     private String name; | ||||
|     private GuestDef.BootType bootType; | ||||
|     private GuestDef.BootMode bootMode; | ||||
| 
 | ||||
|     public boolean parseDomainXML(String domXML) { | ||||
|         DocumentBuilder builder; | ||||
| @ -388,6 +391,7 @@ public class LibvirtDomainXMLParser { | ||||
|             } | ||||
|             extractCpuTuneDef(rootElement); | ||||
|             extractCpuModeDef(rootElement); | ||||
|             extractBootDef(rootElement); | ||||
|             return true; | ||||
|         } catch (ParserConfigurationException e) { | ||||
|             logger.debug(e.toString()); | ||||
| @ -516,6 +520,14 @@ public class LibvirtDomainXMLParser { | ||||
|         return cpuModeDef; | ||||
|     } | ||||
| 
 | ||||
|     public GuestDef.BootType getBootType() { | ||||
|         return bootType; | ||||
|     } | ||||
| 
 | ||||
|     public GuestDef.BootMode getBootMode() { | ||||
|         return bootMode; | ||||
|     } | ||||
| 
 | ||||
|     private void extractCpuTuneDef(final Element rootElement) { | ||||
|         NodeList cpuTunesList = rootElement.getElementsByTagName("cputune"); | ||||
|         if (cpuTunesList.getLength() > 0) { | ||||
| @ -569,4 +581,26 @@ public class LibvirtDomainXMLParser { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected void extractBootDef(final Element rootElement) { | ||||
|         bootType = GuestDef.BootType.BIOS; | ||||
|         bootMode = GuestDef.BootMode.LEGACY; | ||||
|         Element osElement = (Element) rootElement.getElementsByTagName("os").item(0); | ||||
|         if (osElement == null) { | ||||
|             return; | ||||
|         } | ||||
|         NodeList loaderList = osElement.getElementsByTagName("loader"); | ||||
|         if (loaderList.getLength() == 0) { | ||||
|             return; | ||||
|         } | ||||
|         Element loader = (Element) loaderList.item(0); | ||||
|         String type = loader.getAttribute("type"); | ||||
|         String secure = loader.getAttribute("secure"); | ||||
|         if ("pflash".equalsIgnoreCase(type) || loader.getTextContent().toLowerCase().contains("uefi")) { | ||||
|             bootType = GuestDef.BootType.UEFI; | ||||
|         } | ||||
|         if ("yes".equalsIgnoreCase(secure)) { | ||||
|             bootMode = GuestDef.BootMode.SECURE; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -65,7 +65,7 @@ public class LibvirtVMDef { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         enum BootType { | ||||
|         public enum BootType { | ||||
|             UEFI("UEFI"), BIOS("BIOS"); | ||||
| 
 | ||||
|             String _type; | ||||
| @ -80,7 +80,7 @@ public class LibvirtVMDef { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         enum BootMode { | ||||
|         public enum BootMode { | ||||
|             LEGACY("LEGACY"), SECURE("SECURE"); | ||||
| 
 | ||||
|             String _mode; | ||||
|  | ||||
| @ -135,6 +135,12 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra | ||||
|             instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces())); | ||||
|             instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName())); | ||||
|             instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd())); | ||||
|             if (parser.getBootType() != null) { | ||||
|                 instance.setBootType(parser.getBootType().toString()); | ||||
|             } | ||||
|             if (parser.getBootMode() != null) { | ||||
|                 instance.setBootMode(parser.getBootMode().toString()); | ||||
|             } | ||||
| 
 | ||||
|             return instance; | ||||
|         } catch (Exception e) { | ||||
|  | ||||
| @ -16,24 +16,29 @@ | ||||
| // under the License. | ||||
| package com.cloud.hypervisor.kvm.resource; | ||||
| 
 | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.InjectMocks; | ||||
| import org.mockito.Mockito; | ||||
| import org.mockito.Spy; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| 
 | ||||
| import com.cloud.agent.api.to.NicTO; | ||||
| import com.cloud.exception.InternalErrorException; | ||||
| import com.cloud.network.Networks; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| 
 | ||||
| @RunWith(MockitoJUnitRunner.class) | ||||
| public class BridgeVifDriverTest { | ||||
| 
 | ||||
|     private BridgeVifDriver driver; | ||||
|     private static final String BRIDGE_NAME = "cloudbr1"; | ||||
| 
 | ||||
|     @Before | ||||
|     public void setUp() throws Exception { | ||||
|         driver = new BridgeVifDriver(); | ||||
|     } | ||||
|     @Spy | ||||
|     @InjectMocks | ||||
|     private BridgeVifDriver driver = new BridgeVifDriver(); | ||||
| 
 | ||||
|     @Test | ||||
|     public void isBroadcastTypeVlanOrVxlan() { | ||||
| @ -58,4 +63,41 @@ public class BridgeVifDriverTest { | ||||
|         Assert.assertTrue(driver.isValidProtocolAndVnetId("123", "vlan")); | ||||
|         Assert.assertTrue(driver.isValidProtocolAndVnetId("456", "vxlan")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastTypeIsNotStorageButValidValues() throws InternalErrorException { | ||||
|         NicTO nic = new NicTO(); | ||||
|         nic.setBroadcastType(Networks.BroadcastDomainType.Storage); | ||||
|         int vlan = 123; | ||||
|         String newBridge = "br-" + vlan; | ||||
|         nic.setBroadcastUri(Networks.BroadcastDomainType.Storage.toUri(vlan)); | ||||
|         Mockito.doReturn(newBridge).when(driver).createVnetBr(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); | ||||
|         String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME); | ||||
|         Assert.assertEquals(newBridge, result); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastTypeIsNotStorage() throws InternalErrorException { | ||||
|         NicTO nic = new NicTO(); | ||||
|         nic.setBroadcastType(Networks.BroadcastDomainType.Vlan); | ||||
|         String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME); | ||||
|         Assert.assertEquals(BRIDGE_NAME, result); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastUriIsNull() throws InternalErrorException { | ||||
|         NicTO nic = new NicTO(); | ||||
|         nic.setBroadcastType(Networks.BroadcastDomainType.Storage); | ||||
|         String result = driver.createStorageVnetBridgeIfNeeded(nic,  "trafficLabel", BRIDGE_NAME); | ||||
|         Assert.assertEquals(BRIDGE_NAME, result); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void createStorageVnetBridgeIfNeededCreatesVnetBridgeWhenUntaggedVlan() throws InternalErrorException, URISyntaxException { | ||||
|         NicTO nic = new NicTO(); | ||||
|         nic.setBroadcastType(Networks.BroadcastDomainType.Storage); | ||||
|         nic.setBroadcastUri(new URI(Networks.BroadcastDomainType.Storage.scheme() + "://untagged")); | ||||
|         String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME); | ||||
|         Assert.assertEquals(BRIDGE_NAME, result); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -20,8 +20,13 @@ | ||||
| package com.cloud.hypervisor.kvm.resource; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import javax.xml.parsers.DocumentBuilder; | ||||
| import javax.xml.parsers.ParserConfigurationException; | ||||
| 
 | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; | ||||
| import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; | ||||
| @ -31,10 +36,15 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef; | ||||
| 
 | ||||
| import junit.framework.TestCase; | ||||
| import org.apache.cloudstack.utils.qemu.QemuObject; | ||||
| import org.apache.cloudstack.utils.security.ParserUtils; | ||||
| import org.junit.Assert; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| import org.w3c.dom.Document; | ||||
| import org.w3c.dom.Element; | ||||
| import org.xml.sax.InputSource; | ||||
| import org.xml.sax.SAXException; | ||||
| 
 | ||||
| @RunWith(MockitoJUnitRunner.class) | ||||
| public class LibvirtDomainXMLParserTest extends TestCase { | ||||
| @ -386,4 +396,84 @@ public class LibvirtDomainXMLParserTest extends TestCase { | ||||
|         Assert.assertEquals("CPU cores count is parsed", 4, libvirtDomainXMLParser.getCpuModeDef().getCoresPerSocket()); | ||||
|         Assert.assertEquals("CPU threads count is parsed", 2, libvirtDomainXMLParser.getCpuModeDef().getThreadsPerCore()); | ||||
|     } | ||||
| 
 | ||||
|     private LibvirtDomainXMLParser parseElementFromXML(String xml) { | ||||
|         LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser(); | ||||
|         DocumentBuilder builder; | ||||
|         try { | ||||
|             builder = ParserUtils.getSaferDocumentBuilderFactory().newDocumentBuilder(); | ||||
|             InputSource is = new InputSource(); | ||||
|             is.setCharacterStream(new StringReader(xml)); | ||||
|             Document doc = builder.parse(is); | ||||
|             Element element = doc.getDocumentElement(); | ||||
|             parser.extractBootDef(element); | ||||
|         } catch (ParserConfigurationException | IOException | SAXException e) { | ||||
|             Assert.fail("Failed to parse XML: " + e.getMessage()); | ||||
|         } | ||||
|         return parser; | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void extractBootDefParsesUEFISecureBootCorrectly() { | ||||
|         String xml = "<domain type='kvm'>" + | ||||
|                      "<os>" + | ||||
|                      "<loader type='pflash' secure='yes'>/path/to/uefi/loader</loader>" + | ||||
|                      "</os>" + | ||||
|                      "</domain>"; | ||||
| 
 | ||||
|         LibvirtDomainXMLParser parser = parseElementFromXML(xml); | ||||
| 
 | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType()); | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootMode.SECURE, parser.getBootMode()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void extractBootDefParsesUEFILegacyBootCorrectly() { | ||||
|         String xml = "<domain type='kvm'>" + | ||||
|                      "<os>" + | ||||
|                      "<loader type='pflash' secure='no'>/path/to/uefi/loader</loader>" + | ||||
|                      "</os>" + | ||||
|                      "</domain>"; | ||||
| 
 | ||||
|         LibvirtDomainXMLParser parser = parseElementFromXML(xml); | ||||
| 
 | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType()); | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void extractBootDefDefaultsToBIOSLegacyWhenNoLoaderPresent() { | ||||
|         String xml = "<domain type='kvm'>" + | ||||
|                      "<os>" + | ||||
|                      "<type arch='x86_64'>hvm</type>" + | ||||
|                      "</os>" + | ||||
|                      "</domain>"; | ||||
| 
 | ||||
|         LibvirtDomainXMLParser parser = parseElementFromXML(xml); | ||||
| 
 | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType()); | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void extractBootDefHandlesEmptyOSSection() { | ||||
|         String xml = "<domain type='kvm'>" + | ||||
|                      "<os></os>" + | ||||
|                      "</domain>"; | ||||
| 
 | ||||
|         LibvirtDomainXMLParser parser = parseElementFromXML(xml); | ||||
| 
 | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType()); | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void extractBootDefHandlesMissingOSSection() { | ||||
|         String xml = "<domain type='kvm'></domain>"; | ||||
| 
 | ||||
|         LibvirtDomainXMLParser parser = parseElementFromXML(xml); | ||||
| 
 | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType()); | ||||
|         assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -416,18 +416,33 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne | ||||
|         logTransitStateAndThrow(logLevel, message, null, null, ex); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isKubernetesServiceNetworkOfferingConfigured(DataCenter zone) { | ||||
|     private boolean isKubernetesServiceNetworkOfferingConfigured(DataCenter zone, Long networkId) { | ||||
|         // Check network offering | ||||
|         String networkOfferingName = KubernetesClusterNetworkOffering.value(); | ||||
|         if (networkOfferingName == null || networkOfferingName.isEmpty()) { | ||||
|             logger.warn(String.format("Global setting %s is empty. Admin has not yet specified the network offering to be used for provisioning isolated network for the cluster", KubernetesClusterNetworkOffering.key())); | ||||
|         if (StringUtils.isEmpty(networkOfferingName) && networkId == null) { | ||||
|             logger.warn("Global setting: {} is empty. Admin has not yet specified the network offering to be used for provisioning isolated network for the cluster nor has a pre-created network been passed", KubernetesClusterNetworkOffering.key()); | ||||
|             return false; | ||||
|         } | ||||
|         NetworkOfferingVO networkOffering = networkOfferingDao.findByUniqueName(networkOfferingName); | ||||
|         if (networkOffering == null) { | ||||
|             logger.warn(String.format("Unable to find the network offering %s to be used for provisioning Kubernetes cluster", networkOfferingName)); | ||||
|             return false; | ||||
|         NetworkOfferingVO networkOffering = null; | ||||
|         if (networkId != null) { | ||||
|             NetworkVO network = networkDao.findById(networkId); | ||||
|             if (network == null) { | ||||
|                 logger.warn("Unable to find the network with ID: {} passed for the Kubernetes cluster", networkId); | ||||
|                 return false; | ||||
|             } | ||||
|             networkOffering = networkOfferingDao.findById(network.getNetworkOfferingId()); | ||||
|             if (networkOffering == null) { | ||||
|                 logger.warn("Unable to find the network offering of the network: {} ({}) to be used for provisioning Kubernetes cluster", network.getName(), network.getUuid()); | ||||
|                 return false; | ||||
|             } | ||||
|         } else if (StringUtils.isNotEmpty(networkOfferingName)) { | ||||
|             networkOffering = networkOfferingDao.findByUniqueName(networkOfferingName); | ||||
|             if (networkOffering == null) { | ||||
|                 logger.warn("Unable to find the network offering: {} to be used for provisioning Kubernetes cluster", networkOfferingName); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (networkOffering.getState() == NetworkOffering.State.Disabled) { | ||||
|             logger.warn("Network offering: {} is not enabled", networkOffering); | ||||
|             return false; | ||||
| @ -462,8 +477,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     private boolean isKubernetesServiceConfigured(DataCenter zone) { | ||||
|         if (!isKubernetesServiceNetworkOfferingConfigured(zone)) { | ||||
|     private boolean isKubernetesServiceConfigured(DataCenter zone, Long networkId) { | ||||
|         if (!isKubernetesServiceNetworkOfferingConfigured(zone, networkId)) { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
| @ -1018,7 +1033,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne | ||||
| 
 | ||||
|         DataCenter zone = validateAndGetZoneForKubernetesCreateParameters(zoneId, networkId); | ||||
| 
 | ||||
|         if (!isKubernetesServiceConfigured(zone)) { | ||||
|         if (!isKubernetesServiceConfigured(zone, networkId)) { | ||||
|             throw new CloudRuntimeException("Kubernetes service has not been configured properly to provision Kubernetes clusters"); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -32,6 +32,8 @@ import java.util.Map; | ||||
| import javax.inject.Inject; | ||||
| import javax.naming.ConfigurationException; | ||||
| 
 | ||||
| import com.cloud.event.ActionEvent; | ||||
| import com.cloud.event.EventTypes; | ||||
| import org.apache.cloudstack.context.CallContext; | ||||
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | ||||
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | ||||
| @ -545,6 +547,7 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_INTERNAL_LB_VM_STOP, eventDescription = "stopping internal LB VM", async = true) | ||||
|     public VirtualRouter stopInternalLbVm(final long vmId, final boolean forced, final Account caller, final long callerUserId) throws ConcurrentOperationException, ResourceUnavailableException { | ||||
|         final DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); | ||||
|         if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { | ||||
| @ -974,6 +977,7 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_INTERNAL_LB_VM_START, eventDescription = "starting internal LB VM", async = true) | ||||
|     public VirtualRouter startInternalLbVm(final long internalLbVmId, final Account caller, final long callerUserId) throws StorageUnavailableException, InsufficientCapacityException, | ||||
|     ConcurrentOperationException, ResourceUnavailableException { | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,9 @@ | ||||
| // under the License. | ||||
| package org.apache.cloudstack.internallbvmmgr; | ||||
| 
 | ||||
| import static org.mockito.ArgumentMatchers.anyBoolean; | ||||
| import static org.mockito.ArgumentMatchers.anyLong; | ||||
| import static org.mockito.ArgumentMatchers.anyString; | ||||
| import static org.mockito.ArgumentMatchers.nullable; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| @ -24,13 +27,15 @@ import java.util.List; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import com.cloud.event.ActionEventUtils; | ||||
| import org.apache.cloudstack.context.CallContext; | ||||
| import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.ArgumentMatchers; | ||||
| import org.mockito.BDDMockito; | ||||
| import org.mockito.MockedStatic; | ||||
| import org.mockito.Mockito; | ||||
| import org.springframework.test.context.ContextConfiguration; | ||||
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||||
| @ -82,6 +87,8 @@ public class InternalLBVMServiceTest extends TestCase { | ||||
|     @Inject | ||||
|     AccountDao _accountDao; | ||||
| 
 | ||||
|     private MockedStatic<ActionEventUtils> actionEventUtilsMocked; | ||||
| 
 | ||||
|     long validVmId = 1L; | ||||
|     long nonExistingVmId = 2L; | ||||
|     long nonInternalLbVmId = 3L; | ||||
| @ -105,7 +112,7 @@ public class InternalLBVMServiceTest extends TestCase { | ||||
| 
 | ||||
|         Mockito.when(_accountMgr.getSystemUser()).thenReturn(new UserVO(1)); | ||||
|         Mockito.when(_accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); | ||||
|         Mockito.when(_accountDao.findByIdIncludingRemoved(ArgumentMatchers.anyLong())).thenReturn(new AccountVO(2)); | ||||
|         Mockito.when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(new AccountVO(2)); | ||||
|         CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); | ||||
| 
 | ||||
|         final DomainRouterVO validVm = | ||||
| @ -120,11 +127,16 @@ public class InternalLBVMServiceTest extends TestCase { | ||||
|         Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(validVm); | ||||
|         Mockito.when(_domainRouterDao.findById(nonExistingVmId)).thenReturn(null); | ||||
|         Mockito.when(_domainRouterDao.findById(nonInternalLbVmId)).thenReturn(nonInternalLbVm); | ||||
| 
 | ||||
|         actionEventUtilsMocked = Mockito.mockStatic(ActionEventUtils.class); | ||||
|         BDDMockito.given(ActionEventUtils.onStartedActionEvent(anyLong(), anyLong(), anyString(), anyString(), anyLong(), anyString(), anyBoolean(), anyLong())) | ||||
|                 .willReturn(1L); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         actionEventUtilsMocked.close(); | ||||
|         CallContext.unregister(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -121,6 +121,10 @@ public class PrimeraAdapter implements ProviderAdapter { | ||||
|     public void disconnect() { | ||||
|         logger.info("PrimeraAdapter:disconnect(): closing session"); | ||||
|         try { | ||||
|             //Delete session safely without triggering refreshSession | ||||
|             if (key != null && _client != null) { | ||||
|                 logout(); | ||||
|             } | ||||
|             _client.close(); | ||||
|         } catch (IOException e) { | ||||
|             logger.warn("PrimeraAdapter:refreshSession(): Error closing client connection", e); | ||||
| @ -130,6 +134,40 @@ public class PrimeraAdapter implements ProviderAdapter { | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|     /** | ||||
|      * Delete session directly without going through refreshSession to avoid infinite recursion | ||||
|      */ | ||||
|     private void logout() { | ||||
|         CloseableHttpResponse response = null; | ||||
|         try { | ||||
|             logger.debug("PrimeraAdapter:logout(): Delete session directly"); | ||||
|             HttpDelete request = new HttpDelete(url + "/credentials/" + key); | ||||
|             request.addHeader("Content-Type", "application/json"); | ||||
|             request.addHeader("Accept", "application/json"); | ||||
|             request.addHeader("X-HP3PAR-WSAPI-SessionKey", key); | ||||
| 
 | ||||
|             response = (CloseableHttpResponse) _client.execute(request); | ||||
|             final int statusCode = response.getStatusLine().getStatusCode(); | ||||
| 
 | ||||
|             if (statusCode == 200 || statusCode == 404) { | ||||
|                 logger.debug("PrimeraAdapter:logout(): Session deleted successfully or was already expired"); | ||||
|             } else if (statusCode == 401 || statusCode == 403) { | ||||
|                 logger.warn("PrimeraAdapter:logout(): Session already invalid or expired during deletion"); | ||||
|             } else { | ||||
|                 logger.warn("PrimeraAdapter:logout(): Unexpected response when deleting session: {}", statusCode); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             logger.warn("PrimeraAdapter:logout(): Error deleting session: {}", e.getMessage()); | ||||
|         } finally { | ||||
|             if (response != null) { | ||||
|                 try { | ||||
|                     response.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     logger.debug("PrimeraAdapter:logout(): Error closing response from session deletion", e); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ProviderVolume create(ProviderAdapterContext context, ProviderAdapterDataObject dataIn, | ||||
|  | ||||
| @ -54,7 +54,9 @@ public class TotpUserTwoFactorAuthenticator extends AdapterBase implements UserT | ||||
|             logger.info("2FA matches user's input"); | ||||
|             return; | ||||
|         } | ||||
|         throw new CloudTwoFactorAuthenticationException("two-factor authentication code provided is invalid"); | ||||
|         String msg = "two-factor authentication code provided is invalid"; | ||||
|         logger.error(msg); | ||||
|         throw new CloudTwoFactorAuthenticationException(msg); | ||||
|     } | ||||
| 
 | ||||
|     private String get2FAKey(UserAccount userAccount) { | ||||
|  | ||||
| @ -172,10 +172,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa | ||||
|                 } | ||||
|             } else if (template.getDownloadState() == Status.BYPASSED) { | ||||
|                 templateStatus = "Bypassed Secondary Storage"; | ||||
|             }else if (template.getErrorString()==null){ | ||||
|             } else if (template.getErrorString() == null) { | ||||
|                 templateStatus = template.getTemplateState().toString(); | ||||
|             }else { | ||||
|                 templateStatus = template.getErrorString(); | ||||
|             } else { | ||||
|                 templateStatus = template.getErrorString().trim(); | ||||
|             } | ||||
|         } else if (template.getDownloadState() == Status.DOWNLOADED) { | ||||
|             templateStatus = "Download Complete"; | ||||
|  | ||||
| @ -5370,10 +5370,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati | ||||
|                                 vlan.getVlanTag())); | ||||
|                     } | ||||
|                 } | ||||
|                 if (NetUtils.isSameIsolationId(vlanId, vlan.getVlanTag()) && !vlanIp6Gateway.equals(vlan.getIp6Gateway())) { | ||||
|                     throw new InvalidParameterValueException(String.format("The IP range with tag: %s has already been added with gateway %s. Please specify a different tag.", | ||||
|                             vlan.getVlanTag(), vlan.getIp6Gateway())); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -1399,6 +1399,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_CANCEL, eventDescription = "cancel maintenance for host", async = true) | ||||
|     public Host cancelMaintenance(final CancelHostMaintenanceCmd cmd) { | ||||
|         final Long hostId = cmd.getId(); | ||||
| 
 | ||||
| @ -1422,6 +1424,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_HOST_RECONNECT, eventDescription = "reconnecting host", async = true) | ||||
|     public Host reconnectHost(ReconnectHostCmd cmd) throws AgentUnavailableException { | ||||
|         Long hostId = cmd.getId(); | ||||
| 
 | ||||
| @ -1628,6 +1632,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_PREPARE, eventDescription = "prepare maintenance for host", async = true) | ||||
|     public Host maintain(final PrepareForHostMaintenanceCmd cmd) { | ||||
|         final Long hostId = cmd.getId(); | ||||
|         final HostVO host = _hostDao.findById(hostId); | ||||
|  | ||||
| @ -622,6 +622,8 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot from VM snapshot", async = true) | ||||
|     public Snapshot backupSnapshotFromVmSnapshot(Long snapshotId, Long vmId, Long volumeId, Long vmSnapshotId) { | ||||
|         VMInstanceVO vm = _vmDao.findById(vmId); | ||||
|         if (vm == null) { | ||||
|  | ||||
| @ -18,6 +18,29 @@ | ||||
|  */ | ||||
| package org.apache.cloudstack.vm.schedule; | ||||
| 
 | ||||
| import java.time.ZonedDateTime; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| import java.util.TimeZone; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import org.apache.cloudstack.api.ApiCommandResourceType; | ||||
| import org.apache.cloudstack.api.command.user.vm.CreateVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.DeleteVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.ListVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.UpdateVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.response.ListResponse; | ||||
| import org.apache.cloudstack.api.response.VMScheduleResponse; | ||||
| import org.apache.cloudstack.context.CallContext; | ||||
| import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao; | ||||
| import org.apache.commons.lang.time.DateUtils; | ||||
| import org.apache.commons.lang3.ObjectUtils; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.scheduling.support.CronExpression; | ||||
| 
 | ||||
| import com.cloud.api.query.MutualExclusiveIdsManagerBase; | ||||
| import com.cloud.event.ActionEvent; | ||||
| import com.cloud.event.EventTypes; | ||||
| @ -32,26 +55,6 @@ import com.cloud.utils.db.TransactionCallback; | ||||
| import com.cloud.utils.exception.CloudRuntimeException; | ||||
| import com.cloud.vm.UserVmManager; | ||||
| import com.cloud.vm.VirtualMachine; | ||||
| import org.apache.cloudstack.api.ApiCommandResourceType; | ||||
| import org.apache.cloudstack.api.command.user.vm.CreateVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.DeleteVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.ListVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.command.user.vm.UpdateVMScheduleCmd; | ||||
| import org.apache.cloudstack.api.response.ListResponse; | ||||
| import org.apache.cloudstack.api.response.VMScheduleResponse; | ||||
| import org.apache.cloudstack.context.CallContext; | ||||
| import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao; | ||||
| import org.apache.commons.lang.time.DateUtils; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.scheduling.support.CronExpression; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| import java.time.ZonedDateTime; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| import java.util.TimeZone; | ||||
| 
 | ||||
| public class VMScheduleManagerImpl extends MutualExclusiveIdsManagerBase implements VMScheduleManager, PluggableService { | ||||
| 
 | ||||
| @ -205,6 +208,9 @@ public class VMScheduleManagerImpl extends MutualExclusiveIdsManagerBase impleme | ||||
|         Date cmdStartDate = cmd.getStartDate(); | ||||
|         Date cmdEndDate = cmd.getEndDate(); | ||||
|         Boolean enabled = cmd.getEnabled(); | ||||
|         final String originalTimeZone = vmSchedule.getTimeZone(); | ||||
|         final Date originalStartDate = vmSchedule.getStartDate(); | ||||
|         final Date originalEndDate = vmSchedule.getEndDate(); | ||||
| 
 | ||||
|         TimeZone timeZone; | ||||
|         String timeZoneId; | ||||
| @ -231,7 +237,13 @@ public class VMScheduleManagerImpl extends MutualExclusiveIdsManagerBase impleme | ||||
|             startDate = Date.from(DateUtil.getZoneDateTime(cmdStartDate, timeZone.toZoneId()).toInstant()); | ||||
|         } | ||||
| 
 | ||||
|         validateStartDateEndDate(Objects.requireNonNullElse(startDate, DateUtils.addMinutes(new Date(), 1)), endDate, timeZone); | ||||
|         if (ObjectUtils.anyNotNull(cmdStartDate, cmdEndDate, cmdTimeZone) && | ||||
|                 (!Objects.equals(originalTimeZone, timeZoneId) || | ||||
|                         !Objects.equals(originalStartDate, startDate) || | ||||
|                         !Objects.equals(originalEndDate, endDate))) { | ||||
|             validateStartDateEndDate(Objects.requireNonNullElse(startDate, DateUtils.addMinutes(new Date(), 1)), | ||||
|                     endDate, timeZone); | ||||
|         } | ||||
| 
 | ||||
|         if (enabled != null) { | ||||
|             vmSchedule.setEnabled(enabled); | ||||
|  | ||||
| @ -33,7 +33,7 @@ | ||||
|       "headless": true, | ||||
|       "http_directory": "http", | ||||
|       "iso_checksum": "sha512:892cf1185a214d16ff62a18c6b89cdcd58719647c99916f6214bfca6f9915275d727b666c0b8fbf022c425ef18647e9759974abf7fc440431c39b50c296a98d3", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso", | ||||
|       "net_device": "virtio-net", | ||||
|       "output_directory": "../dist", | ||||
|       "qemu_binary": "qemu-system-aarch64", | ||||
|  | ||||
| @ -32,7 +32,7 @@ | ||||
|       "headless": true, | ||||
|       "http_directory": "http", | ||||
|       "iso_checksum": "sha512:892cf1185a214d16ff62a18c6b89cdcd58719647c99916f6214bfca6f9915275d727b666c0b8fbf022c425ef18647e9759974abf7fc440431c39b50c296a98d3", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso", | ||||
|       "net_device": "virtio-net", | ||||
|       "output_directory": "../dist", | ||||
|       "qemu_binary": "qemu-system-aarch64", | ||||
|  | ||||
| @ -28,7 +28,7 @@ | ||||
|       "headless": true, | ||||
|       "http_directory": "http", | ||||
|       "iso_checksum": "sha512:0921d8b297c63ac458d8a06f87cd4c353f751eb5fe30fd0d839ca09c0833d1d9934b02ee14bbd0c0ec4f8917dde793957801ae1af3c8122cdf28dde8f3c3e0da", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.11.0/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso", | ||||
|       "iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso", | ||||
|       "net_device": "virtio-net", | ||||
|       "output_directory": "../dist", | ||||
|       "qemuargs": [ | ||||
|  | ||||
| @ -663,10 +663,14 @@ | ||||
|         /> | ||||
|       </template> | ||||
|       <template v-if="column.key === 'domain'"> | ||||
|         <router-link | ||||
|           v-if="record.domainid && !record.domainid.toString().includes(',') && $store.getters.userInfo.roletype !== 'User'" | ||||
|           :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }" | ||||
|         >{{ text }}</router-link> | ||||
|         <span v-if="record.domainid && $store.getters.userInfo.roletype !== 'User'"> | ||||
|           <template v-for="(id, idx) in record.domainid.split(',')" :key="id"> | ||||
|             <router-link :to="{ path: '/domain/' + id, query: { tab: 'details' } }"> | ||||
|               {{ record.domain.split(',')[idx] || id }} | ||||
|             </router-link> | ||||
|             <span v-if="idx < record.domainid.split(',').length - 1">, </span> | ||||
|           </template> | ||||
|         </span> | ||||
|         <span v-else>{{ text }}</span> | ||||
|       </template> | ||||
|       <template v-if="column.key === 'domainpath'"> | ||||
|  | ||||
| @ -496,9 +496,17 @@ const user = { | ||||
|         }).catch(() => { | ||||
|           resolve() | ||||
|         }).finally(() => { | ||||
|           const paths = ['/', '/client'] | ||||
|           const hostname = window.location.hostname | ||||
|           const domains = [undefined, hostname, `.${hostname}`] | ||||
|           Object.keys(Cookies.get()).forEach(cookieName => { | ||||
|             Cookies.remove(cookieName) | ||||
|             Cookies.remove(cookieName, { path: '/client' }) | ||||
|             paths.forEach(path => { | ||||
|               domains.forEach(domain => { | ||||
|                 const options = { path } | ||||
|                 if (domain) options.domain = domain | ||||
|                 Cookies.remove(cookieName, options) | ||||
|               }) | ||||
|             }) | ||||
|           }) | ||||
|         }) | ||||
|       }) | ||||
|  | ||||
| @ -1879,11 +1879,13 @@ export default { | ||||
|       const query = Object.assign({}, this.$route.query) | ||||
|       delete query.templatefilter | ||||
|       delete query.isofilter | ||||
|       delete query.account | ||||
|       delete query.domainid | ||||
|       delete query.state | ||||
|       delete query.annotationfilter | ||||
|       delete query.leased | ||||
|       if (!['publicip'].includes(this.$route.name)) { | ||||
|         delete query.account | ||||
|         delete query.domainid | ||||
|       } | ||||
|       if (this.$route.name === 'template') { | ||||
|         query.templatefilter = filter | ||||
|       } else if (this.$route.name === 'iso') { | ||||
|  | ||||
| @ -228,8 +228,8 @@ export default { | ||||
|         getAPI('listDiskOfferings', { | ||||
|           id: this.selectedOffering.diskofferingid | ||||
|         }).then(response => { | ||||
|           const diskOfferings = response.listdiskofferingsresponse.diskoffering || [] | ||||
|           if (this.diskOfferings) { | ||||
|           const diskOfferings = response?.listdiskofferingsresponse?.diskoffering || [] | ||||
|           if (diskOfferings?.length > 0) { | ||||
|             this.selectedDiskOffering = diskOfferings[0] | ||||
|           } | ||||
|         }).catch(error => { | ||||
|  | ||||
| @ -85,7 +85,7 @@ | ||||
|           <template #label> | ||||
|             <tooltip-label :title="$t('label.directdownload')" :tooltip="apiParams.directdownload.description"/> | ||||
|           </template> | ||||
|           <a-switch v-model:checked="form.directdownload"/> | ||||
|           <a-switch v-model:checked="form.directdownload" @change="handleDirectDownloadChange"/> | ||||
|         </a-form-item> | ||||
| 
 | ||||
|         <a-form-item ref="checksum" name="checksum"> | ||||
| @ -110,7 +110,7 @@ | ||||
|             }" | ||||
|             :loading="zoneLoading" | ||||
|             :placeholder="apiParams.zoneid.description"> | ||||
|             <a-select-option :value="opt.id" v-for="opt in zones" :key="opt.id" :label="opt.name || opt.description"> | ||||
|             <a-select-option :value="opt.id" v-for="opt in zoneList" :key="opt.id" :label="opt.name || opt.description"> | ||||
|               <span> | ||||
|                 <resource-icon v-if="opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/> | ||||
|                 <global-outlined v-else style="margin-right: 5px" /> | ||||
| @ -361,17 +361,18 @@ export default { | ||||
|   }, | ||||
|   created () { | ||||
|     this.initForm() | ||||
|     this.zones = [] | ||||
|     if (this.$store.getters.userInfo.roletype === 'Admin' && this.currentForm === 'Create') { | ||||
|       this.zones = [ | ||||
|         { | ||||
|           id: '-1', | ||||
|           name: this.$t('label.all.zone') | ||||
|         } | ||||
|       ] | ||||
|     } | ||||
|     this.initZones() | ||||
|     this.fetchData() | ||||
|   }, | ||||
|   computed: { | ||||
|     zoneList () { | ||||
|       let filteredZones = this.zones | ||||
|       if (!this.form.directdownload) { | ||||
|         filteredZones = this.zones.filter(zone => zone.type !== 'Edge') | ||||
|       } | ||||
|       return filteredZones | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     initForm () { | ||||
|       this.formRef = ref() | ||||
| @ -390,6 +391,17 @@ export default { | ||||
|         ostypeid: [{ required: true, message: this.$t('message.error.select') }] | ||||
|       }) | ||||
|     }, | ||||
|     initZones () { | ||||
|       this.zones = [] | ||||
|       if (this.$store.getters.userInfo.roletype === 'Admin' && this.currentForm === 'Create') { | ||||
|         this.zones = [ | ||||
|           { | ||||
|             id: '-1', | ||||
|             name: this.$t('label.all.zone') | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|     fetchData () { | ||||
|       this.fetchZoneData() | ||||
|       this.fetchOsType() | ||||
| @ -412,11 +424,10 @@ export default { | ||||
|         const listZones = json.listzonesresponse.zone | ||||
|         if (listZones) { | ||||
|           this.zones = this.zones.concat(listZones) | ||||
|           this.zones = this.zones.filter(zone => zone.type !== 'Edge') | ||||
|         } | ||||
|       }).finally(() => { | ||||
|         this.zoneLoading = false | ||||
|         this.form.zoneid = (this.zones[0].id ? this.zones[0].id : '') | ||||
|         this.form.zoneid = this.zoneList?.[0]?.id || '' | ||||
|       }) | ||||
|     }, | ||||
|     fetchOsType () { | ||||
| @ -467,6 +478,12 @@ export default { | ||||
|       this.fileList = newFileList | ||||
|       this.form.file = undefined | ||||
|     }, | ||||
|     handleDirectDownloadChange () { | ||||
|       if (this.form.zoneid && this.zoneList.find(entry => entry.id === this.form.zoneid)) { | ||||
|         return | ||||
|       } | ||||
|       this.form.zoneid = this.zoneList?.[0]?.id || '' | ||||
|     }, | ||||
|     beforeUpload (file) { | ||||
|       this.fileList = [file] | ||||
|       this.form.file = file | ||||
| @ -531,7 +548,7 @@ export default { | ||||
|           } | ||||
|           switch (key) { | ||||
|             case 'zoneid': | ||||
|               var zone = this.zones.filter(zone => zone.id === input) | ||||
|               var zone = this.zoneList.filter(zone => zone.id === input) | ||||
|               params[key] = zone[0].id | ||||
|               break | ||||
|             case 'ostypeid': | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user