From 6949be6be6a900a4d7c44e9b9148fb290f7cd924 Mon Sep 17 00:00:00 2001 From: Devashishbasu Date: Thu, 1 Feb 2024 10:28:10 +0530 Subject: [PATCH 01/24] parsing IPv6 literals support added 1.added IPv6 address 2.upated DOMAIN_REGEX for the IPv6 addresses 3.uncommented the related tests removing issue references removing issue references --- .../jkube/kit/config/image/ImageName.java | 4 +++- .../ImageNameDistributionReferenceTest.java | 16 ++++++++-------- .../config/image/ImageNameORASReferenceTest.java | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java index 05a143b6a9..4aeb44444c 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java @@ -342,6 +342,7 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L25 private static final String DOMAIN_COMPONENT_REGEXP = "(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])"; + private static final String IPV6_ADDRESS_REGEXP = "\\[(?:[a-fA-F0-9:]+)\\]"; // ========================================================== @@ -352,7 +353,8 @@ private boolean isRegistryValidPathComponent() { private static final Pattern IMAGE_NAME_REGEXP = Pattern.compile(NAME_COMPONENT_REGEXP + "(?:(?:/" + NAME_COMPONENT_REGEXP + ")+)?"); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L31 - private static final Pattern DOMAIN_REGEXP = Pattern.compile("^" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*(?::[0-9]+)?$"); + private static final Pattern DOMAIN_REGEXP = Pattern.compile("^(" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*)" + + "(?::[0-9]+)?$"); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L37 private static final Pattern TAG_REGEXP = Pattern.compile("^[\\w][\\w.-]{0,127}$"); diff --git a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java index 46ac1d89e1..1b2bf3d740 100644 --- a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java +++ b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java @@ -72,14 +72,14 @@ class ImageNameDistributionReferenceTest { "192.168.0.1:8/debian", "192.168.0.2:25000/debian", "docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", - //"[2001:db8::1]/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8:1:2:3:4:5:6]/repo:tag", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo:tag", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 + "[2001:db8::1]/repo", + "[2001:db8:1:2:3:4:5:6]/repo:tag", + "[2001:db8::1]:5000/repo", + "[2001:db8::1]:5000/repo:tag", + "[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "[2001:db8::]:5000/repo", + "[::1]:5000/repo", }) void validNames(String name) { // Given diff --git a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java index 7795afedd9..dc4c1fab17 100644 --- a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java +++ b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java @@ -42,7 +42,7 @@ class ImageNameORASReferenceTest { "registry.example.com/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", "localhost:5000/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", "127.0.0.1:5000/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", - //"[::1]:5000/hello-world:v1", // https://github.com/eclipse/jkube/issues/2541 + "[::1]:5000/hello-world:v1", //"registry.example.com/hello-world:@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", // https://github.com/eclipse/jkube/issues/2545 }) void validImageNamesCompatibleWithAll(String name) { From 16e07c59655ee7fbc4bb21ad9ab4a9e5c396749b Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Wed, 31 Jan 2024 18:32:47 +0530 Subject: [PATCH 02/24] test : Add TestHttpBuildPackArtifactsServer in jkube-kit/common Add TestHttpBuildPackArtifactsServer to host build pack download artifacts so that this test utility class can be reused in dependent modules Signed-off-by: Rohan Kumar --- .../AbstractBuildPackCliDownloaderTest.java | 29 +++--- .../TestHttpBuildPacksArtifactsServer.java | 86 ++++++++++++++++++ .../pack-v0.32.1-linux-arm64.tgz | Bin .../pack-v0.32.1-linux.tgz | Bin .../pack-v0.32.1-macos-arm64.tgz | Bin .../pack-v0.32.1-macos.tgz | Bin .../pack-v0.32.1-windows.zip | Bin 7 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/TestHttpBuildPacksArtifactsServer.java rename jkube-kit/{build/service/buildpacks/src/test/resources/artifacts => common/src/test/resources/buildpack-download-artifacts}/pack-v0.32.1-linux-arm64.tgz (100%) rename jkube-kit/{build/service/buildpacks/src/test/resources/artifacts => common/src/test/resources/buildpack-download-artifacts}/pack-v0.32.1-linux.tgz (100%) rename jkube-kit/{build/service/buildpacks/src/test/resources/artifacts => common/src/test/resources/buildpack-download-artifacts}/pack-v0.32.1-macos-arm64.tgz (100%) rename jkube-kit/{build/service/buildpacks/src/test/resources/artifacts => common/src/test/resources/buildpack-download-artifacts}/pack-v0.32.1-macos.tgz (100%) rename jkube-kit/{build/service/buildpacks/src/test/resources/artifacts => common/src/test/resources/buildpack-download-artifacts}/pack-v0.32.1-windows.zip (100%) diff --git a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java index 0f52c2ba6c..3d29742861 100644 --- a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java +++ b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java @@ -23,7 +23,7 @@ import org.eclipse.jkube.kit.common.KitLogger; -import org.eclipse.jkube.kit.common.TestHttpStaticServer; +import org.eclipse.jkube.kit.common.TestHttpBuildPacksArtifactsServer; import org.eclipse.jkube.kit.common.util.EnvUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -45,9 +45,8 @@ abstract class AbstractBuildPackCliDownloaderTest { @TempDir private File temporaryFolder; private File oldPackCliInJKubeDir; - private TestHttpStaticServer server; + private TestHttpBuildPacksArtifactsServer server; private BuildPackCliDownloader buildPackCliDownloader; - private String serverBaseUrl; private Properties packProperties; abstract String getApplicablePackBinary(); @@ -67,16 +66,14 @@ void setUp() { overriddenEnvironmentVariables.put("PATH", temporaryFolder.toPath().resolve("bin").toFile().getAbsolutePath()); EnvUtil.overridePropertyGetter(overriddenSystemProperties::get); EnvUtil.overrideEnvGetter(overriddenEnvironmentVariables::get); - File remoteDirectory = new File(Objects.requireNonNull(getClass().getResource("/")).getFile()); - server = new TestHttpStaticServer(remoteDirectory); - serverBaseUrl = String.format("http://localhost:%d/", server.getPort()); + server = new TestHttpBuildPacksArtifactsServer(); packProperties = new Properties(); packProperties.put("version", TEST_PACK_VERSION); - packProperties.put("linux.artifact", serverBaseUrl + "artifacts/pack-v" + TEST_PACK_VERSION + "-linux.tgz"); - packProperties.put("linux-arm64.artifact", serverBaseUrl + "artifacts/pack-v" + TEST_PACK_VERSION + "-linux-arm64.tgz"); - packProperties.put("macos.artifact", serverBaseUrl + "artifacts/pack-v" + TEST_PACK_VERSION + "-macos.tgz"); - packProperties.put("macos-arm64.artifact", serverBaseUrl + "artifacts/pack-v" + TEST_PACK_VERSION + "-macos-arm64.tgz"); - packProperties.put("windows.artifact", serverBaseUrl + "artifacts/pack-v" + TEST_PACK_VERSION + "-windows.zip"); + 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"); buildPackCliDownloader = new BuildPackCliDownloader(kitLogger, packProperties); } @@ -159,11 +156,11 @@ void fileExistsAndHasTheRightSize() { class DownloadFails { @BeforeEach void setUp() { - packProperties.put("linux.artifact", serverBaseUrl + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-linux.tgz"); - packProperties.put("linux-arm64.artifact", serverBaseUrl + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-linux-arm64.tgz"); - packProperties.put("macos.artifact", serverBaseUrl + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-macos.tgz"); - packProperties.put("macos-arm64.artifact", serverBaseUrl + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-macos-arm64.tgz"); - packProperties.put("windows.artifact", serverBaseUrl + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-windows.zip"); + packProperties.put("linux.artifact", server.getBaseUrl() + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-linux.tgz"); + packProperties.put("linux-arm64.artifact", server.getBaseUrl() + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-linux-arm64.tgz"); + packProperties.put("macos.artifact", server.getBaseUrl() + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-macos.tgz"); + packProperties.put("macos-arm64.artifact", server.getBaseUrl() + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-macos-arm64.tgz"); + packProperties.put("windows.artifact", server.getBaseUrl() + "invalid-artifacts/pack-v" + TEST_PACK_VERSION + "-windows.zip"); } @Test diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/TestHttpBuildPacksArtifactsServer.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/TestHttpBuildPacksArtifactsServer.java new file mode 100644 index 0000000000..40f9da047b --- /dev/null +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/TestHttpBuildPacksArtifactsServer.java @@ -0,0 +1,86 @@ +/* + * 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.common; + +import org.apache.commons.io.FileUtils; +import org.eclipse.jkube.kit.common.util.FileUtil; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +public class TestHttpBuildPacksArtifactsServer implements Closeable { + private final TestHttpStaticServer testHttpStaticServer; + private static final String LINUX_ARTIFACT = "pack-v0.32.1-linux.tgz"; + private static final String LINUX_ARM64_ARTIFACT = "pack-v0.32.1-linux-arm64.tgz"; + private static final String MACOS_ARTIFACT = "pack-v0.32.1-macos.tgz"; + private static final String MACOS_ARM64_ARTIFACT = "pack-v0.32.1-macos-arm64.tgz"; + private static final String WINDOWS_ARTIFACT = "pack-v0.32.1-windows.zip"; + private final File remoteBuildPackArtifactsDir; + + public TestHttpBuildPacksArtifactsServer() { + remoteBuildPackArtifactsDir = createTemporaryArtifactsDir(); + testHttpStaticServer = new TestHttpStaticServer(remoteBuildPackArtifactsDir); + } + + public String getLinuxArtifactUrl() { + return createUrlForArtifact(LINUX_ARTIFACT); + } + + public String getLinuxArm64ArtifactUrl() { + return createUrlForArtifact(LINUX_ARM64_ARTIFACT); + } + + public String getMacosArtifactUrl() { + return createUrlForArtifact(MACOS_ARTIFACT); + } + + public String getMacosArm64ArtifactUrl() { + return createUrlForArtifact(MACOS_ARM64_ARTIFACT); + } + + public String getWindowsArtifactUrl() { + return createUrlForArtifact(WINDOWS_ARTIFACT); + } + + public String getBaseUrl() { + return String.format("http://localhost:%d", testHttpStaticServer.getPort()); + } + + private String createUrlForArtifact(String artifactName) { + return String.format("%s/%s", getBaseUrl(), artifactName); + } + + private File createTemporaryArtifactsDir() { + try { + File artifactDir = FileUtil.createTempDirectory(); + + FileUtils.copyInputStreamToFile(Objects.requireNonNull(TestHttpBuildPacksArtifactsServer.class.getResourceAsStream(String.format("/buildpack-download-artifacts/%s", LINUX_ARTIFACT))), new File(artifactDir, LINUX_ARTIFACT)); + FileUtils.copyInputStreamToFile(Objects.requireNonNull(TestHttpBuildPacksArtifactsServer.class.getResourceAsStream(String.format("/buildpack-download-artifacts/%s", LINUX_ARM64_ARTIFACT))), new File(artifactDir, LINUX_ARM64_ARTIFACT)); + FileUtils.copyInputStreamToFile(Objects.requireNonNull(TestHttpBuildPacksArtifactsServer.class.getResourceAsStream(String.format("/buildpack-download-artifacts/%s", MACOS_ARTIFACT))), new File(artifactDir, MACOS_ARTIFACT)); + FileUtils.copyInputStreamToFile(Objects.requireNonNull(TestHttpBuildPacksArtifactsServer.class.getResourceAsStream(String.format("/buildpack-download-artifacts/%s", MACOS_ARM64_ARTIFACT))), new File(artifactDir, MACOS_ARM64_ARTIFACT)); + FileUtils.copyInputStreamToFile(Objects.requireNonNull(TestHttpBuildPacksArtifactsServer.class.getResourceAsStream(String.format("/buildpack-download-artifacts/%s", WINDOWS_ARTIFACT))), new File(artifactDir, WINDOWS_ARTIFACT)); + return artifactDir; + } catch (IOException ioException) { + throw new IllegalStateException("Failure in creating build pack artifacts server : ", ioException); + } + } + + @Override + public void close() throws IOException { + testHttpStaticServer.close(); + FileUtil.cleanDirectory(remoteBuildPackArtifactsDir); + } +} diff --git a/jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-linux-arm64.tgz b/jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-linux-arm64.tgz similarity index 100% rename from jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-linux-arm64.tgz rename to jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-linux-arm64.tgz diff --git a/jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-linux.tgz b/jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-linux.tgz similarity index 100% rename from jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-linux.tgz rename to jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-linux.tgz diff --git a/jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-macos-arm64.tgz b/jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-macos-arm64.tgz similarity index 100% rename from jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-macos-arm64.tgz rename to jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-macos-arm64.tgz diff --git a/jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-macos.tgz b/jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-macos.tgz similarity index 100% rename from jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-macos.tgz rename to jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-macos.tgz diff --git a/jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-windows.zip b/jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-windows.zip similarity index 100% rename from jkube-kit/build/service/buildpacks/src/test/resources/artifacts/pack-v0.32.1-windows.zip rename to jkube-kit/common/src/test/resources/buildpack-download-artifacts/pack-v0.32.1-windows.zip From 302b2b78cf412240ec5e194664758c122425039b Mon Sep 17 00:00:00 2001 From: Arun Erram <140548924+ArunErram@users.noreply.github.com> Date: Thu, 1 Feb 2024 02:56:21 -0600 Subject: [PATCH 03/24] fix: remove KubernetesResourceUtil.ensureHasPort unnecessary 'null' check before 'equals()' call --- .../jkube/kit/enricher/api/util/KubernetesResourceUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java b/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java index 530bfa1d7b..2daf365656 100644 --- a/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java +++ b/jkube-kit/enricher/api/src/main/java/org/eclipse/jkube/kit/enricher/api/util/KubernetesResourceUtil.java @@ -346,7 +346,7 @@ private static void ensureHasPort(Container container, ContainerPort port) { for (ContainerPort cp : ports) { String n1 = cp.getName(); String n2 = port.getName(); - if (n1 != null && n2 != null && n1.equals(n2)) { + if (n1 != null && n1.equals(n2)) { return; } Integer p1 = cp.getContainerPort(); From dfa04865e08d5ce652337faae7aaa0b59c89fa9c Mon Sep 17 00:00:00 2001 From: Prashantkumar Khatri <96608160+ShantKhatri@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:12:20 +0530 Subject: [PATCH 04/24] test(jkube-kit-enricher-api): Replaced org.mockito.Mockito references (#2606) --- .../jkube/kit/enricher/handler/PodTemplateHandlerTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/handler/PodTemplateHandlerTest.java b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/handler/PodTemplateHandlerTest.java index e49e43616c..fa6a4efcaf 100644 --- a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/handler/PodTemplateHandlerTest.java +++ b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/handler/PodTemplateHandlerTest.java @@ -28,8 +28,6 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; class PodTemplateHandlerTest { @@ -68,8 +66,8 @@ void setUp() { .registry("docker.io").build(); images.add(imageConfiguration); - probeHandler = mock(ProbeHandler.class, RETURNS_DEEP_STUBS); - project = mock(JavaProject.class, RETURNS_DEEP_STUBS); + probeHandler = new ProbeHandler(); + project = JavaProject.builder().build(); ContainerHandler containerHandler = getContainerHandler(); podTemplateHandler = new PodTemplateHandler(containerHandler); } From b5dbf12b74d22edc07f6ffe056f5846beabc3a7f Mon Sep 17 00:00:00 2001 From: Prashantkumar Khatri <96608160+ShantKhatri@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:13:30 +0530 Subject: [PATCH 05/24] test(jkube-kit-enricher-api): Replaced org.mockito references from EnricherConfigTest with builders #2597 (#2604) --- .../kit/enricher/api/EnricherConfigTest.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/EnricherConfigTest.java b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/EnricherConfigTest.java index 63104d8729..3798723c69 100644 --- a/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/EnricherConfigTest.java +++ b/jkube-kit/enricher/api/src/test/java/org/eclipse/jkube/kit/enricher/api/EnricherConfigTest.java @@ -16,13 +16,11 @@ import java.util.Collections; import java.util.Map; import org.eclipse.jkube.kit.common.Configs; +import org.eclipse.jkube.kit.common.JavaProject; import org.eclipse.jkube.kit.config.resource.ProcessorConfig; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Answers.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; /** * @author roland @@ -32,14 +30,19 @@ class EnricherConfigTest { private enum Config implements Configs.Config { TYPE } - - @SuppressWarnings("ResultOfMethodCallIgnored") @Test void simple() { - EnricherContext context = mock(EnricherContext.class,RETURNS_DEEP_STUBS); + Map> configMap = Collections.singletonMap("default.service", Collections.singletonMap("TYPE", "LoadBalancer")); - when(context.getConfiguration().getProcessorConfig()).thenReturn(new ProcessorConfig(null, null, configMap)); + EnricherContext context = JKubeEnricherContext.builder() + .project(JavaProject.builder() + .groupId("org.eclipse.jkube") + .artifactId("test-project") + .version("0.0.1") + .build()) + .processorConfig(new ProcessorConfig(null, null, configMap)) + .build(); EnricherConfig config = new EnricherConfig("default.service", context); assertThat(config.get(EnricherConfigTest.Config.TYPE)).isEqualTo("LoadBalancer"); } From b9515f59320e70bbb527be23039126c65026cf3b Mon Sep 17 00:00:00 2001 From: Devashishbasu Date: Fri, 2 Feb 2024 10:17:03 +0530 Subject: [PATCH 06/24] Implemented suggested changes by sonarcloud --- .../java/org/eclipse/jkube/kit/config/image/ImageName.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java index 4aeb44444c..86362bb4ac 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java @@ -342,7 +342,7 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L25 private static final String DOMAIN_COMPONENT_REGEXP = "(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])"; - private static final String IPV6_ADDRESS_REGEXP = "\\[(?:[a-fA-F0-9:]+)\\]"; + private static final String IPV6_ADDRESS_REGEXP = "\\[[a-fA-F0-9:]+\\]"; // ========================================================== @@ -353,8 +353,8 @@ private boolean isRegistryValidPathComponent() { private static final Pattern IMAGE_NAME_REGEXP = Pattern.compile(NAME_COMPONENT_REGEXP + "(?:(?:/" + NAME_COMPONENT_REGEXP + ")+)?"); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L31 - private static final Pattern DOMAIN_REGEXP = Pattern.compile("^(" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*)" + - "(?::[0-9]+)?$"); + private static final Pattern DOMAIN_REGEXP = Pattern.compile("^(?:" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*)" + + "(?::\\d+)?$"); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L37 private static final Pattern TAG_REGEXP = Pattern.compile("^[\\w][\\w.-]{0,127}$"); From 708dff28f38722bb5164dfa40ef6b6f2f3f5815f Mon Sep 17 00:00:00 2001 From: Sankriti Mishra <104777910+sankritimishra@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:14:35 +0530 Subject: [PATCH 07/24] fix: SecretEnricher.getSecretsFromXmlConfig returns Collections.emptyList() instead of null #2530 (#2605) --- .../jkube/enricher/generic/SecretEnricher.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java index 29045a06f9..9fcb8764b0 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java @@ -27,11 +27,13 @@ import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; import org.eclipse.jkube.kit.enricher.api.util.SecretConstants; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jkube.kit.enricher.api.model.Configuration; import java.util.HashMap; import java.util.List; import java.util.Map; - +import java.util.Collections; +import java.util.Optional; public abstract class SecretEnricher extends BaseEnricher { public SecretEnricher(JKubeEnricherContext buildContext, String name) { @@ -128,11 +130,10 @@ private void addSecretsFromXmlConfiguration(KubernetesListBuilder builder) { } private List getSecretsFromXmlConfig() { - ResourceConfig resourceConfig = getConfiguration().getResource(); - if(resourceConfig != null && resourceConfig.getSecrets() != null) { - return resourceConfig.getSecrets(); - } - return null; + return Optional.ofNullable(getConfiguration()) + .map(Configuration::getResource) + .map(ResourceConfig::getSecrets) + .orElse(Collections.emptyList()); } private String getDockerIdFromAnnotation(Map annotation) { From 7a60b298647147752aeb1ada65e38b6d37cd8a0d Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Fri, 2 Feb 2024 09:40:50 +0100 Subject: [PATCH 08/24] feat(helm): add helm-java dependency Signed-off-by: Marc Nuri --- jkube-kit/parent/pom.xml | 6 ++++++ pom.xml | 1 + 2 files changed, 7 insertions(+) diff --git a/jkube-kit/parent/pom.xml b/jkube-kit/parent/pom.xml index 74815950f6..0418634e0c 100644 --- a/jkube-kit/parent/pom.xml +++ b/jkube-kit/parent/pom.xml @@ -394,6 +394,12 @@ ${version.jackson} + + com.marcnuri.helm-java + helm-java + ${version.helm-java} + + org.apache.commons commons-lang3 diff --git a/pom.xml b/pom.xml index 07929911f0..9e2fad612f 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,7 @@ 0.0.3 3.0.19 31.1-jre + 0.0.3 2.15.2 0.8.10 2.5.0 From 70b6723e2860c2182143aded627486f5997e7992 Mon Sep 17 00:00:00 2001 From: Prashantkumar Khatri <96608160+ShantKhatri@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:56:45 +0530 Subject: [PATCH 09/24] test(jkube-kit-build-api): Removed mock statements from AssemblyManagerTest #2599 (#2607) --- .../build/api/assembly/AssemblyManagerTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/assembly/AssemblyManagerTest.java b/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/assembly/AssemblyManagerTest.java index 6a038a0c75..ef20ad044d 100644 --- a/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/assembly/AssemblyManagerTest.java +++ b/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/assembly/AssemblyManagerTest.java @@ -35,8 +35,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class AssemblyManagerTest { @@ -53,8 +51,12 @@ void setUp() throws Exception { assemblyManager = AssemblyManager.getInstance(); targetDirectory = Files.createDirectory(temporaryFolder.resolve("target")).toFile(); logger = spy(new KitLogger.SilentLogger()); - configuration = mock(JKubeConfiguration.class); - project = mock(JavaProject.class); + project = JavaProject.builder() + .buildDirectory(targetDirectory) + .build(); + configuration = JKubeConfiguration.builder() + .project(project) + .build(); } @Test @@ -69,9 +71,9 @@ void getInstance_shouldBeSingleton() { void assemblyFiles() throws Exception { // Given final File buildDirs = Files.createDirectory(temporaryFolder.resolve("buildDirs")).toFile(); - when(configuration.getProject()).thenReturn(project); - when(project.getBaseDirectory()).thenReturn(buildDirs); - when(project.getBuildDirectory()).thenReturn(targetDirectory); + configuration = configuration.toBuilder() + .project(project.toBuilder().baseDirectory(buildDirs).build()) + .build(); ImageConfiguration imageConfiguration = ImageConfiguration.builder() .name("testImage").build(createBuildConfig()) .build(); From 44bbcdb97039e4423e0b6a5495772e997c0b3318 Mon Sep 17 00:00:00 2001 From: Ravinder Singh <83815874+Ravinder-coder@users.noreply.github.com> Date: Fri, 2 Feb 2024 19:04:32 +0530 Subject: [PATCH 10/24] test: DefaultControllerEnricherCreateTest.setUp The declared Exception exception is never thrown issue #2592 (#2611) --- .../enricher/generic/DefaultControllerEnricherCreateTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/DefaultControllerEnricherCreateTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/DefaultControllerEnricherCreateTest.java index 9de91e226b..f180dd06f1 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/DefaultControllerEnricherCreateTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/DefaultControllerEnricherCreateTest.java @@ -47,7 +47,7 @@ class DefaultControllerEnricherCreateTest { private KubernetesListBuilder klb; @BeforeEach - void setUp() throws Exception { + void setUp() { properties = new Properties(); buildContext = JKubeEnricherContext.builder() .log(new KitLogger.SilentLogger()) From 81fed6ac39bc0a9bd8bdcf4160c5012d59cbdd3e Mon Sep 17 00:00:00 2001 From: Devashishbasu Date: Sat, 3 Feb 2024 13:10:58 +0530 Subject: [PATCH 11/24] updated the suggested changes --- .../eclipse/jkube/kit/config/image/ImageName.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java index 86362bb4ac..ca0fee9166 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java @@ -275,7 +275,7 @@ private void doValidate() { String user = inferUser(); String image = user != null ? repository.substring(user.length() + 1) : repository; Object[] checks = new Object[] { - "registry", DOMAIN_REGEXP, registry, + "registry", REGISTRY_REGEXP, registry, "image", IMAGE_NAME_REGEXP, image, "user", NAME_COMP_REGEXP, user, "tag", TAG_REGEXP, tag, @@ -323,7 +323,7 @@ private void parseComponentsBeforeTag(String rest) { } private boolean isValidDomain(String str) { - return containsPeriodOrColon(str) && DOMAIN_REGEXP.matcher(str).matches(); + return containsPeriodOrColon(str) && REGISTRY_REGEXP.matcher(str).matches(); } private boolean isRegistryValidPathComponent() { @@ -342,6 +342,8 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L25 private static final String DOMAIN_COMPONENT_REGEXP = "(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])"; + + //https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L91 private static final String IPV6_ADDRESS_REGEXP = "\\[[a-fA-F0-9:]+\\]"; // ========================================================== @@ -352,9 +354,13 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L53 private static final Pattern IMAGE_NAME_REGEXP = Pattern.compile(NAME_COMPONENT_REGEXP + "(?:(?:/" + NAME_COMPONENT_REGEXP + ")+)?"); + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L65 + private static final String OPTIONAL_PORT_REGEXP = "(?::[0-9]+)?"; + private static final String DOMAIN_NAME_REGEXP = DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*"; + private static final String REGISTRY_HOST_REGEXP = "^(?:" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_NAME_REGEXP + ")"; + // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L31 - private static final Pattern DOMAIN_REGEXP = Pattern.compile("^(?:" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*)" + - "(?::\\d+)?$"); + private static final Pattern REGISTRY_REGEXP = Pattern.compile(REGISTRY_HOST_REGEXP + OPTIONAL_PORT_REGEXP); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L37 private static final Pattern TAG_REGEXP = Pattern.compile("^[\\w][\\w.-]{0,127}$"); From 4a874ff8fc2ba99e80cae63b41c5c1094e9587dd Mon Sep 17 00:00:00 2001 From: Amit Patil <158708202+AmitPatil05@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:58:17 +0530 Subject: [PATCH 12/24] test: remove redundant throws in IngressEnricherTest.setUp (#2618) Remove unnecessary exception declaration in IngressEnricherTest.setUp --- .../org/eclipse/jkube/enricher/generic/IngressEnricherTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java index e1150e51d5..e7e7ee82af 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/IngressEnricherTest.java @@ -59,7 +59,7 @@ class IngressEnricherTest { private KitLogger logger; @BeforeEach - void setUp() throws Exception { + void setUp() { context = mock(JKubeEnricherContext.class,RETURNS_DEEP_STUBS); logger = spy(new KitLogger.SilentLogger()); when(context.getLog()).thenReturn(logger); From 51a80d30ee46c50049d9d2ca2107fb637b333d93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:45:50 +0000 Subject: [PATCH 13/24] chore(deps): Bump org.apache.maven:maven-core in /jkube-kit/parent Bumps [org.apache.maven:maven-core](https://github.com/apache/maven) from 3.6.3 to 3.8.1. - [Release notes](https://github.com/apache/maven/releases) - [Commits](https://github.com/apache/maven/compare/maven-3.6.3...maven-3.8.1) --- updated-dependencies: - dependency-name: org.apache.maven:maven-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- jkube-kit/parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/parent/pom.xml b/jkube-kit/parent/pom.xml index 0418634e0c..a760afcbbf 100644 --- a/jkube-kit/parent/pom.xml +++ b/jkube-kit/parent/pom.xml @@ -50,7 +50,7 @@ 0.38.20 3.0.2 3.6.1 - 3.6.3 + 3.8.1 3.3.1 3.9.0 1.0.86 From ed4154bab96ca25a688cbd5c276b48e32e5697e6 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Fri, 26 Jan 2024 01:42:41 +0530 Subject: [PATCH 14/24] fix (jkube-kit/enricher) : WellKnownLabelEnricher also considers labels added via resource configuration While adding labels and selectors to a resource, WellKnownLabelEnricher and ProjectLabelEnricher would give precedence to label configured via resource label XML/Groovy DSL configuration. This precedence would depend on the type of resource label configuration used. If `all` has been provided in configuration, this means precedence would be given for all resources. However, if some specific resource label configuration is used; precedence would only be given for that specific resource Signed-off-by: Rohan Kumar --- .../it/src/it/well-known-labels/build.gradle | 34 +++++ .../labelsViaResourceConfig/kubernetes.yml | 103 +++++++++++++ .../labelsViaResourceConfig/openshift.yml | 144 ++++++++++++++++++ .../plugin/tests/WellKnownLabelsIT.java | 3 +- .../jkube/kit/common/util/MapUtil.java | 21 +-- .../generic/AbstractLabelEnricher.java | 63 ++++++-- .../generic/ProjectLabelEnricher.java | 25 ++- .../generic/WellKnownLabelsEnricher.java | 23 +-- .../generic/ProjectLabelEnricherTest.java | 110 +++++++++++-- .../generic/WellKnownLabelsEnricherTest.java | 77 +++++++++- 10 files changed, 547 insertions(+), 56 deletions(-) create mode 100644 gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/kubernetes.yml create mode 100644 gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/openshift.yml diff --git a/gradle-plugin/it/src/it/well-known-labels/build.gradle b/gradle-plugin/it/src/it/well-known-labels/build.gradle index 10ed873d9e..b94c3deb4f 100644 --- a/gradle-plugin/it/src/it/well-known-labels/build.gradle +++ b/gradle-plugin/it/src/it/well-known-labels/build.gradle @@ -25,6 +25,32 @@ repositories { mavenCentral() } +def allProperties = new Properties(); +allProperties.put("team","via-resource-groovy-dsl-labels-all") +allProperties.put("language", "via-resource-groovy-dsl-labels-all") +allProperties.put("provider", "via-resource-groovy-dsl-labels-all") +allProperties.put("app", "via-resource-groovy-dsl-labels-all") +allProperties.put("version", "via-resource-groovy-dsl-labels-all") +allProperties.put("group", "via-resource-groovy-dsl-labels-all") +allProperties.put("app.kubernetes.io/name", "via-resource-groovy-dsl-labels-all") +allProperties.put("app.kubernetes.io/version", "via-resource-groovy-dsl-labels-all") +allProperties.put("app.kubernetes.io/component", "via-resource-groovy-dsl-labels-all") +allProperties.put("app.kubernetes.io/managed-by", "via-resource-groovy-dsl-labels-all") +allProperties.put("app.kubernetes.io/part-of", "via-resource-groovy-dsl-labels-all") + +def serviceProperties = new Properties(); +serviceProperties.put("team", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("language", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("provider", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("version", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("group", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app.kubernetes.io/name", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app.kubernetes.io/version", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app.kubernetes.io/component", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app.kubernetes.io/managed-by", "via-resource-groovy-dsl-labels-service") +serviceProperties.put("app.kubernetes.io/part-of", "via-resource-groovy-dsl-labels-service") + def extensionConfig = { offline = true images { @@ -36,6 +62,14 @@ def extensionConfig = { } } } +if (project.hasProperty('labelsViaResourceConfig')) { + resources { + labels { + all = allProperties + service = serviceProperties + } + } +} } kubernetes(extensionConfig) diff --git a/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/kubernetes.yml b/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/kubernetes.yml new file mode 100644 index 0000000000..ba0515e75d --- /dev/null +++ b/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/kubernetes.yml @@ -0,0 +1,103 @@ +--- +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: Service + metadata: + annotations: + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-service + app.kubernetes.io/component: via-resource-groovy-dsl-labels-service + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-service + app.kubernetes.io/name: via-resource-groovy-dsl-labels-service + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-service + app.kubernetes.io/version: via-resource-groovy-dsl-labels-service + group: via-resource-groovy-dsl-labels-service + provider: via-resource-groovy-dsl-labels-service + version: via-resource-groovy-dsl-labels-service + name: well-known-labels + spec: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: via-resource-groovy-dsl-labels-service + app.kubernetes.io/component: via-resource-groovy-dsl-labels-service + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-service + app.kubernetes.io/name: via-resource-groovy-dsl-labels-service + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-service + group: via-resource-groovy-dsl-labels-service + provider: via-resource-groovy-dsl-labels-service +- apiVersion: apps/v1 + kind: Deployment + metadata: + annotations: + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + app.kubernetes.io/version: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + version: via-resource-groovy-dsl-labels-all + name: well-known-labels + spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + template: + metadata: + annotations: + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + app.kubernetes.io/version: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + version: via-resource-groovy-dsl-labels-all + name: well-known-labels + spec: + containers: + - env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: repository/well-known-labels:latest + imagePullPolicy: IfNotPresent + name: repository-well-known-labels + ports: + - containerPort: 8080 + name: http + protocol: TCP + securityContext: + privileged: false diff --git a/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/openshift.yml b/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/openshift.yml new file mode 100644 index 0000000000..b93be39e80 --- /dev/null +++ b/gradle-plugin/it/src/it/well-known-labels/expected/labelsViaResourceConfig/openshift.yml @@ -0,0 +1,144 @@ +--- +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: Service + metadata: + annotations: + app.openshift.io/vcs-ref: "@ignore@" + app.openshift.io/vcs-uri: "@ignore@" + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-service + app.kubernetes.io/component: via-resource-groovy-dsl-labels-service + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-service + app.kubernetes.io/name: via-resource-groovy-dsl-labels-service + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-service + app.kubernetes.io/version: via-resource-groovy-dsl-labels-service + group: via-resource-groovy-dsl-labels-service + provider: via-resource-groovy-dsl-labels-service + version: via-resource-groovy-dsl-labels-service + name: well-known-labels + spec: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: via-resource-groovy-dsl-labels-service + app.kubernetes.io/component: via-resource-groovy-dsl-labels-service + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-service + app.kubernetes.io/name: via-resource-groovy-dsl-labels-service + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-service + group: via-resource-groovy-dsl-labels-service + provider: via-resource-groovy-dsl-labels-service +- apiVersion: apps.openshift.io/v1 + kind: DeploymentConfig + metadata: + annotations: + app.openshift.io/vcs-ref: "@ignore@" + app.openshift.io/vcs-uri: "@ignore@" + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + app.kubernetes.io/version: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + version: via-resource-groovy-dsl-labels-all + name: well-known-labels + spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + strategy: + rollingParams: + timeoutSeconds: 3600 + type: Rolling + template: + metadata: + annotations: + app.openshift.io/vcs-ref: "@ignore@" + app.openshift.io/vcs-uri: "@ignore@" + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + app.kubernetes.io/version: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + version: via-resource-groovy-dsl-labels-all + name: well-known-labels + spec: + containers: + - env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: repository/well-known-labels:latest + imagePullPolicy: IfNotPresent + name: repository-well-known-labels + ports: + - containerPort: 8080 + name: http + protocol: TCP + securityContext: + privileged: false + triggers: + - type: ConfigChange + - imageChangeParams: + automatic: true + containerNames: + - repository-well-known-labels + from: + kind: ImageStreamTag + name: well-known-labels:latest + type: ImageChange +- apiVersion: route.openshift.io/v1 + kind: Route + metadata: + annotations: + app.openshift.io/vcs-ref: "@ignore@" + app.openshift.io/vcs-uri: "@ignore@" + jkube.eclipse.org/git-branch: "@ignore@" + jkube.eclipse.org/git-commit: "@ignore@" + jkube.eclipse.org/git-url: "@ignore@" + labels: + app: via-resource-groovy-dsl-labels-all + app.kubernetes.io/component: via-resource-groovy-dsl-labels-all + app.kubernetes.io/managed-by: via-resource-groovy-dsl-labels-all + app.kubernetes.io/name: via-resource-groovy-dsl-labels-all + app.kubernetes.io/part-of: via-resource-groovy-dsl-labels-all + app.kubernetes.io/version: via-resource-groovy-dsl-labels-all + group: via-resource-groovy-dsl-labels-all + provider: via-resource-groovy-dsl-labels-all + version: via-resource-groovy-dsl-labels-all + name: well-known-labels + spec: + port: + targetPort: 8080 + to: + kind: Service + name: well-known-labels diff --git a/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/WellKnownLabelsIT.java b/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/WellKnownLabelsIT.java index af44d3d3c8..62a8f770d9 100644 --- a/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/WellKnownLabelsIT.java +++ b/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/WellKnownLabelsIT.java @@ -43,7 +43,8 @@ static Stream data() { "-Pjkube.enricher.jkube-well-known-labels.component=custom-component", "-Pjkube.enricher.jkube-well-known-labels.partOf=custom-part-of", "-Pjkube.enricher.jkube-well-known-labels.managedBy=custom-managed-by", - }) + }), + arguments("labelsViaResourceConfig", new String[] {"-PlabelsViaResourceConfig=true"}) ); } diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java index dc6e6b75fa..0aba67da2e 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java @@ -42,23 +42,24 @@ public static void mergeIfAbsent(Map map, Map to } /** - * Returns a new map with all the entries of map1 and any from map2 which don't override map1. + * Returns a new map with all the entries of first map with rest map entries which don't override map1. * - * Can handle either maps being null. Always returns a new mutable map + * Can handle either maps being null. Always returns a new mutable map. * - * @param map1 first hash map - * @param map2 second hash map + * Note: Be careful about the ordering of maps passed here. First map passed in the var args + * would always be given precedence over other maps in case there are colliding entries with same key values. + * + * @param maps var arg for maps * @param first type * @param second type * @return merged hash map */ - public static Map mergeMaps(Map map1, Map map2) { + public static Map mergeMaps(Map ...maps) { Map answer = new HashMap<>(); - if (map2 != null) { - answer.putAll(map2); - } - if (map1 != null) { - answer.putAll(map1); + for (int i = maps.length-1; i >= 0; i--) { + if (maps[i] != null) { + answer.putAll(maps[i]); + } } return answer; diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java index 92b8b82f3d..ec2e6c7e37 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java @@ -29,31 +29,45 @@ import io.fabric8.openshift.api.model.DeploymentConfigBuilder; import io.fabric8.openshift.api.model.DeploymentConfigSpec; import org.eclipse.jkube.kit.common.util.MapUtil; +import org.eclipse.jkube.kit.common.util.PropertiesUtil; +import org.eclipse.jkube.kit.config.resource.MetaDataConfig; import org.eclipse.jkube.kit.config.resource.PlatformMode; +import org.eclipse.jkube.kit.config.resource.ResourceConfig; import org.eclipse.jkube.kit.enricher.api.BaseEnricher; import org.eclipse.jkube.kit.enricher.api.EnricherContext; +import org.eclipse.jkube.kit.enricher.api.model.Configuration; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Properties; + +import static org.eclipse.jkube.kit.common.util.PropertiesUtil.toMap; public abstract class AbstractLabelEnricher extends BaseEnricher { protected AbstractLabelEnricher(EnricherContext enricherContext, String name) { super(enricherContext, name); } - abstract Map createLabels(boolean withoutVersion); + abstract Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig); @Override + @SuppressWarnings("unchecked") public void create(PlatformMode platformMode, KubernetesListBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(ServiceBuilder serviceBuilder) { Map selectors = new HashMap<>(); + Map labelsConfiguredViaResourceConfig = MapUtil.mergeMaps( + toMap(getResourceConfigLabels().getService()), + toMap(getResourceConfigLabels().getAll())); if(serviceBuilder.buildSpec() != null && serviceBuilder.buildSpec().getSelector() != null) { selectors.putAll(serviceBuilder.buildSpec().getSelector()); } - MapUtil.mergeIfAbsent(selectors, createLabels(true)); + MapUtil.mergeIfAbsent(selectors, createLabels(true, labelsConfiguredViaResourceConfig)); serviceBuilder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -64,7 +78,10 @@ public void visit(DeploymentBuilder builder) { final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) .map(DeploymentSpec::getSelector) .map(LabelSelector::getMatchLabels) - .orElse(new HashMap<>())); + .orElse(new HashMap<>()), Arrays.asList( + getResourceConfigLabels().getDeployment(), + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll())); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -74,7 +91,9 @@ public void visit(DeploymentBuilder builder) { public void visit(DeploymentConfigBuilder builder) { final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) .map(DeploymentConfigSpec::getSelector) - .orElse(new HashMap<>())); + .orElse(new HashMap<>()), Arrays.asList( + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll())); builder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -83,10 +102,13 @@ public void visit(DeploymentConfigBuilder builder) { @Override public void visit(DaemonSetBuilder builder) { Map selectors = new HashMap<>(); + Map labelsFromResourceConfig = MapUtil.mergeMaps( + toMap(getResourceConfigLabels().getPod()), + toMap(getResourceConfigLabels().getAll())); if(builder.buildSpec() != null && builder.buildSpec().getSelector() != null && builder.buildSpec().getSelector().getMatchLabels() != null) { selectors.putAll(builder.buildSpec().getSelector().getMatchLabels()); } - MapUtil.mergeIfAbsent(selectors, createLabels(false)); + MapUtil.mergeIfAbsent(selectors, createLabels(false, labelsFromResourceConfig)); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -96,7 +118,9 @@ public void visit(DaemonSetBuilder builder) { public void visit(ReplicationControllerBuilder builder) { final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) .map(ReplicationControllerSpec::getSelector) - .orElse(new HashMap<>())); + .orElse(new HashMap<>()), Arrays.asList( + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll())); builder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -107,7 +131,10 @@ public void visit(ReplicaSetBuilder builder) { final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) .map(ReplicaSetSpec::getSelector) .map(LabelSelector::getMatchLabels) - .orElse(new HashMap<>())); + .orElse(new HashMap<>()), Arrays.asList( + getResourceConfigLabels().getReplicaSet(), + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll())); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -116,10 +143,13 @@ public void visit(ReplicaSetBuilder builder) { @Override public void visit(StatefulSetBuilder builder) { Map selectors = new HashMap<>(); + Map labelsFromResourceConfig = MapUtil.mergeMaps( + toMap(getResourceConfigLabels().getPod()), + toMap(getResourceConfigLabels().getAll())); if(builder.buildSpec() != null && builder.buildSpec().getSelector() != null && builder.buildSpec().getSelector().getMatchLabels() != null) { selectors.putAll(builder.buildSpec().getSelector().getMatchLabels()); } - MapUtil.mergeIfAbsent(selectors, createLabels(false)); + MapUtil.mergeIfAbsent(selectors, createLabels(false, labelsFromResourceConfig)); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -133,14 +163,25 @@ public void enrich(PlatformMode platformMode, KubernetesListBuilder builder) { @Override public void visit(ObjectMetaBuilder element) { Map labels = Optional.ofNullable(element.getLabels()).orElse(new HashMap<>()); - MapUtil.mergeIfAbsent(labels, createLabels(false)); + MapUtil.mergeIfAbsent(labels, createLabels(false, Collections.emptyMap())); element.withLabels(labels); } }); } - private Map mergedSelectors(Map originalSelectors) { - MapUtil.mergeIfAbsent(originalSelectors, createLabels(true)); + @SuppressWarnings("unchecked") + private Map mergedSelectors(Map originalSelectors, List labelPropertyList) { + Map labelsFromResourceConfig = MapUtil.mergeMaps(labelPropertyList.stream() + .map(PropertiesUtil::toMap) + .toArray(Map[]::new)); + MapUtil.mergeIfAbsent(originalSelectors, createLabels(true, labelsFromResourceConfig)); return originalSelectors; } + + protected MetaDataConfig getResourceConfigLabels() { + return Optional.ofNullable(getConfiguration()) + .map(Configuration::getResource) + .map(ResourceConfig::getLabels) + .orElse(MetaDataConfig.builder().build()); + } } diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java index c4b09bbf30..1e52df372d 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java @@ -15,7 +15,9 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import org.apache.commons.lang3.StringUtils; import org.eclipse.jkube.kit.common.Configs; import org.eclipse.jkube.kit.config.resource.GroupArtifactVersion; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; @@ -50,7 +52,7 @@ private enum Config implements Configs.Config { APP("app", null), GROUP("group", null), VERSION("version", null), - PROVIDER("provider", "jkube"); + PROVIDER(LABEL_PROVIDER, "jkube"); @Getter protected String key; @@ -63,22 +65,31 @@ public ProjectLabelEnricher(JKubeEnricherContext buildContext) { } @Override - public Map createLabels(boolean withoutVersion) { + public Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig) { Map ret = new HashMap<>(); boolean enableProjectLabel = Configs.asBoolean(getConfig(Config.USE_PROJECT_LABEL)); final GroupArtifactVersion groupArtifactVersion = getContext().getGav(); if (enableProjectLabel) { - ret.put("project", groupArtifactVersion.getArtifactId()); + ret.putAll(addProjectLabelFromApplicableSource(null, "project", groupArtifactVersion.getArtifactId(), labelsViaResourceConfig)); } else { - ret.put("app", getConfig(Config.APP, groupArtifactVersion.getArtifactId())); + ret.putAll(addProjectLabelFromApplicableSource(Config.APP, "app", groupArtifactVersion.getArtifactId(), labelsViaResourceConfig)); } - ret.put("group", getConfig(Config.GROUP, groupArtifactVersion.getGroupId())); - ret.put(LABEL_PROVIDER, getConfig(Config.PROVIDER)); + ret.putAll(addProjectLabelFromApplicableSource(Config.GROUP, "group", groupArtifactVersion.getGroupId(), labelsViaResourceConfig)); + ret.putAll(addProjectLabelFromApplicableSource(Config.PROVIDER, LABEL_PROVIDER, null, labelsViaResourceConfig)); if (!withoutVersion) { - ret.put("version", getConfig(Config.VERSION, groupArtifactVersion.getVersion())); + ret.putAll(addProjectLabelFromApplicableSource(Config.VERSION, "version", groupArtifactVersion.getVersion(), labelsViaResourceConfig)); } return ret; } + + private Map addProjectLabelFromApplicableSource(Configs.Config key, String labelKey, String defaultValue, Map labelsViaResourceConfig) { + Map entryMap = new HashMap<>(); + String appLabelValueFromConfig = Optional.ofNullable(key) + .map(k -> getConfig(k, defaultValue)) + .orElse(defaultValue); + entryMap.put(labelKey, labelsViaResourceConfig.getOrDefault(labelKey, appLabelValueFromConfig)); + return entryMap; + } } diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricher.java index da7fc9128a..b532a97354 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricher.java @@ -52,28 +52,31 @@ private boolean shouldAddWellKnownLabels() { } @Override - public Map createLabels(boolean withoutVersion) { + public Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig) { Map ret = new HashMap<>(); if (!shouldAddWellKnownLabels()) { return ret; } final GroupArtifactVersion groupArtifactVersion = getContext().getGav(); - ret.putAll(addWellKnownLabelFromConfig(Config.APP_NAME, "name", groupArtifactVersion.getArtifactId())); + ret.putAll(addWellKnownLabelFromApplicableSource(Config.APP_NAME, "name", groupArtifactVersion.getArtifactId(), labelsViaResourceConfig)); if (!withoutVersion) { - ret.putAll(addWellKnownLabelFromConfig(Config.APP_VERSION, "version", groupArtifactVersion.getVersion())); + ret.putAll(addWellKnownLabelFromApplicableSource(Config.APP_VERSION, "version", groupArtifactVersion.getVersion(), labelsViaResourceConfig)); } - ret.putAll(addWellKnownLabelFromConfig(Config.APP_PART_OF, "part-of", groupArtifactVersion.getGroupId())); - ret.putAll(addWellKnownLabelFromConfig(Config.APP_MANAGED_BY, "managed-by", "jkube")); - ret.putAll(addWellKnownLabelFromConfig(Config.APP_COMPONENT, "component", null)); + ret.putAll(addWellKnownLabelFromApplicableSource(Config.APP_PART_OF, "part-of", groupArtifactVersion.getGroupId(), labelsViaResourceConfig)); + ret.putAll(addWellKnownLabelFromApplicableSource(Config.APP_MANAGED_BY, "managed-by", "jkube", labelsViaResourceConfig)); + ret.putAll(addWellKnownLabelFromApplicableSource(Config.APP_COMPONENT, "component", null, labelsViaResourceConfig)); return ret; } - private Map addWellKnownLabelFromConfig(Configs.Config key, String labelKey, String defaultValue) { + private Map addWellKnownLabelFromApplicableSource(Configs.Config key, String labelKey, String defaultValue, Map labelsViaResourceConfig) { Map entryMap = new HashMap<>(); - String value = getConfig(key, defaultValue); - if (StringUtils.isNotBlank(value)) { - entryMap.put(KUBERNETES_APP_LABEL + labelKey, value); + String appLabel = KUBERNETES_APP_LABEL + labelKey; + String appLabelValueFromConfig = getConfig(key, defaultValue); + if (labelsViaResourceConfig.containsKey(appLabel)) { + entryMap.put(appLabel, labelsViaResourceConfig.get(appLabel)); + } else if (StringUtils.isNotBlank(appLabelValueFromConfig)) { + entryMap.put(appLabel, appLabelValueFromConfig); } return entryMap; } diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricherTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricherTest.java index 4ece1f1b91..4e4aa42816 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricherTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricherTest.java @@ -13,33 +13,34 @@ */ package org.eclipse.jkube.enricher.generic; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import java.util.Map; import java.util.Properties; -import io.fabric8.kubernetes.api.model.LabelSelector; -import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; -import io.fabric8.kubernetes.api.model.apps.StatefulSet; -import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder; -import io.fabric8.kubernetes.api.model.apps.StatefulSetSpec; -import org.assertj.core.api.InstanceOfAssertFactories; -import org.eclipse.jkube.kit.config.resource.GroupArtifactVersion; +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import org.eclipse.jkube.kit.common.JavaProject; +import org.eclipse.jkube.kit.config.resource.MetaDataConfig; import org.eclipse.jkube.kit.config.resource.PlatformMode; +import org.eclipse.jkube.kit.config.resource.ResourceConfig; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; + import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; +import io.fabric8.kubernetes.api.model.LabelSelector; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSetSpec; import io.fabric8.openshift.api.model.DeploymentConfigBuilder; +import org.assertj.core.api.InstanceOfAssertFactories; 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 static org.assertj.core.api.Assertions.assertThat; + /** * Test label generation. * @@ -49,14 +50,20 @@ class ProjectLabelEnricherTest { private Properties properties; private ProjectLabelEnricher projectLabelEnricher; + private JKubeEnricherContext context; @BeforeEach void setupExpectations() { - JKubeEnricherContext context = mock(JKubeEnricherContext.class, RETURNS_DEEP_STUBS); - projectLabelEnricher = new ProjectLabelEnricher(context); properties = new Properties(); - when(context.getProperties()).thenReturn(properties); - when(context.getGav()).thenReturn(new GroupArtifactVersion("groupId", "artifactId", "version")); + context = JKubeEnricherContext.builder() + .project(JavaProject.builder() + .properties(properties) + .groupId("groupId") + .artifactId("artifactId") + .version("version") + .build()) + .build(); + projectLabelEnricher = new ProjectLabelEnricher(context); } @Test @@ -211,6 +218,77 @@ void create_withConfiguredVersion_shouldAddConfiguredVersionInSelector() { .containsEntry("version", "0.0.1"); } + @Test + @DisplayName("when labels configured via resource config's labels > all, then use configured labels") + void create_whenProjectLabelConfiguredViaResourceConfigLabelAll_thenUseLabelsViaResourceConfig() { + // Given + Properties allLabels = new Properties(); + allLabels.put("app", "app-via-resource-config"); + allLabels.put("provider", "provider-via-resource-config"); + allLabels.put("group", "group-via-resource-config"); + context = context.toBuilder() + .resources(ResourceConfig.builder() + .labels(MetaDataConfig.builder() + .all(allLabels) + .build()) + .build()) + .build(); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder().withItems(new DeploymentBuilder().build()); + projectLabelEnricher = new ProjectLabelEnricher(context); + + // When + projectLabelEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + Deployment deployment = (Deployment) kubernetesListBuilder.buildFirstItem(); + assertThat(deployment) + .extracting("spec.selector.matchLabels") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app", "app-via-resource-config") + .containsEntry("provider", "provider-via-resource-config") + .containsEntry("group", "group-via-resource-config"); + } + + @Test + @DisplayName("when labels configured via resource config's labels > deployment, then use configured labels for Deployment only") + void create_whenProjectLabelConfiguredViaResourceConfigLabelForSpecificResource_thenUseLabelsViaResourceConfigForSpecificResourceOnly() { + // Given + Properties deploymentLabels = new Properties(); + deploymentLabels.put("app", "app-via-resource-config-labels-deployment"); + deploymentLabels.put("provider", "provider-via-resource-config-labels-deployment"); + deploymentLabels.put("group", "group-via-resource-config-labels-deployment"); + context = context.toBuilder() + .resources(ResourceConfig.builder() + .labels(MetaDataConfig.builder() + .deployment(deploymentLabels) + .build()) + .build()) + .build(); + KubernetesListBuilder kubernetesListBuilder = new KubernetesListBuilder() + .addToItems(new DeploymentBuilder().build()) + .addToItems(new ServiceBuilder().build()); + projectLabelEnricher = new ProjectLabelEnricher(context); + + // When + projectLabelEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + assertThat(kubernetesListBuilder.buildItems()) + .hasSize(2) + .satisfies(items -> assertThat(items.get(0)) + .extracting("spec.selector.matchLabels") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app", "app-via-resource-config-labels-deployment") + .containsEntry("provider", "provider-via-resource-config-labels-deployment") + .containsEntry("group", "group-via-resource-config-labels-deployment")) + .satisfies(items -> assertThat(items.get(1)) + .extracting("spec.selector") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app", "artifactId") + .containsEntry("group", "groupId") + .containsEntry("provider", "jkube")); + } + @Nested @DisplayName("enrich with") class Enrich { diff --git a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricherTest.java b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricherTest.java index 1fe01e2ff4..6629a3fd5a 100644 --- a/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricherTest.java +++ b/jkube-kit/enricher/generic/src/test/java/org/eclipse/jkube/enricher/generic/WellKnownLabelsEnricherTest.java @@ -26,7 +26,9 @@ import io.fabric8.openshift.api.model.DeploymentConfigBuilder; import org.assertj.core.api.InstanceOfAssertFactories; import org.eclipse.jkube.kit.common.JavaProject; +import org.eclipse.jkube.kit.config.resource.MetaDataConfig; import org.eclipse.jkube.kit.config.resource.PlatformMode; +import org.eclipse.jkube.kit.config.resource.ResourceConfig; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -46,11 +48,12 @@ class WellKnownLabelsEnricherTest { private WellKnownLabelsEnricher wellKnownLabelsEnricher; private Properties properties; private KubernetesListBuilder kubernetesListBuilder; + private JKubeEnricherContext context; @BeforeEach void setup() { properties = new Properties(); - JKubeEnricherContext context = JKubeEnricherContext.builder() + context = JKubeEnricherContext.builder() .project(JavaProject.builder() .groupId("org.example") .artifactId("test-project") @@ -139,6 +142,78 @@ void whenWellKnownLabelAlreadyPresent_thenDoNotOverwriteLabel() { .containsEntry("app.kubernetes.io/version", "1.0.0-already-present"); } + @Test + @DisplayName("when labels configured via resource config's labels > all, then use configured labels") + void whenWellKnownLabelConfiguredViaResourceConfigLabelAll_thenUseLabelsViaResourceConfig() { + // Given + Properties allLabels = new Properties(); + allLabels.put("app.kubernetes.io/part-of", "part-of-via-resource-config"); + allLabels.put("app.kubernetes.io/component", "component-via-resource-config"); + allLabels.put("app.kubernetes.io/managed-by", "managed-by-via-resource-config"); + allLabels.put("app.kubernetes.io/name", "name-via-resource-config"); + context = context.toBuilder() + .resources(ResourceConfig.builder() + .labels(MetaDataConfig.builder() + .all(allLabels) + .build()) + .build()) + .build(); + wellKnownLabelsEnricher = new WellKnownLabelsEnricher(context); + + // When + wellKnownLabelsEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + Deployment deployment = (Deployment) kubernetesListBuilder.buildFirstItem(); + assertThat(deployment) + .extracting("spec.selector.matchLabels") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app.kubernetes.io/part-of", "part-of-via-resource-config") + .containsEntry("app.kubernetes.io/component", "component-via-resource-config") + .containsEntry("app.kubernetes.io/managed-by", "managed-by-via-resource-config") + .containsEntry("app.kubernetes.io/name", "name-via-resource-config"); + } + + @Test + @DisplayName("when labels configured via resource config's labels > deployment, then use configured labels for Deployment only") + void whenWellKnownLabelConfiguredViaResourceConfigLabelForSpecificResource_thenUseLabelsViaResourceConfig() { + // Given + Properties deploymentLabels = new Properties(); + deploymentLabels.put("app.kubernetes.io/part-of", "part-of-via-resource-config-labels-deployment"); + deploymentLabels.put("app.kubernetes.io/component", "component-via-resource-config-labels-deployment"); + deploymentLabels.put("app.kubernetes.io/managed-by", "managed-by-via-resource-config-labels-deployment"); + deploymentLabels.put("app.kubernetes.io/name", "name-via-resource-config-labels-deployment"); + context = context.toBuilder() + .resources(ResourceConfig.builder() + .labels(MetaDataConfig.builder() + .deployment(deploymentLabels) + .build()) + .build()) + .build(); + kubernetesListBuilder.addToItems(new ServiceBuilder().build()); + wellKnownLabelsEnricher = new WellKnownLabelsEnricher(context); + + // When + wellKnownLabelsEnricher.create(PlatformMode.kubernetes, kubernetesListBuilder); + + // Then + assertThat(kubernetesListBuilder.buildItems()) + .hasSize(2) + .satisfies(items -> assertThat(items.get(0)) + .extracting("spec.selector.matchLabels") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app.kubernetes.io/part-of", "part-of-via-resource-config-labels-deployment") + .containsEntry("app.kubernetes.io/component", "component-via-resource-config-labels-deployment") + .containsEntry("app.kubernetes.io/managed-by", "managed-by-via-resource-config-labels-deployment") + .containsEntry("app.kubernetes.io/name", "name-via-resource-config-labels-deployment")) + .satisfies(items -> assertThat(items.get(1)) + .extracting("spec.selector") + .asInstanceOf(InstanceOfAssertFactories.MAP) + .containsEntry("app.kubernetes.io/part-of", "org.example") + .containsEntry("app.kubernetes.io/managed-by", "jkube") + .containsEntry("app.kubernetes.io/name", "test-project")); + } + @Test @DisplayName("labels provided via enricher configuration, then add labels") void whenLabelsProvidedViaEnricherConfiguration_thenAddLabels() { From 6cd411a6216a77a05f6da02e1ee979f9e9fa33ed Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Mon, 5 Feb 2024 11:31:05 +0100 Subject: [PATCH 15/24] review: Well Known Label Enricher Signed-off-by: Marc Nuri --- .../jkube/kit/common/util/MapUtil.java | 23 +++- .../generic/AbstractLabelEnricher.java | 115 +++++++++--------- .../generic/ProjectLabelEnricher.java | 5 +- .../generic/WellKnownLabelsEnricher.java | 4 +- 4 files changed, 82 insertions(+), 65 deletions(-) diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java index 0aba67da2e..f2657f2cea 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import java.util.function.BiFunction; public class MapUtil { @@ -54,7 +55,8 @@ public static void mergeIfAbsent(Map map, Map to * @param second type * @return merged hash map */ - public static Map mergeMaps(Map ...maps) { + @SafeVarargs + public static Map mergeMaps(Map... maps) { Map answer = new HashMap<>(); for (int i = maps.length-1; i >= 0; i--) { if (maps[i] != null) { @@ -65,6 +67,25 @@ public static Map mergeMaps(Map ...maps) { } + /** + * Returns a new map with all the entries the provided properties merged. + * + * The first arguments take precedence over the later ones. + * i.e. properties defined in the last argument will not override properties defined in the first argument. + * + * @param properties var arg for properties + * @return merged hash map + */ + public static Map mergeMaps(Properties... properties) { + Map answer = new HashMap<>(); + for (int i = properties.length-1; i >= 0; i--) { + if (properties[i] != null) { + answer.putAll(PropertiesUtil.toMap(properties[i])); + } + } + return answer; + } + /** * Copies all the elements i.e., the mappings, from toPut map into ret, if toPut isn't null. * @param ret target hash map diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java index ec2e6c7e37..3ed6f0e2f5 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/AbstractLabelEnricher.java @@ -16,20 +16,23 @@ import io.fabric8.kubernetes.api.builder.TypedVisitor; import io.fabric8.kubernetes.api.model.KubernetesListBuilder; import io.fabric8.kubernetes.api.model.LabelSelector; +import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.ReplicationControllerBuilder; import io.fabric8.kubernetes.api.model.ReplicationControllerSpec; import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.api.model.ServiceSpec; import io.fabric8.kubernetes.api.model.apps.DaemonSetBuilder; +import io.fabric8.kubernetes.api.model.apps.DaemonSetSpec; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; import io.fabric8.kubernetes.api.model.apps.ReplicaSetBuilder; import io.fabric8.kubernetes.api.model.apps.ReplicaSetSpec; import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSetSpec; import io.fabric8.openshift.api.model.DeploymentConfigBuilder; import io.fabric8.openshift.api.model.DeploymentConfigSpec; import org.eclipse.jkube.kit.common.util.MapUtil; -import org.eclipse.jkube.kit.common.util.PropertiesUtil; import org.eclipse.jkube.kit.config.resource.MetaDataConfig; import org.eclipse.jkube.kit.config.resource.PlatformMode; import org.eclipse.jkube.kit.config.resource.ResourceConfig; @@ -37,37 +40,29 @@ import org.eclipse.jkube.kit.enricher.api.EnricherContext; import org.eclipse.jkube.kit.enricher.api.model.Configuration; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; -import static org.eclipse.jkube.kit.common.util.PropertiesUtil.toMap; - public abstract class AbstractLabelEnricher extends BaseEnricher { protected AbstractLabelEnricher(EnricherContext enricherContext, String name) { super(enricherContext, name); } - abstract Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig); + abstract Map createLabels(boolean includeVersion, Map labelsViaResourceConfig); @Override - @SuppressWarnings("unchecked") public void create(PlatformMode platformMode, KubernetesListBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(ServiceBuilder serviceBuilder) { - Map selectors = new HashMap<>(); - Map labelsConfiguredViaResourceConfig = MapUtil.mergeMaps( - toMap(getResourceConfigLabels().getService()), - toMap(getResourceConfigLabels().getAll())); - if(serviceBuilder.buildSpec() != null && serviceBuilder.buildSpec().getSelector() != null) { - selectors.putAll(serviceBuilder.buildSpec().getSelector()); - } - MapUtil.mergeIfAbsent(selectors, createLabels(true, labelsConfiguredViaResourceConfig)); + final Map selectors = processSelectors( + Optional.ofNullable(serviceBuilder.buildSpec()) + .map(ServiceSpec::getSelector) + .orElse(new HashMap<>()), + false, + getResourceConfigLabels().getService(),getResourceConfigLabels().getAll()); serviceBuilder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -75,13 +70,15 @@ public void visit(ServiceBuilder serviceBuilder) { builder.accept(new TypedVisitor() { @Override public void visit(DeploymentBuilder builder) { - final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) .map(DeploymentSpec::getSelector) .map(LabelSelector::getMatchLabels) - .orElse(new HashMap<>()), Arrays.asList( - getResourceConfigLabels().getDeployment(), - getResourceConfigLabels().getPod(), - getResourceConfigLabels().getAll())); + .orElse(new HashMap<>()), + false, + getResourceConfigLabels().getDeployment(), + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll()); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -89,11 +86,12 @@ public void visit(DeploymentBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(DeploymentConfigBuilder builder) { - final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) .map(DeploymentConfigSpec::getSelector) - .orElse(new HashMap<>()), Arrays.asList( - getResourceConfigLabels().getPod(), - getResourceConfigLabels().getAll())); + .orElse(new HashMap<>()), + false, + getResourceConfigLabels().getPod(), getResourceConfigLabels().getAll()); builder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -101,14 +99,12 @@ public void visit(DeploymentConfigBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(DaemonSetBuilder builder) { - Map selectors = new HashMap<>(); - Map labelsFromResourceConfig = MapUtil.mergeMaps( - toMap(getResourceConfigLabels().getPod()), - toMap(getResourceConfigLabels().getAll())); - if(builder.buildSpec() != null && builder.buildSpec().getSelector() != null && builder.buildSpec().getSelector().getMatchLabels() != null) { - selectors.putAll(builder.buildSpec().getSelector().getMatchLabels()); - } - MapUtil.mergeIfAbsent(selectors, createLabels(false, labelsFromResourceConfig)); + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) + .map(DaemonSetSpec::getSelector) + .map(LabelSelector::getMatchLabels) + .orElse(new HashMap<>()), + true, getResourceConfigLabels().getAll()); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -116,11 +112,12 @@ public void visit(DaemonSetBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(ReplicationControllerBuilder builder) { - final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) .map(ReplicationControllerSpec::getSelector) - .orElse(new HashMap<>()), Arrays.asList( - getResourceConfigLabels().getPod(), - getResourceConfigLabels().getAll())); + .orElse(new HashMap<>()), + false, + getResourceConfigLabels().getPod(), getResourceConfigLabels().getAll()); builder.editOrNewSpec().addToSelector(selectors).endSpec(); } }); @@ -128,13 +125,15 @@ public void visit(ReplicationControllerBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(ReplicaSetBuilder builder) { - final Map selectors = mergedSelectors(Optional.ofNullable(builder.buildSpec()) + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) .map(ReplicaSetSpec::getSelector) .map(LabelSelector::getMatchLabels) - .orElse(new HashMap<>()), Arrays.asList( - getResourceConfigLabels().getReplicaSet(), - getResourceConfigLabels().getPod(), - getResourceConfigLabels().getAll())); + .orElse(new HashMap<>()), + false, + getResourceConfigLabels().getReplicaSet(), + getResourceConfigLabels().getPod(), + getResourceConfigLabels().getAll()); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -142,14 +141,13 @@ public void visit(ReplicaSetBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(StatefulSetBuilder builder) { - Map selectors = new HashMap<>(); - Map labelsFromResourceConfig = MapUtil.mergeMaps( - toMap(getResourceConfigLabels().getPod()), - toMap(getResourceConfigLabels().getAll())); - if(builder.buildSpec() != null && builder.buildSpec().getSelector() != null && builder.buildSpec().getSelector().getMatchLabels() != null) { - selectors.putAll(builder.buildSpec().getSelector().getMatchLabels()); - } - MapUtil.mergeIfAbsent(selectors, createLabels(false, labelsFromResourceConfig)); + final Map selectors = processSelectors( + Optional.ofNullable(builder.buildSpec()) + .map(StatefulSetSpec::getSelector) + .map(LabelSelector::getMatchLabels) + .orElse(new HashMap<>()), + true, + getResourceConfigLabels().getPod(), getResourceConfigLabels().getAll()); builder.editOrNewSpec().editOrNewSelector().withMatchLabels(selectors).endSelector().endSpec(); } }); @@ -162,20 +160,19 @@ public void enrich(PlatformMode platformMode, KubernetesListBuilder builder) { builder.accept(new TypedVisitor() { @Override public void visit(ObjectMetaBuilder element) { - Map labels = Optional.ofNullable(element.getLabels()).orElse(new HashMap<>()); - MapUtil.mergeIfAbsent(labels, createLabels(false, Collections.emptyMap())); + final Map labels = processSelectors( + Optional.ofNullable(element.build()) + .map(ObjectMeta::getLabels) + .orElse(new HashMap<>()), + true); element.withLabels(labels); } }); } - @SuppressWarnings("unchecked") - private Map mergedSelectors(Map originalSelectors, List labelPropertyList) { - Map labelsFromResourceConfig = MapUtil.mergeMaps(labelPropertyList.stream() - .map(PropertiesUtil::toMap) - .toArray(Map[]::new)); - MapUtil.mergeIfAbsent(originalSelectors, createLabels(true, labelsFromResourceConfig)); - return originalSelectors; + private Map processSelectors(Map selectors, boolean includeVersion, Properties... labelPropertyList) { + MapUtil.mergeIfAbsent(selectors, createLabels(includeVersion, MapUtil.mergeMaps(labelPropertyList))); + return selectors; } protected MetaDataConfig getResourceConfigLabels() { diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java index 1e52df372d..3dcab80722 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/ProjectLabelEnricher.java @@ -17,7 +17,6 @@ import java.util.Map; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; import org.eclipse.jkube.kit.common.Configs; import org.eclipse.jkube.kit.config.resource.GroupArtifactVersion; import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext; @@ -65,7 +64,7 @@ public ProjectLabelEnricher(JKubeEnricherContext buildContext) { } @Override - public Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig) { + public Map createLabels(boolean includeVersion, Map labelsViaResourceConfig) { Map ret = new HashMap<>(); boolean enableProjectLabel = Configs.asBoolean(getConfig(Config.USE_PROJECT_LABEL)); @@ -78,7 +77,7 @@ public Map createLabels(boolean withoutVersion, Map createLabels(boolean withoutVersion, Map labelsViaResourceConfig) { + public Map createLabels(boolean includeVersion, Map labelsViaResourceConfig) { Map ret = new HashMap<>(); if (!shouldAddWellKnownLabels()) { return ret; @@ -60,7 +60,7 @@ public Map createLabels(boolean withoutVersion, Map Date: Mon, 5 Feb 2024 21:41:11 +0530 Subject: [PATCH 16/24] SecretEnricher getSecretsFromXmlConfig should return Collections.emptyList() instead of null (#2610) --- .../java/org/eclipse/jkube/enricher/generic/SecretEnricher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java index 9fcb8764b0..2ce9cada8e 100644 --- a/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java +++ b/jkube-kit/enricher/generic/src/main/java/org/eclipse/jkube/enricher/generic/SecretEnricher.java @@ -78,7 +78,7 @@ private void addSecretsFromXmlConfiguration(KubernetesListBuilder builder) { log.verbose("Adding secrets resources from plugin configuration"); List secrets = getSecretsFromXmlConfig(); Map secretToIndexMap = new HashMap<>(); - if (secrets == null || secrets.isEmpty()) { + if (secrets.isEmpty()) { return; } From c1629937d049884c793fe231000fef81e5ca4d83 Mon Sep 17 00:00:00 2001 From: Prashantkumar Khatri <96608160+ShantKhatri@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:12:26 +0530 Subject: [PATCH 17/24] fix(quickstarts/maven): Removed unused run configuration (#2620) --- quickstarts/maven/hello-world/pom.xml | 5 ----- quickstarts/maven/tomee/pom.xml | 5 ----- 2 files changed, 10 deletions(-) diff --git a/quickstarts/maven/hello-world/pom.xml b/quickstarts/maven/hello-world/pom.xml index 045065bcf8..8aa072e3bb 100644 --- a/quickstarts/maven/hello-world/pom.xml +++ b/quickstarts/maven/hello-world/pom.xml @@ -78,11 +78,6 @@ openjdk:latest java -jar maven/${project.artifactId}-${project.version}.jar - - - Hello World! - - diff --git a/quickstarts/maven/tomee/pom.xml b/quickstarts/maven/tomee/pom.xml index f6fe601689..f6a9b17b64 100644 --- a/quickstarts/maven/tomee/pom.xml +++ b/quickstarts/maven/tomee/pom.xml @@ -158,11 +158,6 @@ java -jar maven/${project.artifactId}-exec.jar - - - ${tomee.port}:${tomee.port} - - From d38642f75ba3891299cc96f457ac6d9d6637a642 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Wed, 31 Jan 2024 18:32:47 +0530 Subject: [PATCH 18/24] test : Add TestHttpBuildPackArtifactsServer in jkube-kit/common Add TestHttpBuildPackArtifactsServer to host build pack download artifacts so that this test utility class can be reused in dependent modules Signed-off-by: Rohan Kumar --- .../service/buildpacks/AbstractBuildPackCliDownloaderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java index 3d29742861..84e2ccafe9 100644 --- a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java +++ b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java @@ -55,7 +55,7 @@ abstract class AbstractBuildPackCliDownloaderTest { abstract String getProcessorArchitecture(); @BeforeEach - void setUp() { + void setUp() throws IOException { kitLogger = spy(new KitLogger.SilentLogger()); Map overriddenSystemProperties = new HashMap<>(); Map overriddenEnvironmentVariables = new HashMap<>(); From 0db5ccec0dfa5b224870ec4c0ba43a096d1df2cf Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Wed, 6 Dec 2023 20:51:45 +0530 Subject: [PATCH 19/24] feat (jkube-kit/config/service) : Add BuildPackBuildService (#2493) + 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 --- .../buildpacks/BuildPackCliDownloader.java | 5 + .../AbstractBuildPackCliDownloaderTest.java | 2 +- .../image/build/JKubeBuildStrategy.java | 7 +- jkube-kit/config/service/pom.xml | 4 + .../kubernetes/BuildPackBuildService.java | 119 +++++++++++ .../resources/META-INF/jkube/build-service | 1 + .../JKubeServiceHubBuildServiceTest.java | 2 + .../kubernetes/BuildPackBuildServiceTest.java | 189 ++++++++++++++++++ jkube-kit/parent/pom.xml | 6 + 9 files changed, 333 insertions(+), 2 deletions(-) create mode 100644 jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java create mode 100644 jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java diff --git a/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java b/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java index 44ae9054ae..51d553366f 100644 --- a/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java +++ b/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java @@ -16,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.jkube.kit.common.KitLogger; import org.eclipse.jkube.kit.common.util.FileUtil; +import org.eclipse.jkube.kit.common.util.PropertiesUtil; import java.io.File; import java.io.IOException; @@ -51,6 +52,10 @@ public class BuildPackCliDownloader { private final Properties packProperties; private final File jKubeUserHomeDir; + public BuildPackCliDownloader(KitLogger kitLogger) { + this(kitLogger, PropertiesUtil.getPropertiesFromResource(BuildPackCliDownloader.class.getResource("/META-INF/jkube/pack-cli.properties"))); + } + public BuildPackCliDownloader(KitLogger kitLogger, Properties packProperties) { this.kitLogger = kitLogger; this.packProperties = packProperties; diff --git a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java index 84e2ccafe9..3d29742861 100644 --- a/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java +++ b/jkube-kit/build/service/buildpacks/src/test/java/org/eclipse/jkube/kit/service/buildpacks/AbstractBuildPackCliDownloaderTest.java @@ -55,7 +55,7 @@ abstract class AbstractBuildPackCliDownloaderTest { abstract String getProcessorArchitecture(); @BeforeEach - void setUp() throws IOException { + void setUp() { kitLogger = spy(new KitLogger.SilentLogger()); Map overriddenSystemProperties = new HashMap<>(); Map overriddenEnvironmentVariables = new HashMap<>(); diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/build/JKubeBuildStrategy.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/build/JKubeBuildStrategy.java index 9bacd48741..5e2eee6e45 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/build/JKubeBuildStrategy.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/build/JKubeBuildStrategy.java @@ -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 { diff --git a/jkube-kit/config/service/pom.xml b/jkube-kit/config/service/pom.xml index 7a52f9ccc5..8c675da014 100644 --- a/jkube-kit/config/service/pom.xml +++ b/jkube-kit/config/service/pom.xml @@ -41,6 +41,10 @@ org.eclipse.jkube jkube-kit-build-service-jib + + org.eclipse.jkube + jkube-kit-build-service-buildpacks + org.eclipse.jkube jkube-kit-helm diff --git a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java new file mode 100644 index 0000000000..a2e6c253eb --- /dev/null +++ b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java @@ -0,0 +1,119 @@ +/* + * 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 BuildPackCliDownloader buildPackCliDownloader; + + public BuildPackBuildService(JKubeServiceHub jKubeServiceHub) { + this(jKubeServiceHub, null); + } + + BuildPackBuildService(JKubeServiceHub jKubeServiceHub, Properties packProperties) { + super(jKubeServiceHub); + this.buildServiceConfig = Objects.requireNonNull(jKubeServiceHub.getBuildServiceConfig(), + "BuildServiceConfig is required"); + this.kitLogger = Objects.requireNonNull(jKubeServiceHub.getLog()); + if (packProperties == null) { + this.buildPackCliDownloader = new BuildPackCliDownloader(kitLogger); + } else { + this.buildPackCliDownloader = new BuildPackCliDownloader(kitLogger, packProperties); + } + } + + @Override + protected void buildSingleImage(ImageConfiguration imageConfiguration) { + kitLogger.info("Delegating container image building process to BuildPacks"); + File packCli = buildPackCliDownloader.getPackCLIIfPresentOrDownload(); + kitLogger.info("Using pack %s", packCli.getAbsolutePath()); + BuildPackCliController packCliController = new BuildPackCliController(packCli, kitLogger); + + packCliController.build(BuildPackBuildOptions.builder() + .imageName(imageConfiguration.getName()) + .builderImage(resolveBuildPackBuilderImage()) + .creationTime("now") + .build()); + } + + private String resolveBuildPackBuilderImage() { + File localPackConfig = resolveLocalPackConfig(); + + if (localPackConfig != null && localPackConfig.exists()) { + Properties localPackConfigAsProperties = readLocalPackConfig(localPackConfig); + if (localPackConfigAsProperties.get("default-builder-image") != null) { + return strip(localPackConfigAsProperties.getProperty("default-builder-image"), "\""); + } + } + return DEFAULT_BUILDER_IMAGE; + } + + private Properties readLocalPackConfig(File packConfig) { + try { + return PropertiesUtil.getPropertiesFromResource(packConfig.toURI().toURL()); + } catch (MalformedURLException e) { + kitLogger.warn("Failure in reading pack local configuration : " + e.getMessage()); + } + return new Properties(); + } + + private File resolveLocalPackConfig() { + File packConfigDir = new File(EnvUtil.getUserHome(), PACK_CONFIG_DIR); + if (packConfigDir.exists() && packConfigDir.isDirectory()) { + return new File(packConfigDir, PACK_CONFIG_FILE); + } + return null; + } + + @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 + } +} diff --git a/jkube-kit/config/service/src/main/resources/META-INF/jkube/build-service b/jkube-kit/config/service/src/main/resources/META-INF/jkube/build-service index 2922021448..cb5f809098 100644 --- a/jkube-kit/config/service/src/main/resources/META-INF/jkube/build-service +++ b/jkube-kit/config/service/src/main/resources/META-INF/jkube/build-service @@ -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 \ No newline at end of file diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/JKubeServiceHubBuildServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/JKubeServiceHubBuildServiceTest.java index 0472df2b47..9df6805012 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/JKubeServiceHubBuildServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/JKubeServiceHubBuildServiceTest.java @@ -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; @@ -42,6 +43,7 @@ static Stream 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), diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java new file mode 100644 index 0000000000..8e92d0048f --- /dev/null +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java @@ -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 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 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"); + } + } + } +} diff --git a/jkube-kit/parent/pom.xml b/jkube-kit/parent/pom.xml index a760afcbbf..90ac7f4c1f 100644 --- a/jkube-kit/parent/pom.xml +++ b/jkube-kit/parent/pom.xml @@ -215,6 +215,12 @@ ${project.version} + + org.eclipse.jkube + jkube-kit-build-service-buildpacks + ${project.version} + + org.eclipse.jkube jkube-kit-watcher-api From 005241e908ef0cd030f53b69f0f63456623aa46a Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Mon, 5 Feb 2024 17:41:03 +0100 Subject: [PATCH 20/24] review: BuildPackBuildService Signed-off-by: Marc Nuri --- .../buildpacks/BuildPackCliDownloader.java | 13 +++-- .../jkube/kit/common/util/PropertiesUtil.java | 14 +++++ .../kubernetes/BuildPackBuildService.java | 55 ++++++------------- .../kubernetes/BuildPackBuildServiceTest.java | 3 +- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java b/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java index 51d553366f..af6082ec84 100644 --- a/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java +++ b/jkube-kit/build/service/buildpacks/src/main/java/org/eclipse/jkube/kit/service/buildpacks/BuildPackCliDownloader.java @@ -53,13 +53,18 @@ public class BuildPackCliDownloader { private final File jKubeUserHomeDir; public BuildPackCliDownloader(KitLogger kitLogger) { - this(kitLogger, PropertiesUtil.getPropertiesFromResource(BuildPackCliDownloader.class.getResource("/META-INF/jkube/pack-cli.properties"))); + this(kitLogger, null); } public BuildPackCliDownloader(KitLogger kitLogger, Properties packProperties) { this.kitLogger = kitLogger; - this.packProperties = packProperties; - packCliVersion = (String) packProperties.get(PACK_DEFAULT_CLI_VERSION_PROPERTY); + if (packProperties != null) { + this.packProperties = packProperties; + } else { + this.packProperties = PropertiesUtil + .getPropertiesFromResource(BuildPackCliDownloader.class.getResource("/META-INF/jkube/pack-cli.properties")); + } + packCliVersion = this.packProperties.getProperty(PACK_DEFAULT_CLI_VERSION_PROPERTY); jKubeUserHomeDir = new File(getUserHome(), JKUBE_PACK_DIR); } @@ -146,4 +151,4 @@ private Path resolveBinaryLocation() { } return jKubeUserHomeDir.toPath().resolve(binaryName); } -} \ No newline at end of file +} diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/PropertiesUtil.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/PropertiesUtil.java index eae78aa7e7..350cc49730 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/PropertiesUtil.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/PropertiesUtil.java @@ -18,6 +18,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -46,6 +48,18 @@ public static Properties getPropertiesFromResource(URL resource) { return ret; } + public static Properties readProperties(Path properties) { + final Properties ret = new Properties(); + if (properties != null && properties.toFile().exists() && properties.toFile().isFile()) { + try (InputStream stream = Files.newInputStream(properties)) { + ret.load(stream); + } catch (IOException e) { + throw new IllegalStateException("Error while reading properties from file " + properties, e); + } + } + return ret; + } + /** * Return first Non-Null set property from a set of provided properties * diff --git a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java index a2e6c253eb..737130a1f0 100644 --- a/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java +++ b/jkube-kit/config/service/src/main/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildService.java @@ -14,25 +14,23 @@ 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; +import static org.eclipse.jkube.kit.common.util.EnvUtil.getUserHome; +import static org.eclipse.jkube.kit.common.util.PropertiesUtil.readProperties; public class BuildPackBuildService extends AbstractImageBuildService { private static final String DEFAULT_BUILDER_IMAGE = "paketobuildpacks/builder:base"; @@ -62,48 +60,27 @@ public BuildPackBuildService(JKubeServiceHub jKubeServiceHub) { @Override protected void buildSingleImage(ImageConfiguration imageConfiguration) { kitLogger.info("Delegating container image building process to BuildPacks"); - File packCli = buildPackCliDownloader.getPackCLIIfPresentOrDownload(); + final File packCli = buildPackCliDownloader.getPackCLIIfPresentOrDownload(); kitLogger.info("Using pack %s", packCli.getAbsolutePath()); - BuildPackCliController packCliController = new BuildPackCliController(packCli, kitLogger); - - packCliController.build(BuildPackBuildOptions.builder() + final String builderImage; + final Properties localPackConfig = + readProperties(getUserHome().toPath().resolve(PACK_CONFIG_DIR).resolve(PACK_CONFIG_FILE)); + if (localPackConfig.get("default-builder-image") != null) { + builderImage = strip(localPackConfig.getProperty("default-builder-image"), "\""); + } else { + builderImage = DEFAULT_BUILDER_IMAGE; + } + new BuildPackCliController(packCli, kitLogger) + .build(BuildPackBuildOptions.builder() .imageName(imageConfiguration.getName()) - .builderImage(resolveBuildPackBuilderImage()) + .builderImage(builderImage) .creationTime("now") .build()); } - private String resolveBuildPackBuilderImage() { - File localPackConfig = resolveLocalPackConfig(); - - if (localPackConfig != null && localPackConfig.exists()) { - Properties localPackConfigAsProperties = readLocalPackConfig(localPackConfig); - if (localPackConfigAsProperties.get("default-builder-image") != null) { - return strip(localPackConfigAsProperties.getProperty("default-builder-image"), "\""); - } - } - return DEFAULT_BUILDER_IMAGE; - } - - private Properties readLocalPackConfig(File packConfig) { - try { - return PropertiesUtil.getPropertiesFromResource(packConfig.toURI().toURL()); - } catch (MalformedURLException e) { - kitLogger.warn("Failure in reading pack local configuration : " + e.getMessage()); - } - return new Properties(); - } - - private File resolveLocalPackConfig() { - File packConfigDir = new File(EnvUtil.getUserHome(), PACK_CONFIG_DIR); - if (packConfigDir.exists() && packConfigDir.isDirectory()) { - return new File(packConfigDir, PACK_CONFIG_FILE); - } - return null; - } - @Override - protected void pushSingleImage(ImageConfiguration imageConfiguration, int retries, RegistryConfig registryConfig, boolean skipTag) throws JKubeServiceException { + protected void pushSingleImage(ImageConfiguration imageConfiguration, int retries, RegistryConfig registryConfig, boolean skipTag) { + // NO OP } @Override diff --git a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java index 8e92d0048f..012df0a00d 100644 --- a/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java +++ b/jkube-kit/config/service/src/test/java/org/eclipse/jkube/kit/config/service/kubernetes/BuildPackBuildServiceTest.java @@ -45,9 +45,10 @@ import static org.mockito.Mockito.verify; class BuildPackBuildServiceTest { + + private static final String TEST_PACK_VERSION = "v0.32.1"; private KitLogger kitLogger; private JKubeServiceHub jKubeServiceHub; - private static final String TEST_PACK_VERSION = "v0.32.1"; private ImageConfiguration imageConfiguration; private BuildServiceConfig buildServiceConfig; From 13e01f889f4985344e619180d09b080db362be1e Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Mon, 5 Feb 2024 13:57:52 +0100 Subject: [PATCH 21/24] feat: HelmService provides linting features Signed-off-by: Marc Nuri --- .../jkube/kit/common/JKubeException.java | 22 ++ jkube-kit/helm/pom.xml | 4 + .../jkube/kit/resource/helm/HelmConfig.java | 3 + .../jkube/kit/resource/helm/HelmService.java | 49 +++- .../kit/resource/helm/HelmServiceUtil.java | 13 ++ .../kit/resource/helm/HelmServiceLintIT.java | 218 ++++++++++++++++++ .../resource/helm/HelmServiceUtilTest.java | 25 +- 7 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/JKubeException.java create mode 100644 jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceLintIT.java diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/JKubeException.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/JKubeException.java new file mode 100644 index 0000000000..16748c6b38 --- /dev/null +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/JKubeException.java @@ -0,0 +1,22 @@ +/* + * 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.common; + +public class JKubeException extends RuntimeException { + + public JKubeException(String message) { + super(message); + } + +} diff --git a/jkube-kit/helm/pom.xml b/jkube-kit/helm/pom.xml index 72a9b264e9..38e267f188 100644 --- a/jkube-kit/helm/pom.xml +++ b/jkube-kit/helm/pom.xml @@ -42,6 +42,10 @@ commons-codec commons-codec + + com.marcnuri.helm-java + helm-java + org.eclipse.jkube diff --git a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmConfig.java b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmConfig.java index b6b35a1d25..a35a3ac841 100644 --- a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmConfig.java +++ b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmConfig.java @@ -71,6 +71,9 @@ public class HelmConfig { private HelmRepository stableRepository; private HelmRepository snapshotRepository; private String security; + private boolean lintStrict; + private boolean lintQuiet; + @JsonProperty("dependencies") private List dependencies; diff --git a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java index 7606de43c4..391787a32b 100644 --- a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java +++ b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmService.java @@ -16,6 +16,8 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -28,7 +30,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.marcnuri.helm.Helm; +import com.marcnuri.helm.LintCommand; +import com.marcnuri.helm.LintResult; import org.eclipse.jkube.kit.common.JKubeConfiguration; +import org.eclipse.jkube.kit.common.JKubeException; import org.eclipse.jkube.kit.common.KitLogger; import org.eclipse.jkube.kit.common.RegistryConfig; import org.eclipse.jkube.kit.common.RegistryServerConfiguration; @@ -155,6 +161,34 @@ public void uploadHelmChart(HelmConfig helm) throws BadUploadException, IOExcept } } + public void lint(HelmConfig helmConfig) { + for (HelmConfig.HelmType helmType : helmConfig.getTypes()) { + final Path helmPackage = resolveTarballFile(helmConfig, helmType); + logger.info("Linting %s %s", helmConfig.getChart(), helmConfig.getVersion()); + logger.info("Using packaged file: %s", helmPackage.toFile().getAbsolutePath()); + final LintCommand lintCommand = new Helm(helmPackage).lint(); + if (helmConfig.isLintStrict()) { + lintCommand.strict(); + } + if (helmConfig.isLintQuiet()) { + lintCommand.quiet(); + } + final LintResult lintResult = lintCommand.call(); + if (lintResult.isFailed()) { + for (String message : lintResult.getMessages()) { + // [[W]] see AnsiUtil.COLOR_MAP and computeEmphasisColor to understand the color guides + logger.error("[[W]]%s", message); + } + throw new JKubeException("Linting failed"); + } else { + for (String message : lintResult.getMessages()) { + logger.info("[[W]]%s", message); + } + logger.info("Linting successful"); + } + } + } + private void uploadHelmChart(HelmConfig helmConfig, HelmRepository helmRepository) throws IOException, BadUploadException { @@ -162,18 +196,17 @@ private void uploadHelmChart(HelmConfig helmConfig, HelmRepository helmRepositor for (HelmConfig.HelmType helmType : helmConfig.getTypes()) { logger.info("Uploading Helm Chart \"%s\" to %s", helmConfig.getChart(), helmRepository.getName()); logger.debug("OutputDir: %s", helmConfig.getOutputDir()); - - final File tarballOutputDir = - new File(Objects.requireNonNull(helmConfig.getTarballOutputDir(), - "Tarball output directory is required"), helmType.getOutputDir()); - final File tarballFile = new File(tarballOutputDir, String.format("%s-%s%s.%s", - helmConfig.getChart(), helmConfig.getVersion(), resolveHelmClassifier(helmConfig), helmConfig.getChartExtension())); - - helmUploaderManager.getHelmUploader(helmRepository.getType()).uploadSingle(tarballFile, helmRepository); + helmUploaderManager.getHelmUploader(helmRepository.getType()) + .uploadSingle(resolveTarballFile(helmConfig, helmType).toFile(), helmRepository); logger.info("Upload Successful"); } } + private static Path resolveTarballFile(HelmConfig helmConfig, HelmConfig.HelmType helmType) { + return Paths.get(Objects.requireNonNull(helmConfig.getTarballOutputDir(), "Tarball output directory is required")) + .resolve(helmType.getOutputDir()) + .resolve(String.format("%s-%s%s.%s", helmConfig.getChart(), helmConfig.getVersion(), resolveHelmClassifier(helmConfig), helmConfig.getChartExtension())); + } static File prepareSourceDir(HelmConfig helmConfig, HelmConfig.HelmType type) throws IOException { final File sourceDir = new File(helmConfig.getSourceDir(), type.getSourceDir()); diff --git a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtil.java b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtil.java index dee59cf17a..d29d669616 100644 --- a/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtil.java +++ b/jkube-kit/helm/src/main/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtil.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -73,6 +74,9 @@ public class HelmServiceUtil { protected static final String PROPERTY_SECURITY = "jkube.helm.security"; protected static final String DEFAULT_SECURITY = "~/.m2/settings-security.xml"; + protected static final String PROPERTY_HELM_LINT_STRICT = "jkube.helm.lint.strict"; + protected static final String PROPERTY_HELM_LINT_QUIET = "jkube.helm.lint.quiet"; + private HelmServiceUtil() { } public static HelmConfig.HelmConfigBuilder initHelmConfig( @@ -110,6 +114,8 @@ public static HelmConfig.HelmConfigBuilder initHelmConfig( helmConfig.setTarFileClassifier(resolveFromPropertyOrDefault(PROPERTY_TARBALL_CLASSIFIER, project, helmConfig::getTarFileClassifier, () -> EMPTY)); helmConfig.setTarballOutputDir(resolveFromPropertyOrDefault(PROPERTY_TARBALL_OUTPUT_DIR, project, helmConfig::getTarballOutputDir, helmConfig::getOutputDir)); + helmConfig.setLintStrict(resolveBooleanFromPropertyOrDefault(PROPERTY_HELM_LINT_STRICT, project, helmConfig::isLintStrict)); + helmConfig.setLintQuiet(resolveBooleanFromPropertyOrDefault(PROPERTY_HELM_LINT_QUIET, project, helmConfig::isLintQuiet)); return helmConfig.toBuilder(); } @@ -165,6 +171,13 @@ static String resolveFromPropertyOrDefault(String property, JavaProject project, .orElseGet(defaultValue == null ? () -> null : defaultValue)); } + static boolean resolveBooleanFromPropertyOrDefault(String property, JavaProject project, BooleanSupplier getter) { + return Optional.ofNullable(getProperty(property, project)) + .filter(StringUtils::isNotBlank) + .map(Boolean::parseBoolean) + .orElse(getter.getAsBoolean()); + } + static List getAdditionalFiles(HelmConfig helm, JavaProject project) { List additionalFiles = new ArrayList<>(); if (helm.getAdditionalFiles() != null) { diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceLintIT.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceLintIT.java new file mode 100644 index 0000000000..7f674304ec --- /dev/null +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceLintIT.java @@ -0,0 +1,218 @@ +/* + * 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.resource.helm; + +import com.marcnuri.helm.Helm; +import org.eclipse.jkube.kit.common.JKubeConfiguration; +import org.eclipse.jkube.kit.common.JKubeException; +import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.config.resource.ResourceServiceConfig; +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 java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.Comparator; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@DisplayName("HelmService.uploadHelmChart") +class HelmServiceLintIT { + + @TempDir + private Path tempDir; + private KitLogger kitLogger; + private Path outputDir; + private HelmConfig helmConfig; + private HelmService helmService; + + @BeforeEach + void setUp() { + kitLogger = spy(new KitLogger.SilentLogger()); + outputDir = tempDir.resolve("output"); + helmConfig = HelmConfig.builder() + .chart("helm-test") + .version("0.1.0") + .chartExtension("tgz") + .types(Arrays.asList(HelmConfig.HelmType.KUBERNETES, HelmConfig.HelmType.OPENSHIFT)) + .tarballOutputDir(outputDir.toFile().getAbsolutePath()) + .build(); + helmService = new HelmService(JKubeConfiguration.builder().build(), new ResourceServiceConfig(), kitLogger); + } + + @Nested + class Valid { + + @BeforeEach + void validChartPackage() throws IOException { + final Helm helm = Helm.create().withName("helm-test").withDir(tempDir).call(); + // Create templates as file (instead of dir) to force a warning + Files.walk(tempDir.resolve("helm-test").resolve("templates")) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + Files.createFile(tempDir.resolve("helm-test").resolve("templates")); + helm + .packageIt().withDestination(outputDir.resolve("kubernetes")).call() + .packageIt().withDestination(outputDir.resolve("openshift")).call(); + } + + @Test + void genericInfoMessage() { + helmService.lint(helmConfig); + verify(kitLogger, atLeastOnce()) + .info("Linting %s %s", "helm-test", "0.1.0"); + } + + @Test + void kubernetesPriorInfoMessage() { + helmService.lint(helmConfig); + verify(kitLogger, times(1)) + .info(eq("Using packaged file: %s"), endsWith("kubernetes" + File.separator + "helm-test-0.1.0.tgz")); + } + + @Test + void openshiftPriorInfoMessage() { + helmService.lint(helmConfig); + verify(kitLogger, times(1)) + .info(eq("Using packaged file: %s"), endsWith("openshift" + File.separator + "helm-test-0.1.0.tgz")); + } + + @Test + void lintInfoMessageInWhite() { + helmService.lint(helmConfig); + verify(kitLogger, atLeastOnce()) + .info("[[W]]%s", "[INFO] Chart.yaml: icon is recommended"); + } + + @Test + void successMessage() { + helmService.lint(helmConfig); + verify(kitLogger, atLeastOnce()).info("Linting successful"); + } + + @Nested + class Strict { + @BeforeEach + void setUp() { + helmConfig = helmConfig.toBuilder().lintStrict(true).build(); + helmService = new HelmService(JKubeConfiguration.builder().build(), new ResourceServiceConfig(), kitLogger); + } + + @Test + void lintErrorMessageInWhite() { + assertThatExceptionOfType(JKubeException.class).isThrownBy(() -> helmService.lint(helmConfig)); + verify(kitLogger, atLeastOnce()) + .error("[[W]]%s", "[WARNING] templates/: not a directory"); + } + + @Test + void lintingException() { + assertThatExceptionOfType(JKubeException.class) + .isThrownBy(() -> helmService.lint(helmConfig)) + .withMessage("Linting failed"); + } + } + + @Nested + class Quiet { + @BeforeEach + void setUp() { + helmConfig = helmConfig.toBuilder().lintQuiet(true).build(); + helmService = new HelmService(JKubeConfiguration.builder().build(), new ResourceServiceConfig(), kitLogger); + } + + @Test + void lintInfoMessageOmitted() { + helmService.lint(helmConfig); + verify(kitLogger, never()) + .info("[[W]]%s", "[INFO] Chart.yaml: icon is recommended"); + } + + @Test + void lintWarnMessage() { + helmService.lint(helmConfig); + verify(kitLogger, atLeastOnce()) + .info("[[W]]%s", "[WARNING] templates/: not a directory"); + } + } + + } + + @Nested + class Invalid { + + @BeforeEach + void invalidChartPackage() throws IOException { + final Helm chart = Helm.create().withName("helm-test").withDir(tempDir).call(); + Files.write(tempDir.resolve("helm-test").resolve("Chart.yaml"), + "\nicon: ://invalid-url".getBytes(StandardCharsets.UTF_8), + StandardOpenOption.APPEND + ); + chart + .packageIt().withDestination(outputDir.resolve("kubernetes")).call() + .packageIt().withDestination(outputDir.resolve("openshift")).call(); + } + + @Test + void genericInfoMessage() { + assertThatExceptionOfType(JKubeException.class).isThrownBy(() -> helmService.lint(helmConfig)); + verify(kitLogger, atLeastOnce()) + .info("Linting %s %s", "helm-test", "0.1.0"); + } + + @Test + void kubernetesPriorInfoMessage() { + assertThatExceptionOfType(JKubeException.class).isThrownBy(() -> helmService.lint(helmConfig)); + verify(kitLogger, times(1)) + .info(eq("Using packaged file: %s"), endsWith("kubernetes" + File.separator + "helm-test-0.1.0.tgz")); + } + + @Test + void openshiftPriorInfoMessageNotThrownDueToPriorExceptionHaltingProcessing() { + assertThatExceptionOfType(JKubeException.class).isThrownBy(() -> helmService.lint(helmConfig)); + verify(kitLogger, never()) + .info(eq("Using packaged file: %s"), endsWith("openshift" + File.separator + "helm-test-0.1.0.tgz")); + } + + @Test + void lintErrorMessageInWhite() { + assertThatExceptionOfType(JKubeException.class).isThrownBy(() -> helmService.lint(helmConfig)); + verify(kitLogger, atLeastOnce()) + .error("[[W]]%s", "[ERROR] Chart.yaml: invalid icon URL '://invalid-url'"); + } + + @Test + void lintingException() { + assertThatExceptionOfType(JKubeException.class) + .isThrownBy(() -> helmService.lint(helmConfig)) + .withMessage("Linting failed"); + } + } +} diff --git a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtilTest.java b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtilTest.java index ece97ce988..576454b688 100644 --- a/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtilTest.java +++ b/jkube-kit/helm/src/test/java/org/eclipse/jkube/kit/resource/helm/HelmServiceUtilTest.java @@ -86,7 +86,9 @@ void initHelmConfig_withNoConfig_shouldInitConfigWithDefaultValues() throws IOEx .hasFieldOrPropertyWithValue("types", Collections.singletonList(HelmConfig.HelmType.KUBERNETES)) .hasFieldOrPropertyWithValue("additionalFiles", Collections.emptyList()) .hasFieldOrPropertyWithValue("parameterTemplates", Collections.emptyList()) - .hasFieldOrProperty("icon"); + .hasFieldOrProperty("icon") + .hasFieldOrPropertyWithValue("lintStrict", false) + .hasFieldOrPropertyWithValue("lintQuiet", false); assertThat(result.getSourceDir()).endsWith("target/classes/META-INF/jkube/"); assertThat(result.getOutputDir()).endsWith("target/jkube/helm/artifact-id"); assertThat(result.getTarballOutputDir()).endsWith("target/jkube/helm/artifact-id"); @@ -103,6 +105,8 @@ void initHelmConfig_withOriginalConfig_shouldInitConfigWithoutOverriding() throw .maintainers(Collections.emptyList()) .sourceDir("sources") .outputDir("output") + .lintStrict(true) + .lintQuiet(true) .build(); // When final HelmConfig result = HelmServiceUtil @@ -120,7 +124,9 @@ void initHelmConfig_withOriginalConfig_shouldInitConfigWithoutOverriding() throw .hasFieldOrPropertyWithValue("sources", Collections.emptyList()) .hasFieldOrPropertyWithValue("maintainers", Collections.emptyList()) .hasFieldOrPropertyWithValue("sourceDir", "sources") - .hasFieldOrPropertyWithValue("outputDir", "output"); + .hasFieldOrPropertyWithValue("outputDir", "output") + .hasFieldOrPropertyWithValue("lintStrict", true) + .hasFieldOrPropertyWithValue("lintQuiet", true); } @Test @@ -142,6 +148,21 @@ void initHelmConfig_withTypeProperty_shouldInitConfigWithForSpecifiedTypes() thr ); } + @Test + void initHelmConfig_withLintProperties_shouldInitConfigWithLintSettings() throws IOException { + // Given + javaProject.getProperties().put("jkube.helm.lint.strict", "True"); + javaProject.getProperties().put("jkube.helm.lint.quiet", "trUe"); + // When + final HelmConfig result = HelmServiceUtil + .initHelmConfig(HelmConfig.HelmType.KUBERNETES, javaProject, templateDir, null) + .build(); + // Then + assertThat(result) + .hasFieldOrPropertyWithValue("lintStrict", true) + .hasFieldOrPropertyWithValue("lintQuiet", true); + } + @Test void initHelmConfig_whenValuesSchemaJsonPresentInProjectBaseDir_thenAddToHelmConfig() throws IOException { // Given From d828cd269470d354e752351a0539e98c7c02f31e Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Tue, 6 Feb 2024 13:02:24 +0100 Subject: [PATCH 22/24] feat: helm lint exposed in Gradle and Maven plugins Signed-off-by: Marc Nuri --- .../it/src/it/helm-lint/build.gradle | 42 +++++++++ .../jkube/gradle/plugin/tests/HelmLintIT.java | 56 ++++++++++++ .../jkube/gradle/plugin/KubernetesPlugin.java | 3 + .../plugin/task/KubernetesHelmLintTask.java | 46 ++++++++++ .../gradle/plugin/KubernetesPluginTest.java | 5 +- .../task/KubernetesHelmLintTaskTest.java | 74 ++++++++++++++++ .../jkube/gradle/plugin/OpenShiftPlugin.java | 3 + .../plugin/task/OpenShiftHelmLintTask.java | 26 ++++++ .../gradle/plugin/OpenShiftPluginTest.java | 5 +- .../gradle/plugin/TestOpenShiftExtension.java | 3 +- .../task/OpenShiftHelmLintTaskTest.java | 74 ++++++++++++++++ .../maven/plugin/mojo/build/HelmLintMojo.java | 39 +++++++++ .../mojo/GeneratedPluginDescriptorTest.java | 3 +- .../plugin/mojo/build/HelmLintMojoTest.java | 87 +++++++++++++++++++ .../mojo/build/OpenshiftHelmLintMojo.java | 59 +++++++++++++ ...penShiftGeneratedPluginDescriptorTest.java | 28 +++--- 16 files changed, 534 insertions(+), 19 deletions(-) create mode 100644 gradle-plugin/it/src/it/helm-lint/build.gradle create mode 100644 gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/HelmLintIT.java create mode 100644 gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTask.java create mode 100644 gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTaskTest.java create mode 100644 gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTask.java create mode 100644 gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTaskTest.java create mode 100644 kubernetes-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojo.java create mode 100644 kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojoTest.java create mode 100644 openshift-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/OpenshiftHelmLintMojo.java diff --git a/gradle-plugin/it/src/it/helm-lint/build.gradle b/gradle-plugin/it/src/it/helm-lint/build.gradle new file mode 100644 index 0000000000..fdf4670ec2 --- /dev/null +++ b/gradle-plugin/it/src/it/helm-lint/build.gradle @@ -0,0 +1,42 @@ +/* + * 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 + */ +plugins { + id 'org.eclipse.jkube.kubernetes' version "${jKubeVersion}" + id 'org.eclipse.jkube.openshift' version "${jKubeVersion}" + id 'java' +} + +group = 'org.eclipse.jkube.integration.tests.gradle' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '11' + +repositories { + mavenCentral() +} + +def extensionConfig = { + offline = true + images { + image { + name = 'repository/helm-fragment:latest' + build { + from = 'repository/from:latest' + } + } + } +} + +kubernetes(extensionConfig) +openshift(extensionConfig) + diff --git a/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/HelmLintIT.java b/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/HelmLintIT.java new file mode 100644 index 0000000000..2b66f834f1 --- /dev/null +++ b/gradle-plugin/it/src/test/java/org/eclipse/jkube/gradle/plugin/tests/HelmLintIT.java @@ -0,0 +1,56 @@ +/* + * 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.gradle.plugin.tests; + +import org.gradle.testkit.runner.BuildResult; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class HelmLintIT { + + @RegisterExtension + public final ITGradleRunnerExtension gradleRunner = new ITGradleRunnerExtension(); + + @BeforeEach + void setUp() { + gradleRunner.withITProject("helm-lint"); + } + + @Test + void k8sHelmLint() { + // When + final BuildResult result = gradleRunner + .withArguments("clean", "k8sResource", "k8sHelm", "k8sHelmLint").build(); + // Then + assertThat(result).extracting(BuildResult::getOutput).asString() + .contains("k8s: Linting helm-lint 0.0.1-SNAPSHOT") + .contains("k8s: [INFO] Chart.yaml: icon is recommended") + .contains("k8s: Linting successful"); + } + + @Test + void ocHelmLint() { + // When + final BuildResult result = gradleRunner + .withArguments("clean", "ocResource", "ocHelm", "ocHelmLint").build(); + // Then + assertThat(result).extracting(BuildResult::getOutput).asString() + .contains("oc: Linting helm-lint 0.0.1-SNAPSHOT") + .contains("oc: [INFO] Chart.yaml: icon is recommended") + .contains("oc: Linting successful"); + } +} diff --git a/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/KubernetesPlugin.java b/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/KubernetesPlugin.java index ca1c28e492..a18efc910a 100644 --- a/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/KubernetesPlugin.java +++ b/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/KubernetesPlugin.java @@ -23,6 +23,7 @@ import org.eclipse.jkube.gradle.plugin.task.KubernetesBuildTask; import org.eclipse.jkube.gradle.plugin.task.KubernetesConfigViewTask; import org.eclipse.jkube.gradle.plugin.task.KubernetesDebugTask; +import org.eclipse.jkube.gradle.plugin.task.KubernetesHelmLintTask; import org.eclipse.jkube.gradle.plugin.task.KubernetesHelmPushTask; import org.eclipse.jkube.gradle.plugin.task.KubernetesHelmTask; import org.eclipse.jkube.gradle.plugin.task.KubernetesLogTask; @@ -49,6 +50,7 @@ public Map>> getTaskPrecedence() { ret.put("k8sPush", Collections.singletonList(KubernetesBuildTask.class)); ret.put("k8sHelm", Collections.singletonList(KubernetesResourceTask.class)); ret.put("k8sHelmPush", Collections.singletonList(KubernetesHelmTask.class)); + ret.put("k8sHelmLint", Collections.singletonList(KubernetesHelmTask.class)); return ret; } @@ -64,6 +66,7 @@ protected void jKubeApply(Project project) { register(project, "k8sUndeploy", KubernetesUndeployTask.class); register(project, "k8sHelm", KubernetesHelmTask.class); register(project, "k8sHelmPush", KubernetesHelmPushTask.class); + register(project, "k8sHelmLint", KubernetesHelmLintTask.class); register(project, "k8sRemoteDev", KubernetesRemoteDevTask.class); register(project, "k8sWatch", KubernetesWatchTask.class); } diff --git a/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTask.java b/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTask.java new file mode 100644 index 0000000000..d599f5a78e --- /dev/null +++ b/gradle-plugin/kubernetes/src/main/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTask.java @@ -0,0 +1,46 @@ +/* + * 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.gradle.plugin.task; + +import org.eclipse.jkube.gradle.plugin.KubernetesExtension; +import org.eclipse.jkube.kit.resource.helm.HelmConfig; + +import javax.inject.Inject; + +import static org.eclipse.jkube.kit.resource.helm.HelmServiceUtil.initHelmConfig; + +public class KubernetesHelmLintTask extends AbstractJKubeTask { + @Inject + public KubernetesHelmLintTask(Class extensionClass) { + super(extensionClass); + setDescription("Examine Helm chart for possible issues"); + } + + @Override + public void run() { + if (kubernetesExtension.getSkipOrDefault()) { + return; + } + try { + final HelmConfig helm = initHelmConfig(kubernetesExtension.getDefaultHelmType(), kubernetesExtension.javaProject, + kubernetesExtension.getKubernetesTemplateOrDefault(), + kubernetesExtension.helm) + .build(); + jKubeServiceHub.getHelmService().lint(helm); + } catch (Exception exp) { + kitLogger.error("Error performing helm lint", exp); + throw new IllegalStateException(exp.getMessage(), exp); + } + } +} diff --git a/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/KubernetesPluginTest.java b/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/KubernetesPluginTest.java index c69636f5d8..16a119d983 100644 --- a/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/KubernetesPluginTest.java +++ b/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/KubernetesPluginTest.java @@ -81,12 +81,13 @@ void getTaskPrecedence_withValidProject_shouldReturnTaskPrecedence() { final Map>> result = new KubernetesPlugin().getTaskPrecedence(); // Then assertThat(result) - .hasSize(5) + .hasSize(6) .containsEntry("k8sApply", Collections.singletonList(KubernetesResourceTask.class)) .containsEntry("k8sDebug", Arrays.asList(KubernetesBuildTask.class, KubernetesResourceTask.class, KubernetesApplyTask.class)) .containsEntry("k8sPush", Collections.singletonList(KubernetesBuildTask.class)) .containsEntry("k8sHelm", Collections.singletonList(KubernetesResourceTask.class)) - .containsEntry("k8sHelmPush", Collections.singletonList(KubernetesHelmTask.class)); + .containsEntry("k8sHelmPush", Collections.singletonList(KubernetesHelmTask.class)) + .containsEntry("k8sHelmLint", Collections.singletonList(KubernetesHelmTask.class)); } } diff --git a/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTaskTest.java b/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTaskTest.java new file mode 100644 index 0000000000..c0370b2285 --- /dev/null +++ b/gradle-plugin/kubernetes/src/test/java/org/eclipse/jkube/gradle/plugin/task/KubernetesHelmLintTaskTest.java @@ -0,0 +1,74 @@ +/* + * 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.gradle.plugin.task; + +import com.marcnuri.helm.Helm; +import org.eclipse.jkube.gradle.plugin.KubernetesExtension; +import org.eclipse.jkube.gradle.plugin.TestKubernetesExtension; +import org.eclipse.jkube.kit.resource.helm.HelmConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class KubernetesHelmLintTaskTest { + + @RegisterExtension + private final TaskEnvironmentExtension taskEnvironment = new TaskEnvironmentExtension(); + + @BeforeEach + void setUp() throws IOException { + System.setProperty("jkube.kubernetesTemplate", taskEnvironment.getRoot().getAbsolutePath()); + final TestKubernetesExtension extension = new TestKubernetesExtension(); + extension.helm = HelmConfig.builder().chartExtension("tgz").build(); + extension.isUseColor = false; + when(taskEnvironment.project.getName()).thenReturn("empty-project"); + when(taskEnvironment.project.getVersion()).thenReturn("0.1.0"); + when(taskEnvironment.project.getExtensions().getByType(KubernetesExtension.class)).thenReturn(extension); + } + + @AfterEach + void tearDown() { + System.clearProperty("jkube.kubernetesTemplate"); + } + + @Test + void runTask_withMissingHelmPackage_shouldThrowException() { + KubernetesHelmLintTask kubernetesHelmLintTask = new KubernetesHelmLintTask(KubernetesExtension.class); + assertThatThrownBy(kubernetesHelmLintTask::runTask) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Linting failed"); + verify(taskEnvironment.logger).lifecycle("k8s: Linting empty-project 0.1.0"); + verify(taskEnvironment.logger).lifecycle(startsWith("k8s: Using packaged file:")); + } + + @Test + void runTask_withHelmPackage_shouldSucceed() { + KubernetesHelmLintTask kubernetesHelmLintTask = new KubernetesHelmLintTask(KubernetesExtension.class); + Helm.create().withDir(taskEnvironment.getRoot().toPath()).withName("empty-project").call() + .packageIt().withDestination(taskEnvironment.getRoot().toPath().resolve("build").resolve("jkube").resolve("helm").resolve("empty-project").resolve("kubernetes")).call(); + kubernetesHelmLintTask.runTask(); + verify(taskEnvironment.logger).lifecycle("k8s: Linting empty-project 0.1.0"); + verify(taskEnvironment.logger).lifecycle(startsWith("k8s: Using packaged file:")); + verify(taskEnvironment.logger).lifecycle("k8s: [INFO] Chart.yaml: icon is recommended"); + verify(taskEnvironment.logger).lifecycle("k8s: Linting successful"); + } +} diff --git a/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/OpenShiftPlugin.java b/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/OpenShiftPlugin.java index bf823b3ea1..6087e82a27 100644 --- a/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/OpenShiftPlugin.java +++ b/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/OpenShiftPlugin.java @@ -27,6 +27,7 @@ import org.eclipse.jkube.gradle.plugin.task.OpenShiftApplyTask; import org.eclipse.jkube.gradle.plugin.task.OpenShiftBuildTask; import org.eclipse.jkube.gradle.plugin.task.OpenShiftDebugTask; +import org.eclipse.jkube.gradle.plugin.task.OpenShiftHelmLintTask; import org.eclipse.jkube.gradle.plugin.task.OpenShiftHelmPushTask; import org.eclipse.jkube.gradle.plugin.task.OpenShiftHelmTask; import org.eclipse.jkube.gradle.plugin.task.OpenShiftPushTask; @@ -53,6 +54,7 @@ public Map>> getTaskPrecedence() { ret.put("ocPush", Arrays.asList(KubernetesBuildTask.class, OpenShiftBuildTask.class)); ret.put("ocHelm", Arrays.asList(KubernetesResourceTask.class, OpenShiftResourceTask.class)); ret.put("ocHelmPush", Arrays.asList(KubernetesHelmTask.class, OpenShiftHelmTask.class)); + ret.put("ocHelmLint", Arrays.asList(KubernetesHelmTask.class, OpenShiftHelmTask.class)); return ret; } @@ -68,6 +70,7 @@ protected void jKubeApply(Project project) { register(project, "ocUndeploy", OpenShiftUndeployTask.class); register(project, "ocHelm", OpenShiftHelmTask.class); register(project, "ocHelmPush", OpenShiftHelmPushTask.class); + register(project, "ocHelmLint", OpenShiftHelmLintTask.class); register(project, "ocRemoteDev", OpenShiftRemoteDevTask.class); register(project, "ocWatch", OpenShiftWatchTask.class); } diff --git a/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTask.java b/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTask.java new file mode 100644 index 0000000000..ae19425f3c --- /dev/null +++ b/gradle-plugin/openshift/src/main/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTask.java @@ -0,0 +1,26 @@ +/* + * 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.gradle.plugin.task; + +import org.eclipse.jkube.gradle.plugin.OpenShiftExtension; + +import javax.inject.Inject; + +public class OpenShiftHelmLintTask extends KubernetesHelmLintTask implements OpenShiftJKubeTask { + @Inject + public OpenShiftHelmLintTask(Class extensionClass) { + super(extensionClass); + setDescription("Examine Helm chart for possible issues"); + } +} diff --git a/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/OpenShiftPluginTest.java b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/OpenShiftPluginTest.java index a58443f382..872facb276 100644 --- a/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/OpenShiftPluginTest.java +++ b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/OpenShiftPluginTest.java @@ -39,12 +39,13 @@ void configurePrecedence_withValidProject_shouldReturnTaskPrecedence() { final Map>> result = new OpenShiftPlugin().getTaskPrecedence(); // Then assertThat(result) - .hasSize(5) + .hasSize(6) .containsEntry("ocApply", Arrays.asList(KubernetesResourceTask.class, OpenShiftResourceTask.class)) .containsEntry("ocDebug", Arrays.asList(KubernetesBuildTask.class, OpenShiftBuildTask.class, KubernetesResourceTask.class, OpenShiftResourceTask.class, KubernetesApplyTask.class, OpenShiftApplyTask.class)) .containsEntry("ocPush", Arrays.asList(KubernetesBuildTask.class, OpenShiftBuildTask.class)) .containsEntry("ocHelm", Arrays.asList(KubernetesResourceTask.class, OpenShiftResourceTask.class)) - .containsEntry("ocHelmPush", Arrays.asList(KubernetesHelmTask.class, OpenShiftHelmTask.class)); + .containsEntry("ocHelmPush", Arrays.asList(KubernetesHelmTask.class, OpenShiftHelmTask.class)) + .containsEntry("ocHelmLint", Arrays.asList(KubernetesHelmTask.class, OpenShiftHelmTask.class)); } } diff --git a/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/TestOpenShiftExtension.java b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/TestOpenShiftExtension.java index ead89f8c75..4872fbe399 100644 --- a/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/TestOpenShiftExtension.java +++ b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/TestOpenShiftExtension.java @@ -26,6 +26,7 @@ public class TestOpenShiftExtension extends OpenShiftExtension { public Boolean isOffline; + public Boolean isUseColor; public String buildRecreate; public Boolean isForcePull; public Boolean isFailOnNoKubernetesJson; @@ -42,7 +43,7 @@ public Property getOffline() { @Override public Property getUseColor() { - return property(Boolean.class); + return property(Boolean.class).value(isUseColor); } @Override diff --git a/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTaskTest.java b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTaskTest.java new file mode 100644 index 0000000000..e3ec0dcfe9 --- /dev/null +++ b/gradle-plugin/openshift/src/test/java/org/eclipse/jkube/gradle/plugin/task/OpenShiftHelmLintTaskTest.java @@ -0,0 +1,74 @@ +/* + * 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.gradle.plugin.task; + +import com.marcnuri.helm.Helm; +import org.eclipse.jkube.gradle.plugin.OpenShiftExtension; +import org.eclipse.jkube.gradle.plugin.TestOpenShiftExtension; +import org.eclipse.jkube.kit.resource.helm.HelmConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class OpenShiftHelmLintTaskTest { + + @RegisterExtension + private final TaskEnvironmentExtension taskEnvironment = new TaskEnvironmentExtension(); + + @BeforeEach + void setUp() throws IOException { + System.setProperty("jkube.kubernetesTemplate", taskEnvironment.getRoot().getAbsolutePath()); + final TestOpenShiftExtension extension = new TestOpenShiftExtension(); + extension.helm = HelmConfig.builder().chartExtension("tgz").build(); + extension.isUseColor = false; + when(taskEnvironment.project.getName()).thenReturn("empty-project"); + when(taskEnvironment.project.getVersion()).thenReturn("0.1.0"); + when(taskEnvironment.project.getExtensions().getByType(OpenShiftExtension.class)).thenReturn(extension); + } + + @AfterEach + void tearDown() { + System.clearProperty("jkube.kubernetesTemplate"); + } + + @Test + void runTask_withMissingHelmPackage_shouldThrowException() { + OpenShiftHelmLintTask openShiftHelmLintTask = new OpenShiftHelmLintTask(OpenShiftExtension.class); + assertThatThrownBy(openShiftHelmLintTask::runTask) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Linting failed"); + verify(taskEnvironment.logger).lifecycle("oc: Linting empty-project 0.1.0"); + verify(taskEnvironment.logger).lifecycle(startsWith("oc: Using packaged file:")); + } + + @Test + void runTask_withHelmPackage_shouldSucceed() { + OpenShiftHelmLintTask openShiftHelmLintTask = new OpenShiftHelmLintTask(OpenShiftExtension.class); + Helm.create().withDir(taskEnvironment.getRoot().toPath()).withName("empty-project").call() + .packageIt().withDestination(taskEnvironment.getRoot().toPath().resolve("build").resolve("jkube").resolve("helm").resolve("empty-project").resolve("openshift")).call(); + openShiftHelmLintTask.runTask(); + verify(taskEnvironment.logger).lifecycle("oc: Linting empty-project 0.1.0"); + verify(taskEnvironment.logger).lifecycle(startsWith("oc: Using packaged file:")); + verify(taskEnvironment.logger).lifecycle("oc: [INFO] Chart.yaml: icon is recommended"); + verify(taskEnvironment.logger).lifecycle("oc: Linting successful"); + } +} diff --git a/kubernetes-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojo.java b/kubernetes-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojo.java new file mode 100644 index 0000000000..8b54d272a5 --- /dev/null +++ b/kubernetes-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojo.java @@ -0,0 +1,39 @@ +/* + * 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.maven.plugin.mojo.build; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +import java.io.IOException; + +import static org.eclipse.jkube.kit.resource.helm.HelmServiceUtil.initHelmConfig; + +@Mojo(name = "helm-lint", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.COMPILE) +public class HelmLintMojo extends HelmMojo { + + @Override + public void executeInternal() throws MojoExecutionException { + try { + helm = initHelmConfig(getDefaultHelmType(), javaProject, getKubernetesTemplate(), helm) + .build(); + jkubeServiceHub.getHelmService().lint(helm); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + } +} diff --git a/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/GeneratedPluginDescriptorTest.java b/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/GeneratedPluginDescriptorTest.java index 00f093cf88..a7730a7c42 100644 --- a/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/GeneratedPluginDescriptorTest.java +++ b/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/GeneratedPluginDescriptorTest.java @@ -54,7 +54,8 @@ static Stream data() { arguments("log", "compile+runtime", "validate"), arguments("push", "compile", "install"), arguments("helm", "", "pre-integration-test"), - arguments("helm-push", "compile", "install")); + arguments("helm-push", "compile", "install"), + arguments("helm-lint", "compile", "integration-test")); } @DisplayName("verify, phase and required dependency resolution") diff --git a/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojoTest.java b/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojoTest.java new file mode 100644 index 0000000000..b0ef06a230 --- /dev/null +++ b/kubernetes-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/build/HelmLintMojoTest.java @@ -0,0 +1,87 @@ +/* + * 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.maven.plugin.mojo.build; + +import com.marcnuri.helm.Helm; +import org.apache.maven.project.MavenProject; +import org.apache.maven.settings.Settings; +import org.eclipse.jkube.kit.common.JKubeException; +import org.eclipse.jkube.kit.resource.helm.HelmConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class HelmLintMojoTest { + + @TempDir + private Path projectDir; + private PrintStream originalPrintStream; + private ByteArrayOutputStream outputStream; + private HelmLintMojo helmLintMojo; + + + @BeforeEach + void setUp() throws Exception { + originalPrintStream = System.out; + outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + helmLintMojo = new HelmLintMojo(); + helmLintMojo.helm = HelmConfig.builder().chartExtension("tgz").build(); + helmLintMojo.interpolateTemplateParameters = true; + helmLintMojo.settings = new Settings(); + helmLintMojo.project = new MavenProject(); + helmLintMojo.project.setVersion("0.1.0"); + helmLintMojo.project.getBuild() + .setOutputDirectory(projectDir.resolve("target").resolve("classes").toFile().getAbsolutePath()); + helmLintMojo.project.getBuild().setDirectory(projectDir.resolve("target").toFile().getAbsolutePath()); + helmLintMojo.project.setFile(projectDir.resolve("target").toFile()); + } + + @AfterEach + void tearDown() { + System.setOut(originalPrintStream); + helmLintMojo = null; + } + + @Test + void execute_withMissingHelmPackage_shouldThrowException() { + assertThatThrownBy(helmLintMojo::execute) + .isInstanceOf(JKubeException.class) + .hasMessage("Linting failed"); + assertThat(outputStream.toString()) + .contains("Linting empty-project 0.1.0\n") + .contains("Using packaged file:") + .contains("[[W]]Error unable to open tarball:"); + } + + @Test + void execute_withHelmPackage_shouldSucceed() throws Exception { + Helm.create().withDir(projectDir).withName("empty-project").call() + .packageIt().withDestination(projectDir.resolve("target").resolve("jkube").resolve("helm").resolve("empty-project").resolve("kubernetes")).call(); + helmLintMojo.execute(); + assertThat(outputStream.toString()) + .contains("Linting empty-project 0.1.0\n") + .contains("Using packaged file:") + .contains("[[W]][INFO] Chart.yaml: icon is recommended") + .contains("Linting successful"); + } +} diff --git a/openshift-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/OpenshiftHelmLintMojo.java b/openshift-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/OpenshiftHelmLintMojo.java new file mode 100644 index 0000000000..3aa0d11e7c --- /dev/null +++ b/openshift-maven-plugin/plugin/src/main/java/org/eclipse/jkube/maven/plugin/mojo/build/OpenshiftHelmLintMojo.java @@ -0,0 +1,59 @@ +/* + * 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.maven.plugin.mojo.build; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.eclipse.jkube.kit.resource.helm.HelmConfig; +import org.eclipse.jkube.maven.plugin.mojo.OpenShift; + +import java.io.File; + +@Mojo(name = "helm-lint", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.COMPILE) +public class OpenshiftHelmLintMojo extends HelmLintMojo { + + /** + * The generated kubernetes YAML file + */ + @Parameter(property = "jkube.kubernetesManifest", defaultValue = "${basedir}/target/classes/META-INF/jkube/openshift.yml") + private File openShiftManifest; + + /** + * The generated kubernetes YAML file + */ + @Parameter(property = "jkube.kubernetesManifest", defaultValue = "${basedir}/target/classes/META-INF/jkube/openshift") + private File openShiftTemplate; + + @Override + protected File getKubernetesManifest() { + return openShiftManifest; + } + + @Override + protected File getKubernetesTemplate() { + return openShiftTemplate; + } + + @Override + protected HelmConfig.HelmType getDefaultHelmType() { + return HelmConfig.HelmType.OPENSHIFT; + } + + @Override + protected String getLogPrefix() { + return OpenShift.DEFAULT_LOG_PREFIX; + } +} diff --git a/openshift-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/OpenShiftGeneratedPluginDescriptorTest.java b/openshift-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/OpenShiftGeneratedPluginDescriptorTest.java index 3cd55f80fe..256eb221d7 100644 --- a/openshift-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/OpenShiftGeneratedPluginDescriptorTest.java +++ b/openshift-maven-plugin/plugin/src/test/java/org/eclipse/jkube/maven/plugin/mojo/OpenShiftGeneratedPluginDescriptorTest.java @@ -29,6 +29,7 @@ import java.util.stream.Stream; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; class OpenShiftGeneratedPluginDescriptorTest { private File pluginDescriptor; @@ -40,23 +41,24 @@ void setUp() { pluginDescriptor = new File(pluginDescriptorUrl.getFile()); } - public static Stream data() { + static Stream data() { return Stream.of( - Arguments.of("build", "compile", "pre-integration-test"), - Arguments.of("resource", "compile", "process-resources"), - Arguments.of("apply", "compile+runtime", "install"), - Arguments.of("deploy", "compile+runtime", "validate"), - Arguments.of("watch", "compile+runtime", "package"), - Arguments.of("undeploy", "compile", "install"), - Arguments.of("debug", "compile+runtime", "package"), - Arguments.of("log", "compile+runtime", "validate"), - Arguments.of("push", "compile", "install"), - Arguments.of("helm", "", "pre-integration-test"), - Arguments.of("helm-push", "compile", "install") + arguments("build", "compile", "pre-integration-test"), + arguments("resource", "compile", "process-resources"), + arguments("apply", "compile+runtime", "install"), + arguments("deploy", "compile+runtime", "validate"), + arguments("watch", "compile+runtime", "package"), + arguments("undeploy", "compile", "install"), + arguments("debug", "compile+runtime", "package"), + arguments("log", "compile+runtime", "validate"), + arguments("push", "compile", "install"), + arguments("helm", "", "pre-integration-test"), + arguments("helm-push", "compile", "install"), + arguments("helm-lint", "compile", "integration-test") ); } - @ParameterizedTest(name = "{0}, should have {1} requiresDependencyResolution and {2} phase") + @ParameterizedTest(name = "{index}: {0}, should have {1} requiresDependencyResolution and {2} phase") @MethodSource("data") void verifyPhaseAndRequiresDependencyResolution(String mojo, String expectedRequiresDependencyResolution, String expectedPhase) throws Exception { assertThat(getField(pluginDescriptor, "/plugin/mojos/mojo[goal='" + mojo + "']/requiresDependencyResolution")) From da8eb46b4964e53d452051e796a35f0a7ccef0b6 Mon Sep 17 00:00:00 2001 From: Devashishbasu Date: Thu, 8 Feb 2024 11:20:37 +0530 Subject: [PATCH 23/24] adding suggested changes by rohan sir --- .../java/org/eclipse/jkube/kit/config/image/ImageName.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java index ca0fee9166..ee8ab5c1d1 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java @@ -356,10 +356,14 @@ private boolean isRegistryValidPathComponent() { // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L65 private static final String OPTIONAL_PORT_REGEXP = "(?::[0-9]+)?"; + + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L99 private static final String DOMAIN_NAME_REGEXP = DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*"; + + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L106 private static final String REGISTRY_HOST_REGEXP = "^(?:" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_NAME_REGEXP + ")"; - // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L31 + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L110 private static final Pattern REGISTRY_REGEXP = Pattern.compile(REGISTRY_HOST_REGEXP + OPTIONAL_PORT_REGEXP); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L37 From c142522fb61647f0397d090b020cb32ba23d7a85 Mon Sep 17 00:00:00 2001 From: Devashishbasu Date: Thu, 1 Feb 2024 10:28:10 +0530 Subject: [PATCH 24/24] parsing IPv6 literals support added 1.added IPv6 address 2.upated DOMAIN_REGEX for the IPv6 addresses 3.uncommented the related tests removing issue references removing issue references Implemented suggested changes by sonarcloud updated the suggested changes adding suggested changes by rohan sir --- .../jkube/kit/config/image/ImageName.java | 20 +++++++++++++++---- .../ImageNameDistributionReferenceTest.java | 16 +++++++-------- .../image/ImageNameORASReferenceTest.java | 2 +- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java index 05a143b6a9..ee8ab5c1d1 100644 --- a/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java +++ b/jkube-kit/config/image/src/main/java/org/eclipse/jkube/kit/config/image/ImageName.java @@ -275,7 +275,7 @@ private void doValidate() { String user = inferUser(); String image = user != null ? repository.substring(user.length() + 1) : repository; Object[] checks = new Object[] { - "registry", DOMAIN_REGEXP, registry, + "registry", REGISTRY_REGEXP, registry, "image", IMAGE_NAME_REGEXP, image, "user", NAME_COMP_REGEXP, user, "tag", TAG_REGEXP, tag, @@ -323,7 +323,7 @@ private void parseComponentsBeforeTag(String rest) { } private boolean isValidDomain(String str) { - return containsPeriodOrColon(str) && DOMAIN_REGEXP.matcher(str).matches(); + return containsPeriodOrColon(str) && REGISTRY_REGEXP.matcher(str).matches(); } private boolean isRegistryValidPathComponent() { @@ -343,6 +343,9 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L25 private static final String DOMAIN_COMPONENT_REGEXP = "(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])"; + //https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L91 + private static final String IPV6_ADDRESS_REGEXP = "\\[[a-fA-F0-9:]+\\]"; + // ========================================================== // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L18 @@ -351,8 +354,17 @@ private boolean isRegistryValidPathComponent() { // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L53 private static final Pattern IMAGE_NAME_REGEXP = Pattern.compile(NAME_COMPONENT_REGEXP + "(?:(?:/" + NAME_COMPONENT_REGEXP + ")+)?"); - // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L31 - private static final Pattern DOMAIN_REGEXP = Pattern.compile("^" + DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*(?::[0-9]+)?$"); + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L65 + private static final String OPTIONAL_PORT_REGEXP = "(?::[0-9]+)?"; + + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L99 + private static final String DOMAIN_NAME_REGEXP = DOMAIN_COMPONENT_REGEXP + "(?:\\." + DOMAIN_COMPONENT_REGEXP + ")*"; + + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L106 + private static final String REGISTRY_HOST_REGEXP = "^(?:" + IPV6_ADDRESS_REGEXP + "|" + DOMAIN_NAME_REGEXP + ")"; + + // https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/regexp.go#L110 + private static final Pattern REGISTRY_REGEXP = Pattern.compile(REGISTRY_HOST_REGEXP + OPTIONAL_PORT_REGEXP); // https://github.com/docker/docker/blob/04da4041757370fb6f85510c8977c5a18ddae380/vendor/github.com/docker/distribution/reference/regexp.go#L37 private static final Pattern TAG_REGEXP = Pattern.compile("^[\\w][\\w.-]{0,127}$"); diff --git a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java index 46ac1d89e1..1b2bf3d740 100644 --- a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java +++ b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameDistributionReferenceTest.java @@ -72,14 +72,14 @@ class ImageNameDistributionReferenceTest { "192.168.0.1:8/debian", "192.168.0.2:25000/debian", "docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", - //"[2001:db8::1]/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8:1:2:3:4:5:6]/repo:tag", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo:tag", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541 - //"[2001:db8::]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 - //"[::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541 + "[2001:db8::1]/repo", + "[2001:db8:1:2:3:4:5:6]/repo:tag", + "[2001:db8::1]:5000/repo", + "[2001:db8::1]:5000/repo:tag", + "[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "[2001:db8::]:5000/repo", + "[::1]:5000/repo", }) void validNames(String name) { // Given diff --git a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java index 7795afedd9..dc4c1fab17 100644 --- a/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java +++ b/jkube-kit/config/image/src/test/java/org/eclipse/jkube/kit/config/image/ImageNameORASReferenceTest.java @@ -42,7 +42,7 @@ class ImageNameORASReferenceTest { "registry.example.com/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", "localhost:5000/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", "127.0.0.1:5000/hello-world:v2@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", - //"[::1]:5000/hello-world:v1", // https://github.com/eclipse/jkube/issues/2541 + "[::1]:5000/hello-world:v1", //"registry.example.com/hello-world:@sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", // https://github.com/eclipse/jkube/issues/2545 }) void validImageNamesCompatibleWithAll(String name) {