-
Notifications
You must be signed in to change notification settings - Fork 25k
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
Add gradle plugin for downloading jdk #41461
Conversation
We currently download 3 variants of the same version of the jdk for bundling into the distributions. Additionally, the vagrant images do their own downloading. This commit moves the jdk downloading into a utility gradle plugin. This will be used in a future PR by the packaging tests. The new plugin exposes a "usesJdk" method on tasks. Once the jdk version and platform are set for a task, a "jdkHome" property exists which may be used to get the extracted jdk directory at runtime.
Pinging @elastic/es-core-infra |
if (ALLOWED_PLATFORMS.contains(platform) == false) { | ||
throw new IllegalArgumentException("platform must be one of " + ALLOWED_PLATFORMS); | ||
} | ||
ExtraPropertiesExtension extraProperties = task.getExtensions().findByType(ExtraPropertiesExtension.class); |
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.
nit: could be moved up so it's repeated on line 60
buildSrc/src/main/java/org/elasticsearch/gradle/JdkDownloadPlugin.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
// ensure a root level jdk download task exists | ||
setupRootJdkDownload(project.getRootProject(), platform, version); |
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.
Could we set up a single task to download all as we do for test clusters rather than one for each version ? Having fewer tasks will make configuration faster and I find it easier to follow what's going on.
It could also be a lazily created task that's always set up and then have the tasks that require it depend on it
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 might be missing it, but is task
made dependent on this ?
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 do not think we should have a single configuration for all jdks we download. That means resolving the configuration triggers download of all of them. Additionally, the way this works is to be able to resolve a configuration to a single file.
is task made dependent on this ?
The root project does the extraction, and makes the extracted dir available as an artifact of the root project. The tasks in subprojects add a normal dependency on that "artifact", through a separate configuration in the subproject, and the task then depends on that local subproject configuration.
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 wasn't referring to having a single configuration, we actually need those to be separate to be able to have different versions, but we can extract all in the same task, having multiple tasks for it doesn't buy us anything.
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.
Having a single task would mean the task depends on all those configurations, thus still resolving all the artifacts at the same time. We need a 1-1 mapping to ensure one extraction is done.
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.
Is that all that bad? The configurations are cached, and the task has up to date checks . For most things this all the JDKs will be needed anyway due to the number of tests that depend on the JDK.
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.
For most things this all the JDKs will be needed anyway
I don't think that is true. When I run a packaging test for a single distro, I need one jdk, not many, and certainly not the ones from non linux.
ivyRepo.setName(repoName); | ||
ivyRepo.setUrl("https://download.java.net"); | ||
ivyRepo.patternLayout(layout -> { | ||
layout.artifact("java/GA/jdk" + jdkMajor + "/" + jdkBuild + "/GPL/openjdk-[revision]_[module]-x64_bin.[ext]"); |
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.
we could add something like:
spec.content(c-> c.includeGroup("org.elasticsearch.jdk-downloader"));
And use "org.elasticsearch.jdk-downloader" as a group when downloading the dependency.
It's a good practice for repositories confirmed by plugins.
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.
Sorry I don't follow. The group is completely arbitrary and internal since this is a fake ivy repo.
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.
But the repository is not, so all dependencies could potentially be checked against it.
I just suggested org.elasticsearch.jdk-downloader
to make it more specific, or make it "ours" since it's not really used in the pattern layout. It would work the same way with "jdk".
buildSrc/src/main/java/org/elasticsearch/gradle/JdkDownloadPlugin.java
Outdated
Show resolved
Hide resolved
@atorok I wasn't happy with usesJdk on every task, so I rethought this and have pushed an alternative approach. The new code has a |
Note that I need to update the tests with the new approach, but wanted to get this up here for you to look at if you have time today. |
@elasticmachine run elasticsearch-ci/1 |
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.
Some misc comments, otherwise this looks great.
import java.util.List; | ||
import java.util.regex.Pattern; | ||
|
||
public class Jdk implements Buildable { |
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.
To be more explicit we could also implement Named
here.
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'm happy to add this. Can you explain what benefits it would give us here?
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.
It's just a bit more explicit (getName() will no be an @Override
method) and I believe I recall some Gradle APIs that handle a Named
explicitly.
public class Jdk implements Buildable { | ||
|
||
static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)(\\.\\d+\\.\\d+)?\\+(\\d+)"); | ||
private static final List<String> ALLOWED_PLATFORMS = Collections.unmodifiableList(Arrays.asList("linux", "windows", "darwin")); |
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 not use an enum then?
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.
We have something similar: org.elasticsearch.gradle.OS
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 an enum has any advantages here. In fact, it would require more unnecessary code to convert between the capitalized enum entities and the lowercase platform names we need here.
import java.io.File; | ||
import java.util.function.Supplier; | ||
|
||
public class JdkDownloadExtension { |
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.
This looks to be unused. Seems we went the domain objection container route instead.
return configuration; | ||
} | ||
|
||
public FileCollection getFiles() { |
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'd rename this getFileCollection()
. as FileCollection
itself already has a method called getFiles()
which returns a Set<File>
.
if (rootProject.getRepositories().findByName(repoName) == null) { | ||
rootProject.getRepositories().ivy(ivyRepo -> { | ||
ivyRepo.setName(repoName); | ||
ivyRepo.setUrl("https://download.java.net"); |
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 don't we use jvm-catalog.elastic.co instead? It has a much simpler URL pattern that would allow us to avoid having to create a repo per version as well. If we use a number of versions we are going to make a lot of HEAD requests that return a 404 with this approach.
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.
This would add a considerable load to our infrastructure. We may want to still consider it, but I think it should be separate from this PR, which is just to consolidate existing code, which already uses this url.
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 still have a bit of a concern with this approach of registering so many repositories. Is there anyway perhaps that we could construct the dependency notation so that we can avoid creating a repo per version? I'm not sure this is possible, or if what I see here even works. For example, the download link I see here includes the artifact hash in the download URL.
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 is possible here. The reason we embed this information in the pattern is we only have so many elements we can substitute via the maven/ivy coordinates.
The hash included in the download link is something that changed very recently. There are 2 versions registered here because versions before 12.0.1 still use the old pattern. I could definitely decide which one to register based on the version, but in this PR I'm only trying to move the logic we already have in the build for jdk downloading. We can certainly look at improving this either through reducing repos or moving to using the jvm catalog, but I think these should be discussed separately as followups to this PR.
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.
Since we're only registering all these repos to the root project it's probably ok, as it won't affect dependency solution of subprojects. Let's make sure we create an issue to follow up here. I assume if the recent version download links have changed this is going to be a problem for fetching newer JDK versions, no?
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.
We register 2 ivy repositories, one with the older pattern, and one with the hash. Are you sure you are looking at the latest commit?
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 definitely was not. It seems GitHub was filtering out the latest commits for me. Thanks GH!
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.
Given that we know the version when registering the repo can we be smart about it and avoid registering both for all versions?
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.
Or simpler yet, if the artifact version notation includes a hash, use the hash repo, otherwise use the legacy one.
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.
Sure, I will do that in a followup.
int rootNdx = platform.equals("darwin") ? 2 : 1; | ||
Action<CopySpec> removeRootDir = copy -> { | ||
// remove extra unnecessary directory levels | ||
copy.eachFile((FileCopyDetails details) -> { |
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.
Is this cast to FileCopyDetails
necessary?
|
||
String fakeJdkVersion = Objects.requireNonNull(System.getProperty('tests.jdk_version')) | ||
jdks { | ||
linux_jdk { |
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.
nit: could we remove _jdk
from the name to avoid redundancy ? And keep that as the naming format in general.
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.
This is just an example in a test, but I removed it.
@rjernst ++ I like the approach very much ! You might be able to add some additional magic with |
Thanks for the idea! While I didn't use |
@atorok @mark-vieira I believe I have addressed all your feedback. |
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.
LGTM
We might still need an asType(File)
to be able to pass a JDK to an API that expects a File, but we can add that whenever we need it.
Yeah, I'm on the fence on using |
* Update TLS ciphers and protocols for JDK 11 (elastic#41385) This commit updates the default ciphers and TLS protocols that are used after the minimum supported JDK is JDK 11. The conditionals around TLSv1.3 and 256-bit cipher support have been removed. JDK 11 no longer requires an unlimited JCE policy file for 256 bit cipher support and TLSv1.3 is supported in JDK 11+. New cipher support has been introduced in the newer JDK versions as well. The ciphers are ordered with PFS ciphers being most preferred, then AEAD ciphers, and finally those with mainstream hardware support. * Fixes for TLSv1.3 on JDK11 * fix for JDK-8212885
…tic#41893) The class was called PatternSeenEventExcpectation. This commit is a straight class rename to correct the spelling.
@elasticmachine run elasticsearch-ci/1 |
@elasticmachine run elasticsearch-ci/packaging |
@elasticmachine run elasticsearch-ci/1 |
We currently download 3 variants of the same version of the jdk for bundling into the distributions. Additionally, the vagrant images do their own downloading. This commit moves the jdk downloading into a utility gradle plugin. This will be used in a future PR by the packaging tests. The new plugin exposes a "jdks" project extension which allows creating named jdks. Once the jdk version and platform are set for a named jdk, the jdk object may be used as a lazy String for the jdk home path, or a file collection for copying.
We currently download 3 variants of the same version of the jdk for bundling into the distributions. Additionally, the vagrant images do their own downloading. This commit moves the jdk downloading into a utility gradle plugin. This will be used in a future PR by the packaging tests. The new plugin exposes a "jdks" project extension which allows creating named jdks. Once the jdk version and platform are set for a named jdk, the jdk object may be used as a lazy String for the jdk home path, or a file collection for copying.
We currently download 3 variants of the same version of the jdk for
bundling into the distributions. Additionally, the vagrant images do
their own downloading. This commit moves the jdk downloading into a
utility gradle plugin. This will be used in a future PR by the packaging
tests.
The new plugin exposes a "usesJdk" method on tasks. Once the jdk version
and platform are set for a task, a "jdkHome" property exists which may
be used to get the extracted jdk directory at runtime.