Skip to content
Merged
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
Expand Up @@ -27,4 +27,6 @@ public interface ServiceOfferingDetailsDao extends GenericDao<ServiceOfferingDet
List<Long> findDomainIds(final long resourceId);
List<Long> findZoneIds(final long resourceId);
String getDetail(Long diskOfferingId, String key);
}
List<Long> findOfferingIdsByDomainIds(List<Long> domainIds);
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
Expand Down Expand Up @@ -67,4 +68,10 @@ public String getDetail(Long serviceOfferingId, String key) {
}
return detailValue;
}

@Override
public List<Long> findOfferingIdsByDomainIds(List<Long> domainIds) {
Object[] dIds = domainIds.stream().map(s -> String.valueOf(s)).collect(Collectors.toList()).toArray();
Copy link
Member

Choose a reason for hiding this comment

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

better to mention String[] rather than Object[] since you are explicitly getting string value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored and updated

Copy link
Member

Choose a reason for hiding this comment

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

@davidjumani this can be simplified to domainIds.stream().map(String::valueOf).toArray();

return findResouceIdsByNameAndValueIn("domainid", dIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,5 @@ public interface ResourceDetailsDao<R extends ResourceDetail> extends GenericDao

public void addDetail(long resourceId, String key, String value, boolean display);

public List<Long> findResouceIdsByNameAndValueIn(String name, Object[] values);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
import org.apache.cloudstack.api.ResourceDetail;

import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.SearchCriteria.Op;

public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends GenericDaoBase<R, Long> implements ResourceDetailsDao<R> {
private SearchBuilder<R> AllFieldsSearch;
Expand Down Expand Up @@ -182,4 +184,21 @@ public List<R> listDetails(long resourceId, boolean forDisplay) {
List<R> results = search(sc, null);
return results;
}

@Override
public List<Long> findResouceIdsByNameAndValueIn(String name, Object[] values) {
GenericSearchBuilder<R, Long> sb = createSearchBuilder(Long.class);
sb.selectFields(sb.entity().getResourceId());
sb.and("name", sb.entity().getName(), Op.EQ);
sb.and().op("value", sb.entity().getValue(), Op.IN);
sb.or("valueNull", sb.entity().getValue(), Op.NULL);
sb.cp();
sb.done();

SearchCriteria<Long> sc = sb.create();
sc.setParameters("name", name);
sc.setParameters("value", values);

return customSearch(sc, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ public interface DiskOfferingDetailsDao extends GenericDao<DiskOfferingDetailVO,
List<Long> findDomainIds(final long resourceId);
List<Long> findZoneIds(final long resourceId);
String getDetail(Long diskOfferingId, String key);
}
List<Long> findOfferingIdsByDomainIds(List<Long> domainIds);
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
Expand Down Expand Up @@ -66,4 +67,11 @@ public String getDetail(Long diskOfferingId, String key) {
}
return detailValue;
}
}

@Override
public List<Long> findOfferingIdsByDomainIds(List<Long> domainIds) {
Copy link
Member

Choose a reason for hiding this comment

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

@davidjumani This part is duplicated code right? this can be in a common place for both service and disk offering

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored and updated

Object[] dIds = domainIds.stream().map(s -> String.valueOf(s)).collect(Collectors.toList()).toArray();
return findResouceIdsByNameAndValueIn("domainid", dIds);
}
}

179 changes: 84 additions & 95 deletions server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -119,7 +118,6 @@
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -204,6 +202,7 @@
import com.cloud.server.TaggedResourceService;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ScopeType;
Expand Down Expand Up @@ -346,14 +345,17 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private DiskOfferingJoinDao _diskOfferingJoinDao;

@Inject
private DiskOfferingDetailsDao diskOfferingDetailsDao;
private DiskOfferingDetailsDao _diskOfferingDetailsDao;
Copy link
Contributor

Choose a reason for hiding this comment

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

why add the '_'? we are trying to get away from that convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consistency in the file, unless you'd like me to rename all the class variables ?

Copy link
Contributor

Choose a reason for hiding this comment

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

don't see the use of this consistency. the underscore does not value in field names, does it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm for changing all variables, not just one, which can be done in a separate PR


@Inject
private ServiceOfferingJoinDao _srvOfferingJoinDao;

@Inject
private ServiceOfferingDao _srvOfferingDao;

@Inject
private ServiceOfferingDetailsDao _srvOfferingDetailsDao;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private ServiceOfferingDetailsDao _srvOfferingDetailsDao;
private ServiceOfferingDetailsDao serviceOfferingDetailsDao;


@Inject
private DataCenterJoinDao _dcJoinDao;

Expand Down Expand Up @@ -2824,75 +2826,41 @@ private Pair<List<DiskOfferingJoinVO>, Integer> searchForDiskOfferingsInternal(L
sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC);
}

// FIXME: disk offerings should search back up the hierarchy for
// available disk offerings...
/*
* sb.addAnd("domainId", sb.entity().getDomainId(),
* SearchCriteria.Op.EQ); if (domainId != null) {
* SearchBuilder<DomainVO> domainSearch =
* _domainDao.createSearchBuilder(); domainSearch.addAnd("path",
* domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
* sb.join("domainSearch", domainSearch, sb.entity().getDomainId(),
* domainSearch.entity().getId()); }
*/

// FIXME: disk offerings should search back up the hierarchy for
// available disk offerings...
/*
* if (domainId != null) { sc.setParameters("domainId", domainId); //
* //DomainVO domain = _domainDao.findById((Long)domainId); // // I want
* to join on user_vm.domain_id = domain.id where domain.path like
* 'foo%' //sc.setJoinParameters("domainSearch", "path",
* domain.getPath() + "%"); // }
*/
// Filter offerings that are not associated with caller's domain
Copy link
Contributor

Choose a reason for hiding this comment

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

good method name ;) maybe factor out the below.

// Fetch the offering ids from the details table since theres no smart way to filter them in the join ... yet!
Account caller = CallContext.current().getCallingAccount();
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
Domain callerDomain = _domainDao.findById(caller.getDomainId());
List<Long> domainIds = findRelatedDomainIds(callerDomain, isRecursive);

Pair<List<DiskOfferingJoinVO>, Integer> result = _diskOfferingJoinDao.searchAndCount(sc, searchFilter);
// Remove offerings that are not associated with caller's domain
if (account.getType() != Account.ACCOUNT_TYPE_ADMIN && CollectionUtils.isNotEmpty(result.first())) {
ListIterator<DiskOfferingJoinVO> it = result.first().listIterator();
while (it.hasNext()) {
DiskOfferingJoinVO offering = it.next();
if(!Strings.isNullOrEmpty(offering.getDomainId())) {
boolean toRemove = true;
String[] domainIdsArray = offering.getDomainId().split(",");
for (String domainIdString : domainIdsArray) {
Long dId = Long.valueOf(domainIdString.trim());
if (isRecursive) {
if (_domainDao.isChildDomain(account.getDomainId(), dId)) {
toRemove = false;
break;
}
} else {
if (_domainDao.isChildDomain(dId, account.getDomainId())) {
toRemove = false;
break;
}
}
}
if (toRemove) {
it.remove();
}
}
List<Long> ids = _diskOfferingDetailsDao.findOfferingIdsByDomainIds(domainIds);
SearchBuilder<DiskOfferingJoinVO> sb = _diskOfferingJoinDao.createSearchBuilder();
if (ids != null && !ids.isEmpty()) {
sb.and("id", sb.entity().getId(), Op.IN);
}
sb.or("domainId", sb.entity().getDomainId(), Op.NULL);
sb.done();

SearchCriteria<DiskOfferingJoinVO> scc = sb.create();
if (ids != null && !ids.isEmpty()) {
scc.setParameters("id", ids.toArray());
}
sc.addAnd("domainId", SearchCriteria.Op.SC, scc);
}

Pair<List<DiskOfferingJoinVO>, Integer> result = _diskOfferingJoinDao.searchAndCount(sc, searchFilter);
return new Pair<>(result.first(), result.second());
}

private List<ServiceOfferingJoinVO> filterOfferingsOnCurrentTags(List<ServiceOfferingJoinVO> offerings, ServiceOfferingVO currentVmOffering) {
if (currentVmOffering == null) {
return offerings;
private List<Long> findRelatedDomainIds(Domain domain, boolean isRecursive) {
List<Long> domainIds = _domainDao.getDomainParentIds(domain.getId())
.stream().collect(Collectors.toList());
if (isRecursive) {
List<Long> childrenIds = _domainDao.getDomainChildrenIds(domain.getPath());
if (childrenIds != null && !childrenIds.isEmpty())
domainIds.addAll(childrenIds);
}
List<String> currentTagsList = StringUtils.csvTagsToList(currentVmOffering.getTags());

// New service offering should have all the tags of the current service offering.
List<ServiceOfferingJoinVO> filteredOfferings = new ArrayList<>();
for (ServiceOfferingJoinVO offering : offerings) {
List<String> newTagsList = StringUtils.csvTagsToList(offering.getTags());
if (newTagsList.containsAll(currentTagsList)) {
filteredOfferings.add(offering);
}
}
return filteredOfferings;
return domainIds;
}

@Override
Expand Down Expand Up @@ -3064,39 +3032,60 @@ private Pair<List<ServiceOfferingJoinVO>, Integer> searchForServiceOfferingsInte
sc.addAnd("cpuspeedconstraints", SearchCriteria.Op.SC, cpuSpeedSearchCriteria);
}

Pair<List<ServiceOfferingJoinVO>, Integer> result = _srvOfferingJoinDao.searchAndCount(sc, searchFilter);

//Couldn't figure out a smart way to filter offerings based on tags in sql so doing it in Java.
List<ServiceOfferingJoinVO> filteredOfferings = filterOfferingsOnCurrentTags(result.first(), currentVmOffering);
// Remove offerings that are not associated with caller's domain
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && CollectionUtils.isNotEmpty(filteredOfferings)) {
ListIterator<ServiceOfferingJoinVO> it = filteredOfferings.listIterator();
while (it.hasNext()) {
ServiceOfferingJoinVO offering = it.next();
if(!Strings.isNullOrEmpty(offering.getDomainId())) {
boolean toRemove = true;
String[] domainIdsArray = offering.getDomainId().split(",");
for (String domainIdString : domainIdsArray) {
Long dId = Long.valueOf(domainIdString.trim());
if (isRecursive) {
if (_domainDao.isChildDomain(caller.getDomainId(), dId)) {
toRemove = false;
break;
}
} else {
if (_domainDao.isChildDomain(dId, caller.getDomainId())) {
toRemove = false;
break;
}
}
}
if (toRemove) {
it.remove();
}
// Filter offerings that are not associated with caller's domain
Copy link
Contributor

Choose a reason for hiding this comment

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

once again, a this comment is a good method name to extract the code below to.

// Fetch the offering ids from the details table since theres no smart way to filter them in the join ... yet!
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
Domain callerDomain = _domainDao.findById(caller.getDomainId());
List<Long> domainIds = findRelatedDomainIds(callerDomain, isRecursive);

List<Long> ids = _srvOfferingDetailsDao.findOfferingIdsByDomainIds(domainIds);
Copy link
Member

Choose a reason for hiding this comment

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

Most of this is duplicated code. can be extracted to a single function.

SearchBuilder<ServiceOfferingJoinVO> sb = _srvOfferingJoinDao.createSearchBuilder();
if (ids != null && !ids.isEmpty()) {
sb.and("id", sb.entity().getId(), Op.IN);
}
sb.or("domainId", sb.entity().getDomainId(), Op.NULL);
sb.done();

SearchCriteria<ServiceOfferingJoinVO> scc = sb.create();
if (ids != null && !ids.isEmpty()) {
scc.setParameters("id", ids.toArray());
}
sc.addAnd("domainId", SearchCriteria.Op.SC, scc);
}

if (currentVmOffering != null) {
List<String> storageTags = StringUtils.csvTagsToList(currentVmOffering.getTags());
if (!storageTags.isEmpty()) {
SearchBuilder<ServiceOfferingJoinVO> sb = _srvOfferingJoinDao.createSearchBuilder();
for(String tag : storageTags) {
sb.and(tag, sb.entity().getTags(), Op.FIND_IN_SET);
}
sb.done();

SearchCriteria<ServiceOfferingJoinVO> scc = sb.create();
for(String tag : storageTags) {
scc.setParameters(tag, tag);
}
sc.addAnd("storageTags", SearchCriteria.Op.SC, scc);
}

List<String> hostTags = StringUtils.csvTagsToList(currentVmOffering.getHostTag());
if (!hostTags.isEmpty()) {
SearchBuilder<ServiceOfferingJoinVO> sb = _srvOfferingJoinDao.createSearchBuilder();
for(String tag : hostTags) {
sb.and(tag, sb.entity().getHostTag(), Op.FIND_IN_SET);
}
sb.done();

SearchCriteria<ServiceOfferingJoinVO> scc = sb.create();
for(String tag : hostTags) {
scc.setParameters(tag, tag);
}
sc.addAnd("hostTags", SearchCriteria.Op.SC, scc);
}
}
return new Pair<>(filteredOfferings, result.second());

return _srvOfferingJoinDao.searchAndCount(sc, searchFilter);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,4 @@ public ServiceOfferingJoinVO newServiceOfferingView(ServiceOffering offering) {
assert offerings != null && offerings.size() == 1 : "No service offering found for offering id " + offering.getId();
return offerings.get(0);
}

}