-
Notifications
You must be signed in to change notification settings - Fork 344
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
[CDAP-20993] Namespace and Repository Source control metadata refresh #15641
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright © 2024 Cask Data, Inc. | ||
* | ||
* 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 io.cdap.cdap.app.store; | ||
|
||
import io.cdap.cdap.proto.SourceControlMetadataRecord; | ||
import java.util.List; | ||
|
||
/** | ||
* Represents a response containing a list of source control metadata records, next page token and | ||
* last refresh time. | ||
*/ | ||
|
||
public class ListSourceControlMetadataResponse { | ||
|
||
private final List<SourceControlMetadataRecord> apps; | ||
private final String nextPageToken; | ||
private final Long lastRefreshTime; | ||
|
||
/** | ||
* Constructs a ListSourceControlMetadataResponse object. | ||
* | ||
* @param apps The list of source control metadata records. | ||
* @param nextPageToken The token for fetching the next page of results. | ||
* @param lastRefreshTime The timestamp of the last refresh operation. | ||
*/ | ||
public ListSourceControlMetadataResponse(List<SourceControlMetadataRecord> apps, | ||
String nextPageToken, Long lastRefreshTime) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annotate parameters that can be null with |
||
this.apps = apps; | ||
this.nextPageToken = nextPageToken; | ||
this.lastRefreshTime = lastRefreshTime; | ||
} | ||
|
||
public List<SourceControlMetadataRecord> getApps() { | ||
return apps; | ||
} | ||
|
||
public String getNextPageToken() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these getter methods used? If not, no need to define them. |
||
return nextPageToken; | ||
} | ||
|
||
public Long getLastRefreshTime() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annotate with |
||
return lastRefreshTime; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright © 2024 Cask Data, Inc. | ||
* | ||
* 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 io.cdap.cdap.app.store; | ||
|
||
import io.cdap.cdap.proto.SourceControlMetadataRecord; | ||
|
||
/** | ||
* Represents a response containing a single source control metadata record and last refresh time. | ||
*/ | ||
public class SingleSourceControlMetadataResponse { | ||
|
||
private final SourceControlMetadataRecord app; | ||
private final Long lastRefreshTime; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this nullable? If so, please annotate accordingly. |
||
|
||
/** | ||
* Constructs a SingleSourceControlMetadataResponse object. | ||
* | ||
* @param app The source control metadata record. | ||
* @param lastRefreshTime The timestamp of the last refresh operation. | ||
*/ | ||
public SingleSourceControlMetadataResponse(SourceControlMetadataRecord app, | ||
Long lastRefreshTime) { | ||
this.app = app; | ||
this.lastRefreshTime = lastRefreshTime; | ||
} | ||
|
||
public SourceControlMetadataRecord getApp() { | ||
return app; | ||
} | ||
|
||
public Long getLastRefreshTime() { | ||
return lastRefreshTime; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,8 +33,10 @@ | |
import io.cdap.cdap.api.security.AccessException; | ||
import io.cdap.cdap.app.runtime.ProgramRuntimeService; | ||
import io.cdap.cdap.app.store.ApplicationFilter; | ||
import io.cdap.cdap.app.store.ListSourceControlMetadataResponse; | ||
import io.cdap.cdap.app.store.ScanApplicationsRequest; | ||
import io.cdap.cdap.app.store.ScanSourceControlMetadataRequest; | ||
import io.cdap.cdap.app.store.SingleSourceControlMetadataResponse; | ||
import io.cdap.cdap.common.ApplicationNotFoundException; | ||
import io.cdap.cdap.common.ArtifactAlreadyExistsException; | ||
import io.cdap.cdap.common.BadRequestException; | ||
|
@@ -43,7 +45,9 @@ | |
import io.cdap.cdap.common.NamespaceNotFoundException; | ||
import io.cdap.cdap.common.NotFoundException; | ||
import io.cdap.cdap.common.NotImplementedException; | ||
import io.cdap.cdap.common.RepositoryNotFoundException; | ||
import io.cdap.cdap.common.ServiceException; | ||
import io.cdap.cdap.common.SourceControlMetadataNotFoundException; | ||
import io.cdap.cdap.common.app.RunIds; | ||
import io.cdap.cdap.common.conf.CConfiguration; | ||
import io.cdap.cdap.common.conf.Constants; | ||
|
@@ -129,7 +133,6 @@ | |
* Key in json paginated applications list response. | ||
*/ | ||
public static final String APP_LIST_PAGINATED_KEY = "applications"; | ||
public static final String APP_LIST_PAGINATED_KEY_SHORT = "apps"; | ||
|
||
/** | ||
* Runtime program service for running and managing programs. | ||
|
@@ -295,7 +298,8 @@ | |
} | ||
|
||
/** | ||
* Retrieves all namespace source control metadata for applications within the specified namespace. | ||
* Retrieves all namespace source control metadata for applications within the specified namespace, | ||
* next page token and last refresh time. | ||
* | ||
* @param request The HTTP request containing parameters for retrieving metadata. | ||
* @param responder The HTTP responder for sending the response. | ||
|
@@ -319,31 +323,26 @@ | |
@QueryParam("filter") String filter | ||
) throws Exception { | ||
validateNamespace(namespaceId); | ||
|
||
JsonPaginatedListResponder.respond(GSON, responder, APP_LIST_PAGINATED_KEY_SHORT, | ||
jsonListResponder -> { | ||
AtomicReference<SourceControlMetadataRecord> lastRecord = new AtomicReference<>(null); | ||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached = false; | ||
try { | ||
pageLimitReached = applicationLifecycleService.scanSourceControlMetadata( | ||
scanRequest, batchSize, | ||
scmMetaRecord -> { | ||
jsonListResponder.send(scmMetaRecord); | ||
lastRecord.set(scmMetaRecord); | ||
}); | ||
} catch (IOException e) { | ||
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
} | ||
SourceControlMetadataRecord record = lastRecord.get(); | ||
return !pageLimitReached || record == null ? null : record.getName(); | ||
}); | ||
List<SourceControlMetadataRecord> apps = new ArrayList<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should check if repoconfig is present here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
ScanSourceControlMetadataRequest scanRequest = SourceControlMetadataHelper.getScmStatusScanRequest( | ||
namespaceId, | ||
pageToken, pageSize, sortOrder, sortOn, filter); | ||
boolean pageLimitReached; | ||
pageLimitReached = applicationLifecycleService.scanSourceControlMetadata( | ||
scanRequest, batchSize, | ||
apps::add); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the old code we don't buffer the app, but in the new code we do. I remember do removed the buffered to avoid high memory consumption, but now we are bringing the same problem back. Is buffering needed? Seems like we can refactor the JsonPaginatedListResponder so that it can emit extra fields (lastRefreshTime in this case) before closing the json object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can extend |
||
SourceControlMetadataRecord record = apps.isEmpty() ? null :apps.get(apps.size() - 1); | ||
Check warning on line 334 in cdap-app-fabric/src/main/java/io/cdap/cdap/gateway/handlers/AppLifecycleHttpHandler.java GitHub Actions / Checkstylecom.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAroundCheck
|
||
String nextPageToken = !pageLimitReached || record == null ? null : | ||
record.getName(); | ||
long lastRefreshTime = applicationLifecycleService.getLastRefreshTime(namespaceId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like unwise to sync all apps, shouldn't we just sync the apps fetched in this page? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we are cloning the full repository which would be time taking it might be wasteful to just update few pipelines. |
||
ListSourceControlMetadataResponse response = new ListSourceControlMetadataResponse(apps, | ||
nextPageToken, lastRefreshTime == 0L ? null : lastRefreshTime); | ||
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(response)); | ||
} | ||
|
||
/** | ||
* Retrieves the source control metadata for the specified application within the specified namespace. | ||
* Retrieves the source control metadata for the specified application within the specified namespace | ||
* and last refresh time of git pull/push. | ||
* | ||
* @param request The HTTP request containing parameters for retrieving metadata. | ||
* @param responder The HTTP responder for sending the response. | ||
|
@@ -355,12 +354,15 @@ | |
@Path("/apps/{app-id}/sourcecontrol") | ||
public void getNamespaceSourceControlMetadata(HttpRequest request, HttpResponder responder, | ||
@PathParam("namespace-id") final String namespaceId, | ||
@PathParam("app-id") final String appName) throws Exception { | ||
@PathParam("app-id") final String appName) | ||
throws BadRequestException, NamespaceNotFoundException, | ||
SourceControlMetadataNotFoundException, RepositoryNotFoundException { | ||
validateApplicationId(namespaceId, appName); | ||
|
||
responder.sendJson(HttpResponseStatus.OK, | ||
GSON.toJson(applicationLifecycleService.getSourceControlMetadataRecord( | ||
new ApplicationReference(namespaceId, appName)))); | ||
SourceControlMetadataRecord app = applicationLifecycleService.getSourceControlMetadataRecord( | ||
new ApplicationReference(namespaceId, appName)); | ||
Long lastRefreshTime = applicationLifecycleService.getLastRefreshTime(namespaceId); | ||
SingleSourceControlMetadataResponse response = new SingleSourceControlMetadataResponse(app, lastRefreshTime); | ||
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(response)); | ||
} | ||
|
||
private ScanApplicationsRequest getScanRequest(String namespaceId, String artifactVersion, | ||
|
@@ -375,7 +377,7 @@ | |
} | ||
if (nameFilter != null && !nameFilter.isEmpty()) { | ||
if (nameFilterType != null) { | ||
switch (nameFilterType) { | ||
case EQUALS: | ||
builder.setApplicationReference(new ApplicationReference(namespaceId, nameFilter)); | ||
break; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use boxed type? Is it nullable? It's better not to use box type if possible. Is there a meaning default value for it that you can use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its null if the refresh has not been run yet. I think it would be more appropiate to have default value as null in the API response than a actual long value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it can ever be null. The value comes from
SourceControlMetadataRefresher.getLastRefreshTime
, which returns primitive long, and the implementation is defaulting it to0L