Skip to content

Commit af26286

Browse files
authored
feat: support CSVMetadata displayName & description on CRs (#622)
1 parent b9f9ccb commit af26286

File tree

6 files changed

+86
-15
lines changed

6 files changed

+86
-15
lines changed

bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/BundleProcessor.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static io.quarkiverse.operatorsdk.deployment.AddClusterRolesDecorator.ALL_VERBS;
44

5+
import io.quarkiverse.operatorsdk.common.DependentResourceAugmentedClassInfo;
56
import java.io.ByteArrayInputStream;
67
import java.io.IOException;
78
import java.nio.file.Path;
@@ -35,6 +36,7 @@
3536
import io.quarkiverse.operatorsdk.bundle.runtime.SharedCSVMetadata;
3637
import io.quarkiverse.operatorsdk.common.ClassUtils;
3738
import io.quarkiverse.operatorsdk.common.ConfigurationUtils;
39+
import io.quarkiverse.operatorsdk.common.ReconciledAugmentedClassInfo;
3840
import io.quarkiverse.operatorsdk.common.ReconcilerAugmentedClassInfo;
3941
import io.quarkiverse.operatorsdk.deployment.GeneratedCRDInfoBuildItem;
4042
import io.quarkiverse.operatorsdk.deployment.VersionBuildItem;
@@ -48,10 +50,13 @@
4850
import io.quarkus.kubernetes.spi.GeneratedKubernetesResourceBuildItem;
4951

5052
public class BundleProcessor {
53+
5154
private static final Logger log = Logger.getLogger(BundleProcessor.class);
5255
private static final DotName SHARED_CSV_METADATA = DotName.createSimple(SharedCSVMetadata.class.getName());
5356
private static final DotName CSV_METADATA = DotName.createSimple(CSVMetadata.class.getName());
5457
private static final String BUNDLE = "bundle";
58+
public static final String CRD_DISPLAY_NAME = "CRD_DISPLAY_NAME";
59+
public static final String CRD_DESCRIPTION = "CRD_DESCRIPTION";
5560

5661
@SuppressWarnings({ "unused" })
5762
@BuildStep
@@ -98,12 +103,47 @@ CSVMetadataBuildItem gatherCSVMetadata(ApplicationInfoBuildItem configuration,
98103
reconcilerInfo.nameOrFailIfUnset(),
99104
getMetadataOriginInformation(csvMetadataAnnotation, maybeCSVMetadataName, csvMetadata));
100105

101-
csvGroups.computeIfAbsent(csvMetadata, m -> new ArrayList<>()).add(reconcilerInfo);
106+
csvGroups.computeIfAbsent(csvMetadata, m -> new ArrayList<>()).add(
107+
augmentReconcilerInfo(reconcilerInfo));
102108
});
103109

104110
return new CSVMetadataBuildItem(csvGroups);
105111
}
106112

113+
private static ReconcilerAugmentedClassInfo augmentReconcilerInfo(
114+
ReconcilerAugmentedClassInfo reconcilerInfo) {
115+
// if primary resource is a CR, check if it is annotated with CSVMetadata and augment it if it is
116+
final ReconciledAugmentedClassInfo<?> primaryCI = reconcilerInfo.associatedResourceInfo();
117+
augmentResourceInfoIfCR(primaryCI);
118+
119+
reconcilerInfo.getDependentResourceInfos().forEach(draci -> {
120+
// if the dependent is a CR, check if it is annotated with CSVMetadata and augment it if it is
121+
final ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo = draci.associatedResourceInfo();
122+
augmentResourceInfoIfCR(reconciledAugmentedClassInfo);
123+
});
124+
return reconcilerInfo;
125+
}
126+
127+
private static void augmentResourceInfoIfCR(ReconciledAugmentedClassInfo<?> reconciledAugmentedClassInfo) {
128+
if (reconciledAugmentedClassInfo.isCR()) {
129+
final var csvMetadata = reconciledAugmentedClassInfo.classInfo().annotation(CSV_METADATA);
130+
if (csvMetadata != null) {
131+
// extract display name and description
132+
final var displayName = ConfigurationUtils.annotationValueOrDefault(csvMetadata,
133+
"displayName", AnnotationValue::asString,
134+
() -> reconciledAugmentedClassInfo.asResourceTargeting().kind());
135+
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DISPLAY_NAME, displayName);
136+
final var description = ConfigurationUtils.annotationValueOrDefault(
137+
csvMetadata,
138+
"description", AnnotationValue::asString,
139+
() -> null);
140+
if (description != null) {
141+
reconciledAugmentedClassInfo.setExtendedInfo(CRD_DESCRIPTION, description);
142+
}
143+
}
144+
}
145+
}
146+
107147
private String getMetadataOriginInformation(AnnotationInstance csvMetadataAnnotation, Optional<String> csvMetadataName,
108148
CSVMetadataHolder metadataHolder) {
109149
final var isDefault = csvMetadataAnnotation == null;

bundle-generator/deployment/src/main/java/io/quarkiverse/operatorsdk/bundle/deployment/builders/CsvManifestsBuilder.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package io.quarkiverse.operatorsdk.bundle.deployment.builders;
22

33
import static io.quarkiverse.operatorsdk.bundle.deployment.BundleGenerator.MANIFESTS;
4+
import static io.quarkiverse.operatorsdk.bundle.deployment.BundleProcessor.CRD_DESCRIPTION;
5+
import static io.quarkiverse.operatorsdk.bundle.deployment.BundleProcessor.CRD_DISPLAY_NAME;
46

7+
import io.quarkiverse.operatorsdk.common.ReconciledResourceAugmentedClassInfo;
58
import java.io.FileInputStream;
69
import java.io.IOException;
710
import java.nio.file.Path;
@@ -143,12 +146,7 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, List<ReconcilerAugmentedC
143146
final var resourceInfo = raci.associatedResourceInfo();
144147
if (resourceInfo.isCR()) {
145148
final var asResource = resourceInfo.asResourceTargeting();
146-
final var fullResourceName = asResource.fullResourceName();
147-
ownedCRs.add(new CRDDescriptionBuilder()
148-
.withName(fullResourceName)
149-
.withVersion(asResource.version())
150-
.withKind(asResource.kind())
151-
.build());
149+
ownedCRs.add(createCRDDescription(asResource));
152150
}
153151

154152
// add required CRD for each dependent that targets a CR
@@ -159,12 +157,7 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, List<ReconcilerAugmentedC
159157
.map(ReconciledAugmentedClassInfo::asResourceTargeting)
160158
.forEach(secondaryResource -> {
161159
if (secondaryResource.isCR()) {
162-
final var fullResourceName = secondaryResource.fullResourceName();
163-
requiredCRs.add(new CRDDescriptionBuilder()
164-
.withName(fullResourceName)
165-
.withVersion(secondaryResource.version())
166-
.withKind(secondaryResource.kind())
167-
.build());
160+
requiredCRs.add(createCRDDescription(secondaryResource));
168161
} else {
169162
nativeApis.add(new GroupVersionKind(secondaryResource.group(), secondaryResource.kind(),
170163
secondaryResource.version()));
@@ -196,6 +189,17 @@ public CsvManifestsBuilder(CSVMetadataHolder metadata, List<ReconcilerAugmentedC
196189
.endSpec();
197190
}
198191

192+
private CRDDescription createCRDDescription(ReconciledResourceAugmentedClassInfo<?> secondaryResource) {
193+
final var fullResourceName = secondaryResource.fullResourceName();
194+
return new CRDDescriptionBuilder()
195+
.withName(fullResourceName)
196+
.withDisplayName(secondaryResource.getExtendedInfo(CRD_DISPLAY_NAME, String.class))
197+
.withDescription(secondaryResource.getExtendedInfo(CRD_DESCRIPTION, String.class))
198+
.withVersion(secondaryResource.version())
199+
.withKind(secondaryResource.kind())
200+
.build();
201+
}
202+
199203
private static String asString(GroupVersionKind gvk) {
200204
return gvk.getGroup() + " " + gvk.getKind() + gvk.getVersion();
201205
}

bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/MultipleOperatorsBundleTest.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static io.quarkiverse.operatorsdk.bundle.Utils.getCRDNameFor;
66
import static org.junit.jupiter.api.Assertions.assertEquals;
77

8+
import io.fabric8.openshift.api.model.operatorhub.v1alpha1.CRDDescription;
89
import java.io.IOException;
910
import java.nio.file.Files;
1011

@@ -19,6 +20,7 @@
1920
import io.quarkus.test.ProdBuildResults;
2021
import io.quarkus.test.ProdModeTestResults;
2122
import io.quarkus.test.QuarkusProdModeTest;
23+
import org.testcontainers.shaded.org.apache.commons.lang3.ThreadUtils.ThreadIdPredicate;
2224

2325
public class MultipleOperatorsBundleTest {
2426

@@ -47,9 +49,15 @@ public void shouldWriteBundleForTheOperators() throws IOException {
4749
final var csvAsString = Files.readString(thirdManifests.resolve("third-operator.clusterserviceversion.yaml"));
4850
final var csv = Serialization.unmarshal(csvAsString, ClusterServiceVersion.class);
4951
final var crds = csv.getSpec().getCustomresourcedefinitions();
50-
assertEquals(HasMetadata.getFullResourceName(Third.class), crds.getOwned().get(0).getName());
52+
final var thirdCRD = crds.getOwned().get(0);
53+
assertEquals(HasMetadata.getFullResourceName(Third.class), thirdCRD.getName());
54+
assertEquals(Third.DISPLAY, thirdCRD.getDisplayName());
55+
assertEquals(Third.DESCRIPTION, thirdCRD.getDescription());
5156
// CRDs should be alphabetically ordered
52-
assertEquals(HasMetadata.getFullResourceName(External.class), crds.getRequired().get(0).getName());
57+
final var externalCRD = crds.getRequired().get(0);
58+
assertEquals(HasMetadata.getFullResourceName(External.class), externalCRD.getName());
59+
assertEquals(External.DISPLAY_NAME, externalCRD.getDisplayName());
60+
assertEquals(External.DESCRIPTION, externalCRD.getDescription());
5361
assertEquals(HasMetadata.getFullResourceName(SecondExternal.class), crds.getRequired().get(1).getName());
5462
// should list native APIs as well
5563
final var podGVK = csv.getSpec().getNativeAPIs().get(0);

bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/External.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import io.fabric8.kubernetes.client.CustomResource;
44
import io.fabric8.kubernetes.model.annotation.Group;
55
import io.fabric8.kubernetes.model.annotation.Version;
6+
import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadata;
67

78
@Group("halkyon.io")
89
@Version("v1alpha1")
10+
@CSVMetadata(displayName = External.DISPLAY_NAME, description = External.DESCRIPTION)
911
public class External extends CustomResource<Void, Void> {
1012

13+
public static final String DISPLAY_NAME = "External display name";
14+
public static final String DESCRIPTION = "External description";
1115
}

bundle-generator/deployment/src/test/java/io/quarkiverse/operatorsdk/bundle/sources/Third.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
import io.fabric8.kubernetes.client.CustomResource;
55
import io.fabric8.kubernetes.model.annotation.Group;
66
import io.fabric8.kubernetes.model.annotation.Version;
7+
import io.quarkiverse.operatorsdk.bundle.runtime.CSVMetadata;
78

89
@Group("samples.javaoperatorsdk.io")
910
@Version("v1alpha1")
11+
@CSVMetadata(displayName = Third.DISPLAY, description = Third.DESCRIPTION)
1012
public class Third extends CustomResource<Void, Void> implements Namespaced {
1113

14+
public static final String DESCRIPTION = "Third description";
15+
public static final String DISPLAY = "Third display";
1216
}

common-deployment/src/main/java/io/quarkiverse/operatorsdk/common/SelectiveAugmentedClassInfo.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.ArrayList;
88
import java.util.List;
99
import java.util.Map;
10+
import java.util.concurrent.ConcurrentHashMap;
1011

1112
import org.jboss.jandex.ClassInfo;
1213
import org.jboss.jandex.DotName;
@@ -22,6 +23,7 @@ public abstract class SelectiveAugmentedClassInfo {
2223
private Type[] types;
2324
private final DotName extendedOrImplementedClass;
2425
private final int expectedParameterTypesCardinality;
26+
private final Map<Object, Object> extendedInfos = new ConcurrentHashMap<>();
2527

2628
private final List<String> classNamesToRegisterForReflection = new ArrayList<>();
2729

@@ -105,4 +107,13 @@ protected void augmentIfKept(IndexView index, Logger log, Map<String, Object> co
105107
}
106108

107109
protected abstract void doAugment(IndexView index, Logger log, Map<String, Object> context);
110+
111+
@SuppressWarnings({ "unchecked", "unused" })
112+
public <T> T getExtendedInfo(Object key, Class<T> expectedValueType) {
113+
return (T) extendedInfos.get(key);
114+
}
115+
116+
public void setExtendedInfo(Object key, Object value) {
117+
extendedInfos.put(key, value);
118+
}
108119
}

0 commit comments

Comments
 (0)