Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.ovirt.engine.core.bll;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.inject.Inject;

import org.ovirt.engine.core.bll.context.EngineContext;
import org.ovirt.engine.core.common.businessentities.VdsStatic;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.queries.IdsQueryParameters;
import org.ovirt.engine.core.common.queries.QueryReturnValue;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VdsStaticDao;
import org.ovirt.engine.core.dao.VmDynamicDao;
import org.ovirt.engine.core.utils.CertificateSubjectHelper;


public class GetVdsCertificateSubjectsByVmIdsQuery<P extends IdsQueryParameters> extends QueriesCommandBase<P> {
@Inject
private VmDynamicDao vmDynamicDao;

@Inject
private VdsStaticDao vdsStaticDao;

public GetVdsCertificateSubjectsByVmIdsQuery(P parameters, EngineContext engineContext) {
super(parameters, engineContext);
}

@Override
protected void executeQueryCommand() {
// Initially we set the command as failed:
QueryReturnValue queryReturnValue = getQueryReturnValue();
queryReturnValue.setSucceeded(false);

// Check if the virtual machines are running on hosts, and if so then retrieve the hosts and copy the subject
// of the certificate to the value returned by the query:
List<VmDynamic> vms = vmDynamicDao.getByIds(getParameters().getIds());
List<Guid> vdsIds = vms.stream()
.map(VmDynamic::getRunOnVds)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (!vdsIds.isEmpty()) {
List<VdsStatic> vdss = vdsStaticDao.getByIds(vdsIds);
// Collect certificate subjects for all hosts running the VMs
Map<Guid, String> certificateSubjects = vdss.stream()
.collect(Collectors.toMap(
VdsStatic::getId,
vds -> CertificateSubjectHelper.getCertificateSubject(vds.getHostName())));
// Populate the certificate subjects for corresponding VMs
Map<Guid, String> certificateForVms = new HashMap<>();
for (VmDynamic vm : vms) {
Guid vdsId = vm.getRunOnVds();
if (vdsId != null) {
String subject = certificateSubjects.get(vdsId);
if (subject != null) {
certificateForVms.put(vm.getId(), subject);
}
}
}
if (!certificateForVms.isEmpty()) {
queryReturnValue.setSucceeded(true);
queryReturnValue.setReturnValue(certificateForVms);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ public enum QueryType implements Serializable {

// Cluster
GetVdsCertificateSubjectByVmId(QueryAuthType.User),
GetVdsCertificateSubjectsByVmIds(QueryAuthType.User),
GetAllClusters(QueryAuthType.User),
GetClusterById(QueryAuthType.User),
GetClusterByName(QueryAuthType.User),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public interface VmDynamicDao extends GenericDao<VmDynamic, Guid>, StatusAwareDa
@Override
VmDynamic get(Guid id);

/**
* Get all VmDynamic with the given ids
* @param vmIds
* the list of VM ids
* @return list of corresponding dynamics
*/
List<VmDynamic> getByIds(List<Guid> vmIds);

/**
* Updates the specified dynamic vm.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ public List<VmDynamic> getAllRunningForUserAndActionGroup(Guid userID, ActionGro
getCustomMapSqlParameterSource().addValue("user_id", userID).addValue("action_group_id", actionGroup.getId()));
}

@Override
public List<VmDynamic> getByIds(List<Guid> vmIds) {
return getCallsHandler().executeReadList("GetVmDynamicByVmGuids",
createEntityRowMapper(),
getCustomMapSqlParameterSource()
.addValue("vm_guids", createArrayOfUUIDs(vmIds)));
}

@Override
protected MapSqlParameterSource createIdParameterMapper(Guid id) {
return getCustomMapSqlParameterSource().addValue("vm_guid", id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.ovirt.engine.api.common.util.DetailHelper;
import org.ovirt.engine.api.model.ActionableResource;
import org.ovirt.engine.api.model.AutoPinningPolicy;
import org.ovirt.engine.api.model.Certificate;
import org.ovirt.engine.api.model.Configuration;
import org.ovirt.engine.api.model.ConfigurationType;
import org.ovirt.engine.api.model.Disk;
Expand Down Expand Up @@ -731,6 +732,9 @@ protected Vms mapCollection(List<org.ovirt.engine.core.common.businessentities.V
// optimization of DB access: retrieve GraphicsDevices for all VMs at once
Map<Guid, List<GraphicsDevice>> vmsGraphicsDevices =
DisplayHelper.getGraphicsDevicesForMultipleEntities(this, vmIds);
// optimization of DB access: retrieve Certificates for all VMs at once
Map<Guid, Certificate> vmsCertificate =
DisplayHelper.getDisplayCertificatesForMultipleEntities(this, vmIds);

for (org.ovirt.engine.core.common.businessentities.VM entity : entities) {
Vm vm = map(entity);
Expand All @@ -742,7 +746,7 @@ protected Vms mapCollection(List<org.ovirt.engine.core.common.businessentities.V
vm.setGraphicsConsoles(consoles);
}
DisplayHelper.adjustDisplayData(this, vm, vmsGraphicsDevices, false);
DisplayHelper.addDisplayCertificate(this, vm);
DisplayHelper.addDisplayCertificate(vm, vmsCertificate.get(entity.getId()));
removeRestrictedInfo(vm);
collection.getVms().add(addLinks(populate(vm, entity)));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.ovirt.engine.api.restapi.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -157,6 +159,45 @@ public static void addDisplayCertificate(BackendResource res, Vm vm) {
}
}

public static void addDisplayCertificate(Vm vm, Certificate certificate) {
if (certificate != null) {
if (!vm.isSetDisplay()) {
vm.setDisplay(new Display());
}
vm.getDisplay().setCertificate(certificate);
}
}

public static Map<Guid, Certificate> getDisplayCertificatesForMultipleEntities(BackendResource res, List<Guid> vmIds) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding this addDisplayCertificate and getDisplayCertificatesForMultipleEntities could it not be a possibility to instead break out of the addDisplayCertificate function on cases that it is known there will not be a certificate present? This would reduce the added complexity but still result in the wanted output of less queries being run towards the backend. For example, a VM that is down returns null when the QueryType.GetVdsCertificateSubjectByVmId is ran. Thus this could be seen as an unneeded query and the function could be exited before this is executed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any follow up on this?

QueryReturnValue result =
res.runQuery(QueryType.GetVdsCertificateSubjectsByVmIds,
new IdsQueryParameters(vmIds));

if (result != null && result.getSucceeded() && result.getReturnValue() != null) {
Map<Guid, String> certificateForVms = result.getReturnValue();

String certificateContent = null;
final QueryReturnValue caCertificateReturnValue =
res.runQuery(QueryType.GetCACertificate, new QueryParametersBase());
if (caCertificateReturnValue.getSucceeded()) {
certificateContent = caCertificateReturnValue.getReturnValue();
}
String organizationName = CertificateSubjectHelper.getOrganizationName();

Map<Guid, Certificate> certificates = new HashMap<>();
for (Map.Entry<Guid, String> e : certificateForVms.entrySet()) {
Certificate cert = new Certificate();
cert.setSubject(e.getValue());
cert.setOrganization(organizationName);
cert.setContent(certificateContent);

certificates.put(e.getKey(), cert);
}
return certificates;
}
return Collections.emptyMap();
}

private static Display extractDisplayFromResource(BaseResource res) {
if (res instanceof Vm) {
return ((Vm) res).getDisplay();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.ovirt.engine.api.model.Certificate;
import org.ovirt.engine.api.model.Configuration;
import org.ovirt.engine.api.model.CreationStatus;
import org.ovirt.engine.api.model.Disk;
Expand Down Expand Up @@ -88,13 +89,14 @@ public class BackendVmsResourceTest
private static final String DEFAULT_TEMPLATE_ID = Guid.Empty.toString();
public static final String CERTIFICATE = "O=Redhat,CN=X.Y.Z.Q";
private static final String CA_CERT = "dummy-cert";
private static final String ORG = "ORG";

public BackendVmsResourceTest() {
super(new BackendVmsResource(), SearchType.VM, "VMs : ");
}

public static Stream<MockConfigDescriptor<?>> mockConfiguration() {
return Stream.of(MockConfigDescriptor.of(ConfigValues.OrganizationName, "ORG"),
return Stream.of(MockConfigDescriptor.of(ConfigValues.OrganizationName, ORG),
MockConfigDescriptor.of(ConfigValues.PropagateDiskErrors, false)
);
}
Expand Down Expand Up @@ -1161,11 +1163,11 @@ public void testList() throws Exception {
UriInfo uriInfo = setUpUriExpectations(null);

setUpGetGraphicsMultipleExpectations(3);
setUpQueryExpectations("");
setUpGetCertificateExpectations(1, 0);
setUpGetDisplayCertificatesMultipleExpectations();
setUpGetCaRootExpectations();
setUpQueryExpectations("");
collection.setUriInfo(uriInfo);
verifyCollection(getCollection());
verifyCollection(getCollection(), false, true);
}

@Test
Expand Down Expand Up @@ -1198,7 +1200,7 @@ private void testListAllConsoleAware(boolean allContent) throws Exception {

setUpQueryExpectations("");
collection.setUriInfo(uriInfo);
verifyCollection(getCollection());
verifyCollection(getCollection(), false, allContent);
}

@Test
Expand All @@ -1209,7 +1211,7 @@ public void testListAllContentHeader() throws Exception {
when(httpHeaders.getRequestHeader(BackendResource.ALL_CONTENT_HEADER)).thenReturn(populates);
setUpAllContentExpectations();
collection.setUriInfo(uriInfo);
verifyCollection(getCollection());
verifyCollection(getCollection(), false, true);
}

@Test
Expand All @@ -1221,7 +1223,7 @@ public void testListAllContentQueryParameter() throws Exception {
when(uriInfo.getQueryParameters()).thenReturn(queries);
setUpAllContentExpectations();
collection.setUriInfo(uriInfo);
verifyCollection(getCollection(), true);
verifyCollection(getCollection(), true, true);
}

private void setUpAllContentExpectations() throws Exception {
Expand Down Expand Up @@ -1501,16 +1503,23 @@ protected List<Vm> getCollection() {

@Override
protected void verifyCollection(List<Vm> collection) throws Exception {
verifyCollection(collection, false);
verifyCollection(collection, false, false);
}

private void verifyCollection(List<Vm> collection, boolean isPopulated) throws Exception {
private void verifyCollection(List<Vm> collection, boolean isPopulated, boolean hasCertificates) throws Exception {
super.verifyCollection(collection);

boolean populated = isPopulated || checkPopulatedHeader();

for (Vm vm : collection) {
assertTrue(populated ? vm.isSetConsole() : !vm.isSetConsole());
assertEquals(hasCertificates, vm.getDisplay().isSetCertificate());
if (hasCertificates) {
Certificate cert = vm.getDisplay().getCertificate();
assertEquals(CERTIFICATE, cert.getSubject());
assertEquals(CA_CERT, cert.getContent());
assertEquals(ORG, cert.getOrganization());
}
}
}

Expand Down Expand Up @@ -1705,6 +1714,19 @@ protected void setUpGetGraphicsMultipleExpectations(int times) {
vmDevices);
}

protected void setUpGetDisplayCertificatesMultipleExpectations() {
Map<Guid, String> certificates = new HashMap<>();
for (Guid guid : GUIDS) {
certificates.put(guid, CERTIFICATE);
}

setUpGetEntityExpectations(QueryType.GetVdsCertificateSubjectsByVmIds,
QueryParametersBase.class,
new String[]{},
new Object[]{},
certificates);
}

protected void setUpGetGraphicsExpectations(int times) {
for (int i = 0; i < times; i++) {
setUpGetEntityExpectations(QueryType.GetGraphicsDevices,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.ovirt.engine.api.restapi.util;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.ovirt.engine.api.model.Certificate;
import org.ovirt.engine.api.model.Vm;
import org.ovirt.engine.api.restapi.resource.BackendResource;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.queries.QueryReturnValue;
import org.ovirt.engine.core.common.queries.QueryType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.utils.MockConfigDescriptor;
import org.ovirt.engine.core.utils.MockConfigExtension;

@MockitoSettings(strictness = Strictness.LENIENT)
@ExtendWith(MockConfigExtension.class)
public class DisplayHelperTest {
private static final String CERTIFICATE = "O=Redhat,CN=X.Y.Z.Q";
private static final String CA_CERT = "dummy-cert";
private static final String ORG = "ORG";
private static final List<Guid> GUIDS = Arrays.asList(
new Guid("11111111-1111-1111-1111-111111111111"),
new Guid("22222222-2222-2222-2222-222222222222"));

public static Stream<MockConfigDescriptor<?>> mockConfiguration() {
return Stream.of(MockConfigDescriptor.of(ConfigValues.OrganizationName, ORG));
}

@Test
public void testAddDisplayCertificate() {
Vm vm = new Vm();
Certificate certificate = new Certificate();
DisplayHelper.addDisplayCertificate(vm, certificate);

assertSame(certificate, vm.getDisplay().getCertificate());
}

@Test
public void testGetDisplayCertificatesForMultipleEntitiesNoResult() {
BackendResource res = mock(BackendResource.class);
QueryReturnValue result = new QueryReturnValue();
result.setSucceeded(false);
when(res.runQuery(eq(QueryType.GetVdsCertificateSubjectsByVmIds), any())).thenReturn(result);

Map<Guid, Certificate> certificates = DisplayHelper.getDisplayCertificatesForMultipleEntities(res, GUIDS);
assertTrue(certificates.isEmpty());
}

@Test
public void testGetDisplayCertificatesForMultipleEntities() {
BackendResource res = mock(BackendResource.class);

QueryReturnValue result = new QueryReturnValue();
result.setSucceeded(true);
Map<Guid, String> subjects = GUIDS.stream().collect(Collectors.toMap(Function.identity(), id -> CERTIFICATE));
result.setReturnValue(subjects);
when(res.runQuery(eq(QueryType.GetVdsCertificateSubjectsByVmIds), any())).thenReturn(result);

result = new QueryReturnValue();
result.setSucceeded(true);
result.setReturnValue(CA_CERT);
when(res.runQuery(eq(QueryType.GetCACertificate), any())).thenReturn(result);


Map<Guid, Certificate> certificates = DisplayHelper.getDisplayCertificatesForMultipleEntities(res, GUIDS);
assertEquals(GUIDS.size(), certificates.size());
for (Guid guid : GUIDS) {
Certificate cert = certificates.get(guid);
assertNotNull(cert);
assertEquals(CERTIFICATE, cert.getSubject());
assertEquals(CA_CERT, cert.getContent());
assertEquals(ORG, cert.getOrganization());
}
}
}
Loading