mirror of https://github.com/apache/cloudstack.git
Updated DB encryption for ScaleIO credentials and Added lock while spooling managed storage template (#103)
* Encrypt the ScaleIO storage pool credentials in the DB * Added sync lock while spooling managed storage template
This commit is contained in:
parent
a61ba8c755
commit
7d5a4cde7c
|
|
@ -53,6 +53,7 @@ import com.cloud.storage.dao.VolumeDao;
|
|||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
|
||||
|
|
@ -477,8 +478,10 @@ public class ScaleIOVMSnapshotStrategy extends ManagerBase implements VMSnapshot
|
|||
private ScaleIOGatewayClient getScaleIOClient(final Long storagePoolId) throws Exception {
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(storagePoolId);
|
||||
final String url = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_ENDPOINT).getValue();
|
||||
final String username = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME).getValue();
|
||||
final String password = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
|
||||
final String encryptedUsername = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME).getValue();
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
final String encryptedPassword = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
return ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,6 +837,9 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
|
||||
if (templatePoolRef == null) {
|
||||
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
||||
} else if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) {
|
||||
// Template already exists
|
||||
return templateOnPrimary;
|
||||
}
|
||||
|
||||
// At this point, we have an entry in the DB that points to our cached template.
|
||||
|
|
@ -852,13 +855,6 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId);
|
||||
}
|
||||
|
||||
// Template already exists
|
||||
if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) {
|
||||
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
|
||||
|
||||
return templateOnPrimary;
|
||||
}
|
||||
|
||||
try {
|
||||
// create a cache volume on the back-end
|
||||
|
||||
|
|
@ -908,22 +904,20 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
|
||||
long templatePoolRefId = templatePoolRef.getId();
|
||||
|
||||
templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds);
|
||||
|
||||
if (templatePoolRef == null) {
|
||||
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId);
|
||||
}
|
||||
|
||||
if (templatePoolRef.getDownloadState() == Status.DOWNLOADED) {
|
||||
// There can be cases where we acquired the lock, but the template
|
||||
// was already copied by a previous thread. Just return in that case.
|
||||
|
||||
s_logger.debug("Template already downloaded, nothing to do");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds);
|
||||
|
||||
if (templatePoolRef == null) {
|
||||
throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId);
|
||||
}
|
||||
|
||||
if (templatePoolRef.getDownloadState() == Status.DOWNLOADED) {
|
||||
// There can be cases where we acquired the lock, but the template
|
||||
// was already copied by a previous thread. Just return in that case.
|
||||
s_logger.debug("Template already downloaded, nothing to do");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the template from sec storage to the created volume
|
||||
CreateBaseImageContext<CreateCmdResult> copyContext = new CreateBaseImageContext<>(null, null, destPrimaryDataStore, srcTemplateInfo, copyTemplateFuture, templateOnPrimary,
|
||||
templatePoolRefId);
|
||||
|
|
@ -1236,16 +1230,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
throw new CloudRuntimeException("Destination host should not be null.");
|
||||
}
|
||||
|
||||
PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId);
|
||||
|
||||
// Check if template exists on the storage pool. If not, downland and copy to managed storage pool
|
||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destDataStoreId, srcTemplateId);
|
||||
if (templatePoolRef != null && templatePoolRef.getDownloadState() == Status.DOWNLOADED) {
|
||||
return tmplFactory.getTemplate(srcTemplateId, destPrimaryDataStore);
|
||||
}
|
||||
|
||||
TemplateInfo srcTemplateInfo = tmplFactory.getTemplate(srcTemplateId);
|
||||
|
||||
if (srcTemplateInfo == null) {
|
||||
throw new CloudRuntimeException("Failed to get info of template: " + srcTemplateId);
|
||||
}
|
||||
|
|
@ -1254,8 +1239,29 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
throw new CloudRuntimeException("Unsupported format: " + Storage.ImageFormat.ISO.toString() + " for managed storage template");
|
||||
}
|
||||
|
||||
GlobalLock lock = null;
|
||||
TemplateInfo templateOnPrimary = null;
|
||||
try {
|
||||
String templateIdManagedPoolIdLockString = "templateId:" + srcTemplateId + "managedPoolId:" + destDataStoreId;
|
||||
lock = GlobalLock.getInternLock(templateIdManagedPoolIdLockString);
|
||||
if (lock == null) {
|
||||
throw new CloudRuntimeException("Unable to create managed storage template, couldn't get global lock on " + templateIdManagedPoolIdLockString);
|
||||
}
|
||||
|
||||
int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
|
||||
if (!lock.lock(storagePoolMaxWaitSeconds)) {
|
||||
s_logger.debug("Unable to create managed storage template, couldn't lock on " + templateIdManagedPoolIdLockString);
|
||||
throw new CloudRuntimeException("Unable to create managed storage template, couldn't lock on " + templateIdManagedPoolIdLockString);
|
||||
}
|
||||
|
||||
PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId);
|
||||
|
||||
// Check if template exists on the storage pool. If not, downland and copy to managed storage pool
|
||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destDataStoreId, srcTemplateId);
|
||||
if (templatePoolRef != null && templatePoolRef.getDownloadState() == Status.DOWNLOADED) {
|
||||
return tmplFactory.getTemplate(srcTemplateId, destPrimaryDataStore);
|
||||
}
|
||||
|
||||
templateOnPrimary = createManagedTemplateVolume(srcTemplateInfo, destPrimaryDataStore);
|
||||
if (templateOnPrimary == null) {
|
||||
throw new CloudRuntimeException("Failed to create template " + srcTemplateInfo.getUniqueName() + " on primary storage: " + destDataStoreId);
|
||||
|
|
@ -1311,6 +1317,11 @@ public class VolumeServiceImpl implements VolumeService {
|
|||
}
|
||||
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
} finally {
|
||||
if (lock != null) {
|
||||
lock.unlock();
|
||||
lock.releaseRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ import com.cloud.storage.dao.VMTemplatePoolDao;
|
|||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VirtualMachineManager;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
|
@ -105,8 +106,10 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||
private ScaleIOGatewayClient getScaleIOClient(final Long storagePoolId) throws Exception {
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(storagePoolId);
|
||||
final String url = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_ENDPOINT).getValue();
|
||||
final String username = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME).getValue();
|
||||
final String password = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
|
||||
final String encryptedUsername = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_USERNAME).getValue();
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
final String encryptedPassword = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
return ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
|||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.utils.UriUtils;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
|
||||
|
|
@ -100,7 +101,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||
|
||||
private org.apache.cloudstack.storage.datastore.api.StoragePool findStoragePool(String url, String username, String password, String storagePoolName) {
|
||||
try {
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, 60);
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.value();
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
List<org.apache.cloudstack.storage.datastore.api.StoragePool> storagePools = client.listStoragePools();
|
||||
for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) {
|
||||
if (pool.getName().equals(storagePoolName)) {
|
||||
|
|
@ -212,8 +214,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||
}
|
||||
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT, gatewayApiURL);
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_USERNAME, gatewayUsername);
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_PASSWORD, gatewayPassword);
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_USERNAME, DBEncryptionUtil.encrypt(gatewayUsername));
|
||||
details.put(ScaleIOGatewayClient.GATEWAY_API_PASSWORD, DBEncryptionUtil.encrypt(gatewayPassword));
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_NAME, storagePoolName);
|
||||
details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, scaleIOPool.getSystemId());
|
||||
parameters.setDetails(details);
|
||||
|
|
@ -231,10 +233,13 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||
List<String> connectedSdcIps = null;
|
||||
try {
|
||||
Map <String, String> dataStoreDetails = primaryDataStoreDao.getDetails(dataStore.getId());
|
||||
String url = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
String username = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
String password = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, 60);
|
||||
final String url = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
final String encryptedUsername = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
final String encryptedPassword = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.value();
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
connectedSdcIps = client.listConnectedSdcIps();
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException | URISyntaxException e) {
|
||||
LOGGER.error("Failed to create storage pool", e);
|
||||
|
|
@ -293,9 +298,12 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||
try {
|
||||
Map <String, String> dataStoreDetails = primaryDataStoreDao.getDetails(dataStore.getId());
|
||||
String url = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
String username = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
String password = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, 60);
|
||||
String encryptedUsername = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
String encryptedPassword = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.value();
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
connectedSdcIps = client.listConnectedSdcIps();
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException | URISyntaxException e) {
|
||||
LOGGER.error("Failed to create storage pool", e);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import com.cloud.storage.StorageManager;
|
|||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class ScaleIOHostListener implements HypervisorHostListener {
|
||||
|
|
@ -90,9 +91,11 @@ public class ScaleIOHostListener implements HypervisorHostListener {
|
|||
private boolean isHostSdcConnected(String hostIpAddress, long poolId) {
|
||||
try {
|
||||
Map<String, String> dataStoreDetails = _primaryDataStoreDao.getDetails(poolId);
|
||||
String url = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
String username = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
String password = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
final String url = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT);
|
||||
final String encryptedUsername = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_USERNAME);
|
||||
final String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
final String encryptedPassword = dataStoreDetails.get(ScaleIOGatewayClient.GATEWAY_API_PASSWORD);
|
||||
final String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(poolId);
|
||||
ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout);
|
||||
return client.isSdcConnected(hostIpAddress);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ import com.cloud.storage.StoragePoolHostVO;
|
|||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@PrepareForTest(ScaleIOGatewayClient.class)
|
||||
|
|
@ -136,13 +137,17 @@ public class ScaleIOPrimaryDataStoreLifeCycleTest {
|
|||
|
||||
Map <String, String> mockDataStoreDetails = new HashMap<>();
|
||||
mockDataStoreDetails.put(ScaleIOGatewayClient.GATEWAY_API_ENDPOINT, "https://192.168.1.19/api");
|
||||
mockDataStoreDetails.put(ScaleIOGatewayClient.GATEWAY_API_USERNAME, "root");
|
||||
mockDataStoreDetails.put(ScaleIOGatewayClient.GATEWAY_API_PASSWORD, "Password@123");
|
||||
String encryptedUsername = DBEncryptionUtil.encrypt("root");
|
||||
mockDataStoreDetails.put(ScaleIOGatewayClient.GATEWAY_API_USERNAME, encryptedUsername);
|
||||
String encryptedPassword = DBEncryptionUtil.encrypt("Password@123");
|
||||
mockDataStoreDetails.put(ScaleIOGatewayClient.GATEWAY_API_PASSWORD, encryptedPassword);
|
||||
when(primaryDataStoreDao.getDetails(1L)).thenReturn(mockDataStoreDetails);
|
||||
|
||||
PowerMockito.mockStatic(ScaleIOGatewayClient.class);
|
||||
ScaleIOGatewayClientImpl client = mock(ScaleIOGatewayClientImpl.class);
|
||||
when(ScaleIOGatewayClient.getClient("https://192.168.1.19/api", "root", "Password@123", false, 60)).thenReturn(client);
|
||||
String username = DBEncryptionUtil.decrypt(encryptedUsername);
|
||||
String password = DBEncryptionUtil.decrypt(encryptedPassword);
|
||||
when(ScaleIOGatewayClient.getClient("https://192.168.1.19/api", username, password, false, 60)).thenReturn(client);
|
||||
|
||||
List<String> connectedSdcIps = new ArrayList<>();
|
||||
connectedSdcIps.add("192.168.1.1");
|
||||
|
|
|
|||
Loading…
Reference in New Issue