Merge branch 'main' of https://github.com/apache/cloudstack into nsx-integration

This commit is contained in:
Pearl Dsilva 2023-12-18 10:02:05 -05:00
commit 7cabc66f1c
27 changed files with 364 additions and 63 deletions

View File

@ -1,6 +1,6 @@
# Apache CloudStack [![Build Status](https://github.com/apache/cloudstack/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/apache/cloudstack/actions/workflows/build.yml) [![UI Build](https://github.com/apache/cloudstack/actions/workflows/ui.yml/badge.svg)](https://github.com/apache/cloudstack/actions/workflows/ui.yml) [![License Check](https://github.com/apache/cloudstack/actions/workflows/rat.yml/badge.svg?branch=main)](https://github.com/apache/cloudstack/actions/workflows/rat.yml) [![Simulator CI](https://github.com/apache/cloudstack/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/apache/cloudstack/actions/workflows/ci.yml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=apache_cloudstack&metric=alert_status)](https://sonarcloud.io/dashboard?id=apache_cloudstack) [![codecov](https://codecov.io/gh/apache/cloudstack/branch/main/graph/badge.svg)](https://codecov.io/gh/apache/cloudstack)
[![Apache CloudStack](tools/logo/apache_cloudstack.png)](https://cloudstack.apache.org/)
[![Apache CloudStack](tools/logo/acsxmas.jpg)](https://cloudstack.apache.org/)
Apache CloudStack is open source software designed to deploy and manage large
networks of virtual machines, as a highly available, highly scalable

View File

@ -30,6 +30,8 @@ public interface PublicIpQuarantine extends InternalIdentity, Identity {
String getRemovalReason();
Long getRemoverAccountId();
Date getRemoved();
Date getCreated();

View File

@ -811,6 +811,7 @@ public class ApiConstants {
public static final String IPSEC_PSK = "ipsecpsk";
public static final String GUEST_IP = "guestip";
public static final String REMOVED = "removed";
public static final String REMOVER_ACCOUNT_ID = "removeraccountid";
public static final String REMOVAL_REASON = "removalreason";
public static final String COMPLETED = "completed";
public static final String IKE_VERSION = "ikeversion";

View File

@ -60,6 +60,10 @@ public class IpQuarantineResponse extends BaseResponse {
@Param(description = "The reason for removing the IP from quarantine prematurely.")
private String removalReason;
@SerializedName(ApiConstants.REMOVER_ACCOUNT_ID)
@Param(description = "ID of the account that removed the IP from quarantine.")
private String removerAccountId;
public IpQuarantineResponse() {
super("quarantinedips");
}
@ -127,4 +131,12 @@ public class IpQuarantineResponse extends BaseResponse {
public void setRemovalReason(String removalReason) {
this.removalReason = removalReason;
}
public String getRemoverAccountId() {
return removerAccountId;
}
public void setRemoverAccountId(String removerAccountId) {
this.removerAccountId = removerAccountId;
}
}

View File

@ -3295,7 +3295,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
// get updated state for the network
network = _networksDao.findById(networkId);
if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup && !forced) {
s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState());
s_logger.debug("Network is not in the correct state to be destroyed: " + network.getState());
return false;
}

View File

@ -63,6 +63,9 @@ public class PublicIpQuarantineVO implements PublicIpQuarantine {
@Column(name = "removal_reason")
private String removalReason = null;
@Column(name = "remover_account_id")
private Long removerAccountId = null;
public PublicIpQuarantineVO() {
}
@ -98,6 +101,11 @@ public class PublicIpQuarantineVO implements PublicIpQuarantine {
return removalReason;
}
@Override
public Long getRemoverAccountId() {
return this.removerAccountId;
}
@Override
public String getUuid() {
return uuid;
@ -111,6 +119,10 @@ public class PublicIpQuarantineVO implements PublicIpQuarantine {
this.removalReason = removalReason;
}
public void setRemoverAccountId(Long removerAccountId) {
this.removerAccountId = removerAccountId;
}
@Override
public Date getRemoved() {
return removed;

View File

@ -77,6 +77,7 @@ public class Upgrade41810to41900 implements DbUpgrade, DbUpgradeSystemVmTemplate
decryptConfigurationValuesFromAccountAndDomainScopesNotInSecureHiddenCategories(conn);
migrateBackupDates(conn);
addIndexes(conn);
addRemoverAccountIdForeignKeyToQuarantinedIps(conn);
}
@Override
@ -262,4 +263,7 @@ public class Upgrade41810to41900 implements DbUpgrade, DbUpgradeSystemVmTemplate
DbUpgradeUtils.addIndexIfNeeded(conn, "event", "resource_type", "resource_id");
}
private void addRemoverAccountIdForeignKeyToQuarantinedIps(Connection conn) {
DbUpgradeUtils.addForeignKey(conn, "quarantined_ips", "remover_account_id", "account", "id");
}
}

View File

@ -21,6 +21,8 @@
ALTER TABLE `cloud`.`mshost` MODIFY COLUMN `state` varchar(25);
UPDATE `cloud`.`network_offerings` SET conserve_mode=1 WHERE name='DefaultIsolatedNetworkOfferingForVpcNetworks';
-- Invalidate existing console_session records
UPDATE `cloud`.`console_session` SET removed=now();
-- Modify acquired column in console_session to datetime type
@ -351,3 +353,6 @@ CREATE TABLE `cloud_usage`.`bucket_statistics` (
`size` bigint unsigned COMMENT 'total size of bucket objects',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Add remover account ID to quarantined IPs table.
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.quarantined_ips', 'remover_account_id', 'bigint(20) unsigned DEFAULT NULL COMMENT "ID of the account that removed the IP from quarantine, foreign key to `account` table"');

View File

@ -69,12 +69,12 @@ public final class ConfigureSimulatorHAProviderState extends BaseCmd {
private Boolean activity;
@Parameter(name = ApiConstants.RECOVER, type = CommandType.BOOLEAN,
description = "Set true is haprovider for simulator host should be be recoverable",
description = "Set true is haprovider for simulator host should be recoverable",
required = true)
private Boolean recovery;
@Parameter(name = ApiConstants.FENCE, type = CommandType.BOOLEAN,
description = "Set true is haprovider for simulator host should be be fence-able",
description = "Set true is haprovider for simulator host should be fence-able",
required = true)
private Boolean fenceable;

View File

@ -3543,7 +3543,7 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
if (diskInfo == null) {
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
if (diskInfo != null) {
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
s_logger.info("Found existing disk from chain device bus information: " + infoInChain.getDiskDeviceBusName());
return diskInfo;
}
}

View File

@ -2209,7 +2209,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
if (diskInfo == null) {
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
if (diskInfo != null) {
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
s_logger.info("Found existing disk from chain device bus information: " + infoInChain.getDiskDeviceBusName());
return diskInfo;
}
}

View File

@ -5210,6 +5210,10 @@ public class ApiResponseHelper implements ResponseGenerator {
quarantinedIpsResponse.setRemoved(quarantinedIp.getRemoved());
quarantinedIpsResponse.setEndDate(quarantinedIp.getEndDate());
quarantinedIpsResponse.setRemovalReason(quarantinedIp.getRemovalReason());
if (quarantinedIp.getRemoverAccountId() != null) {
Account removerAccount = _accountMgr.getAccount(quarantinedIp.getRemoverAccountId());
quarantinedIpsResponse.setRemoverAccountId(removerAccount.getUuid());
}
quarantinedIpsResponse.setResponseName("quarantinedip");
return quarantinedIpsResponse;

View File

@ -2471,9 +2471,11 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
PublicIpQuarantineVO publicIpQuarantineVO = publicIpQuarantineDao.findById(quarantineProcessId);
Ip ipAddress = _ipAddressDao.findById(publicIpQuarantineVO.getPublicIpAddressId()).getAddress();
Date removedDate = new Date();
Long removerAccountId = CallContext.current().getCallingAccountId();
publicIpQuarantineVO.setRemoved(removedDate);
publicIpQuarantineVO.setRemovalReason(removalReason);
publicIpQuarantineVO.setRemoverAccountId(removerAccountId);
s_logger.debug(String.format("Removing public IP Address [%s] from quarantine by updating the removed date to [%s].", ipAddress, removedDate));
publicIpQuarantineDao.persist(publicIpQuarantineVO);

View File

@ -18,10 +18,12 @@ package com.cloud.storage;
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.sql.PreparedStatement;
@ -132,8 +134,9 @@ import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -254,8 +257,6 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.common.collect.Sets;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@Component
@ -684,12 +685,21 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
return true;
}
private DataStore createLocalStorage(Map<String, Object> poolInfos) throws ConnectionException{
protected String getValidatedPareForLocalStorage(Object obj, String paramName) {
String result = obj == null ? null : obj.toString();
if (StringUtils.isEmpty(result)) {
throw new InvalidParameterValueException(String.format("Invalid %s provided", paramName));
}
return result;
}
protected DataStore createLocalStorage(Map<String, Object> poolInfos) throws ConnectionException{
Object existingUuid = poolInfos.get("uuid");
if( existingUuid == null ){
poolInfos.put("uuid", UUID.randomUUID().toString());
}
String hostAddress = poolInfos.get("host").toString();
String hostAddress = getValidatedPareForLocalStorage(poolInfos.get("host"), "host");
String hostPath = getValidatedPareForLocalStorage(poolInfos.get("hostPath"), "path");
Host host = _hostDao.findByName(hostAddress);
if( host == null ) {
@ -708,8 +718,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
StoragePoolInfo pInfo = new StoragePoolInfo(poolInfos.get("uuid").toString(),
host.getPrivateIpAddress(),
poolInfos.get("hostPath").toString(),
poolInfos.get("hostPath").toString(),
hostPath,
hostPath,
StoragePoolType.Filesystem,
capacityBytes,
0,
@ -809,6 +819,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException {
String providerName = cmd.getStorageProviderName();
Map<String,String> uriParams = extractUriParamsAsMap(cmd.getUrl());
boolean isFileScheme = "file".equals(uriParams.get("scheme"));
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(providerName);
if (storeProvider == null) {
@ -822,7 +833,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
Long podId = cmd.getPodId();
Long zoneId = cmd.getZoneId();
ScopeType scopeType = uriParams.get("scheme").toString().equals("file") ? ScopeType.HOST : ScopeType.CLUSTER;
ScopeType scopeType = ScopeType.CLUSTER;
if (isFileScheme) {
scopeType = ScopeType.HOST;
}
String scope = cmd.getScope();
if (scope != null) {
try {
@ -889,12 +903,14 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
params.put("managed", cmd.isManaged());
params.put("capacityBytes", cmd.getCapacityBytes());
params.put("capacityIops", cmd.getCapacityIops());
params.putAll(uriParams);
if (MapUtils.isNotEmpty(uriParams)) {
params.putAll(uriParams);
}
DataStoreLifeCycle lifeCycle = storeProvider.getDataStoreLifeCycle();
DataStore store = null;
try {
if (params.get("scheme").toString().equals("file")) {
if (isFileScheme) {
store = createLocalStorage(params);
} else {
store = lifeCycle.initialize(params);
@ -923,42 +939,55 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
return (PrimaryDataStoreInfo)_dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Primary);
}
private Map<String,String> extractUriParamsAsMap(String url){
protected Map<String,String> extractUriParamsAsMap(String url) {
Map<String,String> uriParams = new HashMap<>();
UriUtils.UriInfo uriInfo = UriUtils.getUriInfo(url);
UriUtils.UriInfo uriInfo;
try {
uriInfo = UriUtils.getUriInfo(url);
} catch (CloudRuntimeException cre) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("URI validation for url: %s failed, returning empty uri params", url));
}
return uriParams;
}
String scheme = uriInfo.getScheme();
String storageHost = uriInfo.getStorageHost();
String storagePath = uriInfo.getStoragePath();
try {
if (scheme == null) {
throw new InvalidParameterValueException("scheme is null " + url + ", add nfs:// (or cifs://) as a prefix");
} else if (scheme.equalsIgnoreCase("nfs")) {
if (storageHost == null || storagePath == null || storageHost.trim().isEmpty() || storagePath.trim().isEmpty()) {
throw new InvalidParameterValueException("host or path is null, should be nfs://hostname/path");
}
} else if (scheme.equalsIgnoreCase("cifs")) {
// Don't validate against a URI encoded URI.
if (scheme == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Scheme for url: %s is not found, returning empty uri params", url));
}
return uriParams;
}
boolean isHostOrPathBlank = StringUtils.isAnyBlank(storagePath, storageHost);
if (scheme.equalsIgnoreCase("nfs")) {
if (isHostOrPathBlank) {
throw new InvalidParameterValueException("host or path is null, should be nfs://hostname/path");
}
} else if (scheme.equalsIgnoreCase("cifs")) {
// Don't validate against a URI encoded URI.
try {
URI cifsUri = new URI(url);
String warnMsg = UriUtils.getCifsUriParametersProblems(cifsUri);
if (warnMsg != null) {
throw new InvalidParameterValueException(warnMsg);
}
} else if (scheme.equalsIgnoreCase("sharedMountPoint")) {
if (storagePath == null) {
throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path");
}
} else if (scheme.equalsIgnoreCase("rbd")) {
if (storagePath == null) {
throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool");
}
} else if (scheme.equalsIgnoreCase("gluster")) {
if (storageHost == null || storagePath == null || storageHost.trim().isEmpty() || storagePath.trim().isEmpty()) {
throw new InvalidParameterValueException("host or path is null, should be gluster://hostname/volume");
}
} catch (URISyntaxException e) {
throw new InvalidParameterValueException(url + " is not a valid uri");
}
} else if (scheme.equalsIgnoreCase("sharedMountPoint")) {
if (storagePath == null) {
throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path");
}
} else if (scheme.equalsIgnoreCase("rbd")) {
if (storagePath == null) {
throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool");
}
} else if (scheme.equalsIgnoreCase("gluster")) {
if (isHostOrPathBlank) {
throw new InvalidParameterValueException("host or path is null, should be gluster://hostname/volume");
}
} catch (URISyntaxException e) {
throw new InvalidParameterValueException(url + " is not a valid uri");
}
String hostPath = null;
@ -975,7 +1004,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
uriParams.put("host", storageHost);
uriParams.put("hostPath", hostPath);
uriParams.put("userInfo", uriInfo.getUserInfo());
uriParams.put("port", uriInfo.getPort() + "");
if (uriInfo.getPort() > 0) {
uriParams.put("port", uriInfo.getPort() + "");
}
return uriParams;
}

View File

@ -17,10 +17,12 @@
package com.cloud.api;
import com.cloud.domain.DomainVO;
import com.cloud.network.PublicIpQuarantine;
import com.cloud.network.as.AutoScaleVmGroup;
import com.cloud.network.as.AutoScaleVmGroupVO;
import com.cloud.network.as.AutoScaleVmProfileVO;
import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerVO;
import com.cloud.network.dao.NetworkServiceMapDao;
@ -41,6 +43,7 @@ import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
import org.apache.cloudstack.api.response.IpQuarantineResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
import org.apache.cloudstack.api.response.UsageRecordResponse;
@ -97,6 +100,9 @@ public class ApiResponseHelperTest {
@Mock
UserDataDao userDataDaoMock;
@Mock
IPAddressDao ipAddressDaoMock;
@Spy
@InjectMocks
ApiResponseHelper apiResponseHelper = new ApiResponseHelper();
@ -396,4 +402,54 @@ public class ApiResponseHelperTest {
Assert.assertEquals(1, response.getDisks().size());
Assert.assertEquals(1, response.getNics().size());
}
@Test
public void createQuarantinedIpsResponseTestReturnsObject() {
String quarantinedIpUuid = "quarantined_ip_uuid";
Long previousOwnerId = 300L;
String previousOwnerUuid = "previous_owner_uuid";
String previousOwnerName = "previous_owner_name";
Long removerAccountId = 400L;
String removerAccountUuid = "remover_account_uuid";
Long publicIpAddressId = 500L;
String publicIpAddress = "1.2.3.4";
Date created = new Date(599L);
Date removed = new Date(600L);
Date endDate = new Date(601L);
String removalReason = "removalReason";
PublicIpQuarantine quarantinedIpMock = Mockito.mock(PublicIpQuarantine.class);
IPAddressVO ipAddressVoMock = Mockito.mock(IPAddressVO.class);
Account previousOwner = Mockito.mock(Account.class);
Account removerAccount = Mockito.mock(Account.class);
Mockito.when(quarantinedIpMock.getUuid()).thenReturn(quarantinedIpUuid);
Mockito.when(quarantinedIpMock.getPreviousOwnerId()).thenReturn(previousOwnerId);
Mockito.when(quarantinedIpMock.getPublicIpAddressId()).thenReturn(publicIpAddressId);
Mockito.doReturn(ipAddressVoMock).when(ipAddressDaoMock).findById(publicIpAddressId);
Mockito.when(ipAddressVoMock.getAddress()).thenReturn(new Ip(publicIpAddress));
Mockito.doReturn(previousOwner).when(accountManagerMock).getAccount(previousOwnerId);
Mockito.when(previousOwner.getUuid()).thenReturn(previousOwnerUuid);
Mockito.when(previousOwner.getName()).thenReturn(previousOwnerName);
Mockito.when(quarantinedIpMock.getCreated()).thenReturn(created);
Mockito.when(quarantinedIpMock.getRemoved()).thenReturn(removed);
Mockito.when(quarantinedIpMock.getEndDate()).thenReturn(endDate);
Mockito.when(quarantinedIpMock.getRemovalReason()).thenReturn(removalReason);
Mockito.when(quarantinedIpMock.getRemoverAccountId()).thenReturn(removerAccountId);
Mockito.when(removerAccount.getUuid()).thenReturn(removerAccountUuid);
Mockito.doReturn(removerAccount).when(accountManagerMock).getAccount(removerAccountId);
IpQuarantineResponse result = apiResponseHelper.createQuarantinedIpsResponse(quarantinedIpMock);
Assert.assertEquals(quarantinedIpUuid, result.getId());
Assert.assertEquals(publicIpAddress, result.getPublicIpAddress());
Assert.assertEquals(previousOwnerUuid, result.getPreviousOwnerId());
Assert.assertEquals(previousOwnerName, result.getPreviousOwnerName());
Assert.assertEquals(created, result.getCreated());
Assert.assertEquals(removed, result.getRemoved());
Assert.assertEquals(endDate, result.getEndDate());
Assert.assertEquals(removalReason, result.getRemovalReason());
Assert.assertEquals(removerAccountUuid, result.getRemoverAccountId());
Assert.assertEquals("quarantinedip", result.getResponseName());
}
}

View File

@ -36,12 +36,14 @@ import com.cloud.network.dao.PublicIpQuarantineDao;
import com.cloud.network.vo.PublicIpQuarantineVO;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import org.apache.cloudstack.context.CallContext;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
@ -397,6 +399,31 @@ public class IpAddressManagerTest {
Assert.assertFalse(result);
}
@Test
public void removePublicIpAddressFromQuarantineTestPersistsObject() {
Long quarantineProcessId = 100L;
Long publicAddressId = 200L;
Long callingAccountId = 300L;
String removalReason = "removalReason";
try (MockedStatic<CallContext> callContextMockedStatic = Mockito.mockStatic(CallContext.class)) {
Mockito.doReturn(publicIpQuarantineVOMock).when(publicIpQuarantineDaoMock).findById(quarantineProcessId);
Mockito.when(publicIpQuarantineVOMock.getPublicIpAddressId()).thenReturn(publicAddressId);
Mockito.doReturn(ipAddressVO).when(ipAddressDao).findById(publicAddressId);
CallContext callContextMock = Mockito.mock(CallContext.class);
Mockito.when(callContextMock.getCallingAccountId()).thenReturn(callingAccountId);
callContextMockedStatic.when(CallContext::current).thenReturn(callContextMock);
ipAddressManager.removePublicIpAddressFromQuarantine(quarantineProcessId, removalReason);
Mockito.verify(publicIpQuarantineVOMock).setRemoved(Mockito.any());
Mockito.verify(publicIpQuarantineVOMock).setRemovalReason(removalReason);
Mockito.verify(publicIpQuarantineVOMock).setRemoverAccountId(callingAccountId);
Mockito.verify(publicIpQuarantineDaoMock).persist(publicIpQuarantineVOMock);
}
}
@Test
public void updateSourceNatIpAddress() throws Exception {
IPAddressVO requestedIp = Mockito.mock(IPAddressVO.class);

View File

@ -17,12 +17,15 @@
package com.cloud.storage;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.exception.ConnectionException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.Host;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.collections.MapUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -33,7 +36,9 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class StorageManagerImplTest {
@ -157,4 +162,48 @@ public class StorageManagerImplTest {
}
@Test
public void testExtractUriParamsAsMapWithSolidFireUrl() {
String sfUrl = "MVIP=1.2.3.4;SVIP=6.7.8.9;clusterAdminUsername=admin;" +
"clusterAdminPassword=password;clusterDefaultMinIops=1000;" +
"clusterDefaultMaxIops=2000;clusterDefaultBurstIopsPercentOfMaxIops=2";
Map<String,String> uriParams = storageManagerImpl.extractUriParamsAsMap(sfUrl);
Assert.assertTrue(MapUtils.isEmpty(uriParams));
}
@Test
public void testExtractUriParamsAsMapWithNFSUrl() {
String scheme = "nfs";
String host = "HOST";
String path = "/PATH";
String sfUrl = String.format("%s://%s%s", scheme, host, path);
Map<String,String> uriParams = storageManagerImpl.extractUriParamsAsMap(sfUrl);
Assert.assertTrue(MapUtils.isNotEmpty(uriParams));
Assert.assertEquals(scheme, uriParams.get("scheme"));
Assert.assertEquals(host, uriParams.get("host"));
Assert.assertEquals(path, uriParams.get("hostPath"));
}
@Test(expected = InvalidParameterValueException.class)
public void testCreateLocalStorageHostFailure() {
Map<String, Object> test = new HashMap<>();
test.put("host", null);
try {
storageManagerImpl.createLocalStorage(test);
} catch (ConnectionException e) {
throw new RuntimeException(e);
}
}
@Test(expected = InvalidParameterValueException.class)
public void testCreateLocalStoragePathFailure() {
Map<String, Object> test = new HashMap<>();
test.put("host", "HOST");
test.put("hostPath", "");
try {
storageManagerImpl.createLocalStorage(test);
} catch (ConnectionException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1244,7 +1244,7 @@ class TestListInstances(cloudstackTestCase):
status[0],
"Listing VM's by name and zone failed"
)
# Verifying Verifying that the size of the list is 1
# Verifying that the size of the list is 1
self.assertEqual(
1,
len(list_vms),
@ -1404,7 +1404,7 @@ class TestListInstances(cloudstackTestCase):
status[0],
"Listing VM's by name and zone failed"
)
# Verifying Verifying that the size of the list is 1
# Verifying that the size of the list is 1
self.assertEqual(
1,
len(list_vms),
@ -1474,7 +1474,7 @@ class TestListInstances(cloudstackTestCase):
status[0],
"Listing VM's by name, account and zone failed"
)
# Verifying Verifying that the size of the list is 1
# Verifying that the size of the list is 1
self.assertEqual(
1,
len(list_vms),

View File

@ -1001,23 +1001,23 @@ class TestVPCNetwork(cloudstackTestCase):
# 1. Create a network offering with guest type=Isolated that has all
# supported Services(Vpn,dhcpdns,UserData, SourceNat,Static NAT,LB
# and PF,LB,NetworkAcl ) provided by VPCVR and conserve mode is ON
# 2. Create offering fails since Conserve mode ON isn't allowed within
# VPC
# 2. Create offering should succeed since Conserve mode ON is allowed within
# VPC since https://github.com/apache/cloudstack/pull/8309
# 3. Repeat test for offering which has Netscaler as external LB
# provider
"""
self.debug("Creating network offering with conserve mode = ON")
with self.assertRaises(Exception):
try:
nw = NetworkOffering.create(
self.apiclient,
self.services[value],
conservemode=True
)
self.cleanup.append(nw)
self.debug(
"Network creation failed as VPC support nw with conserve mode OFF")
except Exception as e:
self.warn("Network creation failed in VPC with conserve mode ON")
return

View File

@ -330,6 +330,10 @@
<router-link v-if="record.roleid && $router.resolve('/role/' + record.roleid).matched[0].redirect !== '/exception/404'" :to="{ path: '/role/' + record.roleid }">{{ text }}</router-link>
<span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'project'">
<router-link v-if="$router.resolve('/project/' + record.projectid).matched[0].redirect !== '/exception/404'" :to="{ path: '/project/' + record.projectid }">{{ text }}</router-link>
<span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'templateversion'">
<span> {{ record.version }} </span>
</template>

View File

@ -61,16 +61,18 @@ export default {
if (store.getters.metrics) {
fields.push(...metricsFields)
}
if (store.getters.userInfo.roletype === 'Admin') {
fields.splice(2, 0, 'instancename')
fields.push('account')
fields.push('hostname')
fields.push('account')
} else if (store.getters.userInfo.roletype === 'DomainAdmin') {
fields.push('account')
} else {
fields.push('serviceofferingname')
}
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('zonename')
return fields
},
@ -464,8 +466,13 @@ export default {
columns: () => {
const fields = ['displayname', 'state', 'name', 'type', 'current', 'parentName', 'created']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('domain')
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
} else if (store.getters.listAllProjects) {
fields.push('project')
}
return fields
},
@ -536,6 +543,9 @@ export default {
if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) {
fields.push('account')
}
if (store.listAllProjects) {
fields.push('project')
}
if (store.apis.scaleKubernetesCluster.params.filter(x => x.name === 'autoscalingenabled').length > 0) {
fields.splice(2, 0, 'autoscalingenabled')
}
@ -633,7 +643,13 @@ export default {
docHelp: 'adminguide/autoscale_without_netscaler.html',
resourceType: 'AutoScaleVmGroup',
permission: ['listAutoScaleVmGroups'],
columns: ['name', 'state', 'associatednetworkname', 'publicip', 'publicport', 'privateport', 'minmembers', 'maxmembers', 'availablevirtualmachinecount', 'account'],
columns: (store) => {
var fields = ['name', 'state', 'associatednetworkname', 'publicip', 'publicport', 'privateport', 'minmembers', 'maxmembers', 'availablevirtualmachinecount', 'account']
if (store.listAllProjects) {
fields.push('project')
}
return fields
},
details: ['name', 'id', 'account', 'domain', 'associatednetworkname', 'associatednetworkid', 'lbruleid', 'lbprovider', 'publicip', 'publicipid', 'publicport', 'privateport', 'minmembers', 'maxmembers', 'availablevirtualmachinecount', 'interval', 'state', 'created'],
related: [{
name: 'vm',
@ -737,7 +753,15 @@ export default {
docHelp: 'adminguide/virtual_machines.html#changing-the-vm-name-os-or-group',
resourceType: 'VMInstanceGroup',
permission: ['listInstanceGroups'],
columns: ['name', 'account', 'domain'],
columns: (store) => {
var fields = ['name', 'account']
if (store.listAllProjects) {
fields.push('project')
}
fields.push('domain')
return fields
},
details: ['name', 'id', 'account', 'domain', 'created'],
related: [{
name: 'vm',
@ -791,7 +815,12 @@ export default {
var fields = ['name', 'fingerprint']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
} else if (store.getters.listAllProjects) {
fields.push('project')
}
return fields
},
@ -941,7 +970,12 @@ export default {
var fields = ['name', 'type', 'description']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
} else if (store.getters.listAllProjects) {
fields.push('project')
}
return fields
},

View File

@ -15,13 +15,22 @@
// specific language governing permissions and limitations
// under the License.
import store from '@/store'
export default {
name: 'event',
title: 'label.events',
icon: 'ScheduleOutlined',
docHelp: 'adminguide/events.html',
permission: ['listEvents'],
columns: ['level', 'type', 'state', 'description', 'resource', 'username', 'account', 'domain', 'created'],
columns: () => {
var fields = ['level', 'type', 'state', 'description', 'resource', 'username', 'account']
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push(...['domain', 'created'])
return fields
},
details: ['username', 'id', 'description', 'resourcetype', 'resourceid', 'state', 'level', 'type', 'account', 'domain', 'created'],
searchFilters: ['level', 'domainid', 'account', 'keyword', 'resourcetype'],
related: [{

View File

@ -47,6 +47,9 @@ export default {
fields.push('size')
fields.push('account')
}
if (store.getters.listAllProjects) {
fields.push('project')
}
if (['Admin'].includes(store.getters.userInfo.roletype)) {
fields.push('templatetype')
fields.push('order')
@ -220,6 +223,9 @@ export default {
fields.push('size')
fields.push('account')
}
if (store.getters.listAllProjects) {
fields.push('project')
}
if (['Admin'].includes(store.getters.userInfo.roletype)) {
fields.push('order')
}

View File

@ -34,10 +34,16 @@ export default {
permission: ['listNetworks'],
resourceType: 'Network',
columns: () => {
var fields = ['name', 'state', 'type', 'vpcname', 'cidr', 'ip6cidr', 'broadcasturi', 'domainpath', 'account', 'zonename']
var fields = ['name', 'state', 'type', 'vpcname', 'cidr', 'ip6cidr', 'broadcasturi', 'domainpath']
if (!isAdmin()) {
fields = fields.filter(function (e) { return e !== 'broadcasturi' })
}
if (store.getters.listAllProjects) {
fields.push('project')
} else {
fields.push('account')
}
fields.push('zonename')
return fields
},
details: () => {
@ -197,7 +203,14 @@ export default {
docHelp: 'adminguide/networking_and_traffic.html#configuring-a-virtual-private-cloud',
permission: ['listVPCs'],
resourceType: 'Vpc',
columns: ['name', 'state', 'displaytext', 'cidr', 'account', 'domain', 'zonename'],
columns: () => {
var fields = ['name', 'state', 'displaytext', 'cidr', 'account']
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push(...['domain', 'zonename'])
return fields
},
details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu'],
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'tags'],
related: [{
@ -334,10 +347,16 @@ export default {
if (store.getters.userInfo.roletype === 'Admin') {
fields.splice(2, 0, 'instancename')
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
fields.push('hostname')
} else if (store.getters.userInfo.roletype === 'DomainAdmin') {
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
} else {
fields.push('serviceofferingname')
}
@ -730,7 +749,14 @@ export default {
docHelp: 'adminguide/networking_and_traffic.html#reserving-public-ip-addresses-and-vlans-for-accounts',
permission: ['listPublicIpAddresses'],
resourceType: 'PublicIpAddress',
columns: ['ipaddress', 'state', 'associatednetworkname', 'vpcname', 'virtualmachinename', 'allocated', 'account', 'domain', 'zonename'],
columns: () => {
var fields = ['ipaddress', 'state', 'associatednetworkname', 'vpcname', 'virtualmachinename', 'allocated', 'account']
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push(...['domain', 'zonename'])
return fields
},
details: ['ipaddress', 'id', 'associatednetworkname', 'virtualmachinename', 'networkid', 'issourcenat', 'isstaticnat', 'virtualmachinename', 'vmipaddress', 'vlan', 'allocated', 'account', 'domain', 'zonename'],
filters: ['allocated', 'reserved', 'free'],
component: shallowRef(() => import('@/views/network/PublicIpResource.vue')),
@ -1120,7 +1146,14 @@ export default {
title: 'label.vpncustomergatewayid',
icon: 'lock-outlined',
permission: ['listVpnCustomerGateways'],
columns: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'account', 'domain'],
columns: () => {
var fields = ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'account']
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
return fields
},
details: ['name', 'id', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'ikeversion', 'esppolicy', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'account', 'domain'],
searchFilters: ['keyword', 'domainid', 'account'],
resourceType: 'VPNCustomerGateway',

View File

@ -49,13 +49,15 @@ export default {
if (store.getters.metrics) {
fields.push(...metricsFields)
}
if (store.getters.userInfo.roletype === 'Admin') {
fields.push('account')
fields.push('storage')
fields.push('account')
} else if (store.getters.userInfo.roletype === 'DomainAdmin') {
fields.push('account')
}
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('zonename')
return fields
@ -320,7 +322,12 @@ export default {
var fields = ['name', 'state', 'volumename', 'intervaltype', 'physicalsize', 'created']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('account')
if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('domain')
} else if (store.getters.listAllProjects) {
fields.push('project')
}
fields.push('zonename')
return fields

View File

@ -879,6 +879,9 @@ export default {
this.$store.getters.customColumns[this.$store.getters.userInfo.id][this.$route.path] = this.selectedColumns
} else {
this.selectedColumns = this.$store.getters.customColumns[this.$store.getters.userInfo.id][this.$route.path] || this.selectedColumns
if (this.$store.getters.listAllProjects && !this.projectView) {
this.selectedColumns.push('project')
}
this.updateSelectedColumns()
}
}

View File

@ -1899,7 +1899,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
if (usageVpnUsers.size() > 0) {
s_logger.debug(String.format("We do not need to create the usage VPN user [%s] assigned to account [%s] because it already exists.", userId, accountId));
} else {
s_logger.debug(String.format("Creating VPN user user [%s] assigned to account [%s] domain [%s], zone [%s], and created at [%s]", userId, accountId, domainId, zoneId,
s_logger.debug(String.format("Creating VPN user [%s] assigned to account [%s] domain [%s], zone [%s], and created at [%s]", userId, accountId, domainId, zoneId,
event.getCreateDate()));
UsageVPNUserVO vpnUser = new UsageVPNUserVO(zoneId, accountId, domainId, userId, event.getResourceName(), event.getCreateDate(), null);
_usageVPNUserDao.persist(vpnUser);