Add REST endpoint to reindex a single group

This may become handy to fix single groups that are stale in the
index.

Change-Id: Iab3711f343fe1da9bba4979792edc83c76d75a09
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2017-01-04 14:22:02 +01:00
parent bad459177b
commit 4550a256cb
7 changed files with 153 additions and 0 deletions

View File

@@ -791,6 +791,24 @@ newest audit event comes first.
]
----
[[index-group]]
=== Index Group
--
'POST /groups/link:#group-id[\{group-id\}]/index'
--
Adds or updates the internal group in the secondary index.
.Request
----
POST /groups/fdda826a0815859ab48d22a05a43472f0f55f89a/index HTTP/1.0
----
.Response
----
HTTP/1.1 204 No Content
----
[[group-member-endpoints]]
== Group Member Endpoints

View File

@@ -45,6 +45,7 @@ import org.junit.Test;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -481,6 +482,32 @@ public class GroupsIT extends AbstractDaemonTest {
}
}
// reindex is tested by {@link AbstractQueryGroupsTest#reindex}
@Test
public void reindexPermissions() throws Exception {
TestAccount groupOwner = accounts.user2();
GroupInput in = new GroupInput();
in.name = name("group");
in.members = Collections.singleton(groupOwner).stream()
.map(u -> u.id.toString()).collect(toList());
in.visibleToAll = true;
GroupInfo group = gApi.groups().create(in).get();
// admin can reindex any group
setApiUser(admin);
gApi.groups().id(group.id).index();
// group owner can reindex own group (group is owned by itself)
setApiUser(groupOwner);
gApi.groups().id(group.id).index();
// user cannot reindex any group
setApiUser(user);
exception.expect(AuthException.class);
exception.expectMessage("not allowed to index group");
gApi.groups().id(group.id).index();
}
private void assertAuditEvent(GroupAuditEventInfo info, Type expectedType,
Account.Id expectedUser, Account.Id expectedMember) {
assertThat(info.user._accountId).isEqualTo(expectedUser.get());

View File

@@ -143,6 +143,15 @@ public interface GroupApi {
*/
List<? extends GroupAuditEventInfo> auditLog() throws RestApiException;
/**
* Reindexes the group.
*
* Only supported for internal groups.
*
* @throws RestApiException
*/
void index() throws RestApiException;
/**
* A default implementation which allows source compatibility
* when adding new methods to the interface.
@@ -239,5 +248,10 @@ public interface GroupApi {
throws RestApiException {
throw new NotImplementedException();
}
@Override
public void index() {
throw new NotImplementedException();
}
}
}

View File

@@ -34,6 +34,7 @@ import com.google.gerrit.server.group.GetName;
import com.google.gerrit.server.group.GetOptions;
import com.google.gerrit.server.group.GetOwner;
import com.google.gerrit.server.group.GroupResource;
import com.google.gerrit.server.group.Index;
import com.google.gerrit.server.group.ListIncludedGroups;
import com.google.gerrit.server.group.ListMembers;
import com.google.gerrit.server.group.PutDescription;
@@ -71,6 +72,7 @@ class GroupApiImpl implements GroupApi {
private final DeleteIncludedGroups deleteGroups;
private final GetAuditLog getAuditLog;
private final GroupResource rsrc;
private final Index index;
@AssistedInject
GroupApiImpl(
@@ -91,6 +93,7 @@ class GroupApiImpl implements GroupApi {
AddIncludedGroups addGroups,
DeleteIncludedGroups deleteGroups,
GetAuditLog getAuditLog,
Index index,
@Assisted GroupResource rsrc) {
this.getGroup = getGroup;
this.getDetail = getDetail;
@@ -109,6 +112,7 @@ class GroupApiImpl implements GroupApi {
this.addGroups = addGroups;
this.deleteGroups = deleteGroups;
this.getAuditLog = getAuditLog;
this.index = index;
this.rsrc = rsrc;
}
@@ -270,4 +274,13 @@ class GroupApiImpl implements GroupApi {
throw new RestApiException("Cannot get audit log", e);
}
}
@Override
public void index() throws RestApiException {
try {
index.apply(rsrc, new Index.Input());
} catch (IOException e) {
throw new RestApiException("Cannot index group", e);
}
}
}

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.server.group;
import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.group.Index.Input;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@Singleton
public class Index implements RestModifyView<GroupResource, Input> {
public static class Input {
}
private final GroupCache groupCache;
@Inject
Index(GroupCache groupCache) {
this.groupCache = groupCache;
}
@Override
public Response<?> apply(GroupResource rsrc, Input input)
throws IOException, AuthException, UnprocessableEntityException {
if (!rsrc.getControl().isOwner()) {
throw new AuthException("not allowed to index group");
}
AccountGroup group = GroupDescriptions.toAccountGroup(rsrc.getGroup());
if (group == null) {
throw new UnprocessableEntityException(String
.format("External Group Not Allowed: %s", rsrc.getGroupUUID().get()));
}
// evicting the group from the cache, reindexes the account
groupCache.evict(group);
return Response.none();
}
}

View File

@@ -39,6 +39,7 @@ public class Module extends RestApiModule {
get(GROUP_KIND).to(GetGroup.class);
put(GROUP_KIND).to(PutGroup.class);
get(GROUP_KIND, "detail").to(GetDetail.class);
post(GROUP_KIND, "index").to(Index.class);
post(GROUP_KIND, "members").to(AddMembers.class);
post(GROUP_KIND, "members.add").to(AddMembers.class);
post(GROUP_KIND, "members.delete").to(DeleteMembers.class);

View File

@@ -59,6 +59,7 @@ import org.junit.Test;
import org.junit.rules.TestName;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -300,6 +301,26 @@ public abstract class AbstractQueryGroupsTest extends GerritServerTests {
assertQuery("uuid:" + group.id);
}
// reindex permissions are tested by {@link GroupsIT#reindexPermissions}
@Test
public void reindex() throws Exception {
GroupInfo group1 = createGroupWithDescription(name("group"), "barX");
// update group in the database so that group index is stale
String newDescription = "barY";
AccountGroup group =
db.accountGroups().get(new AccountGroup.Id(group1.groupId));
group.setDescription(newDescription);
db.accountGroups().update(Collections.singleton(group));
assertQuery("description:" + group1.description, group1);
assertQuery("description:" + newDescription);
gApi.groups().id(group1.id).index();
assertQuery("description:" + group1.description);
assertQuery("description:" + newDescription, group1);
}
private Account.Id createAccount(String username, String fullName,
String email, boolean active) throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {