Skip to content

add the internal updateGitMetadata api#15340

Merged
GnsP merged 1 commit intocdapio:developfrom
GnsP:scm-update-git-meta
Oct 24, 2023
Merged

add the internal updateGitMetadata api#15340
GnsP merged 1 commit intocdapio:developfrom
GnsP:scm-update-git-meta

Conversation

@GnsP
Copy link
Copy Markdown
Contributor

@GnsP GnsP commented Sep 29, 2023

This PR adds an internal api api/v3internal/namespaces/:namespace/apps/updateSourceControlMeta. This api takes a list of appIds (with versionIds) with gitFileHashes and updates their scm metadata in the database.

JIRA: CDAP-20856

@GnsP GnsP added the build Triggers github actions build label Oct 11, 2023
Copy link
Copy Markdown
Contributor

@albertshau albertshau left a comment

Choose a reason for hiding this comment

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

can you explain why we need this?

}

@Override
public void updateApplicationSourceControlMeta(List<UpdateSourceControlMetaRequest> updateRequests) throws IOException {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand what the intent of this method is. As implemented, it looks like it is trying to create a new application version with the current app spec but with a different file hash. But why would we want to do that? The file hash is tied to the application information, if it is changing the application should also be changing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have updated the implementation to update only the source_control_metadata column.

*
* @throws IOException if scm meta update fails
*/
void updateApplicationSourceControlMeta(List<UpdateSourceControlMetaRequest> updateRequests)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

List -> Collection

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

any time a store method is added, it must be covered by new unit tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Made the change to take a collection. And added unit test for the method.

ApplicationSpecification specification);

/**
* updates source control meta of an application
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Updates source control metadata for one or more applications

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Like for other batch APIs, this should clearly describe the expected behavior in relevant edge cases. For example, what is the expected behavior if one of the applications in the give collection does not exist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated the javadoc and added exception cases.

* @throws Exception if either namespace or any of the application doesn't exist
*/
@POST
@Path("/apps/updateGitMetadata")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

in ApplicationDetail, it is called 'sourceControlMeta'. Should update this to be consistent, updateSourceControlMeta

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

List<AppUpdateGitMetaRequest> appsUpdateGitMetaRequest;

try {
appsUpdateGitMetaRequest = parseBody(request, listOfAppUpdateGitMetaRequestType);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In general, request bodies should be objects and not collections, even if it is just an object with a single collection field. This allows the API to be more extensible. For example, in the future we could add an options field or something like that.

(This is not always followed in some of the older APIs, but those are bad examples).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

throws IOException {
List<UpdateSourceControlMetaRequest> updateScmMetaRequests = new ArrayList<>();
for (AppUpdateGitMetaRequest updateRequest : updateRequests) {
ApplicationId appId = new ApplicationId(
Copy link
Copy Markdown
Contributor

@albertshau albertshau Oct 17, 2023

Choose a reason for hiding this comment

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

It is possible for this to throw an IllegalArgumentException for invalid application ids. Need to catch it and throw BadRequestException so that it becomes a 400.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

import io.cdap.cdap.proto.id.ApplicationId;
import java.util.Objects;

public class UpdateSourceControlMetaRequest {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

in general, the classes in proto represent something in the REST APIs. This should be moved internally to app-fabric.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

moved to app-fabric. Renamed class to ApplicationSourceControlMeta.

import java.util.Objects;

public class AppUpdateGitMetaRequest {
private final String appId;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

make this consistent with ApplicationDetail.

appId -> name, fileHash -> sourceControlMeta

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done. Also renamed the class to AppUpdateSourceControlMetaRequest.

public void updateAppScmMeta(ApplicationId appId, SourceControlMeta scmMeta) throws IOException {
ApplicationMeta existing = getApplication(appId);
if (existing == null) {
throw new IllegalArgumentException("Application " + appId + " does not exist");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this shouldn't be IllegalArgumentException, ApplicaitonNotFoundException would be more specific.

Though I don't think throwing an exception is actually the behavior we want anyway. For example, if somebody deletes an application while the bulk push is happening, we probably just want to skip it instead of failing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated to throw ApplicationNotFoundException.

I think we should throw the exception here. If we do not want to fail the atomic operation, then we can simply ignore this exception and continue with the transaction.

@Test
public void testAppMarkLatestRequestDeserialize() throws Exception {
String appUpdateGitMetadataRequest = "{\n"
+ " \"appId\": \"test-application-id\","
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

as mentioned in the other PR, this is not a useful test that we need to perform, as it is basically just testing that Gson does the right thing.

Instead, there should be unit tests covering the new logic that was added.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed this test.

@GnsP GnsP force-pushed the scm-update-git-meta branch from 16a41e1 to 9f8bcd9 Compare October 19, 2023 10:10
/**
* Request class to update sourceControlMeta of an application.
*/
public class AppUpdateSourceControlMetaRequest {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please rename to UpdateSourceControlMetaRequest

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

}

/**
* Update scm metadata for the given apps.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Provide context where this will be used.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added javadoc comment providing context on intended usage.

public void updateSourceControlMeta(NamespaceId namespace, AppsUpdateSourceControlMetaRequest appsRequest)
throws IOException, BadRequestException, ApplicationNotFoundException {

List<ApplicationSourceControlMeta> updateScmMetaRequests = new ArrayList<>();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: ApplicationSourceControlMeta class is strictly not needed. We would never need to extend this so we will be able to use a Map<ApplicationId, SourceControlMeta>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

for (AppUpdateSourceControlMetaRequest appRequest : appsRequest.getApps()) {
String appName = appRequest.getName();
boolean isAdded = seenApps.add(appName);
if (!isAdded) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

single line

!(seenApps.add(appRequest.getName()))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.


try {
ApplicationId appId = namespace.app(appName, appRequest.getAppVersion());
SourceControlMeta scmMeta = new SourceControlMeta(appRequest.getSourceControlMeta());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

change SourceControlMeta in request to gitFileHash

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

);
updateScmMetaRequests.add(updateScmMetaRequest);
} catch (IllegalArgumentException | NullPointerException e) {
throw new BadRequestException("Invalid application name or version. " + e.getCause());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the message should include the name , version and pass e as second parameter to the constructor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

AppMetadataStore mds = getAppMetadataStore(context);
for (ApplicationSourceControlMeta updateRequest : updateRequests) {
ApplicationId appId = updateRequest.getAppId();
mds.updateAppScmMeta(appId, updateRequest.getScmMeta());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ignore ApplicationNotFoundException and continue. In case the app isn missing we would still want to update other app metadata

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

}

@Test
public void testUpdateApplicationScmMeta()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add error tests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

* @throws BadRequestException when multiple filehashes are provided for an application
* @throws ApplicationNotFoundException when any of the applications is not found
*/
public void updateSourceControlMeta(NamespaceId namespace, AppsUpdateSourceControlMetaRequest appsRequest)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add unit tests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added unit tests for success and failure cases.

/**
* Request class to update source control meta of multiple applications.
*/
public class AppsUpdateSourceControlMetaRequest {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UpdateMultiSourceControlMetaReqeust

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

@GnsP GnsP force-pushed the scm-update-git-meta branch from 9f8bcd9 to ce67d58 Compare October 19, 2023 12:44
Copy link
Copy Markdown
Contributor

@albertshau albertshau left a comment

Choose a reason for hiding this comment

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

looks mostly good, but the comment about update not working correctly is concerning. Can you describe how it is broken?

appRequest.getName(), appRequest.getAppVersion()
));
}
} catch (IllegalArgumentException | NullPointerException e) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this try-catch should be only around the namespace.app() call. That way it is clear what sort of error this is happening.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

}
} catch (IllegalArgumentException | NullPointerException e) {
throw new BadRequestException(
String.format("Invalid application name (%s) or version (%s).",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use the exception's message new BadRequestException(e.getMessage(), e). The cause already has a more specific error message about what is wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

*/
public void updateAppScmMeta(ApplicationId appId, SourceControlMeta scmMeta)
throws IOException, ApplicationNotFoundException {
final StructuredTable appSpecTable = getApplicationSpecificationTable();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

doesn't need to be declared final

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated.

}

fields.add(Fields.stringField(StoreDefinition.AppMetadataStore.SOURCE_CONTROL_META, GSON.toJson(scmMeta)));
// upsert, because update does not seem to work correctly in the nosql implementation
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what does this mean, what does not work correctly?

It's a big problem if the nosql implementation is broken, would mean anything else using it is broken. If it is indeed broken, please open a blocker jira and reference it in the TODO below

Copy link
Copy Markdown
Contributor Author

@GnsP GnsP Oct 19, 2023

Choose a reason for hiding this comment

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

Added a blocker JIRA to track this. CDAP-20853

@GnsP
Copy link
Copy Markdown
Contributor Author

GnsP commented Oct 19, 2023

looks mostly good, but the comment about update not working correctly is concerning. Can you describe how it is broken?

Created the following JIRA to track this issue. The issue description can be found there.

https://cdap.atlassian.net/browse/CDAP-20853

@GnsP GnsP force-pushed the scm-update-git-meta branch 2 times, most recently from cc2e8e9 to 0ecb43e Compare October 19, 2023 18:32
Copy link
Copy Markdown
Contributor

@albertshau albertshau left a comment

Choose a reason for hiding this comment

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

minor comments, otherwise lgtm.

Though it looks like the build is failing, please be sure to address any problems there.


if (null == appRequest.getGitFileHash()) {
throw new BadRequestException(String.format(
"Null gitFileHash for app (name = %s, version = %s).",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: try to avoid more technical language like 'null' in user facing error messages. gitFileHash missing for app ...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it's also fine to combine the null and empty check into one if block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.


SourceControlMeta scmMeta = new SourceControlMeta(appRequest.getGitFileHash());

if (null != updateScmMetaRequests.put(appId, scmMeta)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: put the null on the other side of the equality check ... != null

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

@GnsP GnsP force-pushed the scm-update-git-meta branch 2 times, most recently from a7eb8f1 to dd9f1c1 Compare October 20, 2023 05:16
@GnsP GnsP force-pushed the scm-update-git-meta branch from dd9f1c1 to 505a87f Compare October 24, 2023 03:42
@samdgupi samdgupi added the 6.10 label Oct 24, 2023
@GnsP GnsP merged commit 1e709f6 into cdapio:develop Oct 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.10 build Triggers github actions build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants