Skip to content

Commit

Permalink
Enable admin access to the internal dogma project. (line#907)
Browse files Browse the repository at this point in the history
Motivation:
@trustin suggested utilizing the internal `dogma` project for the
control plane. However, it's not easy to use the project because it
isn't accessible through UI even for an admin.
The `ProjectManager`, which is used in the `ProjectServiceV1`, is
wrapped with the `SafeProjectManager` that blocks to access the `dogma`
project. (A Plugin uses the `ProjectManager` directly so no problem from
the plugin side.)

Modifications:
- Grant admins to access to the internal `dogma` project via REST API
and web UI.
- Rename `SafeProjectManager` to `ProjectApiManager`.
  - It's also used for Thrift service.

Result:
- Administrators can now access the internal `dogma` project through
both REST API and the web UI.
  • Loading branch information
minwoox authored Feb 1, 2024
1 parent e871425 commit 10ea91f
Show file tree
Hide file tree
Showing 22 changed files with 535 additions and 427 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import com.linecorp.centraldogma.testing.junit.CentralDogmaExtension;

enum ClientType {
@SuppressWarnings("unused")

DEFAULT(CentralDogmaExtension::client),
LEGACY(CentralDogmaExtension::legacyClient);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
import com.linecorp.centraldogma.server.internal.mirror.DefaultMirroringServicePlugin;
import com.linecorp.centraldogma.server.internal.replication.ZooKeeperCommandExecutor;
import com.linecorp.centraldogma.server.internal.storage.project.DefaultProjectManager;
import com.linecorp.centraldogma.server.internal.storage.project.SafeProjectManager;
import com.linecorp.centraldogma.server.internal.storage.project.ProjectApiManager;
import com.linecorp.centraldogma.server.internal.thrift.CentralDogmaExceptionTranslator;
import com.linecorp.centraldogma.server.internal.thrift.CentralDogmaServiceImpl;
import com.linecorp.centraldogma.server.internal.thrift.CentralDogmaTimeoutScheduler;
Expand Down Expand Up @@ -535,8 +535,9 @@ private Server startServer(ProjectManager pm, CommandExecutor executor,
final MetadataService mds = new MetadataService(pm, executor);
final WatchService watchService = new WatchService(meterRegistry);
final AuthProvider authProvider = createAuthProvider(executor, sessionManager, mds);
final ProjectApiManager projectApiManager = new ProjectApiManager(pm, executor, mds);

configureThriftService(sb, pm, executor, watchService, mds);
configureThriftService(sb, projectApiManager, executor, watchService, mds);

sb.service("/title", webAppTitleFile(cfg.webAppTitle(), SystemInfo.hostname()).asService());

Expand All @@ -551,7 +552,7 @@ private Server startServer(ProjectManager pm, CommandExecutor executor,
"Bearer " + CsrfToken.ANONYMOUS))
.build());

configureHttpApi(sb, pm, executor, watchService, mds, authProvider, sessionManager);
configureHttpApi(sb, projectApiManager, executor, watchService, mds, authProvider, sessionManager);

configureMetrics(sb, meterRegistry);

Expand Down Expand Up @@ -645,10 +646,11 @@ private CommandExecutor newZooKeeperCommandExecutor(
meterRegistry, pm, config().writeQuotaPerRepository(), onTakeLeadership, onReleaseLeadership);
}

private void configureThriftService(ServerBuilder sb, ProjectManager pm, CommandExecutor executor,
private void configureThriftService(ServerBuilder sb, ProjectApiManager projectApiManager,
CommandExecutor executor,
WatchService watchService, MetadataService mds) {
final CentralDogmaServiceImpl service =
new CentralDogmaServiceImpl(pm, executor, watchService, mds);
new CentralDogmaServiceImpl(projectApiManager, executor, watchService, mds);

HttpService thriftService =
ThriftCallService.of(service)
Expand All @@ -669,7 +671,7 @@ private void configureThriftService(ServerBuilder sb, ProjectManager pm, Command
}

private void configureHttpApi(ServerBuilder sb,
ProjectManager pm, CommandExecutor executor,
ProjectApiManager projectApiManager, CommandExecutor executor,
WatchService watchService, MetadataService mds,
@Nullable AuthProvider authProvider,
@Nullable SessionManager sessionManager) {
Expand Down Expand Up @@ -702,9 +704,7 @@ protected HttpResponse doGet(ServiceRequestContext ctx, HttpRequest req) {
.andThen(AuthService.newDecorator(new CsrfTokenAuthorizer()));
}

final SafeProjectManager safePm = new SafeProjectManager(pm);

final HttpApiRequestConverter v1RequestConverter = new HttpApiRequestConverter(safePm);
final HttpApiRequestConverter v1RequestConverter = new HttpApiRequestConverter(projectApiManager);
final JacksonRequestConverterFunction jacksonRequestConverterFunction =
// Use the default ObjectMapper without any configuration.
// See JacksonRequestConverterFunctionTest
Expand All @@ -716,13 +716,13 @@ protected HttpResponse doGet(ServiceRequestContext ctx, HttpRequest req) {
decorator = decorator.andThen(contentEncodingDecorator());

sb.annotatedService(API_V1_PATH_PREFIX,
new AdministrativeService(safePm, executor), decorator,
new AdministrativeService(executor), decorator,
v1RequestConverter, jacksonRequestConverterFunction, v1ResponseConverter);
sb.annotatedService(API_V1_PATH_PREFIX,
new ProjectServiceV1(safePm, executor, mds), decorator,
new ProjectServiceV1(projectApiManager), decorator,
v1RequestConverter, jacksonRequestConverterFunction, v1ResponseConverter);
sb.annotatedService(API_V1_PATH_PREFIX,
new RepositoryServiceV1(safePm, executor, mds), decorator,
new RepositoryServiceV1(executor, mds), decorator,
v1RequestConverter, jacksonRequestConverterFunction, v1ResponseConverter);
sb.annotatedService()
.pathPrefix(API_V1_PATH_PREFIX)
Expand All @@ -742,7 +742,7 @@ public String serviceName(ServiceRequestContext ctx) {
.decorator(decorator)
.requestConverters(v1RequestConverter, jacksonRequestConverterFunction)
.responseConverters(v1ResponseConverter)
.build(new ContentServiceV1(safePm, executor, watchService));
.build(new ContentServiceV1(executor, watchService));

if (authProvider != null) {
final AuthConfig authCfg = cfg.authConfig();
Expand All @@ -751,7 +751,7 @@ public String serviceName(ServiceRequestContext ctx) {
new MetadataApiService(mds, authCfg.loginNameNormalizer()),
decorator, v1RequestConverter, jacksonRequestConverterFunction,
v1ResponseConverter);
sb.annotatedService(API_V1_PATH_PREFIX, new TokenService(pm, executor, mds),
sb.annotatedService(API_V1_PATH_PREFIX, new TokenService(executor, mds),
decorator, v1RequestConverter, jacksonRequestConverterFunction,
v1ResponseConverter);

Expand All @@ -774,9 +774,9 @@ public String serviceName(ServiceRequestContext ctx) {
final RestfulJsonResponseConverter httpApiV0Converter = new RestfulJsonResponseConverter();

// TODO(hyangtack): Simplify this if https://github.com/line/armeria/issues/582 is resolved.
sb.annotatedService(API_V0_PATH_PREFIX, new UserService(safePm, executor),
sb.annotatedService(API_V0_PATH_PREFIX, new UserService(executor),
decorator, jacksonRequestConverterFunction, httpApiV0Converter)
.annotatedService(API_V0_PATH_PREFIX, new RepositoryService(safePm, executor),
.annotatedService(API_V0_PATH_PREFIX, new RepositoryService(projectApiManager, executor),
decorator, jacksonRequestConverterFunction, httpApiV0Converter);

if (authProvider != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import static java.util.Objects.requireNonNull;

import javax.annotation.Nullable;

import com.google.common.annotations.VisibleForTesting;

import com.linecorp.armeria.common.RequestContext;
Expand Down Expand Up @@ -55,6 +57,15 @@ public static User currentUser() {
return currentUser(RequestContext.current());
}

@Nullable
public static User currentUserOrNull() {
final ServiceRequestContext currentOrNull = ServiceRequestContext.currentOrNull();
if (currentOrNull == null) {
return null;
}
return currentUser(currentOrNull);
}

public static void setCurrentUser(ServiceRequestContext ctx, User currentUser) {
requireNonNull(ctx, "ctx");
requireNonNull(currentUser, "currentUser");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
import com.linecorp.centraldogma.server.internal.api.HttpApiExceptionHandler;
import com.linecorp.centraldogma.server.internal.api.auth.RequiresReadPermission;
import com.linecorp.centraldogma.server.internal.api.auth.RequiresWritePermission;
import com.linecorp.centraldogma.server.storage.project.ProjectManager;
import com.linecorp.centraldogma.server.internal.storage.project.ProjectApiManager;
import com.linecorp.centraldogma.server.storage.repository.Repository;

/**
Expand All @@ -75,8 +75,11 @@ public class RepositoryService extends AbstractService {

private static final Splitter termSplitter = Splitter.on(',').trimResults().omitEmptyStrings();

public RepositoryService(ProjectManager projectManager, CommandExecutor executor) {
super(projectManager, executor);
private final ProjectApiManager projectApiManager;

public RepositoryService(ProjectApiManager projectApiManager, CommandExecutor executor) {
super(executor);
this.projectApiManager = projectApiManager;
}

/**
Expand All @@ -87,8 +90,8 @@ public RepositoryService(ProjectManager projectManager, CommandExecutor executor
public RevisionDto normalizeRevision(@Param String projectName,
@Param String repoName,
@Param String revision) {
return DtoConverter.convert(projectManager().get(projectName).repos().get(repoName)
.normalizeNow(new Revision(revision)));
return DtoConverter.convert(projectApiManager.getProject(projectName).repos().get(repoName)
.normalizeNow(new Revision(revision)));
}

/**
Expand All @@ -105,7 +108,7 @@ public CompletionStage<EntryDto> getFile(@Param String projectName,
@Param @Default("") String expression) {

final Query<?> query = Query.of(queryType,path, expression);
final Repository repo = projectManager().get(projectName).repos().get(repoName);
final Repository repo = projectApiManager.getProject(projectName).repos().get(repoName);
return repo.get(repo.normalizeNow(new Revision(revision)), query)
.thenApply(DtoConverter::convert);
}
Expand Down Expand Up @@ -174,13 +177,13 @@ public CompletionStage<List<CommitDto>> getHistory(@Param String projectName,
@Param String path,
@Param @Default("-1") String from,
@Param @Default("1") String to) {
return projectManager().get(projectName).repos().get(repoName)
.history(new Revision(from),
new Revision(to),
path + "**")
.thenApply(commits -> commits.stream()
.map(DtoConverter::convert)
.collect(toList()));
return projectApiManager.getProject(projectName).repos().get(repoName)
.history(new Revision(from),
new Revision(to),
path + "**")
.thenApply(commits -> commits.stream()
.map(DtoConverter::convert)
.collect(toList()));
}

/**
Expand All @@ -192,11 +195,11 @@ public CompletionStage<List<EntryDto>> search(@Param String projectName,
@Param String repoName,
@Param String revision,
@Param String term) {
return projectManager().get(projectName).repos().get(repoName)
.find(new Revision(revision), normalizeSearchTerm(term), FIND_ALL_WITH_CONTENT)
.thenApply(entries -> entries.values().stream()
.map(DtoConverter::convert)
.collect(toList()));
return projectApiManager.getProject(projectName).repos().get(repoName)
.find(new Revision(revision), normalizeSearchTerm(term), FIND_ALL_WITH_CONTENT)
.thenApply(entries -> entries.values().stream()
.map(DtoConverter::convert)
.collect(toList()));
}

/**
Expand All @@ -210,18 +213,18 @@ public CompletionStage<List<ChangeDto>> getDiff(@Param String projectName,
@Param String path,
@Param String from,
@Param String to) {
return projectManager().get(projectName).repos().get(repoName)
.diff(new Revision(from), new Revision(to), path)
.thenApply(changeMap -> changeMap.values().stream()
.map(DtoConverter::convert)
.collect(toList()));
return projectApiManager.getProject(projectName).repos().get(repoName)
.diff(new Revision(from), new Revision(to), path)
.thenApply(changeMap -> changeMap.values().stream()
.map(DtoConverter::convert)
.collect(toList()));
}

private CompletableFuture<?> push(String projectName, String repoName,
Revision revision, Author author,
String commitSummary, String commitDetail, Markup commitMarkup,
Change<?> change) {
final Repository repo = projectManager().get(projectName).repos().get(repoName);
final Repository repo = projectApiManager.getProject(projectName).repos().get(repoName);
return push0(projectName, repoName, repo.normalizeNow(revision), author,
commitSummary, commitDetail, commitMarkup, change);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@
import com.linecorp.centraldogma.server.internal.admin.auth.AuthUtil;
import com.linecorp.centraldogma.server.internal.api.AbstractService;
import com.linecorp.centraldogma.server.metadata.User;
import com.linecorp.centraldogma.server.storage.project.ProjectManager;

/**
* Annotated service object for managing users.
*/
public class UserService extends AbstractService {

public UserService(ProjectManager projectManager, CommandExecutor executor) {
super(projectManager, executor);
public UserService(CommandExecutor executor) {
super(executor);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,18 @@

import com.linecorp.centraldogma.server.command.Command;
import com.linecorp.centraldogma.server.command.CommandExecutor;
import com.linecorp.centraldogma.server.storage.project.ProjectManager;

/**
* A base service class for HTTP API.
*/
public class AbstractService {

private final ProjectManager projectManager;
private final CommandExecutor executor;

protected AbstractService(ProjectManager projectManager, CommandExecutor executor) {
this.projectManager = requireNonNull(projectManager, "projectManager");
protected AbstractService(CommandExecutor executor) {
this.executor = requireNonNull(executor, "executor");
}

public final ProjectManager projectManager() {
return projectManager;
}

public final CommandExecutor executor() {
return executor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@
import com.linecorp.centraldogma.internal.jsonpatch.JsonPatchException;
import com.linecorp.centraldogma.server.command.CommandExecutor;
import com.linecorp.centraldogma.server.internal.api.auth.RequiresAdministrator;
import com.linecorp.centraldogma.server.storage.project.ProjectManager;

@ProducesJson
public final class AdministrativeService extends AbstractService {

private static final Logger logger = LoggerFactory.getLogger(AdministrativeService.class);

public AdministrativeService(ProjectManager projectManager, CommandExecutor executor) {
super(projectManager, executor);
public AdministrativeService(CommandExecutor executor) {
super(executor);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
import com.linecorp.centraldogma.server.internal.api.converter.WatchRequestConverter.WatchRequest;
import com.linecorp.centraldogma.server.internal.storage.repository.DefaultMetaRepository;
import com.linecorp.centraldogma.server.storage.project.Project;
import com.linecorp.centraldogma.server.storage.project.ProjectManager;
import com.linecorp.centraldogma.server.storage.repository.FindOption;
import com.linecorp.centraldogma.server.storage.repository.FindOptions;
import com.linecorp.centraldogma.server.storage.repository.Repository;
Expand All @@ -103,9 +102,8 @@ public class ContentServiceV1 extends AbstractService {

private final WatchService watchService;

public ContentServiceV1(ProjectManager projectManager, CommandExecutor executor,
WatchService watchService) {
super(projectManager, executor);
public ContentServiceV1(CommandExecutor executor, WatchService watchService) {
super(executor);
this.watchService = requireNonNull(watchService, "watchService");
}

Expand Down
Loading

0 comments on commit 10ea91f

Please sign in to comment.