Repository navigation
SOLR-18212: Migrate PackageAPI endpoints from @EndPoint/@Command to JAX-RS #4178
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
base: main
Are you sure you want to change the base?
Changes from all commits
a86cf71
9422c8c
744e8ff
cc26412
5040f5b
83c2f5c
d71f199
8994e03
199b0f3
463f590
ae94dd3
62212c3
30ab7cc
99d90e7
7967574
7491730
deb2142
2578d26
bf46dc7
a0bef90
ba61c1b
670562d
702b181
1cfc294
b51a155
742b0ba
59c1c26
47fd06e
aa2d56e
2445ef1
901d90e
9ff3b2f
8a6bdd2
2690834
f8ed9a0
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,9 @@ | ||
| title: The package management API now has OpenAPI and SolrJ support. As part of this migration, the (experimental v2) API path moved from `/api/cluster/package` to `/api/cluster/packages`, and requests for a non-existent package or package version now return HTTP 404 instead of 400. | ||
| type: changed | ||
| authors: | ||
| - name: Eric Pugh | ||
| links: | ||
| - name: PR#4178 | ||
| url: https://github.com/apache/solr/pull/4178 | ||
| - name: SOLR-18212 | ||
| url: https://issues.apache.org/jira/browse/SOLR-18212 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You 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 org.apache.solr.client.api.endpoint; | ||
|
|
||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.Parameter; | ||
| import io.swagger.v3.oas.annotations.parameters.RequestBody; | ||
| import jakarta.ws.rs.DELETE; | ||
| import jakarta.ws.rs.GET; | ||
| import jakarta.ws.rs.POST; | ||
| import jakarta.ws.rs.Path; | ||
| import jakarta.ws.rs.PathParam; | ||
| import jakarta.ws.rs.QueryParam; | ||
| import org.apache.solr.client.api.model.AddPackageVersionRequestBody; | ||
| import org.apache.solr.client.api.model.GetPackageResponse; | ||
| import org.apache.solr.client.api.model.ListPackagesResponse; | ||
| import org.apache.solr.client.api.model.SolrJerseyResponse; | ||
|
|
||
| /** V2 API definitions for managing Solr packages. */ | ||
| @Path("/cluster/packages") | ||
| public interface PackageApis { | ||
|
|
||
| @GET | ||
| @Operation( | ||
| summary = "List all packages registered in this Solr cluster.", | ||
| tags = {"package"}) | ||
| ListPackagesResponse listPackages( | ||
| @Parameter( | ||
| description = | ||
| "If provided, the node waits until its package data matches this ZooKeeper version.") | ||
| @QueryParam("expectedVersion") | ||
| Integer expectedVersion); | ||
|
|
||
| @GET | ||
| @Path("/{packageName}") | ||
| @Operation( | ||
| summary = "Get information about a specific package in this Solr cluster.", | ||
| tags = {"package"}) | ||
| GetPackageResponse getPackage( | ||
| @Parameter(description = "The name of the package.", required = true) | ||
| @PathParam("packageName") | ||
| String packageName, | ||
| @Parameter( | ||
| description = | ||
| "If provided, the node waits until its package data matches this ZooKeeper version before responding.") | ||
| @QueryParam("expectedVersion") | ||
| Integer expectedVersion); | ||
|
|
||
| @POST | ||
| @Path("/{packageName}/versions") | ||
| @Operation( | ||
| summary = "Add a version of a package to this Solr cluster.", | ||
| tags = {"package"}) | ||
| SolrJerseyResponse addPackageVersion( | ||
| @Parameter(description = "The name of the package.", required = true) | ||
| @PathParam("packageName") | ||
| String packageName, | ||
| @RequestBody(description = "Details of the package version to add.", required = true) | ||
| AddPackageVersionRequestBody requestBody); | ||
|
|
||
| @DELETE | ||
| @Path("/{packageName}/versions/{version}") | ||
| @Operation( | ||
| summary = "Delete a specific version of a package from this Solr cluster.", | ||
| tags = {"package"}) | ||
| SolrJerseyResponse deletePackageVersion( | ||
| @Parameter(description = "The name of the package.", required = true) | ||
| @PathParam("packageName") | ||
| String packageName, | ||
| @Parameter(description = "The version of the package to delete.", required = true) | ||
| @PathParam("version") | ||
| String version); | ||
|
|
||
| @POST | ||
| @Path("/{packageName}/refresh") | ||
| @Operation( | ||
| summary = "Refresh a package on all nodes in this Solr cluster.", | ||
| tags = {"package"}) | ||
| SolrJerseyResponse refreshPackage( | ||
| @Parameter(description = "The name of the package to refresh.", required = true) | ||
| @PathParam("packageName") | ||
| String packageName, | ||
| @Parameter( | ||
| description = | ||
| "Indicates whether the refresh should only be done on the receiving node. For internal use only.") | ||
| @QueryParam("localOnly") | ||
| Boolean localOnly); | ||
|
|
||
| @POST | ||
| @Path("/sync") | ||
| @Operation( | ||
| summary = | ||
| "Block until the receiving node's package data matches the given ZooKeeper version. " | ||
| + "Used internally for inter-node fan-out after a package change; not normally invoked directly.", | ||
| tags = {"package"}) | ||
| SolrJerseyResponse syncPackages( | ||
| @Parameter( | ||
| description = "The ZooKeeper version that the receiving node should catch up to.", | ||
| required = true) | ||
| @QueryParam("expectedVersion") | ||
| Integer expectedVersion); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You 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 org.apache.solr.client.api.model; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import java.util.List; | ||
|
|
||
| /** Response for the get-a-specific-package API. */ | ||
| public class GetPackageResponse extends SolrJerseyResponse { | ||
|
|
||
| @JsonProperty("result") | ||
|
Contributor
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. [info] why the key name as "result", why not just "packageInfo" here? |
||
| @Schema(description = "The requested package's data.") | ||
| public PackageInfo result; | ||
|
|
||
| /** Data for a single package, returned by the get-package API. */ | ||
| public static class PackageInfo { | ||
| @JsonProperty("znodeVersion") | ||
| @Schema(description = "The ZooKeeper version of the packages.json node.") | ||
| public int znodeVersion; | ||
|
|
||
| @JsonProperty("name") | ||
| @Schema(description = "The package name.") | ||
| public String name; | ||
|
|
||
| @JsonProperty("versions") | ||
| @Schema(description = "The versions registered for this package.") | ||
| public List<ListPackagesResponse.PackageVersion> versions; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You 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 org.apache.solr.client.api.model; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** Response for the package listing API. */ | ||
| public class ListPackagesResponse extends SolrJerseyResponse { | ||
|
|
||
| @JsonProperty("result") | ||
|
Contributor
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. [question] why not "packages" as the key? |
||
| @Schema(description = "The package data including znode version and package definitions.") | ||
| public PackageData result; | ||
|
|
||
| /** Package data returned by the package API. */ | ||
| public static class PackageData { | ||
| @JsonProperty("znodeVersion") | ||
| @Schema(description = "The ZooKeeper version of the packages.json node.") | ||
| public int znodeVersion; | ||
|
|
||
| @JsonProperty("packages") | ||
| @Schema(description = "Map from package name to list of package versions.") | ||
| public Map<String, List<PackageVersion>> packages; | ||
| } | ||
|
|
||
| /** Describes a single version of a package. */ | ||
| public static class PackageVersion { | ||
| @JsonProperty("package") | ||
| @Schema(description = "The package name.") | ||
| public String pkg; | ||
|
|
||
| @JsonProperty("version") | ||
| @Schema(description = "The version string.") | ||
| public String version; | ||
|
|
||
| @JsonProperty("files") | ||
| @Schema(description = "List of file paths from the file store included in this version.") | ||
| public List<String> files; | ||
|
|
||
| @JsonProperty("manifest") | ||
| @Schema(description = "Optional manifest reference.") | ||
| public String manifest; | ||
|
|
||
| @JsonProperty("manifestSHA512") | ||
| @Schema(description = "Optional SHA-512 hash of the manifest.") | ||
| public String manifestSHA512; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,12 +50,10 @@ | |
| import org.apache.solr.client.solrj.SolrRequest; | ||
| import org.apache.solr.client.solrj.SolrServerException; | ||
| import org.apache.solr.client.solrj.impl.SolrZkClientTimeout; | ||
| import org.apache.solr.client.solrj.request.GenericSolrRequest; | ||
| import org.apache.solr.client.solrj.request.FileStoreApi; | ||
| import org.apache.solr.client.solrj.request.GenericV2SolrRequest; | ||
| import org.apache.solr.client.solrj.request.V2Request; | ||
| import org.apache.solr.client.solrj.request.beans.PackagePayload; | ||
| import org.apache.solr.client.solrj.request.PackageApi; | ||
| import org.apache.solr.client.solrj.request.beans.PluginMeta; | ||
| import org.apache.solr.client.solrj.response.V2Response; | ||
| import org.apache.solr.common.SolrException; | ||
| import org.apache.solr.common.SolrException.ErrorCode; | ||
| import org.apache.solr.common.cloud.SolrZkClient; | ||
|
|
@@ -150,20 +148,9 @@ public void uninstall(String packageName, String version) | |
| // Delete the package by calling the Package API and remove the Jar | ||
|
|
||
| runtime.printSuccess("Executing Package API to remove this package..."); | ||
| PackagePayload.DelVersion del = new PackagePayload.DelVersion(); | ||
| del.version = version; | ||
| del.pkg = packageName; | ||
|
|
||
| V2Request req = | ||
| new V2Request.Builder("/cluster/package") | ||
| .forceV2(true) | ||
| .withMethod(SolrRequest.METHOD.POST) | ||
| .withPayload(Map.of("delete", del)) | ||
| .build(); | ||
|
|
||
| try { | ||
| V2Response resp = req.process(solrClient); | ||
| runtime.printSuccess("Response: " + resp.jsonStr()); | ||
| new PackageApi.DeletePackageVersion(packageName, version).process(solrClient); | ||
|
epugh marked this conversation as resolved.
|
||
| runtime.printSuccess("Package version deleted from Package API."); | ||
| } catch (SolrServerException | IOException e) { | ||
| throw new SolrException(ErrorCode.BAD_REQUEST, e); | ||
| } | ||
|
|
@@ -176,9 +163,8 @@ public void uninstall(String packageName, String version) | |
| String.format(Locale.ROOT, "/package/%s/%s/%s", packageName, version, "manifest.json")); | ||
| for (String filePath : filesToDelete) { | ||
| DistribFileStore.deleteZKFileEntry(zkClient, filePath); | ||
| String path = "/api/cluster/filestore/files" + filePath; | ||
| runtime.printSuccess("Deleting " + path); | ||
| solrClient.request(new GenericSolrRequest(SolrRequest.METHOD.DELETE, path)); | ||
| runtime.printSuccess("Deleting " + filePath); | ||
| new FileStoreApi.DeleteFile(filePath).process(solrClient); | ||
| } | ||
|
|
||
| runtime.printSuccess("Package uninstalled: " + packageName + ":" + version + ":-)"); | ||
|
|
@@ -461,11 +447,8 @@ private Pair<List<String>, List<String>> deployCollectionPackage( | |
| // If updating, refresh the package version for this to take effect | ||
| if (isUpdate || pegToLatest) { | ||
| try { | ||
| SolrCLI.postJsonToSolr( | ||
| solrClient, | ||
| PackageUtils.PACKAGE_PATH, | ||
| "{\"refresh\": \"" + packageInstance.name + "\"}"); | ||
| } catch (Exception ex) { | ||
| new PackageApi.RefreshPackage(packageInstance.name).process(solrClient); | ||
| } catch (SolrServerException | IOException ex) { | ||
| throw new SolrException(ErrorCode.SERVER_ERROR, ex); | ||
| } | ||
| } | ||
|
|
@@ -1079,9 +1062,8 @@ public void undeploy( | |
| solrClient, | ||
| PackageUtils.getCollectionParamsPath(collection), | ||
| "{set: {PKG_VERSIONS: {" + packageName + ": null}}}"); | ||
| SolrCLI.postJsonToSolr( | ||
| solrClient, PackageUtils.PACKAGE_PATH, "{\"refresh\": \"" + packageName + "\"}"); | ||
| } catch (Exception ex) { | ||
| new PackageApi.RefreshPackage(packageName).process(solrClient); | ||
| } catch (Exception ex) { // postJsonToSolr above declares a plain throws Exception | ||
|
Contributor
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. this code comment still valid? |
||
| throw new SolrException(ErrorCode.SERVER_ERROR, ex); | ||
| } | ||
|
|
||
|
|
||
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.
my local IntelliJ showed this warning.
please see, if applicable here.