Skip to content

Commit

Permalink
refactor (jkube-kit) : Move Dockerfile opinionated ImageConfig logic …
Browse files Browse the repository at this point in the history
…from `ConfigHelper.initImageConfiguration` to a dedicated generator

+ ConfigHelper modifies the provided set of ImageConfigurations when it
  detects a `Dockerfile` in project root directory. This is actually a
  feature called Simple Dockerfile Mode. However, this mutation of
  ImageConfiguration from within `initImageConfiguration` does not look
  appropriate. It can be moved to a dedicated generator that will get
  activated when `Dockerfile` is present in project base directory.
+ Add a new generator SimpleDockerfileGenerator, it adds a simple
  ImageConfiguration with Dockerfile configured in build and adds
  it to existing set of ImageConfigurations.

Signed-off-by: Rohan Kumar <rohaan@redhat.com>
  • Loading branch information
rohanKanojia committed Mar 11, 2024
1 parent df35e19 commit 5d14f29
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 91 deletions.
6 changes: 6 additions & 0 deletions gradle-plugin/kubernetes/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
<artifactId>jkube-kit-generator-java-exec</artifactId>
<version>${jkube.kit.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-generator-dockerfile-simple</artifactId>
</dependency>

<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-generator-karaf</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
- helidon
- java-exec
- webapp
- dockerfile-simple
watcher:
includes:
- spring-boot
Expand Down Expand Up @@ -126,6 +127,7 @@
- helidon
- java-exec
- webapp
- dockerfile-simple
enricher:
includes:
- jkube-name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
- helidon
- java-exec
- webapp
- dockerfile-simple
watcher:
includes:
- spring-boot
Expand Down Expand Up @@ -126,6 +127,7 @@
- vertx
- java-exec
- webapp
- dockerfile-simple
enricher:
includes:
- jkube-name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.util.JKubeProjectUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
Expand All @@ -33,12 +32,6 @@
import java.util.Set;
import java.util.stream.Collectors;

import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.addSimpleDockerfileConfig;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.createSimpleDockerfileConfig;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.getTopLevelDockerfile;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.isSimpleDockerFileMode;
import static org.eclipse.jkube.kit.common.util.PropertiesUtil.getValueFromProperties;

/**
* Utility class which helps in resolving, customizing, initializing and validating
* image configuration.
Expand Down Expand Up @@ -174,16 +167,6 @@ public static List<ImageConfiguration> initImageConfiguration(Date buildTimeStam
filter, // A filter which image to process
generatorManager); // GeneratorManager which will invoke generator

// Check for simple Dockerfile mode
ImageConfiguration dockerFileImageConfig = createImageConfigurationForSimpleDockerfile(resolvedImages, jKubeConfiguration, imageNameFormatter);
if (dockerFileImageConfig != null) {
if (resolvedImages.isEmpty()) {
resolvedImages.add(dockerFileImageConfig);
} else {
resolvedImages.set(0, dockerFileImageConfig);
}
}

// Init and validate Image configurations. After this step, getResolvedImages() contains the valid configuration.
for (ImageConfiguration imageConfiguration : resolvedImages) {
imageConfiguration.setName(imageNameFormatter.format(imageConfiguration.getName()));
Expand All @@ -196,20 +179,6 @@ public static List<ImageConfiguration> initImageConfiguration(Date buildTimeStam
return resolvedImages;
}

private static ImageConfiguration createImageConfigurationForSimpleDockerfile(List<ImageConfiguration> resolvedImages, JKubeConfiguration jKubeConfiguration, ImageNameFormatter imageNameFormatter) {
if (isSimpleDockerFileMode(jKubeConfiguration.getBasedir())) {
File topDockerfile = getTopLevelDockerfile(jKubeConfiguration.getBasedir());
String defaultImageName = imageNameFormatter.format(getValueFromProperties(jKubeConfiguration.getProject().getProperties(),
"jkube.image.name", "jkube.generator.name"));
if (resolvedImages.isEmpty()) {
return createSimpleDockerfileConfig(topDockerfile, defaultImageName);
} else if (resolvedImages.size() == 1 && resolvedImages.get(0).getBuildConfiguration() == null) {
return addSimpleDockerfileConfig(resolvedImages.get(0), topDockerfile);
}
}
return null;
}

// =========================================================================

private static void printDockerfileInfoIfDockerfileMode(ImageConfiguration imageConfiguration, KitLogger log, JKubeConfiguration jKubeConfiguration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,36 @@
*/
package org.eclipse.jkube.kit.build.api.helper;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import org.eclipse.jkube.kit.common.JKubeConfiguration;
import org.eclipse.jkube.kit.common.JavaProject;
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.config.image.GeneratorManager;
import org.eclipse.jkube.kit.config.image.ImageConfiguration;
import org.eclipse.jkube.kit.config.image.build.BuildConfiguration;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import org.junit.jupiter.api.io.TempDir;

import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.eq;

class ConfigHelperTest {
private KitLogger logger;
Expand Down Expand Up @@ -85,56 +86,6 @@ void initImageConfiguration_withSimpleImageConfiguration_shouldReturnImageConfig
.isEqualTo(dummyImageConfiguration);
}

@Test
void initImageConfiguration_withSimpleDockerFileInProjectBaseDir_shouldCreateImageConfiguration() {
List<ImageConfiguration> images = new ArrayList<>();
File dockerFile = new File(Objects.requireNonNull(getClass().getResource("/dummy-javaproject/Dockerfile")).getFile());
jKubeConfiguration = jKubeConfiguration.toBuilder()
.project(javaProject.toBuilder()
.baseDirectory(dockerFile.getParentFile())
.build())
.build();

// When
List<ImageConfiguration> resolvedImages = ConfigHelper.initImageConfiguration(new Date(), images, imageConfigResolver, logger, null, generatorManager, jKubeConfiguration);

// Then
assertThat(resolvedImages).isNotNull()
.singleElement()
.hasFieldOrPropertyWithValue("name", "jkube/test-java-project:latest")
.hasFieldOrPropertyWithValue("build.dockerFile", dockerFile)
.hasFieldOrPropertyWithValue("build.ports", Collections.singletonList("8080"));
}

@Test
void initImageConfiguration_withSimpleDockerFileModeEnabledAndImageConfigurationWithNoBuild_shouldModifyExistingImageConfiguration() {
ImageConfiguration dummyImageConfiguration = ImageConfiguration.builder()
.name("imageconfiguration-no-build:latest")
.build();
List<ImageConfiguration> images = new ArrayList<>();
images.add(dummyImageConfiguration);
File dockerFile = new File(getClass().getResource("/dummy-javaproject/Dockerfile").getFile());
jKubeConfiguration = jKubeConfiguration.toBuilder()
.project(javaProject.toBuilder()
.baseDirectory(dockerFile.getParentFile())
.build())
.build();
when(imageConfigResolver.resolve(dummyImageConfiguration, jKubeConfiguration.getProject())).thenReturn(images);
when(generatorManager.generate(images)).thenReturn(images);

// When
List<ImageConfiguration> resolvedImages = ConfigHelper.initImageConfiguration(new Date(), images, imageConfigResolver, logger, null, generatorManager, jKubeConfiguration);

// Then
assertThat(resolvedImages).isNotNull()
.singleElement()
.hasFieldOrPropertyWithValue("name", "imageconfiguration-no-build:latest")
.hasFieldOrPropertyWithValue("build.dockerFile", dockerFile)
.hasFieldOrPropertyWithValue("build.ports", Collections.singletonList("8080"));
verify(logger).info(eq("Using Dockerfile: %s"), anyString());
verify(logger).info(eq("Using Docker Context Directory: %s"), any(File.class));
}

@Test
void initImageConfiguration_whenImageConfigurationNameBlank_thenThrowException() {
// Given
Expand Down Expand Up @@ -163,6 +114,28 @@ void initImageConfiguration_whenNoMatchForImageFilter_thenLogWarning() {
verify(logger).warn("None of the resolved images [%s] match the configured filter '%s'", "foo/bar:latest", "i-dont-exist");
}

@Test
void initImageConfiguration_whenDockerfileUsed_thenLogDockerfilePathAndContextDir(@TempDir File temporaryFolder) {
File dockerFile = temporaryFolder.toPath().resolve("Dockerfile").toFile();
ImageConfiguration dummyImageConfiguration = ImageConfiguration.builder()
.name("imageconfiguration-no-build:latest")
.build(BuildConfiguration.builder()
.dockerFile(dockerFile.getAbsolutePath())
.build())
.build();
List<ImageConfiguration> images = new ArrayList<>();
images.add(dummyImageConfiguration);
when(imageConfigResolver.resolve(dummyImageConfiguration, jKubeConfiguration.getProject())).thenReturn(images);
when(generatorManager.generate(images)).thenReturn(images);

// When
ConfigHelper.initImageConfiguration(new Date(), images, imageConfigResolver, logger, null, generatorManager, jKubeConfiguration);

// Then
verify(logger).info(eq("Using Dockerfile: %s"), anyString());
verify(logger).info(eq("Using Docker Context Directory: %s"), any(File.class));
}

@Test
void validateExternalPropertyActivation_withMultipleImagesWithoutExplicitExternalConfig_shouldThrowException() {
// Given
Expand Down
51 changes: 51 additions & 0 deletions jkube-kit/generator/dockerfile-simple/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2019 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at:
https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-parent</artifactId>
<version>1.17-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

<artifactId>jkube-kit-generator-dockerfile-simple</artifactId>

<name>JKube Kit :: Generator :: Dockerfile Simple</name>

<dependencies>
<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-generator-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.generator.dockerfile.simple;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.eclipse.jkube.generator.api.GeneratorContext;
import org.eclipse.jkube.generator.api.support.BaseGenerator;
import org.eclipse.jkube.kit.build.api.helper.ImageNameFormatter;
import org.eclipse.jkube.kit.common.Configs;
import org.eclipse.jkube.kit.common.JKubeException;
import org.eclipse.jkube.kit.config.image.ImageConfiguration;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.addSimpleDockerfileConfig;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.createSimpleDockerfileConfig;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.getTopLevelDockerfile;
import static org.eclipse.jkube.kit.build.api.helper.DockerFileUtil.isSimpleDockerFileMode;
import static org.eclipse.jkube.kit.common.util.BuildReferenceDateUtil.getBuildTimestamp;
import static org.eclipse.jkube.kit.common.util.PropertiesUtil.getValueFromProperties;

public class SimpleDockerfileGenerator extends BaseGenerator {
public SimpleDockerfileGenerator(GeneratorContext context) {
super(context, "dockerfile-simple");
}

@Override
public boolean isApplicable(List<ImageConfiguration> configs) {
return isSimpleDockerFileMode(getContext().getProject().getBaseDirectory());
}

@Override
public List<ImageConfiguration> customize(List<ImageConfiguration> existingConfigs, boolean prePackagePhase) {
ImageNameFormatter imageNameFormatter = new ImageNameFormatter(getContext().getProject(), extractBuildTimestampFromProject());
File topDockerfile = getTopLevelDockerfile(getContext().getProject().getBaseDirectory());
String defaultImageName = imageNameFormatter.format(getValueFromProperties(getContext().getProject().getProperties(),
"jkube.image.name", "jkube.generator.name"));
List<ImageConfiguration> result = new ArrayList<>();
if (existingConfigs.isEmpty()) {
result.add(createSimpleDockerfileConfig(topDockerfile, defaultImageName));
} else if (existingConfigs.size() == 1 && existingConfigs.get(0).getBuildConfiguration() == null) {
result.add(addSimpleDockerfileConfig(existingConfigs.get(0), topDockerfile));
}
return result;
}

private Date extractBuildTimestampFromProject() {
try {
return getBuildTimestamp(null, null, getContext().getProject().getBuildDirectory().getAbsolutePath(),
"docker/build.timestamp");
} catch (IOException ioException) {
throw JKubeException.launderThrowable("failure in extract project build timestamp", ioException);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# The order of the generators used is defined in the active profile
# (which is the profile "default" by default)
# You can find the default profiles in "profiles-default.yml"

org.eclipse.jkube.generator.dockerfile.simple.SimpleDockerfileGenerator
Loading

0 comments on commit 5d14f29

Please sign in to comment.