Skip to content

Commit

Permalink
refactor (jkube-kit/resource/helm) : Add HelmUploaderManager to manag…
Browse files Browse the repository at this point in the history
…e different Helm repository uploaders

HelmUploaderManager would use PluginServiceFactory to detect applicable
Helm repository uploaders

Signed-off-by: Rohan Kumar <rohaan@redhat.com>
  • Loading branch information
rohanKanojia authored and manusa committed Jul 13, 2023
1 parent adb4dd8 commit c354872
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
*/
package org.eclipse.jkube.kit.common.util;

import java.time.Duration;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
Expand Down Expand Up @@ -56,4 +60,17 @@ public static <T> Function<Predicate<T>, CompletableFuture<T>> await(Supplier<T>
return ret;
});
}

public static <T> T get(CompletableFuture<T> completableFuture, Duration duration) {
try {
return completableFuture.get(duration.toMillis(), TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
} catch (TimeoutException e) {
throw new IllegalStateException("Failure while waiting to get future ", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.common.util;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

class AsyncUtilTest {
@Test
void get_whenFuturePresent_thenReturnValue() {
// Given
CompletableFuture<String> completableFuture = CompletableFuture.completedFuture("foo");

// When
String result = AsyncUtil.get(completableFuture, Duration.ofMinutes(1));

// Then
assertThat(result).isEqualTo("foo");
}

@Test
void get_whenFutureCompletedExceptionally_then() {
// Given
CompletableFuture<String> completableFuture = new CompletableFuture<>();
completableFuture.completeExceptionally(new IOException("io exception"));

// When
// Then
assertThatIllegalStateException()
.isThrownBy(() -> AsyncUtil.get(completableFuture, Duration.ofMinutes(1)))
.withMessageContaining("io exception");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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 org.eclipse.jkube.kit.common.KitLogger;

import java.io.File;

public class ArtifactoryHelmRepositoryUploader extends StandardRepositoryUploader {

public ArtifactoryHelmRepositoryUploader(KitLogger logger) {
super("PUT", logger, HelmRepository.HelmRepoType.ARTIFACTORY);
}

@Override
public String url(File helmChart, HelmRepository repository) {
return formatRepositoryURL(helmChart, repository);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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 org.eclipse.jkube.kit.common.KitLogger;

import java.io.File;

public class ChartMuseumHelmRepositoryUploader extends StandardRepositoryUploader {

public ChartMuseumHelmRepositoryUploader(KitLogger logger) {
super("POST", logger, HelmRepository.HelmRepoType.CHARTMUSEUM);
}

@Override
public String url(File helmChart, HelmRepository repository) {
return repository.getUrl();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private void uploadHelmChart(HelmConfig helmConfig, HelmRepository helmRepositor
throws IOException, BadUploadException {

for (HelmConfig.HelmType helmType : helmConfig.getTypes()) {
final HelmUploader helmUploader = new HelmUploader(logger);
final HelmUploaderManager helmUploaderManager = new HelmUploaderManager(logger);
logger.info("Uploading Helm Chart \"%s\" to %s", helmConfig.getChart(), helmRepository.getName());
logger.debug("OutputDir: %s", helmConfig.getOutputDir());

Expand All @@ -170,7 +170,7 @@ private void uploadHelmChart(HelmConfig helmConfig, HelmRepository helmRepositor
final File tarballFile = new File(tarballOutputDir, String.format("%s-%s%s.%s",
helmConfig.getChart(), helmConfig.getVersion(), resolveHelmClassifier(helmConfig), helmConfig.getChartExtension()));

helmUploader.uploadSingle(tarballFile, helmRepository);
helmUploaderManager.getHelmUploader(helmRepository.getType()).uploadSingle(tarballFile, helmRepository);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,60 +14,9 @@
package org.eclipse.jkube.kit.resource.helm;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.charset.Charset;

import org.eclipse.jkube.kit.common.KitLogger;

import org.apache.commons.io.IOUtils;

public class HelmUploader {

private final KitLogger logger;

public HelmUploader(KitLogger logger) {
this.logger = logger;
}

void uploadSingle(File file, HelmRepository repository)
throws IOException, BadUploadException {
HttpURLConnection connection;

if (repository.getType() == null) {
throw new IllegalArgumentException(
"Repository type missing. Check your plugin configuration.");
}

connection = repository.getType().createConnection(file, repository);

writeFileOnConnection(file, connection);

if (connection.getResponseCode() >= HttpURLConnection.HTTP_MULT_CHOICE) {
String response;
if (connection.getErrorStream() != null) {
response = IOUtils.toString(connection.getErrorStream(), Charset.defaultCharset());
} else if (connection.getInputStream() != null) {
response = IOUtils.toString(connection.getInputStream(), Charset.defaultCharset());
} else {
response = "No details provided";
}
throw new BadUploadException(response);
} else {
String message = Integer.toString(connection.getResponseCode());
if (connection.getInputStream() != null) {
message += " - " + IOUtils.toString(connection.getInputStream(), Charset.defaultCharset());
}
logger.info(message);
}
connection.disconnect();
}

private void writeFileOnConnection(File file, HttpURLConnection connection) throws IOException {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
IOUtils.copy(fileInputStream, connection.getOutputStream());
}
}

}
public interface HelmUploader {
HelmRepository.HelmRepoType getType();
void uploadSingle(File file, HelmRepository repository) throws IOException, BadUploadException ;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* 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 org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.util.PluginServiceFactory;

import java.util.List;

public class HelmUploaderManager {
private static final String[] SERVICE_PATHS = new String[] {
"META-INF/jkube/helm-uploaders"
};

private final List<HelmUploader> helmUploaderList;

public HelmUploaderManager(KitLogger log) {
this.helmUploaderList = new PluginServiceFactory<>(log).createServiceObjects(SERVICE_PATHS);
}

public HelmUploader getHelmUploader(HelmRepository.HelmRepoType type) {
for (HelmUploader helmUploader : helmUploaderList) {
if (helmUploader.getType().equals(type)) {
return helmUploader;
}
}
throw new IllegalStateException("Could not find Helm Uploader for type " + type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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 org.eclipse.jkube.kit.common.KitLogger;

import java.io.File;

public class NexusHelmRepositoryUploader extends StandardRepositoryUploader {
public NexusHelmRepositoryUploader(KitLogger logger) {
super("PUT", logger, HelmRepository.HelmRepoType.NEXUS);
}

@Override
public String url(File helmChart, HelmRepository repository) {
String url = formatRepositoryURL(helmChart, repository);
if (url.endsWith(".tar.gz")) {
url = url.replaceAll("tar.gz$", "tgz");
}
return url;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* 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.client.RequestConfigBuilder;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.http.HttpRequest;
import io.fabric8.kubernetes.client.http.HttpResponse;
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.util.Base64Util;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.Duration;

import static org.eclipse.jkube.kit.common.util.AsyncUtil.get;

public abstract class StandardRepositoryUploader implements HelmUploader {
private final String method;
private final KitLogger logger;
private final HelmRepository.HelmRepoType type;
private static final long HELM_UPLOAD_TIMEOUT_MINUTES = 30;

protected StandardRepositoryUploader(String method, KitLogger logger, HelmRepository.HelmRepoType type) {
this.method = method;
this.logger = logger;
this.type = type;
}

public abstract String url(File helmChart, HelmRepository repository);

@Override
public HelmRepository.HelmRepoType getType() {
return type;
}

@Override
public void uploadSingle(File file, HelmRepository repository) throws IOException, BadUploadException {
String uploadUrl = url(file, repository);

try (HttpClient httpClient = HttpClientUtils.getHttpClientFactory().newBuilder().tag(new RequestConfigBuilder().withRequestRetryBackoffLimit(0).build()).build()) {
HttpRequest.Builder httpRequestBuilder = httpClient.newHttpRequestBuilder();
httpRequestBuilder.uri(uploadUrl);
// At this point username and password are always populated since this is requirement in HelmService
httpRequestBuilder.header("Authorization", String.format("Basic %s", Base64Util.encodeToString(repository.getUsername() + ":" + repository.getPassword())));
httpRequestBuilder.method(method, "application/gzip", Files.newInputStream(file.toPath()), file.length());
HttpResponse<byte[]> response = get(httpClient.sendAsync(httpRequestBuilder.build(), byte[].class), Duration.ofMinutes(HELM_UPLOAD_TIMEOUT_MINUTES));
handleHttpResponse(response);
}
}

private void handleHttpResponse(HttpResponse<byte[]> response) throws BadUploadException {
if (!response.isSuccessful()) {
String responseStr;
if (response.body() != null) {
responseStr = new String(response.body());
} else if (StringUtils.isNotBlank(response.message())) {
responseStr = response.message();
} else {
responseStr = "No details provided";
}
throw new BadUploadException(responseStr);
} else {
String message = Integer.toString(response.code());
if (response.body() != null) {
message += " - " + new String(response.body());
}
logger.info(message);
}
}

protected String formatRepositoryURL(File file, HelmRepository repository) {
return String.format("%s%s", StringUtils.appendIfMissing(repository.getUrl(), "/"), file.getName());
}
}
Loading

0 comments on commit c354872

Please sign in to comment.