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

Implement support for custom Api Versions in informers (#639) #713

Merged
merged 2 commits into from
Jul 19, 2024
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 @@ -20,11 +20,14 @@
import io.kubernetes.client.util.Strings;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
* This class is inspired by the implementation of the <a href="https://github.com/kubernetes-client/java/blob/release-13/util/src/main/java/io/kubernetes/client/util/ModelMapper.java">io.kubernetes.client.util.ModelMapper.java</a>.
Expand All @@ -38,12 +41,19 @@
*/
public class ModelMapper {

private static final Logger LOG = LoggerFactory.getLogger(ModelMapper.class);

// Model's api-group prefix to kubernetes api-group
private final Map<String, String> preBuiltApiGroups = new HashMap<>();

// Model's api-version midfix to kubernetes api-version
private final List<String> preBuiltApiVersions = new ArrayList<>();

// This allows parsing custom (not included in kubernetes core) api versions
// It is based on the kubernetes core one available at https://github.com/kubernetes/apimachinery/blob/master/pkg/util/version/version.go
// and is completed to be able to proceed to extraction from a java class name
private final Pattern customVersionParser = Pattern.compile("^\\s*(V(?:[0-9]+(?:\\.[0-9]+)*)(?:[a-z0-9]*)*)[A-Z]+[a-zA-Z0-9]*$");

public ModelMapper() {
initApiGroupMap();
initApiVersionList();
Expand Down Expand Up @@ -85,17 +95,37 @@ private void initApiVersionList() {
private Pair<String, String> getApiGroup(String name) {
return preBuiltApiGroups.entrySet().stream()
.filter(e -> name.startsWith(e.getKey()))
.map(e -> new MutablePair<String, String>(e.getValue(), name.substring(e.getKey().length())))
.map(e -> new MutablePair<>(e.getValue(), name.substring(e.getKey().length())))
.findFirst()
.orElse(new MutablePair<String, String>(null, name));
.orElse(new MutablePair<>(null, name));
}

private Pair<String, String> getApiVersion(String name) {
return preBuiltApiVersions.stream()
.filter(name::startsWith)
.map(v -> new MutablePair<String, String>(v.toLowerCase(), name.substring(v.length())))
.map(v -> new MutablePair<>(v, extractKind(v, name)))
.findFirst()
.orElse(new MutablePair<String, String>(null, name));
.orElseGet(() -> {
String version = tryGuessCustomApiVersion(name);
return new MutablePair<>(version, extractKind(version, name));
});
}

private String extractKind(String version, String name){
return version == null ? name : name.substring(version.length());
}

private String tryGuessCustomApiVersion(String name) {
var patternMatcher = customVersionParser.matcher(name);

if (patternMatcher.matches() && patternMatcher.groupCount() == 1) {
return patternMatcher.group(1);
}

// Warn the user to avoid wasted debug time (cfr https://github.com/micronaut-projects/micronaut-kubernetes/issues/639)
LOG.warn("Could not extract ApiVersion from entity {}", name);

return null;
}

/**
Expand All @@ -109,8 +139,9 @@ public GroupVersionKind getGroupVersionKindByClass(Class<? extends KubernetesObj
Pair<String, String> versionAndOther = getApiVersion(groupAndOther.getRight());

String group = Strings.nullToEmpty(groupAndOther.getLeft());
String version = versionAndOther.getLeft();
String version = versionAndOther.getLeft() == null ? null : versionAndOther.getLeft().toLowerCase();
String kind = versionAndOther.getRight();

return new GroupVersionKind(group, version, kind);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,15 @@ class ModelMapperSpec extends Specification {
it.kind == "ClusterRole"
}
}

def "it resolves custom api versions"() {
expect:
with(mapper.getGroupVersionKindByClass(V3CustomResource)) {
it.version == "v3"
it.group == ""
it.kind == "CustomResource"
}
}

static class V3CustomResource{}
}
Loading