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

CRD generation from RealmRepresentation #9759

Merged
merged 6 commits into from Jan 27, 2022
Merged

Conversation

andreaTP
Copy link
Contributor

@andreaTP andreaTP commented Jan 24, 2022

This is the first step for #9172

Resolves #9787

those are the changes to the model needed successfully generate a CRD for the operator.

protected List<String> realmRoles;
protected Map<String, List<String>> clientRoles;
// TODO: eventually generate code for Nth levels of depth
// protected List<GroupRepresentation> subGroups;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to limitations in the CRD schema we should limit the recursive subGroups to a finite number.
What would be a reasonable number of allowed, nested, subGroups?
cc. @stianst @pedroigor

private String providerId;
private String subType;
// TODO: eventually generate code for Nth levels of depth
// private MultivaluedHashMap<String, ComponentExportRepresentation> subComponents = new MultivaluedHashMap<>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to limitations in the CRD schema we should limit the recursive subComponents to a finite number.
What would be a reasonable number of allowed, nested, subComponents?
cc. @stianst @pedroigor

pom.xml Outdated
@@ -81,7 +81,7 @@
<infinispan.version>12.1.7.Final</infinispan.version>
<infinispan.protostream.processor.version>4.4.1.Final</infinispan.protostream.processor.version>
<javax.annotation-api.version>1.3.2</javax.annotation-api.version>
<jackson.version>2.12.1</jackson.version>
<jackson.version>2.13.1</jackson.version>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transitive update from the kubernetes-client (the old version breaks)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jackson version needs to honor quarkus / wildfly versions and cannot be changed for the sake of an added library local to a part of the project. See e.g. quarkus/pom.xml on how to override library versions should this be necessary.

@@ -67,6 +67,9 @@ public void setPriority(int priority) {
*
* @return
*/
@Deprecated
private boolean autheticatorFlow;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding this unused field I would be happy to remove the following accessors, unfortunately, the latter is a breaking change for the import/export functionality.
cc. @stianst @pedroigor

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing something, but why do you need to remove a simple boolean field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are adding back the field, that remains unused, since it's emitted by the Json serialization.
If we don't add it, you would need to remove all the relevant fields autheticatorFlow (WITH the typo) from the exported RealmRepresentation before importing it as a CR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stianst this is the only change in the core I'm leaving, as far as I can tell it should be ok, but let me know if I have to duplicate even this file.

@jonathanvila
Copy link
Contributor

I'm a bit lost here. I see files in the test folder, but I haven't found any proper Test checking the changes. Can you clarify ?

@andreaTP
Copy link
Contributor Author

I'm a bit lost here. I see files in the test folder, but I haven't found any proper Test checking the changes. Can you clarify ?

Sure, the files in the test folder will make the compilation fail if the CRD can't be generated.

@vmuzikar vmuzikar requested a review from stianst January 25, 2022 14:47
jonathanvila
jonathanvila previously approved these changes Jan 25, 2022
Copy link
Contributor

@jonathanvila jonathanvila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@vmuzikar vmuzikar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andreaTP Thanks, nice job! ;)

@iankko @pskopek Could you please double check that the dependencies changes (potentially affecting the whole project) are ok?

core/pom.xml Outdated
Comment on lines 91 to 95
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>crd-generator-apt</artifactId>
<scope>test</scope>
</dependency>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this dep used? We don't have any tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is generating a CRD in the test scope.

@@ -67,6 +67,9 @@ public void setPriority(int priority) {
*
* @return
*/
@Deprecated
private boolean autheticatorFlow;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing something, but why do you need to remove a simple boolean field?

@@ -42,6 +44,7 @@
private static final Logger logger = Logger.getLogger(RealmRepresentation.class);

protected String id;
@NotNull
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that eventually realm really is not null but I'm not sure if in some cases it really cannot be null in the process.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to move the NotNull to the id if it's needed.
Just waiting for a nudge from someone 🙂

@@ -33,7 +34,9 @@
private String id;
private String name;
private String iconUri;
@SchemaFrom(type = java.lang.Void.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean we won't support policies here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, according to @pedroigor it's not needed.

private List<PolicyRepresentation> policies;
@SchemaFrom(type = java.lang.Void.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doe it meant we won't support resources here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, according to @pedroigor it's not needed.

import java.util.List;
import java.util.Map;

public class NoSubGroupsGroupRepresentation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate that we need to have another Group representation just without sub-groups. It feels very error prone as changes in the main class could be easily forgot to be ported here. But I guess we don't have many options, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I guess we don't have many options, right?

In other parts of this repository we are generating those things using annotation processors, that would be a cleaner option but will require a little time investment.

// Result is available at: target/test-classes/META-INF/fabric8/examplerealmcrds.keycloak.org-v1.yml
@Group("keycloak.org")
@Version("v1alpha1")
public class ExampleRealmCRD extends CustomResource<ExampleRealmCRDSpec, Void> implements Namespaced {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be part of the final PR. This belongs to the operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the test scope, and guarantees that the model can generate a CRD without throwing exceptions at compile time. It's actually a "compile-time" regression test.


import javax.validation.constraints.NotNull;

public class ExampleRealmCRDSpec {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be part of the final PR. This belongs to the operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I do believe that checking the CRD generation in this module is extremely good for debugging purposes.

@vmuzikar
Copy link
Contributor

@andreaTP One more thing. Could you please create a separate GH Issue for this?

@andreaTP
Copy link
Contributor Author

@vmuzikar ready for next round 👍

Copy link
Contributor

@hmlnarik hmlnarik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR.

I like the idea of generating CRDs from representations. I don't think this approach is valid though for the following reasons:

  • The approach adds new dependencies to keycloak core, meaning that all distributed artifacts (including adapters) would need another set of libraries
  • The approach changes Keycloak representations for the sake of single technology (operator) in a way that is bringing in additional complexity for every other component (REST endpoints, storage).
  • This also affects future storage ability to generate representations automatically, which is one of the future goals of storage work

Can the CRD generation be kept local to the operator module?

@andreaTP
Copy link
Contributor Author

Hi @hmlnarik ! Thanks a lot for sharing your valuable POV!

Let me iterate on your observations:

The approach adds new dependencies to keycloak core, meaning that all distributed artifacts (including adapters) would need another set of libraries

This is not correct, in this PR, the only change of transitive dependencies is the bump of Jackson.
The other two libraries added are marked as provided so that they are needed only at compile time of this module but not included in the transitive dependencies.

The approach changes Keycloak representations for the sake of single technology (operator) in a way that is bringing in additional complexity for every other component (REST endpoints, storage).

All the changes in this PR are strictly NOT affecting the current representation that remains forward and backward compatible. The additions are also not affecting in any sense the usage of the representation in other modules (as demonstrated by the complete source compatibility).
Please note that the underlying reason for those changes is to break recursive data structures solely for the seek of CRD generation (they are not representable in OpenAPI v3).
I would argue that having a model with no recursive data structures is actually a simplification in a good direction (e.g. compatibility with OpenAPI v3) and we might want to tend to it in the future (removing the necessity for the additional annotations and alternative classes).

This also affects future storage ability to generate representations automatically, which is one of the future goals of storage work

I fail to see how, can you please elaborate how adding opt-in annotations for generating a correct CRD is breaking other workflows?

Can the CRD generation be kept local to the operator module?

Only with major hacks/tooling, having the ability to do those kind of changes is the main reason for having the operator in this repository.

Copy link
Contributor

@stianst stianst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core module is used both for the server and the adapters, and can't have these additional dependencies added I'm afraid.

core/pom.xml Outdated Show resolved Hide resolved
core/pom.xml Outdated Show resolved Hide resolved
@andreaTP
Copy link
Contributor Author

@stianst @hmlnarik @vmuzikar
I think this is ready for next round.

Changed the approach to include keycloak-core from sources instead of depending on it, with some Maven juggling.
This imply having to duplicate all the Java source files that need to be "patched", I hope we can revisit this approach in the future.

@andreaTP andreaTP changed the title Enabling CRD generation from RealmRepresentation CRD generation from RealmRepresentation Jan 26, 2022
Copy link
Contributor

@vmuzikar vmuzikar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andreaTP Thanks for the update. Even though it's a nasty workaround, it is good enough for the operator prototype. We for sure need more permanent solution (to "annotate" the fields in a different way) before releasing the operator.

pom.xml Outdated Show resolved Hide resolved
pom.xml Outdated Show resolved Hide resolved
@andreaTP
Copy link
Contributor Author

andreaTP commented Jan 26, 2022

@vmuzikar here you have an alternative approach using sed in a bash script:
https://github.com/andreaTP/keycloak/pull/3/files

there are pro/cons in respect to the current approach ... check out which one is preferred.

@vmuzikar
Copy link
Contributor

@andreaTP +1
The sed approach seems a little bit cleaner to me. More than good enough for the prototype.

Patching keycloak-core with sed
Copy link
Contributor

@vmuzikar vmuzikar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andreaTP Changes LGTM now. But I'm not able to test them. Running mvn package as usually doesn't generate the new CRD. Am I doing something wrong?

@andreaTP
Copy link
Contributor Author

@vmuzikar running from the top folder of the repo:

mvn clean compile -f operator/pom.xml

generates the CRDs in e.g. operator/target/classes/META-INF/fabric8/realms.keycloak.org-v1.yml, the Realm CRD is not copied to the kubernetes folder since it doesn't have an associated Controller (just yet) reference.

@stianst stianst merged commit 24d6f75 into keycloak:main Jan 27, 2022
dgozalo pushed a commit to dgozalo/keycloak that referenced this pull request Jan 31, 2022
Enabling CRD generation from RealmRepresentation

Closes keycloak#9759
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generate the CRD from RealmRepresentation
5 participants