Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a way to trigger Git mirroring manually #1041

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

ikhoon
Copy link
Contributor

@ikhoon ikhoon commented Sep 30, 2024

Motivation:

  • There is no easy way to test Git mirroring configurations.
  • Some users may want to run Git mirroring manually instead of using the periodic scheduler.

Modifications:

  • Add POST /projects/{projectName}/mirrors/{mirrorId}/run REST API to MirroringServiceV1 so as to trigger a mirroring task.
  • Add verboseResponses to CentralDogmaConfig so as to contain full stack traces in error responses.
    • The cause of mirroring failures will be displayed in the UI for administrators or verboseResponses is enabled.
  • Change AbstractMirror to return MirrorResult which is used to notify the result in the UI.
  • Make MirrorDto.schedule nullable.
    • Exclude a mirror configuration from scheduling schedule it is null.
  • Move MirrorException to common and expose it in the error responses.
  • Add cronstrue dependency to package.json to display a human readable description on the mirror form UI.
  • Increase maxWidth of NotificationWrapper to render stack traces well.

Result:

@ikhoon ikhoon marked this pull request as ready for review October 7, 2024 11:03
@ikhoon ikhoon added this to the 0.71.0 milestone Oct 7, 2024
@ikhoon
Copy link
Contributor Author

ikhoon commented Oct 8, 2024

374385177-3dc05873-2e74-4bcf-b90d-d023acd196bc.mp4

@@ -61,16 +62,18 @@ public abstract class AbstractMirror implements Mirror {
private final String remoteBranch;
@Nullable
private final String gitignore;
@Nullable
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: with this change, I feel like the enabled flag doesn't have much value.

e.g. If enabled = false but a manual trigger is done, will the mirror execute?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If enabled = false, the run button is disabled in the UI. However, I didn't reject the execution on the server side. Let me add the validation.

Copy link
Member

Choose a reason for hiding this comment

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

I feel like it still run even when enabled is false because the user might want to verify whether the mirror setting is correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does that mean we check mirroring settings but do not push the mirrored data to the local repository when enabled = false?

I thought users could test a new mirror with enabled = true & scheduled = disabled settings.

@@ -133,6 +134,7 @@ public final class ArmeriaCentralDogma extends AbstractCentralDogma {
.put(RepositoryExistsException.class.getName(), RepositoryExistsException::new)
.put(InvalidPushException.class.getName(), InvalidPushException::new)
.put(ReadOnlyException.class.getName(), ReadOnlyException::new)
.put(MirrorException.class.getName(), MirrorException::new)
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: I understood this will actually never be called since CentralDogma client doesn't have any mirror related APIs

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 added it mechanically. We may add mirror API in CentralDogma client later.

"mirrorApiWorker");
}

public CompletableFuture<MirrorResult> run(String projectName, String mirrorId) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional) For better UX, if a mirrorRunId and the triggeredTime is returned I think it may be more clear to users whether the mirror result is from an in-flight mirror or a new attempt.

Copy link
Contributor Author

@ikhoon ikhoon Oct 8, 2024

Choose a reason for hiding this comment

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

It is difficult to create a unique/incremental ID without an external system. However, triggeredTime can be easily added.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was imagining a simple UUID inside MirrorKey, but I guess just returning triggeredTime is fine too

@@ -262,6 +263,11 @@ Core properties

- the path of the management service. If not specified, the management service is mounted at ``/internal/management``.

- ``verboseResponses`` (boolean)
Copy link
Contributor

Choose a reason for hiding this comment

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

Question) I'm not confident exceptions don't contain sensitive information (e.g. like credentials). If we do add this property, are you planning on enabling it in our in-house clusters by default?

Copy link
Contributor Author

@ikhoon ikhoon Oct 8, 2024

Choose a reason for hiding this comment

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

Right. I intended to add this feature for use in our in-house systems.

  • The sensitive information of credentials is marked when it is serialized.
  • The permission manager will check if the caller is granted to access the information.

Even though sensitive information is exposed in error stack traces and delivered to the caller, I think, the caller will be a user who already has the appropriate permissions.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, if you are confident then would it make more sense to just enable by default instead of adding a flag?

Copy link
Member

Choose a reason for hiding this comment

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

I feel it's too verbose if we return the stack trace for all HTTP APIs.
What do you think about only returning the stack trace for specific APIs (e.g. mirroring) when accessed by non-admin users?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Later, the exception could be used to generate the client-side stack trace as we did in Armeria gRPC implementation.
https://github.com/line/armeria/blob/main/grpc/src/main/java/com/linecorp/armeria/internal/server/grpc/AbstractServerCall.java#L571-L575

Fine-tuning is a good idea, but for now I think this option is enough for our use case.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Looks great all in all. Left small suggestions. 😉

@@ -0,0 +1,21 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Do these files have to be at the root-level?

@@ -125,11 +133,27 @@ private CompletableFuture<PushResultDto> createOrUpdate(String projectName,
});
}

/**
* POST /projects/{projectName}/mirrors/{mirrorId}/run
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if it works or not but how about using a custom verb?
POST /projects/{projectName}/mirrors/{mirrorId}:run
https://cloud.google.com/apis/design/custom_methods

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, we can't use a path pattern for a custom verb but should use regular expressions. I didn't want to use regex for this sample path pattern.

Copy link
Member

Choose a reason for hiding this comment

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

Then, it's fine as is. I might give it a try to get it working one day.

@@ -61,16 +62,18 @@ public abstract class AbstractMirror implements Mirror {
private final String remoteBranch;
@Nullable
private final String gitignore;
@Nullable
Copy link
Member

Choose a reason for hiding this comment

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

I feel like it still run even when enabled is false because the user might want to verify whether the mirror setting is correct.

mirrorConfig.maxNumBytesPerMirror());
}, worker);
// Remove the inflight request when the mirror task is done.
future.handleAsync((unused0, unused1) -> inflightRequests.remove(mirrorKey));
Copy link
Member

Choose a reason for hiding this comment

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

nit: How about using handle or handleAsync with the worker instead of using common pool?

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 didn't use handle intentionally because inflightRequests.remove could be called recursively inside inflightRequests.computeIfAbsent(). I wasn't confident that all supported JDK versions were safe for the operation.

Let me specify worker for the job.

@@ -262,6 +263,11 @@ Core properties

- the path of the management service. If not specified, the management service is mounted at ``/internal/management``.

- ``verboseResponses`` (boolean)
Copy link
Member

Choose a reason for hiding this comment

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

I feel it's too verbose if we return the stack trace for all HTTP APIs.
What do you think about only returning the stack trace for specific APIs (e.g. mirroring) when accessed by non-admin users?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide a way to trigger Git mirroring immediately Manual mirroring schedule
3 participants