Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: don't require an OpenShift Template:Parameter model type #2396

Merged
merged 1 commit into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class HelmConfig {
* the values.yaml file.
*/
private List<Template> parameterTemplates;
private List<Parameter> parameters;
private List<HelmParameter> parameters;
private List<HelmType> types;
private String sourceDir;
private String outputDir;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,49 @@
*/
package org.eclipse.jkube.kit.resource.helm;

import com.fasterxml.jackson.annotation.JsonCreator;
import io.fabric8.openshift.api.model.Parameter;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
public class HelmParameter {

@Getter
private final Parameter parameter;
private static final String GOLANG_EXPRESSION_REGEX = "\\{\\{.+}}";

@JsonCreator
public HelmParameter(Parameter parameter) {
this.parameter = parameter;
private boolean required;
private String name;
private String value;

boolean isGolangExpression() {
return value != null && value.trim().matches(GOLANG_EXPRESSION_REGEX);
}

public String getHelmName() {
return parameter.getName();
String toExpression() {
if (isGolangExpression()) {
return StringUtils.trimToEmpty(getValue());
}
final String defaultValue = StringUtils.trimToEmpty(getValue());
final String defaultExpression;
if (StringUtils.isNotBlank(defaultValue)) {
defaultExpression = " | default \"" + defaultValue + "\"";
} else {
defaultExpression = "";
}
final String requiredExpression;
if (isRequired()) {
requiredExpression = "required \"A valid .Values." + getName() + " entry required!\" ";
} else {
requiredExpression = "";
}
return "{{ " + requiredExpression + ".Values." + getName() + defaultExpression + " }}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jkube.kit.common.JKubeConfiguration;
import org.eclipse.jkube.kit.common.KitLogger;
Expand All @@ -43,10 +42,8 @@
import org.eclipse.jkube.kit.config.resource.ResourceServiceConfig;
import org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceFragments;

import com.google.common.collect.Streams;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import io.fabric8.openshift.api.model.Parameter;
import io.fabric8.openshift.api.model.Template;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.io.FileUtils;
Expand All @@ -71,7 +68,6 @@ public class HelmService {

private static final String CHART_FRAGMENT_REGEX = "^chart\\.helm\\.(?<ext>yaml|yml|json)$";
public static final Pattern CHART_FRAGMENT_PATTERN = Pattern.compile(CHART_FRAGMENT_REGEX, Pattern.CASE_INSENSITIVE);
private static final String GOLANG_EXPRESSION_REGEX = "\\{\\{.+}}";

private final JKubeConfiguration jKubeConfiguration;
private final ResourceServiceConfig resourceServiceConfig;
Expand Down Expand Up @@ -258,7 +254,7 @@ private static Chart chartFromHelmConfig(HelmConfig helmConfig) {
}

private static Chart createChartFromFragment(ResourceServiceConfig resourceServiceConfig, Properties properties) {
File helmChartFragment = resolveChartYamlFileFromFragmentsDir(resourceServiceConfig);
File helmChartFragment = resolveHelmFragment(CHART_FRAGMENT_PATTERN, resourceServiceConfig);
if (helmChartFragment != null && helmChartFragment.exists()) {
try {
String interpolatedFragmentContent = interpolate(helmChartFragment, properties, DEFAULT_FILTER);
Expand All @@ -270,12 +266,12 @@ private static Chart createChartFromFragment(ResourceServiceConfig resourceServi
return null;
}

private static File resolveChartYamlFileFromFragmentsDir(ResourceServiceConfig resourceServiceConfig) {
private static File resolveHelmFragment(Pattern filePattern, ResourceServiceConfig resourceServiceConfig) {
final List<File> fragmentDirs = resourceServiceConfig.getResourceDirs();
if (fragmentDirs != null) {
for (File fragmentDir : fragmentDirs) {
if (fragmentDir.exists() && fragmentDir.isDirectory()) {
final File[] fragments = fragmentDir.listFiles((dir, name) -> CHART_FRAGMENT_PATTERN.matcher(name).matches());
final File[] fragments = fragmentDir.listFiles((dir, name) -> filePattern.matcher(name).matches());
if (fragments != null && fragments.length > 0) {
return fragments[0];
}
Expand All @@ -292,33 +288,18 @@ private static void copyAdditionalFiles(HelmConfig helmConfig, File outputDir) t
}

private static String interpolateTemplateWithHelmParameter(String template, HelmParameter parameter) {
String name = parameter.getParameter().getName();
final String name = parameter.getName();
final String from = "$" + name;
final String braceEnclosedFrom = "${" + name + "}";
final String quotedBraceEnclosedFrom = "\"" + braceEnclosedFrom + "\"";
String answer = template;
final String to = expression(parameter);
final String to = parameter.toExpression();
answer = answer.replace(quotedBraceEnclosedFrom, to);
answer = answer.replace(braceEnclosedFrom, to);
answer = answer.replace(from, to);
return answer;
}

private static String expression(HelmParameter parameter) {
final String value = Optional.ofNullable(parameter.getParameter().getValue()).map(StringUtils::trimToEmpty).orElse("");
if (value.matches(GOLANG_EXPRESSION_REGEX)) {
return value;
}
String defaultExpression = "";
String required = "";
if (StringUtils.isNotBlank(value)) {
defaultExpression = " | default \"" + value + "\"";
}
if (Boolean.TRUE.equals(parameter.getParameter().getRequired())) {
required = "required \"A valid .Values." + parameter.getHelmName() + " entry required!\" ";
}
return "{{ " + required + ".Values." + parameter.getHelmName() + defaultExpression + " }}";
}

private static void interpolateTemplateParameterExpressionsWithHelmExpressions(File file, List<HelmParameter> helmParameters) throws IOException {
final String originalTemplate = FileUtils.readFileToString(file, Charset.defaultCharset());
Expand All @@ -340,26 +321,30 @@ private static void interpolateChartTemplates(List<HelmParameter> helmParameters
}

private static void createValuesYaml(List<HelmParameter> helmParameters, File outputDir) throws IOException {
final Map<String, String> values = helmParameters.stream()
.filter(hp -> hp.getParameter().getValue() != null)
final Map<String, Object> values = helmParameters.stream()
.filter(hp -> hp.getValue() != null)
// Placeholders replaced by Go expressions don't need to be persisted in the values.yaml file
.filter(hp -> !hp.getParameter().getValue().trim().matches(GOLANG_EXPRESSION_REGEX))
.collect(Collectors.toMap(HelmParameter::getHelmName, hp -> hp.getParameter().getValue()));
.filter(hp -> !hp.isGolangExpression())
.collect(Collectors.toMap(HelmParameter::getName, HelmParameter::getValue));

final File outputValuesFile = new File(outputDir, VALUES_FILENAME);
ResourceUtil.save(outputValuesFile, getNestedMap(values), ResourceFileType.yaml);
}

private static List<HelmParameter> collectParameters(HelmConfig helmConfig) {
final List<HelmParameter> parameters = new ArrayList<>();
final Stream<Parameter> fromYaml = Optional.ofNullable(helmConfig.getParameterTemplates())
.orElse(Collections.emptyList()).stream()
.map(Template::getParameters).flatMap(List::stream);
final Stream<Parameter> fromConfig = Optional.ofNullable(helmConfig.getParameters())
.orElse(Collections.emptyList()).stream();
Streams.concat(fromYaml, fromConfig).map(HelmParameter::new).forEach(parameters::add);
parameters.stream().filter(p -> p.getParameter().getName() == null).findAny().ifPresent(p -> {
throw new IllegalArgumentException("Helm parameters must be declared with a valid name: " + p.getParameter().toString());
if (helmConfig.getParameterTemplates() != null) {
helmConfig.getParameterTemplates().stream()
.map(Template::getParameters).flatMap(List::stream)
.map(p -> HelmParameter.builder()
.name(p.getName()).required(Boolean.TRUE.equals(p.getRequired())).value(p.getValue()).build())
.forEach(parameters::add);
}
if (helmConfig.getParameters() != null && !helmConfig.getParameters().isEmpty()) {
parameters.addAll(helmConfig.getParameters());
}
parameters.stream().filter(p -> p.getName() == null).findAny().ifPresent(p -> {
throw new IllegalArgumentException("Helm parameters must be declared with a valid name: " + p);
});
return parameters;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.List;
import java.util.stream.Stream;

import io.fabric8.openshift.api.model.ParameterBuilder;
import org.eclipse.jkube.kit.common.Maintainer;
import org.eclipse.jkube.kit.resource.helm.HelmConfig.HelmType;

Expand Down Expand Up @@ -128,7 +127,7 @@ void deserialize() throws Exception {
.hasFieldOrPropertyWithValue("stableRepository", new HelmRepository())
.hasFieldOrPropertyWithValue("tarballOutputDir", "./tar-output")
.hasFieldOrPropertyWithValue("parameterTemplates", Collections.singletonList(new Template()))
.hasFieldOrPropertyWithValue("parameters", Collections.singletonList(new ParameterBuilder().withName("key").build()))
.hasFieldOrPropertyWithValue("parameters", Collections.singletonList(HelmParameter.builder().name("key").build()))
.hasFieldOrPropertyWithValue("description", "The description")
.hasFieldOrPropertyWithValue("home", "e.t.")
.hasFieldOrPropertyWithValue("icon", "Warhol")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.assertj.ArchiveAssertions;

import io.fabric8.openshift.api.model.ParameterBuilder;
import io.fabric8.openshift.api.model.Template;
import org.apache.commons.io.FileUtils;
import org.eclipse.jkube.kit.common.util.Serialization;
Expand Down Expand Up @@ -77,8 +76,8 @@ void generateHelmChartsTest() throws Exception {
Serialization.unmarshal(HelmServiceIT.class.getResource("/it/sources/global-template.yml"), Template.class)
));
helmConfig.setParameters(Arrays.asList(
new ParameterBuilder().withName("annotation_from_config").withValue("{{ .Chart.Name | upper }}").build(),
new ParameterBuilder().withName("annotation.from.config.dotted").withValue("{{ .Chart.Name }}").build()));
HelmParameter.builder().name("annotation_from_config").value("{{ .Chart.Name | upper }}").build(),
HelmParameter.builder().name("annotation.from.config.dotted").value("{{ .Chart.Name }}").build()));
final AtomicInteger generatedChartCount = new AtomicInteger(0);
helmConfig.setGeneratedChartListeners(Collections.singletonList(
(helmConfig1, type, chartFile) -> generatedChartCount.incrementAndGet()));
Expand Down Expand Up @@ -117,8 +116,8 @@ void generateHelmChartsTest() throws Exception {
void generateHelmChartsTest_withInvalidParameters_throwsException() {
// Given
helmConfig.setTypes(Collections.singletonList(HelmConfig.HelmType.KUBERNETES));
helmConfig.setParameters(Collections.singletonList(new ParameterBuilder()
.withValue("{{ .Chart.Name | upper }}").build()));
helmConfig.setParameters(Collections.singletonList(HelmParameter.builder()
.value("{{ .Chart.Name | upper }}").build()));
// When
final IllegalArgumentException result = assertThrows(IllegalArgumentException.class, () ->
helmService.generateHelmCharts(helmConfig));
Expand All @@ -130,7 +129,7 @@ void generateHelmChartsTest_withInvalidParameters_throwsException() {
void generateHelmChartsTest_preserveParameterCase() throws Exception {
// Given
helmConfig.setTypes(Collections.singletonList(HelmConfig.HelmType.KUBERNETES));
helmConfig.setParameters(Collections.singletonList(new ParameterBuilder().withName("testCamelCase").withValue("testValue").build()));
helmConfig.setParameters(Collections.singletonList(HelmParameter.builder().name("testCamelCase").value("testValue").build()));
// When
helmService.generateHelmCharts(helmConfig);
// Then
Expand Down