diff --git a/api/src/main/java/com/cloud/network/NetworkService.java b/api/src/main/java/com/cloud/network/NetworkService.java index 585ebc89d42..742206c7e3b 100644 --- a/api/src/main/java/com/cloud/network/NetworkService.java +++ b/api/src/main/java/com/cloud/network/NetworkService.java @@ -108,6 +108,10 @@ public interface NetworkService { PhysicalNetwork physicalNetwork, long zoneId, ControlledEntity.ACLType aclType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException; + Network createGuestNetwork(long networkOfferingId, String name, String displayText, Account owner, + PhysicalNetwork physicalNetwork, long zoneId, ControlledEntity.ACLType aclType, Pair vrIfaceMTUs) throws + InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException; + Pair, Integer> searchForNetworks(ListNetworksCmd cmd); boolean deleteNetwork(long networkId, boolean forced); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java index 983ed25d953..e202dfad77b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java @@ -118,6 +118,9 @@ public class ListHostsCmd extends BaseListCmd { since = "4.21.0") private String storageAccessGroup; + @Parameter(name = ApiConstants.VERSION, type = CommandType.STRING, description = "the host version", since = "4.20.3") + private String version; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -222,6 +225,10 @@ public class ListHostsCmd extends BaseListCmd { this.storageAccessGroup = storageAccessGroup; } + public String getVersion() { + return version; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/management/ListMgmtsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/management/ListMgmtsCmd.java index ecc59f7cab8..293cb34e702 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/management/ListMgmtsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/management/ListMgmtsCmd.java @@ -45,6 +45,10 @@ public class ListMgmtsCmd extends BaseListCmd { since = "4.20.1.0") private Boolean peers; + @Parameter(name = ApiConstants.VERSION, type = CommandType.STRING, + description = "the version of the management server", since = "4.20.3") + private String version; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -61,6 +65,10 @@ public class ListMgmtsCmd extends BaseListCmd { return BooleanUtils.toBooleanDefaultIfNull(peers, false); } + public String getVersion() { + return version; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVnfApplianceCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVnfApplianceCmd.java index 4d50dd9c39b..92ddfd5b235 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVnfApplianceCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVnfApplianceCmd.java @@ -43,7 +43,7 @@ import java.util.List; public class DeployVnfApplianceCmd extends DeployVMCmd implements UserCmd { @Parameter(name = ApiConstants.VNF_CONFIGURE_MANAGEMENT, type = CommandType.BOOLEAN, required = false, - description = "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise. " + + description = "False by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. True otherwise. " + "Network rules are configured if management network is an isolated network or shared network with security groups.") private Boolean vnfConfigureManagement; diff --git a/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManager.java b/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManager.java index 6571346ad65..3df59811561 100644 --- a/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManager.java +++ b/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManager.java @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd; import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd; import org.apache.cloudstack.framework.config.ConfigKey; import java.util.List; +import java.util.Map; public interface VnfTemplateManager { @@ -42,11 +43,12 @@ public interface VnfTemplateManager { void updateVnfTemplate(long templateId, UpdateVnfTemplateCmd cmd); - void validateVnfApplianceNics(VirtualMachineTemplate template, List networkIds); + void validateVnfApplianceNics(VirtualMachineTemplate template, List networkIds, Map vmNetworkMap); SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner, DeployVnfApplianceCmd cmd); void createIsolatedNetworkRulesForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner, UserVm vm, DeployVnfApplianceCmd cmd) throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException; + } diff --git a/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateUtils.java b/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateUtils.java index e997a50cec0..16ff2abb564 100644 --- a/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateUtils.java +++ b/api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateUtils.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.storage.template; +import com.cloud.agent.api.to.deployasis.OVFNetworkTO; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.VNF; import com.cloud.storage.Storage; @@ -124,6 +125,9 @@ public class VnfTemplateUtils { public static void validateApiCommandParams(BaseCmd cmd, VirtualMachineTemplate template) { if (cmd instanceof RegisterVnfTemplateCmd) { RegisterVnfTemplateCmd registerCmd = (RegisterVnfTemplateCmd) cmd; + if (registerCmd.isDeployAsIs() && CollectionUtils.isNotEmpty(registerCmd.getVnfNics())) { + throw new InvalidParameterValueException("VNF nics cannot be specified when register a deploy-as-is Template. Please wait until Template settings are read from OVA."); + } validateApiCommandParams(registerCmd.getVnfDetails(), registerCmd.getVnfNics(), registerCmd.getTemplateType()); } else if (cmd instanceof UpdateVnfTemplateCmd) { UpdateVnfTemplateCmd updateCmd = (UpdateVnfTemplateCmd) cmd; @@ -149,4 +153,18 @@ public class VnfTemplateUtils { } } } + + public static void validateDeployAsIsTemplateVnfNics(List ovfNetworks, List vnfNics) { + if (CollectionUtils.isEmpty(vnfNics)) { + return; + } + if (CollectionUtils.isEmpty(ovfNetworks)) { + throw new InvalidParameterValueException("The list of networks read from OVA is empty. Please wait until the template is fully downloaded and processed."); + } + for (VNF.VnfNic vnfNic : vnfNics) { + if (vnfNic.getDeviceId() < ovfNetworks.size() && !vnfNic.isRequired()) { + throw new InvalidParameterValueException(String.format("The VNF nic [device ID: %s ] is required as it is defined in the OVA template.", vnfNic.getDeviceId())); + } + } + } } diff --git a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java index 168b4870909..f1891c774ed 100644 --- a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java +++ b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java @@ -153,6 +153,8 @@ public interface TemplateManager { TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones, Hypervisor.HypervisorType hypervisorType); + DataStore verifyHeuristicRulesForZone(VMTemplateVO template, Long zoneId); + List getTemplateDisksOnImageStore(VirtualMachineTemplate template, DataStoreRole role, String configurationId); static Boolean getValidateUrlIsResolvableBeforeRegisteringTemplateValue() { diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java index 7a1a39ec0f0..475ed0f37bd 100644 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java @@ -89,7 +89,7 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat return; } for (Long vmId : vmIds) { - if (!notUpdated.containsKey(vmId)) { + if (MapUtils.isEmpty(notUpdated) || !notUpdated.containsKey(vmId)) { logger.debug("VM state report is updated. {}, {}, power state: {}", () -> hostCache.get(hostId), () -> vmCache.get(vmId), () -> instancePowerStates.get(vmId)); _messageBus.publish(null, VirtualMachineManager.Topics.VM_POWER_STATE, @@ -158,8 +158,8 @@ public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStat // an update might have occurred that we should not override in case of out of band migration instancePowerStates.put(instance.getId(), VirtualMachine.PowerState.PowerReportMissing); } else { - logger.debug("vm id: {} - time since last state update({} ms) has not passed graceful period yet", - instance.getId(), milliSecondsSinceLastStateUpdate); + logger.debug("vm id: {} - time since last state update({} ms) has not passed graceful period ({} ms) yet", + instance.getId(), milliSecondsSinceLastStateUpdate, milliSecondsGracefulPeriod); } } updateAndPublishVmPowerStates(hostId, instancePowerStates, startTime); diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 138d469005b..a59e0373c1d 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -291,21 +291,41 @@ public class TemplateServiceImpl implements TemplateService { } } - protected boolean isSkipTemplateStoreDownload(VMTemplateVO template, Long zoneId) { + protected boolean shouldDownloadTemplateToStore(VMTemplateVO template, DataStore store) { + Long zoneId = store.getScope().getScopeId(); + DataStore directedStore = _tmpltMgr.verifyHeuristicRulesForZone(template, zoneId); + if (directedStore != null && store.getId() != directedStore.getId()) { + logger.info("Template [{}] will not be download to image store [{}], as a heuristic rule is directing it to another store.", + template.getUniqueName(), store.getName()); + return false; + } + if (template.isPublicTemplate()) { - return false; + logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is public.", template.getUniqueName(), + store.getName()); + return true; } + if (template.isFeatured()) { - return false; + logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is featured.", template.getUniqueName(), + store.getName()); + return true; } + if (TemplateType.SYSTEM.equals(template.getTemplateType())) { - return false; + logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is a system VM template.", + template.getUniqueName(),store.getName()); + return true; } + if (zoneId != null && _vmTemplateStoreDao.findByTemplateZone(template.getId(), zoneId, DataStoreRole.Image) == null) { - logger.debug("Template {} is not present on any image store for the zone ID: {}, its download cannot be skipped", template, zoneId); - return false; + logger.debug("Download of template [{}] to image store [{}] cannot be skipped, as it is not present on any image store of zone [{}].", + template.getUniqueName(), store.getName(), zoneId); + return true; } - return true; + + logger.info("Skipping download of template [{}] to image store [{}].", template.getUniqueName(), store.getName()); + return false; } @Override @@ -533,8 +553,7 @@ public class TemplateServiceImpl implements TemplateService { // download. for (VMTemplateVO tmplt : toBeDownloaded) { // if this is private template, skip sync to a new image store - if (isSkipTemplateStoreDownload(tmplt, zoneId)) { - logger.info("Skip sync downloading private template {} to a new image store", tmplt); + if (!shouldDownloadTemplateToStore(tmplt, store)) { continue; } diff --git a/engine/storage/image/src/test/java/org/apache/cloudstack/storage/image/TemplateServiceImplTest.java b/engine/storage/image/src/test/java/org/apache/cloudstack/storage/image/TemplateServiceImplTest.java index 276581e2e48..cb7994915b3 100644 --- a/engine/storage/image/src/test/java/org/apache/cloudstack/storage/image/TemplateServiceImplTest.java +++ b/engine/storage/image/src/test/java/org/apache/cloudstack/storage/image/TemplateServiceImplTest.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.storage.image; import com.cloud.storage.template.TemplateProp; +import com.cloud.template.TemplateManager; import org.apache.cloudstack.engine.orchestration.service.StorageOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -70,6 +71,9 @@ public class TemplateServiceImplTest { @Mock TemplateObject templateInfoMock; + @Mock + DataStore dataStoreMock; + @Mock DataStore sourceStoreMock; @@ -82,6 +86,9 @@ public class TemplateServiceImplTest { @Mock StorageOrchestrationService storageOrchestrator; + @Mock + TemplateManager templateManagerMock; + Map templatesInSourceStore = new HashMap<>(); @Before @@ -96,45 +103,45 @@ public class TemplateServiceImplTest { Mockito.doReturn(null).when(templateService).listTemplate(destStoreMock); Mockito.doReturn("install-path").when(templateInfoMock).getInstallPath(); Mockito.doReturn(templateInfoMock).when(templateDataFactoryMock).getTemplate(2L, sourceStoreMock); + Mockito.doReturn(3L).when(dataStoreMock).getId(); + Mockito.doReturn(zoneScopeMock).when(dataStoreMock).getScope(); } @Test - public void testIsSkipTemplateStoreDownloadPublicTemplate() { - VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class); - Mockito.when(templateVO.isPublicTemplate()).thenReturn(true); - Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L)); + public void shouldDownloadTemplateToStoreTestSkipsTemplateDirectedToAnotherStorage() { + DataStore destinedStore = Mockito.mock(DataStore.class); + Mockito.doReturn(dataStoreMock.getId() + 1L).when(destinedStore).getId(); + Mockito.when(templateManagerMock.verifyHeuristicRulesForZone(tmpltMock, zoneScopeMock.getScopeId())).thenReturn(destinedStore); + Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); } @Test - public void testIsSkipTemplateStoreDownloadFeaturedTemplate() { - VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class); - Mockito.when(templateVO.isFeatured()).thenReturn(true); - Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L)); + public void shouldDownloadTemplateToStoreTestDownloadsPublicTemplate() { + Mockito.when(tmpltMock.isPublicTemplate()).thenReturn(true); + Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); } @Test - public void testIsSkipTemplateStoreDownloadSystemTemplate() { - VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class); - Mockito.when(templateVO.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM); - Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, 1L)); + public void shouldDownloadTemplateToStoreTestDownloadsFeaturedTemplate() { + Mockito.when(tmpltMock.isFeatured()).thenReturn(true); + Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); } @Test - public void testIsSkipTemplateStoreDownloadPrivateNoRefTemplate() { - VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class); - long id = 1L; - Mockito.when(templateVO.getId()).thenReturn(id); - Mockito.when(templateDataStoreDao.findByTemplateZone(id, id, DataStoreRole.Image)).thenReturn(null); - Assert.assertFalse(templateService.isSkipTemplateStoreDownload(templateVO, id)); + public void shouldDownloadTemplateToStoreTestDownloadsSystemTemplate() { + Mockito.when(tmpltMock.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM); + Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); } @Test - public void testIsSkipTemplateStoreDownloadPrivateExistingTemplate() { - VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class); - long id = 1L; - Mockito.when(templateVO.getId()).thenReturn(id); - Mockito.when(templateDataStoreDao.findByTemplateZone(id, id, DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class)); - Assert.assertTrue(templateService.isSkipTemplateStoreDownload(templateVO, id)); + public void shouldDownloadTemplateToStoreTestDownloadsPrivateNoRefTemplate() { + Assert.assertTrue(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); + } + + @Test + public void shouldDownloadTemplateToStoreTestSkipsPrivateExistingTemplate() { + Mockito.when(templateDataStoreDao.findByTemplateZone(tmpltMock.getId(), zoneScopeMock.getScopeId(), DataStoreRole.Image)).thenReturn(Mockito.mock(TemplateDataStoreVO.class)); + Assert.assertFalse(templateService.shouldDownloadTemplateToStore(tmpltMock, dataStoreMock)); } @Test diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 8b26bc94e21..4d823783a99 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -111,7 +111,9 @@ public class LibvirtDomainXMLParser { def.defNetworkBasedDisk(diskPath, host, port, authUserName, poolUuid, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()), DiskDef.DiskProtocol.valueOf(protocol.toUpperCase()), fmt); - def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase())); + if (StringUtils.isNotBlank(diskCacheMode)) { + def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase())); + } } else { String diskFmtType = getAttrValue("driver", "type", disk); String diskCacheMode = getAttrValue("driver", "cache", disk); diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java index 1acc292b450..af868d8c1c7 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java @@ -45,7 +45,7 @@ public final class CitrixUpdateHostPasswordCommandWrapper extends CommandWrapper Pair result; try { - logger.debug("Executing command in Host: " + cmdLine); + logger.debug("Executing password update command on host: {} for user: {}", hostIp, username); final String hostPassword = citrixResourceBase.getPwdFromQueue(); result = xenServerUtilitiesHelper.executeSshWrapper(hostIp, 22, username, null, hostPassword, cmdLine.toString()); } catch (final Exception e) { diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index f6af2b95978..cf4bbce098a 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -1172,9 +1172,12 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne CallContext networkContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Network); try { + Long zoneId = zone.getId(); + Integer publicMTU = NetworkService.VRPublicInterfaceMtu.valueIn(zoneId); + Integer privateMTU = NetworkService.VRPrivateInterfaceMtu.valueIn(zoneId); network = networkService.createGuestNetwork(networkOffering.getId(), clusterName + "-network", - owner.getAccountName() + "-network", owner, physicalNetwork, zone.getId(), - ControlledEntity.ACLType.Account); + owner.getAccountName() + "-network", owner, physicalNetwork, zoneId, + ControlledEntity.ACLType.Account, new Pair<>(publicMTU, privateMTU)); if (!networkOffering.isForVpc() && NetworkOffering.RoutingMode.Dynamic == networkOffering.getRoutingMode()) { bgpService.allocateASNumber(zone.getId(), asNumber, network.getId(), null); } diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java index 523f694d80b..618536a71f6 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java @@ -82,6 +82,9 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe ConfigKey SAMLRequirePasswordLogin = new ConfigKey("Advanced", Boolean.class, "saml2.require.password", "true", "When enabled SAML2 will validate that the SAML login was performed with a password. If disabled, other forms of authentication are allowed (two-factor, certificate, etc) on the SAML Authentication Provider", true); + ConfigKey EnableLoginAfterSAMLDisable = new ConfigKey<>("Advanced", Boolean.class, "enable.login.with.disabled.saml", "false", "When enabled, if SAML SSO is disabled, enables user to login with user and password, otherwise a user with SAML SSO disabled cannot login", true); + + SAMLProviderMetadata getSPMetadata(); SAMLProviderMetadata getIdPMetadata(String entityId); diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java index 93b7bc5be93..9f8101b867d 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java @@ -451,8 +451,13 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage user.setExternalEntity(entityId); user.setSource(User.Source.SAML2); } else { + boolean enableLoginAfterSAMLDisable = SAML2AuthManager.EnableLoginAfterSAMLDisable.value(); if (user.getSource().equals(User.Source.SAML2)) { - user.setSource(User.Source.SAML2DISABLED); + if(enableLoginAfterSAMLDisable) { + user.setSource(User.Source.UNKNOWN); + } else { + user.setSource(User.Source.SAML2DISABLED); + } } else { return false; } @@ -541,6 +546,6 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage SAMLCloudStackRedirectionUrl, SAMLUserAttributeName, SAMLIdentityProviderMetadataURL, SAMLDefaultIdentityProviderId, SAMLSignatureAlgorithm, SAMLAppendDomainSuffix, SAMLTimeout, SAMLCheckSignature, - SAMLForceAuthn, SAMLUserSessionKeyPathAttribute, SAMLRequirePasswordLogin}; + SAMLForceAuthn, SAMLUserSessionKeyPathAttribute, SAMLRequirePasswordLogin, EnableLoginAfterSAMLDisable}; } } diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 4fa7d759cb1..3b232948395 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -2425,6 +2425,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Long msId = cmd.getManagementServerId(); final CPU.CPUArch arch = cmd.getArch(); String storageAccessGroup = cmd.getStorageAccessGroup(); + String version = cmd.getVersion(); Filter searchFilter = new Filter(HostVO.class, "id", Boolean.TRUE, startIndex, pageSize); @@ -2449,11 +2450,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q hostSearchBuilder.or("storageAccessGroupMiddle", hostSearchBuilder.entity().getStorageAccessGroups(), Op.LIKE); hostSearchBuilder.cp(); } + hostSearchBuilder.and("version", hostSearchBuilder.entity().getVersion(), SearchCriteria.Op.EQ); if (keyword != null) { hostSearchBuilder.and().op("keywordName", hostSearchBuilder.entity().getName(), SearchCriteria.Op.LIKE); hostSearchBuilder.or("keywordStatus", hostSearchBuilder.entity().getStatus(), SearchCriteria.Op.LIKE); hostSearchBuilder.or("keywordType", hostSearchBuilder.entity().getType(), SearchCriteria.Op.LIKE); + hostSearchBuilder.or("keywordVersion", hostSearchBuilder.entity().getVersion(), SearchCriteria.Op.LIKE); hostSearchBuilder.cp(); } @@ -2484,6 +2487,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q sc.setParameters("keywordName", "%" + keyword + "%"); sc.setParameters("keywordStatus", "%" + keyword + "%"); sc.setParameters("keywordType", "%" + keyword + "%"); + sc.setParameters("keywordVersion", "%" + keyword + "%"); } if (id != null) { @@ -2547,6 +2551,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q sc.setParameters("storageAccessGroupMiddle", "%," + storageAccessGroup + ",%"); } + if (version != null) { + sc.setParameters("version", version); + } + Pair, Integer> uniqueHostPair = hostDao.searchAndCount(sc, searchFilter); Integer count = uniqueHostPair.second(); List hostIds = uniqueHostPair.first().stream().map(HostVO::getId).collect(Collectors.toList()); @@ -5715,6 +5723,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q protected Pair, Integer> listManagementServersInternal(ListMgmtsCmd cmd) { Long id = cmd.getId(); String name = cmd.getHostName(); + String version = cmd.getVersion(); + String keyword = cmd.getKeyword(); SearchBuilder sb = managementServerJoinDao.createSearchBuilder(); SearchCriteria sc = sb.create(); @@ -5724,6 +5734,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (name != null) { sc.addAnd("name", SearchCriteria.Op.EQ, name); } + if (version != null) { + sc.addAnd("version", SearchCriteria.Op.EQ, version); + } + if (keyword != null) { + sc.addAnd("version", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + } return managementServerJoinDao.searchAndCount(sc, null); } diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 672d83a27b3..8a933d7d91f 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -76,6 +76,7 @@ import com.cloud.user.Account; import com.cloud.user.AccountService; import com.cloud.user.dao.UserDataDao; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -160,29 +161,50 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation isosInStore = _templateStoreDao.listByTemplateNotBypassed(iso.getId()); diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index cb1ee021d67..dea8a7ec83e 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -1886,6 +1886,18 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C null, null, null, null, null, null, null, null, null, null); } + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network") + public Network createGuestNetwork(long networkOfferingId, String name, String displayText, Account owner, + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Pair vrIfaceMTUs) throws + InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { + return _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, + null, null, null, false, null, owner, null, physicalNetwork, zoneId, + aclType, null, null, null, null, true, null, + null, null, null, null, null, null, null, null, vrIfaceMTUs, null); + } + void checkAndSetRouterSourceNatIp(Account owner, CreateNetworkCmd cmd, Network network) throws InsufficientAddressCapacityException, ResourceAllocationException { String sourceNatIp = cmd.getSourceNatIP(); if (sourceNatIp == null) { diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 37710c1f44f..e579eeeecd6 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1747,8 +1747,9 @@ Configurable, StateListener vms = userVmJoinDao.search(scvm, null); - boolean isDhcpSupported = _ntwkSrvcDao.areServicesSupportedInNetwork(routerJoinVO.getNetworkId(), Service.Dhcp); - boolean isDnsSupported = _ntwkSrvcDao.areServicesSupportedInNetwork(routerJoinVO.getNetworkId(), Service.Dns); + Provider provider = routerJoinVO.getVpcId() != 0 ? Provider.VPCVirtualRouter : Provider.VirtualRouter; + boolean isDhcpSupported = _ntwkSrvcDao.canProviderSupportServiceInNetwork(routerJoinVO.getNetworkId(), Service.Dhcp, provider); + boolean isDnsSupported = _ntwkSrvcDao.canProviderSupportServiceInNetwork(routerJoinVO.getNetworkId(), Service.Dns, provider); for (UserVmJoinVO vm : vms) { vmsData.append("vmName=").append(vm.getName()) .append(",macAddress=").append(vm.getMacAddress()) diff --git a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java index bc3d219395f..2e4deafe576 100644 --- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java @@ -288,7 +288,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { for (long zoneId : zonesIds) { - DataStore imageStore = verifyHeuristicRulesForZone(template, zoneId); + DataStore imageStore = templateMgr.verifyHeuristicRulesForZone(template, zoneId); if (imageStore == null) { List imageStores = getImageStoresThrowsExceptionIfNotFound(zoneId, profile); @@ -299,6 +299,14 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { } } + protected List getImageStoresThrowsExceptionIfNotFound(long zoneId, TemplateProfile profile) { + List imageStores = storeMgr.getImageStoresByZoneIds(zoneId); + if (imageStores == null || imageStores.size() == 0) { + throw new CloudRuntimeException(String.format("Unable to find image store to download the template [%s].", profile.getTemplate())); + } + return imageStores; + } + protected void standardImageStoreAllocation(List imageStores, VMTemplateVO template) { Set zoneSet = new HashSet(); Collections.shuffle(imageStores); @@ -356,7 +364,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { } Long zoneId = zoneIdList.get(0); - DataStore imageStore = verifyHeuristicRulesForZone(template, zoneId); + DataStore imageStore = templateMgr.verifyHeuristicRulesForZone(template, zoneId); List payloads = new LinkedList<>(); if (imageStore == null) { diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index a37be2e73db..d751bf92e7b 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -121,6 +121,7 @@ import com.cloud.agent.api.to.DatadiskTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.api.to.deployasis.OVFNetworkTO; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.vo.UserVmJoinVO; @@ -131,6 +132,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; +import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; @@ -315,6 +317,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, protected SnapshotHelper snapshotHelper; @Inject VnfTemplateManager vnfTemplateManager; + @Inject + TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao; @Inject private SecondaryStorageHeuristicDao secondaryStorageHeuristicDao; @@ -2217,6 +2221,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, templateType = validateTemplateType(cmd, isAdmin, template.isCrossZones(), template.getHypervisorType()); if (cmd instanceof UpdateVnfTemplateCmd) { VnfTemplateUtils.validateApiCommandParams(cmd, template); + UpdateVnfTemplateCmd updateCmd = (UpdateVnfTemplateCmd) cmd; + if (template.isDeployAsIs() && CollectionUtils.isNotEmpty(updateCmd.getVnfNics())) { + List ovfNetworks = templateDeployAsIsDetailsDao.listNetworkRequirementsByTemplateId(template.getId()); + VnfTemplateUtils.validateDeployAsIsTemplateVnfNics(ovfNetworks, updateCmd.getVnfNics()); + } vnfTemplateManager.updateVnfTemplate(template.getId(), (UpdateVnfTemplateCmd) cmd); } templateTag = ((UpdateTemplateCmd)cmd).getTemplateTag(); @@ -2415,6 +2424,17 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, TemplateType.USER, HypervisorType.External)); } + @Override + public DataStore verifyHeuristicRulesForZone(VMTemplateVO template, Long zoneId) { + HeuristicType heuristicType; + if (ImageFormat.ISO.equals(template.getFormat())) { + heuristicType = HeuristicType.ISO; + } else { + heuristicType = HeuristicType.TEMPLATE; + } + return heuristicRuleHelper.getImageStoreIfThereIsHeuristicRule(zoneId, heuristicType, template); + } + void validateDetails(VMTemplateVO template, Map details) { if (MapUtils.isEmpty(details)) { return; diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 16aad891f4e..eccea944fe6 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -6284,7 +6284,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private void verifyTemplate(BaseDeployVMCmd cmd, VirtualMachineTemplate template, Long serviceOfferingId) { if (TemplateType.VNF.equals(template.getTemplateType())) { - vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds()); + vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds(), cmd.getVmNetworkMap()); } else if (cmd instanceof DeployVnfApplianceCmd) { throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template"); } diff --git a/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java b/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java index ef0f6f6b226..0ebff237a44 100644 --- a/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java @@ -201,7 +201,14 @@ public class VnfTemplateManagerImpl extends ManagerBase implements VnfTemplateMa } @Override - public void validateVnfApplianceNics(VirtualMachineTemplate template, List networkIds) { + public void validateVnfApplianceNics(VirtualMachineTemplate template, List networkIds, Map vmNetworkMap) { + if (template.isDeployAsIs()) { + if (CollectionUtils.isNotEmpty(networkIds)) { + throw new InvalidParameterValueException("VNF nics mappings should be empty for deploy-as-is templates"); + } + validateVnfApplianceNetworksMap(template, vmNetworkMap); + return; + } if (CollectionUtils.isEmpty(networkIds)) { throw new InvalidParameterValueException("VNF nics list is empty"); } @@ -213,6 +220,18 @@ public class VnfTemplateManagerImpl extends ManagerBase implements VnfTemplateMa } } + private void validateVnfApplianceNetworksMap(VirtualMachineTemplate template, Map vmNetworkMap) { + if (MapUtils.isEmpty(vmNetworkMap)) { + throw new InvalidParameterValueException("VNF networks map is empty"); + } + List vnfNics = vnfTemplateNicDao.listByTemplateId(template.getId()); + for (VnfTemplateNicVO vnfNic : vnfNics) { + if (vnfNic.isRequired() && vmNetworkMap.size() <= vnfNic.getDeviceId()) { + throw new InvalidParameterValueException("VNF nic is required but not found: " + vnfNic); + } + } + } + protected Set getOpenPortsForVnfAppliance(VirtualMachineTemplate template) { Set ports = new HashSet<>(); VnfTemplateDetailVO accessMethodsDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase()); diff --git a/server/src/test/java/com/cloud/template/HypervisorTemplateAdapterTest.java b/server/src/test/java/com/cloud/template/HypervisorTemplateAdapterTest.java index 2a6d7af434a..e2a97be469f 100644 --- a/server/src/test/java/com/cloud/template/HypervisorTemplateAdapterTest.java +++ b/server/src/test/java/com/cloud/template/HypervisorTemplateAdapterTest.java @@ -49,7 +49,6 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.events.Event; import org.apache.cloudstack.framework.events.EventDistributor; import org.apache.cloudstack.framework.messagebus.MessageBus; -import org.apache.cloudstack.secstorage.heuristics.HeuristicType; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.heuristics.HeuristicRuleHelper; @@ -339,7 +338,7 @@ public class HypervisorTemplateAdapterTest { Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds); Mockito.doReturn(null).when(_adapter).getImageStoresThrowsExceptionIfNotFound(Mockito.any(Long.class), Mockito.any(TemplateProfile.class)); - Mockito.doReturn(null).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); + Mockito.doReturn(null).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); Mockito.doNothing().when(_adapter).standardImageStoreAllocation(Mockito.isNull(), Mockito.any(VMTemplateVO.class)); _adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock); @@ -355,7 +354,7 @@ public class HypervisorTemplateAdapterTest { Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds); Mockito.doReturn(null).when(_adapter).getImageStoresThrowsExceptionIfNotFound(Mockito.any(Long.class), Mockito.any(TemplateProfile.class)); - Mockito.doReturn(null).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); + Mockito.doReturn(null).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); Mockito.doNothing().when(_adapter).standardImageStoreAllocation(Mockito.isNull(), Mockito.any(VMTemplateVO.class)); _adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock); @@ -371,7 +370,7 @@ public class HypervisorTemplateAdapterTest { List zoneIds = List.of(1L); Mockito.when(templateProfileMock.getZoneIdList()).thenReturn(zoneIds); - Mockito.doReturn(dataStoreMock).when(_adapter).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); + Mockito.doReturn(dataStoreMock).when(_templateMgr).verifyHeuristicRulesForZone(Mockito.any(VMTemplateVO.class), Mockito.anyLong()); Mockito.doNothing().when(_adapter).validateSecondaryStorageAndCreateTemplate(Mockito.any(List.class), Mockito.any(VMTemplateVO.class), Mockito.isNull()); _adapter.createTemplateWithinZones(templateProfileMock, vmTemplateVOMock); @@ -409,26 +408,6 @@ public class HypervisorTemplateAdapterTest { _adapter.getImageStoresThrowsExceptionIfNotFound(zoneId, templateProfileMock); } - @Test - public void verifyHeuristicRulesForZoneTestTemplateIsISOFormatShouldCheckForISOHeuristicType() { - VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class); - - Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(ImageFormat.ISO); - _adapter.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L); - - Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.ISO, vmTemplateVOMock); - } - - @Test - public void verifyHeuristicRulesForZoneTestTemplateNotISOFormatShouldCheckForTemplateHeuristicType() { - VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class); - - Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(ImageFormat.QCOW2); - _adapter.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L); - - Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.TEMPLATE, vmTemplateVOMock); - } - @Test public void isZoneAndImageStoreAvailableTestZoneIdIsNullShouldReturnFalse() { DataStore dataStoreMock = Mockito.mock(DataStore.class); diff --git a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java index 819694a226b..7bdc1e7c604 100755 --- a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java +++ b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java @@ -24,6 +24,7 @@ import com.cloud.api.query.dao.SnapshotJoinDao; import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.configuration.Resource; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; @@ -207,6 +208,8 @@ public class TemplateManagerImplTest { VnfTemplateManager vnfTemplateManager; @Inject SnapshotJoinDao snapshotJoinDao; + @Inject + TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao; @Inject HeuristicRuleHelper heuristicRuleHelperMock; @@ -753,6 +756,26 @@ public class TemplateManagerImplTest { Assert.assertNull(type); } + @Test + public void verifyHeuristicRulesForZoneTestTemplateIsISOFormatShouldCheckForISOHeuristicType() { + VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class); + + Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(Storage.ImageFormat.ISO); + templateManager.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L); + + Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.ISO, vmTemplateVOMock); + } + + @Test + public void verifyHeuristicRulesForZoneTestTemplateNotISOFormatShouldCheckForTemplateHeuristicType() { + VMTemplateVO vmTemplateVOMock = Mockito.mock(VMTemplateVO.class); + + Mockito.when(vmTemplateVOMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); + templateManager.verifyHeuristicRulesForZone(vmTemplateVOMock, 1L); + + Mockito.verify(heuristicRuleHelperMock, Mockito.times(1)).getImageStoreIfThereIsHeuristicRule(1L, HeuristicType.TEMPLATE, vmTemplateVOMock); + } + @Configuration @ComponentScan(basePackageClasses = {TemplateManagerImpl.class}, includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, @@ -959,6 +982,11 @@ public class TemplateManagerImplTest { return Mockito.mock(VnfTemplateManager.class); } + @Bean + public TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao() { + return Mockito.mock(TemplateDeployAsIsDetailsDao.class); + } + @Bean public SnapshotHelper snapshotHelper() { return Mockito.mock(SnapshotHelper.class); diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java index fe4ea0838f1..1ea78bff3db 100644 --- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java @@ -1163,7 +1163,7 @@ public class UserVmManagerImplTest { when(templateMock.isDeployAsIs()).thenReturn(false); when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); when(templateMock.getUserDataId()).thenReturn(null); - Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class)); + Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), nullable(Map.class)); ServiceOfferingJoinVO svcOfferingMock = Mockito.mock(ServiceOfferingJoinVO.class); when(serviceOfferingJoinDao.findById(anyLong())).thenReturn(svcOfferingMock); @@ -1175,7 +1175,7 @@ public class UserVmManagerImplTest { UserVm result = userVmManagerImpl.createVirtualMachine(deployVMCmd); assertEquals(userVmVoMock, result); - Mockito.verify(vnfTemplateManager).validateVnfApplianceNics(templateMock, null); + Mockito.verify(vnfTemplateManager).validateVnfApplianceNics(templateMock, null, Collections.emptyMap()); Mockito.verify(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), nullable(Boolean.class), any(), any(), any(), any(), any(), any(), any(), eq(true), any(), any(), any()); @@ -1419,7 +1419,7 @@ public class UserVmManagerImplTest { when(templateMock.isDeployAsIs()).thenReturn(false); when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); when(templateMock.getUserDataId()).thenReturn(null); - Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class)); + Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), nullable(Map.class)); ServiceOfferingJoinVO svcOfferingMock = Mockito.mock(ServiceOfferingJoinVO.class); when(serviceOfferingJoinDao.findById(anyLong())).thenReturn(svcOfferingMock); @@ -3879,7 +3879,7 @@ public class UserVmManagerImplTest { when(templateMock.isDeployAsIs()).thenReturn(false); when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); when(templateMock.getUserDataId()).thenReturn(null); - Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class)); + Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), any()); when(_dcMock.isLocalStorageEnabled()).thenReturn(false); when(_dcMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic); Mockito.doReturn(userVmVoMock).when(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(), @@ -3917,7 +3917,7 @@ public class UserVmManagerImplTest { when(templateMock.isDeployAsIs()).thenReturn(false); when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2); when(templateMock.getUserDataId()).thenReturn(null); - Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class)); + Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), any()); when(_dcMock.isLocalStorageEnabled()).thenReturn(false); when(_dcMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic); Mockito.doReturn(userVmVoMock).when(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(), diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java index 93120673720..54d8d67b6f8 100644 --- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java @@ -231,6 +231,13 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches return null; } + @Override + public Network createGuestNetwork(long networkOfferingId, String name, String displayText, Account owner, + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Pair vrIfaceMTUs) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { + return null; + } + /* (non-Javadoc) * @see com.cloud.network.NetworkService#searchForNetworks(com.cloud.api.commands.ListNetworksCmd) */ diff --git a/server/src/test/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImplTest.java index c3fa0d62604..b9565ebb292 100644 --- a/server/src/test/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImplTest.java @@ -228,25 +228,25 @@ public class VnfTemplateManagerImplTest { @Test public void testValidateVnfApplianceNicsWithRequiredNics() { List networkIds = Arrays.asList(200L, 201L); - vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds); + vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null); } @Test public void testValidateVnfApplianceNicsWithAllNics() { List networkIds = Arrays.asList(200L, 201L, 202L); - vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds); + vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null); } @Test(expected = InvalidParameterValueException.class) public void testValidateVnfApplianceNicsWithEmptyList() { List networkIds = new ArrayList<>(); - vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds); + vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null); } @Test(expected = InvalidParameterValueException.class) public void testValidateVnfApplianceNicsWithMissingNetworkId() { List networkIds = Arrays.asList(200L); - vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds); + vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null); } @Test diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index bbec2027bdc..2405d54162a 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -1725,11 +1725,12 @@ class Template: # If template is ready, # template.status = Download Complete # Downloading - x% Downloaded + # Processing - Initial status # Error - Any other string if template.status == 'Download Complete' and template.isready: return - elif 'Downloaded' in template.status: + elif 'Downloaded' in template.status or template.status == 'Processing': retries = retries - 1 continue diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 8253bbd87bc..275b8dbb0fe 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -47,6 +47,7 @@ "label.acl.rules": "ACL rules", "label.acl.reason.description": "Enter the reason behind an ACL rule.", "label.aclid": "ACL", +"label.aclname": "ACL name", "label.acl.rule.name": "ACL rule name", "label.acquire.new.ip": "Acquire new IP", "label.acquire.new.secondary.ip": "Acquire new secondary IP", @@ -2755,7 +2756,7 @@ "label.vnf.cidr.list": "CIDR from which access to the VNF appliance's Management interface should be allowed from", "label.vnf.cidr.list.tooltip": "the CIDR list to forward traffic from to the VNF management interface. Multiple entries must be separated by a single comma character (,). The default value is 0.0.0.0/0.", "label.vnf.configure.management": "Configure network rules for VNF's management interfaces", -"label.vnf.configure.management.tooltip": "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise. Learn what rules are configured at http://docs.cloudstack.apache.org/en/latest/adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances", +"label.vnf.configure.management.tooltip": "False by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. True otherwise. Learn what rules are configured at http://docs.cloudstack.apache.org/en/latest/adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances", "label.vnf.detail.add": "Add VNF detail", "label.vnf.detail.remove": "Remove VNF detail", "label.vnf.details": "VNF Details", diff --git a/ui/src/views/compute/DeployVnfAppliance.vue b/ui/src/views/compute/DeployVnfAppliance.vue index 93ea41ce885..36fdd86dbf6 100644 --- a/ui/src/views/compute/DeployVnfAppliance.vue +++ b/ui/src/views/compute/DeployVnfAppliance.vue @@ -360,6 +360,7 @@
@@ -1303,7 +1304,8 @@ export default { return tabList }, showVnfNicsSection () { - return this.networks && this.networks.length > 0 && this.vm.templateid && this.templateVnfNics && this.templateVnfNics.length > 0 + return ((this.networks && this.networks.length > 0) || (this.templateNics && this.templateNics.length > 0)) && + this.vm.templateid && this.templateVnfNics && this.templateVnfNics.length > 0 }, showVnfConfigureManagement () { const managementDeviceIds = [] @@ -1313,6 +1315,11 @@ export default { } } for (const deviceId of managementDeviceIds) { + if (this.templateNics && this.templateNics[deviceId] && + ((this.templateNics[deviceId].selectednetworktype === 'Isolated' && this.templateNics[deviceId].selectednetworkvpcid === undefined) || + (this.templateNics[deviceId].selectednetworktype === 'Shared' && this.templateNics[deviceId].selectednetworkwithsg))) { + return true + } if (this.vnfNicNetworks && this.vnfNicNetworks[deviceId] && ((this.vnfNicNetworks[deviceId].type === 'Isolated' && this.vnfNicNetworks[deviceId].vpcid === undefined) || (this.vnfNicNetworks[deviceId].type === 'Shared' && this.vnfNicNetworks[deviceId].service.filter(svc => svc.name === 'SecurityGroupProvider')))) { @@ -2090,7 +2097,7 @@ export default { // All checked networks should be used and only once. // Required NIC must be associated to a network // DeviceID must be consequent - if (this.templateVnfNics && this.templateVnfNics.length > 0) { + if (this.templateVnfNics && this.templateVnfNics.length > 0 && (!this.templateNics || this.templateNics.length === 0)) { let nextDeviceId = 0 const usedNetworkIds = [] const keys = Object.keys(this.vnfNicNetworks) @@ -2720,6 +2727,9 @@ export default { var network = this.options.networks[Math.min(i, this.options.networks.length - 1)] nic.selectednetworkid = network.id nic.selectednetworkname = network.name + nic.selectednetworktype = network.type + nic.selectednetworkvpcid = network.vpcid + nic.selectednetworkwithsg = network.service.filter(svc => svc.name === 'SecurityGroupProvider').length > 0 this.nicToNetworkSelection.push({ nic: nic.id, network: network.id }) } } diff --git a/ui/src/views/compute/wizard/VnfNicsSelection.vue b/ui/src/views/compute/wizard/VnfNicsSelection.vue index fdd5276b4f6..40bdc1c676a 100644 --- a/ui/src/views/compute/wizard/VnfNicsSelection.vue +++ b/ui/src/views/compute/wizard/VnfNicsSelection.vue @@ -50,6 +50,7 @@