Skip to content

Commit

Permalink
feat (jkube-kit/config/service) : Add BuildPackBuildService (#2493)
Browse files Browse the repository at this point in the history
+ Add new enum for buildpacks in JKubeBuildStrategy
+ Add BuildPackBuildService that would be activated when build strategy
  is set to buildpacks

Signed-off-by: Rohan Kumar <[email protected]>
  • Loading branch information
rohanKanojia committed Feb 1, 2024
1 parent 9f2f62b commit c06741e
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 4 deletions.
1 change: 0 additions & 1 deletion jkube-kit/build/service/buildpacks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,4 @@
</resource>
</resources>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ abstract class AbstractBuildPackCliDownloaderTest {
abstract String getProcessorArchitecture();

@BeforeEach
void setUp() throws IOException {
void setUp() {
kitLogger = spy(new KitLogger.SilentLogger());
Map<String, String> overriddenSystemProperties = new HashMap<>();
Map<String, String> overriddenEnvironmentVariables = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ public enum JKubeBuildStrategy {
/**
* Docker build with a binary source
*/
docker("Docker");
docker("Docker"),

/**
* BuildPacks
*/
buildpacks("Buildpacks");

// Source strategy elements
public enum SourceStrategy {
Expand Down
4 changes: 4 additions & 0 deletions jkube-kit/config/service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-build-service-jib</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-build-service-buildpacks</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-helm</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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.kit.config.service.kubernetes;

import java.io.File;
import java.net.MalformedURLException;
import java.util.Objects;
import java.util.Properties;

import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.RegistryConfig;
import org.eclipse.jkube.kit.common.util.EnvUtil;
import org.eclipse.jkube.kit.common.util.PropertiesUtil;
import org.eclipse.jkube.kit.config.image.ImageConfiguration;
import org.eclipse.jkube.kit.config.image.build.JKubeBuildStrategy;
import org.eclipse.jkube.kit.config.service.AbstractImageBuildService;
import org.eclipse.jkube.kit.config.service.BuildServiceConfig;
import org.eclipse.jkube.kit.config.service.JKubeServiceException;
import org.eclipse.jkube.kit.config.service.JKubeServiceHub;
import org.eclipse.jkube.kit.service.buildpacks.BuildPackBuildOptions;
import org.eclipse.jkube.kit.service.buildpacks.BuildPackCliDownloader;
import org.eclipse.jkube.kit.service.buildpacks.controller.BuildPackCliController;

import static org.apache.commons.lang3.StringUtils.strip;

public class BuildPackBuildService extends AbstractImageBuildService {
private static final String DEFAULT_BUILDER_IMAGE = "paketobuildpacks/builder:base";
private static final String PACK_CONFIG_DIR = ".pack";
private static final String PACK_CONFIG_FILE = "config.toml";

private final BuildServiceConfig buildServiceConfig;
private final KitLogger kitLogger;
private final Properties packProperties;

public BuildPackBuildService(JKubeServiceHub jKubeServiceHub) {
this(jKubeServiceHub, PropertiesUtil.getPropertiesFromResource(BuildPackBuildService.class.getResource("/META-INF/jkube/pack-cli.properties")));
}

BuildPackBuildService(JKubeServiceHub jKubeServiceHub, Properties packProperties) {
super(jKubeServiceHub);
this.buildServiceConfig = Objects.requireNonNull(jKubeServiceHub.getBuildServiceConfig(),
"BuildServiceConfig is required");
this.kitLogger = Objects.requireNonNull(jKubeServiceHub.getLog());
this.packProperties = packProperties;

}

@Override
protected void buildSingleImage(ImageConfiguration imageConfiguration) {
kitLogger.info("Delegating container image building process to BuildPacks");
doBuildPackBuild(imageConfiguration);
}

private void doBuildPackBuild(ImageConfiguration imageConfiguration) {
BuildPackCliDownloader packCliDownloader = new BuildPackCliDownloader(kitLogger, packProperties);
File packCli = packCliDownloader.getPackCLIIfPresentOrDownload();
kitLogger.info("Using pack %s", packCli.getAbsolutePath());
BuildPackCliController packCliController = new BuildPackCliController(packCli, kitLogger);
BuildPackBuildOptions buildOptions = createBuildPackOptions(imageConfiguration);
packCliController.build(buildOptions);
}

private BuildPackBuildOptions createBuildPackOptions(ImageConfiguration imageConfiguration) {
Properties packConfigProperties = readLocalPackConfig();
String builderImage = strip(packConfigProperties.getProperty("default-builder-image", DEFAULT_BUILDER_IMAGE), "\"");
BuildPackBuildOptions.BuildPackBuildOptionsBuilder buildOptionsBuilder = BuildPackBuildOptions.builder();
buildOptionsBuilder.imageName(imageConfiguration.getName());
buildOptionsBuilder.builderImage(builderImage);
buildOptionsBuilder.creationTime("now");
return buildOptionsBuilder.build();
}

private Properties readLocalPackConfig() {
File packConfigDir = new File(EnvUtil.getUserHome(), PACK_CONFIG_DIR);
if (packConfigDir.exists() && packConfigDir.isDirectory()) {
File packConfig = new File(packConfigDir, PACK_CONFIG_FILE);
try {
return PropertiesUtil.getPropertiesFromResource(packConfig.toURI().toURL());
} catch (MalformedURLException e) {
kitLogger.warn("Failure in reading pack local configuration : " + e.getMessage());
}
}
return new Properties();
}

@Override
protected void pushSingleImage(ImageConfiguration imageConfiguration, int retries, RegistryConfig registryConfig, boolean skipTag) throws JKubeServiceException {
}

@Override
public boolean isApplicable() {
return buildServiceConfig.getJKubeBuildStrategy() != null &&
buildServiceConfig.getJKubeBuildStrategy().equals(JKubeBuildStrategy.buildpacks);
}

@Override
public void postProcess() {
// NOOP
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.eclipse.jkube.kit.config.service.kubernetes.JibBuildService,100
org.eclipse.jkube.kit.config.service.kubernetes.BuildPackBuildService,110
org.eclipse.jkube.kit.config.service.openshift.OpenshiftBuildService,200
org.eclipse.jkube.kit.config.service.kubernetes.DockerBuildService,9999
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.jkube.kit.common.util.LazyBuilder;
import org.eclipse.jkube.kit.config.image.build.JKubeBuildStrategy;
import org.eclipse.jkube.kit.config.resource.RuntimeMode;
import org.eclipse.jkube.kit.config.service.kubernetes.BuildPackBuildService;
import org.eclipse.jkube.kit.config.service.kubernetes.DockerBuildService;
import org.eclipse.jkube.kit.config.service.kubernetes.JibBuildService;
import org.eclipse.jkube.kit.config.service.openshift.OpenshiftBuildService;
Expand All @@ -42,6 +43,7 @@ static Stream<Arguments> data() {
arguments(RuntimeMode.KUBERNETES, JKubeBuildStrategy.docker, DockerBuildService.class),
arguments(RuntimeMode.KUBERNETES, JKubeBuildStrategy.s2i, DockerBuildService.class),
arguments(RuntimeMode.KUBERNETES, JKubeBuildStrategy.jib, JibBuildService.class),
arguments(RuntimeMode.KUBERNETES, JKubeBuildStrategy.buildpacks, BuildPackBuildService.class),
arguments(RuntimeMode.OPENSHIFT, null, OpenshiftBuildService.class),
arguments(RuntimeMode.OPENSHIFT, JKubeBuildStrategy.docker, OpenshiftBuildService.class),
arguments(RuntimeMode.OPENSHIFT, JKubeBuildStrategy.s2i, OpenshiftBuildService.class),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* 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.kit.config.service.kubernetes;

import org.eclipse.jkube.kit.common.JKubeConfiguration;
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.TestHttpBuildPacksArtifactsServer;
import org.eclipse.jkube.kit.common.util.EnvUtil;
import org.eclipse.jkube.kit.config.image.ImageConfiguration;
import org.eclipse.jkube.kit.config.image.build.BuildConfiguration;
import org.eclipse.jkube.kit.config.image.build.JKubeBuildStrategy;
import org.eclipse.jkube.kit.config.resource.RuntimeMode;
import org.eclipse.jkube.kit.config.service.BuildServiceConfig;
import org.eclipse.jkube.kit.config.service.JKubeServiceHub;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

class BuildPackBuildServiceTest {
private KitLogger kitLogger;
private JKubeServiceHub jKubeServiceHub;
private static final String TEST_PACK_VERSION = "v0.32.1";
private ImageConfiguration imageConfiguration;
private BuildServiceConfig buildServiceConfig;

@TempDir
private File temporaryFolder;

@BeforeEach
void setUp() {
kitLogger = spy(new KitLogger.SilentLogger());
buildServiceConfig = BuildServiceConfig.builder()
.jKubeBuildStrategy(JKubeBuildStrategy.buildpacks)
.build();
jKubeServiceHub = JKubeServiceHub.builder()
.log(kitLogger)
.platformMode(RuntimeMode.KUBERNETES)
.buildServiceConfig(buildServiceConfig)
.configuration(JKubeConfiguration.builder().build())
.build();
imageConfiguration = ImageConfiguration.builder()
.name("foo/bar:latest")
.build(BuildConfiguration.builder()
.from("foo/base:latest")
.build())
.build();
Map<String, String> properties = new HashMap<>();
properties.put("user.home", temporaryFolder.getAbsolutePath());
properties.put("os.name", System.getProperty("os.name"));
properties.put("os.arch", System.getProperty("os.arch"));
Map<String, String> env = new HashMap<>();
env.put("HOME", temporaryFolder.getAbsolutePath());
env.put("PATH", temporaryFolder.toPath().resolve("bin").toFile().getAbsolutePath());
EnvUtil.overrideEnvGetter(env::get);
EnvUtil.overridePropertyGetter(properties::get);
}

@AfterEach
void tearDown() {
EnvUtil.overrideEnvGetter(System::getenv);
EnvUtil.overridePropertyGetter(System::getProperty);
}

@ParameterizedTest
@CsvSource({
"s2i,false", "jib,false", "docker,false", "buildpacks,true"
})
void isApplicable_withGivenStrategy_shouldReturnTrueOnlyForBuildPackStrategy(String buildStrategyValue, boolean expectedResult) {
// Given
jKubeServiceHub = jKubeServiceHub.toBuilder()
.buildServiceConfig(buildServiceConfig.toBuilder()
.jKubeBuildStrategy(JKubeBuildStrategy.valueOf(buildStrategyValue))
.build())
.build();
// When
final boolean result = new BuildPackBuildService(jKubeServiceHub).isApplicable();
// Then
assertThat(result).isEqualTo(expectedResult);
}


@Nested
@DisplayName("buildImage")
class BuildImage {
private TestHttpBuildPacksArtifactsServer server;
private BuildPackBuildService buildPackBuildService;

@BeforeEach
void setUp() {
server = new TestHttpBuildPacksArtifactsServer();
Properties packProperties = new Properties();
packProperties.put("version", TEST_PACK_VERSION);
packProperties.put("windows.binary-extension", "bat");
buildPackBuildService = new BuildPackBuildService(jKubeServiceHub, packProperties);
packProperties.put("linux.artifact", server.getLinuxArtifactUrl());
packProperties.put("linux-arm64.artifact", server.getLinuxArm64ArtifactUrl());
packProperties.put("macos.artifact", server.getMacosArtifactUrl());
packProperties.put("macos-arm64.artifact", server.getMacosArm64ArtifactUrl());
packProperties.put("windows.artifact", server.getWindowsArtifactUrl());
packProperties.put("windows.binary-extension", "bat");
}

@AfterEach
void tearDown() throws IOException {
server.close();
}

@Nested
@DisplayName("local .pack/config.toml exists")
class LocalPackConfigExists {
private File localPackConfig;

@BeforeEach
void setUp() throws IOException {
File packHome = new File(temporaryFolder, ".pack");
Files.createDirectory(packHome.toPath());
localPackConfig = new File(packHome, "config.toml");
}

@Test
@DisplayName("When default builder configured in .pack/config.toml, then use that builder image")
void whenLocalPackConfigHasDefaultBuilderSet_thenUseThatBuilder() throws IOException {
// Given
Files.write(localPackConfig.toPath(), String.format("default-builder-image=\"%s\"", "cnbs/sample-builder:bionic").getBytes());

// When
buildPackBuildService.buildSingleImage(imageConfiguration);

// Then
verify(kitLogger).info("[[s]]%s","build foo/bar:latest --builder cnbs/sample-builder:bionic --creation-time now");
}

@Test
@DisplayName("When .pack/config.toml invalid, then use opinionated builder image")
void whenLocalPackConfigInvalid_thenUseOpinionatedBuilderImage() throws IOException {
// Given
Files.write(localPackConfig.toPath(), "default-builder-image@@=".getBytes());

// When
buildPackBuildService.buildSingleImage(imageConfiguration);

// Then
verify(kitLogger).info("[[s]]%s","build foo/bar:latest --builder paketobuildpacks/builder:base --creation-time now");
}
}

@Nested
@DisplayName("Local .pack/config.toml absent")
class LocalPackConfigAbsent {
@Test
@DisplayName("use opinionated builder image")
void whenLocalPackCLIAndNoDefaultBuilderInPackConfig_thenUseOpinionatedBuilderImage() {
// When
buildPackBuildService.buildSingleImage(imageConfiguration);

// Then
verify(kitLogger).info("[[s]]%s", "build foo/bar:latest --builder paketobuildpacks/builder:base --creation-time now");
}
}
}
}
13 changes: 13 additions & 0 deletions jkube-kit/parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@
<version>${project.version}</version>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-build-service-buildpacks</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>
</dependency>

<dependency>
<groupId>org.eclipse.jkube</groupId>
Expand Down Expand Up @@ -215,6 +222,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-build-service-buildpacks</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.jkube</groupId>
<artifactId>jkube-kit-watcher-api</artifactId>
Expand Down
Loading

0 comments on commit c06741e

Please sign in to comment.