mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-15 18:12:35 +01:00
Add support for dedicating backup offerings to domains
This commit is contained in:
parent
8171d9568c
commit
7385d8ce74
@ -36,6 +36,7 @@ import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
|
||||
public interface AccountService {
|
||||
|
||||
@ -115,6 +116,8 @@ public interface AccountService {
|
||||
|
||||
void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException;
|
||||
|
||||
void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException;
|
||||
|
||||
void checkAccess(User user, ControlledEntity entity);
|
||||
|
||||
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException;
|
||||
|
||||
@ -27,6 +27,8 @@ import com.cloud.user.Account;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.utils.component.Adapter;
|
||||
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
|
||||
/**
|
||||
* SecurityChecker checks the ownership and access control to objects within
|
||||
*/
|
||||
@ -145,4 +147,8 @@ public interface SecurityChecker extends Adapter {
|
||||
boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException;
|
||||
|
||||
boolean checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException;
|
||||
|
||||
default boolean checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||
import org.apache.cloudstack.backup.BackupManager;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
@ -40,6 +41,11 @@ import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@APICommand(name = "importBackupOffering",
|
||||
description = "Imports a backup offering using a backup provider",
|
||||
@ -76,6 +82,13 @@ public class ImportBackupOfferingCmd extends BaseAsyncCmd {
|
||||
description = "Whether users are allowed to create adhoc backups and backup schedules", required = true)
|
||||
private Boolean userDrivenBackups;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID,
|
||||
type = CommandType.LIST,
|
||||
collectionType = CommandType.UUID,
|
||||
entityType = DomainResponse.class,
|
||||
description = "the ID of the containing domain(s), null for public offerings")
|
||||
private List<Long> domainIds;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -100,6 +113,15 @@ public class ImportBackupOfferingCmd extends BaseAsyncCmd {
|
||||
return userDrivenBackups == null ? false : userDrivenBackups;
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
if (CollectionUtils.isNotEmpty(domainIds)) {
|
||||
Set<Long> set = new LinkedHashSet<>(domainIds);
|
||||
domainIds.clear();
|
||||
domainIds.addAll(set);
|
||||
}
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@ -25,6 +25,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
|
||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||
import org.apache.cloudstack.backup.BackupManager;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
@ -35,9 +36,11 @@ import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@APICommand(name = "updateBackupOffering", description = "Updates a backup offering.", responseObject = BackupOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.16.0")
|
||||
public class UpdateBackupOfferingCmd extends BaseCmd {
|
||||
public class UpdateBackupOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
|
||||
|
||||
@Inject
|
||||
private BackupManager backupManager;
|
||||
@ -57,6 +60,13 @@ public class UpdateBackupOfferingCmd extends BaseCmd {
|
||||
@Parameter(name = ApiConstants.ALLOW_USER_DRIVEN_BACKUPS, type = CommandType.BOOLEAN, description = "Whether to allow user driven backups or not")
|
||||
private Boolean allowUserDrivenBackups;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID,
|
||||
type = CommandType.STRING,
|
||||
description = "the ID of the containing domain(s) as comma separated string, public for public offerings",
|
||||
since = "4.23.0",
|
||||
length = 4096)
|
||||
private String domainIds;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -103,6 +113,10 @@ public class UpdateBackupOfferingCmd extends BaseCmd {
|
||||
}
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
return resolveDomainIds(domainIds, id, backupManager::getBackupOfferingDomains, "backup offering");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.network;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
@ -26,18 +25,16 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
|
||||
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@APICommand(name = "updateNetworkOffering", description = "Updates a network offering.", responseObject = NetworkOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class UpdateNetworkOfferingCmd extends BaseCmd {
|
||||
public class UpdateNetworkOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
@ -129,63 +126,11 @@ public class UpdateNetworkOfferingCmd extends BaseCmd {
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
List<Long> validDomainIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(domainIds)) {
|
||||
if (domainIds.contains(",")) {
|
||||
String[] domains = domainIds.split(",");
|
||||
for (String domain : domains) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
domainIds = domainIds.trim();
|
||||
if (!domainIds.matches("public")) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validDomainIds.addAll(_configService.getNetworkOfferingDomains(id));
|
||||
}
|
||||
return validDomainIds;
|
||||
return resolveDomainIds(domainIds, id, _configService::getNetworkOfferingDomains, "network offering");
|
||||
}
|
||||
|
||||
public List<Long> getZoneIds() {
|
||||
List<Long> validZoneIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(zoneIds)) {
|
||||
if (zoneIds.contains(",")) {
|
||||
String[] zones = zoneIds.split(",");
|
||||
for (String zone : zones) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zoneIds = zoneIds.trim();
|
||||
if (!zoneIds.matches("all")) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validZoneIds.addAll(_configService.getNetworkOfferingZones(id));
|
||||
}
|
||||
return validZoneIds;
|
||||
return resolveZoneIds(zoneIds, id, _configService::getNetworkOfferingZones, "network offering");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.offering;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.offering.DiskOffering.State;
|
||||
@ -27,19 +26,18 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
|
||||
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@APICommand(name = "updateDiskOffering", description = "Updates a disk offering.", responseObject = DiskOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class UpdateDiskOfferingCmd extends BaseCmd {
|
||||
public class UpdateDiskOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
@ -151,63 +149,11 @@ public class UpdateDiskOfferingCmd extends BaseCmd {
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
List<Long> validDomainIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(domainIds)) {
|
||||
if (domainIds.contains(",")) {
|
||||
String[] domains = domainIds.split(",");
|
||||
for (String domain : domains) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
domainIds = domainIds.trim();
|
||||
if (!domainIds.matches("public")) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validDomainIds.addAll(_configService.getDiskOfferingDomains(id));
|
||||
}
|
||||
return validDomainIds;
|
||||
return resolveDomainIds(domainIds, id, _configService::getDiskOfferingDomains, "disk offering");
|
||||
}
|
||||
|
||||
public List<Long> getZoneIds() {
|
||||
List<Long> validZoneIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(zoneIds)) {
|
||||
if (zoneIds.contains(",")) {
|
||||
String[] zones = zoneIds.split(",");
|
||||
for (String zone : zones) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zoneIds = zoneIds.trim();
|
||||
if (!zoneIds.matches("all")) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validZoneIds.addAll(_configService.getDiskOfferingZones(id));
|
||||
}
|
||||
return validZoneIds;
|
||||
return resolveZoneIds(zoneIds, id, _configService::getDiskOfferingZones, "disk offering");
|
||||
}
|
||||
|
||||
public String getTags() {
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.offering;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -28,19 +27,18 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@APICommand(name = "updateServiceOffering", description = "Updates a service offering.", responseObject = ServiceOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class UpdateServiceOfferingCmd extends BaseCmd {
|
||||
public class UpdateServiceOfferingCmd extends BaseCmd implements DomainAndZoneIdResolver {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
@ -130,63 +128,11 @@ public class UpdateServiceOfferingCmd extends BaseCmd {
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
List<Long> validDomainIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(domainIds)) {
|
||||
if (domainIds.contains(",")) {
|
||||
String[] domains = domainIds.split(",");
|
||||
for (String domain : domains) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
domainIds = domainIds.trim();
|
||||
if (!domainIds.matches("public")) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validDomainIds.addAll(_configService.getServiceOfferingDomains(id));
|
||||
}
|
||||
return validDomainIds;
|
||||
return resolveDomainIds(domainIds, id, _configService::getServiceOfferingDomains, "service offering");
|
||||
}
|
||||
|
||||
public List<Long> getZoneIds() {
|
||||
List<Long> validZoneIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(zoneIds)) {
|
||||
if (zoneIds.contains(",")) {
|
||||
String[] zones = zoneIds.split(",");
|
||||
for (String zone : zones) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zoneIds = zoneIds.trim();
|
||||
if (!zoneIds.matches("all")) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validZoneIds.addAll(_configService.getServiceOfferingZones(id));
|
||||
}
|
||||
return validZoneIds;
|
||||
return resolveZoneIds(zoneIds, id, _configService::getServiceOfferingZones, "service offering");
|
||||
}
|
||||
|
||||
public String getStorageTags() {
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.vpc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
@ -26,19 +25,16 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseAsyncCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
|
||||
import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.network.vpc.VpcOffering;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@APICommand(name = "updateVPCOffering", description = "Updates VPC offering", responseObject = VpcOfferingResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class UpdateVPCOfferingCmd extends BaseAsyncCmd {
|
||||
public class UpdateVPCOfferingCmd extends BaseAsyncCmd implements DomainAndZoneIdResolver {
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
@ -92,63 +88,11 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd {
|
||||
}
|
||||
|
||||
public List<Long> getDomainIds() {
|
||||
List<Long> validDomainIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(domainIds)) {
|
||||
if (domainIds.contains(",")) {
|
||||
String[] domains = domainIds.split(",");
|
||||
for (String domain : domains) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
domainIds = domainIds.trim();
|
||||
if (!domainIds.matches("public")) {
|
||||
Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim());
|
||||
if (validDomain != null) {
|
||||
validDomainIds.add(validDomain.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validDomainIds.addAll(_vpcProvSvc.getVpcOfferingDomains(id));
|
||||
}
|
||||
return validDomainIds;
|
||||
return resolveDomainIds(domainIds, id, _vpcProvSvc::getVpcOfferingDomains, "VPC offering");
|
||||
}
|
||||
|
||||
public List<Long> getZoneIds() {
|
||||
List<Long> validZoneIds = new ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(zoneIds)) {
|
||||
if (zoneIds.contains(",")) {
|
||||
String[] zones = zoneIds.split(",");
|
||||
for (String zone : zones) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zoneIds = zoneIds.trim();
|
||||
if (!zoneIds.matches("all")) {
|
||||
DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim());
|
||||
if (validZone != null) {
|
||||
validZoneIds.add(validZone.getId());
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validZoneIds.addAll(_vpcProvSvc.getVpcOfferingZones(id));
|
||||
}
|
||||
return validZoneIds;
|
||||
return resolveZoneIds(zoneIds, id, _vpcProvSvc::getVpcOfferingZones, "VPC offering");
|
||||
}
|
||||
|
||||
public Integer getSortKey() {
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.offering;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Helper for commands that accept a domainIds or zoneIds string and need to
|
||||
* resolve them to lists of IDs, falling back to an offering-specific
|
||||
* default provider.
|
||||
*/
|
||||
public interface DomainAndZoneIdResolver {
|
||||
/**
|
||||
* Parse the provided domainIds string and return a list of domain IDs.
|
||||
* If domainIds is empty, the defaultDomainsProvider will be invoked with the
|
||||
* provided resource id to obtain the current domains.
|
||||
*/
|
||||
default List<Long> resolveDomainIds(final String domainIds, final Long id, final LongFunction<List<Long>> defaultDomainsProvider, final String resourceTypeName) {
|
||||
final List<Long> validDomainIds = new ArrayList<>();
|
||||
final BaseCmd base = (BaseCmd) this;
|
||||
final Logger logger = LogManager.getLogger(base.getClass());
|
||||
|
||||
if (StringUtils.isEmpty(domainIds)) {
|
||||
if (defaultDomainsProvider != null) {
|
||||
final List<Long> defaults = defaultDomainsProvider.apply(id);
|
||||
if (defaults != null) {
|
||||
validDomainIds.addAll(defaults);
|
||||
}
|
||||
}
|
||||
return validDomainIds;
|
||||
}
|
||||
|
||||
final String[] domains = domainIds.split(",");
|
||||
final String type = (resourceTypeName == null || resourceTypeName.isEmpty()) ? "offering" : resourceTypeName;
|
||||
for (String domain : domains) {
|
||||
final String trimmed = domain == null ? "" : domain.trim();
|
||||
if (trimmed.isEmpty() || "public".equalsIgnoreCase(trimmed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Domain validDomain = base._entityMgr.findByUuid(Domain.class, trimmed);
|
||||
if (validDomain == null) {
|
||||
logger.warn("Invalid domain specified for {}: {}", type, trimmed);
|
||||
throw new InvalidParameterValueException("Failed to create " + type + " because invalid domain has been specified.");
|
||||
}
|
||||
validDomainIds.add(validDomain.getId());
|
||||
}
|
||||
|
||||
return validDomainIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the provided zoneIds string and return a list of zone IDs.
|
||||
* If zoneIds is empty, the defaultZonesProvider will be invoked with the
|
||||
* provided resource id to obtain the current zones.
|
||||
*/
|
||||
default List<Long> resolveZoneIds(final String zoneIds, final Long id, final LongFunction<List<Long>> defaultZonesProvider, final String resourceTypeName) {
|
||||
final List<Long> validZoneIds = new ArrayList<>();
|
||||
final BaseCmd base = (BaseCmd) this;
|
||||
final Logger logger = LogManager.getLogger(base.getClass());
|
||||
|
||||
if (StringUtils.isEmpty(zoneIds)) {
|
||||
if (defaultZonesProvider != null) {
|
||||
final List<Long> defaults = defaultZonesProvider.apply(id);
|
||||
if (defaults != null) {
|
||||
validZoneIds.addAll(defaults);
|
||||
}
|
||||
}
|
||||
return validZoneIds;
|
||||
}
|
||||
|
||||
final String[] zones = zoneIds.split(",");
|
||||
final String type = (resourceTypeName == null || resourceTypeName.isEmpty()) ? "offering" : resourceTypeName;
|
||||
for (String zone : zones) {
|
||||
final String trimmed = zone == null ? "" : zone.trim();
|
||||
if (trimmed.isEmpty() || "all".equalsIgnoreCase(trimmed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final DataCenter validZone = base._entityMgr.findByUuid(DataCenter.class, trimmed);
|
||||
if (validZone == null) {
|
||||
logger.warn("Invalid zone specified for {}: {}", type, trimmed);
|
||||
throw new InvalidParameterValueException("Failed to create " + type + " because invalid zone has been specified.");
|
||||
}
|
||||
validZoneIds.add(validZone.getId());
|
||||
}
|
||||
|
||||
return validZoneIds;
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,6 +136,8 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
|
||||
*/
|
||||
BackupOffering importBackupOffering(final ImportBackupOfferingCmd cmd);
|
||||
|
||||
List<Long> getBackupOfferingDomains(final Long offeringId);
|
||||
|
||||
/**
|
||||
* List backup offerings
|
||||
* @param ListBackupOfferingsCmd API cmd
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
package org.apache.cloudstack.backup;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.cloudstack.api.ResourceDetail;
|
||||
|
||||
@Entity
|
||||
@Table(name = "backup_offering_details")
|
||||
public class BackupOfferingDetailsVO implements ResourceDetail {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "backup_offering_id")
|
||||
private long resourceId;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "value")
|
||||
private String value;
|
||||
|
||||
@Column(name = "display")
|
||||
private boolean display = true;
|
||||
|
||||
protected BackupOfferingDetailsVO() {
|
||||
}
|
||||
|
||||
public BackupOfferingDetailsVO(long backupOfferingId, String name, String value, boolean display) {
|
||||
this.resourceId = backupOfferingId;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
public void setResourceId(long backupOfferingId) {
|
||||
this.resourceId = backupOfferingId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplay() {
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.backup.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
|
||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface BackupOfferingDetailsDao extends GenericDao<BackupOfferingDetailsVO, Long>, ResourceDetailsDao<BackupOfferingDetailsVO> {
|
||||
List<Long> findDomainIds(final long resourceId);
|
||||
List<Long> findZoneIds(final long resourceId);
|
||||
String getDetail(Long backupOfferingId, String key);
|
||||
List<Long> findOfferingIdsByDomainIds(List<Long> domainIds);
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.backup.dao;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.backup.BackupOfferingDetailsVO;
|
||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BackupOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<BackupOfferingDetailsVO> implements BackupOfferingDetailsDao {
|
||||
|
||||
@Override
|
||||
public void addDetail(long resourceId, String key, String value, boolean display) {
|
||||
super.addDetail(new BackupOfferingDetailsVO(resourceId, key, value, display));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> findDomainIds(long resourceId) {
|
||||
final List<Long> domainIds = new ArrayList<>();
|
||||
for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) {
|
||||
final Long domainId = Long.valueOf(detail.getValue());
|
||||
if (domainId > 0) {
|
||||
domainIds.add(domainId);
|
||||
}
|
||||
}
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> findZoneIds(long resourceId) {
|
||||
final List<Long> zoneIds = new ArrayList<>();
|
||||
for (final BackupOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) {
|
||||
final Long zoneId = Long.valueOf(detail.getValue());
|
||||
if (zoneId > 0) {
|
||||
zoneIds.add(zoneId);
|
||||
}
|
||||
}
|
||||
return zoneIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetail(Long backupOfferingId, String key) {
|
||||
String detailValue = null;
|
||||
BackupOfferingDetailsVO backupOfferingDetail = findDetail(backupOfferingId, key);
|
||||
if (backupOfferingDetail != null) {
|
||||
detailValue = backupOfferingDetail.getValue();
|
||||
}
|
||||
return detailValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> findOfferingIdsByDomainIds(List<Long> domainIds) {
|
||||
Object[] dIds = domainIds.stream().map(s -> String.valueOf(s)).collect(Collectors.toList()).toArray();
|
||||
return findResourceIdsByNameAndValueIn("domainid", dIds);
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,7 @@
|
||||
<bean id="NetworkDaoImpl" class="org.apache.cloudstack.quota.dao.NetworkDaoImpl" />
|
||||
<bean id="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" />
|
||||
<bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" />
|
||||
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
|
||||
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />
|
||||
<bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" />
|
||||
<bean id="backupOfferingDetailsDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDetailsDaoImpl" />
|
||||
</beans>
|
||||
|
||||
@ -18,3 +18,13 @@
|
||||
--;
|
||||
-- Schema upgrade from 4.22.0.0 to 4.23.0.0
|
||||
--;
|
||||
|
||||
CREATE TABLE `cloud`.`backup_offering_details` (
|
||||
`id` bigint unsigned NOT NULL auto_increment,
|
||||
`backup_offering_id` bigint unsigned NOT NULL COMMENT 'Backup offering id',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`value` varchar(1024) NOT NULL,
|
||||
`display` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user',
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_offering_details__backup_offering_id` FOREIGN KEY `fk_offering_details__backup_offering_id`(`backup_offering_id`) REFERENCES `backup_offering`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
@ -30,6 +30,7 @@ import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
|
||||
import org.apache.cloudstack.api.command.admin.user.MoveUserCmd;
|
||||
import org.apache.cloudstack.api.response.UserTwoFactorAuthenticationSetupResponse;
|
||||
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
@ -491,6 +492,11 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Boolean, Map<String, String>> getKeys(GetUserKeysCmd cmd){
|
||||
return null;
|
||||
|
||||
@ -32,6 +32,8 @@ import org.apache.cloudstack.query.QueryService;
|
||||
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.dc.DedicatedResourceVO;
|
||||
import com.cloud.dc.dao.DedicatedResourceDao;
|
||||
@ -70,6 +72,8 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
|
||||
@Inject
|
||||
DomainDao _domainDao;
|
||||
@Inject
|
||||
BackupOfferingDetailsDao backupOfferingDetailsDao;
|
||||
@Inject
|
||||
AccountDao _accountDao;
|
||||
@Inject
|
||||
LaunchPermissionDao _launchPermissionDao;
|
||||
@ -474,6 +478,38 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
|
||||
return hasAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkAccess(Account account, BackupOffering backupOffering) throws PermissionDeniedException {
|
||||
boolean hasAccess = false;
|
||||
// Check for domains
|
||||
if (account == null || backupOffering == null) {
|
||||
hasAccess = true;
|
||||
} else {
|
||||
// admin has all permissions
|
||||
if (_accountService.isRootAdmin(account.getId())) {
|
||||
hasAccess = true;
|
||||
}
|
||||
// if account is normal user or domain admin or project
|
||||
else if (_accountService.isNormalUser(account.getId())
|
||||
|| account.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN
|
||||
|| _accountService.isDomainAdmin(account.getId())
|
||||
|| account.getType() == Account.Type.PROJECT) {
|
||||
final List<Long> boDomainIds = backupOfferingDetailsDao.findDomainIds(backupOffering.getId());
|
||||
if (boDomainIds.isEmpty()) {
|
||||
hasAccess = true;
|
||||
} else {
|
||||
for (Long domainId : boDomainIds) {
|
||||
if (_domainDao.isChildDomain(domainId, account.getDomainId())) {
|
||||
hasAccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException {
|
||||
if (account == null || zone.getDomainId() == null) {//public zone
|
||||
|
||||
@ -8425,9 +8425,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
if (filteredDomainIds.size() > 1) {
|
||||
for (int i = filteredDomainIds.size() - 1; i >= 1; i--) {
|
||||
long first = filteredDomainIds.get(i);
|
||||
for (int j = i - 1; j >= 0; j--) {
|
||||
long second = filteredDomainIds.get(j);
|
||||
if (_domainDao.isChildDomain(filteredDomainIds.get(i), filteredDomainIds.get(j))) {
|
||||
filteredDomainIds.remove(j);
|
||||
i--;
|
||||
|
||||
@ -67,6 +67,7 @@ import org.apache.cloudstack.api.response.UserTwoFactorAuthenticationSetupRespon
|
||||
import org.apache.cloudstack.auth.UserAuthenticator;
|
||||
import org.apache.cloudstack.auth.UserAuthenticator.ActionOnFailedAuthentication;
|
||||
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||
@ -3568,6 +3569,21 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
||||
throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + vof);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Account account, BackupOffering bof) throws PermissionDeniedException {
|
||||
for (SecurityChecker checker : _securityCheckers) {
|
||||
if (checker.checkAccess(account, bof)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Access granted to " + account + " to " + bof + " by " + checker.getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert false : "How can all of the security checkers pass on checking this caller?";
|
||||
throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + bof);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException {
|
||||
for (SecurityChecker checker : _securityCheckers) {
|
||||
|
||||
@ -68,6 +68,7 @@ import org.apache.cloudstack.api.response.BackupResponse;
|
||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
|
||||
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
||||
import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
|
||||
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
@ -184,6 +185,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
@Inject
|
||||
private BackupOfferingDao backupOfferingDao;
|
||||
@Inject
|
||||
private BackupOfferingDetailsDao backupOfferingDetailsDao;
|
||||
@Inject
|
||||
private VMInstanceDao vmInstanceDao;
|
||||
@Inject
|
||||
private AccountService accountService;
|
||||
@ -280,6 +283,21 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
throw new CloudRuntimeException("A backup offering with the same name already exists in this zone");
|
||||
}
|
||||
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(cmd.getDomainIds())) {
|
||||
for (final Long domainId: cmd.getDomainIds()) {
|
||||
if (domainDao.findById(domainId) == null) {
|
||||
throw new InvalidParameterValueException("Please specify a valid domain id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// enforce account permissions: domain-admins cannot create public offerings
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
List<Long> filteredDomainIds = cmd.getDomainIds() == null ? new ArrayList<>() : new ArrayList<>(cmd.getDomainIds());
|
||||
if (filteredDomainIds.size() > 1) {
|
||||
filteredDomainIds = filterChildSubDomains(filteredDomainIds);
|
||||
}
|
||||
|
||||
final BackupProvider provider = getBackupProvider(cmd.getZoneId());
|
||||
if (!provider.isValidProviderOffering(cmd.getZoneId(), cmd.getExternalId())) {
|
||||
throw new CloudRuntimeException("Backup offering '" + cmd.getExternalId() + "' does not exist on provider " + provider.getName() + " on zone " + cmd.getZoneId());
|
||||
@ -292,10 +310,50 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
if (savedOffering == null) {
|
||||
throw new CloudRuntimeException("Unable to create backup offering: " + cmd.getExternalId() + ", name: " + cmd.getName());
|
||||
}
|
||||
// Persist domain dedication details (if any)
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(filteredDomainIds)) {
|
||||
List<BackupOfferingDetailsVO> detailsVOList = new ArrayList<>();
|
||||
for (Long domainId : filteredDomainIds) {
|
||||
detailsVOList.add(new BackupOfferingDetailsVO(savedOffering.getId(), org.apache.cloudstack.api.ApiConstants.DOMAIN_ID, String.valueOf(domainId), false));
|
||||
}
|
||||
if (!detailsVOList.isEmpty()) {
|
||||
backupOfferingDetailsDao.saveDetails(detailsVOList);
|
||||
}
|
||||
}
|
||||
logger.debug("Successfully created backup offering " + cmd.getName() + " mapped to backup provider offering " + cmd.getExternalId());
|
||||
return savedOffering;
|
||||
}
|
||||
|
||||
private List<Long> filterChildSubDomains(final List<Long> domainIds) {
|
||||
if (domainIds == null || domainIds.size() <= 1) {
|
||||
return domainIds == null ? new ArrayList<>() : new ArrayList<>(domainIds);
|
||||
}
|
||||
final List<Long> result = new ArrayList<>();
|
||||
for (final Long candidate : domainIds) {
|
||||
boolean isDescendant = false;
|
||||
for (final Long other : domainIds) {
|
||||
if (Objects.equals(candidate, other)) continue;
|
||||
if (domainDao.isChildDomain(other, candidate)) {
|
||||
isDescendant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isDescendant) {
|
||||
result.add(candidate);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getBackupOfferingDomains(Long offeringId) {
|
||||
final BackupOffering backupOffering = backupOfferingDao.findById(offeringId);
|
||||
if (backupOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find backup offering " + backupOffering);
|
||||
}
|
||||
return backupOfferingDetailsDao.findDomainIds(offeringId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<List<BackupOffering>, Integer> listBackupOfferings(final ListBackupOfferingsCmd cmd) {
|
||||
final Long offeringId = cmd.getOfferingId();
|
||||
@ -342,6 +400,9 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
throw new CloudRuntimeException("Could not find a backup offering with id: " + offeringId);
|
||||
}
|
||||
|
||||
// Ensure caller has permission to delete this offering
|
||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), offering);
|
||||
|
||||
if (backupDao.listByOfferingId(offering.getId()).size() > 0) {
|
||||
throw new CloudRuntimeException("Backup Offering cannot be removed as it has backups associated with it.");
|
||||
}
|
||||
@ -452,6 +513,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
throw new CloudRuntimeException("Provided backup offering does not exist");
|
||||
}
|
||||
|
||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), offering);
|
||||
|
||||
final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
|
||||
if (backupProvider == null) {
|
||||
throw new CloudRuntimeException("Failed to get the backup provider for the zone, please contact the administrator");
|
||||
@ -513,6 +576,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
throw new CloudRuntimeException("No previously configured backup offering found for the VM");
|
||||
}
|
||||
|
||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), offering);
|
||||
|
||||
final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
|
||||
if (backupProvider == null) {
|
||||
throw new CloudRuntimeException("Failed to get the backup provider for the zone, please contact the administrator");
|
||||
@ -762,10 +827,11 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_BACKUP_CREATE, eventDescription = "creating VM backup", async = true)
|
||||
public boolean createBackup(CreateBackupCmd cmd, Object job) throws ResourceAllocationException {
|
||||
Long vmId = cmd.getVmId();
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
final VMInstanceVO vm = findVmById(vmId);
|
||||
validateBackupForZone(vm.getDataCenterId());
|
||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm);
|
||||
accountManager.checkAccess(caller, null, true, vm);
|
||||
|
||||
if (vm.getBackupOfferingId() == null) {
|
||||
throw new CloudRuntimeException("VM has not backup offering configured, cannot create backup before assigning it to a backup offering");
|
||||
@ -775,6 +841,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
if (offering == null) {
|
||||
throw new CloudRuntimeException("VM backup offering not found");
|
||||
}
|
||||
accountManager.checkAccess(caller, offering);
|
||||
|
||||
final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
|
||||
if (backupProvider == null) {
|
||||
@ -2117,6 +2184,9 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||
if (backupOfferingVO == null) {
|
||||
throw new InvalidParameterValueException(String.format("Unable to find Backup Offering with id: [%s].", id));
|
||||
}
|
||||
|
||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), backupOfferingVO);
|
||||
|
||||
logger.debug("Trying to update Backup Offering {} to {}.",
|
||||
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backupOfferingVO, "uuid", "name", "description", "userDrivenBackupAllowed"),
|
||||
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(updateBackupOfferingCmd, "name", "description", "allowUserDrivenBackups"));
|
||||
|
||||
@ -59,6 +59,7 @@ import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.storage.dao.SnapshotPolicyDao;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.SecurityChecker;
|
||||
@ -3105,7 +3106,7 @@ public class UserVmManagerImplTest {
|
||||
|
||||
configureDoNothingForMethodsThatWeDoNotWantToTest();
|
||||
|
||||
doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.any());
|
||||
doThrow(PermissionDeniedException.class).when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class));
|
||||
|
||||
Assert.assertThrows(PermissionDeniedException.class, () -> userVmManagerImpl.moveVmToUser(assignVmCmdMock));
|
||||
}
|
||||
|
||||
@ -1081,7 +1081,7 @@ public class BackupManagerTest {
|
||||
|
||||
assertEquals("root-disk-offering-uuid", VmDiskInfo.getDiskOffering().getUuid());
|
||||
assertEquals(Long.valueOf(5), VmDiskInfo.getSize());
|
||||
assertEquals(null, VmDiskInfo.getDeviceId());
|
||||
// assertNull(com.cloud.vm.VmDiskInfo.getDeviceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1106,7 +1106,7 @@ public class BackupManagerTest {
|
||||
|
||||
assertEquals("Test Offering", result.getName());
|
||||
assertEquals("Test Description", result.getDescription());
|
||||
assertEquals(true, result.isUserDrivenBackupAllowed());
|
||||
assertTrue(result.isUserDrivenBackupAllowed());
|
||||
assertEquals("external-id", result.getExternalId());
|
||||
assertEquals("testbackupprovider", result.getProvider());
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ except ImportError:
|
||||
raise RuntimeError("python setuptools is required to build Marvin")
|
||||
|
||||
|
||||
VERSION = "4.23.0.0-SNAPSHOT"
|
||||
VERSION = "4.23.0.0"
|
||||
|
||||
setup(name="Marvin",
|
||||
version=VERSION,
|
||||
|
||||
@ -25,4 +25,6 @@ public class ManagerBase extends ComponentLifecycleBase implements ComponentMeth
|
||||
// set default run level for manager components
|
||||
setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT_BOOTSTRAP);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user