corda/docker/build.gradle

262 lines
8.6 KiB
Groovy

evaluationDependsOn(":node:capsule")
import com.github.dockerjava.api.model.Identifier
import net.corda.build.docker.DockerImage
import net.corda.build.docker.DockerUtils
import net.corda.build.docker.ObjectInputStreamWithCustomClassLoader
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.stream.Collectors
import java.util.stream.Stream
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'application'
// We need to set mainClassName before applying the shadow plugin.
mainClassName = 'net.corda.core.ConfigExporterMain'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies{
implementation project(':node')
implementation project(':node-api')
implementation project(':common-configuration-parsing')
implementation project(':common-validation')
implementation "com.typesafe:config:$typesafe_config_version"
}
shadowJar {
baseName = 'config-exporter'
classifier = null
version = null
zip64 true
exclude '**/Log4j2Plugins.dat'
}
enum ImageVariant {
UBUNTU_ZULU("Dockerfile", "17", "zulu-openjdk"),
AL_CORRETTO("DockerfileAL", "17", "amazonlinux2"),
OFFICIAL(UBUNTU_ZULU)
String dockerFile
String javaVersion
String baseImageFullName
ImageVariant(ImageVariant other) {
this.dockerFile = other.dockerFile
this.javaVersion = other.javaVersion
this.baseImageFullName = other.baseImageFullName
}
ImageVariant(String dockerFile, String javaVersion, String baseImageFullName) {
this.dockerFile = dockerFile
this.javaVersion = javaVersion
this.baseImageFullName = baseImageFullName
}
static final String getRepository(Project project) {
return project.properties.getOrDefault("docker.image.repository", "corda/corda")
}
Set<Identifier> buildTags(Project project) {
return ["${project.version.toString().toLowerCase()}-${baseImageFullName}"].stream().map {
toAppend -> "${getRepository(project)}:${toAppend}".toString()
}.map(Identifier.&fromCompoundString).collect(Collectors.toSet())
}
static Set<ImageVariant> toBeBuilt = Arrays.stream(values()).collect(Collectors.toSet())
}
class BuildDockerFolderTask extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
@OptionValues("image")
Collection<ImageVariant> getAllVariants() {
return EnumSet.allOf(ImageVariant.class)
}
@Input
Iterable<ImageVariant> getVariantsToBuild() {
return ImageVariant.toBeBuilt
}
@InputFiles
FileCollection getDockerBuildFiles() {
return project.fileTree("${project.projectDir}/src/docker/build")
}
@InputFiles
FileCollection getShellScripts() {
return project.fileTree("${project.projectDir}/src/bash")
}
private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.filter {
it.name.contains("corda")
}.singleFile
private File configExporter = project.tasks.shadowJar.outputs.files.singleFile
private FileCollection getRequiredArtifacts() {
FileCollection res = project.tasks.shadowJar.outputs.files
def capsuleProject = project.findProject(":node:capsule")
def capsuleTaksOutput = capsuleProject.tasks.buildCordaJAR.outputs.files
res += capsuleTaksOutput
return res
}
@OutputFiles
FileCollection getDockerFiles() {
return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map {
new File(dockerBuildDir, it.dockerFile)
}.collect(Collectors.toList()))
}
@OutputDirectory
final File dockerBuildDir = project.file("${project.buildDir}/docker/build")
@TaskAction
def run() {
for(ImageVariant imageVariant : ImageVariant.toBeBuilt) {
def sourceFile = project.projectDir.toPath().resolve("src/docker/${imageVariant.dockerFile}")
def destinationFile = dockerBuildDir.toPath().resolve(imageVariant.dockerFile)
Files.copy(sourceFile, destinationFile, StandardCopyOption.REPLACE_EXISTING)
}
Files.copy(cordaJar.toPath(), dockerBuildDir.toPath().resolve("corda.jar"), StandardCopyOption.REPLACE_EXISTING)
Files.copy(configExporter.toPath(), dockerBuildDir.toPath().resolve("config-exporter.jar"), StandardCopyOption.REPLACE_EXISTING)
["src/bash/run-corda.sh",
"src/config/starting-node.conf",
"src/bash/generate-config.sh"].forEach {
def source = project.file(it).toPath()
Files.copy(source, dockerBuildDir.toPath().resolve(source.fileName), StandardCopyOption.REPLACE_EXISTING)
}
}
}
class BuildDockerImageTask extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
@OptionValues("image")
Collection<ImageVariant> getAllVariants() {
return EnumSet.allOf(ImageVariant.class)
}
@OutputDirectory
final File dockerBuildDir = project.file("${project.buildDir}/docker/build")
@OutputDirectory
final File dockerBuiltImageDir = project.file("${project.buildDir}/docker/images")
@Input
String getRepository() {
return ImageVariant.getRepository(project)
}
@InputFiles
FileCollection dockerFiles
private Map<ImageVariant, DockerImage> images
@OutputFiles
FileCollection getImageFiles() {
return project.objects.fileCollection().from(ImageVariant.toBeBuilt.stream().map { imageVariant ->
dockerBuiltImageDir.toPath().resolve(imageVariant.toString()).toFile()
}.collect(Collectors.toList()))
}
void from(BuildDockerFolderTask buildDockerFolderTask) {
dockerFiles = buildDockerFolderTask.outputs.files
}
@Override
Task configure(Closure closure) {
return super.configure(closure)
}
@TaskAction
def run() {
this.@images = ImageVariant.toBeBuilt.stream().map { imageVariant ->
new Tuple2<>(imageVariant, new DockerImage(
baseDir: dockerBuildDir,
dockerFile: imageVariant.dockerFile,
tags: imageVariant.buildTags(project)))
}.collect(Collectors.toMap({it.first}, {it.second}))
DockerUtils.buildImages(project, this.@images.values())
images.entrySet().forEach { entry ->
ImageVariant imageVariant = entry.key
def destinationFile = dockerBuiltImageDir.toPath().resolve(imageVariant.toString())
new ObjectOutputStream(Files.newOutputStream(destinationFile)).withStream {
it.writeObject(entry.value)
}
}
}
}
class PushDockerImage extends DefaultTask {
@Option(option = "image", description = "Docker image variants that will be built")
void setVariants(List<ImageVariant> variants) {
ImageVariant.toBeBuilt = new HashSet<>(variants)
}
@OptionValues("image")
Collection<ImageVariant> getAllVariants() {
return EnumSet.allOf(ImageVariant.class)
}
private static String registryURL
@Option(option = "registry-url", description = "Docker image registry where images will be pushed, defaults to DockerHub")
void setRegistryURL(String registryURL) {
PushDockerImage.registryURL = registryURL
}
@InputFiles
FileCollection imageFiles
def from(BuildDockerImageTask buildDockerImageTask) {
imageFiles = buildDockerImageTask.outputs.files
}
@TaskAction
def run() {
def classLoader = DockerImage.class.classLoader
Stream<DockerImage> imageStream = imageFiles.files.stream().filter{
it.isFile()
}.map {
new ObjectInputStreamWithCustomClassLoader(Files.newInputStream(it.toPath()), classLoader).withStream {
DockerImage image = it.readObject()
if(PushDockerImage.registryURL) {
image.destination = PushDockerImage.registryURL
}
image
}
}
DockerUtils.pushImages(project, imageStream)
}
}
def buildDockerFolderTask = tasks.register("buildDockerFolder", BuildDockerFolderTask) {
dependsOn = [ tasks.named('shadowJar') ]
}
def buildDockerImageTask = tasks.register("buildDockerImage", BuildDockerImageTask) {
from(buildDockerFolderTask.get())
}
tasks.register("pushDockerImage", PushDockerImage) {
from(buildDockerImageTask.get())
}