corda/docker/build.gradle
2020-11-20 10:21:53 +00:00

270 lines
8.9 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: 'kotlin'
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{
compile project(':node')
}
shadowJar {
baseName = 'config-exporter'
classifier = null
version = null
zip64 true
exclude '**/Log4j2Plugins.dat'
}
enum ImageVariant {
UBUNTU_ZULU("zulu", "Dockerfile", "1.8"),
UBUNTU_ZULU_11("zulu", "Dockerfile11", "11"),
AL_CORRETTO("corretto", "DockerfileAL", "1.8"),
OFFICIAL(UBUNTU_ZULU)
String knownAs
String dockerFile
String javaVersion
String versionString(String baseTag, String version) {
return "${baseTag}-${knownAs}" +
(knownAs.isEmpty() ? "" : "-") +
"java${javaVersion}-" + version
}
ImageVariant(ImageVariant other) {
this.knownAs = other.knownAs
this.dockerFile = other.dockerFile
this.javaVersion = other.javaVersion
}
ImageVariant(String knownAs, String dockerFile, String javaVersion) {
this.knownAs = knownAs
this.dockerFile = dockerFile
this.javaVersion = javaVersion
}
static final String getRepository(Project project) {
return project.properties.getOrDefault("docker.image.repository", "corda/corda")
}
static private final String runTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
def getName(Project project) {
return versionString(getRepository(project), project.version.toString().toLowerCase())
}
Set<Identifier> buildTags(Project project) {
final String suffix = project.version.toString().toLowerCase().contains("snapshot") ? runTime : "RELEASE"
return [suffix, "latest"].stream().map {
toAppend -> "${getName(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> allVariants() {
return EnumSet.allOf(ImageVariant.class)
}
@Input
Iterable<ImageVariant> variantsToBuild() {
return ImageVariant.toBeBuilt
}
@InputFiles
FileCollection getDockerBuildFiles() {
return project.fileTree("${project.projectDir}/src/docker/build")
}
@InputFiles
FileCollection getShellScripts() {
return project.fileTree("${project.projectDir}/src/bash")
}
@Lazy
private File cordaJar = project.findProject(":node:capsule").tasks.buildCordaJAR.outputs.files.singleFile
@Lazy
private File configExporter = project.tasks.shadowJar.outputs.files.singleFile
@Lazy
private File dbMigrator = project.findProject(":tools:dbmigration").tasks.shadowJar.outputs.files.singleFile
@InputFiles
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> allVariants() {
return EnumSet.allOf(ImageVariant.class)
}
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> allVariants() {
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)
def buildDockerImageTask = tasks.register("buildDockerImage", BuildDockerImageTask) {
from(buildDockerFolderTask.get())
}
tasks.register("pushDockerImage", PushDockerImage) {
from(buildDockerImageTask.get())
}