Skip to content

Commit

Permalink
refactor: openshift-model-config & openshift-mode-operator generated …
Browse files Browse the repository at this point in the history
…from OpenAPI schemas

Signed-off-by: Marc Nuri <[email protected]>
  • Loading branch information
manusa committed Sep 5, 2024
1 parent b5ea02b commit 91c4e22
Show file tree
Hide file tree
Showing 674 changed files with 43,578 additions and 9,865 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ generate-openapi-classes:
cd kubernetes-model-generator/kubernetes-model-storageclass && mvn -Pgenerate clean install
cd kubernetes-model-generator/kubernetes-model-resource && mvn -Pgenerate clean install
cd kubernetes-model-generator/kubernetes-model-kustomize && mvn -Pgenerate clean install
cd kubernetes-model-generator/openshift-model-config && mvn -Pgenerate clean install
cd kubernetes-model-generator/openshift-model-operator && mvn -Pgenerate clean install

# Legacy generation of the model: TODO: remove
.PHONY: generate-model-legacy
Expand Down
2 changes: 0 additions & 2 deletions kubernetes-model-generator/generateModel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ ABSOLUTE_BASEDIR=$(realpath "$BASEDIR")

# Array for all existing modules
declare -a modules=(
"openshift-model-config"
"openshift-model"
"openshift-model-operator"
"openshift-model-operatorhub"
"openshift-model-console"
"openshift-model-clusterautoscaling"
Expand Down
7 changes: 1 addition & 6 deletions kubernetes-model-generator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@ require (
k8s.io/apiextensions-apiserver v0.30.0
k8s.io/apimachinery v0.30.0
k8s.io/client-go v12.0.0+incompatible
k8s.io/kube-aggregator v0.30.0
k8s.io/metrics v0.30.0
sigs.k8s.io/gateway-api v1.0.0
sigs.k8s.io/kube-storage-version-migrator v0.0.5
sigs.k8s.io/kustomize/api v0.14.0
)

require (
github.com/PaesslerAG/gval v1.0.0 // indirect
github.com/PaesslerAG/jsonpath v0.1.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.44.204 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
Expand All @@ -44,7 +41,6 @@ require (
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
Expand Down Expand Up @@ -107,7 +103,6 @@ require (
sigs.k8s.io/cluster-api v1.7.1 // indirect
sigs.k8s.io/controller-runtime v0.18.1 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
Expand Down
12 changes: 0 additions & 12 deletions kubernetes-model-generator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -997,8 +997,6 @@ github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ER
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
Expand Down Expand Up @@ -2780,8 +2778,6 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kms v0.30.0/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4=
k8s.io/kube-aggregator v0.21.0/go.mod h1:sIaa9L4QCBo9gjPyoGJns4cBjYVLq3s49FxF7m/1A0A=
k8s.io/kube-aggregator v0.30.0 h1:+Opc0lmhRmHbNM4m3mLSsUFmK/ikMapO9rvGirX5CEM=
k8s.io/kube-aggregator v0.30.0/go.mod h1:KbZZkSSjYE6vkB2TSuZ9GBjU3ucgL7YxT8yX8wll0iQ=
k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
Expand All @@ -2791,8 +2787,6 @@ k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lV
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/metrics v0.30.0 h1:tqB+T0GJY288KahaO3Eb41HaDVeLR18gBmyPo0R417s=
k8s.io/metrics v0.30.0/go.mod h1:nSDA8V19WHhCTBhRYuyzJT9yPJBxSpqbyrGCCQ4jPj4=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
Expand Down Expand Up @@ -2872,18 +2866,12 @@ sigs.k8s.io/cluster-api v1.7.1/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNN
sigs.k8s.io/controller-runtime v0.18.1 h1:RpWbigmuiylbxOCLy0tGnq1cU1qWPwNIQzoJk+QeJx4=
sigs.k8s.io/controller-runtime v0.18.1/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU=
sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs=
sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kube-storage-version-migrator v0.0.5 h1:PumtXIUB3BJ3LnTV/j+owQEybKR2e46lPflC0Sgea2o=
sigs.k8s.io/kube-storage-version-migrator v0.0.5/go.mod h1:igyHfaOB680DSAOk5x/8mcKk6t6y05AhSl7q+eV22NU=
sigs.k8s.io/kustomize/api v0.14.0 h1:6+QLmXXA8X4eDM7ejeaNUyruA1DDB3PVIjbpVhDOJRA=
sigs.k8s.io/kustomize/api v0.14.0/go.mod h1:vmOXlC8BcmcUJQjiceUbcyQ75JBP6eg8sgoyzc+eLpQ=
sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs=
sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,25 @@ public class SchemaFlattener {
private static final String PACKAGE_SEPARATOR_CHARACTER = ".";
private static final String SEPARATOR_CHARACTER = "_";

private static final Map<String, String> sundrioBuilderWorkarounds = new HashMap<>();
private static final Set<String> preservedNames = ConcurrentHashMap.newKeySet();
static {
sundrioBuilderWorkarounds.put("spec", "spc");
sundrioBuilderWorkarounds.put("status", "sts");
preservedNames.add("spec");
preservedNames.add("status");
// makes class names in openshift-model-config more user-friendly
preservedNames.add("aws");
preservedNames.add("azure");
preservedNames.add("baremetal");
preservedNames.add("gcp");
preservedNames.add("ibmcloud");
preservedNames.add("libvirt");
preservedNames.add("nutanix");
preservedNames.add("none");
preservedNames.add("openstack");
preservedNames.add("ovirt");
preservedNames.add("powervs");
preservedNames.add("vsphere");
preservedNames.add("basicAuth");
preservedNames.add("openID");
}
private static final ObjectMapper structureMapper = Json.mapper().copy();
static {
Expand Down Expand Up @@ -148,7 +163,7 @@ private static synchronized void clear(OpenAPI openAPI) {

private final OpenAPI openAPI;
private final Set<String> uniqueNames;
private final Map<String, String> generatedComponentSignatures;
private final Map<String, String> reusableComponentSignatures;
private final Map<String, Schema<?>> componentsToAdd;

public SchemaFlattenerContext(OpenAPI openAPI) {
Expand All @@ -160,11 +175,10 @@ public SchemaFlattenerContext(OpenAPI openAPI) {
openAPI.getComponents().setSchemas(new HashMap<>());
}
uniqueNames = ConcurrentHashMap.newKeySet();
generatedComponentSignatures = new ConcurrentHashMap<>();
reusableComponentSignatures = new HashMap<>();
// Compute signatures of all defined components to be able to reuse them from inlined component definitions
for (String key : openAPI.getComponents().getSchemas().keySet()) {
final Schema<?> schema = openAPI.getComponents().getSchemas().get(key);
generatedComponentSignatures.put(toJson(schema), key);
reusableComponentSignatures.put(toJson(openAPI.getComponents().getSchemas().get(key)), key);
}
componentsToAdd = new ConcurrentHashMap<>();
}
Expand All @@ -175,11 +189,10 @@ Components getComponents() {

void addComponentSchema(String key, Schema<?> componentSchema) {
componentsToAdd.put(key, componentSchema);
generatedComponentSignatures.put(toJson(componentSchema), key);
}

Schema<?> toRef(Schema<?> schema, ComponentName componentName) {
final String existingModelName = generatedComponentSignatures.getOrDefault(toJson(schema), null);
final String existingModelName = reusableComponentSignatures.getOrDefault(toJson(schema), null);
final Schema<?> refSchema = new Schema<>();
refSchema.setRequired(schema.getRequired());
if (existingModelName != null) {
Expand Down Expand Up @@ -211,7 +224,6 @@ private String uniqueName(final String name) {
uniqueName = name + SEPARATOR_CHARACTER + ++count;
}
}

}

private static final class ComponentName {
Expand Down Expand Up @@ -273,19 +285,35 @@ public String toString() {
// Middle parts are contracted (unless preserved)
for (int it = 1; it < nameParts.size() - 1; it++) {
final String part = nameParts.get(it);
sb.append(part.substring(0, 1).toUpperCase());
if (sundrioBuilderWorkarounds.containsKey(part)) {
sb.append(part.substring(1));
if (preservedNames.contains(part)) {
sb.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
} else {
sb.append(contract(part));
}
}
// Last part is capitalized
if (nameParts.size() > 1) {
final String part = nameParts.get(nameParts.size() - 1);
final String lastPart = sundrioBuilderWorkarounds.getOrDefault(part, part);
final String lastPart = nameParts.get(nameParts.size() - 1);
sb.append(lastPart.substring(0, 1).toUpperCase());
sb.append(lastPart.substring(1));
}
return sb.toString();
}
}

private static String contract(String word) {
final StringBuilder sb = new StringBuilder();
sb.append(word.substring(0, 1).toUpperCase());
boolean inWord = true;
for (int i = 1; i < word.length(); i++) {
final char c = word.charAt(i);
if (!inWord && Character.isUpperCase(c)) {
sb.append(c);
inWord = true;
} else if (inWord && Character.isLowerCase(c)) {
inWord = false;
}
}
return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ void setUp() {
openAPI = new OpenAPI(SpecVersion.V31);
openAPI.setComponents(new Components());
openAPI.setPaths(new Paths());
openAPI.getComponents().addSchemas("Common", new ObjectSchema()
.addProperty("name", new StringSchema()));
openAPI.getComponents().addSchemas("Root", new ObjectSchema()
.addProperty("child", new ObjectSchema()
.addProperty("name", new StringSchema())
Expand Down Expand Up @@ -76,8 +78,10 @@ void setUp() {
.addProperty("mName", new StringSchema())
.addProperty("child", new ObjectSchema()
.addProperty("mName", new StringSchema())
.addProperty("common", new ObjectSchema()
.addProperty("name", new StringSchema()))))));
.addProperty("child", new ObjectSchema()
.addProperty("mName", new StringSchema())
.addProperty("common", new ObjectSchema()
.addProperty("name", new StringSchema())))))));
openAPI.getComponents().addSchemas("CommonArray", new ObjectSchema()
.addProperty("child", new ArraySchema()
.items(new ObjectSchema()
Expand All @@ -103,9 +107,20 @@ void setUp() {
.addProperty("metadata", new ObjectSchema())
.addProperty("spec", new ObjectSchema()
.addProperty("replicas", new IntegerSchema())
.addProperty("openAPI", new ObjectSchema()
.addProperty("in-openAPI", new StringSchema())
.addProperty("schema", new ObjectSchema()
.addProperty("$ref", new StringSchema())))
.addProperty("selector", new ObjectSchema()
.addProperty("in-spec", new BooleanSchema())
.addProperty("matchLabels", new MapSchema().additionalProperties(new StringSchema()))))
.addProperty("matchLabels", new MapSchema().additionalProperties(new StringSchema())))
.addProperty("aws", new ObjectSchema()
.addProperty("spec", new ObjectSchema()
.addProperty("in-aws", new StringSchema())))
.addProperty("libvirt", new ObjectSchema()
.addProperty("spec", new ObjectSchema()
.addProperty("in-libvirt", new StringSchema()))))

.addProperty("status", new ObjectSchema()
.addProperty("phase", new StringSchema())
.addProperty("selector", new ObjectSchema()
Expand All @@ -116,7 +131,7 @@ void setUp() {
}

@ParameterizedTest
@ValueSource(strings = { "RootChild", "RootCChild", "RootCCChild" })
@ValueSource(strings = { "Common", "RootChild", "RootCChild" })
void preservesStringFields(String componentName) {
assertEquals("string",
((Schema<?>) openAPI.getComponents().getSchemas().get(componentName).getProperties().get("name")).getType());
Expand Down Expand Up @@ -144,74 +159,65 @@ void contractsNameOfSecondInlined(String expectedComponentName) {
}

@ParameterizedTest
@ValueSource(strings = { "RootCCChild", "GRootCCChild", "com.example.with.package.RootCCChild" })
@ValueSource(strings = { "GRootCCChild", "com.example.with.package.RootCCChild", "MapCCChild" })
void contractsNameOfThirdInlined(String expectedComponentName) {
assertTrue(openAPI.getComponents().getSchemas().containsKey(expectedComponentName));
}

@Test
void contractsContiguousUpperCaseProperly() {
assertTrue(openAPI.getComponents().getSchemas().containsKey("com.example.kubernetes.TypicalSpecOpenAPI"));
assertTrue(openAPI.getComponents().getSchemas().containsKey("com.example.kubernetes.TypicalSpecOASchema"));
}

@ParameterizedTest
@ValueSource(strings = { "Aws", "Libvirt" })
void contractPreservesNames(String preservedName) {
assertTrue(
openAPI.getComponents().getSchemas().containsKey("com.example.kubernetes.TypicalSpec" + preservedName + "Spec"));
}

}

@Nested
class ReusesCommonSchema {
class ReusesCommonTopLevelSchemas {

@Test
void rootChildReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("RootCChild").getProperties().get("child")).get$ref());
}

@Test
void grootChildReusesRootSchema() {
assertEquals("#/components/schemas/RootCCChild",
void grootChildReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("GRootCCChild").getProperties().get("common")).get$ref());
}

@Test
void arrayChildReusesRootSchema() {
assertEquals("#/components/schemas/RootCCChild",
void arrayChildReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("ArrayCChild").getProperties().get("common")).get$ref());
}

@Test
void arraySchemaReusesRootSchema() {
assertEquals("#/components/schemas/RootCCChild",
void arraySchemaReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("CommonArray").getProperties().get("child")).getItems()
.get$ref());
}

@Test
void mapChildReusesRootSchema() {
assertEquals("#/components/schemas/RootCCChild",
((Schema<?>) openAPI.getComponents().getSchemas().get("MapCChild").getProperties().get("common")).get$ref());
void mapChildReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("MapCCChild").getProperties().get("common")).get$ref());
}

@Test
void packagedChildReusesRootSchema() {
assertEquals("#/components/schemas/RootCCChild",
void packagedChildReusesCommonSchema() {
assertEquals("#/components/schemas/Common",
((Schema<?>) openAPI.getComponents().getSchemas().get("com.example.with.package.RootCCChild").getProperties()
.get("common")).get$ref());
}
}

/**
* To avoid problems with Sundrio (https://github.com/fabric8io/kubernetes-client/issues/6320)
* we'll do special handling of inlined nested fields (spec, status, parameters)
* <p>
* This is required because their names will likely collision with the generated classes when creating the builders
*/
@Nested
class SundrioHandling {

@ParameterizedTest
@ValueSource(strings = {
"com.example.kubernetes.TypicalSpc",
"com.example.kubernetes.TypicalSts"
})
void keywordsAreTranslated(String expectedComponentName) {
assertTrue(openAPI.getComponents().getSchemas().containsKey(expectedComponentName));
}

@ParameterizedTest
@ValueSource(strings = {
"com.example.kubernetes.TypicalSpecSelector",
"com.example.kubernetes.TypicalStatusSelector"
})
void preservesInlinedKeywords(String expectedComponentName) {
assertTrue(openAPI.getComponents().getSchemas().containsKey(expectedComponentName));
}
}
}

Large diffs are not rendered by default.

Loading

0 comments on commit 91c4e22

Please sign in to comment.