Skip to content

Commit

Permalink
feat(helm): HelmService exposes Helm uninstall functionality (3304)
Browse files Browse the repository at this point in the history
Signed-off-by: Rohan Kumar <[email protected]>
  • Loading branch information
rohanKanojia authored Aug 8, 2024
1 parent 4ff6ff6 commit 1d2ca4a
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@
import com.marcnuri.helm.LintCommand;
import com.marcnuri.helm.LintResult;
import com.marcnuri.helm.Release;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import com.marcnuri.helm.UninstallCommand;
import org.eclipse.jkube.kit.common.JKubeConfiguration;
import org.eclipse.jkube.kit.common.JKubeException;
import org.eclipse.jkube.kit.common.KitLogger;
Expand Down Expand Up @@ -87,6 +86,7 @@ public class HelmService {

private static final String VALUES_FRAGMENT_REGEX = "^values\\.helm\\.(?<ext>yaml|yml|json)$";
public static final Pattern VALUES_FRAGMENT_PATTERN = Pattern.compile(VALUES_FRAGMENT_REGEX, Pattern.CASE_INSENSITIVE);
private static final String SYSTEM_LINE_SEPARATOR_REGEX = "\r?\n";

private final JKubeConfiguration jKubeConfiguration;
private final ResourceServiceConfig resourceServiceConfig;
Expand Down Expand Up @@ -190,7 +190,7 @@ public void dependencyUpdate(HelmConfig helmConfig) {
dependencyUpdateCommand.skipRefresh();
}
Arrays.stream(dependencyUpdateCommand.call()
.split("\r?\n"))
.split(SYSTEM_LINE_SEPARATOR_REGEX))
.forEach(l -> logger.info("[[W]]%s", l));
}
}
Expand Down Expand Up @@ -222,12 +222,22 @@ public void install(HelmConfig helmConfig) {
Arrays.stream(release.getOutput().split("---"))
.filter(o -> o.contains("Deleting outdated charts"))
.findFirst()
.ifPresent(s -> Arrays.stream(s.split("\r?\n"))
.ifPresent(s -> Arrays.stream(s.split(SYSTEM_LINE_SEPARATOR_REGEX))
.filter(StringUtils::isNotBlank)
.forEach(l -> logger.info("[[W]]%s", l)));
}
}

public void uninstall(HelmConfig helmConfig) {
logger.info("Uninstalling Helm Chart %s %s", helmConfig.getChart(), helmConfig.getVersion());
UninstallCommand uninstallCommand = Helm.uninstall(helmConfig.getReleaseName())
.withKubeConfig(createTemporaryKubeConfigForInstall());

Arrays.stream(uninstallCommand.call().split(SYSTEM_LINE_SEPARATOR_REGEX))
.filter(StringUtils::isNotBlank)
.forEach(l -> logger.info("[[W]]%s", l));
}

private Path createTemporaryKubeConfigForInstall() {
try {
File kubeConfigParentDir = new File(jKubeConfiguration.getProject().getBuildDirectory(), "jkube-temp");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.resource.helm;

import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretListBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
import io.fabric8.openshift.api.model.Template;
import org.eclipse.jkube.kit.common.JKubeConfiguration;
import org.eclipse.jkube.kit.common.JavaProject;
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.access.ClusterConfiguration;
import org.eclipse.jkube.kit.common.util.Serialization;
import org.eclipse.jkube.kit.config.resource.ResourceServiceConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;

import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.eclipse.jkube.kit.common.util.KubernetesMockServerUtil.prepareMockWebServerExpectationsForAggregatedDiscoveryEndpoints;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@DisplayName("HelmService.uninstall")
@EnableKubernetesMockClient(crud = true)
class HelmServiceUninstallIT {
@TempDir
private Path tempDir;
private HelmConfig helmConfig;
private HelmService helmService;
private KitLogger kitLogger;
private KubernetesClient kubernetesClient;
private KubernetesMockServer server;

@BeforeEach
void setUp() throws URISyntaxException, IOException {
kitLogger = spy(new KitLogger.SilentLogger());
Template helmParameterTemplates = Serialization.unmarshal(HelmServiceUninstallIT.class.getResource("/it/sources/global-template.yml"), Template.class);
Path outputDir = tempDir.resolve("output");
helmConfig = HelmConfig.builder()
.chart("helm-test")
.version("0.1.0")
.chartExtension("tgz")
.types(Collections.singletonList(HelmConfig.HelmType.KUBERNETES))
.tarballOutputDir(outputDir.toFile().getAbsolutePath())
.outputDir(outputDir.toString())
.parameterTemplates(Collections.singletonList(helmParameterTemplates))
.sourceDir(new File(Objects.requireNonNull(HelmServiceUninstallIT.class.getResource("/it/sources")).toURI()).getAbsolutePath())
.releaseName("test-project")
.disableOpenAPIValidation(true)
.parameters(Arrays.asList(
HelmParameter.builder().name("annotation_from_config").value("{{ .Chart.Name | upper }}").build(),
HelmParameter.builder().name("annotation.from.config.dotted").value("{{ .Chart.Name }}").build(),
HelmParameter.builder().name("deployment.replicas").value(1).build()))
.build();
// Remove after https://github.com/fabric8io/kubernetes-client/issues/6062 is fixed
prepareMockWebServerExpectationsForAggregatedDiscoveryEndpoints(server);
helmService = new HelmService(JKubeConfiguration.builder()
.project(JavaProject.builder()
.buildDirectory(tempDir.resolve("target").toFile())
.build())
.clusterConfiguration(ClusterConfiguration.from(kubernetesClient.getConfiguration()).build())
.build(), new ResourceServiceConfig(), kitLogger);
}

@Test
@DisplayName("uninstall invoked, then log uninstallation details after uninstall")
void uninstall_thenLogUninstalledChartDetails() throws IOException {
// Given
helmService.generateHelmCharts(helmConfig);
helmService.install(helmConfig);
Secret secret = kubernetesClient.secrets().withName("sh.helm.release.v1.test-project.v1").get();
server.expect().get().withPath("/api/v1/namespaces/test/secrets?labelSelector=name%3Dtest-project%2Cowner%3Dhelm")
.andReturn(200, new SecretListBuilder()
.addToItems(secret)
.build())
.once();
// When
helmService.uninstall(helmConfig);
// Then
verify(kitLogger, times(1)).info("[[W]]%s", "release \"test-project\" uninstalled");
}

@Test
@DisplayName("when chart not present, then uninstall fails")
void chartAbsent_thenLogChartUninstallFailure() {
assertThatIllegalStateException()
.isThrownBy(() -> helmService.uninstall(helmConfig))
.withMessageContaining(" not found");
}
}

0 comments on commit 1d2ca4a

Please sign in to comment.