Merge branch 'main' into cks-enhancements-upstream

This commit is contained in:
nvazquez 2025-04-25 07:42:45 -03:00
commit a9bc998d1a
No known key found for this signature in database
GPG Key ID: 656E1BCC8CB54F84
87 changed files with 1119 additions and 488 deletions

View File

@ -59,6 +59,7 @@ github:
- nicoschmdt
- abh1sar
- sudo87
- rosi-shapeblue
protected_branches: ~

View File

@ -236,7 +236,7 @@ jobs:
- name: Install Python dependencies
run: |
python3 -m pip install --user --upgrade urllib3 lxml paramiko nose texttable ipmisim pyopenssl pycrypto mock flask netaddr pylint pycodestyle six astroid
python3 -m pip install --user --upgrade urllib3 lxml paramiko nose texttable ipmisim pyopenssl pycrypto mock flask netaddr pylint pycodestyle six astroid pynose
- name: Install jacoco dependencies
run: |

View File

@ -17,6 +17,7 @@
package com.cloud.storage;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.InternalIdentity;
@ -25,6 +26,8 @@ public interface VMTemplateStorageResourceAssoc extends InternalIdentity {
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
}
List<Status> PENDING_DOWNLOAD_STATES = List.of(Status.NOT_DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
String getInstallPath();
long getTemplateId();

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.user.iso;
import com.cloud.dc.DataCenter;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
@ -101,7 +102,15 @@ public class ExtractIsoCmd extends BaseAsyncCmd {
@Override
public String getEventDescription() {
return "extracting ISO: " + getId() + " from zone: " + getZoneId();
String isoId = this._uuidMgr.getUuid(VirtualMachineTemplate.class, getId());
String baseDescription = String.format("Extracting ISO: %s", isoId);
Long zoneId = getZoneId();
if (zoneId == null) {
return baseDescription;
}
return String.format("%s from zone: %s", baseDescription, this._uuidMgr.getUuid(DataCenter.class, zoneId));
}
@Override

View File

@ -101,7 +101,15 @@ public class ExtractTemplateCmd extends BaseAsyncCmd {
@Override
public String getEventDescription() {
return "extracting template: " + this._uuidMgr.getUuid(VirtualMachineTemplate.class, getId()) + ((getZoneId() != null) ? " from zone: " + this._uuidMgr.getUuid(DataCenter.class, getZoneId()) : "");
String templateId = this._uuidMgr.getUuid(VirtualMachineTemplate.class, getId());
String baseDescription = String.format("Extracting template: %s", templateId);
Long zoneId = getZoneId();
if (zoneId == null) {
return baseDescription;
}
return String.format("%s from zone: %s", baseDescription, this._uuidMgr.getUuid(DataCenter.class, zoneId));
}
@Override

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.user.volume;
import com.cloud.dc.DataCenter;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
@ -114,12 +115,15 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
@Override
public String getEventDescription() {
return "Extraction job";
String volumeId = this._uuidMgr.getUuid(Volume.class, getId());
String zoneId = this._uuidMgr.getUuid(DataCenter.class, getZoneId());
return String.format("Extracting volume: %s from zone: %s", volumeId, zoneId);
}
@Override
public void execute() {
CallContext.current().setEventDetails("Volume Id: " + this._uuidMgr.getUuid(Volume.class, getId()));
CallContext.current().setEventDetails(getEventDescription());
String uploadUrl = _volumeService.extractVolume(this);
if (uploadUrl != null) {
ExtractResponse response = _responseGenerator.createVolumeExtractResponse(id, zoneId, getEntityOwnerId(), mode, uploadUrl);

View File

@ -44,7 +44,7 @@ public class PurgeExpungedResourcesCmdTest {
@Spy
@InjectMocks
PurgeExpungedResourcesCmd spyCmd = Mockito.spy(new PurgeExpungedResourcesCmd());
PurgeExpungedResourcesCmd spyCmd;
@Test
public void testGetResourceType() {

View File

@ -20,14 +20,11 @@ package org.apache.cloudstack.api.command.admin.storage;
import com.cloud.utils.Pair;
import org.apache.cloudstack.api.response.ExtractResponse;
import org.apache.cloudstack.storage.browser.StorageBrowser;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
@ -48,18 +45,6 @@ public class DownloadImageStoreObjectCmdTest {
@Spy
private DownloadImageStoreObjectCmd cmd;
private AutoCloseable closeable;
@Before
public void setUp() {
closeable = MockitoAnnotations.openMocks(this);
}
@After
public void tearDown() throws Exception {
closeable.close();
}
@Test
public void testExecute() throws Exception {
ReflectionTestUtils.setField(cmd, "storeId", 1L);

View File

@ -68,6 +68,12 @@ public class MigrateVirtualMachineWithVolumeCmdTest {
@Mock
Host hostMock;
@Mock
private Object job;
@Mock
private Object _responseObject;
@Spy
@InjectMocks
MigrateVirtualMachineWithVolumeCmd cmdSpy;

View File

@ -20,7 +20,6 @@ package org.apache.cloudstack.api.command.admin.vpc;
import com.cloud.network.vpc.VpcService;
import com.cloud.user.AccountService;
import com.cloud.utils.db.EntityManager;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ResponseGenerator;
import org.junit.Assert;
import org.junit.Test;
@ -34,7 +33,7 @@ import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class CreateVPCCmdByAdminTest extends TestCase {
public class CreateVPCCmdByAdminTest {
@Mock
public VpcService _vpcService;
@ -43,8 +42,10 @@ public class CreateVPCCmdByAdminTest extends TestCase {
@Mock
public AccountService _accountService;
private ResponseGenerator responseGenerator;
@Mock
public Object job;
@InjectMocks
CreateVPCCmdByAdmin cmd = new CreateVPCCmdByAdmin();
CreateVPCCmdByAdmin cmd;
@Test
public void testBgpPeerIds() {

View File

@ -41,7 +41,10 @@ public class UpdateNetworkCmdTest {
NetworkService networkService;
@Mock
public EntityManager _entityMgr;
private ResponseGenerator responseGenerator;
@Mock
private ResponseGenerator _responseGenerator;
@Mock
private Object job;
@InjectMocks
UpdateNetworkCmd cmd = new UpdateNetworkCmd();
@ -176,15 +179,13 @@ public class UpdateNetworkCmdTest {
ReflectionTestUtils.setField(cmd, "id", networkId);
ReflectionTestUtils.setField(cmd, "publicMtu", publicmtu);
Network network = Mockito.mock(Network.class);
responseGenerator = Mockito.mock(ResponseGenerator.class);
NetworkResponse response = Mockito.mock(NetworkResponse.class);
response.setPublicMtu(publicmtu);
Mockito.when(networkService.getNetwork(networkId)).thenReturn(network);
Mockito.when(networkService.updateGuestNetwork(cmd)).thenReturn(network);
cmd._responseGenerator = responseGenerator;
Mockito.when(responseGenerator.createNetworkResponse(ResponseObject.ResponseView.Restricted, network)).thenReturn(response);
Mockito.when(_responseGenerator.createNetworkResponse(ResponseObject.ResponseView.Restricted, network)).thenReturn(response);
cmd.execute();
Mockito.verify(responseGenerator).createNetworkResponse(Mockito.any(ResponseObject.ResponseView.class), Mockito.any(Network.class));
Mockito.verify(_responseGenerator).createNetworkResponse(Mockito.any(ResponseObject.ResponseView.class), Mockito.any(Network.class));
NetworkResponse actualResponse = (NetworkResponse) cmd.getResponseObject();
Assert.assertEquals(response, actualResponse);

View File

@ -25,7 +25,6 @@ import com.cloud.network.vpc.Vpc;
import com.cloud.network.vpc.VpcService;
import com.cloud.user.AccountService;
import com.cloud.utils.db.EntityManager;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.response.VpcResponse;
@ -39,7 +38,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
@RunWith(MockitoJUnitRunner.class)
public class CreateVPCCmdTest extends TestCase {
public class CreateVPCCmdTest {
@Mock
public VpcService _vpcService;
@ -47,9 +46,13 @@ public class CreateVPCCmdTest extends TestCase {
public EntityManager _entityMgr;
@Mock
public AccountService _accountService;
private ResponseGenerator responseGenerator;
@Mock
private ResponseGenerator _responseGenerator;
@Mock
private Object job;
@InjectMocks
CreateVPCCmd cmd = new CreateVPCCmd();
CreateVPCCmd cmd;
@Test
public void testGetAccountName() {
@ -185,11 +188,9 @@ public class CreateVPCCmdTest extends TestCase {
VpcResponse response = Mockito.mock(VpcResponse.class);
ReflectionTestUtils.setField(cmd, "id", 1L);
responseGenerator = Mockito.mock(ResponseGenerator.class);
Mockito.doNothing().when(_vpcService).startVpc(cmd);
Mockito.when(_entityMgr.findById(Mockito.eq(Vpc.class), Mockito.any(Long.class))).thenReturn(vpc);
cmd._responseGenerator = responseGenerator;
Mockito.when(responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, vpc)).thenReturn(response);
Mockito.when(_responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, vpc)).thenReturn(response);
cmd.execute();
Mockito.verify(_vpcService, Mockito.times(1)).startVpc(cmd);
}

View File

@ -5240,10 +5240,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
workJob = newVmWorkJobAndInfo.first();
VmWorkMigrateAway workInfo = new VmWorkMigrateAway(newVmWorkJobAndInfo.second(), srcHostId);
workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
setCmdInfoAndSubmitAsyncJob(workJob, workInfo, vmId);
}
_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vmId);
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId());

View File

@ -208,9 +208,7 @@ public class DataMigrationUtility {
List<TemplateInfo> files = new LinkedList<>();
for (TemplateDataStoreVO template : templates) {
VMTemplateVO templateVO = templateDao.findById(template.getTemplateId());
if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && templateVO != null &&
(!templateVO.isPublicTemplate() || (templateVO.isPublicTemplate() && templateVO.getUrl() == null)) &&
templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator && templateVO.getParentTemplateId() == null) {
if (shouldMigrateTemplate(template, templateVO)) {
files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore));
}
}
@ -231,6 +229,34 @@ public class DataMigrationUtility {
return getAllReadyTemplates(srcDataStore, childTemplates, templates);
}
/**
* Returns whether a template should be migrated. A template should be migrated if:
* <ol>
* <li>its state is ready, and</li>
* <li>its hypervisor type is not simulator, and</li>
* <li>it is not a child template.</li>
* </ol>
*/
protected boolean shouldMigrateTemplate(TemplateDataStoreVO template, VMTemplateVO templateVO) {
if (template.getState() != State.Ready) {
logger.debug("Template [{}] should not be migrated as it is not ready.", template);
return false;
}
if (templateVO.getHypervisorType() == Hypervisor.HypervisorType.Simulator) {
logger.debug("Template [{}] should not be migrated as its hypervisor type is simulator.", template);
return false;
}
if (templateVO.getParentTemplateId() != null) {
logger.debug("Template [{}] should not be migrated as it has a parent template.", template);
return false;
}
logger.debug("Template [{}] should be migrated.", template);
return true;
}
/** Returns parent snapshots and snapshots that do not have any children; snapshotChains comprises of the snapshot chain info
* for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
* are migrated to the same datastore

View File

@ -0,0 +1,88 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.engine.orchestration;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.VMTemplateVO;
import junit.framework.TestCase;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class DataMigrationUtilityTest extends TestCase {
@Spy
private DataMigrationUtility dataMigrationUtility;
@Mock
private VMTemplateVO templateVoMock;
@Mock
private TemplateDataStoreVO templateDataStoreVoMock;
private void prepareForShouldMigrateTemplateTests() {
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
Mockito.when(templateVoMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
Mockito.when(templateVoMock.getParentTemplateId()).thenReturn(null);
}
@Test
public void shouldMigrateTemplateTestReturnsFalseWhenTemplateIsNotReady() {
prepareForShouldMigrateTemplateTests();
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Migrating);
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
Assert.assertFalse(result);
}
@Test
public void shouldMigrateTemplateTestReturnsFalseWhenHypervisorTypeIsSimulator() {
prepareForShouldMigrateTemplateTests();
Mockito.when(templateVoMock.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.Simulator);
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
Assert.assertFalse(result);
}
@Test
public void shouldMigrateTemplateTestReturnsFalseWhenTemplateHasParentTemplate() {
prepareForShouldMigrateTemplateTests();
Mockito.when(templateVoMock.getParentTemplateId()).thenReturn(1L);
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
Assert.assertFalse(result);
}
@Test
public void shouldMigrateTemplateTestReturnsTrueWhenTemplateIsReadyAndDoesNotHaveParentTemplateAndHypervisorTypeIsNotSimulator() {
prepareForShouldMigrateTemplateTests();
boolean result = dataMigrationUtility.shouldMigrateTemplate(templateDataStoreVoMock, templateVoMock);
Assert.assertTrue(result);
}
}

View File

@ -503,7 +503,7 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
@Override
public String toString() {
return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type"));
return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type", "state"));
}
@Override

View File

@ -47,3 +47,25 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.storage_pool', 'used_iops', 'bigint
-- Add reason column for op_ha_work
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.op_ha_work', 'reason', 'varchar(32) DEFAULT NULL COMMENT "Reason for the HA work"');
-- Grant access to 2FA APIs for the "Read-Only User - Default" role
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Read-Only User - Default', 'setupUserTwoFactorAuthentication', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Read-Only User - Default', 'validateUserTwoFactorAuthenticationCode', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Read-Only User - Default', 'listUserTwoFactorAuthenticatorProviders', 'ALLOW');
-- Grant access to 2FA APIs for the "Support User - Default" role
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Support User - Default', 'setupUserTwoFactorAuthentication', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Support User - Default', 'validateUserTwoFactorAuthenticationCode', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Support User - Default', 'listUserTwoFactorAuthenticatorProviders', 'ALLOW');
-- Grant access to 2FA APIs for the "Read-Only Admin - Default" role
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Read-Only Admin - Default', 'setupUserTwoFactorAuthentication', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Read-Only Admin - Default', 'validateUserTwoFactorAuthenticationCode', 'ALLOW');
-- Grant access to 2FA APIs for the "Support Admin - Default" role
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Support Admin - Default', 'setupUserTwoFactorAuthentication', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Support Admin - Default', 'validateUserTwoFactorAuthenticationCode', 'ALLOW');

View File

@ -24,6 +24,9 @@ import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.download.DownloadListener;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
@ -118,26 +121,21 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
}
} else if (srcDataObject instanceof TemplateInfo && templateChain != null && templateChain.containsKey(srcDataObject)) {
for (TemplateInfo templateInfo : templateChain.get(srcDataObject).first()) {
if (templateIsOnDestination(templateInfo, destDatastore)) {
res.setResult("Template already exists on destination.");
res.setSuccess(true);
logger.debug("Deleting template {} from source data store [{}].", srcDataObject.getTO().toString(),
srcDataObject.getDataStore().getTO().toString());
srcDataObject.getDataStore().delete(srcDataObject);
future.complete(res);
continue;
}
destDataObject = destDatastore.create(templateInfo);
templateInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
migrateJob(future, templateInfo, destDataObject, destDatastore);
}
}
else {
// Check if template in destination store, if yes, do not proceed
if (srcDataObject instanceof TemplateInfo) {
logger.debug("Checking if template present at destination");
TemplateDataStoreVO templateStoreVO = templateStoreDao.findByStoreTemplate(destDatastore.getId(), srcDataObject.getId());
if (templateStoreVO != null) {
String msg = "Template already exists in destination store";
logger.debug(msg);
res.setResult(msg);
res.setSuccess(true);
future.complete(res);
return future;
}
}
} else {
destDataObject = destDatastore.create(srcDataObject);
srcDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
@ -160,6 +158,69 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
return future;
}
/**
* Returns a boolean indicating whether a template is ready on the provided data store. If the template is being downloaded,
* waits until the download finishes.
* @param srcDataObject the template.
* @param destDatastore the data store.
*/
protected boolean templateIsOnDestination(DataObject srcDataObject, DataStore destDatastore) {
if (!(srcDataObject instanceof TemplateInfo)) {
return false;
}
String templateAsString = srcDataObject.getTO().toString();
String destDatastoreAsString = destDatastore.getTO().toString();
TemplateDataStoreVO templateStoreVO;
long timer = getTemplateDownloadTimeout();
long msToSleep = 10000L;
int previousDownloadPercentage = -1;
while (true) {
templateStoreVO = templateStoreDao.findByStoreTemplate(destDatastore.getId(), srcDataObject.getId());
if (templateStoreVO == null) {
logger.debug("{} is not present at destination [{}].", templateAsString, destDatastoreAsString);
return false;
}
VMTemplateStorageResourceAssoc.Status downloadState = templateStoreVO.getDownloadState();
if (downloadState == null || !VMTemplateStorageResourceAssoc.PENDING_DOWNLOAD_STATES.contains(downloadState)) {
break;
}
if (previousDownloadPercentage == templateStoreVO.getDownloadPercent()) {
timer -= msToSleep;
} else {
timer = getTemplateDownloadTimeout();
}
if (timer <= 0) {
throw new CloudRuntimeException(String.format("Timeout while waiting for %s to be downloaded to image store [%s]. " +
"The download percentage has not changed for %d milliseconds.", templateAsString, destDatastoreAsString, getTemplateDownloadTimeout()));
}
waitForTemplateDownload(msToSleep, templateAsString, destDatastoreAsString);
}
if (templateStoreVO.getState() == ObjectInDataStoreStateMachine.State.Ready) {
logger.debug("{} already exists on destination [{}].", templateAsString, destDatastoreAsString);
return true;
}
return false;
}
protected long getTemplateDownloadTimeout() {
return DownloadListener.DOWNLOAD_TIMEOUT;
}
protected void waitForTemplateDownload(long msToSleep, String templateAsString, String destDatastoreAsString) {
logger.debug("{} is being downloaded to destination [{}]; we will verify in {} milliseconds if the download has finished.",
templateAsString, destDatastoreAsString, msToSleep);
try {
Thread.sleep(msToSleep);
} catch (InterruptedException e) {
logger.warn("[ignored] interrupted while waiting for template {} download to finish before trying to migrate it to data store [{}].",
templateAsString, destDatastoreAsString);
}
}
protected void migrateJob(AsyncCallFuture<DataObjectResult> future, DataObject srcDataObject, DataObject destDataObject, DataStore destDatastore) throws ExecutionException, InterruptedException {
MigrateDataContext<DataObjectResult> context = new MigrateDataContext<DataObjectResult>(null, future, srcDataObject, destDataObject, destDatastore);
AsyncCallbackDispatcher<SecondaryStorageServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);

View File

@ -0,0 +1,138 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.image;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.utils.exception.CloudRuntimeException;
import junit.framework.TestCase;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SecondaryStorageServiceImplTest extends TestCase {
@Spy
@InjectMocks
private SecondaryStorageServiceImpl secondaryStorageService;
@Mock
TemplateDataStoreDao templateDataStoreDaoMock;
@Mock
TemplateDataStoreVO templateDataStoreVoMock;
@Mock
TemplateInfo templateInfoMock;
@Mock
TemplateObjectTO templateObjectToMock;
@Mock
DataStore dataStoreMock;
@Mock
DataStoreTO dataStoreToMock;
private void prepareForTemplateIsOnDestinationTests() {
long dataStoreId = 1;
long templateId = 2;
Mockito.when(dataStoreMock.getId()).thenReturn(dataStoreId);
Mockito.when(dataStoreMock.getTO()).thenReturn(dataStoreToMock);
Mockito.when(templateInfoMock.getId()).thenReturn(templateId);
Mockito.when(templateInfoMock.getTO()).thenReturn(templateObjectToMock);
Mockito.doReturn(templateDataStoreVoMock).when(templateDataStoreDaoMock).findByStoreTemplate(dataStoreId, templateId);
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
}
@Test
public void templateIsOnDestinationTestReturnsFalseWhenTemplateStoreRefDoesNotExist() {
prepareForTemplateIsOnDestinationTests();
Mockito.doReturn(null).when(templateDataStoreDaoMock).findByStoreTemplate(Mockito.anyLong(), Mockito.anyLong());
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
Assert.assertFalse(result);
}
@Test
public void templateIsOnDestinationTestReturnsTrueWhenTemplateIsReady() {
prepareForTemplateIsOnDestinationTests();
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
Assert.assertTrue(result);
}
@Test
public void templateIsOnDestinationTestReturnsFalseWhenTemplateIsNotReady() {
prepareForTemplateIsOnDestinationTests();
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Creating);
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
Assert.assertFalse(result);
}
@Test
public void templateIsOnDestinationTestReturnsTrueIfTemplateIsDownloadedSuccessfully() {
prepareForTemplateIsOnDestinationTests();
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
Mockito.doAnswer(I -> Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).when(secondaryStorageService).waitForTemplateDownload(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString());
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
Assert.assertTrue(result);
}
@Test
public void templateIsOnDestinationTestReturnsFalseIfTemplateIsNotDownloadedSuccessfully() {
prepareForTemplateIsOnDestinationTests();
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
Mockito.doAnswer(I -> {
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR);
Mockito.when(templateDataStoreVoMock.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Failed);
return "mocked download fail";
}).when(secondaryStorageService).waitForTemplateDownload(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString());
boolean result = secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
Assert.assertFalse(result);
}
@Test(expected = CloudRuntimeException.class)
public void templateIsOnDestinationTestThrowsExceptionIfDownloadTimesOut() {
prepareForTemplateIsOnDestinationTests();
Mockito.when(templateDataStoreVoMock.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
Mockito.doReturn(0L).when(secondaryStorageService).getTemplateDownloadTimeout();
secondaryStorageService.templateIsOnDestination(templateInfoMock, dataStoreMock);
}
}

View File

@ -73,8 +73,8 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
private static final int EXECUTOR_SHUTDOWN_TIMEOUT = 1000; // 1 second
private static final int DEFAULT_OUTGOING_WORKERS = 5;
private final List<ClusterManagerListener> _listeners = new ArrayList<ClusterManagerListener>();
private final Map<Long, ManagementServerHostVO> _activePeers = new HashMap<Long, ManagementServerHostVO>();
private final List<ClusterManagerListener> _listeners = new ArrayList<>();
private final Map<Long, ManagementServerHostVO> _activePeers = new HashMap<>();
private final Map<String, ClusterService> _clusterPeers;
@ -83,7 +83,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
private final ScheduledExecutorService _heartbeatScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Cluster-Heartbeat"));
private final ExecutorService _notificationExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("Cluster-Notification"));
private final List<ClusterManagerMessage> _notificationMsgs = new ArrayList<ClusterManagerMessage>();
private final List<ClusterManagerMessage> _notificationMsgs = new ArrayList<>();
private ConnectionConcierge _heartbeatConnection = null;
private final ExecutorService _executor;
@ -118,12 +118,12 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
private String _clusterNodeIP = "127.0.0.1";
private final List<ClusterServicePdu> _clusterPduOutgoingQueue = new ArrayList<ClusterServicePdu>();
private final List<ClusterServicePdu> _clusterPduIncomingQueue = new ArrayList<ClusterServicePdu>();
private final Map<Long, ClusterServiceRequestPdu> _outgoingPdusWaitingForAck = new HashMap<Long, ClusterServiceRequestPdu>();
private final List<ClusterServicePdu> _clusterPduOutgoingQueue = new ArrayList<>();
private final List<ClusterServicePdu> _clusterPduIncomingQueue = new ArrayList<>();
private final Map<Long, ClusterServiceRequestPdu> _outgoingPdusWaitingForAck = new HashMap<>();
public ClusterManagerImpl() {
_clusterPeers = new HashMap<String, ClusterService>();
_clusterPeers = new HashMap<>();
// executor to perform remote-calls in another thread context, to avoid potential
// recursive remote calls between nodes
@ -161,7 +161,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
}
private void cancelClusterRequestToPeer(final String strPeer) {
final List<ClusterServiceRequestPdu> candidates = new ArrayList<ClusterServiceRequestPdu>();
final List<ClusterServiceRequestPdu> candidates = new ArrayList<>();
synchronized (_outgoingPdusWaitingForAck) {
for (final Map.Entry<Long, ClusterServiceRequestPdu> entry : _outgoingPdusWaitingForAck.entrySet()) {
if (entry.getValue().getDestPeer().equalsIgnoreCase(strPeer)) {
@ -193,7 +193,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
synchronized (_clusterPduOutgoingQueue) {
try {
_clusterPduOutgoingQueue.wait(timeoutMs);
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
if (_clusterPduOutgoingQueue.size() > 0) {
@ -216,7 +216,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
synchronized (_clusterPduIncomingQueue) {
try {
_clusterPduIncomingQueue.wait(timeoutMs);
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
if (_clusterPduIncomingQueue.size() > 0) {
@ -449,7 +449,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
synchronized (pdu) {
try {
pdu.wait();
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
}
@ -620,8 +620,8 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
if (profiler.getDurationInMillis() >= HeartbeatInterval.value()) {
if (logger.isDebugEnabled()) {
logger.debug("Management server heartbeat takes too long to finish. profiler: " + profiler.toString() + ", profilerHeartbeatUpdate: " +
profilerHeartbeatUpdate.toString() + ", profilerPeerScan: " + profilerPeerScan.toString());
logger.debug("Management server heartbeat takes too long to finish. profiler: " + profiler + ", profilerHeartbeatUpdate: " +
profilerHeartbeatUpdate + ", profilerPeerScan: " + profilerPeerScan);
}
}
}
@ -685,7 +685,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
synchronized (_notificationMsgs) {
try {
_notificationMsgs.wait(1000);
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
}
@ -745,7 +745,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
try {
Thread.sleep(1000);
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
}
}
@ -816,7 +816,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
}
}
final List<ManagementServerHostVO> downHostList = new ArrayList<ManagementServerHostVO>();
final List<ManagementServerHostVO> downHostList = new ArrayList<>();
for (final ManagementServerHostVO host : inactiveList) {
// Check if peer state is Up in the period
if (!_mshostPeerDao.isPeerUpState(_mshostId, host.getId(), new Date(cutTime.getTime() - HeartbeatThreshold.value()))) {
@ -846,8 +846,8 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
final Profiler profilerSyncClusterInfo = new Profiler();
profilerSyncClusterInfo.start();
final List<ManagementServerHostVO> removedNodeList = new ArrayList<ManagementServerHostVO>();
final List<ManagementServerHostVO> invalidatedNodeList = new ArrayList<ManagementServerHostVO>();
final List<ManagementServerHostVO> removedNodeList = new ArrayList<>();
final List<ManagementServerHostVO> invalidatedNodeList = new ArrayList<>();
if (_mshostId != null) {
@ -941,7 +941,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
try {
JmxUtil.unregisterMBean("ClusterManager", "Node " + mshost.getId());
} catch (final Exception e) {
logger.warn("Unable to deregister cluster node from JMX monitoring due to exception " + e.toString());
logger.warn("Unable to deregister cluster node from JMX monitoring due to exception " + e);
}
}
@ -961,7 +961,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
try {
JmxUtil.unregisterMBean("ClusterManager", "Node " + mshost.getId());
} catch (final Exception e) {
logger.warn("Unable to deregiester cluster node from JMX monitoring due to exception " + e.toString());
logger.warn("Unable to deregiester cluster node from JMX monitoring due to exception " + e);
}
} else {
logger.info("Management node {} is detected inactive by timestamp but sent node status to this node", mshost);
@ -975,7 +975,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
}
private void processNewNodes(Date cutTime, List<ManagementServerHostVO> currentList) {
final List<ManagementServerHostVO> newNodeList = new ArrayList<ManagementServerHostVO>();
final List<ManagementServerHostVO> newNodeList = new ArrayList<>();
for (final ManagementServerHostVO mshost : currentList) {
if (!_activePeers.containsKey(mshost.getId())) {
_activePeers.put(mshost.getId(), mshost);
@ -1037,7 +1037,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
logger.info("Starting Cluster manager, msid: {}, mshost: {}", _msId, _mshost);
}
final ManagementServerHostVO mshost = Transaction.execute(new TransactionCallback<ManagementServerHostVO>() {
final ManagementServerHostVO mshost = Transaction.execute(new TransactionCallback<>() {
@Override
public ManagementServerHostVO doInTransaction(final TransactionStatus status) {
@ -1105,11 +1105,13 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
}
if (_mshostId != null) {
final ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId);
ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId);
if (mshost != null) {
ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid());
if (mshostStatus != null) {
mshost.setState(ManagementServerHost.State.Down);
mshostStatus.setLastJvmStop(new Date());
_mshostDao.update(_mshostId, mshost);
mshostStatusDao.update(mshostStatus.getId(), mshostStatus);
} else {
logger.warn("Found a management server host [{}] without a status. This should never happen!", mshost);
@ -1135,7 +1137,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
try {
_heartbeatScheduler.awaitTermination(EXECUTOR_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS);
_executor.awaitTermination(EXECUTOR_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (final InterruptedException e) {
} catch (final InterruptedException ignored) {
}
if (logger.isInfoEnabled()) {
@ -1271,14 +1273,14 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
if (sch != null) {
try {
sch.close();
} catch (final IOException e) {
} catch (final IOException ignored) {
}
}
}
try {
Thread.sleep(1000);
} catch (final InterruptedException ex) {
} catch (final InterruptedException ignored) {
}
}

View File

@ -94,15 +94,17 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
return suitableHosts;
}
String offeringHostTag = offering.getHostTag();
VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
String templateTag = template.getTemplateTag();
String hostTag = null;
if (ObjectUtils.anyNull(offeringHostTag, templateTag)) {
hostTag = offeringHostTag;
hostTag = hostTag == null ? templateTag : String.format("%s, %s", hostTag, templateTag);
logger.debug(String.format("Looking for hosts in dc [%s], pod [%s], cluster [%s] and complying with host tag(s): [%s]", dcId, podId, clusterId, hostTag));
if (ObjectUtils.anyNotNull(offeringHostTag, templateTag)) {
hostTag = ObjectUtils.allNotNull(offeringHostTag, templateTag) ?
String.format("%s, %s", offeringHostTag, templateTag) :
ObjectUtils.firstNonNull(offeringHostTag, templateTag);
logger.debug("Looking for hosts in dc [{}], pod [{}], cluster [{}] and complying with host tag(s): [{}]", dcId, podId, clusterId, hostTag);
} else {
logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
logger.debug("Looking for hosts in dc: {} pod: {} cluster: {}", dcId , podId, clusterId);
}
if (hosts != null) {
// retain all computing hosts, regardless of whether they support routing...it's random after all

View File

@ -704,7 +704,7 @@ public class LibvirtMigrateCommandWrapperTest {
@Test
public void deleteOrDisconnectDisksOnSourcePoolTest() {
LibvirtMigrateCommandWrapper spyLibvirtMigrateCmdWrapper = Mockito.spy(libvirtMigrateCmdWrapper);
LibvirtMigrateCommandWrapper spyLibvirtMigrateCmdWrapper = libvirtMigrateCmdWrapper;
Mockito.doNothing().when(spyLibvirtMigrateCmdWrapper).deleteLocalVolume("volPath");
List<MigrateDiskInfo> migrateDiskInfoList = new ArrayList<>();

View File

@ -32,6 +32,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.agent.api.to.DataStoreTO;
@ -42,7 +43,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
@RunWith(MockitoJUnitRunner.class)
public class LibvirtRevertSnapshotCommandWrapperTest {
LibvirtRevertSnapshotCommandWrapper libvirtRevertSnapshotCommandWrapperSpy = Mockito.spy(LibvirtRevertSnapshotCommandWrapper.class);
@Spy
LibvirtRevertSnapshotCommandWrapper libvirtRevertSnapshotCommandWrapperSpy;
@Mock
KVMStoragePool kvmStoragePoolPrimaryMock;
@ -107,7 +109,7 @@ public class LibvirtRevertSnapshotCommandWrapperTest {
Mockito.doReturn(snapshotPath).when(snapshotObjectToPrimaryMock).getPath();
try (MockedStatic<Files> ignored = Mockito.mockStatic(Files.class)) {
Mockito.when(Files.exists(Mockito.any(Path.class), Mockito.any())).thenReturn(true);
Mockito.when(Files.exists(Mockito.any(Path.class))).thenReturn(true);
Pair<String, SnapshotObjectTO> result = libvirtRevertSnapshotCommandWrapperSpy.getSnapshot(
snapshotObjectToPrimaryMock, snapshotObjectToSecondaryMock,

View File

@ -5104,9 +5104,9 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
answer.setVolumeChainInfo(chainInfo);
return answer;
} catch (Exception e) {
String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.getMessage();
logger.error(msg, e);
return new MigrateVolumeAnswer(cmd, false, msg, null);
return new MigrateVolumeAnswer(cmd, false, e.getMessage(), null);
}
}

View File

@ -260,7 +260,7 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy {
} else {
answer = agentMgr.sendTo(sourcePool.getDataCenterId(), HypervisorType.VMware, cmd);
}
updateVolumeAfterMigration(answer, srcData, destData);
handleAnswerAndUpdateVolumeAfterMigration(answer, srcData, destData);
CopyCommandResult result = new CopyCommandResult(null, answer);
callback.complete(result);
}
@ -286,21 +286,19 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy {
return hostId;
}
private void updateVolumeAfterMigration(Answer answer, DataObject srcData, DataObject destData) {
private void handleAnswerAndUpdateVolumeAfterMigration(Answer answer, DataObject srcData, DataObject destData) {
VolumeVO destinationVO = volDao.findById(destData.getId());
if (!(answer instanceof MigrateVolumeAnswer)) {
// OfflineVmwareMigration: reset states and such
VolumeVO sourceVO = volDao.findById(srcData.getId());
sourceVO.setState(Volume.State.Ready);
volDao.update(sourceVO.getId(), sourceVO);
if (destinationVO.getId() != sourceVO.getId()) {
destinationVO.setState(Volume.State.Expunged);
destinationVO.setRemoved(new Date());
volDao.update(destinationVO.getId(), destinationVO);
}
resetVolumeState(srcData, destinationVO);
throw new CloudRuntimeException("unexpected answer from hypervisor agent: " + answer.getDetails());
}
MigrateVolumeAnswer ans = (MigrateVolumeAnswer) answer;
if (!answer.getResult()) {
String msg = "Unable to migrate volume: " + srcData.getName() + " due to " + answer.getDetails();
resetVolumeState(srcData, destinationVO);
throw new CloudRuntimeException(msg);
}
if (logger.isDebugEnabled()) {
String format = "retrieved '%s' as new path for volume(%d)";
logger.debug(String.format(format, ans.getVolumePath(), destData.getId()));
@ -311,6 +309,17 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy {
volDao.update(destinationVO.getId(), destinationVO);
}
private void resetVolumeState(DataObject srcData, VolumeVO destinationVO) {
VolumeVO sourceVO = volDao.findById(srcData.getId());
sourceVO.setState(Volume.State.Ready);
volDao.update(sourceVO.getId(), sourceVO);
if (destinationVO.getId() != sourceVO.getId()) {
destinationVO.setState(Volume.State.Expunged);
destinationVO.setRemoved(new Date());
volDao.update(destinationVO.getId(), destinationVO);
}
}
@Override
public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;

View File

@ -69,6 +69,8 @@ public class VmwareManagerImplTest {
private Map<String, String> clusterDetails;
@Mock
private Map<String, String> hostDetails;
@Mock
private Map<String, Object> _configParams;
@Before
public void beforeTest() {

View File

@ -41,6 +41,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.ScaleVmAnswer;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.HostDatastoreBrowserMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
@ -52,7 +54,6 @@ import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsAnswer;
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsCommand;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -62,17 +63,14 @@ import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CheckGuestOsMappingAnswer;
import com.cloud.agent.api.CheckGuestOsMappingCommand;
import com.cloud.agent.api.GetHypervisorGuestOsNamesAnswer;
import com.cloud.agent.api.GetHypervisorGuestOsNamesCommand;
import com.cloud.agent.api.ScaleVmAnswer;
import com.cloud.agent.api.ScaleVmCommand;
import com.cloud.agent.api.routing.GetAutoScaleMetricsAnswer;
import com.cloud.agent.api.routing.GetAutoScaleMetricsCommand;
@ -185,6 +183,8 @@ public class VmwareResourceTest {
VimPortType vimService;
@Mock
HostCapability hostCapability;
@Mock
ManagedObjectReference _morHyperHost;
CopyCommand storageCmd;
EnumMap<VmwareStorageProcessorConfigurableFields, Object> params = new EnumMap<VmwareStorageProcessorConfigurableFields,Object>(VmwareStorageProcessorConfigurableFields.class);
@ -201,11 +201,9 @@ public class VmwareResourceTest {
private Map<String,String> specsArray = new HashMap<String,String>();
AutoCloseable closeable;
@Before
public void setup() throws Exception {
closeable = MockitoAnnotations.openMocks(this);
storageCmd = mock(CopyCommand.class);
doReturn(context).when(_resource).getServiceContext(null);
when(cmd.getVirtualMachine()).thenReturn(vmSpec);
@ -234,11 +232,6 @@ public class VmwareResourceTest {
when(hostCapability.isNestedHVSupported()).thenReturn(true);
}
@After
public void tearDown() throws Exception {
closeable.close();
}
//Test successful scaling up the vm
@Test
public void testScaleVMF1() throws Exception {

View File

@ -154,7 +154,7 @@ public class ManagementServerMaintenanceManagerImplTest {
ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class);
List<ManagementServerHostVO> msHostList = new ArrayList<>();
msHostList.add(msHost2);
Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.lenient().when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1);
PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class);
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
@ -169,7 +169,7 @@ public class ManagementServerMaintenanceManagerImplTest {
ManagementServerHostVO msHost = mock(ManagementServerHostVO.class);
Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up);
List<ManagementServerHostVO> msHostList = new ArrayList<>();
Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.lenient().when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost);
PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class);
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
@ -185,7 +185,7 @@ public class ManagementServerMaintenanceManagerImplTest {
ManagementServerHostVO msHost = mock(ManagementServerHostVO.class);
Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up);
List<ManagementServerHostVO> msHostList = new ArrayList<>();
Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.lenient().when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost);
PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class);
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);
@ -200,7 +200,7 @@ public class ManagementServerMaintenanceManagerImplTest {
public void prepareForShutdownCmdSuccessResponseFromClusterManager() {
ManagementServerHostVO msHost = mock(ManagementServerHostVO.class);
Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up);
Mockito.when(msHostDao.listBy(any())).thenReturn(new ArrayList<>());
Mockito.lenient().when(msHostDao.listBy(any())).thenReturn(new ArrayList<>());
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost);
Mockito.when(hostDao.listByMs(anyLong())).thenReturn(new ArrayList<>());
PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class);
@ -279,7 +279,7 @@ public class ManagementServerMaintenanceManagerImplTest {
ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class);
List<ManagementServerHostVO> msHostList = new ArrayList<>();
msHostList.add(msHost2);
Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.lenient().when(msHostDao.listBy(any())).thenReturn(msHostList);
Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1);
TriggerShutdownCmd cmd = mock(TriggerShutdownCmd.class);
Mockito.when(cmd.getManagementServerId()).thenReturn(1L);

View File

@ -56,7 +56,7 @@
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<artifactId>mockito-core</artifactId>
<version>${cs.mockito.version}</version>
</dependency>
<dependency>

View File

@ -776,7 +776,8 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
if (answer != null && answer.getResult()) {
// successfully downloaded template to primary storage
answer = createVolumeSnapshot(cmd, size, conn, volName, dstTO);
TemplateObjectTO templ = (TemplateObjectTO) ((CopyCmdAnswer) answer).getNewData();
answer = createVolumeSnapshot(cmd, size, conn, volName, templ);
} else {
err = answer != null ? answer.getDetails() : "Unknown error while downloading template. Null answer returned.";
}
@ -983,7 +984,6 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
} else {
dstTO.setPath(StorPoolUtil.devPath(
StorPoolUtil.getSnapshotNameFromResponse(resp, false, StorPoolUtil.GLOBAL_ID)));
dstTO.setSize(size);
answer = new CopyCmdAnswer(dstTO);
}
return answer;

View File

@ -134,7 +134,7 @@
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<artifactId>mockito-core</artifactId>
<version>${cs.mockito.version}</version>
<scope>compile</scope>
<exclusions>
@ -147,7 +147,7 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.5</version>
<version>1.15.11</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@ -59,6 +59,12 @@
<artifactId>assertj-core</artifactId>
<version>${cs.assertj.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -81,10 +81,10 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, required = false, description = "User uuid")
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "User uuid")
private Long userId;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, required = false, description = "Domain uuid")
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Domain uuid")
private Long domainId;
@Override
@ -131,10 +131,12 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
}
if (userUuid != null && domainUuid != null) {
logger.debug("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserAccount.getId() + "] to useraccount [" + userUuid + "] in domain [" + domainUuid + "]");
final User user = _userDao.findByUuid(userUuid);
final Domain domain = _domainDao.findByUuid(domainUuid);
final UserAccount nextUserAccount = _accountService.getUserAccountById(user.getId());
if (nextUserAccount != null && !nextUserAccount.getAccountState().equals(Account.State.ENABLED.toString())) {
logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account [" + nextUserAccount.getAccountName() + "] is not enabled");
throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(),
"The requested user account is locked and cannot be switched to, please contact your administrator.",
params, responseType));
@ -145,25 +147,31 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
|| !nextUserAccount.getExternalEntity().equals(currentUserAccount.getExternalEntity())
|| (nextUserAccount.getDomainId() != domain.getId())
|| (nextUserAccount.getSource() != User.Source.SAML2)) {
logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account is not found or invalid");
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(),
"User account is not allowed to switch to the requested account",
params, responseType));
}
try {
if (_apiServer.verifyUser(nextUserAccount.getId())) {
logger.info("User [" + currentUserAccount.getUsername() + "] user profile switch is accepted: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]");
// need to set a sessoin variable to inform the login function of the specific user to login as, rather than using email only (which could have multiple matches)
session.setAttribute("nextUserId", user.getId());
final LoginCmdResponse loginResponse = (LoginCmdResponse) _apiServer.loginUser(session, nextUserAccount.getUsername(), nextUserAccount.getUsername() + nextUserAccount.getSource().toString(),
nextUserAccount.getDomainId(), null, remoteAddress, params);
SAMLUtils.setupSamlUserCookies(loginResponse, resp);
resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value());
session.removeAttribute("nextUserId");
logger.debug("User [" + currentUserAccount.getUsername() + "] user profile switch cookies set: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]");
//resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value());
return ApiResponseSerializer.toSerializedString(loginResponse, responseType);
}
} catch (CloudAuthenticationException | IOException exception) {
logger.debug("Failed to switch to request SAML user account due to: " + exception.getMessage());
logger.debug("User [{}] user profile switch cookies set FAILED: from [{}] to user profile [{}] in domain [{}] with account [{}]", currentUserAccount.getUsername(), currentUserId, userUuid, domainUuid, nextUserAccount.getAccountName(), exception);
}
} else {
List<UserAccountVO> switchableAccounts = _userAccountDao.getAllUsersByNameAndEntity(currentUserAccount.getUsername(), currentUserAccount.getExternalEntity());
if (switchableAccounts != null && switchableAccounts.size() > 0 && currentUserId != User.UID_SYSTEM) {
List<SamlUserAccountResponse> accountResponses = new ArrayList<SamlUserAccountResponse>();
if (switchableAccounts != null && !switchableAccounts.isEmpty() && currentUserId != User.UID_SYSTEM) {
List<SamlUserAccountResponse> accountResponses = new ArrayList<>();
for (UserAccountVO userAccount: switchableAccounts) {
User user = _userDao.getUser(userAccount.getId());
Domain domain = _domainService.getDomain(userAccount.getDomainId());
@ -176,8 +184,9 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
accountResponse.setAccountName(userAccount.getAccountName());
accountResponse.setIdpId(user.getExternalEntity());
accountResponses.add(accountResponse);
logger.debug("Returning available useraccount for [{}]: UserUUID: [{}], DomainUUID: [{}], Account: [{}]", currentUserAccount.getUsername(), user.getUuid(), domain.getUuid(), userAccount.getAccountName());
}
ListResponse<SamlUserAccountResponse> response = new ListResponse<SamlUserAccountResponse>();
ListResponse<SamlUserAccountResponse> response = new ListResponse<>();
response.setResponses(accountResponses);
response.setResponseName(getCommandName());
return ApiResponseSerializer.toSerializedString(response, responseType);
@ -196,7 +205,7 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
@Override
public void setAuthenticators(List<PluggableAPIAuthenticator> authenticators) {
for (PluggableAPIAuthenticator authManager: authenticators) {
if (authManager != null && authManager instanceof SAML2AuthManager) {
if (authManager instanceof SAML2AuthManager) {
_samlAuthManager = (SAML2AuthManager) authManager;
}
}

View File

@ -78,7 +78,7 @@ import com.cloud.user.UserAccountVO;
import com.cloud.user.dao.UserAccountDao;
import com.cloud.utils.db.EntityManager;
@APICommand(name = "samlSso", description = "SP initiated SAML Single Sign On", requestHasSensitiveInfo = true, responseObject = LoginCmdResponse.class, entityType = {})
@APICommand(name = "samlSso", description = "SP initiated SAML Single Sign On", responseObject = LoginCmdResponse.class)
public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthenticator, Configurable {
private static final String s_name = "loginresponse";
@ -97,7 +97,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
@Inject
private UserAccountDao userAccountDao;
protected static ConfigKey<String> saml2FailedLoginRedirectUrl = new ConfigKey<String>("Advanced", String.class, "saml2.failed.login.redirect.url", "",
protected static ConfigKey<String> saml2FailedLoginRedirectUrl = new ConfigKey<>("Advanced", String.class, "saml2.failed.login.redirect.url", "",
"The URL to redirect the SAML2 login failed message (the default vaulue is empty).", true);
SAML2AuthManager samlAuthManager;
@ -190,7 +190,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
String authnId = SAMLUtils.generateSecureRandomId();
samlAuthManager.saveToken(authnId, domainPath, idpMetadata.getEntityId());
logger.debug("Sending SAMLRequest id=" + authnId);
String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value());
String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), SAML2AuthManager.SAMLRequirePasswordLogin.value());
resp.sendRedirect(redirectUrl);
return "";
} if (params.containsKey("SAMLart")) {
@ -207,7 +207,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
params, responseType));
}
String username = null;
String username;
Issuer issuer = processedSAMLResponse.getIssuer();
SAMLProviderMetadata spMetadata = samlAuthManager.getSPMetadata();
SAMLProviderMetadata idpMetadata = samlAuthManager.getIdPMetadata(issuer.getValue());
@ -273,7 +273,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
try {
assertion = decrypter.decrypt(encryptedAssertion);
} catch (DecryptionException e) {
logger.warn("SAML EncryptedAssertion error: " + e.toString());
logger.warn("SAML EncryptedAssertion error: " + e);
}
if (assertion == null) {
continue;
@ -310,7 +310,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
UserAccount userAccount = null;
List<UserAccountVO> possibleUserAccounts = userAccountDao.getAllUsersByNameAndEntity(username, issuer.getValue());
if (possibleUserAccounts != null && possibleUserAccounts.size() > 0) {
if (possibleUserAccounts != null && !possibleUserAccounts.isEmpty()) {
// Log into the first enabled user account
// Users can switch to other allowed accounts later
for (UserAccountVO possibleUserAccount : possibleUserAccounts) {
@ -370,7 +370,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
@Override
public void setAuthenticators(List<PluggableAPIAuthenticator> authenticators) {
for (PluggableAPIAuthenticator authManager: authenticators) {
if (authManager != null && authManager instanceof SAML2AuthManager) {
if (authManager instanceof SAML2AuthManager) {
samlAuthManager = (SAML2AuthManager) authManager;
}
}

View File

@ -79,6 +79,10 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
ConfigKey<String> SAMLUserSessionKeyPathAttribute = new ConfigKey<String>("Advanced", String.class, "saml2.user.sessionkey.path", "",
"The Path attribute of sessionkey cookie when SAML users have logged in. If not set, it will be set to the path of SAML redirection URL (saml2.redirect.url).", true);
ConfigKey<Boolean> SAMLRequirePasswordLogin = new ConfigKey<Boolean>("Advanced", Boolean.class, "saml2.require.password", "true",
"When enabled SAML2 will validate that the SAML login was performed with a password. If disabled, other forms of authentication are allowed (two-factor, certificate, etc) on the SAML Authentication Provider", true);
SAMLProviderMetadata getSPMetadata();
SAMLProviderMetadata getIdPMetadata(String entityId);
Collection<SAMLProviderMetadata> getAllIdPMetadata();

View File

@ -541,6 +541,6 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
SAMLCloudStackRedirectionUrl, SAMLUserAttributeName,
SAMLIdentityProviderMetadataURL, SAMLDefaultIdentityProviderId,
SAMLSignatureAlgorithm, SAMLAppendDomainSuffix, SAMLTimeout, SAMLCheckSignature,
SAMLForceAuthn, SAMLUserSessionKeyPathAttribute};
SAMLForceAuthn, SAMLUserSessionKeyPathAttribute, SAMLRequirePasswordLogin};
}
}

View File

@ -152,11 +152,11 @@ public class SAMLUtils {
return null;
}
public static String buildAuthnRequestUrl(final String authnId, final SAMLProviderMetadata spMetadata, final SAMLProviderMetadata idpMetadata, final String signatureAlgorithm) {
public static String buildAuthnRequestUrl(final String authnId, final SAMLProviderMetadata spMetadata, final SAMLProviderMetadata idpMetadata, final String signatureAlgorithm, boolean requirePasswordAuthentication) {
String redirectUrl = "";
try {
DefaultBootstrap.bootstrap();
AuthnRequest authnRequest = SAMLUtils.buildAuthnRequestObject(authnId, spMetadata.getEntityId(), idpMetadata.getSsoUrl(), spMetadata.getSsoUrl());
AuthnRequest authnRequest = SAMLUtils.buildAuthnRequestObject(authnId, spMetadata.getEntityId(), idpMetadata.getSsoUrl(), spMetadata.getSsoUrl(), requirePasswordAuthentication);
PrivateKey privateKey = null;
if (spMetadata.getKeyPair() != null) {
privateKey = spMetadata.getKeyPair().getPrivate();
@ -169,13 +169,36 @@ public class SAMLUtils {
return redirectUrl;
}
public static AuthnRequest buildAuthnRequestObject(final String authnId, final String spId, final String idpUrl, final String consumerUrl) {
public static AuthnRequest buildAuthnRequestObject(final String authnId, final String spId, final String idpUrl, final String consumerUrl, boolean requirePasswordAuthentication) {
// Issuer object
IssuerBuilder issuerBuilder = new IssuerBuilder();
Issuer issuer = issuerBuilder.buildObject();
issuer.setValue(spId);
// AuthnContextClass
// Creation of AuthRequestObject
AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
AuthnRequest authnRequest = authRequestBuilder.buildObject();
// AuthnContextClass. When this is false, the authentication requirements are defered to the SAML IDP and its default or configured workflow
if (requirePasswordAuthentication) {
setRequestedAuthnContext(authnRequest, requirePasswordAuthentication);
}
authnRequest.setID(authnId);
authnRequest.setDestination(idpUrl);
authnRequest.setVersion(SAMLVersion.VERSION_20);
authnRequest.setForceAuthn(SAML2AuthManager.SAMLForceAuthn.value());
authnRequest.setIsPassive(false);
authnRequest.setIssueInstant(new DateTime());
authnRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
authnRequest.setAssertionConsumerServiceURL(consumerUrl);
authnRequest.setProviderName(spId);
authnRequest.setIssuer(issuer);
return authnRequest;
}
public static void setRequestedAuthnContext(AuthnRequest authnRequest, boolean requirePasswordAuthentication) {
AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder();
AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject(
SAMLConstants.SAML20_NS,
@ -187,23 +210,7 @@ public class SAMLUtils {
RequestedAuthnContext requestedAuthnContext = requestedAuthnContextBuilder.buildObject();
requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT);
requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef);
// Creation of AuthRequestObject
AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
AuthnRequest authnRequest = authRequestBuilder.buildObject();
authnRequest.setID(authnId);
authnRequest.setDestination(idpUrl);
authnRequest.setVersion(SAMLVersion.VERSION_20);
authnRequest.setForceAuthn(SAML2AuthManager.SAMLForceAuthn.value());
authnRequest.setIsPassive(false);
authnRequest.setIssueInstant(new DateTime());
authnRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
authnRequest.setAssertionConsumerServiceURL(consumerUrl);
authnRequest.setProviderName(spId);
authnRequest.setIssuer(issuer);
authnRequest.setRequestedAuthnContext(requestedAuthnContext);
return authnRequest;
}
public static LogoutRequest buildLogoutRequest(String logoutUrl, String spId, String nameIdString) {
@ -285,23 +292,6 @@ public class SAMLUtils {
}
public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp) throws IOException {
resp.addCookie(new Cookie("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8)));
resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8)));
resp.addCookie(new Cookie("role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8)));
resp.addCookie(new Cookie("username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8)));
resp.addCookie(new Cookie("account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8)));
resp.addCookie(new Cookie("isSAML", URLEncoder.encode("true", HttpUtils.UTF_8)));
resp.addCookie(new Cookie("twoFaEnabled", URLEncoder.encode(loginResponse.is2FAenabled(), HttpUtils.UTF_8)));
String providerFor2FA = loginResponse.getProviderFor2FA();
if (StringUtils.isNotEmpty(providerFor2FA)) {
resp.addCookie(new Cookie("twoFaProvider", URLEncoder.encode(loginResponse.getProviderFor2FA(), HttpUtils.UTF_8)));
}
String timezone = loginResponse.getTimeZone();
if (timezone != null) {
resp.addCookie(new Cookie("timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8)));
}
resp.addCookie(new Cookie("userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20")));
String redirectUrl = SAML2AuthManager.SAMLCloudStackRedirectionUrl.value();
String path = SAML2AuthManager.SAMLUserSessionKeyPathAttribute.value();
String domain = null;
@ -317,6 +307,18 @@ public class SAMLUtils {
} catch (URISyntaxException ex) {
throw new CloudRuntimeException("Invalid URI: " + redirectUrl);
}
addBaseCookies(loginResponse, resp, domain, path);
String providerFor2FA = loginResponse.getProviderFor2FA();
if (StringUtils.isNotEmpty(providerFor2FA)) {
resp.addCookie(newCookie(domain, path,"twoFaProvider", URLEncoder.encode(loginResponse.getProviderFor2FA(), HttpUtils.UTF_8)));
}
String timezone = loginResponse.getTimeZone();
if (timezone != null) {
resp.addCookie(newCookie(domain, path,"timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8)));
}
String sameSite = ApiServlet.getApiSessionKeySameSite();
String sessionKeyCookie = String.format("%s=%s;Domain=%s;Path=%s;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), domain, path, sameSite);
LOGGER.debug("Adding sessionkey cookie to response: " + sessionKeyCookie);
@ -324,6 +326,24 @@ public class SAMLUtils {
resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly;Path=/client/api;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), sameSite));
}
private static void addBaseCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp, String domain, String path) throws IOException {
resp.addCookie(newCookie(domain, path, "userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"isSAML", URLEncoder.encode("true", HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"twoFaEnabled", URLEncoder.encode(loginResponse.is2FAenabled(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20")));
}
private static Cookie newCookie(final String domain, final String path, final String name, final String value) {
Cookie cookie = new Cookie(name, value);
cookie.setDomain(domain);
cookie.setPath(path);
return cookie;
}
/**
* Returns base64 encoded PublicKey
* @param key PublicKey

View File

@ -58,7 +58,7 @@ public class SAMLUtilsTest extends TestCase {
String idpUrl = "http://idp.domain.example";
String spId = "cloudstack";
String authnId = SAMLUtils.generateSecureRandomId();
AuthnRequest req = SAMLUtils.buildAuthnRequestObject(authnId, spId, idpUrl, consumerUrl);
AuthnRequest req = SAMLUtils.buildAuthnRequestObject(authnId, spId, idpUrl, consumerUrl, true);
assertEquals(req.getAssertionConsumerServiceURL(), consumerUrl);
assertEquals(req.getDestination(), idpUrl);
assertEquals(req.getIssuer().getValue(), spId);
@ -86,7 +86,7 @@ public class SAMLUtilsTest extends TestCase {
idpMetadata.setSsoUrl(idpUrl);
idpMetadata.setEntityId(idpId);
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value()));
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), true));
assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("SAMLRequest");
assertEquals(urlScheme, redirectUrl.getScheme());
assertEquals(idpDomain, redirectUrl.getHost());
@ -115,7 +115,7 @@ public class SAMLUtilsTest extends TestCase {
idpMetadata.setSsoUrl(idpUrl);
idpMetadata.setEntityId(idpId);
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value()));
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), true));
assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("idpid").hasParameter("SAMLRequest");
assertEquals(urlScheme, redirectUrl.getScheme());
assertEquals(idpDomain, redirectUrl.getHost());

View File

@ -213,7 +213,6 @@ public class ListAndSwitchSAMLAccountCmdTest extends TestCase {
loginCmdResponse.set2FAenabled("false");
Mockito.when(apiServer.loginUser(nullable(HttpSession.class), nullable(String.class), nullable(String.class),
nullable(Long.class), nullable(String.class), nullable(InetAddress.class), nullable(Map.class))).thenReturn(loginCmdResponse);
Mockito.doNothing().when(resp).sendRedirect(nullable(String.class));
try {
cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
} catch (ServerApiException exception) {
@ -221,7 +220,6 @@ public class ListAndSwitchSAMLAccountCmdTest extends TestCase {
} finally {
// accountService should have been called 4 times by now, for this case twice and 2 for cases above
Mockito.verify(accountService, Mockito.times(4)).getUserAccountById(Mockito.anyLong());
Mockito.verify(resp, Mockito.times(1)).sendRedirect(anyString());
}
}

View File

@ -111,6 +111,9 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
@Mock
HttpServletRequest req;
@Mock
Object _responseObject;
@Spy
@InjectMocks
private SAML2LoginAPIAuthenticatorCmd cmdSpy;

View File

@ -116,7 +116,7 @@
<cs.junit.dataprovider.version>1.13.1</cs.junit.dataprovider.version>
<cs.junit.jupiter.version>5.9.1</cs.junit.jupiter.version>
<cs.guava-testlib.version>18.0</cs.guava-testlib.version>
<cs.mockito.version>4.11.0</cs.mockito.version>
<cs.mockito.version>5.16.1</cs.mockito.version>
<cs.selenium.server.version>1.0-20081010.060147</cs.selenium.server.version>
<cs.selenium-java-client-driver.version>1.0.1</cs.selenium-java-client-driver.version>
<cs.testng.version>7.1.0</cs.testng.version>
@ -750,7 +750,7 @@
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<artifactId>mockito-core</artifactId>
<version>${cs.mockito.version}</version>
<scope>test</scope>
<exclusions>

View File

@ -25,7 +25,6 @@ import java.util.Map;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.springframework.stereotype.Component;
@ -130,8 +129,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
// FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of routing or not
return new ArrayList<>();
}
logger.debug("Looking for hosts in zone [{}], pod [{}], cluster [{}]", dcId, podId, clusterId);
String paramAsStringToLog = String.format("zone [%s], pod [%s], cluster [%s]", dcId, podId, clusterId);
logger.debug("Looking for hosts in {}", paramAsStringToLog);
String hostTagOnOffering = offering.getHostTag();
String hostTagOnTemplate = template.getTemplateTag();
@ -203,8 +202,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
if (clusterHosts.isEmpty()) {
logger.error("No suitable host found for vm [{}] with tags [{}].", vmProfile, hostTagOnOffering);
throw new CloudRuntimeException(String.format("No suitable host found for vm [%s].", vmProfile));
logger.warn("No suitable host found for VM [{}] with tags {} in {}.", vmProfile, hostTagOnOffering, paramAsStringToLog);
return null;
}
// add all hosts that we are not considering to the avoid list
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);

View File

@ -196,6 +196,7 @@ import static org.apache.cloudstack.user.UserPasswordResetManager.UserPasswordRe
@Component
public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService, Configurable {
private static final Logger ACCESSLOGGER = LogManager.getLogger("apiserver." + ApiServer.class.getName());
private static final String SANITIZATION_REGEX = "[\n\r]";
@ -240,9 +241,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
private EventDistributor eventDistributor = null;
private static int s_workerCount = 0;
private static Map<String, List<Class<?>>> s_apiNameCmdClassMap = new HashMap<String, List<Class<?>>>();
private static Map<String, List<Class<?>>> s_apiNameCmdClassMap = new HashMap<>();
private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory(
private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory(
"ApiServer"));
@Inject
@ -358,7 +359,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
String jobEvent = eventInfo.second();
if (logger.isTraceEnabled())
logger.trace("Handle asyjob publish event " + jobEvent);
logger.trace("Handle asyjob publish event {}", jobEvent);
if (eventDistributor == null) {
setEventDistributor(ComponentContext.getComponent(EventDistributor.class));
}
@ -383,7 +384,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
cmdEventType = eventTypeObj;
if (logger.isDebugEnabled())
logger.debug("Retrieved cmdEventType from job info: " + cmdEventType);
logger.debug("Retrieved cmdEventType from job info: {}", cmdEventType);
} else {
if (logger.isDebugEnabled())
logger.debug("Unable to locate cmdEventType marker in job info. publish as unknown event");
@ -427,11 +428,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
protected void setupIntegrationPortListener(Integer apiPort) {
if (apiPort == null || apiPort <= 0) {
logger.trace(String.format("Skipping setting up listener for integration port as %s is set to %d",
IntegrationAPIPort.key(), apiPort));
logger.trace("Skipping setting up listener for integration port as {} is set to {}",
IntegrationAPIPort.key(), apiPort);
return;
}
logger.debug(String.format("Setting up integration API service listener on port: %d", apiPort));
logger.debug("Setting up integration API service listener on port: {}", apiPort);
final ListenerThread listenerThread = new ListenerThread(this, apiPort);
listenerThread.start();
}
@ -442,24 +443,24 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
Integer apiPort = IntegrationAPIPort.value(); // api port, null by default
final Long snapshotLimit = ConcurrentSnapshotsThresholdPerHost.value();
if (snapshotLimit == null || snapshotLimit.longValue() <= 0) {
if (snapshotLimit == null || snapshotLimit <= 0) {
logger.debug("Global concurrent snapshot config parameter " + ConcurrentSnapshotsThresholdPerHost.value() + " is less or equal 0; defaulting to unlimited");
} else {
dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit);
}
final Long migrationLimit = VolumeApiService.ConcurrentMigrationsThresholdPerDatastore.value();
if (migrationLimit == null || migrationLimit.longValue() <= 0) {
if (migrationLimit == null || migrationLimit <= 0) {
logger.debug("Global concurrent migration config parameter " + VolumeApiService.ConcurrentMigrationsThresholdPerDatastore.value() + " is less or equal 0; defaulting to unlimited");
} else {
dispatcher.setMigrateQueueSizeLimit(migrationLimit);
}
final Set<Class<?>> cmdClasses = new HashSet<Class<?>>();
final Set<Class<?>> cmdClasses = new HashSet<>();
for (final PluggableService pluggableService : pluggableServices) {
cmdClasses.addAll(pluggableService.getCommands());
if (logger.isDebugEnabled()) {
logger.debug("Discovered plugin " + pluggableService.getClass().getSimpleName());
logger.debug("Discovered plugin {}", pluggableService.getClass().getSimpleName());
}
}
@ -472,7 +473,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
String apiName = at.name();
List<Class<?>> apiCmdList = s_apiNameCmdClassMap.get(apiName);
if (apiCmdList == null) {
apiCmdList = new ArrayList<Class<?>>();
apiCmdList = new ArrayList<>();
s_apiNameCmdClassMap.put(apiName, apiCmdList);
}
apiCmdList.add(cmdClass);
@ -574,14 +575,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
throw e;
}
} finally {
logger.info(sb.toString());
ACCESSLOGGER.info(sb.toString());
CallContext.unregister();
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void checkCharacterInkParams(final Map params) {
final Map<String, String> stringMap = new HashMap<String, String>();
final Map<String, String> stringMap = new HashMap<>();
final Set keys = params.keySet();
final Iterator keysIter = keys.iterator();
while (keysIter.hasNext()) {
@ -604,7 +605,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
public String handleRequest(final Map params, final String responseType, final StringBuilder auditTrailSb) throws ServerApiException {
checkCharacterInkParams(params);
String response = null;
String response;
String[] command = null;
try {
@ -625,7 +626,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (authManager.getAPIAuthenticator(command[0]) != null) {
return null;
}
final Map<String, String> paramMap = new HashMap<String, String>();
final Map<String, String> paramMap = new HashMap<>();
final Set keys = params.keySet();
final Iterator keysIter = keys.iterator();
while (keysIter.hasNext()) {
@ -641,16 +642,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (cmdClass != null) {
APICommand annotation = cmdClass.getAnnotation(APICommand.class);
if (annotation == null) {
logger.error("No APICommand annotation found for class " + cmdClass.getCanonicalName());
logger.error("No APICommand annotation found for class {}", cmdClass.getCanonicalName());
throw new CloudRuntimeException("No APICommand annotation found for class " + cmdClass.getCanonicalName());
}
BaseCmd cmdObj = (BaseCmd)cmdClass.newInstance();
BaseCmd cmdObj = (BaseCmd)cmdClass.getDeclaredConstructor().newInstance();
cmdObj = ComponentContext.inject(cmdObj);
cmdObj.configure();
cmdObj.setFullUrlParams(paramMap);
cmdObj.setResponseType(responseType);
cmdObj.setHttpMethod(paramMap.get(ApiConstants.HTTPMETHOD).toString());
cmdObj.setHttpMethod(paramMap.get(ApiConstants.HTTPMETHOD));
// This is where the command is either serialized, or directly dispatched
StringBuilder log = new StringBuilder();
@ -659,14 +660,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
} else {
final String errorString = "Unknown API command: " + command[0];
logger.warn(errorString);
auditTrailSb.append(" " + errorString);
auditTrailSb.append(" ").append(errorString);
throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString);
}
}
} catch (final InvalidParameterValueException ex) {
logger.info(ex.getMessage());
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
} catch (final IllegalArgumentException ex) {
} catch (final InvalidParameterValueException | IllegalArgumentException ex) {
logger.info(ex.getMessage());
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex);
} catch (final PermissionDeniedException ex) {
@ -679,9 +677,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
buf.append(obj.getUuid());
buf.append(" ");
}
logger.info("PermissionDenied: " + ex.getMessage() + " on objs: [" + buf.toString() + "]");
logger.info("PermissionDenied: " + ex.getMessage() + " on objs: [" + buf + "]");
} else {
logger.info("PermissionDenied: " + ex.getMessage());
logger.info("PermissionDenied: {}", ex.getMessage());
}
throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex);
} catch (final AccountLimitException ex) {
@ -756,7 +754,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
throw new ServerApiException(ApiErrorCode.SERVICE_UNAVAILABLE, msg);
}
Long objectId = null;
String objectUuid = null;
String objectUuid;
if (cmdObj instanceof BaseAsyncCreateCmd) {
final BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd)cmdObj;
dispatcher.dispatchCreateCmd(createCmd, params);
@ -797,7 +795,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
}
params.put("ctxStartEventId", String.valueOf(startEventId));
params.put("cmdEventType", asyncCmd.getEventType().toString());
params.put("cmdEventType", asyncCmd.getEventType());
params.put("ctxDetails", ApiGsonHelper.getBuilder().create().toJson(ctx.getContextParameters()));
if (asyncCmd.getHttpMethod() != null) {
params.put(ApiConstants.HTTPMETHOD, asyncCmd.getHttpMethod().toString());
@ -860,9 +858,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
@SuppressWarnings("unchecked")
private void buildAsyncListResponse(final BaseListCmd command, final Account account) {
final List<ResponseObject> responses = ((ListResponse)command.getResponseObject()).getResponses();
if (responses != null && responses.size() > 0) {
List<? extends AsyncJob> jobs = null;
final List<ResponseObject> responses = ((ListResponse<ResponseObject>)command.getResponseObject()).getResponses();
if (responses != null && !responses.isEmpty()) {
List<? extends AsyncJob> jobs;
// list all jobs for ROOT admin
if (accountMgr.isRootAdmin(account.getId())) {
@ -871,11 +869,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
jobs = asyncMgr.findInstancePendingAsyncJobs(command.getApiResourceType().toString(), account.getId());
}
if (jobs.size() == 0) {
if (jobs.isEmpty()) {
return;
}
final Map<String, AsyncJob> objectJobMap = new HashMap<String, AsyncJob>();
final Map<String, AsyncJob> objectJobMap = new HashMap<>();
for (final AsyncJob job : jobs) {
if (job.getInstanceId() == null) {
continue;
@ -912,7 +910,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (Boolean.TRUE.equals(apiKeyAccessEnabled)) {
return true;
} else {
logger.info("Api-Key access is disabled for the User " + user.toString());
logger.info("Api-Key access is disabled for the User {}", user);
return false;
}
}
@ -921,7 +919,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (Boolean.TRUE.equals(apiKeyAccessEnabled)) {
return true;
} else {
logger.info("Api-Key access is disabled for the Account " + account.toString());
logger.info("Api-Key access is disabled for the Account {}", account);
return false;
}
}
@ -938,7 +936,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
public boolean verifyRequest(final Map<String, Object[]> requestParameters, final Long userId, InetAddress remoteAddress) throws ServerApiException {
try {
String apiKey = null;
String secretKey = null;
String secretKey;
String signature = null;
String unsignedRequest = null;
@ -966,11 +964,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
// - build a request string with sorted params, make sure it's all lowercase
// - sign the request, verify the signature is the same
final List<String> parameterNames = new ArrayList<String>();
for (final Object paramNameObj : requestParameters.keySet()) {
parameterNames.add((String)paramNameObj); // put the name in a list that we'll sort later
}
// put the name in a list that we'll sort later
final List<String> parameterNames = new ArrayList<>(requestParameters.keySet());
Collections.sort(parameterNames);
@ -1006,7 +1002,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
return false; // no signature, bad request
}
Date expiresTS = null;
Date expiresTS;
// FIXME: Hard coded signature, why not have an enum
if ("3".equals(signatureVersion)) {
// New signature authentication. Check for expire parameter and its validity
@ -1026,18 +1022,18 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (expiresTS.before(now)) {
signature = signature.replaceAll(SANITIZATION_REGEX, "_");
apiKey = apiKey.replaceAll(SANITIZATION_REGEX, "_");
logger.debug(String.format("Request expired -- ignoring ...sig [%s], apiKey [%s].", signature, apiKey));
logger.debug("Request expired -- ignoring ...sig [{}], apiKey [{}].", signature, apiKey);
return false;
}
}
final TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB);
txn.close();
User user = null;
User user;
// verify there is a user with this api key
final Pair<User, Account> userAcctPair = accountMgr.findUserByApiKey(apiKey);
if (userAcctPair == null) {
logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey);
logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: {}", apiKey);
return false;
}
@ -1078,7 +1074,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
if (!equalSig) {
signature = signature.replaceAll(SANITIZATION_REGEX, "_");
logger.info(String.format("User signature [%s] is not equaled to computed signature [%s].", signature, computedSignature));
logger.info("User signature [{}] is not equaled to computed signature [{}].", signature, computedSignature);
} else {
CallContext.register(user, account);
}
@ -1137,10 +1133,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
session.removeAttribute("domain_UUID");
}
final Enumeration attrNames = session.getAttributeNames();
final Enumeration<String> attrNames = session.getAttributeNames();
if (attrNames != null) {
while (attrNames.hasMoreElements()) {
final String attrName = (String) attrNames.nextElement();
final String attrName = attrNames.nextElement();
final Object attrObj = session.getAttribute(attrName);
if (ApiConstants.USERNAME.equalsIgnoreCase(attrName)) {
response.setUsername(attrObj.toString());
@ -1202,7 +1198,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
domainId = userDomain.getId();
}
UserAccount userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters);
Long userId = (Long)session.getAttribute("nextUserId");
UserAccount userAcct = null;
if (userId != null) {
userAcct = accountMgr.getUserAccountById(userId);
} else {
userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters);
}
if (userAcct != null) {
final String timezone = userAcct.getTimezone();
float offsetInHrs = 0f;
@ -1214,7 +1217,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
final long longDate = date.getTime();
final float offsetInMs = (t.getOffset(longDate));
offsetInHrs = offsetInMs / (1000 * 60 * 60);
logger.info("Timezone offset from UTC is: " + offsetInHrs);
logger.info("Timezone offset from UTC is: {}", offsetInHrs);
}
final Account account = accountMgr.getAccount(userAcct.getAccountId());
@ -1272,7 +1275,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
// (bug 5483) generate a session key that the user must submit on every request to prevent CSRF, add that
// to the login response so that session-based authenticators know to send the key back
final SecureRandom sesssionKeyRandom = new SecureRandom();
final byte sessionKeyBytes[] = new byte[20];
final byte[] sessionKeyBytes = new byte[20];
sesssionKeyRandom.nextBytes(sessionKeyBytes);
final String sessionKey = Base64.encodeBase64URLSafeString(sessionKeyBytes);
session.setAttribute(ApiConstants.SESSIONKEY, sessionKey);
@ -1285,7 +1288,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
@Override
public void logoutUser(final long userId) {
accountMgr.logoutUser(userId);
return;
}
@Override
@ -1313,30 +1315,26 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
throw new CloudRuntimeException(errorMessage);
}
if (StringUtils.isBlank(userAccount.getEmail())) {
logger.error(String.format(
"Email is not set. username: %s account id: %d domain id: %d",
userAccount.getUsername(), userAccount.getAccountId(), userAccount.getDomainId()));
logger.error("Email is not set. username: {} account id: {} domain id: {}",
userAccount.getUsername(), userAccount.getAccountId(), userAccount.getDomainId());
throw new CloudRuntimeException("Email is not set for the user.");
}
if (!EnumUtils.getEnumIgnoreCase(Account.State.class, userAccount.getState()).equals(Account.State.ENABLED)) {
logger.error(String.format(
"User is not enabled. username: %s account id: %d domain id: %s",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid()));
logger.error("User is not enabled. username: {} account id: {} domain id: {}",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid());
throw new CloudRuntimeException("User is not enabled.");
}
if (!EnumUtils.getEnumIgnoreCase(Account.State.class, userAccount.getAccountState()).equals(Account.State.ENABLED)) {
logger.error(String.format(
"Account is not enabled. username: %s account id: %d domain id: %s",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid()));
logger.error("Account is not enabled. username: {} account id: {} domain id: {}",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid());
throw new CloudRuntimeException("Account is not enabled.");
}
if (!domain.getState().equals(Domain.State.Active)) {
logger.error(String.format(
"Domain is not active. username: %s account id: %d domain id: %s",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid()));
logger.error("Domain is not active. username: {} account id: {} domain id: {}",
userAccount.getUsername(), userAccount.getAccountId(), domain.getUuid());
throw new CloudRuntimeException("Domain is not active.");
}
@ -1444,7 +1442,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
// code to be very specific to our needs
static class ListenerThread extends Thread {
private static Logger LOGGER = LogManager.getLogger(ListenerThread.class);
private static final Logger LOGGER = LogManager.getLogger(ListenerThread.class);
private HttpService _httpService = null;
private ServerSocket _serverSocket = null;
private HttpParams _params = null;
@ -1483,7 +1481,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
@Override
public void run() {
LOGGER.info("ApiServer listening on port " + _serverSocket.getLocalPort());
LOGGER.info("ApiServer listening on port {}", _serverSocket.getLocalPort());
while (!Thread.interrupted()) {
try {
// Set up HTTP connection
@ -1526,10 +1524,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
}
} catch (final IOException ex) {
if (logger.isTraceEnabled()) {
logger.trace("ApiServer: IOException - " + ex);
logger.trace("ApiServer: IOException - {}", ex.toString());
}
} catch (final HttpException ex) {
logger.warn("ApiServer: Unrecoverable HTTP protocol violation" + ex);
logger.warn("ApiServer: Unrecoverable HTTP protocol violation {}", ex.toString());
} finally {
try {
_conn.shutdown();
@ -1542,7 +1540,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
@Override
public String getSerializedApiError(final int errorCode, final String errorText, final Map<String, Object[]> apiCommandParams, final String responseType) {
String responseName = null;
Class<?> cmdClass = null;
Class<?> cmdClass;
String responseText = null;
try {
@ -1555,7 +1553,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
final String cmdName = ((String[])cmdObj)[0];
cmdClass = getCmdClass(cmdName);
if (cmdClass != null) {
responseName = ((BaseCmd)cmdClass.newInstance()).getCommandName();
responseName = ((BaseCmd)cmdClass.getDeclaredConstructor().newInstance()).getCommandName();
} else {
responseName = "errorresponse";
}
@ -1577,7 +1575,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
@Override
public String getSerializedApiError(final ServerApiException ex, final Map<String, Object[]> apiCommandParams, final String responseType) {
String responseName = null;
Class<?> cmdClass = null;
Class<?> cmdClass;
String responseText = null;
if (ex == null) {
@ -1595,7 +1593,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
final String cmdName = ((String[])cmdObj)[0];
cmdClass = getCmdClass(cmdName);
if (cmdClass != null) {
responseName = ((BaseCmd)cmdClass.newInstance()).getCommandName();
responseName = ((BaseCmd)cmdClass.getDeclaredConstructor().newInstance()).getCommandName();
} else {
responseName = "errorresponse";
}
@ -1607,8 +1605,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
apiResponse.setResponseName(responseName);
final ArrayList<ExceptionProxyObject> idList = ex.getIdProxyList();
if (idList != null) {
for (int i = 0; i < idList.size(); i++) {
apiResponse.addProxyObject(idList.get(i));
for (ExceptionProxyObject exceptionProxyObject : idList) {
apiResponse.addProxyObject(exceptionProxyObject);
}
}
// Also copy over the cserror code and the function/layer in which

View File

@ -21,7 +21,6 @@ import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -76,9 +75,7 @@ import com.cloud.utils.net.NetUtils;
@Component("apiServlet")
public class ApiServlet extends HttpServlet {
protected static Logger LOGGER = LogManager.getLogger(ApiServlet.class);
private final static List<String> s_clientAddressHeaders = Collections
.unmodifiableList(Arrays.asList("X-Forwarded-For",
"HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR", "Remote_Addr"));
private static final Logger ACCESSLOGGER = LogManager.getLogger("apiserver." + ApiServlet.class.getName());
private static final String REPLACEMENT = "_";
private static final String LOGGER_REPLACEMENTS = "[\n\r\t]";
@ -374,7 +371,7 @@ public class ApiServlet extends HttpServlet {
LOGGER.error("unknown exception writing api response", ex);
auditTrailSb.append(" unknown exception writing api response");
} finally {
LOGGER.info(auditTrailSb.toString());
ACCESSLOGGER.info(auditTrailSb.toString());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("===END=== " + reqStr);
}

View File

@ -151,11 +151,6 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
activeTmpltSearch.and("store_id", activeTmpltSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
activeTmpltSearch.and("type", activeTmpltSearch.entity().getTemplateType(), SearchCriteria.Op.EQ);
activeTmpltSearch.and("templateState", activeTmpltSearch.entity().getTemplateState(), SearchCriteria.Op.EQ);
activeTmpltSearch.and().op("public", activeTmpltSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ);
activeTmpltSearch.or().op("publicNoUrl", activeTmpltSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ);
activeTmpltSearch.and("url", activeTmpltSearch.entity().getUrl(), SearchCriteria.Op.NULL);
activeTmpltSearch.cp();
activeTmpltSearch.cp();
activeTmpltSearch.done();
publicTmpltSearch = createSearchBuilder();
@ -688,8 +683,6 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
sc.setParameters("store_id", storeId);
sc.setParameters("type", TemplateType.USER);
sc.setParameters("templateState", VirtualMachineTemplate.State.Active);
sc.setParameters("public", Boolean.FALSE);
sc.setParameters("publicNoUrl",Boolean.TRUE);
return searchIncludingRemoved(sc, null, null, false);
}

View File

@ -384,11 +384,10 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
}
@Override
public boolean scheduleMigration(final VMInstanceVO vm, ReasonType reasonType) {
public boolean scheduleMigration(final VMInstanceVO vm, HighAvailabilityManager.ReasonType reasonType) {
if (vm.getHostId() == null) {
return false;
}
if (!VmHaEnabled.valueIn(vm.getDataCenterId())) {
String message = String.format("Unable to schedule migration for the VM %s on host %s, VM high availability manager is disabled.", vm, _hostDao.findById(vm.getHostId()));
if (logger.isDebugEnabled()) {
@ -398,6 +397,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
return false;
}
Long hostId = VirtualMachine.State.Migrating.equals(vm.getState()) ? vm.getLastHostId() : vm.getHostId();
final HaWorkVO work = new HaWorkVO(vm.getId(), vm.getType(), WorkType.Migration, Step.Scheduled, vm.getHostId(), vm.getState(), 0, vm.getUpdated(), reasonType);
_haDao.persist(work);
logger.info("Scheduled migration work of VM {} from host {} with HAWork {}", vm, _hostDao.findById(vm.getHostId()), work);
@ -813,6 +813,18 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
return null;
}
logger.info("Migration attempt: for VM {}from host {}. Starting attempt: {}/{} times.", vm, srcHost, 1 + work.getTimesTried(), _maxRetries);
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
logger.info(String.format("vm %s is Stopped, skipping migrate.", vm));
return null;
}
if (VirtualMachine.State.Running.equals(vm.getState()) && srcHostId != vm.getHostId()) {
logger.info(String.format("VM %s is running on a different host %s, skipping migration", vm, vm.getHostId()));
return null;
}
logger.info("Migration attempt: for VM " + vm.getUuid() + "from host id " + srcHostId +
". Starting attempt: " + (1 + work.getTimesTried()) + "/" + _maxRetries + " times.");
try {
work.setStep(Step.Migrating);
_haDao.update(work.getId(), work);
@ -1148,6 +1160,15 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements Configur
@Override
public void run() {
logger.info("Starting work");
try {
synchronized (this) {
wait(_timeToSleep);
}
} catch (final InterruptedException e) {
logger.info("Interrupted");
}
logger.info("Starting work");
while (!_stopped) {
_managedContext.runWithContext(new Runnable() {
@Override

View File

@ -1038,36 +1038,48 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
@Override
public void markPublicIpAsAllocated(final IPAddressVO addr) {
synchronized (allocatedLock) {
Transaction.execute(new TransactionCallbackNoReturn() {
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId());
if (_ipAddressDao.lockRow(addr.getId(), true) != null) {
final IPAddressVO userIp = _ipAddressDao.findById(addr.getId());
if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free || addr.getState() == IpAddress.State.Reserved) {
boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr);
addr.setState(IpAddress.State.Allocated);
if (_ipAddressDao.update(addr.getId(), addr)) {
// Save usage event
if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
VlanVO vlan = _vlanDao.findById(addr.getVlanId());
String guestType = vlan.getVlanType().toString();
if (!isIpDedicated(addr)) {
final boolean usageHidden = isUsageHidden(addr);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(),
addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden,
addr.getClass().getName(), addr.getUuid());
}
if (shouldUpdateIpResourceCount) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
}
}
} else {
logger.error("Failed to mark public IP as allocated: {}", addr);
final IPAddressVO userIp = _ipAddressDao.lockRow(addr.getId(), true);
if (userIp == null) {
logger.error(String.format("Failed to acquire row lock to mark public IP as allocated with ID [%s] and address [%s]", addr.getId(), addr.getAddress()));
return;
}
List<IpAddress.State> expectedIpAddressStates = List.of(IpAddress.State.Allocating, IpAddress.State.Free, IpAddress.State.Reserved);
if (!expectedIpAddressStates.contains(userIp.getState())) {
logger.debug(String.format("Not marking public IP with ID [%s] and address [%s] as allocated, since it is in the [%s] state.", addr.getId(), addr.getAddress(), userIp.getState()));
return;
}
boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr);
addr.setState(IpAddress.State.Allocated);
boolean updatedIpAddress = _ipAddressDao.update(addr.getId(), addr);
if (!updatedIpAddress) {
logger.error(String.format("Failed to mark public IP as allocated with ID [%s] and address [%s]", addr.getId(), addr.getAddress()));
return;
}
if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
if (shouldUpdateIpResourceCount) {
try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1L, reservationDao, _resourceLimitMgr)) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
} catch (Exception e) {
_ipAddressDao.unassignIpAddress(addr.getId());
throw new CloudRuntimeException(e);
}
}
} else {
logger.error("Failed to acquire row lock to mark public IP as allocated: {}", addr);
VlanVO vlan = _vlanDao.findById(addr.getVlanId());
String guestType = vlan.getVlanType().toString();
if (!isIpDedicated(addr)) {
final boolean usageHidden = isUsageHidden(addr);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(),
addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden,
addr.getClass().getName(), addr.getUuid());
}
}
}
});
@ -1553,27 +1565,31 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
boolean isSourceNat = isSourceNatAvailableForNetwork(owner, ipToAssoc, network);
logger.debug("Associating ip " + ipToAssoc + " to network " + network);
logger.debug(String.format("Associating IP [%s] to network [%s].", ipToAssoc, network));
boolean success = false;
IPAddressVO ip = null;
try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1l, reservationDao, _resourceLimitMgr)) {
ip = _ipAddressDao.findById(ipId);
//update ip address with networkId
ip.setAssociatedWithNetworkId(networkId);
ip.setSourceNat(isSourceNat);
_ipAddressDao.update(ipId, ip);
try {
Pair<IPAddressVO, Boolean> updatedIpAddress = Transaction.execute((TransactionCallbackWithException<Pair<IPAddressVO, Boolean>, Exception>) status -> {
IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
ipAddress.setAssociatedWithNetworkId(networkId);
ipAddress.setSourceNat(isSourceNat);
_ipAddressDao.update(ipId, ipAddress);
return new Pair<>(_ipAddressDao.findById(ipId), applyIpAssociations(network, false));
});
success = applyIpAssociations(network, false);
ip = updatedIpAddress.first();
success = updatedIpAddress.second();
if (success) {
logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network);
logger.debug(String.format("Successfully associated IP address [%s] to network [%s]", ip.getAddress().addr(), network));
} else {
logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
logger.warn(String.format("Failed to associate IP address [%s] to network [%s]", ip.getAddress().addr(), network));
}
return _ipAddressDao.findById(ipId);
return ip;
} catch (Exception e) {
logger.error(String.format("Failed to associate ip address %s to network %s", ipToAssoc, network), e);
throw new CloudRuntimeException(String.format("Failed to associate ip address %s to network %s", ipToAssoc, network), e);
String errorMessage = String.format("Failed to associate IP address [%s] to network [%s]", ipToAssoc, network);
logger.error(errorMessage, e);
throw new CloudRuntimeException(errorMessage, e);
} finally {
if (!success && releaseOnFailure) {
if (ip != null) {

View File

@ -1782,10 +1782,19 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), NETWORK_OFFERING_ID);
}
if (GuestType.Shared == ntwkOff.getGuestType() && !ntwkOff.isSpecifyVlan() && Objects.isNull(associatedNetworkId)) {
throw new CloudRuntimeException("Associated network must be provided when creating Shared networks when specifyVlan is false");
}
if (GuestType.Shared == ntwkOff.getGuestType()) {
if (!ntwkOff.isSpecifyIpRanges()) {
throw new CloudRuntimeException("The 'specifyipranges' parameter should be true for Shared Networks");
}
if (ipv4 && Objects.isNull(startIP)) {
throw new CloudRuntimeException("IPv4 address range needs to be provided");
}
if (ipv6 && Objects.isNull(startIPv6)) {
throw new CloudRuntimeException("IPv6 address range needs to be provided");
}
}
Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zone.getId());
mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu);

View File

@ -203,8 +203,8 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
private static Map<Service, Map<Capability, String>> setCapabilities() {
Map<Service, Map<Capability, String>> capabilities = new HashMap<>();
capabilities.put(Service.UserData, null);
capabilities.put(Service.Dhcp, new HashMap<>());
capabilities.put(Service.Dns, new HashMap<>());
capabilities.put(Service.Dhcp, Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true"));
capabilities.put(Service.Dns, Map.of(Capability.AllowDnsSuffixModification, "true"));
return capabilities;
}
@ -841,7 +841,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm,
DeployDestination dest,
ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
return false;
return true;
}
@Override

View File

@ -50,7 +50,6 @@ import com.cloud.dc.dao.ASNumberDao;
import com.cloud.dc.Vlan;
import com.cloud.network.dao.NsxProviderDao;
import com.cloud.network.element.NsxProviderVO;
import com.cloud.resourcelimit.CheckedReservation;
import com.google.common.collect.Sets;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.alert.AlertService;
@ -3206,32 +3205,27 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
// check permissions
_accountMgr.checkAccess(caller, null, false, owner, vpc);
logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
logger.debug(String.format("Associating IP [%s] to VPC [%s]", ipToAssoc, vpc));
final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(vpc.getAccountId(), vpcId, false) == null;
try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1l, reservationDao, _resourceLimitMgr)) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) {
try {
IPAddressVO updatedIpAddress = Transaction.execute((TransactionCallbackWithException<IPAddressVO, CloudRuntimeException>) status -> {
final IPAddressVO ip = _ipAddressDao.findById(ipId);
// update ip address with networkId
ip.setVpcId(vpcId);
ip.setSourceNat(isSourceNatFinal);
_ipAddressDao.update(ipId, ip);
// mark ip as allocated
_ipAddrMgr.markPublicIpAsAllocated(ip);
}
return _ipAddressDao.findById(ipId);
});
} catch (Exception e) {
logger.error("Failed to associate ip " + ipToAssoc + " to vpc " + vpc, e);
throw new CloudRuntimeException("Failed to associate ip " + ipToAssoc + " to vpc " + vpc, e);
}
logger.debug("Successfully assigned ip " + ipToAssoc + " to vpc " + vpc);
CallContext.current().putContextParameter(IpAddress.class, ipToAssoc.getUuid());
return _ipAddressDao.findById(ipId);
logger.debug(String.format("Successfully assigned IP [%s] to VPC [%s]", ipToAssoc, vpc));
CallContext.current().putContextParameter(IpAddress.class, ipToAssoc.getUuid());
return updatedIpAddress;
} catch (Exception e) {
String errorMessage = String.format("Failed to associate IP address [%s] to VPC [%s]", ipToAssoc, vpc);
logger.error(errorMessage, e);
throw new CloudRuntimeException(errorMessage, e);
}
}
@Override

View File

@ -3740,7 +3740,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
VolumeApiResult result = future.get();
if (result.isFailed()) {
logger.debug("migrate volume failed:" + result.getResult());
throw new StorageUnavailableException("Migrate volume failed: " + result.getResult(), destPool.getId());
throw new CloudRuntimeException("Migrate volume failed: " + result.getResult());
}
return result.getVolume();
} catch (InterruptedException e) {
@ -4117,7 +4117,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
Optional<String> extractUrl = setExtractVolumeSearchCriteria(sc, volume);
if (extractUrl.isPresent()) {
return extractUrl.get();
String url = extractUrl.get();
CallContext.current().setEventDetails(String.format("Download URL: %s, volume ID: %s", url, volume.getUuid()));
return url;
}
VMInstanceVO vm = null;
@ -4134,7 +4136,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
VmWorkJobVO placeHolder = null;
placeHolder = createPlaceHolderWork(vm.getId());
try {
return orchestrateExtractVolume(volume.getId(), zoneId);
String url = orchestrateExtractVolume(volume.getId(), zoneId);
CallContext.current().setEventDetails(String.format("Download URL: %s, volume ID: %s", url, volume.getUuid()));
return url;
} finally {
_workJobDao.expunge(placeHolder.getId());
}
@ -4163,13 +4167,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
// retrieve the entity url from job result
if (jobResult != null && jobResult instanceof String) {
return (String)jobResult;
String url = (String) jobResult;
CallContext.current().setEventDetails(String.format("Download URL: %s, volume ID: %s", url, volume.getUuid()));
return url;
}
return null;
}
}
return orchestrateExtractVolume(volume.getId(), zoneId);
String url = orchestrateExtractVolume(volume.getId(), zoneId);
CallContext.current().setEventDetails(String.format("Download URL: %s, volume ID: %s", url, volume.getUuid()));
return url;
}
@Override

View File

@ -76,7 +76,7 @@ public abstract class DownloadActiveState extends DownloadState {
getDownloadListener().log("handleTimeout, updateMs=" + updateMs + ", curr state= " + getName(), Level.TRACE);
}
String newState = getName();
if (updateMs > 5 * DownloadListener.STATUS_POLL_INTERVAL) {
if (updateMs > DownloadListener.DOWNLOAD_TIMEOUT) {
newState = Status.DOWNLOAD_ERROR.toString();
getDownloadListener().log("timeout: transitioning to download error state, currstate=" + getName(), Level.DEBUG);
} else if (updateMs > 3 * DownloadListener.STATUS_POLL_INTERVAL) {

View File

@ -100,6 +100,7 @@ public class DownloadListener implements Listener {
protected Logger logger = LogManager.getLogger(getClass());
public static final int SMALL_DELAY = 100;
public static final long STATUS_POLL_INTERVAL = 10000L;
public static final long DOWNLOAD_TIMEOUT = 5 * STATUS_POLL_INTERVAL;
public static final String DOWNLOADED = Status.DOWNLOADED.toString();
public static final String NOT_DOWNLOADED = Status.NOT_DOWNLOADED.toString();

View File

@ -390,15 +390,27 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
boolean result = snapshotStrategy.revertSnapshot(snapshotInfo);
if (result) {
// update volume size and primary storage count
_resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize() - snapshot.getSize()));
volume.setSize(snapshot.getSize());
_volsDao.update(volume.getId(), volume);
updateVolumeSizeAndPrimaryStorageCount(volume, snapshot);
return snapshotInfo;
}
return null;
}
public void updateVolumeSizeAndPrimaryStorageCount(VolumeVO volume, SnapshotVO snapshot) {
Long differenceBetweenVolumeAndSnapshotSize = new Long(volume.getSize() - snapshot.getSize());
if (differenceBetweenVolumeAndSnapshotSize != 0) {
if (differenceBetweenVolumeAndSnapshotSize > 0) {
_resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, differenceBetweenVolumeAndSnapshotSize);
} else if (differenceBetweenVolumeAndSnapshotSize < 0) {
_resourceLimitMgr.incrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, differenceBetweenVolumeAndSnapshotSize * -1L);
}
volume.setSize(snapshot.getSize());
_volsDao.update(volume.getId(), volume);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_POLICY_UPDATE, eventDescription = "updating snapshot policy", async = true)
public SnapshotPolicy updateSnapshotPolicy(UpdateSnapshotPolicyCmd cmd) {
@ -805,7 +817,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
return result;
} catch (Exception e) {
logger.debug("Failed to delete snapshot {}:{}", snapshotCheck, e.toString());
logger.debug("Failed to delete snapshot {}:{}", snapshotCheck.getId(), e.toString());
throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
}

View File

@ -294,7 +294,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
}
/**
* For each zone ID in {@link TemplateProfile#zoneIdList}, verifies if there is active heuristic rules for allocating template and returns the
* For each zone ID in {@link TemplateProfile#getZoneIdList()}, verifies if there is active heuristic rules for allocating template and returns the
* {@link DataStore} returned by the heuristic rule. If there is not an active heuristic rule, then allocate it to a random {@link DataStore}, if the ISO/template is private
* or allocate it to all {@link DataStore} in the zone, if it is public.
* @param profile
@ -454,10 +454,10 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
/**
* If the template/ISO is marked as private, then it is allocated to a random secondary storage; otherwise, allocates to every storage pool in every zone given by the
* {@link TemplateProfile#zoneIdList}.
* {@link TemplateProfile#getZoneIdList()}.
*/
private void postUploadAllocation(List<DataStore> imageStores, VMTemplateVO template, List<TemplateOrVolumePostUploadCommand> payloads) {
Set<Long> zoneSet = new HashSet<Long>();
Set<Long> zoneSet = new HashSet<>();
Collections.shuffle(imageStores);
for (DataStore imageStore : imageStores) {
Long zoneId_is = imageStore.getScope().getScopeId();
@ -698,8 +698,8 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
}
// delete all cache entries for this template
List<TemplateInfo> cacheTmpls = imageFactory.listTemplateOnCache(template.getId());
for (TemplateInfo tmplOnCache : cacheTmpls) {
List<TemplateInfo> cachedTemplates = imageFactory.listTemplateOnCache(template.getId());
for (TemplateInfo tmplOnCache : cachedTemplates) {
logger.info("Delete template: {} from image cache store: {}", tmplOnCache, tmplOnCache.getDataStore());
tmplOnCache.delete();
}
@ -728,27 +728,32 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
}
// remove its related ACL permission
Pair<Class<?>, Long> tmplt = new Pair<Class<?>, Long>(VirtualMachineTemplate.class, template.getId());
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, tmplt);
checkAndRemoveTemplateDetails(template);
// Remove comments (if any)
AnnotationService.EntityType entityType = template.getFormat().equals(ImageFormat.ISO) ?
AnnotationService.EntityType.ISO : AnnotationService.EntityType.TEMPLATE;
annotationDao.removeByEntityType(entityType.name(), template.getUuid());
Pair<Class<?>, Long> templateClassForId = new Pair<>(VirtualMachineTemplate.class, template.getId());
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, templateClassForId);
List<VMTemplateZoneVO> zoneRegistrations = templateZoneDao.listByTemplateId(template.getId());
if (zoneRegistrations.isEmpty()) {
removeTemplateDetails(template);
removeTemplateAnnotations(template);
}
}
return success;
}
private void removeTemplateAnnotations(VMTemplateVO template) {
// Remove comments (if any)
AnnotationService.EntityType entityType = template.getFormat().equals(ImageFormat.ISO) ?
AnnotationService.EntityType.ISO : AnnotationService.EntityType.TEMPLATE;
annotationDao.removeByEntityType(entityType.name(), template.getUuid());
}
/**
* removes details of the template and
* if the template is registered as deploy as is,
* then it also deletes the details related to deploy as is only if there are no VMs using the template
* @param template
*/
void checkAndRemoveTemplateDetails(VMTemplateVO template) {
private void removeTemplateDetails(VMTemplateVO template) {
templateDetailsDao.removeDetails(template.getId());
if (template.isDeployAsIs()) {

View File

@ -489,7 +489,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
String mode = cmd.getMode();
Long eventId = cmd.getStartEventId();
return extract(account, templateId, url, zoneId, mode, eventId, true);
String extractUrl = extract(account, templateId, url, zoneId, mode, eventId, true);
CallContext.current().setEventDetails(String.format("Download URL: %s, ISO ID: %s", extractUrl, _tmpltDao.findById(templateId).getUuid()));
return extractUrl;
}
@Override
@ -507,7 +509,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
throw new InvalidParameterValueException("unable to find template with id " + templateId);
}
return extract(caller, templateId, url, zoneId, mode, eventId, false);
String extractUrl = extract(caller, templateId, url, zoneId, mode, eventId, false);
CallContext.current().setEventDetails(String.format("Download URL: %s, template ID: %s", extractUrl, template.getUuid()));
return extractUrl;
}
@Override

View File

@ -386,6 +386,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
true,
ConfigKey.Scope.Domain);
static ConfigKey<Boolean> userAllowMultipleAccounts = new ConfigKey<>("Advanced",
Boolean.class,
"user.allow.multiple.accounts",
"false",
"Determines if the same username can be added to more than one account in the same domain (SAML-only).",
true,
ConfigKey.Scope.Domain);
protected AccountManagerImpl() {
super();
}
@ -1289,7 +1297,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// Check permissions
checkAccess(getCurrentCallingAccount(), domain);
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
if (!userAllowMultipleAccounts.valueInScope(ConfigKey.Scope.Domain, domainId) && !_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new InvalidParameterValueException(String.format("The user %s already exists in domain %s", userName, domain));
}
@ -1477,9 +1485,15 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
throw new PermissionDeniedException(String.format("Account: %s is a system account, can't add a user to it", account));
}
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new CloudRuntimeException(String.format("The user %s already exists in domain %s", userName, domain));
if (!userAllowMultipleAccounts.valueInScope(ConfigKey.Scope.Domain, domainId) && !_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new CloudRuntimeException("The user " + userName + " already exists in domain " + domainId);
}
List<UserVO> duplicatedUsers = _userDao.findUsersByName(userName);
for (UserVO duplicatedUser : duplicatedUsers) {
// users can't exist in same account
assertUserNotAlreadyInAccount(duplicatedUser, account);
}
UserVO user;
user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone, userUUID, source);
return user;
@ -1607,7 +1621,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
* <li> The username must be unique in each domain. Therefore, if there is already another user with the same username, an {@link InvalidParameterValueException} is thrown.
* </ul>
*/
protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user, Account account) {
protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, UserVO newUser, Account newAccount) {
String userName = updateUserCmd.getUsername();
if (userName == null) {
return;
@ -1615,18 +1629,21 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (StringUtils.isBlank(userName)) {
throw new InvalidParameterValueException("Username cannot be empty.");
}
List<UserVO> duplicatedUsers = _userDao.findUsersByName(userName);
for (UserVO duplicatedUser : duplicatedUsers) {
if (duplicatedUser.getId() == user.getId()) {
List<UserVO> existingUsers = _userDao.findUsersByName(userName);
for (UserVO existingUser : existingUsers) {
if (existingUser.getId() == newUser.getId()) {
continue;
}
Account duplicatedUserAccountWithUserThatHasTheSameUserName = _accountDao.findById(duplicatedUser.getAccountId());
if (duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId() == account.getDomainId()) {
DomainVO domain = _domainDao.findById(duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId());
throw new InvalidParameterValueException(String.format("Username (%s) already exists in domain (%s)", duplicatedUser, domain));
// duplicate usernames cannot exist in same domain unless explicitly configured
if (!userAllowMultipleAccounts.valueInScope(ConfigKey.Scope.Domain, newAccount.getDomainId())) {
assertUserNotAlreadyInDomain(existingUser, newAccount);
}
// can't rename a username to an existing one in the same account
assertUserNotAlreadyInAccount(existingUser, newAccount);
}
user.setUsername(userName);
newUser.setUsername(userName);
}
/**
@ -1895,7 +1912,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// make sure the account is enabled too
// if the user is either locked already or disabled already, don't change state...only lock currently enabled
// users
// users
boolean success;
if (user.getState().equals(State.LOCKED)) {
// already locked...no-op
@ -3408,7 +3425,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {UseSecretKeyInResponse, enableUserTwoFactorAuthentication,
userTwoFactorAuthenticationDefaultProvider, mandateUserTwoFactorAuthentication, userTwoFactorAuthenticationIssuer, apiKeyAccess};
userTwoFactorAuthenticationDefaultProvider, mandateUserTwoFactorAuthentication, userTwoFactorAuthenticationIssuer, apiKeyAccess,
userAllowMultipleAccounts};
}
public List<UserTwoFactorAuthenticator> getUserTwoFactorAuthenticationProviders() {
@ -3593,4 +3611,21 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return userAccountVO;
});
}
void assertUserNotAlreadyInAccount(User existingUser, Account newAccount) {
System.out.println(existingUser.getAccountId());
System.out.println(newAccount.getId());
if (existingUser.getAccountId() == newAccount.getId()) {
AccountVO existingAccount = _accountDao.findById(newAccount.getId());
throw new InvalidParameterValueException(String.format("Username [%s] already exists in account [id=%s,name=%s]", existingUser.getUsername(), existingAccount.getUuid(), existingAccount.getAccountName()));
}
}
void assertUserNotAlreadyInDomain(User existingUser, Account originalAccount) {
Account existingAccount = _accountDao.findById(existingUser.getAccountId());
if (existingAccount.getDomainId() == originalAccount.getDomainId()) {
DomainVO existingDomain = _domainDao.findById(existingAccount.getDomainId());
throw new InvalidParameterValueException(String.format("Username [%s] already exists in domain [id=%s,name=%s] user account [id=%s,name=%s]", existingUser.getUsername(), existingDomain.getUuid(), existingDomain.getName(), existingAccount.getUuid(), existingAccount.getAccountName()));
}
}
}

View File

@ -28,7 +28,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@ -3106,42 +3105,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware);
if (securityGroupIdList != null && isVMware) {
throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor");
} else {
// Get default guest network in Basic zone
Network defaultNetwork = null;
try {
DataCenterVO zone = _dcDao.findById(vm.getDataCenterId());
if (zone.getNetworkType() == NetworkType.Basic) {
// Get default guest network in Basic zone
defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId());
} else if (_networkModel.checkSecurityGroupSupportForNetwork(_accountMgr.getActiveAccountById(vm.getAccountId()), zone, Collections.emptyList(), securityGroupIdList)) {
NicVO defaultNic = _nicDao.findDefaultNicForVM(vm.getId());
if (defaultNic != null) {
defaultNetwork = _networkDao.findById(defaultNic.getNetworkId());
}
}
} catch (InvalidParameterValueException e) {
if(logger.isDebugEnabled()) {
logger.debug(e.getMessage(),e);
}
defaultNetwork = _networkModel.getDefaultNetworkForVm(id);
}
if (securityGroupIdList != null && _networkModel.isSecurityGroupSupportedInNetwork(defaultNetwork) && _networkModel.canAddDefaultSecurityGroup()) {
if (vm.getState() == State.Stopped) {
// Remove instance from security groups
_securityGroupMgr.removeInstanceFromGroups(vm);
// Add instance in provided groups
_securityGroupMgr.addInstanceToGroups(vm, securityGroupIdList);
} else {
throw new InvalidParameterValueException("Virtual machine must be stopped prior to update security groups ");
}
}
}
List<? extends Nic> nics = _nicDao.listByVmId(vm.getId());
if (hostName != null) {
// Check is hostName is RFC compliant
@ -3174,6 +3137,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
.getUuid(), nic.getId(), extraDhcpOptionsMap);
}
checkAndUpdateSecurityGroupForVM(securityGroupIdList, vm, networks);
_vmDao.updateVM(id, displayName, ha, osTypeId, userData, userDataId,
userDataDetails, isDisplayVmEnabled, isDynamicallyScalable,
deleteProtection, customId, hostName, instanceName);
@ -3189,6 +3154,48 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return _vmDao.findById(id);
}
private void checkAndUpdateSecurityGroupForVM(List<Long> securityGroupIdList, UserVmVO vm, List<NetworkVO> networks) {
boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware);
if (securityGroupIdList != null && isVMware) {
throw new InvalidParameterValueException("Security group feature is not supported for VMware hypervisor");
} else if (securityGroupIdList != null) {
DataCenterVO zone = _dcDao.findById(vm.getDataCenterId());
List<Long> networkIds = new ArrayList<>();
try {
if (zone.getNetworkType() == NetworkType.Basic) {
// Get default guest network in Basic zone
Network defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId());
networkIds.add(defaultNetwork.getId());
} else {
networkIds = networks.stream().map(Network::getId).collect(Collectors.toList());
}
} catch (InvalidParameterValueException e) {
if(logger.isDebugEnabled()) {
logger.debug(e.getMessage(),e);
}
}
if (_networkModel.checkSecurityGroupSupportForNetwork(
_accountMgr.getActiveAccountById(vm.getAccountId()),
zone, networkIds, securityGroupIdList)
) {
updateSecurityGroup(vm, securityGroupIdList);
}
}
}
private void updateSecurityGroup(UserVmVO vm, List<Long> securityGroupIdList) {
if (vm.getState() == State.Stopped) {
// Remove instance from security groups
_securityGroupMgr.removeInstanceFromGroups(vm);
// Add instance in provided groups
_securityGroupMgr.addInstanceToGroups(vm, securityGroupIdList);
} else {
throw new InvalidParameterValueException(String.format("VM %s must be stopped prior to update security groups", vm.getUuid()));
}
}
protected void updateUserData(UserVm vm) throws ResourceUnavailableException, InsufficientCapacityException {
boolean result = updateUserDataInternal(vm);
if (result) {
@ -3696,7 +3703,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
boolean isVmWare = (template.getHypervisorType() == HypervisorType.VMware || (hypervisor != null && hypervisor == HypervisorType.VMware));
if (securityGroupIdList != null && isVmWare) {
throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor");
throw new InvalidParameterValueException("Security group feature is not supported for VMware hypervisor");
} else if (!isVmWare && _networkModel.isSecurityGroupSupportedInNetwork(defaultNetwork) && _networkModel.canAddDefaultSecurityGroup()) {
//add the default securityGroup only if no security group is specified
if (securityGroupIdList == null || securityGroupIdList.isEmpty()) {
@ -3756,7 +3763,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} else if (securityGroupIdList != null && !securityGroupIdList.isEmpty()) {
if (isVmWare) {
throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor");
throw new InvalidParameterValueException("Security group feature is not supported for VMware hypervisor");
}
// Only one network can be specified, and it should be security group enabled
if (networkIdList.size() > 1 && template.getHypervisorType() != HypervisorType.KVM && hypervisor != HypervisorType.KVM) {

View File

@ -114,7 +114,7 @@ public class QueryManagerImplTest {
@Spy
@InjectMocks
private QueryManagerImpl queryManagerImplSpy = new QueryManagerImpl();
private QueryManagerImpl queryManagerImplSpy;
@Mock
EntityManager entityManager;
@ -225,7 +225,7 @@ public class QueryManagerImplTest {
Mockito.when(entityManager.findByUuidIncludingRemoved(Network.class, uuid)).thenReturn(network);
Mockito.doNothing().when(accountManager).checkAccess(account, SecurityChecker.AccessType.ListEntry, true, network);
Mockito.when(eventDao.searchAndCount(Mockito.any(), Mockito.any(Filter.class))).thenReturn(pair);
Mockito.when(eventJoinDao.searchByIds(Mockito.any())).thenReturn(eventJoins);
Mockito.lenient().when(eventJoinDao.searchByIds(Mockito.any())).thenReturn(eventJoins);
List<EventResponse> respList = new ArrayList<EventResponse>();
for (EventJoinVO vt : eventJoins) {
respList.add(eventJoinDao.newEventResponse(vt));

View File

@ -118,6 +118,11 @@ import com.cloud.vm.dao.NicDao;
@RunWith(MockitoJUnitRunner.class)
public class NetworkServiceImplTest {
@Mock
Object job;
@Mock
Object _responseObject;
@Mock
AccountManager accountManager;
@Mock
@ -141,11 +146,11 @@ public class NetworkServiceImplTest {
@Mock
VpcManager vpcMgr;
@Mock
NetworkOrchestrationService networkManager;
NetworkOrchestrationService _networkMgr;
@Mock
AlertManager alertManager;
@Mock
DataCenterDao dcDao;
DataCenterDao _dcDao;
@Mock
UserDao userDao;
@Mock
@ -165,7 +170,7 @@ public class NetworkServiceImplTest {
@Mock
DomainRouterDao routerDao;
@Mock
AccountService accountService;
AccountService _accountService;
@Mock
NetworkHelper networkHelper;
@Mock
@ -192,7 +197,7 @@ public class NetworkServiceImplTest {
@Mock
private DomainVO domainVOMock;
@InjectMocks
NetworkServiceImpl service = new NetworkServiceImpl();
NetworkServiceImpl service;
@Mock
DomainDao domainDaoMock;
@ -297,14 +302,11 @@ public class NetworkServiceImplTest {
vpc = Mockito.mock(VpcVO.class);
service._networkOfferingDao = networkOfferingDao;
service._physicalNetworkDao = physicalNetworkDao;
service._dcDao = dcDao;
service._accountMgr = accountManager;
service._networkMgr = networkManager;
service.alertManager = alertManager;
service._configMgr = configMgr;
service._vpcDao = vpcDao;
service._vpcMgr = vpcMgr;
service._accountService = accountService;
service._networksDao = networkDao;
service._nicDao = nicDao;
service._ipAddressDao = ipAddressDao;
@ -323,7 +325,7 @@ public class NetworkServiceImplTest {
Mockito.when(entityMgr.findById(NetworkOffering.class, 1L)).thenReturn(networkOffering);
Mockito.when(networkOfferingDao.findById(1L)).thenReturn(offering);
Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(phyNet);
Mockito.when(dcDao.findById(Mockito.anyLong())).thenReturn(dc);
Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc);
Mockito.when(accountManager.isRootAdmin(accountMock.getId())).thenReturn(true);
}
@ -442,12 +444,12 @@ public class NetworkServiceImplTest {
Mockito.when(dc.getId()).thenReturn(1L);
Mockito.when(dc.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled);
Map<String, String> networkProvidersMap = new HashMap<String, String>();
Mockito.when(networkManager.finalizeServicesAndProvidersForNetwork(ArgumentMatchers.any(NetworkOffering.class), anyLong())).thenReturn(networkProvidersMap);
Mockito.when(_networkMgr.finalizeServicesAndProvidersForNetwork(ArgumentMatchers.any(NetworkOffering.class), anyLong())).thenReturn(networkProvidersMap);
Mockito.when(configMgr.isOfferingForVpc(offering)).thenReturn(false);
Mockito.when(offering.isInternalLb()).thenReturn(false);
service.createGuestNetwork(createNetworkCmd);
Mockito.verify(networkManager, times(1)).createGuestNetwork(1L, "testNetwork", "Test Network", null,
Mockito.verify(_networkMgr, times(1)).createGuestNetwork(1L, "testNetwork", "Test Network", null,
null, null, false, null, accountMock, null, phyNet,
1L, null, null, null, null, null,
true, null, null, null, null, null,
@ -769,7 +771,7 @@ public class NetworkServiceImplTest {
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
when(cmd.getZoneId()).thenReturn(zoneId);
when(dcDao.findById(zoneId)).thenReturn(zone);
when(_dcDao.findById(zoneId)).thenReturn(zone);
when(zone.getId()).thenReturn(zoneId);
try {
@ -795,7 +797,7 @@ public class NetworkServiceImplTest {
ReflectionTestUtils.setField(createNetworkCmd, "vpcId", vpcId);
dc = Mockito.mock(DataCenterVO.class);
Mockito.when(dcDao.findById(zoneId)).thenReturn(dc);
Mockito.when(_dcDao.findById(zoneId)).thenReturn(dc);
Mockito.when(dc.getId()).thenReturn(zoneId);
vpc = Mockito.mock(VpcVO.class);
Mockito.when(vpc.getName()).thenReturn("Vpc 1");
@ -831,7 +833,7 @@ public class NetworkServiceImplTest {
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
when(cmd.getZoneId()).thenReturn(zoneId);
when(dcDao.findById(zoneId)).thenReturn(zone);
when(_dcDao.findById(zoneId)).thenReturn(zone);
when(zone.getId()).thenReturn(zoneId);
try {
@ -859,7 +861,7 @@ public class NetworkServiceImplTest {
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
when(cmd.getZoneId()).thenReturn(zoneId);
when(dcDao.findById(zoneId)).thenReturn(zone);
when(_dcDao.findById(zoneId)).thenReturn(zone);
when(zone.getId()).thenReturn(zoneId);
try {
@ -889,7 +891,7 @@ public class NetworkServiceImplTest {
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
when(cmd.getZoneId()).thenReturn(zoneId);
when(dcDao.findById(zoneId)).thenReturn(zone);
when(_dcDao.findById(zoneId)).thenReturn(zone);
when(zone.getId()).thenReturn(zoneId);
try {

View File

@ -171,7 +171,9 @@ public class VirtualRouterElementTest {
@Mock private RemoteAccessVpnDao _vpnDao;
@Mock private VpnUserDao _vpnUsersDao;
@Mock private VirtualRouterProviderDao _vrProviderDao;
@Mock private LoadBalancerDao loadBalancerDao;
@Mock private LoadBalancerDao _lbDao;
@Mock private NetworkDao networkDao;
@Mock private NetworkDao _networksDao;
@Mock private OvsProviderDao _ovsProviderDao;
@ -180,6 +182,7 @@ public class VirtualRouterElementTest {
@Mock private AccountManager _accountMgr;
@Mock private ConfigurationManager _configMgr;
@Mock private NetworkModel networkModel;
@Mock private NetworkModel _networkMdl;
@Mock private NetworkOrchestrationService _networkMgr;
@Mock private ResourceManager _resourceMgr;

View File

@ -86,13 +86,11 @@ import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vpc.MockResourceLimitManagerImpl;
import junit.framework.TestCase;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ResourceLimitManagerImplTest extends TestCase {
public class ResourceLimitManagerImplTest {
private Logger logger = LogManager.getLogger(ResourceLimitManagerImplTest.class);
MockResourceLimitManagerImpl _resourceLimitService = new MockResourceLimitManagerImpl();
@ -142,14 +140,11 @@ public class ResourceLimitManagerImplTest extends TestCase {
f.set(configKey, o);
}
@Before
public void setUp() {
try {
overrideDefaultConfigValue(ResourceLimitService.ResourceLimitHostTags, "_defaultValue", StringUtils.join(hostTags, ","));
overrideDefaultConfigValue(ResourceLimitService.ResourceLimitStorageTags, "_defaultValue", StringUtils.join(storageTags, ","));
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.error("Failed to update configurations");
}
public void setUp() throws Exception {
overrideDefaultConfigValue(ResourceLimitService.ResourceLimitHostTags, "_defaultValue", StringUtils.join(hostTags, ","));
overrideDefaultConfigValue(ResourceLimitService.ResourceLimitStorageTags, "_defaultValue", StringUtils.join(storageTags, ","));
Account account = mock(Account.class);
User user = mock(User.class);
@ -288,6 +283,7 @@ public class ResourceLimitManagerImplTest extends TestCase {
Mockito.when(template.getTemplateTag()).thenReturn(hostTags.get(0));
Account account = Mockito.mock(Account.class);
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVmResourceLimit(account, true, serviceOffering, template);
List<String> tags = new ArrayList<>();
@ -347,6 +343,7 @@ public class ResourceLimitManagerImplTest extends TestCase {
Mockito.when(diskOffering.getTagsArray()).thenReturn(new String[]{checkTag});
Account account = Mockito.mock(Account.class);
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVolumeResourceLimit(account, true, 100L, diskOffering);
List<String> tags = new ArrayList<>();

View File

@ -235,7 +235,6 @@ public class SnapshotManagerTest {
doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class));
doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class), anyLong());
doNothing().when(_resourceLimitMgr).decrementResourceCount(anyLong(), any(ResourceType.class), anyLong());
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class));
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class), anyLong());
@ -352,7 +351,6 @@ public class SnapshotManagerTest {
when(_vmDao.findById(anyLong())).thenReturn(vmMock);
when(vmMock.getState()).thenReturn(State.Stopped);
when (snapshotStrategy.revertSnapshot(any(SnapshotInfo.class))).thenReturn(true);
when(_volumeDao.update(anyLong(), any(VolumeVO.class))).thenReturn(true);
doReturn(DataStoreRole.Image).when(snapshotHelperMock).getDataStoreRole(any());
Snapshot snapshot = _snapshotMgr.revertSnapshot(TEST_SNAPSHOT_ID);
Assert.assertNotNull(snapshot);

View File

@ -113,6 +113,8 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
@Mock
private AccountVO accountVoMock;
@Mock
private AccountVO _systemAccount;
@Mock
private ProjectAccountVO projectAccountVO;
@ -1406,4 +1408,75 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
Assert.assertNull(updatedUser.getUser2faProvider());
Assert.assertNull(updatedUser.getKeyFor2fa());
}
@Test(expected = InvalidParameterValueException.class)
public void testAssertUserNotAlreadyInAccount_UserExistsInAccount() {
User existingUser = new UserVO();
existingUser.setUsername("testuser");
existingUser.setAccountId(1L);
Account newAccount = Mockito.mock(Account.class);
Mockito.when(newAccount.getId()).thenReturn(1L);
AccountVO existingAccount = Mockito.mock(AccountVO.class);
Mockito.when(existingAccount.getUuid()).thenReturn("existing-account-uuid");
Mockito.when(existingAccount.getAccountName()).thenReturn("existing-account");
Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount);
accountManagerImpl.assertUserNotAlreadyInAccount(existingUser, newAccount);
}
@Test
public void testAssertUserNotAlreadyInAccount_UserExistsInDiffAccount() {
User existingUser = new UserVO();
existingUser.setUsername("testuser");
existingUser.setAccountId(2L);
Account newAccount = Mockito.mock(Account.class);
Mockito.when(newAccount.getId()).thenReturn(1L);
accountManagerImpl.assertUserNotAlreadyInAccount(existingUser, newAccount);
}
@Test(expected = InvalidParameterValueException.class)
public void testAssertUserNotAlreadyInDomain_UserExistsInDomain() {
User existingUser = new UserVO();
existingUser.setUsername("testuser");
existingUser.setAccountId(1L);
Account originalAccount = Mockito.mock(Account.class);
Mockito.when(originalAccount.getDomainId()).thenReturn(1L);
AccountVO existingAccount = Mockito.mock(AccountVO.class);
Mockito.when(existingAccount.getDomainId()).thenReturn(1L);
Mockito.when(existingAccount.getUuid()).thenReturn("existing-account-uuid");
Mockito.when(existingAccount.getAccountName()).thenReturn("existing-account");
DomainVO existingDomain = Mockito.mock(DomainVO.class);
Mockito.when(existingDomain.getUuid()).thenReturn("existing-domain-uuid");
Mockito.when(existingDomain.getName()).thenReturn("existing-domain");
Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount);
Mockito.when(_domainDao.findById(1L)).thenReturn(existingDomain);
accountManagerImpl.assertUserNotAlreadyInDomain(existingUser, originalAccount);
}
@Test
public void testAssertUserNotAlreadyInDomain_UserExistsInDiffDomain() {
User existingUser = new UserVO();
existingUser.setUsername("testuser");
existingUser.setAccountId(1L);
Account originalAccount = Mockito.mock(Account.class);
Mockito.when(originalAccount.getDomainId()).thenReturn(1L);
AccountVO existingAccount = Mockito.mock(AccountVO.class);
Mockito.when(existingAccount.getDomainId()).thenReturn(2L);
Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount);
accountManagerImpl.assertUserNotAlreadyInDomain(existingUser, originalAccount);
}
}

View File

@ -56,8 +56,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -150,7 +150,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
lenient().when(_domainMgr.getDomain(nullable(Long.class))).thenReturn(domain);
Mockito.doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
lenient().doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class));
}

View File

@ -286,7 +286,7 @@ public class SnapshotHelperTest {
@Test (expected = CloudRuntimeException.class)
public void validateThrowCloudRuntimeExceptionOfSnapshotsOnlyInPrimaryStorage() {
Mockito.doReturn(new ArrayList<>()).when(snapshotDaoMock).listByIds(Mockito.any());
Mockito.lenient().doReturn(new ArrayList<>()).when(snapshotDaoMock).listByIds(Mockito.any());
snapshotHelperSpy.throwCloudRuntimeExceptionOfSnapshotsOnlyInPrimaryStorage(null, new HashSet<>());
}

View File

@ -22,7 +22,6 @@ import org.apache.logging.log4j.Logger;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import java.io.File;
import java.nio.file.Files;
@ -104,7 +103,7 @@ public class NfsSecondaryStorageResourceTest {
@Test
public void testCleanupStagingNfs() throws Exception{
NfsSecondaryStorageResource spyResource = spy(resource);
NfsSecondaryStorageResource spyResource = resource;
spyResource.logger = loggerMock;
RuntimeException exception = new RuntimeException();
doThrow(exception).when(spyResource).execute(any(DeleteCommand.class));

View File

@ -82,7 +82,7 @@ class CsDhcp(CsDataBag):
CsHelper.service("dnsmasq", "reload")
def configure_server(self):
# self.conf.addeq("dhcp-hostsfile=%s" % DHCP_HOSTS)
self.conf.add("bind-interfaces", 0)
idx = 0
listen_address = ["127.0.0.1"]
for i in self.devinfo:

View File

@ -2878,7 +2878,7 @@
"message.attach.volume.progress": "Attaching volume",
"message.attach.volume.success": "Successfully attached the volume to the instance",
"message.authorization.failed": "Session expired, authorization verification failed.",
"message.autoscale.loadbalancer.update": "The load balancer rule can be updated only when autoscaling group is DISABLED.",
"message.autoscale.loadbalancer.update": "The load balancer rule can be updated. However, instance can be removed only when autoscaling group is DISABLED.",
"message.autoscale.policies.update": "The scale up/down policies can be updated only when autoscaling group is DISABLED.",
"message.autoscale.vm.networks": "Please choose at least one Network for Instances in the autoscaling group. The default Network must be an Isolated Network or VPC Network Tier which supports Instance AutoScaling and has load balancing rules.",
"message.autoscale.vmprofile.update": "The autoscale Instance profile can be updated only when autoscaling group is DISABLED.",
@ -2960,6 +2960,7 @@
"message.confirm.remove.vmware.datacenter": "Please confirm you want to remove VMware datacenter.",
"message.confirm.remove.vpc.offering": "Are you sure you want to remove this VPC offering?",
"message.confirm.replace.acl.new.one": "Do you want to replace the ACL with a new one?",
"message.confirm.reset.configuration.value": "Are you sure you want reset configuration - %x?",
"message.confirm.reset.network.permissions": "Are you sure you want to reset this Network permissions?",
"message.confirm.scale.up.router.vm": "Do you really want to scale up the router Instance?",
"message.confirm.scale.up.system.vm": "Do you really want to scale up the system VM?",

View File

@ -88,6 +88,7 @@ export default {
this.showSwitcher = false
return
}
this.samlAccounts = samlAccounts
this.samlAccounts = _.orderBy(samlAccounts, ['domainPath'], ['asc'])
const currentAccount = this.samlAccounts.filter(x => {
return x.userId === store.getters.userInfo.id
@ -109,6 +110,8 @@ export default {
this.$message.success(`Switched to "${account.accountName} (${account.domainPath})"`)
this.$router.go()
})
}).else(error => {
console.log('error refreshing with new user context: ' + error)
})
}
}

View File

@ -673,7 +673,7 @@
<span v-else>{{ resource.podname || resource.pod || resource.podid }}</span>
</div>
</div>
<div class="resource-detail-item" v-if="resource.zoneid">
<div class="resource-detail-item" v-if="resource.zoneid && !['template', 'iso'].includes($route.path.split('/')[1])">
<div class="resource-detail-item__label">{{ $t('label.zone') }}</div>
<div class="resource-detail-item__details">
<span v-if="images.zone">
@ -760,7 +760,7 @@
<span v-else>{{ resource.managementserver || resource.managementserverid }}</span>
</div>
</div>
<div class="resource-detail-item" v-if="resource.created">
<div class="resource-detail-item" v-if="resource.created && !['template', 'iso'].includes($route.path.split('/')[1])">
<div class="resource-detail-item__label">{{ $t('label.created') }}</div>
<div class="resource-detail-item__details">
<calendar-outlined />{{ $toLocaleDate(resource.created) }}

View File

@ -543,7 +543,7 @@
iconTwoToneColor="#52c41a" />
<tooltip-button
:tooltip="$t('label.reset.config.value')"
@onClick="resetConfig(record)"
@onClick="$resetConfigurationValueConfirm(item, resetConfig)"
v-if="editableValueKey !== record.key"
icon="reload-outlined"
:disabled="!('updateConfiguration' in $store.getters.apis)" />

View File

@ -35,7 +35,8 @@ import {
resourceTypePlugin,
fileSizeUtilPlugin,
genericUtilPlugin,
localesPlugin
localesPlugin,
dialogUtilPlugin
} from './utils/plugins'
import { VueAxios } from './utils/request'
import directives from './utils/directives'
@ -51,6 +52,7 @@ vueApp.use(resourceTypePlugin)
vueApp.use(fileSizeUtilPlugin)
vueApp.use(localesPlugin)
vueApp.use(genericUtilPlugin)
vueApp.use(dialogUtilPlugin)
vueApp.use(extensions)
vueApp.use(directives)

View File

@ -331,7 +331,7 @@ const user = {
commit('SET_MS_ID', msId)
// Ensuring we get the user info so that store.getters.user is never empty when the page is freshly loaded
api('listUsers', { username: Cookies.get('username'), listall: true }).then(response => {
api('listUsers', { id: Cookies.get('userid'), listall: true }).then(response => {
const result = response.listusersresponse.user[0]
commit('SET_INFO', result)
commit('SET_NAME', result.firstname + ' ' + result.lastname)
@ -404,7 +404,7 @@ const user = {
}).catch(ignored => {})
}
api('listUsers', { username: Cookies.get('username') }).then(response => {
api('listUsers', { id: Cookies.get('userid') }).then(response => {
const result = response.listusersresponse.user[0]
commit('SET_INFO', result)
commit('SET_NAME', result.firstname + ' ' + result.lastname)

View File

@ -18,7 +18,7 @@
import _ from 'lodash'
import { i18n } from '@/locales'
import { api } from '@/api'
import { message, notification } from 'ant-design-vue'
import { message, notification, Modal } from 'ant-design-vue'
import eventBus from '@/config/eventBus'
import store from '@/store'
import { sourceToken } from '@/utils/request'
@ -526,3 +526,18 @@ export function createPathBasedOnVmType (vmtype, virtualmachineid) {
return path + virtualmachineid
}
export const dialogUtilPlugin = {
install (app) {
app.config.globalProperties.$resetConfigurationValueConfirm = function (configRecord, callback) {
Modal.confirm({
title: i18n.global.t('label.reset.config.value'),
content: `${i18n.global.t('message.confirm.reset.configuration.value').replace('%x', configRecord.name)}`,
okText: i18n.global.t('label.yes'),
cancelText: i18n.global.t('label.no'),
okType: 'primary',
onOk: () => callback(configRecord)
})
}
}
}

View File

@ -206,7 +206,7 @@ export default {
zoneid: this.resource.zoneid
}).then(response => {
const zone = response?.listzonesresponse?.zone || []
this.securityGroupsEnabled = zone?.[0]?.securitygroupsenabled
this.securityGroupsEnabled = zone?.[0]?.securitygroupsenabled || this.$store.getters.showSecurityGroups
})
},
fetchSecurityGroups () {

View File

@ -179,6 +179,7 @@ export default {
vm: {},
totalStorage: 0,
currentTab: 'details',
showUpdateSecurityGroupsModal: false,
showAddVolumeModal: false,
diskOfferings: [],
annotations: [],

View File

@ -48,6 +48,9 @@
<span v-if="record.isready">{{ $t('label.yes') }}</span>
<span v-else>{{ $t('label.no') }}</span>
</template>
<template v-else-if="column.key === 'created'">
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
</template>
<template v-if="column.key === 'actions'">
<span style="margin-right: 5px">
<tooltip-button
@ -262,6 +265,11 @@ export default {
title: this.$t('label.zonename'),
dataIndex: 'zonename'
},
{
key: 'created',
title: this.$t('label.created'),
dataIndex: 'created'
},
{
title: this.$t('label.status'),
dataIndex: 'status'

View File

@ -48,6 +48,9 @@
<span v-if="record.isready">{{ $t('label.yes') }}</span>
<span v-else>{{ $t('label.no') }}</span>
</template>
<template v-else-if="column.key === 'created'">
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
</template>
<template v-if="column.key === 'actions'">
<tooltip-button
style="margin-right: 5px"
@ -308,6 +311,11 @@ export default {
title: this.$t('label.zonename'),
dataIndex: 'zonename'
},
{
key: 'created',
title: this.$t('label.created'),
dataIndex: 'created'
},
{
title: this.$t('label.status'),
dataIndex: 'status'

View File

@ -703,6 +703,7 @@ export default {
title = this.$t('label.view')
break
case 'virtualmachinename':
title = this.$t('label.virtualmachinename')
dataIndex = 'name'
break
default:

View File

@ -449,12 +449,16 @@ export default {
services.push({
name: 'Dhcp',
provider: [
{ name: 'VpcVirtualRouter' }
{ name: 'VpcVirtualRouter' },
{ name: 'ConfigDrive' }
]
})
services.push({
name: 'Dns',
provider: [{ name: 'VpcVirtualRouter' }]
provider: [
{ name: 'VpcVirtualRouter' },
{ name: 'ConfigDrive' }
]
})
services.push({
name: 'Lb',

View File

@ -184,7 +184,7 @@
:disabled="valueLoading" />
<tooltip-button
:tooltip="$t('label.reset.config.value')"
@onClick="resetConfigurationValue(configrecord)"
@onClick="$resetConfigurationValueConfirm(configrecord, resetConfigurationValue)"
v-if="editableValueKey === null"
icon="reload-outlined"
:disabled="(!('resetConfiguration' in $store.getters.apis) || configDisabled || valueLoading)" />

View File

@ -31,7 +31,8 @@ import {
showIconPlugin,
resourceTypePlugin,
fileSizeUtilPlugin,
genericUtilPlugin
genericUtilPlugin,
dialogUtilPlugin
} from '@/utils/plugins'
function createMockRouter (newRoutes = []) {
@ -88,6 +89,7 @@ function createFactory (component, options) {
resourceTypePlugin,
fileSizeUtilPlugin,
genericUtilPlugin,
dialogUtilPlugin,
StoragePlugin
],
mocks

View File

@ -143,7 +143,7 @@ const vueConfig = {
ws: false,
changeOrigin: true,
proxyTimeout: 10 * 60 * 1000, // 10 minutes
cookieDomainRewrite: '*',
cookieDomainRewrite: process.env.CS_COOKIE_HOST || 'localhost',
cookiePathRewrite: {
'/client': '/'
}

View File

@ -29,6 +29,7 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@ -36,7 +37,9 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.nio.TrustAllManager;
import com.google.gson.JsonElement;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
@ -75,14 +78,15 @@ public class RedfishClient {
private boolean ignoreSsl;
private int redfishRequestMaxRetries;
private final static String SYSTEMS_URL_PATH = "redfish/v1/Systems/";
private final static String COMPUTER_SYSTEM_RESET_URL_PATH = "/Actions/ComputerSystem.Reset";
private final static String SYSTEMS_URL_PATH = "redfish/v1/Systems";
private final static String COMPUTER_SYSTEM_RESET_URL_PATH = "Actions/ComputerSystem.Reset";
private final static String REDFISH_RESET_TYPE = "ResetType";
private final static String POWER_STATE = "PowerState";
private final static String APPLICATION_JSON = "application/json";
private final static String ACCEPT = "accept";
private final static String ODATA_ID = "@odata.id";
private final static String MEMBERS = "Members";
private final static String LINKS = "Links";
private final static String EXPECTED_HTTP_STATUS = "2XX";
private final static int WAIT_FOR_REQUEST_RETRY = 2;
@ -265,12 +269,12 @@ public class RedfishClient {
if (StringUtils.isBlank(resourceId)) {
throw new RedfishException(String.format("Command '%s' requires a valid resource ID '%s'.", cmd, resourceId));
}
return String.format("%s%s", SYSTEMS_URL_PATH, resourceId);
return String.format("%s/%s", SYSTEMS_URL_PATH, resourceId);
case ComputerSystemReset:
if (StringUtils.isBlank(resourceId)) {
throw new RedfishException(String.format("Command '%s' requires a valid resource ID '%s'.", cmd, resourceId));
}
return String.format("%s%s%s", SYSTEMS_URL_PATH, resourceId, COMPUTER_SYSTEM_RESET_URL_PATH);
return String.format("%s/%s/%s", SYSTEMS_URL_PATH, resourceId, COMPUTER_SYSTEM_RESET_URL_PATH);
default:
throw new RedfishException(String.format("Redfish client does not support command '%s'.", cmd));
}
@ -305,8 +309,8 @@ public class RedfishClient {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
throw new RedfishException(String.format("Failed to get System power state for host '%s' with request '%s: %s'. The expected HTTP status code is '%s' but it got '%s'.",
HttpGet.METHOD_NAME, url, hostAddress, EXPECTED_HTTP_STATUS, statusCode));
throw new RedfishException(String.format("Failed to execute System power command for host by performing '%s' request on URL '%s' and host address '%s'. The expected HTTP status code is '%s' but it got '%s'.",
HttpPost.METHOD_NAME, url, hostAddress, EXPECTED_HTTP_STATUS, statusCode));
}
logger.debug(String.format("Sending ComputerSystem.Reset Command '%s' to host '%s' with request '%s %s'", resetCommand, hostAddress, HttpPost.METHOD_NAME, url));
}
@ -340,16 +344,25 @@ public class RedfishClient {
try {
in = response.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
jsonString = streamReader.readLine();
jsonString = streamReader.lines().collect(Collectors.joining());
} catch (UnsupportedOperationException | IOException e) {
throw new RedfishException("Failed to process system Response", e);
}
// retrieving the system ID (e.g. 'System.Embedded.1') via JsonParser:
// (...) Members":[{"@odata.id":"/redfish/v1/Systems/System.Embedded.1"}] (...)
JsonArray jArray = new JsonParser().parse(jsonString).getAsJsonObject().get(MEMBERS).getAsJsonArray();
JsonObject jsonnObject = jArray.get(0).getAsJsonObject();
String jsonObjectAsString = jsonnObject.get(ODATA_ID).getAsString();
JsonArray jArray = null;
JsonElement jsonElement = new JsonParser().parse(jsonString);
if (jsonElement.getAsJsonObject().get(MEMBERS) != null) {
jArray = jsonElement.getAsJsonObject().get(MEMBERS).getAsJsonArray();
} else if (jsonElement.getAsJsonObject().get(LINKS) != null){
jArray = jsonElement.getAsJsonObject().get(LINKS).getAsJsonObject().get(MEMBERS).getAsJsonArray();
}
if (jArray == null || jArray.size() < 1) {
throw new CloudRuntimeException("Members not found in the Redfish Systems JSON, unable to determine Redfish system ID");
}
JsonObject jsonObject = jArray.get(0).getAsJsonObject();
String jsonObjectAsString = jsonObject.get(ODATA_ID).getAsString();
String[] arrayOfStrings = StringUtils.split(jsonObjectAsString, '/');
return arrayOfStrings[arrayOfStrings.length - 1];
@ -384,8 +397,7 @@ public class RedfishClient {
try {
in = response.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
jsonString = streamReader.readLine();
jsonString = streamReader.lines().collect(Collectors.joining());
String powerState = new JsonParser().parse(jsonString).getAsJsonObject().get(POWER_STATE).getAsString();
return RedfishPowerState.valueOf(powerState);
} catch (UnsupportedOperationException | IOException e) {

View File

@ -276,8 +276,8 @@ public class UriUtilsTest {
@Test
public void validateUrl() {
Pair<String, Integer> url1 = UriUtils.validateUrl("https://www.cloudstack.org");
Assert.assertEquals(url1.first(), "www.cloudstack.org");
Pair<String, Integer> url1 = UriUtils.validateUrl("https://cloudstack.apache.org/");
Assert.assertEquals(url1.first(), "cloudstack.apache.org");
Pair<String, Integer> url2 = UriUtils.validateUrl("https://www.apache.org");
Assert.assertEquals(url2.first(), "www.apache.org");

View File

@ -41,9 +41,9 @@ public class RedfishClientTest {
private static final String PASSWORD = "password";
private static final String oobAddress = "oob.host.address";
private static final String systemId = "SystemID.1";
private final static String COMPUTER_SYSTEM_RESET_URL_PATH = "/Actions/ComputerSystem.Reset";
private final static String COMPUTER_SYSTEM_RESET_URL_PATH = "Actions/ComputerSystem.Reset";
private final static Integer REDFISHT_REQUEST_RETRIES = Integer.valueOf(2);
private static final String url = "https://address.system.net/redfish/v1/Systems/";
private static final String url = "https://address.system.net/redfish/v1/Systems";
private static final HttpRequestBase httpReq = new HttpGet(url);
@Mock
@ -87,7 +87,7 @@ public class RedfishClientTest {
public void buildRequestUrlTestHttpsGetSystemId() {
RedfishClient redfishclient = new RedfishClient(USERNAME, PASSWORD, true, false, REDFISHT_REQUEST_RETRIES);
String result = redfishclient.buildRequestUrl(oobAddress, RedfishClient.RedfishCmdType.GetSystemId, systemId);
String expected = String.format("https://%s/redfish/v1/Systems/", oobAddress);
String expected = String.format("https://%s/redfish/v1/Systems", oobAddress);
Assert.assertEquals(expected, result);
}
@ -95,7 +95,7 @@ public class RedfishClientTest {
public void buildRequestUrlTestGetSystemId() {
RedfishClient redfishclient = new RedfishClient(USERNAME, PASSWORD, false, false, REDFISHT_REQUEST_RETRIES);
String result = redfishclient.buildRequestUrl(oobAddress, RedfishClient.RedfishCmdType.GetSystemId, systemId);
String expected = String.format("http://%s/redfish/v1/Systems/", oobAddress);
String expected = String.format("http://%s/redfish/v1/Systems", oobAddress);
Assert.assertEquals(expected, result);
}
@ -103,7 +103,7 @@ public class RedfishClientTest {
public void buildRequestUrlTestHttpsComputerSystemReset() {
RedfishClient redfishclient = new RedfishClient(USERNAME, PASSWORD, true, false, REDFISHT_REQUEST_RETRIES);
String result = redfishclient.buildRequestUrl(oobAddress, RedfishClient.RedfishCmdType.ComputerSystemReset, systemId);
String expected = String.format("https://%s/redfish/v1/Systems/%s%s", oobAddress, systemId, COMPUTER_SYSTEM_RESET_URL_PATH);
String expected = String.format("https://%s/redfish/v1/Systems/%s/%s", oobAddress, systemId, COMPUTER_SYSTEM_RESET_URL_PATH);
Assert.assertEquals(expected, result);
}
@ -111,7 +111,7 @@ public class RedfishClientTest {
public void buildRequestUrlTestComputerSystemReset() {
RedfishClient redfishclient = new RedfishClient(USERNAME, PASSWORD, false, false, REDFISHT_REQUEST_RETRIES);
String result = redfishclient.buildRequestUrl(oobAddress, RedfishClient.RedfishCmdType.ComputerSystemReset, systemId);
String expected = String.format("http://%s/redfish/v1/Systems/%s%s", oobAddress, systemId, COMPUTER_SYSTEM_RESET_URL_PATH);
String expected = String.format("http://%s/redfish/v1/Systems/%s/%s", oobAddress, systemId, COMPUTER_SYSTEM_RESET_URL_PATH);
Assert.assertEquals(expected, result);
}