@@ -154,9 +154,11 @@ def firestoreDb = project.findProperty('firestoreDb') ?: 'firestoredb'
154154
155155def dockerImageRoot = project. findProperty(' dockerImageRoot' ) ?: " us.gcr.io/${ gcpProject.replaceAll(':', '/')} /java-postcommit-it"
156156def dockerJavaImageContainer = " ${ dockerImageRoot} /java"
157+ def distrolessDockerJavaImageContainer = " ${ dockerImageRoot} /java-distroless"
157158def dockerPythonImageContainer = " ${ dockerImageRoot} /python"
158159def dockerTag = new Date (). format(' yyyyMMddHHmmss' )
159160ext. dockerJavaImageName = " ${ dockerJavaImageContainer} :${ dockerTag} "
161+ ext. distrolessDockerJavaImageName = " ${ distrolessDockerJavaImageContainer} :${ dockerTag} "
160162ext. dockerPythonImageName = " ${ dockerPythonImageContainer} :${ dockerTag} "
161163
162164def legacyPipelineOptions = [
@@ -174,12 +176,22 @@ def runnerV2PipelineOptions = [
174176 " --project=${ gcpProject} " ,
175177 " --region=${ gcpRegion} " ,
176178 " --tempRoot=${ dataflowValidatesTempRoot} " ,
177- " --sdkContainerImage=${ dockerJavaImageContainer } : ${ dockerTag } " ,
179+ " --sdkContainerImage=${ dockerJavaImageName } " ,
178180 " --experiments=use_unified_worker,use_runner_v2" ,
179181 " --firestoreDb=${ firestoreDb} " ,
180182 " --experiments=enable_lineage"
181183]
182184
185+ def runnerV2PipelineOptionsDistroless = [
186+ " --runner=TestDataflowRunner" ,
187+ " --project=${ gcpProject} " ,
188+ " --region=${ gcpRegion} " ,
189+ " --tempRoot=${ dataflowValidatesTempRoot} " ,
190+ " --sdkContainerImage=${ distrolessDockerJavaImageName} " ,
191+ " --experiments=use_unified_worker,use_runner_v2" ,
192+ " --firestoreDb=${ firestoreDb} " ,
193+ ]
194+
183195def commonLegacyExcludeCategories = [
184196 // Should be run only in a properly configured SDK harness environment
185197 ' org.apache.beam.sdk.testing.UsesSdkHarnessEnvironment' ,
@@ -279,69 +291,6 @@ def createRunnerV2ValidatesRunnerTest = { Map args ->
279291 }
280292}
281293
282- tasks. register(' examplesJavaRunnerV2IntegrationTestDistroless' , Test . class) {
283- group = " verification"
284- dependsOn ' buildAndPushDistrolessContainerImage'
285- def javaVer = project. findProperty(' testJavaVersion' )
286- def repository = " us.gcr.io/apache-beam-testing/${ System.getenv('USER')} "
287- def tag = project. findProperty(' dockerTag' )
288- def imageURL = " ${ repository} /beam_${ javaVer} _sdk_distroless:${ tag} "
289- def pipelineOptions = [
290- " --runner=TestDataflowRunner" ,
291- " --project=${ gcpProject} " ,
292- " --region=${ gcpRegion} " ,
293- " --tempRoot=${ dataflowValidatesTempRoot} " ,
294- " --sdkContainerImage=${ imageURL} " ,
295- " --experiments=use_unified_worker,use_runner_v2" ,
296- " --firestoreDb=${ firestoreDb} " ,
297- ]
298- systemProperty " beamTestPipelineOptions" , JsonOutput . toJson(pipelineOptions)
299-
300- include ' **/*IT.class'
301-
302- maxParallelForks 4
303- classpath = configurations. examplesJavaIntegrationTest
304- testClassesDirs = files(project(" :examples:java" ). sourceSets. test. output. classesDirs)
305- useJUnit { }
306- }
307-
308- tasks. register(' buildAndPushDistrolessContainerImage' , Task . class) {
309- // Only Java 17 and 21 are supported.
310- // See https://github.com/GoogleContainerTools/distroless/tree/main/java#image-contents.
311- def allowed = [" java17" , " java21" ]
312- doLast {
313- def javaVer = project. findProperty(' testJavaVersion' )
314- if (! allowed. contains(javaVer)) {
315- throw new GradleException (" testJavaVersion must be one of ${ allowed} , got: ${ javaVer} " )
316- }
317- if (! project. hasProperty(' dockerTag' )) {
318- throw new GradleException (" dockerTag is missing but required" )
319- }
320- def repository = " us.gcr.io/apache-beam-testing/${ System.getenv('USER')} "
321- def tag = project. findProperty(' dockerTag' )
322- def imageURL = " ${ repository} /beam_${ javaVer} _sdk_distroless:${ tag} "
323- exec {
324- executable ' docker'
325- workingDir rootDir
326- args = [
327- ' buildx' ,
328- ' build' ,
329- ' -t' ,
330- imageURL,
331- ' -f' ,
332- ' sdks/java/container/Dockerfile-distroless' ,
333- " --build-arg=BEAM_BASE=gcr.io/apache-beam-testing/beam-sdk/beam_${ javaVer} _sdk" ,
334- " --build-arg=DISTROLESS_BASE=gcr.io/distroless/${ javaVer} -debian12" ,
335- ' .'
336- ]
337- }
338- exec {
339- executable ' docker'
340- args = [' push' , imageURL]
341- }
342- }
343- }
344-
345294// Push docker images to a container registry for use within tests.
346295// NB: Tasks which consume docker images from the registry should depend on this
347296// task directly ('dependsOn buildAndPushDockerJavaContainer'). This ensures the correct
@@ -383,6 +332,47 @@ def cleanUpDockerJavaImages = tasks.register("cleanUpDockerJavaImages") {
383332 }
384333}
385334
335+ // Push docker images to a container registry for use within tests.
336+ // NB: Tasks which consume docker images from the registry should depend on this
337+ // task directly ('dependsOn buildAndPushDistrolessDockerJavaContainer'). This ensures the correct
338+ // task ordering such that the registry doesn't get cleaned up prior to task completion.
339+ def buildAndPushDistrolessDockerJavaContainer = tasks. register(" buildAndPushDistrolessDockerJavaContainer" ) {
340+ def javaVer = getSupportedJavaVersion()
341+ if (project. hasProperty(' testJavaVersion' )) {
342+ javaVer = " java${ project.getProperty('testJavaVersion')} "
343+ }
344+ dependsOn " :sdks:java:container:distroless:${ javaVer} :docker"
345+ def defaultDockerImageName = containerImageName(
346+ name : " ${ project.docker_image_default_repo_prefix}${ javaVer} _sdk_distroless" ,
347+ root : " apache" ,
348+ tag : project. sdk_version)
349+ doLast {
350+ exec {
351+ commandLine " docker" , " tag" , " ${ defaultDockerImageName} " , " ${ distrolessDockerJavaImageName} "
352+ }
353+ exec {
354+ commandLine " gcloud" , " docker" , " --" , " push" , " ${ distrolessDockerJavaImageName} "
355+ }
356+ }
357+ }
358+
359+ // Clean up built distroless Java images
360+ def cleanUpDistrolessDockerJavaImages = tasks. register(" cleanUpDistrolessDockerJavaImages" ) {
361+ doLast {
362+ exec {
363+ commandLine " docker" , " rmi" , " --force" , " ${ distrolessDockerJavaImageName} "
364+ }
365+ exec {
366+ ignoreExitValue true
367+ commandLine " gcloud" , " --quiet" , " container" , " images" , " untag" , " ${ distrolessDockerJavaImageName} "
368+ }
369+ exec {
370+ ignoreExitValue true
371+ commandLine " ./scripts/cleanup_untagged_gcr_images.sh" , " ${ distrolessDockerJavaImageContainer} "
372+ }
373+ }
374+ }
375+
386376// Push docker images to a container registry for use within tests.
387377// NB: Tasks which consume docker images from the registry should depend on this
388378// task directly ('dependsOn buildAndPushDockerPythonContainer'). This ensures the correct
@@ -432,6 +422,9 @@ afterEvaluate {
432422 if (t. dependsOn. contains(buildAndPushDockerJavaContainer) && ! t. name. equalsIgnoreCase(' printRunnerV2PipelineOptions' )) {
433423 t. finalizedBy cleanUpDockerJavaImages
434424 }
425+ if (t. dependsOn. contains(buildAndPushDistrolessDockerJavaContainer)) {
426+ t. finalizedBy cleanUpDistrolessDockerJavaImages
427+ }
435428 if (t. dependsOn. contains(buildAndPushDockerPythonContainer)) {
436429 t. finalizedBy cleanUpDockerPythonImages
437430 }
@@ -505,15 +498,15 @@ createCrossLanguageValidatesRunnerTask(
505498 " --runner=TestDataflowRunner" ,
506499 " --project=${ gcpProject} " ,
507500 " --region=${ gcpRegion} " ,
508- " --sdk_harness_container_image_overrides=.*java.*,${ dockerJavaImageContainer } : ${ dockerTag } " ,
501+ " --sdk_harness_container_image_overrides=.*java.*,${ dockerJavaImageName } " ,
509502 ],
510503 javaPipelineOptions : [
511504 " --runner=TestDataflowRunner" ,
512505 " --project=${ gcpProject} " ,
513506 " --region=${ gcpRegion} " ,
514507 " --tempRoot=${ dataflowValidatesTempRoot} " ,
515- " --sdkContainerImage=${ dockerJavaImageContainer } : ${ dockerTag } " ,
516- " --sdkHarnessContainerImageOverrides=.*python.*,${ dockerPythonImageContainer } : ${ dockerTag } " ,
508+ " --sdkContainerImage=${ dockerJavaImageName } " ,
509+ " --sdkHarnessContainerImageOverrides=.*python.*,${ dockerPythonImageName } " ,
517510 ],
518511 pytestOptions : [
519512 " --capture=no" ,
@@ -527,7 +520,7 @@ createCrossLanguageValidatesRunnerTask(
527520 " --dataflow_project ${ gcpProject} " ,
528521 " --region ${ gcpRegion} " ,
529522 " --tests \" ./test/integration/xlang ./test/integration/io/xlang/...\" " ,
530- " --sdk_overrides \" .*java.*,${ dockerJavaImageContainer } : ${ dockerTag } \" " ,
523+ " --sdk_overrides \" .*java.*,${ dockerJavaImageName } \" " ,
531524 ],
532525)
533526
@@ -750,6 +743,36 @@ task examplesJavaRunnerV2IntegrationTest(type: Test) {
750743 useJUnit { }
751744}
752745
746+ task examplesJavaDistrolessRunnerV2PreCommit (type : Test ) {
747+ group = " Verification"
748+ dependsOn buildAndPushDistrolessDockerJavaContainer
749+ systemProperty " beamTestPipelineOptions" , JsonOutput . toJson(runnerV2PipelineOptionsDistroless)
750+ include ' **/WordCountIT.class'
751+ include ' **/WindowedWordCountIT.class'
752+
753+ maxParallelForks 4
754+ classpath = configurations. examplesJavaIntegrationTest
755+ testClassesDirs = files(project(" :examples:java" ). sourceSets. test. output. classesDirs)
756+ useJUnit { }
757+ }
758+
759+ task examplesJavaRunnerV2IntegrationTestDistroless (type : Test ) {
760+ group = " Verification"
761+ dependsOn buildAndPushDistrolessDockerJavaContainer
762+ if (project. hasProperty(" testJavaVersion" )) {
763+ dependsOn " :sdks:java:testing:test-utils:verifyJavaVersion${ project.property("testJavaVersion")} "
764+ }
765+
766+ systemProperty " beamTestPipelineOptions" , JsonOutput . toJson(runnerV2PipelineOptionsDistroless)
767+
768+ include ' **/*IT.class'
769+
770+ maxParallelForks 4
771+ classpath = configurations. examplesJavaIntegrationTest
772+ testClassesDirs = files(project(" :examples:java" ). sourceSets. test. output. classesDirs)
773+ useJUnit { }
774+ }
775+
753776task coreSDKJavaLegacyWorkerIntegrationTest (type : Test ) {
754777 group = " Verification"
755778 dependsOn " :runners:google-cloud-dataflow-java:worker:shadowJar"
@@ -838,36 +861,3 @@ task GCSUpload(type: JavaExec) {
838861 args " --stagingLocation=${ dataflowUploadTemp} /staging" ,
839862 " --filesToStage=${ testFilesToStage} "
840863}
841-
842- def buildAndPushDistrolessDockerJavaContainer = tasks. register(" buildAndPushDistrolessDockerJavaContainer" ) {
843- def javaVer = getSupportedJavaVersion()
844- if (project. hasProperty(' testJavaVersion' )) {
845- javaVer = " java${ project.getProperty('testJavaVersion')} "
846- }
847- dependsOn " :sdks:java:container:distroless:${ javaVer} :docker"
848- def defaultDockerImageName = containerImageName(
849- name : " ${ project.docker_image_default_repo_prefix}${ javaVer} _sdk_distroless" ,
850- root : " apache" ,
851- tag : project. sdk_version)
852- doLast {
853- exec {
854- commandLine " docker" , " tag" , " ${ defaultDockerImageName} " , " ${ dockerJavaImageName} "
855- }
856- exec {
857- commandLine " gcloud" , " docker" , " --" , " push" , " ${ dockerJavaImageName} "
858- }
859- }
860- }
861-
862- task examplesJavaDistrolessRunnerV2PreCommit (type : Test ) {
863- group = " Verification"
864- dependsOn buildAndPushDistrolessDockerJavaContainer
865- systemProperty " beamTestPipelineOptions" , JsonOutput . toJson(runnerV2PipelineOptions)
866- include ' **/WordCountIT.class'
867- include ' **/WindowedWordCountIT.class'
868-
869- maxParallelForks 4
870- classpath = configurations. examplesJavaIntegrationTest
871- testClassesDirs = files(project(" :examples:java" ). sourceSets. test. output. classesDirs)
872- useJUnit { }
873- }
0 commit comments