From e4f95081398ab9e718abf2a609d83ec35a5d5b83 Mon Sep 17 00:00:00 2001 From: ThameezBo Date: Mon, 22 May 2023 17:46:46 +0200 Subject: [PATCH 01/12] feat(manifests/helmfile): install helmfile binary --- Dockerfile.slim | 7 +++++++ Dockerfile.ubuntu | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/Dockerfile.slim b/Dockerfile.slim index 4c5ba1b15..759d909b0 100644 --- a/Dockerfile.slim +++ b/Dockerfile.slim @@ -4,6 +4,7 @@ LABEL maintainer="sig-platform@spinnaker.io" ENV KUSTOMIZE_VERSION=3.8.6 ENV KUSTOMIZE4_VERSION=4.5.5 ENV PACKER_VERSION=1.8.1 +ENV HELMFILE_VERSION=0.153.1 ARG TARGETARCH @@ -42,6 +43,12 @@ RUN mkdir kustomize && \ mv ./kustomize/kustomize /usr/local/bin/kustomize4 && \ rm -rf ./kustomize +RUN mkdir helmfile && \ + curl -s -L https://github.com/helmfile/helmfile/releases/download/v${HELMFILE_VERSION}/helmfile_${HELMFILE_VERSION}_linux_${TARGETARCH}.tar.gz|\ + tar xvz -C helmfile/ && \ + mv ./helmfile/helmfile /usr/local/bin/helmfile && \ + rm -rf ./helmfile + RUN addgroup -S -g 10111 spinnaker RUN adduser -S -G spinnaker -u 10111 spinnaker COPY rosco-web/build/install/rosco /opt/rosco diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu index 0bbd3f963..080147d92 100644 --- a/Dockerfile.ubuntu +++ b/Dockerfile.ubuntu @@ -4,6 +4,7 @@ LABEL maintainer="sig-platform@spinnaker.io" ENV KUSTOMIZE_VERSION=3.8.6 ENV KUSTOMIZE4_VERSION=4.5.5 ENV PACKER_VERSION=1.8.1 +ENV HELMFILE_VERSION=0.153.1 ARG TARGETARCH @@ -41,6 +42,12 @@ RUN mkdir kustomize && \ mv ./kustomize/kustomize /usr/local/bin/kustomize4 && \ rm -rf ./kustomize +RUN mkdir helmfile && \ + curl -s -L https://github.com/helmfile/helmfile/releases/download/v${HELMFILE_VERSION}/helmfile_${HELMFILE_VERSION}_linux_${TARGETARCH}.tar.gz|\ + tar xvz -C helmfile/ && \ + mv ./helmfile/helmfile /usr/local/bin/helmfile && \ + rm -rf ./helmfile + RUN adduser --system --uid 10111 --group spinnaker COPY rosco-web/build/install/rosco /opt/rosco COPY rosco-web/config /opt/rosco From 95ff86ba300a6c93f40400be77b7b1ab8a521bee Mon Sep 17 00:00:00 2001 From: ThameezBo Date: Tue, 23 May 2023 17:04:56 +0200 Subject: [PATCH 02/12] feat(manifests/helmfile): add code feat(manifests/helmfile): add tests --- .../rosco/manifests/BakeManifestRequest.java | 1 + .../RoscoHelmfileConfigurationProperties.java | 26 + .../helmfile/HelmfileBakeManifestRequest.java | 18 + .../helmfile/HelmfileBakeManifestService.java | 49 ++ .../helmfile/HelmfileTemplateUtils.java | 157 ++++ .../helmfile/HelmfileTemplateUtilsTest.java | 674 ++++++++++++++++++ .../com/netflix/spinnaker/rosco/Main.groovy | 2 + 7 files changed, 927 insertions(+) create mode 100644 rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java create mode 100644 rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java create mode 100644 rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java create mode 100644 rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java create mode 100644 rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/BakeManifestRequest.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/BakeManifestRequest.java index be5c8b67e..6a1eb36c8 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/BakeManifestRequest.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/BakeManifestRequest.java @@ -17,6 +17,7 @@ public enum TemplateRenderer { HELM3, KUSTOMIZE, KUSTOMIZE4, + HELMFILE, CF; @JsonCreator diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java new file mode 100644 index 000000000..f91deadd9 --- /dev/null +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020 Grab Holdings, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.rosco.manifests.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("helmfile") +@Data +public class RoscoHelmfileConfigurationProperties { + private String ExecutablePath = "helmfile"; +} diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java new file mode 100644 index 000000000..99a4ed4e4 --- /dev/null +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java @@ -0,0 +1,18 @@ +package com.netflix.spinnaker.rosco.manifests.helmfile; + +import com.netflix.spinnaker.kork.artifacts.model.Artifact; +import com.netflix.spinnaker.rosco.manifests.BakeManifestRequest; +import java.util.List; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HelmfileBakeManifestRequest extends BakeManifestRequest { + private String helmfileFilePath; + private String environment; + private String namespace; + + List inputArtifacts; + boolean includeCRDs; +} diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java new file mode 100644 index 000000000..ce2fce969 --- /dev/null +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java @@ -0,0 +1,49 @@ +package com.netflix.spinnaker.rosco.manifests.helmfile; + +import static com.netflix.spinnaker.rosco.manifests.BakeManifestRequest.TemplateRenderer; + +import com.google.common.collect.ImmutableSet; +import com.netflix.spinnaker.kork.artifacts.model.Artifact; +import com.netflix.spinnaker.rosco.jobs.BakeRecipe; +import com.netflix.spinnaker.rosco.jobs.JobExecutor; +import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; +import com.netflix.spinnaker.rosco.manifests.BakeManifestService; +import java.io.IOException; +import java.util.Base64; +import org.springframework.stereotype.Component; + +@Component +public class HelmfileBakeManifestService extends BakeManifestService { + private final HelmfileTemplateUtils helmfileTemplateUtils; + private static final ImmutableSet supportedTemplates = + ImmutableSet.of(TemplateRenderer.HELMFILE.toString()); + + public HelmfileBakeManifestService( + HelmfileTemplateUtils helmTemplateUtils, JobExecutor jobExecutor) { + super(jobExecutor); + this.helmfileTemplateUtils = helmTemplateUtils; + } + + @Override + public Class requestType() { + return HelmfileBakeManifestRequest.class; + } + + @Override + public boolean handles(String type) { + return supportedTemplates.contains(type); + } + + public Artifact bake(HelmfileBakeManifestRequest helmfileBakeManifestRequest) throws IOException { + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, helmfileBakeManifestRequest); + + String bakeResult = helmfileTemplateUtils.removeTestsDirectoryTemplates(doBake(recipe)); + return Artifact.builder() + .type("embedded/base64") + .name(helmfileBakeManifestRequest.getOutputArtifactName()) + .reference(Base64.getEncoder().encodeToString(bakeResult.getBytes())) + .build(); + } + } +} diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java new file mode 100644 index 000000000..b7eae94f0 --- /dev/null +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -0,0 +1,157 @@ +package com.netflix.spinnaker.rosco.manifests.helmfile; + +import com.netflix.spinnaker.kork.artifacts.model.Artifact; +import com.netflix.spinnaker.kork.exceptions.SpinnakerException; +import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; +import com.netflix.spinnaker.rosco.jobs.BakeRecipe; +import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; +import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; +import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmConfigurationProperties; +import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmfileConfigurationProperties; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class HelmfileTemplateUtils { + private static final String MANIFEST_SEPARATOR = "---\n"; + private static final Pattern REGEX_TESTS_MANIFESTS = + Pattern.compile("# Source: .*/templates/tests/.*"); + + private final ArtifactDownloader artifactDownloader; + private final RoscoHelmfileConfigurationProperties helmfileConfigurationProperties; + private final RoscoHelmConfigurationProperties helmConfigurationProperties = + new RoscoHelmConfigurationProperties(); + + public HelmfileTemplateUtils( + ArtifactDownloader artifactDownloader, + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties) { + this.artifactDownloader = artifactDownloader; + this.helmfileConfigurationProperties = helmfileConfigurationProperties; + } + + public BakeRecipe buildBakeRecipe( + BakeManifestEnvironment env, HelmfileBakeManifestRequest request) throws IOException { + BakeRecipe result = new BakeRecipe(); + result.setName(request.getOutputName()); + + Path helmfileFilePath; + + List valuePaths = new ArrayList<>(); + List inputArtifacts = request.getInputArtifacts(); + if (inputArtifacts == null || inputArtifacts.isEmpty()) { + throw new IllegalArgumentException("At least one input artifact must be provided to bake"); + } + + log.info("helmfileFilePath: '{}'", request.getHelmfileFilePath()); + Artifact helmfileTemplateArtifact = inputArtifacts.get(0); + String artifactType = Optional.ofNullable(helmfileTemplateArtifact.getType()).orElse(""); + if ("git/repo".equals(artifactType)) { + env.downloadArtifactTarballAndExtract(artifactDownloader, helmfileTemplateArtifact); + + // If there's no helmfile path specified, assume it lives in the root of + // the git/repo artifact. + helmfileFilePath = + env.resolvePath(Optional.ofNullable(request.getHelmfileFilePath()).orElse("")); + } else { + try { + helmfileFilePath = downloadArtifactToTmpFile(env, helmfileTemplateArtifact); + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("template", e), e); + } + } + + log.info("path to helmfile: {}", helmfileFilePath); + + try { + // not a stream to keep exception handling cleaner + for (Artifact valueArtifact : inputArtifacts.subList(1, inputArtifacts.size())) { + valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); + } + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("values file", e), e); + } + + List command = new ArrayList<>(); + String executable = helmfileConfigurationProperties.getExecutablePath(); + + command.add(executable); + command.add("template"); + command.add("--file"); + command.add(helmfileFilePath.toString()); + + command.add("--helm-binary"); + command.add(getHelm3ExecutablePath()); + + String environment = request.getEnvironment(); + if (environment != null && !environment.isEmpty()) { + command.add("--environment"); + command.add(environment); + } + + String namespace = request.getNamespace(); + if (namespace != null && !namespace.isEmpty()) { + command.add("--namespace"); + command.add(namespace); + } + + if (request.isIncludeCRDs()) { + command.add("--include-crds"); + } + + Map overrides = request.getOverrides(); + if (!overrides.isEmpty()) { + List overrideList = new ArrayList<>(); + for (Map.Entry entry : overrides.entrySet()) { + overrideList.add(entry.getKey() + "=" + entry.getValue().toString()); + } + command.add("--set"); + command.add(String.join(",", overrideList)); + } + + if (!valuePaths.isEmpty()) { + command.add("--values"); + command.add(valuePaths.stream().map(Path::toString).collect(Collectors.joining(","))); + } + + result.setCommand(command); + + return result; + } + + private String fetchFailureMessage(String description, Exception e) { + return "Failed to fetch helmfile " + description + ": " + e.getMessage(); + } + + public String removeTestsDirectoryTemplates(String inputString) { + return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) + .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) + .collect(Collectors.joining(MANIFEST_SEPARATOR)); + } + + private Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) + throws IOException { + String fileName = UUID.randomUUID().toString(); + Path targetPath = env.resolvePath(fileName); + artifactDownloader.downloadArtifactToFile(artifact, targetPath); + return targetPath; + } + + private String getHelm3ExecutablePath() { + return helmConfigurationProperties.getV3ExecutablePath(); + } +} diff --git a/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java b/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java new file mode 100644 index 000000000..0cb22234d --- /dev/null +++ b/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java @@ -0,0 +1,674 @@ +/* + * Copyright 2019 Google, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.rosco.manifests.helmfile; + +import static com.netflix.spinnaker.rosco.manifests.ManifestTestUtils.makeSpinnakerHttpException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.netflix.spinnaker.kork.artifacts.model.Artifact; +import com.netflix.spinnaker.kork.exceptions.SpinnakerException; +import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; +import com.netflix.spinnaker.rosco.jobs.BakeRecipe; +import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; +import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; +import com.netflix.spinnaker.rosco.manifests.BakeManifestRequest; +import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmConfigurationProperties; +import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmfileConfigurationProperties; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; +import org.apache.commons.compress.utils.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; +import org.springframework.http.HttpStatus; + +@RunWith(JUnitPlatform.class) +final class HelmfileTemplateUtilsTest { + + private ArtifactDownloader artifactDownloader; + + private HelmfileTemplateUtils helmfileTemplateUtils; + + private HelmfileBakeManifestRequest bakeManifestRequest; + + @BeforeEach + private void init(TestInfo testInfo) { + System.out.println("--------------- Test " + testInfo.getDisplayName()); + + artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + Artifact chartArtifact = Artifact.builder().name("test-artifact").version("3").build(); + + bakeManifestRequest = new HelmfileBakeManifestRequest(); + bakeManifestRequest.setInputArtifacts(ImmutableList.of(chartArtifact)); + } + + @Test + public void nullReferenceTest() throws IOException { + bakeManifestRequest.setOverrides(ImmutableMap.of()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, bakeManifestRequest); + } + } + + @Test + public void exceptionDownloading() throws IOException { + // When artifactDownloader throws an exception, make sure we wrap it and get + // a chance to include our own message, so the exception that goes up the + // chain includes something about helmfile. + SpinnakerException spinnakerException = new SpinnakerException("error from ArtifactDownloader"); + doThrow(spinnakerException) + .when(artifactDownloader) + .downloadArtifactToFile(any(Artifact.class), any(Path.class)); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + IllegalStateException thrown = + assertThrows( + IllegalStateException.class, + () -> helmfileTemplateUtils.buildBakeRecipe(env, bakeManifestRequest)); + + assertThat(thrown.getMessage()).contains("Failed to fetch helmfile template"); + assertThat(thrown.getCause()).isEqualTo(spinnakerException); + } + } + + @Test + public void httpExceptionDownloading() throws IOException { + // When artifactDownloader throws a SpinnakerHttpException, make sure we + // wrap it and get a chance to include our own message, so the exception + // that goes up the chain includes something about helm charts. It's + // important that HelmTemplateUtils also throws a SpinnakerHttpException so + // it's eventually handled properly...meaning the status code in the http + // response and the logging correspond to what happened. For example, if + // there's a 404 from clouddriver, rosco also responds with 404, and doesn't + // log an error. + + SpinnakerHttpException spinnakerHttpException = + makeSpinnakerHttpException(HttpStatus.NOT_FOUND.value()); + doThrow(spinnakerHttpException) + .when(artifactDownloader) + .downloadArtifactToFile(any(Artifact.class), any(Path.class)); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + SpinnakerHttpException thrown = + assertThrows( + SpinnakerHttpException.class, + () -> helmfileTemplateUtils.buildBakeRecipe(env, bakeManifestRequest)); + + assertThat(thrown.getMessage()).contains("Failed to fetch helmfile template"); + assertThat(thrown.getResponseCode()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(thrown.getCause()).isEqualTo(spinnakerHttpException); + } + } + + @Test + public void removeTestsDirectoryTemplatesWithTests() throws IOException { + String inputManifests = + "---\n" + + "# Source: mysql/templates/pvc.yaml\n" + + "\n" + + "kind: PersistentVolumeClaim\n" + + "apiVersion: v1\n" + + "metadata:\n" + + " name: release-name-mysql\n" + + " namespace: default\n" + + "spec:\n" + + " accessModes:\n" + + " - \"ReadWriteOnce\"\n" + + " resources:\n" + + " requests:\n" + + " storage: \"8Gi\"\n" + + "---\n" + + "# Source: mysql/templates/tests/test-configmap.yaml\n" + + "apiVersion: v1\n" + + "kind: ConfigMap\n" + + "metadata:\n" + + " name: release-name-mysql-test\n" + + " namespace: default\n" + + "data:\n" + + " run.sh: |-\n"; + + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + String output = helmfileTemplateUtils.removeTestsDirectoryTemplates(inputManifests); + + String expected = + "---\n" + + "# Source: mysql/templates/pvc.yaml\n" + + "\n" + + "kind: PersistentVolumeClaim\n" + + "apiVersion: v1\n" + + "metadata:\n" + + " name: release-name-mysql\n" + + " namespace: default\n" + + "spec:\n" + + " accessModes:\n" + + " - \"ReadWriteOnce\"\n" + + " resources:\n" + + " requests:\n" + + " storage: \"8Gi\"\n"; + + assertEquals(expected.trim(), output.trim()); + } + + @Test + public void removeTestsDirectoryTemplatesWithoutTests() throws IOException { + String inputManifests = + "---\n" + + "# Source: mysql/templates/pvc.yaml\n" + + "\n" + + "kind: PersistentVolumeClaim\n" + + "apiVersion: v1\n" + + "metadata:\n" + + " name: release-name-mysql\n" + + " namespace: default\n" + + "spec:\n" + + " accessModes:\n" + + " - \"ReadWriteOnce\"\n" + + " resources:\n" + + " requests:\n" + + " storage: \"8Gi\"\n" + + "---\n" + + "# Source: mysql/templates/configmap.yaml\n" + + "apiVersion: v1\n" + + "kind: ConfigMap\n" + + "metadata:\n" + + " name: release-name-mysql-test\n" + + " namespace: default\n" + + "data:\n" + + " run.sh: |-\n"; + + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + String output = helmfileTemplateUtils.removeTestsDirectoryTemplates(inputManifests); + + assertEquals(inputManifests.trim(), output.trim()); + } + + @ParameterizedTest + @MethodSource("helmfileRendererArgs") + public void buildBakeRecipeSelectsHelm3ExecutableWhenNoneSet( + String command, BakeManifestRequest.TemplateRenderer templateRenderer) throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + RoscoHelmConfigurationProperties helmConfigurationProperties = + new RoscoHelmConfigurationProperties(); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + request.setTemplateRenderer(templateRenderer); + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + + assertEquals(helmConfigurationProperties.getV3ExecutablePath(), recipe.getCommand().get(5)); + } + } + + private static Stream helmfileRendererArgs() { + // The command here (e.g. helmfile) must match the defaults in + // RoscoHelmfileConfigurationProperties + return Stream.of(Arguments.of("helmfile", BakeManifestRequest.TemplateRenderer.HELMFILE)); + } + + @Test + public void buildBakeRecipeWithGitRepoArtifact(@TempDir Path tempDir) throws IOException { + // git/repo artifacts appear as a tarball, so create one that contains a + // helmfile file + // and helm chart. + addTestHelmfile(tempDir); + + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + + Artifact artifact = + Artifact.builder().type("git/repo").reference("https://github.com/some/repo.git").build(); + + // Set up the mock artifactDownloader to supply the tarball that represents + // the git/repo artifact + when(artifactDownloader.downloadArtifact(artifact)).thenReturn(makeTarball(tempDir)); + + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + + // Make sure we're really testing the git/repo logic + verify(artifactDownloader).downloadArtifact(artifact); + + // Make sure the BakeManifestEnvironment has the files in our git/repo artifact. + assertTrue(env.resolvePath("helmfile.yaml").toFile().exists()); + assertTrue(env.resolvePath("Chart.yaml").toFile().exists()); + assertTrue(env.resolvePath("values.yaml").toFile().exists()); + assertTrue(env.resolvePath("templates/foo.yaml").toFile().exists()); + } + } + + @Test + public void buildBakeRecipeWithGitRepoArtifactUsingHelmfileFilePath(@TempDir Path tempDir) + throws IOException { + // Create a tarball with a helmfile in a sub directory + String subDirName = "subdir"; + Path subDir = tempDir.resolve(subDirName); + addTestHelmfile(subDir); + + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + + // Note that supplying a location for a git/repo artifact doesn't change the + // path in the resulting tarball. It's here because it's likely that it's + // used together with helmChartFilePath. Removing it wouldn't change the + // test. + Artifact artifact = + Artifact.builder() + .type("git/repo") + .reference("https://github.com/some/repo.git") + .location(subDirName) + .build(); + + // Set up the mock artifactDownloader to supply the tarball that represents + // the git/repo artifact + when(artifactDownloader.downloadArtifact(artifact)).thenReturn(makeTarball(tempDir)); + + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + // This is the key part of this test. + request.setHelmfileFilePath(subDirName); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + + // Make sure we're really testing the git/repo logic + verify(artifactDownloader).downloadArtifact(artifact); + + // Make sure the BakeManifestEnvironment has the files in our git/repo + // artifact in the expected location. + assertTrue(env.resolvePath(Path.of(subDirName, "helmfile.yaml")).toFile().exists()); + assertTrue(env.resolvePath(Path.of(subDirName, "Chart.yaml")).toFile().exists()); + assertTrue(env.resolvePath(Path.of(subDirName, "values.yaml")).toFile().exists()); + assertTrue(env.resolvePath(Path.of(subDirName, "templates/foo.yaml")).toFile().exists()); + + // And that the helm template command includes the path to the subdirectory + // + // The expected elements in the + // command list are: + // + // 0 - the helm executable + // 1 - template + // 2 - --file flag + // 3 - the path to helmfile.yaml + assertEquals(env.resolvePath(subDirName).toString(), recipe.getCommand().get(3)); + } + } + + /** + * Add a helmfile and helm chart for testing + * + * @param path the location of the helmfile file (e.g. helmfile.yaml) + */ + void addTestHelmfile(Path path) throws IOException { + addFile( + path, + "helmfile.yaml", + "releases:\n" + + " - name: test\n" + + " namespace: namespace\n" + + " chart: Chart.yaml\n" + + " values:\n" + + " - values.yaml\n"); + + addFile( + path, + "Chart.yaml", + "apiVersion: v1\n" + + "name: example\n" + + "description: chart for testing\n" + + "version: 0.1\n" + + "engine: gotpl\n"); + + addFile(path, "values.yaml", "foo: bar\n"); + + addFile( + path, + "templates/foo.yaml", + "labels:\n" + "helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}\n"); + } + + /** + * Create a new file in the temp directory + * + * @param path the path of the file to create (relative to the temp directory's root) + * @param content the content of the file, or null for an empty file + */ + void addFile(Path tempDir, String path, String content) throws IOException { + Path pathToCreate = tempDir.resolve(path); + pathToCreate.toFile().getParentFile().mkdirs(); + Files.write(pathToCreate, content.getBytes()); + } + + /** + * Make a gzipped tarball of all files in a path + * + * @param rootPath the root path of the tarball + * @return an InputStream containing the gzipped tarball + */ + InputStream makeTarball(Path rootPath) throws IOException { + ArrayList filePathsToAdd = + Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS) + .filter(path -> !path.equals(rootPath)) + .collect(Collectors.toCollection(ArrayList::new)); + + // See + // https://commons.apache.org/proper/commons-compress/examples.html#Common_Archival_Logic + // for background + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + GzipCompressorOutputStream gzo = new GzipCompressorOutputStream(os); + TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(gzo)) { + for (Path path : filePathsToAdd) { + TarArchiveEntry tarEntry = + new TarArchiveEntry(path.toFile(), rootPath.relativize(path).toString()); + tarArchive.setBigNumberMode(tarArchive.BIGNUMBER_POSIX); + tarArchive.setLongFileMode(tarArchive.LONGFILE_POSIX); + tarArchive.putArchiveEntry(tarEntry); + if (path.toFile().isFile()) { + IOUtils.copy(Files.newInputStream(path), tarArchive); + } + tarArchive.closeArchiveEntry(); + } + + tarArchive.finish(); + gzo.finish(); + + return new ByteArrayInputStream(os.toByteArray()); + } + } + + @Test + public void buildBakeRecipeIncludesEnvironmentWhenSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + String envName = "testEnvironment"; + request.setEnvironment(envName); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertTrue(recipe.getCommand().contains("--environment")); + assertTrue(recipe.getCommand().contains(envName)); + // Assert that the flag position goes after 'helmfile template' subcommand + assertTrue(recipe.getCommand().indexOf("--environment") > 1); + } + } + + @Test + public void buildBakeRecipeDoesNotIncludeEnvironmentWhenNotSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertFalse(recipe.getCommand().contains("--environment")); + } + } + + @Test + public void buildBakeRecipeIncludesNamespaceWhenSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + String namespaceName = "testNamespace"; + request.setNamespace(namespaceName); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertTrue(recipe.getCommand().contains("--namespace")); + assertTrue(recipe.getCommand().contains(namespaceName)); + // Assert that the flag position goes after 'helmfile template' subcommand + assertTrue(recipe.getCommand().indexOf("--namespace") > 1); + } + } + + @Test + public void buildBakeRecipeDoesNotIncludeNamespaceWhenNotSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertFalse(recipe.getCommand().contains("--namespace")); + } + } + + @Test + public void buildBakeRecipeIncludingCRDsWithHelm3() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setIncludeCRDs(true); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertTrue(recipe.getCommand().contains("--include-crds")); + // Assert that the flag position goes after 'helmfile template' subcommand + assertTrue(recipe.getCommand().indexOf("--include-crds") > 1); + } + } + + @Test + public void buildBakeRecipeNotIncludingCRDsWithHelm3() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertFalse(recipe.getCommand().contains("--include-crds")); + } + } + + @Test + public void buildBakeRecipeIncludesOverridesWhenSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + String overrideKey = "testOverrideKey"; + String overrideValue = "testOverrideValue"; + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.singletonMap(overrideKey, overrideValue)); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertTrue(recipe.getCommand().contains("--set")); + assertTrue(recipe.getCommand().contains(overrideKey + "=" + overrideValue)); + // Assert that the flag position goes after 'helmfile template' subcommand + assertTrue(recipe.getCommand().indexOf("--set") > 1); + } + } + + @Test + public void buildBakeRecipeDoesNotIncludeOverridesWhenNotSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertFalse(recipe.getCommand().contains("--set")); + } + } + + @Test + public void buildBakeRecipeIncludesValuesWhenSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + + List artifacts = new ArrayList<>(); + Artifact artifact = Artifact.builder().build(); + Artifact testValue = Artifact.builder().build(); + artifacts.add(artifact); + artifacts.add(testValue); + + request.setInputArtifacts(artifacts); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertTrue(recipe.getCommand().contains("--values")); + // Assert that the flag position goes after 'helmfile template' subcommand + assertTrue(recipe.getCommand().indexOf("--values") > 1); + } + } + + @Test + public void buildBakeRecipeDoesNotIncludeValuesWhenNotSet() throws IOException { + ArtifactDownloader artifactDownloader = mock(ArtifactDownloader.class); + RoscoHelmfileConfigurationProperties helmfileConfigurationProperties = + new RoscoHelmfileConfigurationProperties(); + HelmfileTemplateUtils helmfileTemplateUtils = + new HelmfileTemplateUtils(artifactDownloader, helmfileConfigurationProperties); + + HelmfileBakeManifestRequest request = new HelmfileBakeManifestRequest(); + Artifact artifact = Artifact.builder().build(); + request.setInputArtifacts(Collections.singletonList(artifact)); + request.setOverrides(Collections.emptyMap()); + + try (BakeManifestEnvironment env = BakeManifestEnvironment.create()) { + BakeRecipe recipe = helmfileTemplateUtils.buildBakeRecipe(env, request); + assertFalse(recipe.getCommand().contains("--values")); + } + } +} diff --git a/rosco-web/src/main/groovy/com/netflix/spinnaker/rosco/Main.groovy b/rosco-web/src/main/groovy/com/netflix/spinnaker/rosco/Main.groovy index 1f6fa34a8..4349529e7 100644 --- a/rosco-web/src/main/groovy/com/netflix/spinnaker/rosco/Main.groovy +++ b/rosco-web/src/main/groovy/com/netflix/spinnaker/rosco/Main.groovy @@ -19,6 +19,7 @@ package com.netflix.spinnaker.rosco import com.netflix.spinnaker.rosco.config.RoscoPackerConfigurationProperties import com.netflix.spinnaker.rosco.jobs.config.LocalJobConfig import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmConfigurationProperties +import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmfileConfigurationProperties import com.netflix.spinnaker.rosco.manifests.config.RoscoKustomizeConfigurationProperties import com.netflix.spinnaker.rosco.providers.alicloud.config.RoscoAliCloudConfiguration import com.netflix.spinnaker.rosco.providers.aws.config.RoscoAWSConfiguration @@ -68,6 +69,7 @@ import javax.servlet.Filter RoscoTencentCloudConfiguration, RoscoPackerConfigurationProperties, RoscoHelmConfigurationProperties, + RoscoHelmfileConfigurationProperties, RoscoKustomizeConfigurationProperties, LocalJobConfig ]) From 30ad3e3f69d88ad81e3a1e8e463fda07630c34fc Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Tue, 20 Jun 2023 11:19:00 +0200 Subject: [PATCH 03/12] copyright Signed-off-by: Salvatore Mazzarino --- .../RoscoHelmfileConfigurationProperties.java | 4 ++-- .../helmfile/HelmfileBakeManifestRequest.java | 16 ++++++++++++++++ .../helmfile/HelmfileBakeManifestService.java | 16 ++++++++++++++++ .../helmfile/HelmfileTemplateUtils.java | 16 ++++++++++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java index f91deadd9..c9bd9fa93 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/config/RoscoHelmfileConfigurationProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Grab Holdings, Inc. + * Copyright 2023 Grab Holdings, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,5 +22,5 @@ @ConfigurationProperties("helmfile") @Data public class RoscoHelmfileConfigurationProperties { - private String ExecutablePath = "helmfile"; + private String executablePath = "helmfile"; } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java index 99a4ed4e4..9b878c206 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Grab Holdings, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.netflix.spinnaker.rosco.manifests.helmfile; import com.netflix.spinnaker.kork.artifacts.model.Artifact; diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java index ce2fce969..a3061927a 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestService.java @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Grab Holdings, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.netflix.spinnaker.rosco.manifests.helmfile; import static com.netflix.spinnaker.rosco.manifests.BakeManifestRequest.TemplateRenderer; diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index b7eae94f0..85823f1eb 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Grab Holdings, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.netflix.spinnaker.rosco.manifests.helmfile; import com.netflix.spinnaker.kork.artifacts.model.Artifact; From 997a5749ccf7b8a586b9185476c894681e2766ad Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Tue, 20 Jun 2023 11:23:03 +0200 Subject: [PATCH 04/12] test changes Signed-off-by: Salvatore Mazzarino --- .../rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java b/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java index 0cb22234d..a6119e6be 100644 --- a/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java +++ b/rosco-manifests/src/test/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Google, LLC + * Copyright 2023 Grab Holdings, Inc. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. @@ -62,11 +62,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; import org.springframework.http.HttpStatus; -@RunWith(JUnitPlatform.class) final class HelmfileTemplateUtilsTest { private ArtifactDownloader artifactDownloader; From a67d35dc813af7377c6341985529fa442210494b Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Tue, 20 Jun 2023 12:34:14 +0200 Subject: [PATCH 05/12] add javadoc Signed-off-by: Salvatore Mazzarino --- .../helmfile/HelmfileBakeManifestRequest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java index 9b878c206..097802c2d 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java @@ -26,9 +26,27 @@ @EqualsAndHashCode(callSuper = true) public class HelmfileBakeManifestRequest extends BakeManifestRequest { private String helmfileFilePath; + + /** + * The environment name used to customize the content of the helmfile manifest. + * The environment name defaults to default. + */ private String environment; + + /** + * The namespace to be released into. + */ private String namespace; + /** + * The 0th element is (or contains) the helmfile template. The rest (possibly none) are values + * files. + */ List inputArtifacts; + + /** + * Include custom resource definition manifests in the templated output. + * Helmfile uses Helm v3 only which provides the option to include CRDs as part of the rendered output. + */ boolean includeCRDs; } From 7e1f5160aaa7459b22009484ea56c8b6dcd8aea9 Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Thu, 22 Jun 2023 18:16:24 +0200 Subject: [PATCH 06/12] make the code dry Signed-off-by: Salvatore Mazzarino --- .../manifests/HelmBakeTemplateUtils.java | 61 +++++++++++++++++++ .../manifests/helm/HelmTemplateUtils.java | 33 ++-------- .../helmfile/HelmfileTemplateUtils.java | 36 +++-------- 3 files changed, 75 insertions(+), 55 deletions(-) create mode 100644 rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java new file mode 100644 index 000000000..683137528 --- /dev/null +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java @@ -0,0 +1,61 @@ +/* + * Copyright 2023 Grab Holdings, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.rosco.manifests; + +import com.netflix.spinnaker.kork.artifacts.model.Artifact; +import com.netflix.spinnaker.kork.exceptions.SpinnakerException; +import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public abstract class HelmBakeTemplateUtils { + private static final String MANIFEST_SEPARATOR = "---\n"; + private static final Pattern REGEX_TESTS_MANIFESTS = + Pattern.compile("# Source: .*/templates/tests/.*"); + + private final ArtifactDownloader artifactDownloader; + + protected HelmBakeTemplateUtils(ArtifactDownloader artifactDownloader) { + this.artifactDownloader = artifactDownloader; + } + + public ArtifactDownloader getArtifactDownloader() { + return artifactDownloader; + } + + public abstract String fetchFailureMessage(String description, Exception e); + + public String removeTestsDirectoryTemplates(String inputString) { + return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) + .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) + .collect(Collectors.joining(MANIFEST_SEPARATOR)); + } + + protected Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) + throws IOException { + String fileName = UUID.randomUUID().toString(); + Path targetPath = env.resolvePath(fileName); + artifactDownloader.downloadArtifactToFile(artifact, targetPath); + return targetPath; + } + + public abstract String getHelmExecutableForRequest(T request); +} diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java index cd92fd3e8..214d60e55 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java @@ -7,34 +7,27 @@ import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; import com.netflix.spinnaker.rosco.manifests.BakeManifestRequest; +import com.netflix.spinnaker.rosco.manifests.HelmBakeTemplateUtils; import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmConfigurationProperties; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.UUID; -import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component @Slf4j -public class HelmTemplateUtils { - private static final String MANIFEST_SEPARATOR = "---\n"; - private static final Pattern REGEX_TESTS_MANIFESTS = - Pattern.compile("# Source: .*/templates/tests/.*"); - - private final ArtifactDownloader artifactDownloader; +public class HelmTemplateUtils extends HelmBakeTemplateUtils { private final RoscoHelmConfigurationProperties helmConfigurationProperties; public HelmTemplateUtils( ArtifactDownloader artifactDownloader, RoscoHelmConfigurationProperties helmConfigurationProperties) { - this.artifactDownloader = artifactDownloader; + super(artifactDownloader); this.helmConfigurationProperties = helmConfigurationProperties; } @@ -53,7 +46,7 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR Artifact helmTemplateArtifact = inputArtifacts.get(0); String artifactType = Optional.ofNullable(helmTemplateArtifact.getType()).orElse(""); if ("git/repo".equals(artifactType)) { - env.downloadArtifactTarballAndExtract(artifactDownloader, helmTemplateArtifact); + env.downloadArtifactTarballAndExtract(super.getArtifactDownloader(), helmTemplateArtifact); log.info("helmChartFilePath: '{}'", request.getHelmChartFilePath()); @@ -134,25 +127,11 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR return result; } - private String fetchFailureMessage(String description, Exception e) { + public String fetchFailureMessage(String description, Exception e) { return "Failed to fetch helm " + description + ": " + e.getMessage(); } - public String removeTestsDirectoryTemplates(String inputString) { - return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) - .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) - .collect(Collectors.joining(MANIFEST_SEPARATOR)); - } - - private Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) - throws IOException { - String fileName = UUID.randomUUID().toString(); - Path targetPath = env.resolvePath(fileName); - artifactDownloader.downloadArtifactToFile(artifact, targetPath); - return targetPath; - } - - private String getHelmExecutableForRequest(HelmBakeManifestRequest request) { + public String getHelmExecutableForRequest(HelmBakeManifestRequest request) { if (BakeManifestRequest.TemplateRenderer.HELM2.equals(request.getTemplateRenderer())) { return helmConfigurationProperties.getV2ExecutablePath(); } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index 85823f1eb..89cc86688 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -22,29 +22,23 @@ import com.netflix.spinnaker.rosco.jobs.BakeRecipe; import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; +import com.netflix.spinnaker.rosco.manifests.HelmBakeTemplateUtils; import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmConfigurationProperties; import com.netflix.spinnaker.rosco.manifests.config.RoscoHelmfileConfigurationProperties; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.UUID; -import java.util.regex.Pattern; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component @Slf4j -public class HelmfileTemplateUtils { - private static final String MANIFEST_SEPARATOR = "---\n"; - private static final Pattern REGEX_TESTS_MANIFESTS = - Pattern.compile("# Source: .*/templates/tests/.*"); - - private final ArtifactDownloader artifactDownloader; +public class HelmfileTemplateUtils extends HelmBakeTemplateUtils { private final RoscoHelmfileConfigurationProperties helmfileConfigurationProperties; private final RoscoHelmConfigurationProperties helmConfigurationProperties = new RoscoHelmConfigurationProperties(); @@ -52,7 +46,7 @@ public class HelmfileTemplateUtils { public HelmfileTemplateUtils( ArtifactDownloader artifactDownloader, RoscoHelmfileConfigurationProperties helmfileConfigurationProperties) { - this.artifactDownloader = artifactDownloader; + super(artifactDownloader); this.helmfileConfigurationProperties = helmfileConfigurationProperties; } @@ -73,7 +67,7 @@ public BakeRecipe buildBakeRecipe( Artifact helmfileTemplateArtifact = inputArtifacts.get(0); String artifactType = Optional.ofNullable(helmfileTemplateArtifact.getType()).orElse(""); if ("git/repo".equals(artifactType)) { - env.downloadArtifactTarballAndExtract(artifactDownloader, helmfileTemplateArtifact); + env.downloadArtifactTarballAndExtract(super.getArtifactDownloader(), helmfileTemplateArtifact); // If there's no helmfile path specified, assume it lives in the root of // the git/repo artifact. @@ -111,7 +105,7 @@ public BakeRecipe buildBakeRecipe( command.add(helmfileFilePath.toString()); command.add("--helm-binary"); - command.add(getHelm3ExecutablePath()); + command.add(getHelmExecutableForRequest(null)); String environment = request.getEnvironment(); if (environment != null && !environment.isEmpty()) { @@ -149,25 +143,11 @@ public BakeRecipe buildBakeRecipe( return result; } - private String fetchFailureMessage(String description, Exception e) { + public String fetchFailureMessage(String description, Exception e) { return "Failed to fetch helmfile " + description + ": " + e.getMessage(); } - public String removeTestsDirectoryTemplates(String inputString) { - return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) - .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) - .collect(Collectors.joining(MANIFEST_SEPARATOR)); - } - - private Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) - throws IOException { - String fileName = UUID.randomUUID().toString(); - Path targetPath = env.resolvePath(fileName); - artifactDownloader.downloadArtifactToFile(artifact, targetPath); - return targetPath; - } - - private String getHelm3ExecutablePath() { + public String getHelmExecutableForRequest(HelmfileBakeManifestRequest request) { return helmConfigurationProperties.getV3ExecutablePath(); } } From 256756c8639f715b1b6d97fb22d35600bb3985cb Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Thu, 22 Jun 2023 19:45:32 +0200 Subject: [PATCH 07/12] reduce value paths Signed-off-by: Salvatore Mazzarino --- .../rosco/manifests/HelmBakeTemplateUtils.java | 17 +++++++++++++++++ .../rosco/manifests/helm/HelmTemplateUtils.java | 14 +++----------- .../helmfile/HelmfileTemplateUtils.java | 13 ++----------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java index 683137528..117f44f84 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java @@ -58,4 +58,21 @@ protected Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact a } public abstract String getHelmExecutableForRequest(T request); + + protected List getValuePaths(List artifacts, BakeManifestEnvironment env) { + List valuePaths = new ArrayList<>(); + + try { + // not a stream to keep exception handling cleaner + for (Artifact valueArtifact : artifacts.subList(1, artifacts.size())) { + valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); + } + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("values file", e), e); + } + + return valuePaths; + } } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java index 214d60e55..0d412a484 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java @@ -37,7 +37,8 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR result.setName(request.getOutputName()); Path templatePath; - List valuePaths = new ArrayList<>(); + List valuePaths; + List inputArtifacts = request.getInputArtifacts(); if (inputArtifacts == null || inputArtifacts.isEmpty()) { throw new IllegalArgumentException("At least one input artifact must be provided to bake"); @@ -66,16 +67,7 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR log.info("path to Chart.yaml: {}", templatePath); - try { - // not a stream to keep exception handling cleaner - for (Artifact valueArtifact : inputArtifacts.subList(1, inputArtifacts.size())) { - valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); - } - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("values file", e), e); - } + valuePaths = getValuePaths(inputArtifacts, env); List command = new ArrayList<>(); String executable = getHelmExecutableForRequest(request); diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index 89cc86688..21b0a98d8 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -56,8 +56,8 @@ public BakeRecipe buildBakeRecipe( result.setName(request.getOutputName()); Path helmfileFilePath; + List valuePaths; - List valuePaths = new ArrayList<>(); List inputArtifacts = request.getInputArtifacts(); if (inputArtifacts == null || inputArtifacts.isEmpty()) { throw new IllegalArgumentException("At least one input artifact must be provided to bake"); @@ -85,16 +85,7 @@ public BakeRecipe buildBakeRecipe( log.info("path to helmfile: {}", helmfileFilePath); - try { - // not a stream to keep exception handling cleaner - for (Artifact valueArtifact : inputArtifacts.subList(1, inputArtifacts.size())) { - valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); - } - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("values file", e), e); - } + valuePaths = getValuePaths(inputArtifacts, env); List command = new ArrayList<>(); String executable = helmfileConfigurationProperties.getExecutablePath(); From c0ceabce016153a452ef26bb4ca91be5f20c7c8f Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Mon, 10 Jul 2023 10:22:27 +0200 Subject: [PATCH 08/12] avoid using wildcards Signed-off-by: Salvatore Mazzarino --- .../spinnaker/rosco/manifests/HelmBakeTemplateUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java index 117f44f84..c0dfac132 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java @@ -22,7 +22,10 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; import java.util.regex.Pattern; import java.util.stream.Collectors; From f2ac9e006e0de341dd461cfc814ca32102a751fa Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Mon, 10 Jul 2023 11:47:06 +0200 Subject: [PATCH 09/12] reduce redundant code Signed-off-by: Salvatore Mazzarino --- .../manifests/HelmBakeTemplateUtils.java | 25 +++++++++++++++++++ .../manifests/helm/HelmTemplateUtils.java | 21 +--------------- .../helmfile/HelmfileTemplateUtils.java | 19 +------------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java index c0dfac132..eba30af98 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -78,4 +79,28 @@ protected List getValuePaths(List artifacts, BakeManifestEnviron return valuePaths; } + + protected Path getHelmTypePathFromArtifact(BakeManifestEnvironment env, List inputArtifacts , String filePath) throws IOException { + Path helmTypeFilePath; + + Artifact helmTypeTemplateArtifact = inputArtifacts.get(0); + String artifactType = Optional.ofNullable(helmTypeTemplateArtifact.getType()).orElse(""); + + if ("git/repo".equals(artifactType)) { + env.downloadArtifactTarballAndExtract(getArtifactDownloader(), helmTypeTemplateArtifact); + + helmTypeFilePath = + env.resolvePath(Optional.ofNullable(filePath).orElse("")); + } else { + try { + helmTypeFilePath = downloadArtifactToTmpFile(env, helmTypeTemplateArtifact); + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("template", e), e); + } + } + + return helmTypeFilePath; + } } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java index 0d412a484..248a3563b 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java @@ -44,26 +44,7 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR throw new IllegalArgumentException("At least one input artifact must be provided to bake"); } - Artifact helmTemplateArtifact = inputArtifacts.get(0); - String artifactType = Optional.ofNullable(helmTemplateArtifact.getType()).orElse(""); - if ("git/repo".equals(artifactType)) { - env.downloadArtifactTarballAndExtract(super.getArtifactDownloader(), helmTemplateArtifact); - - log.info("helmChartFilePath: '{}'", request.getHelmChartFilePath()); - - // If there's no helm chart path specified, assume it lives in the root of - // the git/repo artifact. - templatePath = - env.resolvePath(Optional.ofNullable(request.getHelmChartFilePath()).orElse("")); - } else { - try { - templatePath = downloadArtifactToTmpFile(env, helmTemplateArtifact); - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("template", e), e); - } - } + templatePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmChartFilePath()); log.info("path to Chart.yaml: {}", templatePath); diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index 21b0a98d8..fb114e1c9 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -64,24 +64,7 @@ public BakeRecipe buildBakeRecipe( } log.info("helmfileFilePath: '{}'", request.getHelmfileFilePath()); - Artifact helmfileTemplateArtifact = inputArtifacts.get(0); - String artifactType = Optional.ofNullable(helmfileTemplateArtifact.getType()).orElse(""); - if ("git/repo".equals(artifactType)) { - env.downloadArtifactTarballAndExtract(super.getArtifactDownloader(), helmfileTemplateArtifact); - - // If there's no helmfile path specified, assume it lives in the root of - // the git/repo artifact. - helmfileFilePath = - env.resolvePath(Optional.ofNullable(request.getHelmfileFilePath()).orElse("")); - } else { - try { - helmfileFilePath = downloadArtifactToTmpFile(env, helmfileTemplateArtifact); - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("template", e), e); - } - } + helmfileFilePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmfileFilePath()); log.info("path to helmfile: {}", helmfileFilePath); From f877ba0d9d7768eaf9855c511719ae6eff75fddf Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Mon, 10 Jul 2023 12:06:48 +0200 Subject: [PATCH 10/12] increase reuse Signed-off-by: Salvatore Mazzarino --- .../manifests/helm/HelmTemplateUtils.java | 39 +++++++++---------- .../helmfile/HelmfileTemplateUtils.java | 31 +++++++-------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java index 248a3563b..c20326640 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java @@ -1,8 +1,6 @@ package com.netflix.spinnaker.rosco.manifests.helm; import com.netflix.spinnaker.kork.artifacts.model.Artifact; -import com.netflix.spinnaker.kork.exceptions.SpinnakerException; -import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; import com.netflix.spinnaker.rosco.jobs.BakeRecipe; import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; @@ -14,7 +12,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -33,11 +30,7 @@ public HelmTemplateUtils( public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestRequest request) throws IOException { - BakeRecipe result = new BakeRecipe(); - result.setName(request.getOutputName()); - Path templatePath; - List valuePaths; List inputArtifacts = request.getInputArtifacts(); if (inputArtifacts == null || inputArtifacts.isEmpty()) { @@ -47,8 +40,25 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR templatePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmChartFilePath()); log.info("path to Chart.yaml: {}", templatePath); + return buildCommand( + request, getValuePaths(inputArtifacts, env), templatePath); + } + + public String fetchFailureMessage(String description, Exception e) { + return "Failed to fetch helm " + description + ": " + e.getMessage(); + } + + public String getHelmExecutableForRequest(HelmBakeManifestRequest request) { + if (BakeManifestRequest.TemplateRenderer.HELM2.equals(request.getTemplateRenderer())) { + return helmConfigurationProperties.getV2ExecutablePath(); + } + return helmConfigurationProperties.getV3ExecutablePath(); + } - valuePaths = getValuePaths(inputArtifacts, env); + public BakeRecipe buildCommand( + HelmBakeManifestRequest request, List valuePaths, Path templatePath) { + BakeRecipe result = new BakeRecipe(); + result.setName(request.getOutputName()); List command = new ArrayList<>(); String executable = getHelmExecutableForRequest(request); @@ -75,7 +85,7 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR } if (request.isIncludeCRDs() - && request.getTemplateRenderer() == BakeManifestRequest.TemplateRenderer.HELM3) { + && request.getTemplateRenderer() == BakeManifestRequest.TemplateRenderer.HELM3) { command.add("--include-crds"); } @@ -99,15 +109,4 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR return result; } - - public String fetchFailureMessage(String description, Exception e) { - return "Failed to fetch helm " + description + ": " + e.getMessage(); - } - - public String getHelmExecutableForRequest(HelmBakeManifestRequest request) { - if (BakeManifestRequest.TemplateRenderer.HELM2.equals(request.getTemplateRenderer())) { - return helmConfigurationProperties.getV2ExecutablePath(); - } - return helmConfigurationProperties.getV3ExecutablePath(); - } } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index fb114e1c9..c5e3f6e01 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -17,8 +17,6 @@ package com.netflix.spinnaker.rosco.manifests.helmfile; import com.netflix.spinnaker.kork.artifacts.model.Artifact; -import com.netflix.spinnaker.kork.exceptions.SpinnakerException; -import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; import com.netflix.spinnaker.rosco.jobs.BakeRecipe; import com.netflix.spinnaker.rosco.manifests.ArtifactDownloader; import com.netflix.spinnaker.rosco.manifests.BakeManifestEnvironment; @@ -30,7 +28,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -52,11 +49,7 @@ public HelmfileTemplateUtils( public BakeRecipe buildBakeRecipe( BakeManifestEnvironment env, HelmfileBakeManifestRequest request) throws IOException { - BakeRecipe result = new BakeRecipe(); - result.setName(request.getOutputName()); - Path helmfileFilePath; - List valuePaths; List inputArtifacts = request.getInputArtifacts(); if (inputArtifacts == null || inputArtifacts.isEmpty()) { @@ -67,8 +60,22 @@ public BakeRecipe buildBakeRecipe( helmfileFilePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmfileFilePath()); log.info("path to helmfile: {}", helmfileFilePath); + return buildCommand( + request, getValuePaths(inputArtifacts, env), helmfileFilePath); + } + + public String fetchFailureMessage(String description, Exception e) { + return "Failed to fetch helmfile " + description + ": " + e.getMessage(); + } + + public String getHelmExecutableForRequest(HelmfileBakeManifestRequest request) { + return helmConfigurationProperties.getV3ExecutablePath(); + } - valuePaths = getValuePaths(inputArtifacts, env); + public BakeRecipe buildCommand( + HelmfileBakeManifestRequest request, List valuePaths, Path helmfileFilePath) { + BakeRecipe result = new BakeRecipe(); + result.setName(request.getOutputName()); List command = new ArrayList<>(); String executable = helmfileConfigurationProperties.getExecutablePath(); @@ -116,12 +123,4 @@ public BakeRecipe buildBakeRecipe( return result; } - - public String fetchFailureMessage(String description, Exception e) { - return "Failed to fetch helmfile " + description + ": " + e.getMessage(); - } - - public String getHelmExecutableForRequest(HelmfileBakeManifestRequest request) { - return helmConfigurationProperties.getV3ExecutablePath(); - } } From 3e86a4b886a1fa6a41be9559432a296ffbc2bc00 Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Thu, 13 Jul 2023 09:57:48 +0200 Subject: [PATCH 11/12] run spotless Signed-off-by: Salvatore Mazzarino --- .../manifests/HelmBakeTemplateUtils.java | 138 +++++++++--------- .../manifests/helm/HelmTemplateUtils.java | 7 +- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java index eba30af98..5e1f99075 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/HelmBakeTemplateUtils.java @@ -19,7 +19,6 @@ import com.netflix.spinnaker.kork.artifacts.model.Artifact; import com.netflix.spinnaker.kork.exceptions.SpinnakerException; import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerHttpException; - import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -31,76 +30,77 @@ import java.util.stream.Collectors; public abstract class HelmBakeTemplateUtils { - private static final String MANIFEST_SEPARATOR = "---\n"; - private static final Pattern REGEX_TESTS_MANIFESTS = - Pattern.compile("# Source: .*/templates/tests/.*"); - - private final ArtifactDownloader artifactDownloader; - - protected HelmBakeTemplateUtils(ArtifactDownloader artifactDownloader) { - this.artifactDownloader = artifactDownloader; - } - - public ArtifactDownloader getArtifactDownloader() { - return artifactDownloader; - } - - public abstract String fetchFailureMessage(String description, Exception e); - - public String removeTestsDirectoryTemplates(String inputString) { - return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) - .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) - .collect(Collectors.joining(MANIFEST_SEPARATOR)); - } - - protected Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) - throws IOException { - String fileName = UUID.randomUUID().toString(); - Path targetPath = env.resolvePath(fileName); - artifactDownloader.downloadArtifactToFile(artifact, targetPath); - return targetPath; + private static final String MANIFEST_SEPARATOR = "---\n"; + private static final Pattern REGEX_TESTS_MANIFESTS = + Pattern.compile("# Source: .*/templates/tests/.*"); + + private final ArtifactDownloader artifactDownloader; + + protected HelmBakeTemplateUtils(ArtifactDownloader artifactDownloader) { + this.artifactDownloader = artifactDownloader; + } + + public ArtifactDownloader getArtifactDownloader() { + return artifactDownloader; + } + + public abstract String fetchFailureMessage(String description, Exception e); + + public String removeTestsDirectoryTemplates(String inputString) { + return Arrays.stream(inputString.split(MANIFEST_SEPARATOR)) + .filter(manifest -> !REGEX_TESTS_MANIFESTS.matcher(manifest).find()) + .collect(Collectors.joining(MANIFEST_SEPARATOR)); + } + + protected Path downloadArtifactToTmpFile(BakeManifestEnvironment env, Artifact artifact) + throws IOException { + String fileName = UUID.randomUUID().toString(); + Path targetPath = env.resolvePath(fileName); + artifactDownloader.downloadArtifactToFile(artifact, targetPath); + return targetPath; + } + + public abstract String getHelmExecutableForRequest(T request); + + protected List getValuePaths(List artifacts, BakeManifestEnvironment env) { + List valuePaths = new ArrayList<>(); + + try { + // not a stream to keep exception handling cleaner + for (Artifact valueArtifact : artifacts.subList(1, artifacts.size())) { + valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); + } + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("values file", e), e); } - public abstract String getHelmExecutableForRequest(T request); - - protected List getValuePaths(List artifacts, BakeManifestEnvironment env) { - List valuePaths = new ArrayList<>(); - - try { - // not a stream to keep exception handling cleaner - for (Artifact valueArtifact : artifacts.subList(1, artifacts.size())) { - valuePaths.add(downloadArtifactToTmpFile(env, valueArtifact)); - } - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("values file", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("values file", e), e); - } - - return valuePaths; + return valuePaths; + } + + protected Path getHelmTypePathFromArtifact( + BakeManifestEnvironment env, List inputArtifacts, String filePath) + throws IOException { + Path helmTypeFilePath; + + Artifact helmTypeTemplateArtifact = inputArtifacts.get(0); + String artifactType = Optional.ofNullable(helmTypeTemplateArtifact.getType()).orElse(""); + + if ("git/repo".equals(artifactType)) { + env.downloadArtifactTarballAndExtract(getArtifactDownloader(), helmTypeTemplateArtifact); + + helmTypeFilePath = env.resolvePath(Optional.ofNullable(filePath).orElse("")); + } else { + try { + helmTypeFilePath = downloadArtifactToTmpFile(env, helmTypeTemplateArtifact); + } catch (SpinnakerHttpException e) { + throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); + } catch (IOException | SpinnakerException e) { + throw new IllegalStateException(fetchFailureMessage("template", e), e); + } } - protected Path getHelmTypePathFromArtifact(BakeManifestEnvironment env, List inputArtifacts , String filePath) throws IOException { - Path helmTypeFilePath; - - Artifact helmTypeTemplateArtifact = inputArtifacts.get(0); - String artifactType = Optional.ofNullable(helmTypeTemplateArtifact.getType()).orElse(""); - - if ("git/repo".equals(artifactType)) { - env.downloadArtifactTarballAndExtract(getArtifactDownloader(), helmTypeTemplateArtifact); - - helmTypeFilePath = - env.resolvePath(Optional.ofNullable(filePath).orElse("")); - } else { - try { - helmTypeFilePath = downloadArtifactToTmpFile(env, helmTypeTemplateArtifact); - } catch (SpinnakerHttpException e) { - throw new SpinnakerHttpException(fetchFailureMessage("template", e), e); - } catch (IOException | SpinnakerException e) { - throw new IllegalStateException(fetchFailureMessage("template", e), e); - } - } - - return helmTypeFilePath; - } + return helmTypeFilePath; + } } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java index c20326640..f0d74e943 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helm/HelmTemplateUtils.java @@ -40,8 +40,7 @@ public BakeRecipe buildBakeRecipe(BakeManifestEnvironment env, HelmBakeManifestR templatePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmChartFilePath()); log.info("path to Chart.yaml: {}", templatePath); - return buildCommand( - request, getValuePaths(inputArtifacts, env), templatePath); + return buildCommand(request, getValuePaths(inputArtifacts, env), templatePath); } public String fetchFailureMessage(String description, Exception e) { @@ -56,7 +55,7 @@ public String getHelmExecutableForRequest(HelmBakeManifestRequest request) { } public BakeRecipe buildCommand( - HelmBakeManifestRequest request, List valuePaths, Path templatePath) { + HelmBakeManifestRequest request, List valuePaths, Path templatePath) { BakeRecipe result = new BakeRecipe(); result.setName(request.getOutputName()); @@ -85,7 +84,7 @@ public BakeRecipe buildCommand( } if (request.isIncludeCRDs() - && request.getTemplateRenderer() == BakeManifestRequest.TemplateRenderer.HELM3) { + && request.getTemplateRenderer() == BakeManifestRequest.TemplateRenderer.HELM3) { command.add("--include-crds"); } From 54249e29748b62a77ea5f8ff6c607c9e4e15f0f8 Mon Sep 17 00:00:00 2001 From: Salvatore Mazzarino Date: Thu, 13 Jul 2023 10:18:49 +0200 Subject: [PATCH 12/12] run another round of spotless Signed-off-by: Salvatore Mazzarino --- .../helmfile/HelmfileBakeManifestRequest.java | 12 +++++------- .../manifests/helmfile/HelmfileTemplateUtils.java | 9 ++++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java index 097802c2d..2367059d2 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileBakeManifestRequest.java @@ -28,14 +28,12 @@ public class HelmfileBakeManifestRequest extends BakeManifestRequest { private String helmfileFilePath; /** - * The environment name used to customize the content of the helmfile manifest. - * The environment name defaults to default. + * The environment name used to customize the content of the helmfile manifest. The environment + * name defaults to default. */ private String environment; - /** - * The namespace to be released into. - */ + /** The namespace to be released into. */ private String namespace; /** @@ -45,8 +43,8 @@ public class HelmfileBakeManifestRequest extends BakeManifestRequest { List inputArtifacts; /** - * Include custom resource definition manifests in the templated output. - * Helmfile uses Helm v3 only which provides the option to include CRDs as part of the rendered output. + * Include custom resource definition manifests in the templated output. Helmfile uses Helm v3 + * only which provides the option to include CRDs as part of the rendered output. */ boolean includeCRDs; } diff --git a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java index c5e3f6e01..3abb66c95 100644 --- a/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java +++ b/rosco-manifests/src/main/java/com/netflix/spinnaker/rosco/manifests/helmfile/HelmfileTemplateUtils.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; - import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -57,11 +56,11 @@ public BakeRecipe buildBakeRecipe( } log.info("helmfileFilePath: '{}'", request.getHelmfileFilePath()); - helmfileFilePath = getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmfileFilePath()); + helmfileFilePath = + getHelmTypePathFromArtifact(env, inputArtifacts, request.getHelmfileFilePath()); log.info("path to helmfile: {}", helmfileFilePath); - return buildCommand( - request, getValuePaths(inputArtifacts, env), helmfileFilePath); + return buildCommand(request, getValuePaths(inputArtifacts, env), helmfileFilePath); } public String fetchFailureMessage(String description, Exception e) { @@ -73,7 +72,7 @@ public String getHelmExecutableForRequest(HelmfileBakeManifestRequest request) { } public BakeRecipe buildCommand( - HelmfileBakeManifestRequest request, List valuePaths, Path helmfileFilePath) { + HelmfileBakeManifestRequest request, List valuePaths, Path helmfileFilePath) { BakeRecipe result = new BakeRecipe(); result.setName(request.getOutputName());