Skip to content

Commit 73f79b8

Browse files
committed
Also cover event archival + unit tests
1 parent b2c589b commit 73f79b8

File tree

7 files changed

+234
-199
lines changed

7 files changed

+234
-199
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/event/ArchiveEventsCmd.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.apache.cloudstack.context.CallContext;
3232

3333
import com.cloud.event.Event;
34-
import com.cloud.exception.InvalidParameterValueException;
3534
import com.cloud.user.Account;
3635

3736
@APICommand(name = "archiveEvents", description = "Archive one or more events.", responseObject = SuccessResponse.class, entityType = {Event.class},
@@ -82,6 +81,22 @@ public String getType() {
8281
return type;
8382
}
8483

84+
public void setIds(List<Long> ids) {
85+
this.ids = ids;
86+
}
87+
88+
public void setEndDate(Date endDate) {
89+
this.endDate = endDate;
90+
}
91+
92+
public void setStartDate(Date startDate) {
93+
this.startDate = startDate;
94+
}
95+
96+
public void setType(String type) {
97+
this.type = type;
98+
}
99+
85100
/////////////////////////////////////////////////////
86101
/////////////// API Implementation///////////////////
87102
/////////////////////////////////////////////////////
@@ -97,17 +112,12 @@ public long getEntityOwnerId() {
97112

98113
@Override
99114
public void execute() {
100-
if (ids == null && type == null && endDate == null) {
101-
throw new InvalidParameterValueException("either ids, type or enddate must be specified");
102-
} else if (startDate != null && endDate == null) {
103-
throw new InvalidParameterValueException("enddate must be specified with startdate parameter");
104-
}
105115
boolean result = _mgr.archiveEvents(this);
106116
if (result) {
107117
SuccessResponse response = new SuccessResponse(getCommandName());
108118
setResponseObject(response);
109-
} else {
110-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to archive Events, one or more parameters has invalid values");
119+
return;
111120
}
121+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to archive Events. One or more parameters have invalid values.");
112122
}
113123
}

api/src/main/java/org/apache/cloudstack/api/command/user/event/DeleteEventsCmd.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,22 @@ public String getType() {
8181
return type;
8282
}
8383

84+
public void setIds(List<Long> ids) {
85+
this.ids = ids;
86+
}
87+
88+
public void setEndDate(Date endDate) {
89+
this.endDate = endDate;
90+
}
91+
92+
public void setStartDate(Date startDate) {
93+
this.startDate = startDate;
94+
}
95+
96+
public void setType(String type) {
97+
this.type = type;
98+
}
99+
84100
// ///////////////////////////////////////////////////
85101
// ///////////// API Implementation///////////////////
86102
// ///////////////////////////////////////////////////

engine/schema/src/main/java/com/cloud/event/dao/EventDao.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,11 @@
2020
import java.util.List;
2121

2222
import com.cloud.event.EventVO;
23-
import com.cloud.utils.db.Filter;
2423
import com.cloud.utils.db.GenericDao;
25-
import com.cloud.utils.db.SearchCriteria;
2624

2725
public interface EventDao extends GenericDao<EventVO, Long> {
28-
public List<EventVO> searchAllEvents(SearchCriteria<EventVO> sc, Filter filter);
29-
30-
EventVO findCompletedEvent(long startId);
31-
32-
public List<EventVO> listToArchiveOrDeleteEvents(List<Long> ids, String type, Date startDate, Date endDate, List<Long> accountIds);
33-
34-
public void archiveEvents(List<EventVO> events);
26+
long archiveEvents(List<Long> ids, String type, Date startDate, Date endDate, Long accountId, List<Long> domainIds,
27+
long limitPerQuery);
3528

3629
long purgeAll(List<Long> ids, Date startDate, Date endDate, Date limitDate, String type, Long accountId, List<Long> domainIds,
3730
long limitPerQuery);

engine/schema/src/main/java/com/cloud/event/dao/EventDaoImpl.java

Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@
1616
// under the License.
1717
package com.cloud.event.dao;
1818

19+
import java.sql.PreparedStatement;
20+
import java.sql.SQLException;
1921
import java.util.Date;
2022
import java.util.List;
23+
import java.util.stream.Collectors;
2124

2225

26+
import com.cloud.utils.db.DB;
27+
import com.cloud.utils.db.Filter;
28+
import com.cloud.utils.exception.CloudRuntimeException;
2329
import org.apache.commons.collections4.CollectionUtils;
2430
import org.springframework.stereotype.Component;
2531

26-
import com.cloud.event.Event.State;
2732
import com.cloud.event.EventVO;
28-
import com.cloud.utils.db.Filter;
2933
import com.cloud.utils.db.GenericDaoBase;
3034
import com.cloud.utils.db.SearchBuilder;
3135
import com.cloud.utils.db.SearchCriteria;
@@ -34,21 +38,15 @@
3438

3539
@Component
3640
public class EventDaoImpl extends GenericDaoBase<EventVO, Long> implements EventDao {
37-
protected final SearchBuilder<EventVO> CompletedEventSearch;
41+
3842
protected final SearchBuilder<EventVO> ToArchiveOrDeleteEventSearch;
3943

4044
public EventDaoImpl() {
41-
CompletedEventSearch = createSearchBuilder();
42-
CompletedEventSearch.and("state", CompletedEventSearch.entity().getState(), SearchCriteria.Op.EQ);
43-
CompletedEventSearch.and("startId", CompletedEventSearch.entity().getStartId(), SearchCriteria.Op.EQ);
44-
CompletedEventSearch.and("archived", CompletedEventSearch.entity().getArchived(), Op.EQ);
45-
CompletedEventSearch.done();
46-
4745
ToArchiveOrDeleteEventSearch = createSearchBuilder();
46+
ToArchiveOrDeleteEventSearch.select("id", SearchCriteria.Func.NATIVE, ToArchiveOrDeleteEventSearch.entity().getId());
4847
ToArchiveOrDeleteEventSearch.and("id", ToArchiveOrDeleteEventSearch.entity().getId(), Op.IN);
4948
ToArchiveOrDeleteEventSearch.and("type", ToArchiveOrDeleteEventSearch.entity().getType(), Op.EQ);
5049
ToArchiveOrDeleteEventSearch.and("accountId", ToArchiveOrDeleteEventSearch.entity().getAccountId(), Op.EQ);
51-
ToArchiveOrDeleteEventSearch.and("accountIds", ToArchiveOrDeleteEventSearch.entity().getAccountId(), Op.IN);
5250
ToArchiveOrDeleteEventSearch.and("domainIds", ToArchiveOrDeleteEventSearch.entity().getDomainId(), Op.IN);
5351
ToArchiveOrDeleteEventSearch.and("createdDateB", ToArchiveOrDeleteEventSearch.entity().getCreateDate(), Op.BETWEEN);
5452
ToArchiveOrDeleteEventSearch.and("createdDateL", ToArchiveOrDeleteEventSearch.entity().getCreateDate(), Op.LTEQ);
@@ -57,77 +55,73 @@ public EventDaoImpl() {
5755
ToArchiveOrDeleteEventSearch.done();
5856
}
5957

60-
@Override
61-
public List<EventVO> searchAllEvents(SearchCriteria<EventVO> sc, Filter filter) {
62-
return listIncludingRemovedBy(sc, filter);
63-
}
64-
65-
@Override
66-
public EventVO findCompletedEvent(long startId) {
67-
SearchCriteria<EventVO> sc = CompletedEventSearch.create();
68-
sc.setParameters("state", State.Completed);
69-
sc.setParameters("startId", startId);
70-
sc.setParameters("archived", false);
71-
return findOneIncludingRemovedBy(sc);
72-
}
73-
74-
@Override
75-
public List<EventVO> listToArchiveOrDeleteEvents(List<Long> ids, String type, Date startDate, Date endDate, List<Long> accountIds) {
58+
private SearchCriteria<EventVO> createEventSearchCriteria(List<Long> ids, String type, Date startDate, Date endDate,
59+
Date limitDate, Long accountId, List<Long> domainIds) {
7660
SearchCriteria<EventVO> sc = ToArchiveOrDeleteEventSearch.create();
77-
if (ids != null) {
78-
sc.setParameters("id", ids.toArray(new Object[ids.size()]));
61+
62+
if (CollectionUtils.isNotEmpty(ids)) {
63+
sc.setParameters("id", ids.toArray(new Object[0]));
7964
}
80-
if (type != null) {
81-
sc.setParameters("type", type);
65+
if (CollectionUtils.isNotEmpty(domainIds)) {
66+
sc.setParameters("domainIds", domainIds.toArray(new Object[0]));
8267
}
8368
if (startDate != null && endDate != null) {
8469
sc.setParameters("createdDateB", startDate, endDate);
8570
} else if (endDate != null) {
8671
sc.setParameters("createdDateL", endDate);
8772
}
88-
if (accountIds != null && !accountIds.isEmpty()) {
89-
sc.setParameters("accountIds", accountIds.toArray(new Object[accountIds.size()]));
90-
}
73+
sc.setParametersIfNotNull("accountId", accountId);
74+
sc.setParametersIfNotNull("createdDateLT", limitDate);
75+
sc.setParametersIfNotNull("type", type);
9176
sc.setParameters("archived", false);
92-
return search(sc, null);
77+
78+
return sc;
9379
}
9480

9581
@Override
96-
public void archiveEvents(List<EventVO> events) {
97-
if (events != null && !events.isEmpty()) {
98-
TransactionLegacy txn = TransactionLegacy.currentTxn();
99-
txn.start();
100-
for (EventVO event : events) {
101-
event = lockRow(event.getId(), true);
102-
event.setArchived(true);
103-
update(event.getId(), event);
104-
txn.commit();
82+
public long archiveEvents(List<Long> ids, String type, Date startDate, Date endDate, Long accountId, List<Long> domainIds,
83+
long limitPerQuery) {
84+
SearchCriteria<EventVO> sc = createEventSearchCriteria(ids, type, startDate, endDate, null, accountId, domainIds);
85+
Filter filter = null;
86+
if (limitPerQuery > 0) {
87+
filter = new Filter(limitPerQuery);
88+
}
89+
90+
long archived;
91+
long totalArchived = 0L;
92+
93+
do {
94+
List<EventVO> events = search(sc, filter);
95+
if (events.isEmpty()) {
96+
break;
10597
}
106-
txn.close();
98+
99+
archived = archiveEventsInternal(events);
100+
totalArchived += archived;
101+
} while (limitPerQuery > 0 && archived >= limitPerQuery);
102+
103+
return totalArchived;
104+
}
105+
106+
@DB
107+
private long archiveEventsInternal(List<EventVO> events) {
108+
final String idsAsString = events.stream()
109+
.map(e -> Long.toString(e.getId()))
110+
.collect(Collectors.joining(","));
111+
final String query = String.format("UPDATE event SET archived=true WHERE id IN (%s)", idsAsString);
112+
113+
try (TransactionLegacy txn = TransactionLegacy.currentTxn();
114+
PreparedStatement pstmt = txn.prepareStatement(query)) {
115+
return pstmt.executeUpdate();
116+
} catch (SQLException e) {
117+
throw new CloudRuntimeException(e);
107118
}
108119
}
109120

110121
@Override
111122
public long purgeAll(List<Long> ids, Date startDate, Date endDate, Date limitDate, String type, Long accountId,
112123
List<Long> domainIds, long limitPerQuery) {
113-
SearchCriteria<EventVO> sc = ToArchiveOrDeleteEventSearch.create();
114-
115-
if (CollectionUtils.isNotEmpty(ids)) {
116-
sc.setParameters("id", ids.toArray(new Object[0]));
117-
}
118-
if (startDate != null && endDate != null) {
119-
sc.setParameters("createdDateB", startDate, endDate);
120-
} else if (endDate != null) {
121-
sc.setParameters("createdDateL", endDate);
122-
}
123-
sc.setParametersIfNotNull("createdDateLT", limitDate);
124-
sc.setParametersIfNotNull("type", type);
125-
sc.setParametersIfNotNull("accountId", accountId);
126-
if (CollectionUtils.isNotEmpty(domainIds)) {
127-
sc.setParameters("domainIds", domainIds.toArray(new Object[0]));
128-
}
129-
sc.setParameters("archived", false);
130-
124+
SearchCriteria<EventVO> sc = createEventSearchCriteria(ids, type, startDate, endDate, limitDate, accountId, domainIds);
131125
return batchExpunge(sc, limitPerQuery);
132126
}
133127
}

server/src/main/java/com/cloud/server/ManagementServerImpl.java

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,6 @@
725725
import com.cloud.event.ActionEvent;
726726
import com.cloud.event.ActionEventUtils;
727727
import com.cloud.event.EventTypes;
728-
import com.cloud.event.EventVO;
729728
import com.cloud.event.dao.EventDao;
730729
import com.cloud.exception.AgentUnavailableException;
731730
import com.cloud.exception.ConcurrentOperationException;
@@ -1216,29 +1215,29 @@ protected void checkPortParameters(final String publicPort, final String private
12161215
}
12171216

12181217
@Override
1219-
public boolean archiveEvents(final ArchiveEventsCmd cmd) {
1220-
final Account caller = getCaller();
1221-
final List<Long> ids = cmd.getIds();
1222-
boolean result = true;
1223-
List<Long> permittedAccountIds = new ArrayList<>();
1218+
public boolean archiveEvents(ArchiveEventsCmd cmd) {
1219+
List<Long> ids = cmd.getIds();
1220+
String type = cmd.getType();
1221+
Date startDate = cmd.getStartDate();
1222+
Date endDate = cmd.getEndDate();
1223+
1224+
validateEventOperationParameters(ids, type, endDate, startDate);
1225+
1226+
Long accountId = null;
1227+
List<Long> domainIds = null;
1228+
Account caller = getCaller();
1229+
Account.Type callerType = caller.getType();
12241230

1225-
if (_accountService.isNormalUser(caller.getId()) || caller.getType() == Account.Type.PROJECT) {
1226-
permittedAccountIds.add(caller.getId());
1231+
if (callerType == Account.Type.NORMAL || callerType == Account.Type.PROJECT) {
1232+
accountId = caller.getId();
12271233
} else {
1228-
final DomainVO domain = _domainDao.findById(caller.getDomainId());
1229-
final List<Long> permittedDomainIds = _domainDao.getDomainChildrenIds(domain.getPath());
1230-
permittedAccountIds = _accountDao.getAccountIdsForDomains(permittedDomainIds);
1234+
domainIds = _domainDao.getDomainAndChildrenIds(caller.getDomainId());
12311235
}
12321236

1233-
final List<EventVO> events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getStartDate(), cmd.getEndDate(), permittedAccountIds);
1234-
final ControlledEntity[] sameOwnerEvents = events.toArray(new ControlledEntity[events.size()]);
1235-
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, sameOwnerEvents);
1237+
long totalArchived = _eventDao.archiveEvents(ids, type, startDate, endDate, accountId, domainIds,
1238+
ConfigurationManagerImpl.DELETE_QUERY_BATCH_SIZE.value());
12361239

1237-
if (ids != null && events.size() < ids.size()) {
1238-
return false;
1239-
}
1240-
_eventDao.archiveEvents(events);
1241-
return result;
1240+
return totalArchived > 0;
12421241
}
12431242

12441243
@Override
@@ -1248,12 +1247,7 @@ public boolean deleteEvents(DeleteEventsCmd cmd) {
12481247
Date startDate = cmd.getStartDate();
12491248
Date endDate = cmd.getEndDate();
12501249

1251-
if (CollectionUtils.isEmpty(ids) && ObjectUtils.allNull(type, endDate)) {
1252-
throw new InvalidParameterValueException("Either 'ids', 'type' or 'enddate' must be specified.");
1253-
}
1254-
if (startDate != null && endDate == null) {
1255-
throw new InvalidParameterValueException("'startdate' must be specified with 'enddate' parameter.");
1256-
}
1250+
validateEventOperationParameters(ids, type, endDate, startDate);
12571251

12581252
Long accountId = null;
12591253
List<Long> domainIds = null;
@@ -1272,6 +1266,15 @@ public boolean deleteEvents(DeleteEventsCmd cmd) {
12721266
return totalRemoved > 0;
12731267
}
12741268

1269+
protected void validateEventOperationParameters(List<Long> ids, String type, Date endDate, Date startDate) {
1270+
if (CollectionUtils.isEmpty(ids) && ObjectUtils.allNull(type, endDate)) {
1271+
throw new InvalidParameterValueException("Either 'ids', 'type' or 'enddate' must be specified.");
1272+
}
1273+
if (startDate != null && endDate == null) {
1274+
throw new InvalidParameterValueException("'startdate' must be specified with 'enddate' parameter.");
1275+
}
1276+
}
1277+
12751278
@Override
12761279
public List<? extends Cluster> searchForClusters(long zoneId, final Long startIndex, final Long pageSizeVal, final String hypervisorType) {
12771280
final Filter searchFilter = new Filter(ClusterVO.class, "id", true, startIndex, pageSizeVal);

0 commit comments

Comments
 (0)