Add DRA snapshot build (#91018)

* Add support for building against defined build-ids of dependent artifacts
* Introduce DraResolvePlugin and functional tests
* Declare initial dra snapshot ci job for elasticsearch

We run the DRA builds against ubuntu as other release related ci jobs have in the past. Also we only have libs2xmlutills available on our ubuntu based ci workers
This commit is contained in:
Rene Groeschke 2022-11-09 16:16:21 +01:00 committed by GitHub
parent a867ba128a
commit f880d41669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 365 additions and 57 deletions

View File

@ -0,0 +1,6 @@
---
jjbb-template: periodic-trigger-lgc.yml
vars:
- periodic-job: elastic+elasticsearch+%BRANCH%+periodic+dra-snapshot
- lgc-job: elastic+elasticsearch+%BRANCH%+intake
- cron: "H H/12 * * *"

View File

@ -0,0 +1,47 @@
---
- job:
name: elastic+elasticsearch+%BRANCH%+periodic+dra-snapshot
workspace: /dev/shm/elastic+elasticsearch+%BRANCH%+periodic+dra-snapshot
display-name: "elastic / elasticsearch # %BRANCH% - DRA snapshot"
description: "Publishing Daily Releasable Artifacts (DRAs) of Elasticsearch %BRANCH% snapshots.\n"
node: "ubuntu-18.04 || ubuntu-20.04"
builders:
- inject:
properties-file: '.ci/java-versions.properties'
properties-content: |
JAVA_HOME=$HOME/.java/$ES_BUILD_JAVA
RUNTIME_JAVA_HOME=$HOME/.java/$ES_RUNTIME_JAVA
- shell: |
#!/usr/local/bin/runbld --redirect-stderr
ES_VERSION=$(cat build-tools-internal/version.properties \
| grep elasticsearch \
| sed "s/elasticsearch//g" \
| sed "s/ //g" \
| sed "s/=//")
BEATS_BUILD_ID="$(./.ci/scripts/resolve-dra-manifest.sh beats master)"
ML_CPP_BUILD_ID="$(./.ci/scripts/resolve-dra-manifest.sh ml-cpp master)"
set -euo pipefail
set +x
VAULT_TOKEN=$(vault write -field=token auth/approle/login role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID)
export VAULT_TOKEN
$WORKSPACE/.ci/scripts/run-gradle.sh assemble -Ddra.artifacts=true -Ddra.artifacts.dependency.beats=${BEATS_BUILD_ID} -Ddra.artifacts.dependency.ml-cpp=${ML_CPP_BUILD_ID}
unset VAULT_TOKEN
set -x
$WORKSPACE/x-pack/plugin/sql/connectors/tableau/package.sh
# Artifacts should be generated
docker run --rm \
--name release-manager \
-e VAULT_ADDR \
-e VAULT_ROLE_ID \
-e VAULT_SECRET_ID \
--mount type=bind,readonly=false,src="$PWD",target=/artifacts \
docker.elastic.co/infra/release-manager:latest \
cli collect \
--project elasticsearch \
--branch "master" \
--commit "$GIT_COMMIT" \
--workflow "snapshot" \
--version "$ES_VERSION" \
--artifact-set main \
--dependency https://artifacts-snapshot.elastic.co/beats/${BEATS_BUILD_ID}/manifest-${ES_VERSION}-SNAPSHOT.json \
--dependency https://artifacts-snapshot.elastic.co/ml-cpp/${ML_CPP_BUILD_ID}/manifest-${ES_VERSION}-SNAPSHOT.json

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -e
ARTIFACT="${ARTIFACT:-$1}"
BRANCH="${BRANCH:-$2}"
curl -sS https://artifacts-snapshot.elastic.co/$ARTIFACT/latest/$BRANCH.json \
| jq -r '.build_id'

View File

@ -51,6 +51,10 @@ gradlePlugin {
id = 'elasticsearch.docs-test' id = 'elasticsearch.docs-test'
implementationClass = 'org.elasticsearch.gradle.internal.doc.DocsTestPlugin' implementationClass = 'org.elasticsearch.gradle.internal.doc.DocsTestPlugin'
} }
draArtifacts {
id = 'elasticsearch.dra-artifacts'
implementationClass = 'org.elasticsearch.gradle.internal.dra.DraResolvePlugin'
}
globalBuildInfo { globalBuildInfo {
id = 'elasticsearch.global-build-info' id = 'elasticsearch.global-build-info'
implementationClass = 'org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin' implementationClass = 'org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin'

View File

@ -39,6 +39,9 @@ class LocalRepositoryFixture extends ExternalResource {
targetFolder.mkdirs() targetFolder.mkdirs()
def jarFile = new File(targetFolder, "${module}-${version}.jar") def jarFile = new File(targetFolder, "${module}-${version}.jar")
if (clazzNames.size() == 0) {
jarFile.write("blubb")
} else {
clazzNames.each { clazzName -> clazzNames.each { clazzName ->
DynamicType.Unloaded<?> dynamicType = new ByteBuddy().subclass(Object.class) DynamicType.Unloaded<?> dynamicType = new ByteBuddy().subclass(Object.class)
.name(clazzName) .name(clazzName)
@ -51,6 +54,8 @@ class LocalRepositoryFixture extends ExternalResource {
} }
} }
}
void configureBuild(File buildFile) { void configureBuild(File buildFile) {
buildFile << """ buildFile << """
repositories { repositories {

View File

@ -0,0 +1,127 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.dra
import org.elasticsearch.gradle.fixtures.AbstractGradleFuncTest
import org.elasticsearch.gradle.fixtures.LocalRepositoryFixture
import org.elasticsearch.gradle.fixtures.WiremockFixture
import org.gradle.testkit.runner.TaskOutcome
import org.junit.ClassRule
import spock.lang.Shared
class DraResolvePluginFuncTest extends AbstractGradleFuncTest {
@Shared
@ClassRule
public LocalRepositoryFixture repository = new LocalRepositoryFixture()
def setup() {
configurationCacheCompatible = false
buildFile << """
plugins {
id 'elasticsearch.dra-artifacts'
}
repositories.all {
// for supporting http testing repos here
allowInsecureProtocol = true
}
"""
}
def "provides flag indicating dra usage"() {
setup:
repository.generateJar("org.acme", "ml-cpp", "8.6.0-SNAPSHOT")
buildFile << """
if(useDra == false) {
repositories {
maven {
name = "local-test"
url = "${repository.getRepoDir().toURI()}"
metadataSources {
artifact()
}
}
}
}
"""
buildFile << """
configurations {
someConfig
}
dependencies {
someConfig "org.acme:ml-cpp:8.6.0-SNAPSHOT"
}
tasks.register('resolveArtifacts') {
doLast {
configurations.someConfig.files.each { println it }
}
}
"""
when:
def result = gradleRunner("resolveArtifacts").build()
then:
result.task(":resolveArtifacts").outcome == TaskOutcome.SUCCESS
when:
result = gradleRunner("resolveArtifacts", "-Ddra.artifacts=true").buildAndFail()
then:
result.task(":resolveArtifacts").outcome == TaskOutcome.FAILED
result.output.contains("Cannot resolve external dependency org.acme:ml-cpp:8.6.0-SNAPSHOT because no repositories are defined.")
}
def "configures repositories to resolve #draKey like dra #artifactType artifacts"() {
setup:
repository.generateJar("some.group", "bar", "1.0.0")
repository.generateJar("some.group", "baz", "1.0.0-SNAPSHOT")
repository.configureBuild(buildFile)
buildFile << """
configurations {
someConfig
}
dependencies {
someConfig "some.group:bar:1.0.0"
someConfig "some.group:baz:1.0.0-SNAPSHOT"
someConfig "org.acme:$draArtifact:$draVersion:deps@zip"
}
tasks.register('resolveArtifacts') {
doLast {
configurations.someConfig.files.each { println it }
}
}
"""
when:
def result = WiremockFixture.withWireMock(expectedRequest, "content".getBytes('UTF-8')) { server ->
gradleRunner("resolveArtifacts",
'-Ddra.artifacts=true',
"-Ddra.artifacts.dependency.${draKey}=$buildId",
"-Ddra.artifacts.url.repo.${artifactType}.prefix=${server.baseUrl()}").build()
}
then:
result.task(":resolveArtifacts").outcome == TaskOutcome.SUCCESS
where:
artifactType | buildId | draVersion | draKey | draArtifact | expectedRequest
"snapshot" | '8.6.0-f633b1d7' | "8.6.0-SNAPSHOT" | "ml-cpp" | "ml-cpp" | "/$draKey/${buildId}/downloads/$draArtifact/${draArtifact}-${draVersion}-deps.zip"
"release" | '8.6.0-f633b1d7' | "8.6.0" | "ml-cpp" | "ml-cpp" | "/$draKey/${buildId}/downloads/$draArtifact/${draArtifact}-${draVersion}-deps.zip"
"snapshot" | '8.6.0-f633b1d7' | "8.6.0-SNAPSHOT" | "beats" | "metricbeat" | "/$draKey/${buildId}/downloads/$draKey/$draArtifact/${draArtifact}-${draVersion}-deps.zip"
"release" | '8.6.0-f633b1d7' | "8.6.0" | "beats" | "metricbeat" | "/$draKey/${buildId}/downloads/$draKey/$draArtifact/${draArtifact}-${draVersion}-deps.zip"
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle.internal.dra;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.initialization.layout.BuildLayout;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import static java.util.Map.Entry;
public class DraResolvePlugin implements Plugin<Project> {
public static final String USE_DRA_ARTIFACTS_FLAG = "dra.artifacts";
public static final String DRA_ARTIFACTS_DEPENDENCY_PREFIX = "dra.artifacts.dependency";
private final ProviderFactory providerFactory;
private BuildLayout buildLayout;
private final Provider<String> snapshotRepositoryPrefix;
private final Provider<String> releaseRepositoryPrefix;
@Inject
public DraResolvePlugin(ProviderFactory providerFactory, BuildLayout buildLayout) {
this.providerFactory = providerFactory;
this.buildLayout = buildLayout;
this.snapshotRepositoryPrefix = providerFactory.systemProperty("dra.artifacts.url.repo.snapshot.prefix");
this.releaseRepositoryPrefix = providerFactory.systemProperty("dra.artifacts.url.repo.release.prefix");
}
@Override
public void apply(Project project) {
boolean useDra = providerFactory.systemProperty(USE_DRA_ARTIFACTS_FLAG).map(Boolean::parseBoolean).getOrElse(false);
project.getExtensions().getExtraProperties().set("useDra", useDra);
if (useDra) {
resolveBuildIdProperties().get().forEach((key, buildId) -> {
configureDraRepository(
project,
"dra-snapshot-artifacts-" + key,
key,
buildId,
snapshotRepositoryPrefix.orElse("https://artifacts-snapshot.elastic.co/"),
".*SNAPSHOT"
);
configureDraRepository(
project,
"dra-release-artifacts-" + key,
key,
buildId,
releaseRepositoryPrefix.orElse("https://artifacts.elastic.co/"),
"^(.(?!SNAPSHOT))*$"
);
});
}
}
private void configureDraRepository(
Project project,
String repositoryName,
String draKey,
String buildId,
Provider<String> repoPrefix,
String includeVersionRegex
) {
project.getRepositories().ivy(repo -> {
repo.setName(repositoryName);
repo.setUrl(repoPrefix.get());
repo.patternLayout(patternLayout -> {
patternLayout.artifact(
String.format("/%s/%s/downloads/%s/[module]-[revision]-[classifier].[ext]", draKey, buildId, draKey)
);
patternLayout.artifact(
String.format("/%s/%s/downloads/%s/[module]/[module]-[revision]-[classifier].[ext]", draKey, buildId, draKey)
);
});
repo.metadataSources(metadataSources -> metadataSources.artifact());
repo.content(repositoryContentDescriptor -> repositoryContentDescriptor.includeVersionByRegex(".*", ".*", includeVersionRegex));
});
}
private Provider<Map<String, String>> resolveBuildIdProperties() {
return providerFactory.systemPropertiesPrefixedBy(DRA_ARTIFACTS_DEPENDENCY_PREFIX)
.map(
stringStringMap -> stringStringMap.entrySet()
.stream()
.collect(
Collectors.toMap(entry -> entry.getKey().substring(DRA_ARTIFACTS_DEPENDENCY_PREFIX.length() + 1), Entry::getValue)
)
);
}
}

View File

@ -8,6 +8,7 @@ import org.elasticsearch.gradle.internal.docker.DockerSupportPlugin
import org.elasticsearch.gradle.internal.docker.DockerSupportService import org.elasticsearch.gradle.internal.docker.DockerSupportService
import org.elasticsearch.gradle.internal.docker.ShellRetry import org.elasticsearch.gradle.internal.docker.ShellRetry
import org.elasticsearch.gradle.internal.docker.TransformLog4jConfigFilter import org.elasticsearch.gradle.internal.docker.TransformLog4jConfigFilter
import org.elasticsearch.gradle.internal.dra.DraResolvePlugin
import org.elasticsearch.gradle.internal.info.BuildParams import org.elasticsearch.gradle.internal.info.BuildParams
import org.elasticsearch.gradle.util.GradleUtils import org.elasticsearch.gradle.util.GradleUtils
@ -17,9 +18,10 @@ import java.time.temporal.ChronoUnit
apply plugin: 'elasticsearch.internal-yaml-rest-test' apply plugin: 'elasticsearch.internal-yaml-rest-test'
apply plugin: 'elasticsearch.test.fixtures' apply plugin: 'elasticsearch.test.fixtures'
apply plugin: 'elasticsearch.internal-distribution-download' apply plugin: 'elasticsearch.internal-distribution-download'
apply plugin: 'elasticsearch.dra-artifacts'
String buildId = providers.systemProperty('build.id').getOrNull() String buildId = providers.systemProperty('build.id').getOrNull()
boolean useLocalArtifacts = buildId != null && buildId.isBlank() == false boolean useLocalArtifacts = buildId != null && buildId.isBlank() == false && useDra == false
repositories { repositories {
// Define a repository that allows Gradle to fetch a resource from GitHub. This // Define a repository that allows Gradle to fetch a resource from GitHub. This
@ -35,7 +37,10 @@ repositories {
metadataSources { artifact() } metadataSources { artifact() }
content { includeGroup 'krallin' } content { includeGroup 'krallin' }
} }
}
if(useDra == false) {
repositories {
// Cloud builds bundle some beats // Cloud builds bundle some beats
ivy { ivy {
name = 'beats' name = 'beats'
@ -60,6 +65,7 @@ repositories {
content { includeGroup 'beats' } content { includeGroup 'beats' }
} }
} }
}
testFixtures.useFixture() testFixtures.useFixture()

View File

@ -1,8 +1,10 @@
import org.elasticsearch.gradle.VersionProperties import org.elasticsearch.gradle.VersionProperties
import org.elasticsearch.gradle.internal.dra.DraResolvePlugin
apply plugin: 'elasticsearch.internal-es-plugin' apply plugin: 'elasticsearch.internal-es-plugin'
apply plugin: 'elasticsearch.internal-cluster-test' apply plugin: 'elasticsearch.internal-cluster-test'
apply plugin: 'elasticsearch.internal-test-artifact' apply plugin: 'elasticsearch.internal-test-artifact'
apply plugin: 'elasticsearch.dra-artifacts'
esplugin { esplugin {
name 'x-pack-ml' name 'x-pack-ml'
@ -13,7 +15,7 @@ esplugin {
} }
def localRepo = providers.systemProperty('build.ml_cpp.repo').orNull def localRepo = providers.systemProperty('build.ml_cpp.repo').orNull
if (useDra == false) {
repositories { repositories {
exclusiveContent { exclusiveContent {
filter { filter {
@ -48,6 +50,8 @@ repositories {
} }
} }
}
configurations { configurations {
nativeBundle { nativeBundle {
resolutionStrategy.cacheChangingModulesFor 2, 'hours' resolutionStrategy.cacheChangingModulesFor 2, 'hours'