mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Compare commits
1 Commits
24d3b3ccdd
...
44bd146ca5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bd146ca5 |
@ -93,6 +93,7 @@ import com.cloud.utils.nio.Link;
|
|||||||
import com.cloud.utils.nio.NioClient;
|
import com.cloud.utils.nio.NioClient;
|
||||||
import com.cloud.utils.nio.NioConnection;
|
import com.cloud.utils.nio.NioConnection;
|
||||||
import com.cloud.utils.nio.Task;
|
import com.cloud.utils.nio.Task;
|
||||||
|
import com.cloud.utils.script.OutputInterpreter;
|
||||||
import com.cloud.utils.script.Script;
|
import com.cloud.utils.script.Script;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -597,9 +598,9 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getAgentArch() {
|
protected String getAgentArch() {
|
||||||
String arch = Script.runSimpleBashScript(Script.getExecutableAbsolutePath("arch"), 2000);
|
final Script command = new Script("/usr/bin/arch", 500, logger);
|
||||||
logger.debug("Arch for agent: {} found: {}", _name, arch);
|
final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
|
||||||
return arch;
|
return command.execute(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.cloud.user.UserData;
|
||||||
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
|
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.config.ListCfgGroupsByCmd;
|
import org.apache.cloudstack.api.command.admin.config.ListCfgGroupsByCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||||
@ -65,7 +66,6 @@ import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
|
||||||
import org.apache.cloudstack.config.Configuration;
|
import org.apache.cloudstack.config.Configuration;
|
||||||
import org.apache.cloudstack.config.ConfigurationGroup;
|
import org.apache.cloudstack.config.ConfigurationGroup;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
|
||||||
|
|
||||||
import com.cloud.alert.Alert;
|
import com.cloud.alert.Alert;
|
||||||
import com.cloud.capacity.Capacity;
|
import com.cloud.capacity.Capacity;
|
||||||
@ -85,7 +85,6 @@ import com.cloud.storage.GuestOSHypervisor;
|
|||||||
import com.cloud.storage.GuestOsCategory;
|
import com.cloud.storage.GuestOsCategory;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.user.SSHKeyPair;
|
import com.cloud.user.SSHKeyPair;
|
||||||
import com.cloud.user.UserData;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.Ternary;
|
import com.cloud.utils.Ternary;
|
||||||
import com.cloud.vm.InstanceGroup;
|
import com.cloud.vm.InstanceGroup;
|
||||||
@ -99,14 +98,6 @@ import com.cloud.vm.VirtualMachine.Type;
|
|||||||
public interface ManagementService {
|
public interface ManagementService {
|
||||||
static final String Name = "management-server";
|
static final String Name = "management-server";
|
||||||
|
|
||||||
ConfigKey<Boolean> JsInterpretationEnabled = new ConfigKey<>("Hidden"
|
|
||||||
, Boolean.class
|
|
||||||
, "js.interpretation.enabled"
|
|
||||||
, "false"
|
|
||||||
, "Enable/Disable all JavaScript interpretation related functionalities to create or update Javascript rules."
|
|
||||||
, false
|
|
||||||
, ConfigKey.Scope.Global);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the a map of the names/values in the configuration table
|
* returns the a map of the names/values in the configuration table
|
||||||
*
|
*
|
||||||
@ -490,6 +481,4 @@ public interface ManagementService {
|
|||||||
|
|
||||||
Pair<Boolean, String> patchSystemVM(PatchSystemVMCmd cmd);
|
Pair<Boolean, String> patchSystemVM(PatchSystemVMCmd cmd);
|
||||||
|
|
||||||
void checkJsInterpretationAllowedIfNeededForParameterValue(String paramName, boolean paramValue);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ package com.cloud.server;
|
|||||||
|
|
||||||
public interface ResourceManagerUtil {
|
public interface ResourceManagerUtil {
|
||||||
long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType);
|
long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType);
|
||||||
long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType, boolean checkAccess);
|
|
||||||
String getUuid(String resourceId, ResourceTag.ResourceObjectType resourceType);
|
String getUuid(String resourceId, ResourceTag.ResourceObjectType resourceType);
|
||||||
ResourceTag.ResourceObjectType getResourceType(String resourceTypeStr);
|
ResourceTag.ResourceObjectType getResourceType(String resourceTypeStr);
|
||||||
void checkResourceAccessible(Long accountId, Long domainId, String exceptionMessage);
|
void checkResourceAccessible(Long accountId, Long domainId, String exceptionMessage);
|
||||||
|
|||||||
@ -26,7 +26,6 @@ public class ApiConstants {
|
|||||||
public static final String ACTIVATION_RULE = "activationrule";
|
public static final String ACTIVATION_RULE = "activationrule";
|
||||||
public static final String ACTIVITY = "activity";
|
public static final String ACTIVITY = "activity";
|
||||||
public static final String ADAPTER_TYPE = "adaptertype";
|
public static final String ADAPTER_TYPE = "adaptertype";
|
||||||
public static final String ADDITONAL_CONFIG_ENABLED = "additionalconfigenabled";
|
|
||||||
public static final String ADDRESS = "address";
|
public static final String ADDRESS = "address";
|
||||||
public static final String ALGORITHM = "algorithm";
|
public static final String ALGORITHM = "algorithm";
|
||||||
public static final String ALIAS = "alias";
|
public static final String ALIAS = "alias";
|
||||||
|
|||||||
@ -73,7 +73,6 @@ public class ListCapabilitiesCmd extends BaseCmd {
|
|||||||
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
|
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
|
||||||
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
|
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
|
||||||
response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
|
response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
|
||||||
response.setAdditionalConfigEnabled((Boolean) capabilities.get(ApiConstants.ADDITONAL_CONFIG_ENABLED));
|
|
||||||
response.setObjectName("capability");
|
response.setObjectName("capability");
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
this.setResponseObject(response);
|
this.setResponseObject(response);
|
||||||
|
|||||||
@ -140,10 +140,6 @@ public class CapabilitiesResponse extends BaseResponse {
|
|||||||
@Param(description = "true if dynamically scaling for instances is enabled", since = "4.21.0")
|
@Param(description = "true if dynamically scaling for instances is enabled", since = "4.21.0")
|
||||||
private Boolean dynamicScalingEnabled;
|
private Boolean dynamicScalingEnabled;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.ADDITONAL_CONFIG_ENABLED)
|
|
||||||
@Param(description = "true if additional configurations or extraconfig can be passed to Instances", since = "4.20.2")
|
|
||||||
private Boolean additionalConfigEnabled;
|
|
||||||
|
|
||||||
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
|
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
|
||||||
this.securityGroupsEnabled = securityGroupsEnabled;
|
this.securityGroupsEnabled = securityGroupsEnabled;
|
||||||
}
|
}
|
||||||
@ -259,8 +255,4 @@ public class CapabilitiesResponse extends BaseResponse {
|
|||||||
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
|
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
|
||||||
this.dynamicScalingEnabled = dynamicScalingEnabled;
|
this.dynamicScalingEnabled = dynamicScalingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAdditionalConfigEnabled(Boolean additionalConfigEnabled) {
|
|
||||||
this.additionalConfigEnabled = additionalConfigEnabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -294,8 +294,6 @@ public interface StorageManager extends StorageService {
|
|||||||
|
|
||||||
Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException;
|
Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException;
|
||||||
|
|
||||||
void updateStoragePoolHostVOAndBytes(StoragePool pool, long hostId, ModifyStoragePoolAnswer mspAnswer);
|
|
||||||
|
|
||||||
CapacityVO getSecondaryStorageUsedStats(Long hostId, Long zoneId);
|
CapacityVO getSecondaryStorageUsedStats(Long hostId, Long zoneId);
|
||||||
|
|
||||||
CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId);
|
CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId);
|
||||||
|
|||||||
@ -56,13 +56,6 @@ public interface TemplateManager {
|
|||||||
+ "will validate if the provided URL is resolvable during the register of templates/ISOs before persisting them in the database.",
|
+ "will validate if the provided URL is resolvable during the register of templates/ISOs before persisting them in the database.",
|
||||||
true);
|
true);
|
||||||
|
|
||||||
ConfigKey<Boolean> TemplateDeleteFromPrimaryStorage = new ConfigKey<Boolean>("Advanced",
|
|
||||||
Boolean.class,
|
|
||||||
"template.delete.from.primary.storage", "true",
|
|
||||||
"Template when deleted will be instantly deleted from the Primary Storage",
|
|
||||||
true,
|
|
||||||
ConfigKey.Scope.Global);
|
|
||||||
|
|
||||||
static final String VMWARE_TOOLS_ISO = "vmware-tools.iso";
|
static final String VMWARE_TOOLS_ISO = "vmware-tools.iso";
|
||||||
static final String XS_TOOLS_ISO = "xs-tools.iso";
|
static final String XS_TOOLS_ISO = "xs-tools.iso";
|
||||||
|
|
||||||
@ -110,8 +103,6 @@ public interface TemplateManager {
|
|||||||
*/
|
*/
|
||||||
List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool);
|
List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool);
|
||||||
|
|
||||||
void evictTemplateFromStoragePoolsForZones(Long templateId, List<Long> zoneId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a template in the specified storage pool.
|
* Deletes a template in the specified storage pool.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -4772,18 +4772,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selectedIp != null && GuestType.Shared.equals(network.getGuestType())) {
|
|
||||||
IPAddressVO ipAddressVO = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), selectedIp);
|
|
||||||
if (ipAddressVO != null && IpAddress.State.Free.equals(ipAddressVO.getState())) {
|
|
||||||
ipAddressVO.setState(IPAddressVO.State.Allocated);
|
|
||||||
ipAddressVO.setAllocatedTime(new Date());
|
|
||||||
Account account = _accountDao.findById(vm.getAccountId());
|
|
||||||
ipAddressVO.setAllocatedInDomainId(account.getDomainId());
|
|
||||||
ipAddressVO.setAllocatedToAccountId(account.getId());
|
|
||||||
_ipAddressDao.update(ipAddressVO.getId(), ipAddressVO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
|
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
|
||||||
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
|
||||||
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
|
||||||
@ -4795,15 +4783,15 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
if (network.getGuestType() == GuestType.L2) {
|
if (network.getGuestType() == GuestType.L2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return GuestType.Shared.equals(network.getGuestType()) ?
|
return dataCenter.getNetworkType() == NetworkType.Basic ?
|
||||||
getSelectedIpForNicImportOnSharedNetwork(ipAddresses.getIp4Address(), network, dataCenter):
|
getSelectedIpForNicImportOnBasicZone(ipAddresses.getIp4Address(), network, dataCenter):
|
||||||
_ipAddrMgr.acquireGuestIpAddress(network, ipAddresses.getIp4Address());
|
_ipAddrMgr.acquireGuestIpAddress(network, ipAddresses.getIp4Address());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSelectedIpForNicImportOnSharedNetwork(String requestedIp, Network network, DataCenter dataCenter) {
|
protected String getSelectedIpForNicImportOnBasicZone(String requestedIp, Network network, DataCenter dataCenter) {
|
||||||
IPAddressVO ipAddressVO = StringUtils.isBlank(requestedIp) ?
|
IPAddressVO ipAddressVO = StringUtils.isBlank(requestedIp) ?
|
||||||
_ipAddressDao.findBySourceNetworkIdAndDatacenterIdAndState(network.getId(), dataCenter.getId(), IpAddress.State.Free):
|
_ipAddressDao.findBySourceNetworkIdAndDatacenterIdAndState(network.getId(), dataCenter.getId(), IpAddress.State.Free):
|
||||||
_ipAddressDao.findByIpAndSourceNetworkId(network.getId(), requestedIp);
|
_ipAddressDao.findByIp(requestedIp);
|
||||||
if (ipAddressVO == null || ipAddressVO.getState() != IpAddress.State.Free) {
|
if (ipAddressVO == null || ipAddressVO.getState() != IpAddress.State.Free) {
|
||||||
String msg = String.format("Cannot find a free IP to assign to VM NIC on network %s", network.getName());
|
String msg = String.format("Cannot find a free IP to assign to VM NIC on network %s", network.getName());
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
|
|||||||
@ -822,7 +822,7 @@ public class NetworkOrchestratorTest extends TestCase {
|
|||||||
Mockito.when(network.getId()).thenReturn(networkId);
|
Mockito.when(network.getId()).thenReturn(networkId);
|
||||||
Mockito.when(dataCenter.getId()).thenReturn(dataCenterId);
|
Mockito.when(dataCenter.getId()).thenReturn(dataCenterId);
|
||||||
Mockito.when(ipAddresses.getIp4Address()).thenReturn(requestedIp);
|
Mockito.when(ipAddresses.getIp4Address()).thenReturn(requestedIp);
|
||||||
Mockito.when(testOrchestrator._ipAddressDao.findByIpAndSourceNetworkId(networkId, requestedIp)).thenReturn(ipAddressVO);
|
Mockito.when(testOrchestrator._ipAddressDao.findByIp(requestedIp)).thenReturn(ipAddressVO);
|
||||||
String ipAddress = testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
|
String ipAddress = testOrchestrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
|
||||||
Assert.assertEquals(requestedIp, ipAddress);
|
Assert.assertEquals(requestedIp, ipAddress);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,8 +35,6 @@ public interface VMTemplatePoolDao extends GenericDao<VMTemplateStoragePoolVO, L
|
|||||||
|
|
||||||
List<VMTemplateStoragePoolVO> listByPoolIdAndState(long poolId, ObjectInDataStoreStateMachine.State state);
|
List<VMTemplateStoragePoolVO> listByPoolIdAndState(long poolId, ObjectInDataStoreStateMachine.State state);
|
||||||
|
|
||||||
List<VMTemplateStoragePoolVO> listByPoolIdsAndTemplate(List<Long> poolIds, Long templateId);
|
|
||||||
|
|
||||||
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState);
|
||||||
|
|
||||||
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState, long poolId);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState, long poolId);
|
||||||
|
|||||||
@ -150,16 +150,6 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
return findOneIncludingRemovedBy(sc);
|
return findOneIncludingRemovedBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<VMTemplateStoragePoolVO> listByPoolIdsAndTemplate(List<Long> poolIds, Long templateId) {
|
|
||||||
SearchCriteria<VMTemplateStoragePoolVO> sc = PoolTemplateSearch.create();
|
|
||||||
if (CollectionUtils.isNotEmpty(poolIds)) {
|
|
||||||
sc.setParameters("pool_id", poolIds.toArray());
|
|
||||||
}
|
|
||||||
sc.setParameters("template_id", templateId);
|
|
||||||
return listBy(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState) {
|
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState) {
|
||||||
SearchCriteria<VMTemplateStoragePoolVO> sc = TemplateStatusSearch.create();
|
SearchCriteria<VMTemplateStoragePoolVO> sc = TemplateStatusSearch.create();
|
||||||
|
|||||||
@ -116,17 +116,17 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
|
|||||||
|
|
||||||
protected Attribute _updateTimeAttr;
|
protected Attribute _updateTimeAttr;
|
||||||
|
|
||||||
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) " +
|
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) " +
|
||||||
"FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE ";
|
"FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE ";
|
||||||
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " AND host.type = 'Routing' AND host.removed is null GROUP BY host.cluster_id " +
|
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " AND host.type = 'Routing' AND host.removed is null GROUP BY host.cluster_id " +
|
||||||
"ORDER BY 2 ASC ";
|
"ORDER BY 2 ASC ";
|
||||||
|
|
||||||
private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) FROM `cloud`.`" +
|
private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`" +
|
||||||
"host_pod_ref` pod LEFT JOIN `cloud`.`vm_instance` vm ON pod.id = vm.pod_id WHERE pod.data_center_id = ? AND pod.removed is null "
|
"host_pod_ref` pod LEFT JOIN `cloud`.`vm_instance` vm ON pod.id = vm.pod_id WHERE pod.data_center_id = ? AND pod.removed is null "
|
||||||
+ " GROUP BY pod.id ORDER BY 2 ASC ";
|
+ " GROUP BY pod.id ORDER BY 2 ASC ";
|
||||||
|
|
||||||
private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT =
|
private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT =
|
||||||
"SELECT host.id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id " +
|
"SELECT host.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id " +
|
||||||
"WHERE host.data_center_id = ? AND host.type = 'Routing' AND host.removed is null ";
|
"WHERE host.data_center_id = ? AND host.type = 'Routing' AND host.removed is null ";
|
||||||
|
|
||||||
private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " GROUP BY host.id ORDER BY 2 ASC ";
|
private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " GROUP BY host.id ORDER BY 2 ASC ";
|
||||||
|
|||||||
@ -154,6 +154,4 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
String keyword, Filter searchFilter);
|
String keyword, Filter searchFilter);
|
||||||
|
|
||||||
List<StoragePoolVO> listByIds(List<Long> ids);
|
List<StoragePoolVO> listByIds(List<Long> ids);
|
||||||
|
|
||||||
List<StoragePoolVO> listByDataCenterIds(List<Long> dataCenterIds);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,6 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
private final GenericSearchBuilder<StoragePoolVO, Long> StatusCountSearch;
|
private final GenericSearchBuilder<StoragePoolVO, Long> StatusCountSearch;
|
||||||
private final SearchBuilder<StoragePoolVO> ClustersSearch;
|
private final SearchBuilder<StoragePoolVO> ClustersSearch;
|
||||||
private final SearchBuilder<StoragePoolVO> IdsSearch;
|
private final SearchBuilder<StoragePoolVO> IdsSearch;
|
||||||
private final SearchBuilder<StoragePoolVO> DcsSearch;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private StoragePoolDetailsDao _detailsDao;
|
private StoragePoolDetailsDao _detailsDao;
|
||||||
@ -156,9 +155,6 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
IdsSearch.and("ids", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
|
IdsSearch.and("ids", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
|
||||||
IdsSearch.done();
|
IdsSearch.done();
|
||||||
|
|
||||||
DcsSearch = createSearchBuilder();
|
|
||||||
DcsSearch.and("dataCenterId", DcsSearch.entity().getDataCenterId(), SearchCriteria.Op.IN);
|
|
||||||
DcsSearch.done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -737,16 +733,6 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<StoragePoolVO> listByDataCenterIds(List<Long> dataCenterIds) {
|
|
||||||
if (CollectionUtils.isEmpty(dataCenterIds)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
SearchCriteria<StoragePoolVO> sc = DcsSearch.create();
|
|
||||||
sc.setParameters("dataCenterId", dataCenterIds.toArray());
|
|
||||||
return listBy(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SearchCriteria<StoragePoolVO> createStoragePoolSearchCriteria(Long storagePoolId, String storagePoolName,
|
private SearchCriteria<StoragePoolVO> createStoragePoolSearchCriteria(Long storagePoolId, String storagePoolName,
|
||||||
Long zoneId, String path, Long podId, Long clusterId, String address, ScopeType scopeType,
|
Long zoneId, String path, Long podId, Long clusterId, String address, ScopeType scopeType,
|
||||||
StoragePoolStatus status, String keyword) {
|
StoragePoolStatus status, String keyword) {
|
||||||
|
|||||||
@ -159,9 +159,7 @@ public class PrimaryDataStoreHelper {
|
|||||||
pool.setScope(scope.getScopeType());
|
pool.setScope(scope.getScopeType());
|
||||||
pool.setUsedBytes(existingInfo.getCapacityBytes() - existingInfo.getAvailableBytes());
|
pool.setUsedBytes(existingInfo.getCapacityBytes() - existingInfo.getAvailableBytes());
|
||||||
pool.setCapacityBytes(existingInfo.getCapacityBytes());
|
pool.setCapacityBytes(existingInfo.getCapacityBytes());
|
||||||
if (pool.getStatus() != StoragePoolStatus.Disabled) {
|
pool.setStatus(StoragePoolStatus.Up);
|
||||||
pool.setStatus(StoragePoolStatus.Up);
|
|
||||||
}
|
|
||||||
this.dataStoreDao.update(pool.getId(), pool);
|
this.dataStoreDao.update(pool.getId(), pool);
|
||||||
this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getUsedBytes());
|
this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getUsedBytes());
|
||||||
return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
|
return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.user.Account;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
|
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
|
||||||
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
|
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
|
||||||
@ -61,7 +62,6 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import com.cloud.usage.UsageVO;
|
import com.cloud.usage.UsageVO;
|
||||||
import com.cloud.usage.dao.UsageDao;
|
import com.cloud.usage.dao.UsageDao;
|
||||||
import com.cloud.user.Account;
|
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.utils.DateUtil;
|
import com.cloud.utils.DateUtil;
|
||||||
@ -467,7 +467,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsInterpreter.injectVariable("resourceType", presetVariables.getResourceType());
|
jsInterpreter.injectStringVariable("resourceType", presetVariables.getResourceType());
|
||||||
jsInterpreter.injectVariable("value", presetVariables.getValue().toString());
|
jsInterpreter.injectVariable("value", presetVariables.getValue().toString());
|
||||||
jsInterpreter.injectVariable("zone", presetVariables.getZone().toString());
|
jsInterpreter.injectVariable("zone", presetVariables.getZone().toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -270,7 +270,7 @@ public class QuotaManagerImplTest {
|
|||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("project"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("project"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("resourceType"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectStringVariable(Mockito.eq("resourceType"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ public class QuotaManagerImplTest {
|
|||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("project"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("project"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("resourceType"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectStringVariable(Mockito.eq("resourceType"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
|
||||||
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
|
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.utils.DateUtil;
|
||||||
import org.apache.cloudstack.api.ApiErrorCode;
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
|
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
|
||||||
@ -69,8 +70,8 @@ import org.apache.cloudstack.quota.dao.QuotaCreditsDao;
|
|||||||
import org.apache.cloudstack.quota.dao.QuotaEmailConfigurationDao;
|
import org.apache.cloudstack.quota.dao.QuotaEmailConfigurationDao;
|
||||||
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
|
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
|
||||||
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
|
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
|
||||||
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
|
|
||||||
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
|
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
|
||||||
|
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
|
||||||
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
|
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
|
||||||
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
|
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
|
||||||
import org.apache.cloudstack.quota.vo.QuotaEmailConfigurationVO;
|
import org.apache.cloudstack.quota.vo.QuotaEmailConfigurationVO;
|
||||||
@ -78,28 +79,26 @@ import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
|
|||||||
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
|
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
|
||||||
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
|
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.domain.DomainVO;
|
import com.cloud.domain.DomainVO;
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.event.ActionEvent;
|
|
||||||
import com.cloud.event.EventTypes;
|
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.exception.PermissionDeniedException;
|
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.User;
|
import com.cloud.user.User;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.user.dao.UserDao;
|
import com.cloud.user.dao.UserDao;
|
||||||
import com.cloud.utils.DateUtil;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
|
import com.cloud.event.ActionEvent;
|
||||||
|
import com.cloud.event.EventTypes;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||||
@ -140,12 +139,6 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
|||||||
@Inject
|
@Inject
|
||||||
private ApiDiscoveryService apiDiscoveryService;
|
private ApiDiscoveryService apiDiscoveryService;
|
||||||
|
|
||||||
protected void checkActivationRulesAllowed(String activationRule) {
|
|
||||||
if (!_quotaService.isJsInterpretationEnabled() && StringUtils.isNotEmpty(activationRule)) {
|
|
||||||
throw new PermissionDeniedException("Quota Tariff Activation Rule cannot be set, as Javascript interpretation is disabled in the configuration.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff, boolean returnActivationRule) {
|
public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff, boolean returnActivationRule) {
|
||||||
final QuotaTariffResponse response = new QuotaTariffResponse();
|
final QuotaTariffResponse response = new QuotaTariffResponse();
|
||||||
@ -447,8 +440,6 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
|||||||
throw new InvalidParameterValueException(String.format("There is no quota tariffs with name [%s].", name));
|
throw new InvalidParameterValueException(String.format("There is no quota tariffs with name [%s].", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkActivationRulesAllowed(activationRule);
|
|
||||||
|
|
||||||
Date currentQuotaTariffStartDate = currentQuotaTariff.getEffectiveOn();
|
Date currentQuotaTariffStartDate = currentQuotaTariff.getEffectiveOn();
|
||||||
|
|
||||||
currentQuotaTariff.setRemoved(now);
|
currentQuotaTariff.setRemoved(now);
|
||||||
@ -705,8 +696,6 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
|||||||
throw new InvalidParameterValueException(String.format("A quota tariff with name [%s] already exist.", name));
|
throw new InvalidParameterValueException(String.format("A quota tariff with name [%s] already exist.", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkActivationRulesAllowed(activationRule);
|
|
||||||
|
|
||||||
if (startDate.compareTo(now) < 0) {
|
if (startDate.compareTo(now) < 0) {
|
||||||
throw new InvalidParameterValueException(String.format("The value passed as Quota tariff's start date is in the past: [%s]. " +
|
throw new InvalidParameterValueException(String.format("The value passed as Quota tariff's start date is in the past: [%s]. " +
|
||||||
"Please, inform a date in the future or do not pass the parameter to use the current date and time.", startDate));
|
"Please, inform a date in the future or do not pass the parameter to use the current date and time.", startDate));
|
||||||
|
|||||||
@ -16,15 +16,15 @@
|
|||||||
//under the License.
|
//under the License.
|
||||||
package org.apache.cloudstack.quota;
|
package org.apache.cloudstack.quota;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import com.cloud.user.AccountVO;
|
||||||
import java.util.Date;
|
import com.cloud.utils.component.PluggableService;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
|
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
|
||||||
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
|
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
|
||||||
|
|
||||||
import com.cloud.user.AccountVO;
|
import java.math.BigDecimal;
|
||||||
import com.cloud.utils.component.PluggableService;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface QuotaService extends PluggableService {
|
public interface QuotaService extends PluggableService {
|
||||||
|
|
||||||
@ -40,6 +40,4 @@ public interface QuotaService extends PluggableService {
|
|||||||
|
|
||||||
boolean saveQuotaAccount(AccountVO account, BigDecimal aggrUsage, Date endDate);
|
boolean saveQuotaAccount(AccountVO account, BigDecimal aggrUsage, Date endDate);
|
||||||
|
|
||||||
boolean isJsInterpretationEnabled();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,6 @@ import com.cloud.configuration.Config;
|
|||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.exception.PermissionDeniedException;
|
import com.cloud.exception.PermissionDeniedException;
|
||||||
import com.cloud.server.ManagementService;
|
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
@ -87,8 +86,6 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
|
|||||||
|
|
||||||
private TimeZone _usageTimezone;
|
private TimeZone _usageTimezone;
|
||||||
|
|
||||||
private boolean jsInterpretationEnabled = false;
|
|
||||||
|
|
||||||
public QuotaServiceImpl() {
|
public QuotaServiceImpl() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -100,8 +97,6 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
|
|||||||
String timeZoneStr = ObjectUtils.defaultIfNull(_configDao.getValue(Config.UsageAggregationTimezone.toString()), "GMT");
|
String timeZoneStr = ObjectUtils.defaultIfNull(_configDao.getValue(Config.UsageAggregationTimezone.toString()), "GMT");
|
||||||
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
|
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
|
||||||
|
|
||||||
jsInterpretationEnabled = ManagementService.JsInterpretationEnabled.value();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,8 +284,4 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isJsInterpretationEnabled() {
|
|
||||||
return jsInterpretationEnabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ public class KVMHostInfo {
|
|||||||
private long reservedMemory;
|
private long reservedMemory;
|
||||||
private long overCommitMemory;
|
private long overCommitMemory;
|
||||||
private List<String> capabilities = new ArrayList<>();
|
private List<String> capabilities = new ArrayList<>();
|
||||||
private static String cpuArchRetrieveExecutable = "arch";
|
private static String cpuArchCommand = "/usr/bin/arch";
|
||||||
private static List<String> cpuInfoFreqFileNames = List.of("/sys/devices/system/cpu/cpu0/cpufreq/base_frequency","/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
|
private static List<String> cpuInfoFreqFileNames = List.of("/sys/devices/system/cpu/cpu0/cpufreq/base_frequency","/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
|
||||||
|
|
||||||
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed, int reservedCpus) {
|
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed, int reservedCpus) {
|
||||||
@ -248,6 +248,6 @@ public class KVMHostInfo {
|
|||||||
|
|
||||||
private String getCPUArchFromCommand() {
|
private String getCPUArchFromCommand() {
|
||||||
LOGGER.info("Fetching host CPU arch");
|
LOGGER.info("Fetching host CPU arch");
|
||||||
return Script.runSimpleBashScript(Script.getExecutableAbsolutePath(cpuArchRetrieveExecutable));
|
return Script.runSimpleBashScript(cpuArchCommand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5837,20 +5837,11 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
|
|||||||
if (toolsStatus == VirtualMachineToolsStatus.TOOLS_NOT_INSTALLED) {
|
if (toolsStatus == VirtualMachineToolsStatus.TOOLS_NOT_INSTALLED) {
|
||||||
details += "Vmware tools not installed.";
|
details += "Vmware tools not installed.";
|
||||||
} else {
|
} else {
|
||||||
var normalizedMac = cmd.getMacAddress().replaceAll("-", ":");
|
ip = guestInfo.getIpAddress();
|
||||||
for(var guestInfoNic : guestInfo.getNet()) {
|
if (ip != null) {
|
||||||
var normalizedNicMac = guestInfoNic.getMacAddress().replaceAll("-", ":");
|
result = true;
|
||||||
if (!result && normalizedNicMac.equalsIgnoreCase(normalizedMac)) {
|
|
||||||
result = true;
|
|
||||||
details = null;
|
|
||||||
for (var ipAddr : guestInfoNic.getIpAddress()) {
|
|
||||||
if (NetUtils.isValidIp4(ipAddr) && (cmd.getVmNetworkCidr() == null || NetUtils.isIpWithInCidrRange(ipAddr, cmd.getVmNetworkCidr()))) {
|
|
||||||
details = ipAddr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
details = ip;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
details += "VM " + vmName + " no longer exists on vSphere host: " + hyperHost.getHyperHostName();
|
details += "VM " + vmName + " no longer exists on vSphere host: " + hyperHost.getHyperHostName();
|
||||||
|
|||||||
@ -381,9 +381,6 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
logger.warn("Unable to find the network with ID: {} passed for the Kubernetes cluster", networkId);
|
logger.warn("Unable to find the network with ID: {} passed for the Kubernetes cluster", networkId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isDirectAccess(network)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
networkOffering = networkOfferingDao.findById(network.getNetworkOfferingId());
|
networkOffering = networkOfferingDao.findById(network.getNetworkOfferingId());
|
||||||
if (networkOffering == null) {
|
if (networkOffering == null) {
|
||||||
logger.warn("Unable to find the network offering of the network: {} ({}) to be used for provisioning Kubernetes cluster", network.getName(), network.getUuid());
|
logger.warn("Unable to find the network offering of the network: {} ({}) to be used for provisioning Kubernetes cluster", network.getName(), network.getUuid());
|
||||||
@ -1554,7 +1551,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
try {
|
try {
|
||||||
Role role = getProjectKubernetesAccountRole();
|
Role role = getProjectKubernetesAccountRole();
|
||||||
UserAccount userAccount = accountService.createUserAccount(accountName,
|
UserAccount userAccount = accountService.createUserAccount(accountName,
|
||||||
UUID.randomUUID().toString(), PROJECT_KUBERNETES_ACCOUNT_FIRST_NAME,
|
UuidUtils.first(UUID.randomUUID().toString()), PROJECT_KUBERNETES_ACCOUNT_FIRST_NAME,
|
||||||
PROJECT_KUBERNETES_ACCOUNT_LAST_NAME, null, null, accountName, Account.Type.NORMAL, role.getId(),
|
PROJECT_KUBERNETES_ACCOUNT_LAST_NAME, null, null, accountName, Account.Type.NORMAL, role.getId(),
|
||||||
project.getDomainId(), null, null, null, null, User.Source.NATIVE);
|
project.getDomainId(), null, null, null, null, User.Source.NATIVE);
|
||||||
projectManager.assignAccountToProject(project, userAccount.getAccountId(), ProjectAccount.Role.Regular,
|
projectManager.assignAccountToProject(project, userAccount.getAccountId(), ProjectAccount.Role.Regular,
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import static com.cloud.utils.NumbersUtil.toReadableSize;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -33,6 +32,8 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.dc.ClusterVO;
|
||||||
|
import com.cloud.utils.Ternary;
|
||||||
import org.apache.cloudstack.api.ApiErrorCode;
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
import org.apache.cloudstack.api.ListClustersMetricsCmd;
|
import org.apache.cloudstack.api.ListClustersMetricsCmd;
|
||||||
import org.apache.cloudstack.api.ListDbMetricsCmd;
|
import org.apache.cloudstack.api.ListDbMetricsCmd;
|
||||||
@ -99,7 +100,6 @@ import com.cloud.capacity.CapacityManager;
|
|||||||
import com.cloud.capacity.dao.CapacityDao;
|
import com.cloud.capacity.dao.CapacityDao;
|
||||||
import com.cloud.capacity.dao.CapacityDaoImpl;
|
import com.cloud.capacity.dao.CapacityDaoImpl;
|
||||||
import com.cloud.cluster.dao.ManagementServerHostDao;
|
import com.cloud.cluster.dao.ManagementServerHostDao;
|
||||||
import com.cloud.dc.ClusterVO;
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
import com.cloud.dc.dao.ClusterDao;
|
import com.cloud.dc.dao.ClusterDao;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
@ -112,7 +112,6 @@ import com.cloud.host.Status;
|
|||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.network.router.VirtualRouter;
|
import com.cloud.network.router.VirtualRouter;
|
||||||
import com.cloud.org.Cluster;
|
import com.cloud.org.Cluster;
|
||||||
import com.cloud.projects.Project;
|
|
||||||
import com.cloud.server.DbStatsCollection;
|
import com.cloud.server.DbStatsCollection;
|
||||||
import com.cloud.server.ManagementServerHostStats;
|
import com.cloud.server.ManagementServerHostStats;
|
||||||
import com.cloud.server.StatsCollector;
|
import com.cloud.server.StatsCollector;
|
||||||
@ -125,7 +124,6 @@ import com.cloud.usage.dao.UsageJobDao;
|
|||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.Ternary;
|
|
||||||
import com.cloud.utils.db.DbProperties;
|
import com.cloud.utils.db.DbProperties;
|
||||||
import com.cloud.utils.db.DbUtil;
|
import com.cloud.utils.db.DbUtil;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
@ -186,10 +184,6 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
|
|||||||
|
|
||||||
private static Gson gson = new Gson();
|
private static Gson gson = new Gson();
|
||||||
|
|
||||||
private final List<Account.Type> AccountTypesWithRecursiveUsageAccess = Arrays.asList(
|
|
||||||
Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN, Account.Type.READ_ONLY_ADMIN
|
|
||||||
);
|
|
||||||
|
|
||||||
protected MetricsServiceImpl() {
|
protected MetricsServiceImpl() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -251,30 +245,17 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
|
|||||||
* @return the list of VMs.
|
* @return the list of VMs.
|
||||||
*/
|
*/
|
||||||
protected Pair<List<UserVmVO>, Integer> searchForUserVmsInternal(ListVMsUsageHistoryCmd cmd) {
|
protected Pair<List<UserVmVO>, Integer> searchForUserVmsInternal(ListVMsUsageHistoryCmd cmd) {
|
||||||
final Long id = cmd.getId();
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
|
||||||
List<Long> permittedAccounts = new ArrayList<>();
|
|
||||||
boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(caller.getType());
|
|
||||||
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(null, recursive, null);
|
|
||||||
accountMgr.buildACLSearchParameters(caller, id, null, null, permittedAccounts, domainIdRecursiveListProject, true, false);
|
|
||||||
Long domainId = domainIdRecursiveListProject.first();
|
|
||||||
Boolean isRecursive = domainIdRecursiveListProject.second();
|
|
||||||
Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
|
||||||
|
|
||||||
Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||||
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
|
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
|
||||||
String name = cmd.getName();
|
String name = cmd.getName();
|
||||||
String keyword = cmd.getKeyword();
|
String keyword = cmd.getKeyword();
|
||||||
|
|
||||||
SearchBuilder<UserVmVO> sb = userVmDao.createSearchBuilder();
|
SearchBuilder<UserVmVO> sb = userVmDao.createSearchBuilder();
|
||||||
sb.select(null, SearchCriteria.Func.DISTINCT, sb.entity().getId()); // select distinct
|
|
||||||
accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN);
|
sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN);
|
||||||
sb.and("displayName", sb.entity().getDisplayName(), SearchCriteria.Op.LIKE);
|
sb.and("displayName", sb.entity().getDisplayName(), SearchCriteria.Op.LIKE);
|
||||||
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
|
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
SearchCriteria<UserVmVO> sc = sb.create();
|
SearchCriteria<UserVmVO> sc = sb.create();
|
||||||
accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
if (CollectionUtils.isNotEmpty(ids)) {
|
if (CollectionUtils.isNotEmpty(ids)) {
|
||||||
sc.setParameters("idIN", ids.toArray());
|
sc.setParameters("idIN", ids.toArray());
|
||||||
}
|
}
|
||||||
@ -288,14 +269,7 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
|
|||||||
sc.addAnd("displayName", SearchCriteria.Op.SC, ssc);
|
sc.addAnd("displayName", SearchCriteria.Op.SC, ssc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<List<UserVmVO>, Integer> uniqueVmPair = userVmDao.searchAndCount(sc, searchFilter);
|
return userVmDao.searchAndCount(sc, searchFilter);
|
||||||
Integer count = uniqueVmPair.second();
|
|
||||||
if (count == 0) {
|
|
||||||
return new Pair<>(new ArrayList<>(), count);
|
|
||||||
}
|
|
||||||
List<Long> vmIds = uniqueVmPair.first().stream().map(UserVmVO::getId).collect(Collectors.toList());
|
|
||||||
List<UserVmVO> vms = userVmDao.listByIds(vmIds);
|
|
||||||
return new Pair<>(vms, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,49 +331,17 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
|
|||||||
* @return the list of VMs.
|
* @return the list of VMs.
|
||||||
*/
|
*/
|
||||||
protected Pair<List<VolumeVO>, Integer> searchForVolumesInternal(ListVolumesUsageHistoryCmd cmd) {
|
protected Pair<List<VolumeVO>, Integer> searchForVolumesInternal(ListVolumesUsageHistoryCmd cmd) {
|
||||||
final Long id = cmd.getId();
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
|
||||||
List<Long> permittedAccounts = new ArrayList<>();
|
|
||||||
boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(caller.getType());
|
|
||||||
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(null, recursive, null);
|
|
||||||
accountMgr.buildACLSearchParameters(caller, id, null, null, permittedAccounts, domainIdRecursiveListProject, true, false);
|
|
||||||
Long domainId = domainIdRecursiveListProject.first();
|
|
||||||
Boolean isRecursive = domainIdRecursiveListProject.second();
|
|
||||||
Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
|
||||||
|
|
||||||
Filter searchFilter = new Filter(VolumeVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
Filter searchFilter = new Filter(VolumeVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||||
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
|
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
|
||||||
String name = cmd.getName();
|
String name = cmd.getName();
|
||||||
String keyword = cmd.getKeyword();
|
String keyword = cmd.getKeyword();
|
||||||
|
|
||||||
SearchBuilder<VolumeVO> sb = volumeDao.createSearchBuilder();
|
SearchBuilder<VolumeVO> sb = volumeDao.createSearchBuilder();
|
||||||
sb.select(null, SearchCriteria.Func.DISTINCT, sb.entity().getId()); // select distinct
|
|
||||||
accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN);
|
sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN);
|
||||||
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
||||||
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
|
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
boolean shouldListSystemVmVolumes = accountMgr.isRootAdmin(CallContext.current().getCallingAccountId());
|
|
||||||
List<Long> vmIds = new ArrayList<>();
|
|
||||||
if (!shouldListSystemVmVolumes) {
|
|
||||||
SearchBuilder<UserVmVO> vmSearch = userVmDao.createSearchBuilder();
|
|
||||||
vmSearch.select(null, SearchCriteria.Func.DISTINCT, vmSearch.entity().getId());
|
|
||||||
accountMgr.buildACLSearchBuilder(vmSearch, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
SearchCriteria<UserVmVO> vmSc = vmSearch.create();
|
|
||||||
accountMgr.buildACLSearchCriteria(vmSc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
List<UserVmVO> vms = userVmDao.search(vmSc, null);
|
|
||||||
vmIds = vms.stream().map(UserVmVO::getId).collect(Collectors.toList());
|
|
||||||
if (vmIds.isEmpty()) {
|
|
||||||
sb.and("instanceIdNull", sb.entity().getInstanceId(), SearchCriteria.Op.NULL);
|
|
||||||
} else {
|
|
||||||
sb.and().op("instanceIdNull", sb.entity().getInstanceId(), SearchCriteria.Op.NULL);
|
|
||||||
sb.or("instanceIds", sb.entity().getInstanceId(), SearchCriteria.Op.IN);
|
|
||||||
sb.cp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchCriteria<VolumeVO> sc = sb.create();
|
SearchCriteria<VolumeVO> sc = sb.create();
|
||||||
accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
|
||||||
if (CollectionUtils.isNotEmpty(ids)) {
|
if (CollectionUtils.isNotEmpty(ids)) {
|
||||||
sc.setParameters("idIN", ids.toArray());
|
sc.setParameters("idIN", ids.toArray());
|
||||||
}
|
}
|
||||||
@ -412,18 +354,8 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
|
|||||||
ssc.addOr("state", SearchCriteria.Op.EQ, keyword);
|
ssc.addOr("state", SearchCriteria.Op.EQ, keyword);
|
||||||
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
|
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
|
||||||
}
|
}
|
||||||
if (!shouldListSystemVmVolumes && CollectionUtils.isNotEmpty(vmIds)) {
|
|
||||||
sc.setParameters("instanceIds", vmIds.toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<List<VolumeVO>, Integer> uniqueVolumePair = volumeDao.searchAndCount(sc, searchFilter);
|
return volumeDao.searchAndCount(sc, searchFilter);
|
||||||
Integer count = uniqueVolumePair.second();
|
|
||||||
if (count == 0) {
|
|
||||||
return new Pair<>(new ArrayList<>(), count);
|
|
||||||
}
|
|
||||||
List<Long> volumeIds = uniqueVolumePair.first().stream().map(VolumeVO::getId).collect(Collectors.toList());
|
|
||||||
List<VolumeVO> volumes = volumeDao.listByIds(volumeIds);
|
|
||||||
return new Pair<>(volumes, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -19,16 +19,13 @@ package org.apache.cloudstack.metrics;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ListVMsUsageHistoryCmd;
|
import org.apache.cloudstack.api.ListVMsUsageHistoryCmd;
|
||||||
import org.apache.cloudstack.api.ListVolumesUsageHistoryCmd;
|
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
|
||||||
import org.apache.cloudstack.response.VmMetricsStatsResponse;
|
import org.apache.cloudstack.response.VmMetricsStatsResponse;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@ -38,18 +35,12 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.Captor;
|
import org.mockito.Captor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.storage.VolumeVO;
|
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
|
||||||
import com.cloud.user.Account;
|
|
||||||
import com.cloud.user.AccountManager;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.vm.UserVmVO;
|
import com.cloud.vm.UserVmVO;
|
||||||
@ -84,12 +75,6 @@ public class MetricsServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
VmStatsDao vmStatsDaoMock;
|
VmStatsDao vmStatsDaoMock;
|
||||||
|
|
||||||
@Mock
|
|
||||||
AccountManager accountManager;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
VolumeDao volumeDao;
|
|
||||||
|
|
||||||
@Captor
|
@Captor
|
||||||
ArgumentCaptor<String> stringCaptor1, stringCaptor2;
|
ArgumentCaptor<String> stringCaptor1, stringCaptor2;
|
||||||
|
|
||||||
@ -110,26 +95,12 @@ public class MetricsServiceImplTest {
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
VmStatsVO vmStatsVOMock;
|
VmStatsVO vmStatsVOMock;
|
||||||
@Mock
|
|
||||||
Account mockAccount;
|
|
||||||
@Mock
|
|
||||||
ListVolumesUsageHistoryCmd listVolumesUsageHistoryCmdMock;
|
|
||||||
@Mock
|
|
||||||
VolumeVO volumeVOMock;
|
|
||||||
@Mock
|
|
||||||
SearchBuilder<VolumeVO> volumeSearchBuilderMock;
|
|
||||||
@Mock
|
|
||||||
SearchCriteria<VolumeVO> volumeSearchCriteriaMock;
|
|
||||||
@Mock
|
|
||||||
Filter filterMock;
|
|
||||||
|
|
||||||
|
|
||||||
private void prepareSearchCriteriaWhenUseSetParameters() {
|
private void prepareSearchCriteriaWhenUseSetParameters() {
|
||||||
Mockito.doNothing().when(scMock).setParameters(Mockito.anyString(), Mockito.any());
|
Mockito.doNothing().when(scMock).setParameters(Mockito.anyString(), Mockito.any());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preparesearchForUserVmsInternalTest() {
|
private void preparesearchForUserVmsInternalTest() {
|
||||||
Mockito.when(mockAccount.getType()).thenReturn(Account.Type.NORMAL);
|
|
||||||
expectedVmListAndCounter = new Pair<>(Arrays.asList(userVmVOMock), 1);
|
expectedVmListAndCounter = new Pair<>(Arrays.asList(userVmVOMock), 1);
|
||||||
|
|
||||||
Mockito.doReturn(1L).when(listVMsUsageHistoryCmdMock).getStartIndex();
|
Mockito.doReturn(1L).when(listVMsUsageHistoryCmdMock).getStartIndex();
|
||||||
@ -140,10 +111,8 @@ public class MetricsServiceImplTest {
|
|||||||
Mockito.doReturn(userVmVOMock).when(sbMock).entity();
|
Mockito.doReturn(userVmVOMock).when(sbMock).entity();
|
||||||
Mockito.doReturn(scMock).when(sbMock).create();
|
Mockito.doReturn(scMock).when(sbMock).create();
|
||||||
|
|
||||||
Mockito.doReturn(expectedVmListAndCounter)
|
Mockito.doReturn(new Pair<List<UserVmVO>, Integer>(Arrays.asList(userVmVOMock), 1))
|
||||||
.when(userVmDaoMock).searchAndCount(Mockito.any(), Mockito.any());
|
.when(userVmDaoMock).searchAndCount(Mockito.any(), Mockito.any());
|
||||||
Mockito.doReturn(expectedVmListAndCounter.first())
|
|
||||||
.when(userVmDaoMock).listByIds(Mockito.anyList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -155,17 +124,12 @@ public class MetricsServiceImplTest {
|
|||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
||||||
|
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
||||||
Assert.assertEquals("idIN", stringCaptor1.getValue());
|
Assert.assertEquals("idIN", stringCaptor1.getValue());
|
||||||
Assert.assertEquals(fakeVmId1, objectArrayCaptor.getAllValues().get(0)[0]);
|
Assert.assertEquals(fakeVmId1, objectArrayCaptor.getAllValues().get(0)[0]);
|
||||||
Assert.assertEquals(expectedVmListAndCounter, result);
|
Assert.assertEquals(expectedVmListAndCounter, result);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -177,17 +141,13 @@ public class MetricsServiceImplTest {
|
|||||||
Mockito.doReturn(expected).when(listVMsUsageHistoryCmdMock).getIds();
|
Mockito.doReturn(expected).when(listVMsUsageHistoryCmdMock).getIds();
|
||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
||||||
Assert.assertEquals("idIN", stringCaptor1.getValue());
|
|
||||||
Assert.assertArrayEquals(expected.toArray(), objectArrayCaptor.getAllValues().get(0));
|
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
||||||
Assert.assertEquals(expectedVmListAndCounter, result);
|
Assert.assertEquals("idIN", stringCaptor1.getValue());
|
||||||
}
|
Assert.assertArrayEquals(expected.toArray(), objectArrayCaptor.getAllValues().get(0));
|
||||||
|
Assert.assertEquals(expectedVmListAndCounter, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -199,17 +159,12 @@ public class MetricsServiceImplTest {
|
|||||||
Mockito.doReturn("fakeName").when(listVMsUsageHistoryCmdMock).getName();
|
Mockito.doReturn("fakeName").when(listVMsUsageHistoryCmdMock).getName();
|
||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword();
|
||||||
|
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture());
|
||||||
Assert.assertEquals("displayName", stringCaptor1.getValue());
|
Assert.assertEquals("displayName", stringCaptor1.getValue());
|
||||||
Assert.assertEquals("%fakeName%", objectArrayCaptor.getValue()[0]);
|
Assert.assertEquals("%fakeName%", objectArrayCaptor.getValue()[0]);
|
||||||
Assert.assertEquals(expectedVmListAndCounter, result);
|
Assert.assertEquals(expectedVmListAndCounter, result);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -222,21 +177,16 @@ public class MetricsServiceImplTest {
|
|||||||
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName();
|
||||||
Mockito.doReturn("fakeKeyword").when(listVMsUsageHistoryCmdMock).getKeyword();
|
Mockito.doReturn("fakeKeyword").when(listVMsUsageHistoryCmdMock).getKeyword();
|
||||||
|
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Mockito.verify(scMock, Mockito.times(2)).addOr(stringCaptor1.capture(), opCaptor.capture(), objectArrayCaptor.capture());
|
Mockito.verify(scMock, Mockito.times(2)).addOr(stringCaptor1.capture(), opCaptor.capture(), objectArrayCaptor.capture());
|
||||||
List<String> conditions = stringCaptor1.getAllValues();
|
List<String> conditions = stringCaptor1.getAllValues();
|
||||||
List<Object[]> params = objectArrayCaptor.getAllValues();
|
List<Object[]> params = objectArrayCaptor.getAllValues();
|
||||||
Assert.assertEquals("displayName", conditions.get(0));
|
Assert.assertEquals("displayName", conditions.get(0));
|
||||||
Assert.assertEquals("state", conditions.get(1));
|
Assert.assertEquals("state", conditions.get(1));
|
||||||
Assert.assertEquals("%fakeKeyword%", params.get(0)[0]);
|
Assert.assertEquals("%fakeKeyword%", params.get(0)[0]);
|
||||||
Assert.assertEquals("fakeKeyword", params.get(1)[0]);
|
Assert.assertEquals("fakeKeyword", params.get(1)[0]);
|
||||||
Assert.assertEquals(expectedVmListAndCounter, result);
|
Assert.assertEquals(expectedVmListAndCounter, result);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -367,57 +317,4 @@ public class MetricsServiceImplTest {
|
|||||||
|
|
||||||
spy.createStatsResponse(Arrays.asList(vmStatsVOMock));
|
spy.createStatsResponse(Arrays.asList(vmStatsVOMock));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void searchForVolumesInternalWithValidParameters() {
|
|
||||||
Mockito.doReturn(null).when(listVolumesUsageHistoryCmdMock).getId();
|
|
||||||
Mockito.doReturn(Arrays.asList(1L, 2L)).when(listVolumesUsageHistoryCmdMock).getIds();
|
|
||||||
Mockito.doReturn("volumeName").when(listVolumesUsageHistoryCmdMock).getName();
|
|
||||||
Mockito.doReturn("keyword").when(listVolumesUsageHistoryCmdMock).getKeyword();
|
|
||||||
Mockito.doReturn(volumeSearchBuilderMock).when(volumeDao).createSearchBuilder();
|
|
||||||
Mockito.doReturn(volumeVOMock).when(volumeSearchBuilderMock).entity();
|
|
||||||
SearchBuilder vmSearchBuilderMock = Mockito.mock(SearchBuilder.class);
|
|
||||||
Mockito.doReturn(vmSearchBuilderMock).when(userVmDaoMock).createSearchBuilder();
|
|
||||||
Mockito.doReturn(userVmVOMock).when(vmSearchBuilderMock).entity();
|
|
||||||
Mockito.doReturn(volumeSearchCriteriaMock).when(volumeSearchBuilderMock).create();
|
|
||||||
Mockito.doReturn(volumeSearchCriteriaMock).when(volumeDao).createSearchCriteria();
|
|
||||||
Mockito.doReturn(new Pair<>(Arrays.asList(volumeVOMock), 1)).when(volumeDao).searchAndCount(Mockito.any(), Mockito.any());
|
|
||||||
Mockito.doReturn(Arrays.asList(volumeVOMock)).when(volumeDao).listByIds(Mockito.anyList());
|
|
||||||
|
|
||||||
|
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Pair<List<VolumeVO>, Integer> result = spy.searchForVolumesInternal(listVolumesUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Assert.assertNotNull(result);
|
|
||||||
Assert.assertEquals(1, result.second().intValue());
|
|
||||||
Assert.assertEquals(volumeVOMock, result.first().get(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void searchForVolumesInternalWithValidParametersNoItem() {
|
|
||||||
Mockito.doReturn(1L).when(listVolumesUsageHistoryCmdMock).getId();
|
|
||||||
Mockito.doReturn(volumeSearchBuilderMock).when(volumeDao).createSearchBuilder();
|
|
||||||
Mockito.doReturn(volumeVOMock).when(volumeSearchBuilderMock).entity();
|
|
||||||
Mockito.doReturn(volumeSearchCriteriaMock).when(volumeSearchBuilderMock).create();
|
|
||||||
Mockito.doReturn(new Pair<>(Collections.emptyList(), 0)).when(volumeDao).searchAndCount(Mockito.any(), Mockito.any());
|
|
||||||
|
|
||||||
|
|
||||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
|
||||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
|
||||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
|
||||||
Mockito.when(callContextMock.getCallingAccount()).thenReturn(mockAccount);
|
|
||||||
Mockito.when(callContextMock.getCallingAccountId()).thenReturn(1L);
|
|
||||||
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(true);
|
|
||||||
Mockito.when(mockAccount.getType()).thenReturn(Account.Type.ADMIN);
|
|
||||||
Pair<List<VolumeVO>, Integer> result = spy.searchForVolumesInternal(listVolumesUsageHistoryCmdMock);
|
|
||||||
|
|
||||||
Assert.assertNotNull(result);
|
|
||||||
Assert.assertEquals(0, result.second().intValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -448,8 +448,8 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl extends BasePrimaryDataStor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancelMaintain(DataStore store) {
|
public boolean cancelMaintain(DataStore store) {
|
||||||
dataStoreHelper.cancelMaintain(store);
|
|
||||||
storagePoolAutmation.cancelMaintain(store);
|
storagePoolAutmation.cancelMaintain(store);
|
||||||
|
dataStoreHelper.cancelMaintain(store);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +500,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl extends BasePrimaryDataStor
|
|||||||
@Override
|
@Override
|
||||||
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
|
||||||
DataStore dataStore = dataStoreHelper.attachHost(store, scope, existingInfo);
|
DataStore dataStore = dataStoreHelper.attachHost(store, scope, existingInfo);
|
||||||
if (existingInfo.getCapacityBytes() == 0) {
|
if(existingInfo.getCapacityBytes() == 0){
|
||||||
try {
|
try {
|
||||||
storageMgr.connectHostToSharedPool(hostDao.findById(scope.getScopeId()), dataStore.getId());
|
storageMgr.connectHostToSharedPool(hostDao.findById(scope.getScopeId()), dataStore.getId());
|
||||||
} catch (StorageUnavailableException ex) {
|
} catch (StorageUnavailableException ex) {
|
||||||
|
|||||||
@ -5,12 +5,6 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [2025-10-03]
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Revert qcow2 snapshot now use sparse/discard options to convert on thin devices.
|
|
||||||
|
|
||||||
## [2025-08-05]
|
## [2025-08-05]
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@ -26,39 +26,24 @@ import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
|
|||||||
import com.cloud.resource.CommandWrapper;
|
import com.cloud.resource.CommandWrapper;
|
||||||
import com.cloud.resource.ResourceWrapper;
|
import com.cloud.resource.ResourceWrapper;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.script.Script;
|
|
||||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||||
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
|
||||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImgFile;
|
import org.apache.cloudstack.utils.qemu.QemuImgFile;
|
||||||
import org.joda.time.Duration;
|
|
||||||
import org.libvirt.LibvirtException;
|
import org.libvirt.LibvirtException;
|
||||||
|
|
||||||
@ResourceWrapper(handles = LinstorRevertBackupSnapshotCommand.class)
|
@ResourceWrapper(handles = LinstorRevertBackupSnapshotCommand.class)
|
||||||
public final class LinstorRevertBackupSnapshotCommandWrapper
|
public final class LinstorRevertBackupSnapshotCommandWrapper
|
||||||
extends CommandWrapper<LinstorRevertBackupSnapshotCommand, CopyCmdAnswer, LibvirtComputingResource>
|
extends CommandWrapper<LinstorRevertBackupSnapshotCommand, CopyCmdAnswer, LibvirtComputingResource>
|
||||||
{
|
{
|
||||||
|
private void convertQCow2ToRAW(final String srcPath, final String dstPath, int waitMilliSeconds)
|
||||||
private void convertQCow2ToRAW(
|
|
||||||
KVMStoragePool pool, final String srcPath, final String dstUuid, int waitMilliSeconds)
|
|
||||||
throws LibvirtException, QemuImgException
|
throws LibvirtException, QemuImgException
|
||||||
{
|
{
|
||||||
final String dstPath = pool.getPhysicalDisk(dstUuid).getPath();
|
|
||||||
final QemuImgFile srcQemuFile = new QemuImgFile(
|
final QemuImgFile srcQemuFile = new QemuImgFile(
|
||||||
srcPath, QemuImg.PhysicalDiskFormat.QCOW2);
|
srcPath, QemuImg.PhysicalDiskFormat.QCOW2);
|
||||||
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(pool, LinstorUtil.RSC_PREFIX + dstUuid);
|
final QemuImg qemu = new QemuImg(waitMilliSeconds);
|
||||||
if (zeroedDevice)
|
|
||||||
{
|
|
||||||
// blockdiscard the device to ensure the device is filled with zeroes
|
|
||||||
Script blkDiscardScript = new Script("blkdiscard", Duration.millis(waitMilliSeconds));
|
|
||||||
blkDiscardScript.add("-f");
|
|
||||||
blkDiscardScript.add(dstPath);
|
|
||||||
blkDiscardScript.execute();
|
|
||||||
}
|
|
||||||
final QemuImg qemu = new QemuImg(waitMilliSeconds, zeroedDevice, true);
|
|
||||||
final QemuImgFile dstFile = new QemuImgFile(dstPath, QemuImg.PhysicalDiskFormat.RAW);
|
final QemuImgFile dstFile = new QemuImgFile(dstPath, QemuImg.PhysicalDiskFormat.RAW);
|
||||||
qemu.convert(srcQemuFile, dstFile);
|
qemu.convert(srcQemuFile, dstFile);
|
||||||
}
|
}
|
||||||
@ -85,9 +70,8 @@ public final class LinstorRevertBackupSnapshotCommandWrapper
|
|||||||
srcDataStore.getUrl() + File.separator + srcFile.getParent());
|
srcDataStore.getUrl() + File.separator + srcFile.getParent());
|
||||||
|
|
||||||
convertQCow2ToRAW(
|
convertQCow2ToRAW(
|
||||||
linstorPool,
|
|
||||||
secondaryPool.getLocalPath() + File.separator + srcFile.getName(),
|
secondaryPool.getLocalPath() + File.separator + srcFile.getName(),
|
||||||
dst.getPath(),
|
linstorPool.getPhysicalDisk(dst.getPath()).getPath(),
|
||||||
cmd.getWaitInMillSeconds());
|
cmd.getWaitInMillSeconds());
|
||||||
|
|
||||||
final VolumeObjectTO dstVolume = new VolumeObjectTO();
|
final VolumeObjectTO dstVolume = new VolumeObjectTO();
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import javax.annotation.Nonnull;
|
|||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.script.Script;
|
import com.cloud.utils.script.Script;
|
||||||
|
|
||||||
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
||||||
@ -56,6 +57,7 @@ import com.linbit.linstor.api.model.ResourceGroupSpawn;
|
|||||||
import com.linbit.linstor.api.model.ResourceMakeAvailable;
|
import com.linbit.linstor.api.model.ResourceMakeAvailable;
|
||||||
import com.linbit.linstor.api.model.ResourceWithVolumes;
|
import com.linbit.linstor.api.model.ResourceWithVolumes;
|
||||||
import com.linbit.linstor.api.model.StoragePool;
|
import com.linbit.linstor.api.model.StoragePool;
|
||||||
|
import com.linbit.linstor.api.model.Volume;
|
||||||
import com.linbit.linstor.api.model.VolumeDefinition;
|
import com.linbit.linstor.api.model.VolumeDefinition;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -571,6 +573,40 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
return copyPhysicalDisk(disk, name, destPool, timeout, null, null, null);
|
return copyPhysicalDisk(disk, name, destPool, timeout, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all diskful resource are on a zeroed block device.
|
||||||
|
* @param destPool Linstor pool to use
|
||||||
|
* @param resName Linstor resource name
|
||||||
|
* @return true if all resources are on a provider with zeroed blocks.
|
||||||
|
*/
|
||||||
|
private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resName) {
|
||||||
|
final DevelopersApi api = getLinstorAPI(destPool);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<ResourceWithVolumes> resWithVols = api.viewResources(
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.singletonList(resName),
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList(),
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (resWithVols != null) {
|
||||||
|
return resWithVols.stream()
|
||||||
|
.allMatch(res -> {
|
||||||
|
Volume vol0 = res.getVolumes().get(0);
|
||||||
|
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
|
||||||
|
vol0.getProviderKind() == ProviderKind.ZFS ||
|
||||||
|
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
|
||||||
|
vol0.getProviderKind() == ProviderKind.DISKLESS);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} catch (ApiException apiExc) {
|
||||||
|
logger.error(apiExc.getMessage());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
|
* Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
|
||||||
* The initial systemvm template resource isn't created on the management server, but
|
* The initial systemvm template resource isn't created on the management server, but
|
||||||
@ -641,7 +677,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
destFile.setFormat(dstDisk.getFormat());
|
destFile.setFormat(dstDisk.getFormat());
|
||||||
destFile.setSize(disk.getVirtualSize());
|
destFile.setSize(disk.getVirtualSize());
|
||||||
|
|
||||||
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
|
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
|
||||||
try {
|
try {
|
||||||
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
|
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
|
||||||
qemu.convert(srcFile, destFile);
|
qemu.convert(srcFile, destFile);
|
||||||
|
|||||||
@ -42,7 +42,6 @@ import java.util.Map;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -432,37 +431,4 @@ public class LinstorUtil {
|
|||||||
public static boolean isRscDiskless(ResourceWithVolumes rsc) {
|
public static boolean isRscDiskless(ResourceWithVolumes rsc) {
|
||||||
return rsc.getFlags() != null && rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS);
|
return rsc.getFlags() != null && rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if all diskful resource are on a zeroed block device.
|
|
||||||
* @param pool Linstor pool to use
|
|
||||||
* @param resName Linstor resource name
|
|
||||||
* @return true if all resources are on a provider with zeroed blocks.
|
|
||||||
*/
|
|
||||||
public static boolean resourceSupportZeroBlocks(KVMStoragePool pool, String resName) {
|
|
||||||
final DevelopersApi api = getLinstorAPI(pool.getSourceHost());
|
|
||||||
try {
|
|
||||||
List<ResourceWithVolumes> resWithVols = api.viewResources(
|
|
||||||
Collections.emptyList(),
|
|
||||||
Collections.singletonList(resName),
|
|
||||||
Collections.emptyList(),
|
|
||||||
Collections.emptyList(),
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
if (resWithVols != null) {
|
|
||||||
return resWithVols.stream()
|
|
||||||
.allMatch(res -> {
|
|
||||||
Volume vol0 = res.getVolumes().get(0);
|
|
||||||
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
|
|
||||||
vol0.getProviderKind() == ProviderKind.ZFS ||
|
|
||||||
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
|
|
||||||
vol0.getProviderKind() == ProviderKind.DISKLESS);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
} catch (ApiException apiExc) {
|
|
||||||
LOGGER.error(apiExc.getMessage());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@ -158,7 +158,7 @@
|
|||||||
<cs.jakarta.xml.bind.version>2.3.3</cs.jakarta.xml.bind.version>
|
<cs.jakarta.xml.bind.version>2.3.3</cs.jakarta.xml.bind.version>
|
||||||
<cs.jaxws.version>2.3.7</cs.jaxws.version>
|
<cs.jaxws.version>2.3.7</cs.jaxws.version>
|
||||||
<cs.jersey-client.version>2.26</cs.jersey-client.version>
|
<cs.jersey-client.version>2.26</cs.jersey-client.version>
|
||||||
<cs.jetty.version>9.4.58.v20250814</cs.jetty.version>
|
<cs.jetty.version>9.4.51.v20230217</cs.jetty.version>
|
||||||
<cs.jetty-maven-plugin.version>9.4.27.v20200227</cs.jetty-maven-plugin.version>
|
<cs.jetty-maven-plugin.version>9.4.27.v20200227</cs.jetty-maven-plugin.version>
|
||||||
<cs.jna.version>5.5.0</cs.jna.version>
|
<cs.jna.version>5.5.0</cs.jna.version>
|
||||||
<cs.joda-time.version>2.12.5</cs.joda-time.version>
|
<cs.joda-time.version>2.12.5</cs.joda-time.version>
|
||||||
|
|||||||
@ -68,14 +68,14 @@ class configFileOps:
|
|||||||
for entry in self.entries:
|
for entry in self.entries:
|
||||||
if entry.op == "add":
|
if entry.op == "add":
|
||||||
if entry.separator == "=":
|
if entry.separator == "=":
|
||||||
matchString = r"^\ *" + entry.name + ".*"
|
matchString = "^\ *" + entry.name + ".*"
|
||||||
elif entry.separator == " ":
|
elif entry.separator == " ":
|
||||||
matchString = r"^\ *" + entry.name + r"\ *" + entry.value
|
matchString = "^\ *" + entry.name + "\ *" + entry.value
|
||||||
else:
|
else:
|
||||||
if entry.separator == "=":
|
if entry.separator == "=":
|
||||||
matchString = r"^\ *" + entry.name + r"\ *=\ *" + entry.value
|
matchString = "^\ *" + entry.name + "\ *=\ *" + entry.value
|
||||||
else:
|
else:
|
||||||
matchString = r"^\ *" + entry.name + r"\ *" + entry.value
|
matchString = "^\ *" + entry.name + "\ *" + entry.value
|
||||||
|
|
||||||
match = re.match(matchString, line)
|
match = re.match(matchString, line)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
|
|||||||
@ -45,11 +45,8 @@ class networkConfig:
|
|||||||
if not cmd.isSuccess():
|
if not cmd.isSuccess():
|
||||||
logging.debug("Failed to get default route")
|
logging.debug("Failed to get default route")
|
||||||
raise CloudRuntimeException("Failed to get default route")
|
raise CloudRuntimeException("Failed to get default route")
|
||||||
output = cmd.getStdout().strip()
|
|
||||||
result = output.split(" ")
|
result = cmd.getStdout().split(" ")
|
||||||
if len(result) < 2:
|
|
||||||
logging.debug("Output for the default route incomplete: %s. It should have been '<GATEWAY> <DEVICE>'" % output)
|
|
||||||
raise CloudRuntimeException("Output for the default route incomplete")
|
|
||||||
gateway = result[0]
|
gateway = result[0]
|
||||||
dev = result[1]
|
dev = result[1]
|
||||||
|
|
||||||
@ -153,10 +150,10 @@ class networkConfig:
|
|||||||
if line.find("HWaddr") != -1:
|
if line.find("HWaddr") != -1:
|
||||||
macAddr = line.split("HWaddr ")[1].strip(" ")
|
macAddr = line.split("HWaddr ")[1].strip(" ")
|
||||||
elif line.find("inet ") != -1:
|
elif line.find("inet ") != -1:
|
||||||
m = re.search(r"addr:([^\s]+)\s*Bcast:([^\s]+)\s*Mask:([^\s]+)", line)
|
m = re.search("addr:(.*)\ *Bcast:(.*)\ *Mask:(.*)", line)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
ipAddr = m.group(1).strip()
|
ipAddr = m.group(1).rstrip(" ")
|
||||||
netmask = m.group(3).strip()
|
netmask = m.group(3).rstrip(" ")
|
||||||
|
|
||||||
if networkConfig.isBridgePort(dev):
|
if networkConfig.isBridgePort(dev):
|
||||||
type = "brport"
|
type = "brport"
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class bash:
|
|||||||
return self.stdout.decode('utf-8').strip('\n')
|
return self.stdout.decode('utf-8').strip('\n')
|
||||||
|
|
||||||
def getLines(self):
|
def getLines(self):
|
||||||
return self.stdout.decode('utf-8').strip('\n').split('\n')
|
return self.stdout.decode('utf-8').strip('\n')
|
||||||
|
|
||||||
def getStderr(self):
|
def getStderr(self):
|
||||||
return self.stderr.decode('utf-8').strip('\n')
|
return self.stderr.decode('utf-8').strip('\n')
|
||||||
|
|||||||
@ -5335,7 +5335,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
|
|
||||||
//Validation - 1.3
|
//Validation - 1.3
|
||||||
if (resourceIdStr != null) {
|
if (resourceIdStr != null) {
|
||||||
resourceId = resourceManagerUtil.getResourceId(resourceIdStr, resourceType, true);
|
resourceId = resourceManagerUtil.getResourceId(resourceIdStr, resourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<? extends ResourceDetail> detailList = new ArrayList<>();
|
List<? extends ResourceDetail> detailList = new ArrayList<>();
|
||||||
|
|||||||
@ -483,8 +483,6 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
|
|||||||
throw new InvalidParameterValueException("Cannot create Network ACL Item. ACL Id or network Id is required");
|
throw new InvalidParameterValueException("Cannot create Network ACL Item. ACL Id or network Id is required");
|
||||||
}
|
}
|
||||||
Network network = networkModel.getNetwork(createNetworkACLCmd.getNetworkId());
|
Network network = networkModel.getNetwork(createNetworkACLCmd.getNetworkId());
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
|
||||||
_accountMgr.checkAccess(caller, null, true, network);
|
|
||||||
if (network.getVpcId() == null) {
|
if (network.getVpcId() == null) {
|
||||||
throw new InvalidParameterValueException("Network: " + network.getUuid() + " does not belong to VPC");
|
throw new InvalidParameterValueException("Network: " + network.getUuid() + " does not belong to VPC");
|
||||||
}
|
}
|
||||||
@ -746,7 +744,6 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
|
|||||||
|
|
||||||
if (networkId != null) {
|
if (networkId != null) {
|
||||||
final Network network = _networkDao.findById(networkId);
|
final Network network = _networkDao.findById(networkId);
|
||||||
_accountMgr.checkAccess(caller, null, true, network);
|
|
||||||
aclId = network.getNetworkACLId();
|
aclId = network.getNetworkACLId();
|
||||||
if (aclId == null) {
|
if (aclId == null) {
|
||||||
// No aclId associated with the network.
|
// No aclId associated with the network.
|
||||||
|
|||||||
@ -154,7 +154,6 @@ import com.cloud.org.Cluster;
|
|||||||
import com.cloud.org.Grouping;
|
import com.cloud.org.Grouping;
|
||||||
import com.cloud.org.Managed;
|
import com.cloud.org.Managed;
|
||||||
import com.cloud.serializer.GsonHelper;
|
import com.cloud.serializer.GsonHelper;
|
||||||
import com.cloud.server.ManagementService;
|
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.service.dao.ServiceOfferingDao;
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||||
@ -272,8 +271,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
private ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
|
private ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
|
||||||
@Inject
|
@Inject
|
||||||
private UserVmManager userVmManager;
|
private UserVmManager userVmManager;
|
||||||
@Inject
|
|
||||||
ManagementService managementService;
|
|
||||||
|
|
||||||
private List<? extends Discoverer> _discoverers;
|
private List<? extends Discoverer> _discoverers;
|
||||||
|
|
||||||
@ -1939,9 +1936,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
|
public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
|
||||||
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
|
|
||||||
Boolean.TRUE.equals(cmd.getIsTagARule()));
|
|
||||||
|
|
||||||
return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
|
return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
|
||||||
cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getIsTagARule(), cmd.getAnnotation(), false);
|
cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getIsTagARule(), cmd.getAnnotation(), false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1040,8 +1040,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
|
|
||||||
protected List<DeploymentPlanner> _planners;
|
protected List<DeploymentPlanner> _planners;
|
||||||
|
|
||||||
private boolean jsInterpretationEnabled = false;
|
|
||||||
|
|
||||||
private final List<HypervisorType> supportedHypervisors = new ArrayList<>();
|
private final List<HypervisorType> supportedHypervisors = new ArrayList<>();
|
||||||
|
|
||||||
public List<DeploymentPlanner> getPlanners() {
|
public List<DeploymentPlanner> getPlanners() {
|
||||||
@ -1128,8 +1126,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
supportedHypervisors.add(HypervisorType.KVM);
|
supportedHypervisors.add(HypervisorType.KVM);
|
||||||
supportedHypervisors.add(HypervisorType.XenServer);
|
supportedHypervisors.add(HypervisorType.XenServer);
|
||||||
|
|
||||||
jsInterpretationEnabled = JsInterpretationEnabled.value();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4026,10 +4022,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
cmdList.add(ListGuestVlansCmd.class);
|
cmdList.add(ListGuestVlansCmd.class);
|
||||||
cmdList.add(AssignVolumeCmd.class);
|
cmdList.add(AssignVolumeCmd.class);
|
||||||
cmdList.add(ListSecondaryStorageSelectorsCmd.class);
|
cmdList.add(ListSecondaryStorageSelectorsCmd.class);
|
||||||
if (jsInterpretationEnabled) {
|
cmdList.add(CreateSecondaryStorageSelectorCmd.class);
|
||||||
cmdList.add(CreateSecondaryStorageSelectorCmd.class);
|
cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
|
||||||
cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
|
|
||||||
}
|
|
||||||
cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
|
cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
|
||||||
cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
|
cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
|
||||||
|
|
||||||
@ -4072,8 +4066,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {vmPasswordLength, sshKeyLength, humanReadableSizes, customCsIdentifier,
|
return new ConfigKey<?>[] {vmPasswordLength, sshKeyLength, humanReadableSizes, customCsIdentifier};
|
||||||
JsInterpretationEnabled};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class EventPurgeTask extends ManagedContextRunnable {
|
protected class EventPurgeTask extends ManagedContextRunnable {
|
||||||
@ -4542,8 +4535,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
}
|
}
|
||||||
capabilities.put(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT, fsVmMinCpu);
|
capabilities.put(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT, fsVmMinCpu);
|
||||||
capabilities.put(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE, fsVmMinRam);
|
capabilities.put(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE, fsVmMinRam);
|
||||||
capabilities.put(ApiConstants.ADDITONAL_CONFIG_ENABLED, UserVmManager.EnableAdditionalVmConfig.valueIn(caller.getId()));
|
|
||||||
|
|
||||||
|
|
||||||
return capabilities;
|
return capabilities;
|
||||||
}
|
}
|
||||||
@ -5530,13 +5521,4 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
_lockControllerListener = lockControllerListener;
|
_lockControllerListener = lockControllerListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkJsInterpretationAllowedIfNeededForParameterValue(String paramName, boolean paramValue) {
|
|
||||||
if (!paramValue || jsInterpretationEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new InvalidParameterValueException(String.format(
|
|
||||||
"The parameter %s cannot be set to true as JS interpretation is disabled",
|
|
||||||
paramName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,7 +213,6 @@ import com.cloud.org.Grouping.AllocationState;
|
|||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
import com.cloud.server.ConfigurationServer;
|
import com.cloud.server.ConfigurationServer;
|
||||||
import com.cloud.server.ManagementServer;
|
import com.cloud.server.ManagementServer;
|
||||||
import com.cloud.server.ManagementService;
|
|
||||||
import com.cloud.server.StatsCollector;
|
import com.cloud.server.StatsCollector;
|
||||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
@ -399,8 +398,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
ConfigurationDao configurationDao;
|
ConfigurationDao configurationDao;
|
||||||
@Inject
|
@Inject
|
||||||
private ImageStoreDetailsUtil imageStoreDetailsUtil;
|
private ImageStoreDetailsUtil imageStoreDetailsUtil;
|
||||||
@Inject
|
|
||||||
ManagementService managementService;
|
|
||||||
|
|
||||||
protected List<StoragePoolDiscoverer> _discoverers;
|
protected List<StoragePoolDiscoverer> _discoverers;
|
||||||
|
|
||||||
@ -1018,9 +1015,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
throw new PermissionDeniedException(String.format("Cannot perform this operation, Zone is currently disabled: %s", zone));
|
throw new PermissionDeniedException(String.format("Cannot perform this operation, Zone is currently disabled: %s", zone));
|
||||||
}
|
}
|
||||||
|
|
||||||
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
|
|
||||||
Boolean.TRUE.equals(cmd.isTagARule()));
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.put("zoneId", zone.getId());
|
params.put("zoneId", zone.getId());
|
||||||
params.put("clusterId", clusterId);
|
params.put("clusterId", clusterId);
|
||||||
@ -1203,9 +1197,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
// Input validation
|
// Input validation
|
||||||
Long id = cmd.getId();
|
Long id = cmd.getId();
|
||||||
|
|
||||||
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
|
|
||||||
Boolean.TRUE.equals(cmd.isTagARule()));
|
|
||||||
|
|
||||||
StoragePoolVO pool = _storagePoolDao.findById(id);
|
StoragePoolVO pool = _storagePoolDao.findById(id);
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
throw new IllegalArgumentException("Unable to find storage pool with ID: " + id);
|
throw new IllegalArgumentException("Unable to find storage pool with ID: " + id);
|
||||||
@ -2697,8 +2688,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void updateStoragePoolHostVOAndBytes(StoragePool pool, long hostId, ModifyStoragePoolAnswer mspAnswer) {
|
||||||
public void updateStoragePoolHostVOAndBytes(StoragePool pool, long hostId, ModifyStoragePoolAnswer mspAnswer) {
|
|
||||||
StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(pool.getId(), hostId);
|
StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(pool.getId(), hostId);
|
||||||
if (poolHost == null) {
|
if (poolHost == null) {
|
||||||
poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
|
poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
|
||||||
@ -2708,10 +2698,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
|
StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
|
||||||
if (!Storage.StoragePoolType.StorPool.equals(poolVO.getPoolType())) {
|
poolVO.setUsedBytes(mspAnswer.getPoolInfo().getCapacityBytes() - mspAnswer.getPoolInfo().getAvailableBytes());
|
||||||
poolVO.setUsedBytes(mspAnswer.getPoolInfo().getCapacityBytes() - mspAnswer.getPoolInfo().getAvailableBytes());
|
poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes());
|
||||||
poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
_storagePoolDao.update(pool.getId(), poolVO);
|
_storagePoolDao.update(pool.getId(), poolVO);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -346,7 +346,6 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation {
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("ModifyStoragePool add succeeded");
|
logger.debug("ModifyStoragePool add succeeded");
|
||||||
}
|
}
|
||||||
storageManager.updateStoragePoolHostVOAndBytes(pool, host.getId(), (ModifyStoragePoolAnswer) answer);
|
|
||||||
if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) {
|
if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) {
|
||||||
logger.debug("Started synchronising datastore cluster storage pool {} with vCenter", pool);
|
logger.debug("Started synchronising datastore cluster storage pool {} with vCenter", pool);
|
||||||
storageManager.syncDatastoreClusterStoragePool(pool.getId(), ((ModifyStoragePoolAnswer) answer).getDatastoreClusterChildren(), host.getId());
|
storageManager.syncDatastoreClusterStoragePool(pool.getId(), ((ModifyStoragePoolAnswer) answer).getDatastoreClusterChildren(), host.getId());
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
|
||||||
import org.apache.cloudstack.api.Identity;
|
import org.apache.cloudstack.api.Identity;
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
@ -129,11 +128,6 @@ public class ResourceManagerUtilImpl implements ResourceManagerUtil {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType) {
|
public long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType) {
|
||||||
return getResourceId(resourceId, resourceType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getResourceId(String resourceId, ResourceTag.ResourceObjectType resourceType, boolean checkAccess) {
|
|
||||||
Class<?> clazz = s_typeMap.get(resourceType);
|
Class<?> clazz = s_typeMap.get(resourceType);
|
||||||
Object entity = entityMgr.findByUuid(clazz, resourceId);
|
Object entity = entityMgr.findByUuid(clazz, resourceId);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
@ -144,11 +138,6 @@ public class ResourceManagerUtilImpl implements ResourceManagerUtil {
|
|||||||
}
|
}
|
||||||
entity = entityMgr.findById(clazz, resourceId);
|
entity = entityMgr.findById(clazz, resourceId);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
if (checkAccess && entity instanceof ControlledEntity) {
|
|
||||||
ControlledEntity controlledEntity = (ControlledEntity)entity;
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
|
||||||
accountMgr.checkAccess(caller, null, false, controlledEntity);
|
|
||||||
}
|
|
||||||
return ((InternalIdentity)entity).getId();
|
return ((InternalIdentity)entity).getId();
|
||||||
}
|
}
|
||||||
throw new InvalidParameterValueException("Unable to find resource by id " + resourceId + " and type " + resourceType);
|
throw new InvalidParameterValueException("Unable to find resource by id " + resourceId + " and type " + resourceType);
|
||||||
|
|||||||
@ -627,7 +627,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
|
|
||||||
boolean dataDiskDeletetionResult = true;
|
boolean dataDiskDeletetionResult = true;
|
||||||
List<VMTemplateVO> dataDiskTemplates = templateDao.listByParentTemplatetId(template.getId());
|
List<VMTemplateVO> dataDiskTemplates = templateDao.listByParentTemplatetId(template.getId());
|
||||||
if (CollectionUtils.isNotEmpty(dataDiskTemplates)) {
|
if (dataDiskTemplates != null && dataDiskTemplates.size() > 0) {
|
||||||
logger.info("Template: {} has Datadisk template(s) associated with it. Delete Datadisk templates before deleting the template", template);
|
logger.info("Template: {} has Datadisk template(s) associated with it. Delete Datadisk templates before deleting the template", template);
|
||||||
for (VMTemplateVO dataDiskTemplate : dataDiskTemplates) {
|
for (VMTemplateVO dataDiskTemplate : dataDiskTemplates) {
|
||||||
logger.info("Delete Datadisk template: {} from image store: {}", dataDiskTemplate, imageStore);
|
logger.info("Delete Datadisk template: {} from image store: {}", dataDiskTemplate, imageStore);
|
||||||
@ -693,9 +693,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
if (success) {
|
if (success) {
|
||||||
if ((imageStores != null && imageStores.size() > 1) && (profile.getZoneIdList() != null)) {
|
if ((imageStores != null && imageStores.size() > 1) && (profile.getZoneIdList() != null)) {
|
||||||
//if template is stored in more than one image stores, and the zone id is not null, then don't delete other templates.
|
//if template is stored in more than one image stores, and the zone id is not null, then don't delete other templates.
|
||||||
if (templateMgr.TemplateDeleteFromPrimaryStorage.value()) {
|
|
||||||
templateMgr.evictTemplateFromStoragePoolsForZones(template.getId(), profile.getZoneIdList());
|
|
||||||
}
|
|
||||||
return cleanupTemplate(template, success);
|
return cleanupTemplate(template, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +705,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
|
|
||||||
// find all eligible image stores for this template
|
// find all eligible image stores for this template
|
||||||
List<DataStore> iStores = templateMgr.getImageStoreByTemplate(template.getId(), null);
|
List<DataStore> iStores = templateMgr.getImageStoreByTemplate(template.getId(), null);
|
||||||
if (CollectionUtils.isEmpty(iStores)) {
|
if (iStores == null || iStores.size() == 0) {
|
||||||
// remove any references from template_zone_ref
|
// remove any references from template_zone_ref
|
||||||
List<VMTemplateZoneVO> templateZones = templateZoneDao.listByTemplateId(template.getId());
|
List<VMTemplateZoneVO> templateZones = templateZoneDao.listByTemplateId(template.getId());
|
||||||
if (templateZones != null) {
|
if (templateZones != null) {
|
||||||
@ -729,10 +726,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (templateMgr.TemplateDeleteFromPrimaryStorage.value()) {
|
|
||||||
templateMgr.evictTemplateFromStoragePoolsForZones(template.getId(), profile.getZoneIdList());
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove its related ACL permission
|
// remove its related ACL permission
|
||||||
Pair<Class<?>, Long> templateClassForId = new Pair<>(VirtualMachineTemplate.class, template.getId());
|
Pair<Class<?>, Long> templateClassForId = new Pair<>(VirtualMachineTemplate.class, template.getId());
|
||||||
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, templateClassForId);
|
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, templateClassForId);
|
||||||
|
|||||||
@ -1024,51 +1024,31 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
return adapter.delete(new TemplateProfile(userId, template, zoneId));
|
return adapter.delete(new TemplateProfile(userId, template, zoneId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean templateIsUnusedInPool(VMTemplateStoragePoolVO templatePoolVO) {
|
|
||||||
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
|
|
||||||
|
|
||||||
// If this is a routing template, consider it in use
|
|
||||||
if (template.getTemplateType() == TemplateType.SYSTEM) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the template is not yet downloaded to the pool, consider it in use
|
|
||||||
if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (template.getFormat() == ImageFormat.ISO || _volumeDao.isAnyVolumeActivelyUsingTemplateOnPool(template.getId(), templatePoolVO.getPoolId())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool) {
|
public List<VMTemplateStoragePoolVO> getUnusedTemplatesInPool(StoragePoolVO pool) {
|
||||||
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = new ArrayList<VMTemplateStoragePoolVO>();
|
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = new ArrayList<VMTemplateStoragePoolVO>();
|
||||||
List<VMTemplateStoragePoolVO> allTemplatesInPool = _tmpltPoolDao.listByPoolId(pool.getId());
|
List<VMTemplateStoragePoolVO> allTemplatesInPool = _tmpltPoolDao.listByPoolId(pool.getId());
|
||||||
|
|
||||||
for (VMTemplateStoragePoolVO templatePoolVO : allTemplatesInPool) {
|
for (VMTemplateStoragePoolVO templatePoolVO : allTemplatesInPool) {
|
||||||
if (templateIsUnusedInPool(templatePoolVO)) {
|
VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
|
||||||
|
|
||||||
|
// If this is a routing template, consider it in use
|
||||||
|
if (template.getTemplateType() == TemplateType.SYSTEM) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the template is not yet downloaded to the pool, consider it in
|
||||||
|
// use
|
||||||
|
if (templatePoolVO.getDownloadState() != Status.DOWNLOADED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (template.getFormat() != ImageFormat.ISO && !_volumeDao.isAnyVolumeActivelyUsingTemplateOnPool(template.getId(), pool.getId())) {
|
||||||
unusedTemplatesInPool.add(templatePoolVO);
|
unusedTemplatesInPool.add(templatePoolVO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return unusedTemplatesInPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
return unusedTemplatesInPool;
|
||||||
public void evictTemplateFromStoragePoolsForZones(Long templateId, List<Long> zoneIds) {
|
|
||||||
List<Long> poolIds = new ArrayList<>();
|
|
||||||
if (CollectionUtils.isNotEmpty(zoneIds)) {
|
|
||||||
List<StoragePoolVO> pools = _poolDao.listByDataCenterIds(zoneIds);
|
|
||||||
poolIds = pools.stream().map(StoragePoolVO::getId).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
List<VMTemplateStoragePoolVO> templateStoragePoolVOS = _tmpltPoolDao.listByPoolIdsAndTemplate(poolIds, templateId);
|
|
||||||
for (VMTemplateStoragePoolVO templateStoragePoolVO: templateStoragePoolVOS) {
|
|
||||||
if (templateIsUnusedInPool(templateStoragePoolVO)) {
|
|
||||||
evictTemplateFromStoragePool(templateStoragePoolVO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2388,10 +2368,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {AllowPublicUserTemplates,
|
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize, ValidateUrlIsResolvableBeforeRegisteringTemplate};
|
||||||
TemplatePreloaderPoolSize,
|
|
||||||
ValidateUrlIsResolvableBeforeRegisteringTemplate,
|
|
||||||
TemplateDeleteFromPrimaryStorage};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TemplateAdapter> getTemplateAdapters() {
|
public List<TemplateAdapter> getTemplateAdapters() {
|
||||||
|
|||||||
@ -2747,10 +2747,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
|||||||
logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone);
|
logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
Account callingAccount = getCurrentCallingAccount();
|
passwordPolicy.verifyIfPasswordCompliesWithPasswordPolicies(password, userName, getAccount(accountId).getDomainId());
|
||||||
if (callingAccount.getId() != Account.ACCOUNT_ID_SYSTEM) {
|
|
||||||
passwordPolicy.verifyIfPasswordCompliesWithPasswordPolicies(password, userName, getAccount(accountId).getDomainId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String encodedPassword = null;
|
String encodedPassword = null;
|
||||||
for (UserAuthenticator authenticator : _userPasswordEncoders) {
|
for (UserAuthenticator authenticator : _userPasswordEncoders) {
|
||||||
|
|||||||
@ -83,15 +83,6 @@ public interface UserVmManager extends UserVmService {
|
|||||||
"If set to true, tags specified in `resource.limit.host.tags` are also included in vm.strict.host.tags.",
|
"If set to true, tags specified in `resource.limit.host.tags` are also included in vm.strict.host.tags.",
|
||||||
true);
|
true);
|
||||||
|
|
||||||
ConfigKey<Boolean> EnableAdditionalVmConfig = new ConfigKey<>(
|
|
||||||
"Advanced",
|
|
||||||
Boolean.class,
|
|
||||||
"enable.additional.vm.configuration",
|
|
||||||
"false",
|
|
||||||
"allow additional arbitrary configuration to vm",
|
|
||||||
true,
|
|
||||||
ConfigKey.Scope.Account);
|
|
||||||
|
|
||||||
static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
|
static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
|
||||||
|
|
||||||
public static final String CKS_NODE = "cksnode";
|
public static final String CKS_NODE = "cksnode";
|
||||||
|
|||||||
@ -670,6 +670,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
private static final ConfigKey<Boolean> AllowDeployVmIfGivenHostFails = new ConfigKey<Boolean>("Advanced", Boolean.class, "allow.deploy.vm.if.deploy.on.given.host.fails", "false",
|
private static final ConfigKey<Boolean> AllowDeployVmIfGivenHostFails = new ConfigKey<Boolean>("Advanced", Boolean.class, "allow.deploy.vm.if.deploy.on.given.host.fails", "false",
|
||||||
"allow vm to deploy on different host if vm fails to deploy on the given host ", true);
|
"allow vm to deploy on different host if vm fails to deploy on the given host ", true);
|
||||||
|
|
||||||
|
private static final ConfigKey<Boolean> EnableAdditionalVmConfig = new ConfigKey<>("Advanced", Boolean.class,
|
||||||
|
"enable.additional.vm.configuration", "false", "allow additional arbitrary configuration to vm", true, ConfigKey.Scope.Account);
|
||||||
|
|
||||||
private static final ConfigKey<String> KvmAdditionalConfigAllowList = new ConfigKey<>(String.class,
|
private static final ConfigKey<String> KvmAdditionalConfigAllowList = new ConfigKey<>(String.class,
|
||||||
"allow.additional.vm.configuration.list.kvm", "Advanced", "", "Comma separated list of allowed additional configuration options.", true, ConfigKey.Scope.Account, null, null, EnableAdditionalVmConfig.key(), null, null, ConfigKey.Kind.CSV, null);
|
"allow.additional.vm.configuration.list.kvm", "Advanced", "", "Comma separated list of allowed additional configuration options.", true, ConfigKey.Scope.Account, null, null, EnableAdditionalVmConfig.key(), null, null, ConfigKey.Kind.CSV, null);
|
||||||
|
|
||||||
@ -753,7 +756,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
String networkCidr;
|
String networkCidr;
|
||||||
String macAddress;
|
String macAddress;
|
||||||
|
|
||||||
public VmIpAddrFetchThread(long vmId, String vmUuid, long nicId, String instanceName, boolean windows, Long hostId, String networkCidr, String macAddress) {
|
public VmIpAddrFetchThread(long vmId, long nicId, String instanceName, boolean windows, Long hostId, String networkCidr, String macAddress) {
|
||||||
this.vmId = vmId;
|
this.vmId = vmId;
|
||||||
this.vmUuid = vmUuid;
|
this.vmUuid = vmUuid;
|
||||||
this.nicId = nicId;
|
this.nicId = nicId;
|
||||||
@ -775,13 +778,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
Answer answer = _agentMgr.send(hostId, cmd);
|
Answer answer = _agentMgr.send(hostId, cmd);
|
||||||
if (answer.getResult()) {
|
if (answer.getResult()) {
|
||||||
String vmIp = answer.getDetails();
|
String vmIp = answer.getDetails();
|
||||||
if (vmIp == null) {
|
|
||||||
// we got a valid response and the NIC does not have an IP assigned, as such we will update the database with null
|
if (NetUtils.isValidIp4(vmIp)) {
|
||||||
if (nic.getIPv4Address() != null) {
|
|
||||||
nic.setIPv4Address(null);
|
|
||||||
_nicDao.update(nicId, nic);
|
|
||||||
}
|
|
||||||
} else if (NetUtils.isValidIp4(vmIp)) {
|
|
||||||
// set this vm ip addr in vm nic.
|
// set this vm ip addr in vm nic.
|
||||||
if (nic != null) {
|
if (nic != null) {
|
||||||
nic.setIPv4Address(vmIp);
|
nic.setIPv4Address(vmIp);
|
||||||
@ -796,8 +794,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// since no changes are being done, we should not decrement IP usage
|
//previously vm has ip and nic table has ip address. After vm restart or stop/start
|
||||||
decrementCount = false;
|
//if vm doesnot get the ip then set the ip in nic table to null
|
||||||
|
if (nic.getIPv4Address() != null) {
|
||||||
|
nic.setIPv4Address(null);
|
||||||
|
_nicDao.update(nicId, nic);
|
||||||
|
}
|
||||||
if (answer.getDetails() != null) {
|
if (answer.getDetails() != null) {
|
||||||
logger.debug("Failed to get vm ip for Vm [id: {}, uuid: {}, name: {}], details: {}",
|
logger.debug("Failed to get vm ip for Vm [id: {}, uuid: {}, name: {}], details: {}",
|
||||||
vmId, vmUuid, vmName, answer.getDetails());
|
vmId, vmUuid, vmName, answer.getDetails());
|
||||||
@ -2694,8 +2696,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(userVm);
|
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(userVm);
|
||||||
VirtualMachine vm = vmProfile.getVirtualMachine();
|
VirtualMachine vm = vmProfile.getVirtualMachine();
|
||||||
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
||||||
|
_vmIpFetchThreadExecutor.execute(new VmIpAddrFetchThread(vmId, nicId, vmInstance.getInstanceName(),
|
||||||
_vmIpFetchThreadExecutor.execute(new VmIpAddrFetchThread(vmId, vmInstance.getUuid(), nicId, vmInstance.getInstanceName(),
|
|
||||||
isWindows, vm.getHostId(), network.getCidr(), nicVo.getMacAddress()));
|
isWindows, vm.getHostId(), network.getCidr(), nicVo.getMacAddress()));
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6279,7 +6280,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
protected void persistExtraConfigVmware(String decodedUrl, UserVm vm) {
|
protected void persistExtraConfigVmware(String decodedUrl, UserVm vm) {
|
||||||
boolean isValidConfig = isValidKeyValuePair(decodedUrl);
|
boolean isValidConfig = isValidKeyValuePair(decodedUrl);
|
||||||
if (isValidConfig) {
|
if (isValidConfig) {
|
||||||
String[] extraConfigs = decodedUrl.split("\\r?\\n+");
|
String[] extraConfigs = decodedUrl.split("\\r?\\n");
|
||||||
for (String cfg : extraConfigs) {
|
for (String cfg : extraConfigs) {
|
||||||
// Validate cfg against unsupported operations set by admin here
|
// Validate cfg against unsupported operations set by admin here
|
||||||
String[] allowedKeyList = VmwareAdditionalConfigAllowList.value().split(",");
|
String[] allowedKeyList = VmwareAdditionalConfigAllowList.value().split(",");
|
||||||
@ -6307,7 +6308,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
protected void persistExtraConfigXenServer(String decodedUrl, UserVm vm) {
|
protected void persistExtraConfigXenServer(String decodedUrl, UserVm vm) {
|
||||||
boolean isValidConfig = isValidKeyValuePair(decodedUrl);
|
boolean isValidConfig = isValidKeyValuePair(decodedUrl);
|
||||||
if (isValidConfig) {
|
if (isValidConfig) {
|
||||||
String[] extraConfigs = decodedUrl.split("\\r?\\n+");
|
String[] extraConfigs = decodedUrl.split("\\r?\\n");
|
||||||
int i = 1;
|
int i = 1;
|
||||||
String extraConfigKey = ApiConstants.EXTRA_CONFIG + "-";
|
String extraConfigKey = ApiConstants.EXTRA_CONFIG + "-";
|
||||||
for (String cfg : extraConfigs) {
|
for (String cfg : extraConfigs) {
|
||||||
@ -6387,8 +6388,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
// validate config against denied cfg commands
|
// validate config against denied cfg commands
|
||||||
validateKvmExtraConfig(decodedUrl, vm.getAccountId());
|
validateKvmExtraConfig(decodedUrl, vm.getAccountId());
|
||||||
String[] extraConfigs = decodedUrl.split("\n\n");
|
String[] extraConfigs = decodedUrl.split("\n\n");
|
||||||
int i = 1;
|
|
||||||
for (String cfg : extraConfigs) {
|
for (String cfg : extraConfigs) {
|
||||||
|
int i = 1;
|
||||||
String[] cfgParts = cfg.split("\n");
|
String[] cfgParts = cfg.split("\n");
|
||||||
String extraConfigKey = ApiConstants.EXTRA_CONFIG;
|
String extraConfigKey = ApiConstants.EXTRA_CONFIG;
|
||||||
String extraConfigValue;
|
String extraConfigValue;
|
||||||
|
|||||||
@ -607,20 +607,10 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
|
protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
|
||||||
validateNetworkCidrSize(cidrSize);
|
validateNetworkCidrSize(ownerAccountId, cidrSize);
|
||||||
List<DataCenterIpv4GuestSubnetVO> subnets = getZoneSubnetsForAccount(ownerDomainId, ownerAccountId, zoneId);
|
List<DataCenterIpv4GuestSubnetVO> subnets = getZoneSubnetsForAccount(ownerDomainId, ownerAccountId, zoneId);
|
||||||
for (DataCenterIpv4GuestSubnetVO subnet : subnets) {
|
for (DataCenterIpv4GuestSubnetVO subnet : subnets) {
|
||||||
Ipv4GuestSubnetNetworkMap result = getIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnet);
|
Ipv4GuestSubnetNetworkMap result = getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnet);
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Boolean isAutoAllocationEnabled = RoutedIPv4NetworkCidrAutoAllocationEnabled.valueIn(ownerAccountId);
|
|
||||||
if (!Boolean.TRUE.equals(isAutoAllocationEnabled)) {
|
|
||||||
throw new InvalidParameterValueException("CIDR auto-allocation is disabled for this account");
|
|
||||||
}
|
|
||||||
for (DataCenterIpv4GuestSubnetVO subnet : subnets) {
|
|
||||||
Ipv4GuestSubnetNetworkMap result = createIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnet);
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -628,11 +618,11 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Ipv4GuestSubnetNetworkMap getIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
|
protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
|
||||||
return ipv4GuestSubnetNetworkMapDao.findFirstAvailable(subnet.getId(), cidrSize);
|
Ipv4GuestSubnetNetworkMap map = ipv4GuestSubnetNetworkMapDao.findFirstAvailable(subnet.getId(), cidrSize);
|
||||||
}
|
if (map != null) {
|
||||||
|
return map;
|
||||||
protected Ipv4GuestSubnetNetworkMap createIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
|
}
|
||||||
try {
|
try {
|
||||||
return createIpv4SubnetFromParentSubnet(subnet, cidrSize);
|
return createIpv4SubnetFromParentSubnet(subnet, cidrSize);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -641,14 +631,6 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
|
|
||||||
Ipv4GuestSubnetNetworkMap map = getIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnet);
|
|
||||||
if (map != null) {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
return createIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnet);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(String networkCidr, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
|
protected void getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(String networkCidr, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
|
||||||
Ipv4GuestSubnetNetworkMapVO subnetMap = ipv4GuestSubnetNetworkMapDao.findBySubnet(networkCidr);
|
Ipv4GuestSubnetNetworkMapVO subnetMap = ipv4GuestSubnetNetworkMapDao.findBySubnet(networkCidr);
|
||||||
if (subnetMap != null) {
|
if (subnetMap != null) {
|
||||||
@ -711,9 +693,13 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateNetworkCidrSize(Integer networkCidrSize) {
|
private void validateNetworkCidrSize(long accountId, Integer networkCidrSize) {
|
||||||
if (networkCidrSize == null) {
|
if (networkCidrSize == null) {
|
||||||
throw new InvalidParameterValueException("network/vpc CidrSize is null");
|
throw new CloudRuntimeException("network/vpc CidrSize is null");
|
||||||
|
}
|
||||||
|
Boolean isAutoAllocationEnabled = RoutedIPv4NetworkCidrAutoAllocationEnabled.valueIn(accountId);
|
||||||
|
if (!Boolean.TRUE.equals(isAutoAllocationEnabled)) {
|
||||||
|
throw new CloudRuntimeException("CIDR auto-allocation is disabled for this account");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,7 +755,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
// Allocate a subnet automatically
|
// Allocate a subnet automatically
|
||||||
String networkCidr = getFreeNetworkCidr(subnetsInFreeIpRanges, networkCidrSize);
|
String networkCidr = getFreeNetworkCidr(subnetsInFreeIpRanges, networkCidrSize);
|
||||||
if (networkCidr == null) {
|
if (networkCidr == null) {
|
||||||
throw new InvalidParameterValueException("Failed to automatically allocate a subnet with specified cidrsize");
|
throw new CloudRuntimeException("Failed to automatically allocate a subnet with specified cidrsize");
|
||||||
}
|
}
|
||||||
return networkCidr;
|
return networkCidr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,17 +55,6 @@ public interface UserPasswordResetManager {
|
|||||||
"Use auth in the SMTP server for sending emails for resetting password for ACS users",
|
"Use auth in the SMTP server for sending emails for resetting password for ACS users",
|
||||||
false, ConfigKey.Scope.Global);
|
false, ConfigKey.Scope.Global);
|
||||||
|
|
||||||
ConfigKey<Boolean> UserPasswordResetSMTPUseStartTLS = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED,
|
|
||||||
Boolean.class, "user.password.reset.smtp.useStartTLS", "false",
|
|
||||||
"If set to true and if we enable security via user.password.reset.smtp.useAuth, this will enable StartTLS to secure the connection.",
|
|
||||||
true,
|
|
||||||
ConfigKey.Scope.Global);
|
|
||||||
|
|
||||||
ConfigKey<String> UserPasswordResetSMTPEnabledSecurityProtocols = new ConfigKey<String>(ConfigKey.CATEGORY_ADVANCED,
|
|
||||||
String.class, "user.password.reset.smtp.enabledSecurityProtocols", "",
|
|
||||||
"White-space separated security protocols; ex: \"TLSv1 TLSv1.1\". Supported protocols: SSLv2Hello, SSLv3, TLSv1, TLSv1.1 and TLSv1.2",
|
|
||||||
true, ConfigKey.Kind.WhitespaceSeparatedListWithOptions, "SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2");
|
|
||||||
|
|
||||||
ConfigKey<String> UserPasswordResetSMTPUsername = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED,
|
ConfigKey<String> UserPasswordResetSMTPUsername = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED,
|
||||||
String.class, "user.password.reset.smtp.username", null,
|
String.class, "user.password.reset.smtp.username", null,
|
||||||
"Username for SMTP server for sending emails for resetting password for ACS users",
|
"Username for SMTP server for sending emails for resetting password for ACS users",
|
||||||
|
|||||||
@ -93,8 +93,6 @@ public class UserPasswordResetManagerImpl extends ManagerBase implements UserPas
|
|||||||
UserPasswordResetSMTPHost,
|
UserPasswordResetSMTPHost,
|
||||||
UserPasswordResetSMTPPort,
|
UserPasswordResetSMTPPort,
|
||||||
UserPasswordResetSMTPUseAuth,
|
UserPasswordResetSMTPUseAuth,
|
||||||
UserPasswordResetSMTPUseStartTLS,
|
|
||||||
UserPasswordResetSMTPEnabledSecurityProtocols,
|
|
||||||
UserPasswordResetSMTPUsername,
|
UserPasswordResetSMTPUsername,
|
||||||
UserPasswordResetSMTPPassword,
|
UserPasswordResetSMTPPassword,
|
||||||
PasswordResetMailTemplate
|
PasswordResetMailTemplate
|
||||||
@ -108,8 +106,6 @@ public class UserPasswordResetManagerImpl extends ManagerBase implements UserPas
|
|||||||
Boolean useAuth = UserPasswordResetSMTPUseAuth.value();
|
Boolean useAuth = UserPasswordResetSMTPUseAuth.value();
|
||||||
String username = UserPasswordResetSMTPUsername.value();
|
String username = UserPasswordResetSMTPUsername.value();
|
||||||
String password = UserPasswordResetSMTPPassword.value();
|
String password = UserPasswordResetSMTPPassword.value();
|
||||||
Boolean useStartTLS = UserPasswordResetSMTPUseStartTLS.value();
|
|
||||||
String enabledSecurityProtocols = UserPasswordResetSMTPEnabledSecurityProtocols.value();
|
|
||||||
|
|
||||||
if (!StringUtils.isEmpty(smtpHost) && smtpPort != null && smtpPort > 0) {
|
if (!StringUtils.isEmpty(smtpHost) && smtpPort != null && smtpPort > 0) {
|
||||||
String namespace = "password.reset.smtp";
|
String namespace = "password.reset.smtp";
|
||||||
@ -121,8 +117,6 @@ public class UserPasswordResetManagerImpl extends ManagerBase implements UserPas
|
|||||||
configs.put(getKey(namespace, SMTPMailSender.CONFIG_USE_AUTH), useAuth.toString());
|
configs.put(getKey(namespace, SMTPMailSender.CONFIG_USE_AUTH), useAuth.toString());
|
||||||
configs.put(getKey(namespace, SMTPMailSender.CONFIG_USERNAME), username);
|
configs.put(getKey(namespace, SMTPMailSender.CONFIG_USERNAME), username);
|
||||||
configs.put(getKey(namespace, SMTPMailSender.CONFIG_PASSWORD), password);
|
configs.put(getKey(namespace, SMTPMailSender.CONFIG_PASSWORD), password);
|
||||||
configs.put(getKey(namespace, SMTPMailSender.CONFIG_USE_STARTTLS), useStartTLS.toString());
|
|
||||||
configs.put(getKey(namespace, SMTPMailSender.CONFIG_ENABLED_SECURITY_PROTOCOLS), enabledSecurityProtocols);
|
|
||||||
|
|
||||||
mailSender = new SMTPMailSender(configs, namespace);
|
mailSender = new SMTPMailSender(configs, namespace);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,6 +71,7 @@ import com.cloud.host.dao.HostDao;
|
|||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.hypervisor.HypervisorGuru;
|
import com.cloud.hypervisor.HypervisorGuru;
|
||||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||||
|
import com.cloud.network.IpAddressManager;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
import com.cloud.network.NetworkModel;
|
import com.cloud.network.NetworkModel;
|
||||||
import com.cloud.network.Networks;
|
import com.cloud.network.Networks;
|
||||||
@ -270,6 +271,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
@Inject
|
@Inject
|
||||||
private PhysicalNetworkDao physicalNetworkDao;
|
private PhysicalNetworkDao physicalNetworkDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
private IpAddressManager ipAddressManager;
|
||||||
|
@Inject
|
||||||
private StoragePoolHostDao storagePoolHostDao;
|
private StoragePoolHostDao storagePoolHostDao;
|
||||||
@Inject
|
@Inject
|
||||||
private HypervisorGuruManager hypervisorGuruManager;
|
private HypervisorGuruManager hypervisorGuruManager;
|
||||||
@ -1125,7 +1128,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String internalCSName = unmanagedInstance.getInternalCSName();
|
String internalCSName = unmanagedInstance.getInternalCSName();
|
||||||
if (StringUtils.isEmpty(internalCSName)) {
|
if (StringUtils.isEmpty(instanceNameInternal)) {
|
||||||
internalCSName = instanceNameInternal;
|
internalCSName = instanceNameInternal;
|
||||||
}
|
}
|
||||||
Map<String, String> allDetails = new HashMap<>(details);
|
Map<String, String> allDetails = new HashMap<>(details);
|
||||||
@ -2610,8 +2613,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String macAddress = networkModel.getNextAvailableMacAddressInNetwork(networkId);
|
String macAddress = networkModel.getNextAvailableMacAddressInNetwork(networkId);
|
||||||
|
String ipAddress = null;
|
||||||
String ipAddress = network.getGuestType() != Network.GuestType.L2 ? "auto" : null;
|
if (network.getGuestType() != Network.GuestType.L2) {
|
||||||
|
ipAddress = ipAddressManager.acquireGuestIpAddress(network, null);
|
||||||
|
}
|
||||||
|
|
||||||
Network.IpAddresses requestedIpPair = new Network.IpAddresses(ipAddress, null, macAddress);
|
Network.IpAddresses requestedIpPair = new Network.IpAddresses(ipAddress, null, macAddress);
|
||||||
|
|
||||||
|
|||||||
@ -545,12 +545,12 @@ public class RoutedIpv4ManagerImplTest {
|
|||||||
DataCenterIpv4GuestSubnetVO subnet3 = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
|
DataCenterIpv4GuestSubnetVO subnet3 = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
|
||||||
when(dataCenterIpv4GuestSubnetDao.listNonDedicatedByDataCenterId(zoneId)).thenReturn(Arrays.asList(subnet3));
|
when(dataCenterIpv4GuestSubnetDao.listNonDedicatedByDataCenterId(zoneId)).thenReturn(Arrays.asList(subnet3));
|
||||||
|
|
||||||
doReturn(null).doReturn(null).doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).getIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
|
doReturn(null).doReturn(null).doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
|
||||||
|
|
||||||
Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, domainId, accountId, zoneId);
|
Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, domainId, accountId, zoneId);
|
||||||
|
|
||||||
Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
|
Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
|
||||||
verify(routedIpv4Manager, times(3)).getIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
|
verify(routedIpv4Manager, times(3)).getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -22,15 +22,13 @@ set -x
|
|||||||
function configure_locale() {
|
function configure_locale() {
|
||||||
grep LANG=en_US.UTF-8 /etc/default/locale && \
|
grep LANG=en_US.UTF-8 /etc/default/locale && \
|
||||||
grep LC_ALL=en_US.UTF-8 /etc/default/locale && \
|
grep LC_ALL=en_US.UTF-8 /etc/default/locale && \
|
||||||
grep "^en_US.UTF-8 UTF-8" /etc/locale.gen &&
|
grep "en_US.UTF-8 UTF-8" /etc/locale.gen &&
|
||||||
return
|
return
|
||||||
|
|
||||||
cat >> /etc/default/locale << EOF
|
cat >> /etc/default/locale << EOF
|
||||||
LANG=en_US.UTF-8
|
LANG=en_US.UTF-8
|
||||||
LC_ALL=en_US.UTF-8
|
LC_ALL=en_US.UTF-8
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
grep "^en_US.UTF-8 UTF-8" /etc/locale.gen || \
|
|
||||||
cat >> /etc/locale.gen << EOF
|
cat >> /etc/locale.gen << EOF
|
||||||
en_US.UTF-8 UTF-8
|
en_US.UTF-8 UTF-8
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@ -32,8 +32,8 @@
|
|||||||
"format": "qcow2",
|
"format": "qcow2",
|
||||||
"headless": true,
|
"headless": true,
|
||||||
"http_directory": "http",
|
"http_directory": "http",
|
||||||
"iso_checksum": "sha512:55ab206cd8b0da2898767c3eb6ab5ebef101e3925ec91b3b5f0a286136195b7072588f6ac2d059c545c6938978704ae78cd18d7d9d2a86a7380e46ce27ee4e7b",
|
"iso_checksum": "sha512:892cf1185a214d16ff62a18c6b89cdcd58719647c99916f6214bfca6f9915275d727b666c0b8fbf022c425ef18647e9759974abf7fc440431c39b50c296a98d3",
|
||||||
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.12.0/arm64/iso-cd/debian-12.12.0-arm64-netinst.iso",
|
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso",
|
||||||
"net_device": "virtio-net",
|
"net_device": "virtio-net",
|
||||||
"output_directory": "../dist",
|
"output_directory": "../dist",
|
||||||
"qemu_binary": "qemu-system-aarch64",
|
"qemu_binary": "qemu-system-aarch64",
|
||||||
|
|||||||
@ -31,8 +31,8 @@
|
|||||||
"format": "qcow2",
|
"format": "qcow2",
|
||||||
"headless": true,
|
"headless": true,
|
||||||
"http_directory": "http",
|
"http_directory": "http",
|
||||||
"iso_checksum": "sha512:55ab206cd8b0da2898767c3eb6ab5ebef101e3925ec91b3b5f0a286136195b7072588f6ac2d059c545c6938978704ae78cd18d7d9d2a86a7380e46ce27ee4e7b",
|
"iso_checksum": "sha512:892cf1185a214d16ff62a18c6b89cdcd58719647c99916f6214bfca6f9915275d727b666c0b8fbf022c425ef18647e9759974abf7fc440431c39b50c296a98d3",
|
||||||
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.12.0/arm64/iso-cd/debian-12.12.0-arm64-netinst.iso",
|
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso",
|
||||||
"net_device": "virtio-net",
|
"net_device": "virtio-net",
|
||||||
"output_directory": "../dist",
|
"output_directory": "../dist",
|
||||||
"qemu_binary": "qemu-system-aarch64",
|
"qemu_binary": "qemu-system-aarch64",
|
||||||
|
|||||||
@ -27,8 +27,8 @@
|
|||||||
"format": "qcow2",
|
"format": "qcow2",
|
||||||
"headless": true,
|
"headless": true,
|
||||||
"http_directory": "http",
|
"http_directory": "http",
|
||||||
"iso_checksum": "sha512:c93055182057dd19a334260671c7e10880541b7721ad9c8df87be47e0a11d5bbf85018350ff224ff6a5f6a68320b07e95d539cef9dc020c93966bfaa86d4b2ce",
|
"iso_checksum": "sha512:0921d8b297c63ac458d8a06f87cd4c353f751eb5fe30fd0d839ca09c0833d1d9934b02ee14bbd0c0ec4f8917dde793957801ae1af3c8122cdf28dde8f3c3e0da",
|
||||||
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.12.0/amd64/iso-cd/debian-12.12.0-amd64-netinst.iso",
|
"iso_url": "https://cdimage.debian.org/mirror/cdimage/archive/12.11.0/amd64/iso-cd/debian-12.11.0-amd64-netinst.iso",
|
||||||
"net_device": "virtio-net",
|
"net_device": "virtio-net",
|
||||||
"output_directory": "../dist",
|
"output_directory": "../dist",
|
||||||
"qemuargs": [
|
"qemuargs": [
|
||||||
|
|||||||
3
ui/public/config.json
vendored
3
ui/public/config.json
vendored
@ -97,6 +97,5 @@
|
|||||||
"basicZoneEnabled": true,
|
"basicZoneEnabled": true,
|
||||||
"multipleServer": false,
|
"multipleServer": false,
|
||||||
"allowSettingTheme": true,
|
"allowSettingTheme": true,
|
||||||
"docHelpMappings": {},
|
"docHelpMappings": {}
|
||||||
"notifyLatestCSVersion": true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -975,8 +975,6 @@
|
|||||||
"label.externalid": "External Id",
|
"label.externalid": "External Id",
|
||||||
"label.externalloadbalanceripaddress": "External load balancer IP address.",
|
"label.externalloadbalanceripaddress": "External load balancer IP address.",
|
||||||
"label.extra": "Extra arguments",
|
"label.extra": "Extra arguments",
|
||||||
"label.extraconfig": "Additional Configuration",
|
|
||||||
"label.extraconfig.tooltip": "Additional configuration parameters (extraconfig) to pass to the instance in plain text",
|
|
||||||
"label.f5": "F5",
|
"label.f5": "F5",
|
||||||
"label.f5.ip.loadbalancer": "F5 BIG-IP load balancer.",
|
"label.f5.ip.loadbalancer": "F5 BIG-IP load balancer.",
|
||||||
"label.failed": "Failed",
|
"label.failed": "Failed",
|
||||||
|
|||||||
@ -317,6 +317,7 @@ const user = {
|
|||||||
const result = response.listusersresponse.user[0]
|
const result = response.listusersresponse.user[0]
|
||||||
commit('SET_INFO', result)
|
commit('SET_INFO', result)
|
||||||
commit('SET_NAME', result.firstname + ' ' + result.lastname)
|
commit('SET_NAME', result.firstname + ' ' + result.lastname)
|
||||||
|
store.dispatch('SetCsLatestVersion', result.rolename)
|
||||||
resolve(cachedApis)
|
resolve(cachedApis)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
@ -563,9 +564,6 @@ const user = {
|
|||||||
commit('SET_DOMAIN_STORE', domainStore)
|
commit('SET_DOMAIN_STORE', domainStore)
|
||||||
},
|
},
|
||||||
SetCsLatestVersion ({ commit }, rolename) {
|
SetCsLatestVersion ({ commit }, rolename) {
|
||||||
if (!vueProps.$config.notifyLatestCSVersion) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const lastFetchTs = store.getters.latestVersion?.fetchedTs ? store.getters.latestVersion.fetchedTs : 0
|
const lastFetchTs = store.getters.latestVersion?.fetchedTs ? store.getters.latestVersion.fetchedTs : 0
|
||||||
if (rolename === 'Root Admin' && (+new Date() - lastFetchTs) > 24 * 60 * 60 * 1000) {
|
if (rolename === 'Root Admin' && (+new Date() - lastFetchTs) > 24 * 60 * 60 * 1000) {
|
||||||
axios.get(
|
axios.get(
|
||||||
|
|||||||
@ -724,12 +724,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="extraConfigEnabled" name="extraconfig" ref="extraconfig">
|
|
||||||
<template #label>
|
|
||||||
<tooltip-label :title="$t('label.extraconfig')" :tooltip="$t('label.extraconfig.tooltip')"/>
|
|
||||||
</template>
|
|
||||||
<a-textarea v-model:value="form.extraconfig"/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item :label="$t('label.affinity.groups')">
|
<a-form-item :label="$t('label.affinity.groups')">
|
||||||
<affinity-group-selection
|
<affinity-group-selection
|
||||||
:items="options.affinityGroups"
|
:items="options.affinityGroups"
|
||||||
@ -1424,9 +1418,6 @@ export default {
|
|||||||
dynamicScalingVmConfigValue () {
|
dynamicScalingVmConfigValue () {
|
||||||
return this.$store.getters.features.dynamicscalingenabled
|
return this.$store.getters.features.dynamicscalingenabled
|
||||||
},
|
},
|
||||||
extraConfigEnabled () {
|
|
||||||
return this.$store.getters.features.additionalconfigenabled
|
|
||||||
},
|
|
||||||
isCustomizedDiskIOPS () {
|
isCustomizedDiskIOPS () {
|
||||||
return this.diskSelected?.iscustomizediops || false
|
return this.diskSelected?.iscustomizediops || false
|
||||||
},
|
},
|
||||||
@ -2063,9 +2054,6 @@ export default {
|
|||||||
if (isUserdataAllowed && values.userdata && values.userdata.length > 0) {
|
if (isUserdataAllowed && values.userdata && values.userdata.length > 0) {
|
||||||
deployVmData.userdata = this.$toBase64AndURIEncoded(values.userdata)
|
deployVmData.userdata = this.$toBase64AndURIEncoded(values.userdata)
|
||||||
}
|
}
|
||||||
if (values.extraconfig && values.extraconfig.length > 0) {
|
|
||||||
deployVmData.extraconfig = encodeURIComponent(values.extraconfig)
|
|
||||||
}
|
|
||||||
// step 2: select template/iso
|
// step 2: select template/iso
|
||||||
if (this.tabKey === 'templateid') {
|
if (this.tabKey === 'templateid') {
|
||||||
deployVmData.templateid = values.templateid
|
deployVmData.templateid = values.templateid
|
||||||
|
|||||||
@ -91,12 +91,6 @@
|
|||||||
<a-textarea v-model:value="form.userdata">
|
<a-textarea v-model:value="form.userdata">
|
||||||
</a-textarea>
|
</a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="extraConfigEnabled">
|
|
||||||
<template #label>
|
|
||||||
<tooltip-label :title="$t('label.extraconfig')" :tooltip="$t('label.extraconfig.tooltip')"/>
|
|
||||||
</template>
|
|
||||||
<a-textarea v-model:value="form.extraconfig"/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item ref="securitygroupids" name="securitygroupids" :label="$t('label.security.groups')" v-if="securityGroupsEnabled">
|
<a-form-item ref="securitygroupids" name="securitygroupids" :label="$t('label.security.groups')" v-if="securityGroupsEnabled">
|
||||||
<a-select
|
<a-select
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
@ -173,19 +167,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
extraConfigEnabled () {
|
|
||||||
return this.$store.getters.features.additionalconfigenabled
|
|
||||||
},
|
|
||||||
combinedExtraConfig () {
|
|
||||||
if (!this.extraConfigEnabled || !this.resource.details) return ''
|
|
||||||
const configs = Object.keys(this.resource.details)
|
|
||||||
.filter(key => key.startsWith('extraconfig-'))
|
|
||||||
.map(key => this.resource.details[key] || '')
|
|
||||||
.filter(val => val.trim())
|
|
||||||
return configs.join('\n\n')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeCreate () {
|
beforeCreate () {
|
||||||
this.apiParams = this.$getApiParams('updateVirtualMachine')
|
this.apiParams = this.$getApiParams('updateVirtualMachine')
|
||||||
},
|
},
|
||||||
@ -204,8 +185,7 @@ export default {
|
|||||||
deleteprotection: this.resource.deleteprotection,
|
deleteprotection: this.resource.deleteprotection,
|
||||||
group: this.resource.group,
|
group: this.resource.group,
|
||||||
userdata: '',
|
userdata: '',
|
||||||
haenable: this.resource.haenable,
|
haenable: this.resource.haenable
|
||||||
extraconfig: this.combinedExtraConfig
|
|
||||||
})
|
})
|
||||||
this.rules = reactive({})
|
this.rules = reactive({})
|
||||||
},
|
},
|
||||||
@ -362,9 +342,6 @@ export default {
|
|||||||
if (values.userdata && values.userdata.length > 0) {
|
if (values.userdata && values.userdata.length > 0) {
|
||||||
params.userdata = this.$toBase64AndURIEncoded(values.userdata)
|
params.userdata = this.$toBase64AndURIEncoded(values.userdata)
|
||||||
}
|
}
|
||||||
if (values.extraconfig && values.extraconfig.length > 0) {
|
|
||||||
params.extraconfig = encodeURIComponent(values.extraconfig)
|
|
||||||
}
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
||||||
api('updateVirtualMachine', {}, 'POST', params).then(json => {
|
api('updateVirtualMachine', {}, 'POST', params).then(json => {
|
||||||
|
|||||||
@ -396,7 +396,7 @@ export default {
|
|||||||
placeHolder: 'message.error.server',
|
placeHolder: 'message.error.server',
|
||||||
required: true,
|
required: true,
|
||||||
display: {
|
display: {
|
||||||
primaryStorageProtocol: ['nfs', 'iscsi', 'gluster', 'SMB', 'Linstor', 'datastorecluster', 'vmfs']
|
primaryStorageProtocol: ['nfs', 'iscsi', 'gluster', 'SMB', 'Linstor']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1510,10 +1510,10 @@ export default {
|
|||||||
}
|
}
|
||||||
path += '/' + this.prefillContent.primaryStorageVmfsDatastore
|
path += '/' + this.prefillContent.primaryStorageVmfsDatastore
|
||||||
if (protocol === 'vmfs') {
|
if (protocol === 'vmfs') {
|
||||||
url = this.vmfsURL(server, path)
|
url = this.vmfsURL('dummy', path)
|
||||||
}
|
}
|
||||||
if (protocol === 'datastorecluster') {
|
if (protocol === 'datastorecluster') {
|
||||||
url = this.datastoreclusterURL(server, path)
|
url = this.datastoreclusterURL('dummy', path)
|
||||||
}
|
}
|
||||||
} else if (protocol === 'iscsi') {
|
} else if (protocol === 'iscsi') {
|
||||||
let iqn = this.prefillContent?.primaryStorageTargetIQN || ''
|
let iqn = this.prefillContent?.primaryStorageTargetIQN || ''
|
||||||
|
|||||||
@ -413,7 +413,7 @@ export default {
|
|||||||
for (const index in net.traffics) {
|
for (const index in net.traffics) {
|
||||||
if (this.hypervisor === 'VMware') {
|
if (this.hypervisor === 'VMware') {
|
||||||
delete this.physicalNetworks[idx].traffics[index].label
|
delete this.physicalNetworks[idx].traffics[index].label
|
||||||
} else if (!net.traffics[index].label) {
|
} else {
|
||||||
this.physicalNetworks[idx].traffics[index].label = ''
|
this.physicalNetworks[idx].traffics[index].label = ''
|
||||||
}
|
}
|
||||||
const traffic = net.traffics[index]
|
const traffic = net.traffics[index]
|
||||||
|
|||||||
@ -29,7 +29,6 @@ import java.net.URI;
|
|||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@ -158,7 +157,13 @@ public class Script implements Callable<String> {
|
|||||||
boolean obscureParam = false;
|
boolean obscureParam = false;
|
||||||
for (int i = 0; i < command.length; i++) {
|
for (int i = 0; i < command.length; i++) {
|
||||||
String cmd = command[i];
|
String cmd = command[i];
|
||||||
if (sanitizeViCmdParameter(cmd, builder) || sanitizeRbdFileFormatCmdParameter(cmd, builder)) {
|
if (StringUtils.isNotEmpty(cmd) && cmd.startsWith("vi://")) {
|
||||||
|
String[] tokens = cmd.split("@");
|
||||||
|
if (tokens.length >= 2) {
|
||||||
|
builder.append("vi://").append("******@").append(tokens[1]).append(" ");
|
||||||
|
} else {
|
||||||
|
builder.append("vi://").append("******").append(" ");
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (obscureParam) {
|
if (obscureParam) {
|
||||||
@ -176,41 +181,6 @@ public class Script implements Callable<String> {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sanitizeViCmdParameter(String cmd, StringBuilder builder) {
|
|
||||||
if (StringUtils.isEmpty(cmd) || !cmd.startsWith("vi://")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] tokens = cmd.split("@");
|
|
||||||
if (tokens.length >= 2) {
|
|
||||||
builder.append("vi://").append("******@").append(tokens[1]).append(" ");
|
|
||||||
} else {
|
|
||||||
builder.append("vi://").append("******").append(" ");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean sanitizeRbdFileFormatCmdParameter(String cmd, StringBuilder builder) {
|
|
||||||
if (StringUtils.isEmpty(cmd) || !cmd.startsWith("rbd:") || !cmd.contains("key=")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] tokens = cmd.split("key=");
|
|
||||||
if (tokens.length != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String tokenWithKey = tokens[1];
|
|
||||||
String[] options = tokenWithKey.split(":");
|
|
||||||
if (options.length > 1) {
|
|
||||||
String optionsAfterKey = String.join(":", Arrays.copyOfRange(options, 1, options.length));
|
|
||||||
builder.append(tokens[0]).append("key=").append("******").append(":").append(optionsAfterKey).append(" ");
|
|
||||||
} else {
|
|
||||||
builder.append(tokens[0]).append("key=").append("******").append(" ");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeout() {
|
public long getTimeout() {
|
||||||
return _timeout;
|
return _timeout;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,52 +19,31 @@ package org.apache.cloudstack.utils.jsinterpreter;
|
|||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import javax.script.Bindings;
|
|
||||||
import javax.script.Compilable;
|
|
||||||
import javax.script.CompiledScript;
|
|
||||||
import javax.script.ScriptContext;
|
|
||||||
import javax.script.ScriptEngine;
|
|
||||||
import javax.script.ScriptException;
|
|
||||||
import javax.script.SimpleBindings;
|
|
||||||
import javax.script.SimpleScriptContext;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.openjdk.nashorn.api.scripting.ClassFilter;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
|
||||||
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||||
|
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes JavaScript with strong restrictions to mitigate RCE risks.
|
* A class to execute JavaScript scripts, with the possibility to inject context to the scripts.
|
||||||
* - Disables Java interop via --no-java AND a deny-all ClassFilter
|
|
||||||
* - Disables Nashorn syntax extensions
|
|
||||||
* - Uses Bindings instead of string-splicing variables
|
|
||||||
* - Fresh ScriptContext per execution, with timeout on a daemon worker
|
|
||||||
*/
|
*/
|
||||||
public class JsInterpreter implements Closeable {
|
public class JsInterpreter implements Closeable {
|
||||||
protected Logger logger = LogManager.getLogger(JsInterpreter.class);
|
protected Logger logger = LogManager.getLogger(JsInterpreter.class);
|
||||||
|
|
||||||
protected static final List<String> RESTRICTED_TOKENS = Arrays.asList( "engine", "context", "factory",
|
|
||||||
"Java", "java", "Packages"," javax", "load", "loadWithNewGlobal", "print", "factory", "getClass",
|
|
||||||
"runCommand", "Runtime", "exec", "ProcessBuilder", "Thread", "thread", "Threads", "Class", "class");
|
|
||||||
|
|
||||||
protected ScriptEngine interpreter;
|
protected ScriptEngine interpreter;
|
||||||
protected String interpreterName;
|
protected String interpreterName;
|
||||||
private final String injectingLogMessage = "Injecting variable [%s] with value [%s] into the JS interpreter.";
|
private final String injectingLogMessage = "Injecting variable [%s] with value [%s] into the JS interpreter.";
|
||||||
@ -72,40 +51,21 @@ public class JsInterpreter implements Closeable {
|
|||||||
private TimeUnit defaultTimeUnit = TimeUnit.MILLISECONDS;
|
private TimeUnit defaultTimeUnit = TimeUnit.MILLISECONDS;
|
||||||
private long timeout;
|
private long timeout;
|
||||||
private String timeoutDefaultMessage;
|
private String timeoutDefaultMessage;
|
||||||
|
protected Map<String, String> variables = new LinkedHashMap<>();
|
||||||
// Store variables as Objects; they go into Bindings (no code splicing)
|
|
||||||
protected Map<String, Object> variables = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/** Deny-all filter: no Java class is visible from scripts. */
|
|
||||||
static final class DenyAllClassFilter implements ClassFilter {
|
|
||||||
@Override public boolean exposeToScripts(String className) { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor created exclusively for unit testing.
|
* Constructor created exclusively for unit testing.
|
||||||
*/
|
*/
|
||||||
protected JsInterpreter() { }
|
protected JsInterpreter() {
|
||||||
|
}
|
||||||
|
|
||||||
public JsInterpreter(long timeout) {
|
public JsInterpreter(long timeout) {
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.timeoutDefaultMessage = String.format(
|
this.timeoutDefaultMessage = String.format("Timeout (in milliseconds) defined in the global setting [quota.activationrule.timeout]: [%s].", this.timeout);
|
||||||
"Timeout (in milliseconds) defined in the global setting [quota.activationrule.timeout]: [%s].", this.timeout);
|
|
||||||
|
|
||||||
if (System.getProperty("nashorn.args") == null) {
|
|
||||||
System.setProperty("nashorn.args", "--no-java --no-syntax-extensions");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.executor = new ThreadPoolExecutor(
|
|
||||||
1, 1, 60L, TimeUnit.SECONDS,
|
|
||||||
new LinkedBlockingQueue<>(),
|
|
||||||
r -> {
|
|
||||||
Thread t = new Thread(r, "JsInterpreter-worker");
|
|
||||||
t.setDaemon(true);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
executor = Executors.newSingleThreadExecutor();
|
||||||
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
|
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
|
||||||
|
|
||||||
this.interpreterName = factory.getEngineName();
|
this.interpreterName = factory.getEngineName();
|
||||||
logger.trace(String.format("Initiating JS interpreter: %s.", interpreterName));
|
logger.trace(String.format("Initiating JS interpreter: %s.", interpreterName));
|
||||||
|
|
||||||
@ -113,53 +73,49 @@ public class JsInterpreter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void setScriptEngineDisablingJavaLanguage(NashornScriptEngineFactory factory) {
|
protected void setScriptEngineDisablingJavaLanguage(NashornScriptEngineFactory factory) {
|
||||||
String[] opts = new String[] {
|
interpreter = factory.getScriptEngine("--no-java");
|
||||||
"--no-java",
|
|
||||||
"--no-syntax-extensions",
|
|
||||||
};
|
|
||||||
interpreter = factory.getScriptEngine(
|
|
||||||
opts,
|
|
||||||
JsInterpreter.class.getClassLoader(),
|
|
||||||
new DenyAllClassFilter()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Discards the current variables map and create a new one. */
|
/**
|
||||||
|
* Discards the current variables map and create a new one.
|
||||||
|
*/
|
||||||
public void discardCurrentVariables() {
|
public void discardCurrentVariables() {
|
||||||
logger.trace("Discarding current variables map and creating a new one.");
|
logger.trace("Discarding current variables map and creating a new one.");
|
||||||
variables = new LinkedHashMap<>();
|
variables = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a variable that will be exposed via ENGINE_SCOPE bindings.
|
* Adds the parameters to a Map that will be converted to JS variables right before executing the script.
|
||||||
* Safe against code injection (no string concatenation).
|
* @param key The name of the variable.
|
||||||
|
* @param value The value of the variable.
|
||||||
*/
|
*/
|
||||||
public void injectVariable(String key, Object value) {
|
public void injectVariable(String key, String value) {
|
||||||
if (key == null) return;
|
logger.trace(String.format(injectingLogMessage, key, value));
|
||||||
logger.trace(String.format(injectingLogMessage, key, String.valueOf(value)));
|
|
||||||
variables.put(key, value);
|
variables.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Not needed when using Bindings; kept for source compatibility.
|
* Adds the parameter, surrounded by double quotes, to a Map that will be converted to a JS variable right before executing the script.
|
||||||
* Prefer {@link #injectVariable(String, Object)}.
|
* @param key The name of the variable.
|
||||||
|
* @param value The value of the variable.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public void injectStringVariable(String key, String value) {
|
public void injectStringVariable(String key, String value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
logger.trace(String.format("Not injecting [%s] because its value is null.", key));
|
logger.trace(String.format("Not injecting [%s] because its value is null.", key));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
injectVariable(key, value);
|
value = String.format("\"%s\"", value);
|
||||||
|
logger.trace(String.format(injectingLogMessage, key, value));
|
||||||
|
variables.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects the variables via Bindings and executes the script with a fresh context.
|
* Injects the variables to the script and execute it.
|
||||||
* @param script Code to be executed.
|
* @param script Code to be executed.
|
||||||
* @return The result of the executed script.
|
* @return The result of the executed script.
|
||||||
*/
|
*/
|
||||||
public Object executeScript(String script) {
|
public Object executeScript(String script) {
|
||||||
Objects.requireNonNull(script, "script");
|
script = addVariablesToScript(script);
|
||||||
|
|
||||||
logger.debug(String.format("Executing script [%s].", script));
|
logger.debug(String.format("Executing script [%s].", script));
|
||||||
|
|
||||||
@ -170,60 +126,43 @@ public class JsInterpreter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Object executeScriptInThread(String script) {
|
protected Object executeScriptInThread(String script) {
|
||||||
final Callable<Object> task = () -> {
|
Callable<Object> task = () -> interpreter.eval(script);
|
||||||
final SimpleScriptContext ctx = new SimpleScriptContext();
|
|
||||||
|
|
||||||
final Bindings engineBindings = new SimpleBindings();
|
Future<Object> future = executor.submit(task);
|
||||||
if (MapUtils.isNotEmpty(variables)) {
|
|
||||||
engineBindings.putAll(variables);
|
|
||||||
}
|
|
||||||
for (String token : RESTRICTED_TOKENS) {
|
|
||||||
engineBindings.put(token, null);
|
|
||||||
}
|
|
||||||
ctx.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE);
|
|
||||||
|
|
||||||
final StringWriter out = new StringWriter();
|
|
||||||
ctx.setWriter(out);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final CompiledScript compiled = ((Compilable) interpreter).compile(script);
|
|
||||||
Object result = compiled.eval(ctx);
|
|
||||||
if (out.getBuffer().length() > 0) {
|
|
||||||
logger.info("Script produced output on stdout: [{}]", out);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (ScriptException se) {
|
|
||||||
String msg = se.getMessage() == null ? "Script error" : se.getMessage();
|
|
||||||
throw new ScriptException("Script error: " + msg, se.getFileName(), se.getLineNumber(), se.getColumnNumber());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final Future<Object> future = executor.submit(task);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return future.get(this.timeout, defaultTimeUnit);
|
return future.get(this.timeout, defaultTimeUnit);
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException | InterruptedException | ExecutionException e) {
|
||||||
String message = String.format(
|
String message = String.format("Unable to execute script [%s] due to [%s]", script, e.getMessage());
|
||||||
"Execution of script [%s] took too long and timed out. %s", script, timeoutDefaultMessage);
|
|
||||||
|
if (e instanceof TimeoutException) {
|
||||||
|
message = String.format("Execution of script [%s] took too long and timed out. %s", script, timeoutDefaultMessage);
|
||||||
|
}
|
||||||
|
|
||||||
logger.error(message, e);
|
logger.error(message, e);
|
||||||
throw new CloudRuntimeException(message, e);
|
throw new CloudRuntimeException(message, e);
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
String message = String.format("Execution of script [%s] was interrupted.", script);
|
|
||||||
logger.error(message, e);
|
|
||||||
throw new CloudRuntimeException(message, e);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
Throwable cause = e.getCause() == null ? e : e.getCause();
|
|
||||||
String message = String.format("Unable to execute script [%s] due to [%s]", script, cause.getMessage());
|
|
||||||
logger.error(message, cause);
|
|
||||||
throw new CloudRuntimeException(message, cause);
|
|
||||||
} finally {
|
} finally {
|
||||||
future.cancel(true);
|
future.cancel(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String addVariablesToScript(String script) {
|
||||||
|
if (MapUtils.isEmpty(variables)) {
|
||||||
|
logger.trace(String.format("There is no variables to add to script [%s]. Returning.", script));
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
|
String variablesToString = "";
|
||||||
|
for (Map.Entry<String, String> variable : variables.entrySet()) {
|
||||||
|
variablesToString = String.format("%s %s = %s;", variablesToString, variable.getKey(), variable.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format("%s %s", variablesToString, script);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
executor.shutdownNow();
|
executor.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,12 +16,12 @@
|
|||||||
//under the License.
|
//under the License.
|
||||||
package org.apache.cloudstack.utils.jsinterpreter;
|
package org.apache.cloudstack.utils.jsinterpreter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TagAsRuleHelper {
|
public class TagAsRuleHelper {
|
||||||
|
|
||||||
@ -32,6 +32,7 @@ public class TagAsRuleHelper {
|
|||||||
|
|
||||||
public static boolean interpretTagAsRule(String rule, String tags, long timeout) {
|
public static boolean interpretTagAsRule(String rule, String tags, long timeout) {
|
||||||
String script = PARSE_TAGS + rule;
|
String script = PARSE_TAGS + rule;
|
||||||
|
tags = String.format("'%s'", StringEscapeUtils.escapeEcmaScript(tags));
|
||||||
try (JsInterpreter jsInterpreter = new JsInterpreter(timeout)) {
|
try (JsInterpreter jsInterpreter = new JsInterpreter(timeout)) {
|
||||||
jsInterpreter.injectVariable("tags", tags);
|
jsInterpreter.injectVariable("tags", tags);
|
||||||
Object scriptReturn = jsInterpreter.executeScript(script);
|
Object scriptReturn = jsInterpreter.executeScript(script);
|
||||||
|
|||||||
@ -20,7 +20,6 @@ package org.apache.cloudstack.utils.jsinterpreter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -28,8 +27,7 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import javax.script.ScriptEngine;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -38,10 +36,9 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.openjdk.nashorn.api.scripting.ClassFilter;
|
|
||||||
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||||
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import javax.script.ScriptEngine;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class JsInterpreterTest {
|
public class JsInterpreterTest {
|
||||||
@ -64,6 +61,30 @@ public class JsInterpreterTest {
|
|||||||
Assert.assertTrue(executor.isShutdown());
|
Assert.assertTrue(executor.isShutdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVariablesToScriptTestVariablesMapIsEmptyReturnScript() {
|
||||||
|
String script = "a + b";
|
||||||
|
jsInterpreterSpy.variables = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
String result = jsInterpreterSpy.addVariablesToScript(script);
|
||||||
|
|
||||||
|
Assert.assertEquals(script, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVariablesToScriptTestVariablesMapIsNotEmptyInjectVariableToScript() {
|
||||||
|
String script = "a + b";
|
||||||
|
String var1 = "{test: \"test\"}";
|
||||||
|
jsInterpreterSpy.injectVariable("var1", var1);
|
||||||
|
jsInterpreterSpy.injectVariable("var2", var1);
|
||||||
|
|
||||||
|
String expected = String.format(" var1 = %s; var2 = %s; %s", var1, var1, script);
|
||||||
|
|
||||||
|
String result = jsInterpreterSpy.addVariablesToScript(script);
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void executeScriptTestReturnResultOfScriptExecution() {
|
public void executeScriptTestReturnResultOfScriptExecution() {
|
||||||
String script = "5";
|
String script = "5";
|
||||||
@ -133,7 +154,7 @@ public class JsInterpreterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void discardCurrentVariablesTestInstantiateNewMap() {
|
public void discardCurrentVariablesTestInstantiateNewMap() {
|
||||||
Map<String, Object> variables = new LinkedHashMap<>();
|
Map<String, String> variables = new LinkedHashMap<>();
|
||||||
variables.put("a", "b");
|
variables.put("a", "b");
|
||||||
variables.put("b", null);
|
variables.put("b", null);
|
||||||
|
|
||||||
@ -149,14 +170,12 @@ public class JsInterpreterTest {
|
|||||||
NashornScriptEngineFactory nashornScriptEngineFactoryMock = Mockito.spy(NashornScriptEngineFactory.class);
|
NashornScriptEngineFactory nashornScriptEngineFactoryMock = Mockito.spy(NashornScriptEngineFactory.class);
|
||||||
ScriptEngine scriptEngineMock = Mockito.mock(ScriptEngine.class);
|
ScriptEngine scriptEngineMock = Mockito.mock(ScriptEngine.class);
|
||||||
|
|
||||||
Mockito.doReturn(scriptEngineMock).when(nashornScriptEngineFactoryMock).getScriptEngine(Mockito.any(),
|
Mockito.doReturn(scriptEngineMock).when(nashornScriptEngineFactoryMock).getScriptEngine(Mockito.anyString());
|
||||||
Mockito.any(ClassLoader.class), Mockito.any(ClassFilter.class));
|
|
||||||
|
|
||||||
jsInterpreterSpy.setScriptEngineDisablingJavaLanguage(nashornScriptEngineFactoryMock);
|
jsInterpreterSpy.setScriptEngineDisablingJavaLanguage(nashornScriptEngineFactoryMock);
|
||||||
|
|
||||||
Assert.assertEquals(scriptEngineMock, jsInterpreterSpy.interpreter);
|
Assert.assertEquals(scriptEngineMock, jsInterpreterSpy.interpreter);
|
||||||
Mockito.verify(nashornScriptEngineFactoryMock).getScriptEngine(Mockito.any(),
|
Mockito.verify(nashornScriptEngineFactoryMock).getScriptEngine("--no-java");
|
||||||
Mockito.any(ClassLoader.class), Mockito.any(ClassFilter.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -174,46 +193,6 @@ public class JsInterpreterTest {
|
|||||||
|
|
||||||
jsInterpreterSpy.injectStringVariable("a", "b");
|
jsInterpreterSpy.injectStringVariable("a", "b");
|
||||||
|
|
||||||
Assert.assertEquals(jsInterpreterSpy.variables.get("a"), "b");
|
Assert.assertEquals(jsInterpreterSpy.variables.get("a"), "\"b\"");
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void executeScriptTestValidScriptShouldPassWithMixedVariables() {
|
|
||||||
try (JsInterpreter jsInterpreter = new JsInterpreter(1000)) {
|
|
||||||
jsInterpreter.injectVariable("x", 10);
|
|
||||||
jsInterpreter.injectVariable("y", "hello");
|
|
||||||
jsInterpreter.injectVariable("z", true);
|
|
||||||
String validScript = "var result = x + (z ? 1 : 0); y + '-' + result;";
|
|
||||||
Object result = jsInterpreter.executeScript(validScript);
|
|
||||||
Assert.assertEquals("hello-11", result);
|
|
||||||
} catch (IOException exception) {
|
|
||||||
Assert.fail("IOException not expected here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runMaliciousScriptFileTest(String script, String filename) {
|
|
||||||
try (JsInterpreter jsInterpreter = new JsInterpreter(1000)) {
|
|
||||||
jsInterpreter.executeScript(script);
|
|
||||||
} catch (CloudRuntimeException ex) {
|
|
||||||
Assert.assertTrue(ex.getMessage().contains("Unable to execute script"));
|
|
||||||
java.io.File f = new java.io.File(filename);
|
|
||||||
Assert.assertFalse(f.exists());
|
|
||||||
} catch (IOException exception) {
|
|
||||||
Assert.fail("IOException not expected here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void executeScriptTestMaliciousScriptShouldThrowException1() {
|
|
||||||
String filename = "/tmp/hack1-" + UUID.randomUUID();
|
|
||||||
String maliciousScript = "Java.type('java.lang.Runtime').getRuntime().exec('touch " + filename + "')";
|
|
||||||
runMaliciousScriptFileTest(maliciousScript, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void executeScriptTestMaliciousScriptShouldThrowException2() {
|
|
||||||
String filename = "/tmp/hack2-" + UUID.randomUUID();
|
|
||||||
String maliciousScript = "var e=this.engine.getFactory().getScriptEngine('-Dnashorn.args=--no-java=False'); e.eval(\"java.lang.Runtime.getRuntime().exec(['/bin/bash','-c','touch " + filename + "']);\");";
|
|
||||||
runMaliciousScriptFileTest(maliciousScript, filename);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user