Skip to content

Commit 66dbab1

Browse files
authored
fix(crd-generator): adds an additional printer column annotation (6390)
fix: adds an additional printer column annotation closes: #3069 Signed-off-by: Steve Hawkins <[email protected]> --- switching to enums for format and type based upon Bernhard Strähle's review Signed-off-by: Steve Hawkins <[email protected]> --- updating to jsonPath Signed-off-by: Steve Hawkins <[email protected]>
1 parent 4d1fd2b commit 66dbab1

File tree

8 files changed

+203
-23
lines changed

8 files changed

+203
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Fix #6214: Java generator does not recognize fields in CRDs other than metadata, spec, and status
88

99
#### Improvements
10+
* Fix #3069: added AdditionalPrinterColumn type annotation to completely specify additional printer columns
1011
* Fix #5264: Remove deprecated `Config.errorMessages` field
1112
* Fix #6008: removing the optional dependency on bouncy castle
1213
* Fix #6407: sundrio builder-annotations is not available via bom import

crd-generator/api-v2/src/main/java/io/fabric8/crdv2/generator/AbstractCustomResourceHandler.java

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.fabric8.crdv2.generator;
1717

18+
import io.fabric8.crd.generator.annotation.AdditionalPrinterColumn;
19+
import io.fabric8.crd.generator.annotation.AdditionalPrinterColumn.Format;
1820
import io.fabric8.crd.generator.annotation.PrinterColumn;
1921
import io.fabric8.crdv2.generator.AbstractJsonSchema.AnnotationMetadata;
2022
import io.fabric8.kubernetes.api.model.HasMetadata;
@@ -44,29 +46,35 @@ void addPrinterColumn(String path, String column, String format,
4446

4547
protected void handlePrinterColumns(AbstractJsonSchema<?, ?> resolver, PrinterColumnHandler handler) {
4648
TreeMap<String, AnnotationMetadata> sortedCols = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
49+
resolver.getAdditionalPrinterColumns().forEach(apc -> sortedCols.put(apc.jsonPath(), new AnnotationMetadata(apc, null)));
4750
sortedCols.putAll(resolver.getAllPaths(PrinterColumn.class));
4851
sortedCols.forEach((path, property) -> {
49-
PrinterColumn printerColumn = ((PrinterColumn) property.annotation);
50-
String column = printerColumn.name();
51-
if (Utils.isNullOrEmpty(column)) {
52-
column = path.substring(path.lastIndexOf(".") + 1).toUpperCase();
53-
}
54-
String format = printerColumn.format();
55-
format = Utils.isNotNullOrEmpty(format) ? format : null;
56-
int priority = printerColumn.priority();
57-
String type = property.schema.getType();
58-
if ("object".equals(type) || "array".equals(type)) {
59-
LOGGER.warn("Printer column '{}' has a type '{}' that is not allowed, will use string intead", column, type);
60-
type = "string";
61-
} else if ("string".equals(type) && "date".equals(property.schema.getFormat())) {
62-
type = "date";
63-
}
52+
if (property.annotation instanceof AdditionalPrinterColumn) {
53+
AdditionalPrinterColumn printerColumn = ((AdditionalPrinterColumn) property.annotation);
54+
String column = printerColumn.name();
55+
String format = printerColumn.format() == Format.NONE ? null : printerColumn.format().getValue();
56+
String type = printerColumn.type().getValue();
57+
int priority = printerColumn.priority();
58+
String description = printerColumn.getDescription();
59+
handler.addPrinterColumn(path, column, format, priority, type, description);
60+
} else {
61+
PrinterColumn printerColumn = ((PrinterColumn) property.annotation);
62+
String column = printerColumn.name();
63+
String format = printerColumn.format();
64+
format = Utils.isNotNullOrEmpty(format) ? format : null;
65+
String type = property.schema.getType();
66+
if ("object".equals(type) || "array".equals(type)) {
67+
LOGGER.warn("Printer column '{}' has a type '{}' that is not allowed, will use string intead", column, type);
68+
type = "string";
69+
} else if ("string".equals(type) && "date".equals(property.schema.getFormat())) {
70+
type = "date";
71+
}
72+
int priority = printerColumn.priority();
6473

65-
// TODO: add description to the annotation? The previous logic considered the comments, which are not available here
66-
String description = property.schema.getDescription();
67-
description = Utils.isNotNullOrEmpty(description) ? description : null;
68-
69-
handler.addPrinterColumn(path, column, format, priority, type, description);
74+
// TODO: add description to the annotation? The previous logic considered the comments, which are not available here
75+
String description = property.schema.getDescription();
76+
handler.addPrinterColumn(path, column, format, priority, type, description);
77+
}
7078
});
7179
}
7280

crd-generator/api-v2/src/main/java/io/fabric8/crdv2/generator/AbstractJsonSchema.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.fasterxml.jackson.module.jsonSchema.types.ReferenceSchema;
2929
import com.fasterxml.jackson.module.jsonSchema.types.StringSchema;
3030
import com.fasterxml.jackson.module.jsonSchema.types.ValueTypeSchema;
31+
import io.fabric8.crd.generator.annotation.AdditionalPrinterColumn;
3132
import io.fabric8.crd.generator.annotation.PreserveUnknownFields;
3233
import io.fabric8.crd.generator.annotation.PrinterColumn;
3334
import io.fabric8.crd.generator.annotation.SchemaFrom;
@@ -93,6 +94,7 @@ public abstract class AbstractJsonSchema<T extends KubernetesJSONSchemaProps, V
9394
private ResolvingContext resolvingContext;
9495
private T root;
9596
private Set<String> dependentClasses = new HashSet<>();
97+
private Set<AdditionalPrinterColumn> additionalPrinterColumns = new HashSet<>();
9698

9799
public static class AnnotationMetadata {
98100
public final Annotation annotation;
@@ -141,6 +143,8 @@ public Map<String, AnnotationMetadata> getAllPaths(Class<PrinterColumn> clazz) {
141143
private T resolveRoot(Class<?> definition) {
142144
InternalSchemaSwaps schemaSwaps = new InternalSchemaSwaps();
143145
JsonSchema schema = resolvingContext.toJsonSchema(definition);
146+
consumeRepeatingAnnotation(definition, AdditionalPrinterColumn.class,
147+
additionalPrinterColumns::add);
144148
if (schema instanceof GeneratorObjectSchema) {
145149
return resolveObject(new LinkedHashMap<>(), schemaSwaps, schema, "kind", "apiVersion", "metadata");
146150
}
@@ -598,4 +602,8 @@ private static String mapNotEmpty(String s) {
598602

599603
protected abstract T raw();
600604

605+
public Set<AdditionalPrinterColumn> getAdditionalPrinterColumns() {
606+
return additionalPrinterColumns;
607+
}
608+
601609
}

crd-generator/api-v2/src/main/java/io/fabric8/crdv2/generator/v1/CustomResourceHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public void handle(CustomResourceInfo config, ResolvingContext resolvingContext)
6969
handlePrinterColumns(resolver, new PrinterColumnHandler() {
7070
@Override
7171
public void addPrinterColumn(String path, String column, String format, int priority, String type, String description) {
72+
if (Utils.isNullOrEmpty(column)) {
73+
column = path.substring(path.lastIndexOf(".") + 1).toUpperCase();
74+
}
75+
description = Utils.isNotNullOrEmpty(description) ? description : null;
76+
7277
builder.addNewAdditionalPrinterColumn()
7378
.withType(type)
7479
.withName(column)

crd-generator/api-v2/src/test/java/io/fabric8/crdv2/example/joke/JokeRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.fabric8.crdv2.example.joke;
1717

18+
import io.fabric8.crd.generator.annotation.AdditionalPrinterColumn;
19+
import io.fabric8.crd.generator.annotation.AdditionalPrinterColumn.Type;
1820
import io.fabric8.kubernetes.api.model.Namespaced;
1921
import io.fabric8.kubernetes.client.CustomResource;
2022
import io.fabric8.kubernetes.model.annotation.Group;
@@ -24,6 +26,7 @@
2426
@Group("samples.javaoperatorsdk.io")
2527
@Version("v1alpha1")
2628
@ShortNames("jr")
29+
@AdditionalPrinterColumn(name = "Age", jsonPath = ".metadata.creationTimestamp", type = Type.DATE)
2730
public class JokeRequest extends CustomResource<JokeRequestSpec, JokeRequestStatus> implements Namespaced {
2831

2932
}

crd-generator/api-v2/src/test/java/io/fabric8/crdv2/generator/CRDGeneratorTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,18 +387,23 @@ void jokerequestCRDShouldWork() {
387387
// printer columns should be ordered in the alphabetical order of their json path
388388
final List<CustomResourceColumnDefinition> printerColumns = version
389389
.getAdditionalPrinterColumns();
390-
assertEquals(3, printerColumns.size());
390+
assertEquals(4, printerColumns.size());
391391
CustomResourceColumnDefinition columnDefinition = printerColumns.get(0);
392+
assertEquals("date", columnDefinition.getType());
393+
assertEquals(".metadata.creationTimestamp", columnDefinition.getJsonPath());
394+
assertEquals("Age", columnDefinition.getName());
395+
assertEquals(0, columnDefinition.getPriority());
396+
columnDefinition = printerColumns.get(1);
392397
assertEquals("string", columnDefinition.getType());
393398
assertEquals(".spec.category", columnDefinition.getJsonPath());
394399
assertEquals("jokeCategory", columnDefinition.getName());
395400
assertEquals(1, columnDefinition.getPriority());
396-
columnDefinition = printerColumns.get(1);
401+
columnDefinition = printerColumns.get(2);
397402
assertEquals("string", columnDefinition.getType());
398403
assertEquals(".spec.excluded", columnDefinition.getJsonPath());
399404
assertEquals("excludedTopics", columnDefinition.getName());
400405
assertEquals(0, columnDefinition.getPriority());
401-
columnDefinition = printerColumns.get(2);
406+
columnDefinition = printerColumns.get(3);
402407
assertEquals("string", columnDefinition.getType());
403408
assertEquals(".status.category", columnDefinition.getJsonPath());
404409
assertEquals("jokeCategory", columnDefinition.getName());
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (C) 2015 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.fabric8.crd.generator.annotation;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Repeatable;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Defines an additional printer column. Must be placed at the root of the
26+
* custom resource.
27+
*/
28+
@Repeatable(AdditionalPrinterColumns.class)
29+
@Target({ ElementType.TYPE })
30+
@Retention(RetentionPolicy.RUNTIME)
31+
public @interface AdditionalPrinterColumn {
32+
33+
//https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#type
34+
enum Type {
35+
36+
STRING("string"),
37+
INTEGER("integer"),
38+
NUMBER("number"),
39+
BOOLEAN("boolean"),
40+
DATE("date");
41+
42+
public final String value;
43+
44+
Type(String value) {
45+
this.value = value;
46+
}
47+
48+
public String getValue() {
49+
return value;
50+
}
51+
}
52+
53+
// https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#format
54+
enum Format {
55+
56+
NONE(""),
57+
INT32("int32"),
58+
INT64("int64"),
59+
FLOAT("float"),
60+
DOUBLE("double"),
61+
BYTE("byte"),
62+
DATE("date"),
63+
DATE_TIME("date-time"),
64+
PASSWORD("password");
65+
66+
public final String value;
67+
68+
Format(String value) {
69+
this.value = value;
70+
}
71+
72+
public String getValue() {
73+
return value;
74+
}
75+
}
76+
77+
/**
78+
* The name of the column. An empty column name implies the use of the last path
79+
* element
80+
*
81+
* @return the column name, or empty string if the last path element should be
82+
* used.
83+
*/
84+
String name() default "";
85+
86+
/**
87+
* The printer column format.
88+
*
89+
* @return the format or NONE if no format is specified.
90+
*/
91+
Format format() default Format.NONE;
92+
93+
/**
94+
* The printer column priority.
95+
*
96+
* @return the priority or 0 if no priority is specified.
97+
*/
98+
int priority() default 0;
99+
100+
/**
101+
* The JSON Path to the field
102+
*
103+
* @return
104+
*/
105+
String jsonPath();
106+
107+
/**
108+
* The type of the printer column
109+
*
110+
* @return the type
111+
*/
112+
Type type() default Type.STRING;
113+
114+
/**
115+
* The description of the printer column
116+
*
117+
* @return the description
118+
*/
119+
String getDescription() default "";
120+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2015 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.fabric8.crd.generator.annotation;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
22+
23+
/**
24+
* A container for multiple {@link AdditionalPrinterColumn}s
25+
*/
26+
@Target({ ElementType.TYPE })
27+
@Retention(RetentionPolicy.RUNTIME)
28+
public @interface AdditionalPrinterColumns {
29+
AdditionalPrinterColumn[] value();
30+
}

0 commit comments

Comments
 (0)