[SPARK-59229][CORE] Identify Apache Spark in the User-Agent for Ivy dependency resolution - #58508
Open
brianf wants to merge 1 commit into
Open
[SPARK-59229][CORE] Identify Apache Spark in the User-Agent for Ivy dependency resolution#58508brianf wants to merge 1 commit into
brianf wants to merge 1 commit into
Conversation
…ependency resolution
### What changes were proposed in this pull request?
Set the `http.agent` system property in `MavenUtils` so Ivy identifies itself as
Spark when resolving `--packages` / `spark.jars.packages` coordinates from remote
repositories:
Apache-Spark/4.0.0 (Apache-Ivy/2.5.3)
instead of Ivy's default `Apache Ivy/2.5.3`. The format follows RFC 9110 Section
10.1.5 (`product *( RWS ( product / comment ) )`), preserving the Ivy version that
existing operator tooling matches on.
`http.agent` is Ivy's own designed override point. The property is set once, if
absent, rather than set-and-restored: Ivy's HttpClient-backed handler bakes the
User-Agent into a static singleton at class-initialization time, so a
save/set/restore wrapper would have no effect on requests and would race between
concurrent resolutions.
### Why are the changes needed?
Repository operators use the User-Agent to attribute traffic and reach the
responsible party when a client misbehaves. A bare `Apache Ivy/2.5.3` is
un-attributable — it could be Spark, Ant, sbt, or a hand-rolled Ivy client.
### Does this PR introduce _any_ user-facing change?
Yes. Dependency-resolution requests now carry the Spark User-Agent. Setting
`-Dhttp.agent=...` explicitly still wins, and is documented under
`spark.jars.packages` in `docs/configuration.md`.
### How was this patch tested?
New `MavenUtilsSuite` tests cover the RFC 9110 format, both settings builders
setting the property, and an explicitly configured value not being overwritten.
The suite's `beforeEach`/`afterEach` now save/clear/restore `http.agent` so the
global side effect cannot leak between tests.
`./build/mvn -pl common/utils -am test` → 101 succeeded, 0 failed.
`./dev/scalastyle` → passed.
Also verified on the wire against a local HTTP server, confirming both the Spark
User-Agent and the `-Dhttp.agent` override reach the server.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brianf
force-pushed
the
spark-ivy-user-agent
branch
from
September 3, 2026 22:35
358cb95 to
0c51272
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
Set the
http.agentsystem property inMavenUtilsso that Ivy identifies itself as Spark when resolving--packages/spark.jars.packagescoordinates from remote repositories.Requests now carry:
instead of Ivy's default
Apache Ivy/2.5.3.The format follows RFC 9110 Section 10.1.5 (
product *( RWS ( product / comment ) )) — a product token carrying Spark's identity and version, plus a comment carrying the underlying resolution engine, so operator tooling that already matches on the Ivy version keeps working.Details:
http.agentis Ivy's own designed override point —AbstractURLHandler.getUserAgent()returnsSystem.getProperty("http.agent", "Apache Ivy/" + Ivy.getIvyVersion()), and bothBasicURLHandlerandHttpClientHandlerinherit it. No new Ivy API or custom handler is required.URLHandlerRegistry.getHttp()returnsHttpClientHandler.DELETE_ON_EXIT_INSTANCEwhen httpclient is on the classpath (it is — httpclient 4.5.14 ships in the distribution), and that singleton bakes the User-Agent in at class-initialization time viaHttpClients.custom().setUserAgent(...). A save/set/restore wrapper would therefore have no effect on requests and would race between concurrent resolutions.buildIvySettings()/loadIvySettings()are the insertion points: all three call paths (Artifact.scala,IsolatedClientLoader.scala,DependencyUtils.scala) go through one of them beforeresolveMavenCoordinates(), and neither touches HTTP itself. InloadIvySettings()it is the first statement, ahead ofivySettings.load(file), becauseXmlSettingsParseris the one reachable path that can triggerHttpClientHandler's static init (when the settings XML carrieshttpRequestMethod).SparkBuildInfo.spark_versionis used rather thanorg.apache.spark.SPARK_VERSION, which lives incoreand is not available fromcommon/utils.Why are the changes needed?
Repository operators rely on the User-Agent to attribute traffic and to reach the responsible party when a client misbehaves. A bare
Apache Ivy/2.5.3is un-attributable: it could be Spark, Ant, sbt, or a hand-rolled Ivy client. Operators cannot tell which tool to talk to, cannot distinguish an old Spark with poor caching behavior from a current one, and have no signal to route a conversation about excessive consumption.This matters in practice because Spark clusters without a repository-manager proxy generate a burst of resolution traffic at every job launch, so Spark is a meaningful share of this traffic on public repositories.
Does this PR introduce any user-facing change?
Yes, in two respects, both additive:
User-Agent: Apache-Spark/<version> (Apache-Ivy/<version>)instead ofApache Ivy/<version>. No resolution behavior changes.-Dhttp.agent=...explicitly continues to win — the property is only set when unset — and this is now documented underspark.jars.packagesindocs/configuration.md.Note that
http.agentis a JVM-global property affecting anyHttpURLConnection, not only Ivy. In practice the Spark-adjacent HTTP clients (Hadoop, AWS SDK, Kubernetes client) use their own stacks and set their own User-Agent, so the blast radius is small, and labelling stray JDK-level requests from a Spark driver as Spark is accurate anyway. The set-only-if-absent guard is the mitigation.How was this patch tested?
New tests in
MavenUtilsSuite:product RWS commentform, and is composed from the realSparkBuildInfo.spark_versionandIvy.getIvyVersionrather than a hardcoded literal;buildIvySettingssets the property when it is unset;loadIvySettingssets it too;The suite's
beforeEach/afterEachwere extended to save, clear, and restorehttp.agent, so the new global side effect cannot leak between tests or into other suites in the same JVM.→ 101 tests succeeded, 0 failed (
MavenUtilsSuite:tests="17" failures="0" errors="0")../dev/scalastyle→ passed.Additionally, verified on the wire rather than only by inspection, since the
HttpClientHandlerclass-init timing is the part worth confirming empirically. A local HTTP server was pointed at as the repository and the request headers logged:and with the override in place:
Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5)