brianf opened a new pull request, #58508:
URL: https://github.com/apache/spark/pull/58508

   ### What changes were proposed in this pull request?
   
   Set the `http.agent` system property in `MavenUtils` so that Ivy identifies 
itself as Spark when resolving `--packages` / `spark.jars.packages` coordinates 
from remote repositories.
   
   Requests now carry:
   
   ```
   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 ) )`) — 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.agent` is Ivy's own designed override point — 
`AbstractURLHandler.getUserAgent()` returns `System.getProperty("http.agent", 
"Apache Ivy/" + Ivy.getIvyVersion())`, and both `BasicURLHandler` and 
`HttpClientHandler` inherit it. No new Ivy API or custom handler is required.
   - The property is set **once, if absent**, rather than set-and-restored 
around the download. `URLHandlerRegistry.getHttp()` returns 
`HttpClientHandler.DELETE_ON_EXIT_INSTANCE` when 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 via 
`HttpClients.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 before 
`resolveMavenCoordinates()`, and neither touches HTTP itself. In 
`loadIvySettings()` it is the first statement, ahead of 
`ivySettings.load(file)`, because `XmlSettingsParser` is the one reachable path 
that can trigger `HttpClientHandler`'s static init (when the settings XML 
carries `httpRequestMethod`).
   - `SparkBuildInfo.spark_version` is used rather than 
`org.apache.spark.SPARK_VERSION`, which lives in `core` and is not available 
from `common/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.3` 
is 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:
   
   1. Requests Spark makes to remote artifact repositories during dependency 
resolution now carry `User-Agent: Apache-Spark/<version> 
(Apache-Ivy/<version>)` instead of `Apache Ivy/<version>`. No resolution 
behavior changes.
   2. Setting `-Dhttp.agent=...` explicitly continues to win — the property is 
only set when unset — and this is now documented under `spark.jars.packages` in 
`docs/configuration.md`.
   
   Note that `http.agent` is a JVM-global property affecting any 
`HttpURLConnection`, 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`:
   
   - the User-Agent matches the RFC 9110 `product RWS comment` form, and is 
composed from the real `SparkBuildInfo.spark_version` and `Ivy.getIvyVersion` 
rather than a hardcoded literal;
   - `buildIvySettings` sets the property when it is unset;
   - `loadIvySettings` sets it too;
   - an explicitly configured value is not overwritten.
   
   The suite's `beforeEach`/`afterEach` were extended to save, clear, and 
restore `http.agent`, so the new global side effect cannot leak between tests 
or into other suites in the same JVM.
   
   ```
   ./build/mvn -pl common/utils -am test
   ```
   → 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 
`HttpClientHandler` class-init timing is the part worth confirming empirically. 
A local HTTP server was pointed at as the repository and the request headers 
logged:
   
   ```
   CONFIGURED_AGENT=Apache-Spark/5.0.0-SNAPSHOT (Apache-Ivy/2.5.3)
   OBSERVED_USER_AGENT=Apache-Spark/5.0.0-SNAPSHOT (Apache-Ivy/2.5.3)
   ```
   
   and with the override in place:
   
   ```
   CONFIGURED_AGENT=AcmeCorp/1.0
   OBSERVED_USER_AGENT=AcmeCorp/1.0
   ```
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Claude Opus 5)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to