Skip to content

Commit

Permalink
Merge branch 'eclipse:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
sankritimishra authored Jan 13, 2024
2 parents f90f423 + 4e36ff7 commit 0fa2292
Show file tree
Hide file tree
Showing 12 changed files with 853 additions and 209 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Usage:
* Fix #2257: Provide guidance when the final project packaged file is not found in Quarkus projeicts
* Fix #1690: Base images based on ubi9
* Fix #2070: build goals/tasks log warning if user forgets to run package/build goal/task
* Fix #2314: Add chart name validation before doing Helm OCI push
* Fix #2381: Container Images based on Java 21 (Java-exec, Tomcat, Jetty, Karaf)
* Fix #2389: Helm `values.yaml` sorted alphabetically
* Fix #2390: support for all missing Chart.yaml fields
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ private static class ExecutorServiceHolder {
public static final ExecutorService INSTANCE = Executors.newCachedThreadPool();
}

public static <T> CompletableFuture<T> async(Callable<T> callable) {
public static <T> CompletableFuture<T> async(ThrowingFunction<CompletableFuture<T>, T> function) {
final CompletableFuture<T> future = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try {
future.complete(callable.call());
future.complete(function.apply(future));
} catch (Exception ex) {
future.completeExceptionally(ex);
}
Expand All @@ -51,6 +51,10 @@ public static <T> CompletableFuture<T> async(Callable<T> callable) {
return future;
}

public static <T> CompletableFuture<T> async(Callable<T> callable) {
return async(f -> callable.call());
}

public static <T> Function<Predicate<T>, CompletableFuture<T>> await(Supplier<T> supplier) {
return predicate -> async(() -> {
T ret;
Expand All @@ -73,4 +77,20 @@ public static <T> T get(CompletableFuture<T> completableFuture, Duration duratio
throw new IllegalStateException("Failure while waiting to get future ", e);
}
}

public static <T> T get(CompletableFuture<T> completableFuture) {
try {
return completableFuture.get();
} catch (ExecutionException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
}

@FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T t) throws Exception;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,16 @@
package org.eclipse.jkube.kit.common.util;


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
Expand All @@ -35,7 +32,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

Expand All @@ -45,6 +43,8 @@
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReview;
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReviewBuilder;
import io.fabric8.kubernetes.client.utils.ApiVersionUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.eclipse.jkube.kit.common.KitLogger;

import io.fabric8.kubernetes.api.model.Container;
Expand Down Expand Up @@ -89,9 +89,11 @@
import io.fabric8.openshift.api.model.DeploymentConfigSpec;
import org.apache.commons.lang3.StringUtils;

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


public class KubernetesHelper {
protected static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX";
protected static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.n]X");
private static final String FILENAME_PATTERN_REGEX = "^(?<name>.*?)(-(?<type>[^-]+))?\\.(?<ext>yaml|yml|json)$";
private static final String PROFILES_PATTERN_REGEX = "^profiles?\\.ya?ml$";
public static final Pattern FILENAME_PATTERN = Pattern.compile(FILENAME_PATTERN_REGEX, Pattern.CASE_INSENSITIVE);
Expand Down Expand Up @@ -383,32 +385,23 @@ public static String getBuildStatusPhase(Build build) {
return null;
}

public static void printLogsAsync(LogWatch logWatcher, final String failureMessage, final CountDownLatch terminateLatch, final KitLogger log) {
final InputStream in = logWatcher.getOutput();
Thread thread = new Thread() {
@Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
while (true) {
String line = reader.readLine();
if (line == null) {
return;
}
if (terminateLatch.getCount() <= 0L) {
return;
}
log.info("[[s]]%s", line);
}
} catch (IOException e) {
// Check again the latch which could be already count down to zero in between
// so that an IO exception occurs on read
if (terminateLatch.getCount() > 0L) {
log.error("%s : %s", failureMessage, e);
}
}
}
};
thread.start();
public static CompletableFuture<Void> printLogsAsync(LogWatch logWatcher, Consumer<String> lineConsumer) {
final LineIterator it = IOUtils.lineIterator(logWatcher.getOutput(), StandardCharsets.UTF_8);
return async(cf -> {
while (it.hasNext()) {
final String line = it.nextLine();
if (line == null) {
cf.complete(null);
} else {
lineConsumer.accept(line);
}
// Can be completed internally or externally
if (cf.isDone()) {
return null;
}
}
return null;
});
}

public static String getBuildStatusReason(Build build) {
Expand Down Expand Up @@ -550,32 +543,28 @@ private static LabelSelector toLabelSelector(Map<String, String> matchLabels) {
}

public static boolean isNewerResource(HasMetadata newer, HasMetadata older) {
Date t1 = getCreationTimestamp(newer);
Date t2 = getCreationTimestamp(older);
Instant t1 = getCreationTimestamp(newer);
Instant t2 = getCreationTimestamp(older);
return t1 != null && (t2 == null || t1.compareTo(t2) > 0);
}

public static Date getCreationTimestamp(HasMetadata hasMetadata) {
public static Instant getCreationTimestamp(HasMetadata hasMetadata) {
ObjectMeta metadata = hasMetadata.getMetadata();
if (metadata != null) {
return parseTimestamp(metadata.getCreationTimestamp());
}
return null;
}

private static Date parseTimestamp(String text) {
private static Instant parseTimestamp(String text) {
if (StringUtils.isBlank(text)) {
return null;
}
return parseDate(text);
}

public static Date parseDate(String text) {
try {
return new SimpleDateFormat(DATE_TIME_FORMAT).parse(text);
} catch (ParseException e) {
return null;
}
public static Instant parseDate(String text) {
return Instant.from(DATE_TIME_FORMATTER.parse(text));
}

public static Pod getNewestPod(Collection<Pod> pods) {
Expand All @@ -584,8 +573,8 @@ public static Pod getNewestPod(Collection<Pod> pods) {
}
List<Pod> sortedPods = new ArrayList<>(pods);
sortedPods.sort((p1, p2) -> {
Date t1 = getCreationTimestamp(p1);
Date t2 = getCreationTimestamp(p2);
Instant t1 = getCreationTimestamp(p1);
Instant t2 = getCreationTimestamp(p2);
if (t1 != null) {
if (t2 == null) {
return 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReview;
Expand Down Expand Up @@ -482,6 +486,24 @@ static Stream<Arguments> getKindTestCases() {
);
}

@ParameterizedTest(name = "{index}: {0} returns {1}")
@MethodSource("getCreationTimestampTestCases")
void getCreationTimestamp(String timestamp, LocalDateTime expectedDate) {
final ConfigMap cm = new ConfigMapBuilder().withNewMetadata().withCreationTimestamp(timestamp).endMetadata()
.build();
assertThat(KubernetesHelper.getCreationTimestamp(cm))
.isEqualTo(expectedDate.atZone(ZoneOffset.UTC).toInstant());
}

static Stream<Arguments> getCreationTimestampTestCases() {
return Stream.of(
Arguments.of("1955-11-12T06:38:00Z", LocalDateTime.of(1955, 11, 12, 6, 38)),
Arguments.of("1955-11-12T06:38:00+01", LocalDateTime.of(1955, 11, 12, 5, 38)),
Arguments.of("1955-11-12T06:38:00.123456789Z", LocalDateTime.of(1955, 11, 12, 6, 38, 0, 123456789)),
Arguments.of("1955-11-12T06:38:00.625Z", LocalDateTime.of(1955, 11, 12, 6, 38, 0, 625))
);
}

private void assertLocalFragments(File[] fragments, int expectedSize) {
assertThat(fragments).hasSize(expectedSize);
assertThat(Arrays.stream(fragments).anyMatch( f -> f.getName().equals("deployment.yml"))).isTrue();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.config.image;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

/**
* This test has been added to ensure ImageName's upstream compatibility with Docker Distribution Reference.
* Tests ported from <a href="https://github.com/distribution/reference/blob/8507c7fcf0da9f570540c958ea7b972c30eeaeca/reference_test.go">Distribution Reference</a>
*/
class ImageNameDistributionReferenceTest {

@ParameterizedTest
@ValueSource(strings = {
"test.com/foo",
"test:8080/foo",
"docker.io/library/foo",
"test_com",
"test.com:tag",
"test.com:5000",
"test.com/repo:tag",
"test:5000/repo",
"test:5000/repo:tag",
"lowercase:Uppercase",
"test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"sub-dom1.foo.com/bar/baz/quux",
"sub-dom1.foo.com/bar/baz/quux:some-long-tag",
"b.gcr.io/test.example.com/my-app:test.example.com",
"xn--n3h.com/myimage:xn--n3h.com",
//"xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2540
"foo_bar.com:8080",
"foo/foo_bar.com:8080",
"192.168.1.1",
"192.168.1.1:tag",
"192.168.1.1:5000",
"192.168.1.1/repo",
"192.168.1.1:5000/repo",
"192.168.1.1:5000/repo:5050",
"a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a:tag-puts-this-over-max",
"docker/docker",
"library/debian",
"debian",
"localhost/library/debian",
"localhost/debian",
"docker.io/docker/docker",
"docker.io/library/debian",
"docker.io/debian",
"index.docker.io/docker/docker",
"index.docker.io/library/debian",
"index.docker.io/debian",
"127.0.0.1:5000/docker/docker",
"127.0.0.1:5000/library/debian",
"127.0.0.1:5000/debian",
"192.168.0.1",
"192.168.0.1:80",
"192.168.0.1:8/debian",
"192.168.0.2:25000/debian",
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
//"[2001:db8::1]/repo", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8:1:2:3:4:5:6]/repo:tag", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8::1]:5000/repo:tag", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2541
//"[2001:db8::]:5000/repo", // https://github.com/eclipse/jkube/issues/2541
//"[::1]:5000/repo", // https://github.com/eclipse/jkube/issues/2541
})
void validNames(String name) {
// Given
ImageName imageName = new ImageName(name);

// When + Then
assertThat(imageName).isNotNull();
}

@ParameterizedTest
@ValueSource(strings = {
"",
":justtag",
"@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
//"a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a:tag", // https://github.com/eclipse/jkube/issues/2542
//"repo@sha256:ffffffffffffffffffffffffffffffffff", // https://github.com/eclipse/jkube/issues/2543
"validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"Uppercase:tag",
"test:5000/Uppercase/lowercase:tag",
"aa/asdf$$^/aa",
//"[fe80::1%eth0]:5000/repo", // https://github.com/eclipse/jkube/issues/2541
//"[fe80::1%@invalidzone]:5000/repo", // https://github.com/eclipse/jkube/issues/2541
})
void invalidNames(String name) {
assertThatIllegalArgumentException().isThrownBy(() -> new ImageName(name));
}
}
Loading

0 comments on commit 0fa2292

Please sign in to comment.