Merge branch '4.20' into 4.22

This commit is contained in:
Daan Hoogland 2026-01-27 15:23:23 +01:00
commit 75db42bca6
32 changed files with 321 additions and 127 deletions

View File

@ -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<Integer, Integer> vrIfaceMTUs) throws
InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException;
Pair<List<? extends Network>, Integer> searchForNetworks(ListNetworksCmd cmd);
boolean deleteNetwork(long networkId, boolean forced);

View File

@ -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///////////////////
/////////////////////////////////////////////////////

View File

@ -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///////////////////
/////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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<Long> networkIds);
void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds, Map<Integer, Long> 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;
}

View File

@ -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<OVFNetworkTO> ovfNetworks, List<VNF.VnfNic> 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()));
}
}
}
}

View File

@ -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<DatadiskTO> getTemplateDisksOnImageStore(VirtualMachineTemplate template, DataStoreRole role, String configurationId);
static Boolean getValidateUrlIsResolvableBeforeRegisteringTemplateValue() {

View File

@ -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);

View File

@ -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;
}

View File

@ -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<String, TemplateProp> 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

View File

@ -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);

View File

@ -45,7 +45,7 @@ public final class CitrixUpdateHostPasswordCommandWrapper extends CommandWrapper
Pair<Boolean, String> 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) {

View File

@ -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);
}

View File

@ -82,6 +82,9 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
ConfigKey<Boolean> SAMLRequirePasswordLogin = new ConfigKey<Boolean>("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<Boolean> 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);

View File

@ -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};
}
}

View File

@ -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<List<HostVO>, Integer> uniqueHostPair = hostDao.searchAndCount(sc, searchFilter);
Integer count = uniqueHostPair.second();
List<Long> hostIds = uniqueHostPair.first().stream().map(HostVO::getId).collect(Collectors.toList());
@ -5715,6 +5723,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
protected Pair<List<ManagementServerJoinVO>, Integer> listManagementServersInternal(ListMgmtsCmd cmd) {
Long id = cmd.getId();
String name = cmd.getHostName();
String version = cmd.getVersion();
String keyword = cmd.getKeyword();
SearchBuilder<ManagementServerJoinVO> sb = managementServerJoinDao.createSearchBuilder();
SearchCriteria<ManagementServerJoinVO> 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);
}

View File

@ -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<Templa
_count = "select count(distinct temp_zone_pair) from template_view WHERE ";
}
private String getTemplateStatus(TemplateJoinVO template) {
String templateStatus = null;
if (template.getDownloadState() != Status.DOWNLOADED) {
templateStatus = "Processing";
if (template.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
if (template.getDownloadPercent() == 100) {
templateStatus = "Installing Template";
} else {
templateStatus = template.getDownloadPercent() + "% Downloaded";
}
} else if (template.getDownloadState() == Status.BYPASSED) {
templateStatus = "Bypassed Secondary Storage";
} else if (template.getErrorString() == null) {
templateStatus = template.getTemplateState().toString();
} else {
templateStatus = template.getErrorString().trim();
}
} else if (template.getDownloadState() == Status.DOWNLOADED) {
templateStatus = "Download Complete";
} else {
templateStatus = "Successfully Installed";
private enum TemplateStatus {
SUCCESSFULLY_INSTALLED("Successfully Installed"),
INSTALLING_TEMPLATE("Installing Template"),
INSTALLING_ISO("Installing ISO"),
BYPASSED_SECONDARY_STORAGE("Bypassed Secondary Storage"),
PROCESSING("Processing"),
DOWNLOADING("%d%% Downloaded"),
DOWNLOAD_COMPLETE("Download Complete");
private final String status;
TemplateStatus(String status) {
this.status = status;
}
return templateStatus;
public String getStatus() {
return status;
}
// For statuses that have dynamic details (e.g. "75% Downloaded").
public String format(int percent) {
return String.format(status, percent);
}
}
private String getTemplateStatus(TemplateJoinVO template) {
if (template == null) {
return null;
}
boolean isIso = Storage.ImageFormat.ISO == template.getFormat();
TemplateStatus templateStatus;
if (template.getDownloadState() == Status.DOWNLOADED) {
templateStatus = isIso ? TemplateStatus.SUCCESSFULLY_INSTALLED : TemplateStatus.DOWNLOAD_COMPLETE;
} else if (template.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
if (template.getDownloadPercent() == 100) {
templateStatus = isIso ? TemplateStatus.INSTALLING_ISO : TemplateStatus.INSTALLING_TEMPLATE;
} else {
return TemplateStatus.DOWNLOADING.format(template.getDownloadPercent());
}
} else if (template.getDownloadState() == Status.BYPASSED) {
templateStatus = TemplateStatus.BYPASSED_SECONDARY_STORAGE;
} else if (StringUtils.isNotBlank(template.getErrorString())) {
return template.getErrorString().trim();
} else {
templateStatus = TemplateStatus.PROCESSING;
}
return templateStatus.getStatus();
}
@Override
@ -503,24 +525,9 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
// If the user is an admin, add the template download status
if (isAdmin || caller.getId() == iso.getAccountId()) {
// add download status
if (iso.getDownloadState() != Status.DOWNLOADED) {
String isoStatus = "Processing";
if (iso.getDownloadState() == Status.DOWNLOADED) {
isoStatus = "Download Complete";
} else if (iso.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
if (iso.getDownloadPercent() == 100) {
isoStatus = "Installing ISO";
} else {
isoStatus = iso.getDownloadPercent() + "% Downloaded";
}
} else if (iso.getDownloadState() == Status.BYPASSED) {
isoStatus = "Bypassed Secondary Storage";
} else {
isoStatus = iso.getErrorString();
}
isoResponse.setStatus(isoStatus);
} else {
isoResponse.setStatus("Successfully Installed");
String templateStatus = getTemplateStatus(iso);
if (templateStatus != null) {
isoResponse.setStatus(templateStatus);
}
isoResponse.setUrl(iso.getUrl());
List<TemplateDataStoreVO> isosInStore = _templateStoreDao.listByTemplateNotBypassed(iso.getId());

View File

@ -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<Integer, Integer> 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) {

View File

@ -1747,8 +1747,9 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
scvm.setParameters("networkId", routerJoinVO.getNetworkId());
scvm.setParameters("state", VirtualMachine.State.Running);
List<UserVmJoinVO> 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())

View File

@ -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<DataStore> imageStores = getImageStoresThrowsExceptionIfNotFound(zoneId, profile);
@ -299,6 +299,14 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
}
}
protected List<DataStore> getImageStoresThrowsExceptionIfNotFound(long zoneId, TemplateProfile profile) {
List<DataStore> 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<DataStore> imageStores, VMTemplateVO template) {
Set<Long> zoneSet = new HashSet<Long>();
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<TemplateOrVolumePostUploadCommand> payloads = new LinkedList<>();
if (imageStore == null) {

View File

@ -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<OVFNetworkTO> 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<String, String> details) {
if (MapUtils.isEmpty(details)) {
return;

View File

@ -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");
}

View File

@ -201,7 +201,14 @@ public class VnfTemplateManagerImpl extends ManagerBase implements VnfTemplateMa
}
@Override
public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds) {
public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds, Map<Integer, Long> 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<Integer, Long> vmNetworkMap) {
if (MapUtils.isEmpty(vmNetworkMap)) {
throw new InvalidParameterValueException("VNF networks map is empty");
}
List<VnfTemplateNicVO> 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<Integer> getOpenPortsForVnfAppliance(VirtualMachineTemplate template) {
Set<Integer> ports = new HashSet<>();
VnfTemplateDetailVO accessMethodsDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase());

View File

@ -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<Long> 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);

View File

@ -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);

View File

@ -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(),

View File

@ -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<Integer, Integer> vrIfaceMTUs)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
return null;
}
/* (non-Javadoc)
* @see com.cloud.network.NetworkService#searchForNetworks(com.cloud.api.commands.ListNetworksCmd)
*/

View File

@ -228,25 +228,25 @@ public class VnfTemplateManagerImplTest {
@Test
public void testValidateVnfApplianceNicsWithRequiredNics() {
List<Long> networkIds = Arrays.asList(200L, 201L);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
}
@Test
public void testValidateVnfApplianceNicsWithAllNics() {
List<Long> networkIds = Arrays.asList(200L, 201L, 202L);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidateVnfApplianceNicsWithEmptyList() {
List<Long> networkIds = new ArrayList<>();
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidateVnfApplianceNicsWithMissingNetworkId() {
List<Long> networkIds = Arrays.asList(200L);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
}
@Test

View File

@ -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

View File

@ -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",

View File

@ -360,6 +360,7 @@
<div>
<vnf-nics-selection
:items="templateVnfNics"
:templateNics="templateNics"
:networks="networks"
@update-vnf-nic-networks="($event) => updateVnfNicNetworks($event)" />
</div>
@ -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 })
}
}

View File

@ -50,6 +50,7 @@
<template #network="{ record }">
<a-form-item style="display: block" :name="'nic-' + record.deviceid">
<a-select
disabled="templateNics && templateNics.length > 0"
@change="updateNicNetworkValue($event, record.deviceid)"
optionFilterProp="label"
:filterOption="(input, option) => {
@ -75,6 +76,10 @@ export default {
type: Array,
default: () => []
},
templateNics: {
type: Array,
default: () => []
},
networks: {
type: Array,
default: () => []