Merge branch '4.19'

This commit is contained in:
Vishesh 2024-07-17 17:43:40 +05:30
commit 35fd17c62e
No known key found for this signature in database
GPG Key ID: 4E395186CBFA790B
23 changed files with 126 additions and 80 deletions

View File

@ -116,6 +116,7 @@ public class ListBackupsCmd extends BaseListProjectAndAccountResourcesCmd {
Pair<List<Backup>, Integer> result = backupManager.listBackups(this);
setupResponseBackupList(result.first(), result.second());
} catch (Exception e) {
logger.debug("Exception while listing backups", e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}

View File

@ -134,6 +134,7 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
}
long getVmId();
long getBackupOfferingId();
String getExternalId();
String getType();
Date getDate();

View File

@ -29,6 +29,7 @@ import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
@ -538,21 +539,25 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
@Override
public void removeOldUsageRecords(int days) {
String sql = DELETE_ALL_BY_INTERVAL;
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
PreparedStatement pstmt = null;
try {
txn.start();
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setLong(1, days);
pstmt.executeUpdate();
txn.commit();
} catch (Exception ex) {
txn.rollback();
logger.error("error removing old cloud_usage records for interval: " + days);
} finally {
txn.close();
}
Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmt = null;
try {
txn.start();
pstmt = txn.prepareAutoCloseStatement(DELETE_ALL_BY_INTERVAL);
pstmt.setLong(1, days);
pstmt.executeUpdate();
txn.commit();
} catch (Exception ex) {
txn.rollback();
logger.error("error removing old cloud_usage records for interval: " + days);
} finally {
txn.close();
}
}
});
}
public UsageVO persistUsage(final UsageVO usage) {

View File

@ -856,6 +856,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
SearchBuilder<NicVO> nicSearch = nicDao.createSearchBuilder();
nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
nicSearch.and("removed", nicSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
NetworkTypeSearch = createSearchBuilder();
NetworkTypeSearch.and("types", NetworkTypeSearch.entity().getType(), SearchCriteria.Op.IN);

View File

@ -158,6 +158,7 @@ public class BackupVO implements Backup {
this.status = status;
}
@Override
public long getBackupOfferingId() {
return backupOfferingId;
}

View File

@ -145,7 +145,11 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
AccountVO account = accountDao.findByIdIncludingRemoved(vm.getAccountId());
DomainVO domain = domainDao.findByIdIncludingRemoved(vm.getDomainId());
DataCenterVO zone = dataCenterDao.findByIdIncludingRemoved(vm.getDataCenterId());
BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(vm.getBackupOfferingId());
Long offeringId = vm.getBackupOfferingId();
if (offeringId == null) {
offeringId = backup.getBackupOfferingId();
}
BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(offeringId);
BackupResponse response = new BackupResponse();
response.setId(backup.getUuid());

View File

@ -26,6 +26,7 @@ import java.util.List;
import java.util.UUID;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
@ -49,8 +50,7 @@ public class LibvirtOvsFetchInterfaceCommandWrapperTest {
while(interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.getInetAddresses().hasMoreElements() &&
(networkInterface.getName().startsWith("eth") ||
networkInterface.getName().startsWith("wl"))) {
networkInterface.getName().matches("^(eth|wl|en).*")) {
interfaceName = networkInterface.getName();
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while(addresses.hasMoreElements()) {
@ -60,9 +60,13 @@ public class LibvirtOvsFetchInterfaceCommandWrapperTest {
break;
};
}
if (StringUtils.isNotBlank(interfaceName) && StringUtils.isNotBlank(ipAddress)) {
break;
}
}
}
} catch (SocketException ignored) {}
Assume.assumeTrue(StringUtils.isNotBlank(interfaceName));
Ternary<String, String, String> result = null;
try {
result = wrapper.getInterfaceDetails(interfaceName);

View File

@ -226,6 +226,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
"Received SAML response for a SSO request that we may not have made or has expired, please try logging in again",
params, responseType));
}
samlAuthManager.purgeToken(token);
// Set IdpId for this session
session.setAttribute(SAMLPluginConstants.SAML_IDPID, issuer.getValue());

View File

@ -71,16 +71,17 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
"SAML2 IDP Metadata refresh interval in seconds, minimum value is set to 300", true);
ConfigKey<Boolean> SAMLCheckSignature = new ConfigKey<Boolean>("Advanced", Boolean.class, "saml2.check.signature", "true",
"Whether SAML2 signature must be checked, when enforced and when the SAML response does not have a signature would lead to login exception", true);
"When enabled (default and recommended), SAML2 signature checks are enforced and lack of signature in the SAML SSO response will cause login exception. Disabling this is not advisable but provided for backward compatibility for users who are able to accept the risks.", false);
public SAMLProviderMetadata getSPMetadata();
public SAMLProviderMetadata getIdPMetadata(String entityId);
public Collection<SAMLProviderMetadata> getAllIdPMetadata();
SAMLProviderMetadata getSPMetadata();
SAMLProviderMetadata getIdPMetadata(String entityId);
Collection<SAMLProviderMetadata> getAllIdPMetadata();
public boolean isUserAuthorized(Long userId, String entityId);
public boolean authorizeUser(Long userId, String entityId, boolean enable);
boolean isUserAuthorized(Long userId, String entityId);
boolean authorizeUser(Long userId, String entityId, boolean enable);
public void saveToken(String authnId, String domain, String entity);
public SAMLTokenVO getToken(String authnId);
public void expireTokens();
void saveToken(String authnId, String domain, String entity);
SAMLTokenVO getToken(String authnId);
void purgeToken(SAMLTokenVO token);
void expireTokens();
}

View File

@ -485,6 +485,13 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
return _samlTokenDao.findByUuid(authnId);
}
@Override
public void purgeToken(SAMLTokenVO token) {
if (token != null) {
_samlTokenDao.remove(token.getId());
}
}
@Override
public void expireTokens() {
_samlTokenDao.expireTokens();

View File

@ -279,7 +279,7 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
@Test
public void testFailOnSAMLSignatureCheckWhenFalse() throws NoSuchFieldException, IllegalAccessException {
overrideDefaultConfigValue(SAML2AuthManager.SAMLCheckSignature, "_defaultValue", "false");
overrideDefaultConfigValue(SAML2AuthManager.SAMLCheckSignature, "_value", false);
SAML2LoginAPIAuthenticatorCmd cmd = new SAML2LoginAPIAuthenticatorCmd();
try {
cmd.checkAndFailOnMissingSAMLSignature(null);
@ -290,7 +290,7 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
@Test(expected = ServerApiException.class)
public void testFailOnSAMLSignatureCheckWhenTrue() throws NoSuchFieldException, IllegalAccessException {
overrideDefaultConfigValue(SAML2AuthManager.SAMLCheckSignature, "_defaultValue", "true");
overrideDefaultConfigValue(SAML2AuthManager.SAMLCheckSignature, "_value", true);
SAML2LoginAPIAuthenticatorCmd cmd = new SAML2LoginAPIAuthenticatorCmd();
cmd.checkAndFailOnMissingSAMLSignature(null);
}

View File

@ -2791,14 +2791,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Override
public boolean canHostPrepareStoragePoolAccess(Host host, StoragePool pool) {
if (host == null || pool == null) {
if (host == null || pool == null || !pool.isManaged()) {
return false;
}
if (!pool.isManaged()) {
return true;
}
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
return storeDriver instanceof PrimaryDataStoreDriver && ((PrimaryDataStoreDriver)storeDriver).canHostPrepareStoragePoolAccess(host, pool);

View File

@ -140,6 +140,7 @@ public class ActionEventInterceptorTest {
}
utils.init();
CallContext.register(user, account);
}
/**
@ -152,6 +153,7 @@ public class ActionEventInterceptorTest {
Mockito.when(configDao.getValue(Config.PublishActionEvent.key())).thenReturn("true");
componentContextMocked = Mockito.mockStatic(ComponentContext.class);
Mockito.when(ComponentContext.getComponent(EventBus.class)).thenReturn(eventBus);
persistedEvents = new ArrayList<>();
//Needed for persist to actually set an ID that can be returned from the ActionEventUtils
//methods.
@ -231,11 +233,11 @@ public class ActionEventInterceptorTest {
Object event = actionEventInterceptor.interceptStart(m, tester);
Assert.assertNull(event);
Assert.assertEquals(persistedEvents.size(), 1);
Assert.assertEquals(1, persistedEvents.size());
EventVO eventVO = persistedEvents.get(0);
Assert.assertEquals(eventVO.getType(), EventTypes.EVENT_VM_START);
Assert.assertEquals(eventVO.getDescription(), "Starting VM");
Assert.assertEquals(eventVO.getState(), com.cloud.event.Event.State.Started);
Assert.assertEquals(EventTypes.EVENT_VM_START, eventVO.getType());
Assert.assertEquals(eventDescription, eventVO.getDescription());
Assert.assertEquals(com.cloud.event.Event.State.Started, eventVO.getState());
}
@Test
@ -244,12 +246,12 @@ public class ActionEventInterceptorTest {
Method m = tester.getClass().getMethod("testMethod");
actionEventInterceptor.interceptComplete(m, tester, null);
Assert.assertEquals(persistedEvents.size(), 1);
Assert.assertEquals(1, persistedEvents.size());
EventVO eventVO = persistedEvents.get(0);
Assert.assertEquals(eventVO.getType(), eventType);
Assert.assertEquals(eventType, eventVO.getType());
Assert.assertTrue(eventVO.getDescription().endsWith(eventDescription));
Assert.assertEquals(eventVO.getLevel(), EventVO.LEVEL_INFO);
Assert.assertEquals(eventVO.getState(), com.cloud.event.Event.State.Completed);
Assert.assertEquals(EventVO.LEVEL_INFO, eventVO.getLevel());
Assert.assertEquals(com.cloud.event.Event.State.Completed, eventVO.getState());
}
@Test
@ -258,12 +260,12 @@ public class ActionEventInterceptorTest {
Method m = tester.getClass().getMethod("testMethod");
actionEventInterceptor.interceptException(m, tester, null);
Assert.assertEquals(persistedEvents.size(), 1);
Assert.assertEquals(1, persistedEvents.size());
EventVO eventVO = persistedEvents.get(0);
Assert.assertEquals(eventVO.getType(), eventType);
Assert.assertEquals(eventType, eventVO.getType());
Assert.assertTrue(eventVO.getDescription().endsWith(eventDescription));
Assert.assertEquals(eventVO.getLevel(), EventVO.LEVEL_ERROR);
Assert.assertEquals(eventVO.getState(), com.cloud.event.Event.State.Completed);
Assert.assertEquals(EventVO.LEVEL_ERROR, eventVO.getLevel());
Assert.assertEquals(com.cloud.event.Event.State.Completed, eventVO.getState());
}
@Test
@ -276,14 +278,14 @@ public class ActionEventInterceptorTest {
Method m = tester.getClass().getMethod("testMethod");
actionEventInterceptor.interceptException(m, tester, null);
Assert.assertEquals(persistedEvents.size(), 1);
Assert.assertEquals(1, persistedEvents.size());
EventVO eventVO = persistedEvents.get(0);
Assert.assertEquals(eventVO.getType(), eventType);
Assert.assertEquals(eventType, eventVO.getType());
Assert.assertTrue(eventVO.getDescription().endsWith(eventDescription));
Assert.assertEquals(eventVO.getLevel(), EventVO.LEVEL_ERROR);
Assert.assertEquals(eventVO.getState(), com.cloud.event.Event.State.Completed);
Assert.assertEquals(eventVO.getResourceId(), resourceId);
Assert.assertEquals(eventVO.getResourceType(), resourceType.toString());
Assert.assertEquals(EventVO.LEVEL_ERROR, eventVO.getLevel());
Assert.assertEquals(com.cloud.event.Event.State.Completed, eventVO.getState());
Assert.assertEquals(resourceId, eventVO.getResourceId());
Assert.assertEquals(resourceType.toString(), eventVO.getResourceType());
}
@Test

View File

@ -10,12 +10,12 @@
"docBase": "http://docs.cloudstack.apache.org/en/latest",
"appTitle": "CloudStack",
"footer": "Licensed under the <a href='http://www.apache.org/licenses/' target='_blank'>Apache License</a>, Version 2.0.",
"loginTitle": "CloudStack",
"loginFavicon": "assets/logo.svg",
"loginFooter": "",
"logo": "assets/logo.svg",
"minilogo": "assets/mini-logo.svg",
"banner": "assets/banner.svg",
"loginPageTitle": "CloudStack",
"loginPageFavicon": "assets/logo.svg",
"error": {
"403": "assets/403.png",
"404": "assets/404.png",

View File

@ -58,8 +58,8 @@
fetch('./config.json')
.then(response => response.json())
.then(data => {
document.getElementById("favicon").setAttribute("href", data.loginPageFavicon);
document.getElementById("title").innerHTML = data.loginPageTitle;
document.getElementById("favicon").setAttribute("href", data.loginFavicon);
document.getElementById("title").innerHTML = data.loginTitle;
}).catch((err) => {});
</script>
</html>

View File

@ -1942,6 +1942,7 @@
"label.service.connectivity.distributedroutercapabilitycheckbox": "Distributed router",
"label.service.connectivity.regionlevelvpccapabilitycheckbox": "Region level VPC",
"label.service.group": "Service group",
"label.serviceip": "Service IP",
"label.service.lb.elasticlbcheckbox": "Elastic LB",
"label.service.lb.inlinemodedropdown": "Mode",
"label.service.lb.lbisolationdropdown": "LB isolation",

View File

@ -104,18 +104,6 @@
v-if="resource.id"
/>
</a-tooltip>
<a-tooltip placement="right" >
<template #title>
<span>{{ $t('label.copy.consoleurl') }}</span>
</template>
<console
copyUrlToClipboard
style="margin-top: -5px;"
:resource="resource"
size="default"
v-if="resource.id"
/>
</a-tooltip>
</div>
</slot>
</div>

View File

@ -56,17 +56,10 @@ export default {
this.url = (json && json.createconsoleendpointresponse) ? json.createconsoleendpointresponse.consoleendpoint.url : '#/exception/404'
if (json.createconsoleendpointresponse.consoleendpoint.success) {
if (this.copyUrlToClipboard) {
this.$copyText(this.url)
this.$message.success({
content: this.$t('label.copied.clipboard')
})
const hiddenElement = document.createElement('textarea')
hiddenElement.value = this.url
document.body.appendChild(hiddenElement)
hiddenElement.focus()
hiddenElement.select()
document.execCommand('copy')
document.body.removeChild(hiddenElement)
} else {
window.open(this.url, '_blank')
}

View File

@ -31,6 +31,30 @@ export default {
name: 'accountuser',
title: 'label.users',
param: 'account'
}, {
name: 'vm',
title: 'label.vms',
param: 'account'
}, {
name: 'volume',
title: 'label.volumes',
param: 'account'
}, {
name: 'guestnetwork',
title: 'label.networks',
param: 'account'
}, {
name: 'ssh',
title: 'label.sshkeypairs',
param: 'account'
}, {
name: 'userdata',
title: 'label.userdata',
param: 'account'
}, {
name: 'template',
title: 'label.templates',
param: 'account'
}],
filters: () => {
const filters = ['enabled', 'disabled', 'locked']

View File

@ -32,7 +32,7 @@ export default {
getApiToCall: () => store.getters.metrics ? 'listVirtualMachinesMetrics' : 'listVirtualMachines',
resourceType: 'UserVm',
params: () => {
var params = { details: 'group,nics,secgrp,tmpl,servoff,diskoff,iso,volume,affgrp' }
var params = { details: 'group,nics,secgrp,tmpl,servoff,diskoff,iso,volume,affgrp,backoff' }
if (store.getters.metrics) {
params = { details: 'all,stats' }
}

View File

@ -32,6 +32,22 @@ export default {
name: 'account',
title: 'label.accounts',
param: 'domainid'
}, {
name: 'vm',
title: 'label.vms',
param: 'domainid'
}, {
name: 'volume',
title: 'label.volumes',
param: 'domainid'
}, {
name: 'guestnetwork',
title: 'label.networks',
param: 'domainid'
}, {
name: 'template',
title: 'label.templates',
param: 'domainid'
}],
tabs: [
{

View File

@ -32,7 +32,7 @@ export default {
},
params: { type: 'routing' },
columns: () => {
const fields = ['name', 'state', 'resourcestate', 'ipaddress', 'hypervisor', 'instances', 'powerstate']
const fields = ['name', 'state', 'resourcestate', 'ipaddress', 'hypervisor', 'instances', 'powerstate', 'version']
const metricsFields = ['cpunumber', 'cputotalghz', 'cpuusedghz', 'cpuallocatedghz', 'memorytotalgb', 'memoryusedgb', 'memoryallocatedgb', 'networkread', 'networkwrite']
if (store.getters.metrics) {
fields.push(...metricsFields)

View File

@ -26,8 +26,8 @@ export default {
permission: ['listManagementServersMetrics'],
resourceType: 'ManagementServer',
columns: () => {
const fields = ['name', 'state', 'version']
const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload', 'heapmemoryused', 'agentcount']
const fields = ['name', 'state', 'serviceip', 'version', 'osdistribution', 'agentcount']
const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload', 'heapmemoryused']
if (store.getters.metrics) {
fields.push(...metricsFields)
}