Skip to content

Native Image Friendly #231

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

Merged
merged 34 commits into from
Nov 26, 2020

Conversation

s-soroosh
Copy link
Contributor

@s-soroosh s-soroosh commented Nov 19, 2020

@kirek007 Here is the PoC.
You should be able to run the https://github.com/java-operator-sdk/basic-native-operator-example/tree/init with this version of the SDK with no need to define neither the donable class nor the custom resource class in @controller annotation.

closes #224

@kirek007
Copy link
Contributor

@psycho-ir thanks! Change looks nice, I'll test it and merge if possible, even today :)

@kirek007
Copy link
Contributor

kirek007 commented Nov 20, 2020

@psycho-ir I've tested and it works like a harm. I've added integration test to the example so we can be sure that application is starting and at least it's possible to create CRD and CR.
I've also notice that CustomResourceList class was need to used mixedoperations api so I've added generation of this class, but I'm not that familiar with this API and it would be great to hear what you, @adam-sandor and @csviri things about it.
I was not able to push to your repository so my changes are here: https://github.com/java-operator-sdk/java-operator-sdk/compare/annotation-processor-test

@s-soroosh
Copy link
Contributor Author

Thanks for the feedback @kirek007, if we decide that we want to go in this direction I'll make the code simpler and test a few cases that I think fails with the current implementation.
This project can be used to make the code simpler
https://github.com/square/javapoet
and this one to test the compilation:
https://github.com/google/compile-testing

@kirek007
Copy link
Contributor

This code will be removed as soon as kubernetes-client v5 will reach stable release (There is already MR with implementation #229) , at least for Doneable class. I still don't know if we should generate List class or leave it to the developer. I will check that.

Personally I like that with this code we can start building native operators right now! I believe that it's worth investing to make it happen.

I'd like to hear from @adam-sandor and @csviri what they thinks about it.

@kirek007
Copy link
Contributor

This project can be used to make the code simpler
https://github.com/square/javapoet
and this one to test the compilation:
https://github.com/google/compile-testing

Yup, sounds reasonable to use them.

@csviri
Copy link
Collaborator

csviri commented Nov 20, 2020

@kirek007 @psycho-ir We don't have to generate the list class, we can use the base class as it is now.

@kirek007
Copy link
Contributor

@kirek007 @psycho-ir We don't have to generate the list class, we can use the base class as it is now.

Makes sense because then it's up to developer if he want's to cast List results to custom object or implement List class to have clear API.

Ok, so this code will be removed when stable kubernetes-client 5.0 for quarkus will be available.
@psycho-ir you can ignore my changes then

@s-soroosh
Copy link
Contributor Author

@kirek007 @csviri OK, so I'll continue to work on this PR if to address #224 and #166 if there is no objection.

@metacosm
Copy link
Collaborator

Note that we're planning more improvements on the Custom Resource handling in the k8s client. See fabric8io/kubernetes-client#2611, ideas are welcome.

@s-soroosh s-soroosh changed the title [WIP] Native Image Friendly Native Image Friendly Nov 21, 2020
@s-soroosh
Copy link
Contributor Author

The PR is ready for review.
I added 2 tests for an annotation processor to ensure it can handle cases the class implement more than 1 interfaces or there is an intermediary class.

} catch (CannotCompileException | NotFoundException e) {
throw new IllegalStateException(e);
final Class<T> customResourceClass = getCustomResourceClass(controller);
return (Class<? extends CustomResourceDoneable<T>>) Class.forName(customResourceClass.getCanonicalName() + "Doneable");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Will this work if the CR class is an inner class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it does work, haven't tested that with native-images yet though.
@kirek007 do you think we can have an integration test in example repository where has the CustomResource as inner class?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I'll add this test

Copy link
Contributor

Choose a reason for hiding this comment

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

After while, I believe that we should test it here, not in example. We would like to introduce native build as a main feature of the SDK.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could add native build as a test step in next PR.
WDYT: @adam-sandor @csviri ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After while, I believe that we should test it here, not in example. We would like to introduce native build as a main feature of the SDK.

True, would be great to have it as one of the examples in this repository, will be easier to find for the users and also can be used as regression tests for future changes in the framework.

@kirek007
Copy link
Contributor

Code looks good to me, If @csviri and @adam-sandor doesn't have anything to add I would suggest merging it.

@kirek007 kirek007 self-assigned this Nov 24, 2020
@@ -37,7 +36,8 @@ static boolean getGenerationEventProcessing(ResourceController controller) {
}

static <R extends CustomResource> Class<R> getCustomResourceClass(ResourceController<R> controller) {
return (Class<R>) getAnnotation(controller).customResourceClass();
final Class<R> type = Arrays.stream(controller.getClass().getGenericInterfaces()).filter(i -> i instanceof ParameterizedType).map(i -> (ParameterizedTypeImpl) i).findFirst().map(i -> (Class<R>) i.getActualTypeArguments()[0]).get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

In the future we plan to have a hierarchy of controllers, so extend from an abstract controller. Thus this should be aware of inheritance. I think its not trivial to cover all possible scenarios, that was the reason it was explicit in the annotation. Are you sure this will handle all the cases?
@psycho-ir

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 a very good point, the simplest solution would be searching for the interface we are interested in recursively, but that won't work with native-images as it's impossible to guarantee that reflection is enabled for the entire hierarchy.

I changed the annotation processor implementation to generate a file with a mapping of controller class names to custom resource names and used it here to get the class in one shot.

Changes are already committed, would be great if you could review it. Needs a little bit refactoring & cleanup though that I'll do tomorrow.


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@RegisterForReflection
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this the only reason we have quarkus on classpath? Would be cleaner if we could do it without it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So if somebody wan't to use quarkus, it can be added to the project. But if not its an unnecessary dependency on classpath.
However if there is no other way to do this, then we can let it here, since quarkus is a priority.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, good point.
We can create project that will act like "springboot-starter" for quarkus. It will take of usign supported quarkus version and configuration of reflections.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep, I'm planning on doing that with #228.

Copy link
Contributor

@kirek007 kirek007 Nov 25, 2020

Choose a reason for hiding this comment

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

So my suggestion is to:

  1. Remove quarkus from this PR
  2. Because WIP: feat: make it possible to externally configure the operator #228 is getting quite big let's open new PR dedicated only for implementing quarkus starter
    If @metacosm don't mind I can take care of this

Copy link
Collaborator

Choose a reason for hiding this comment

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

That said, I'm not sure that native compilation will work properly without using RegisterForReflection… I also think we should merge #229 as soon as possible because that will simplify a lot of things by removing the need to deal with Doneable classes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@kirek007 another aspect is also that #228 tries to extract the configuration parts from the Spring Boot starter so that it could be reused in a Quarkus extension instead of duplicating the code so I really think that it should get done sooner rather than later. That said, I'm not quite satisfied with how it currently is, in terms of configuration I mean.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can remove the Quarkus dependency from here, the other way to achieve the same is generating a ReflectionConfigurationFile in compile time (just like what Quarkus is doing with the annotations). Can be done in the new module that will be added.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That would be great @psycho-ir

</plugin>
</plugins>
</build>
<profiles>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't that be removed now that we only target Java 11+?

Copy link
Contributor

@kirek007 kirek007 Nov 26, 2020

Choose a reason for hiding this comment

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

@psycho-ir, this should be removed, because we support only 11+ (it's already in master)

@metacosm
Copy link
Collaborator

Any idea of when this will be merged, @psycho-ir @csviri ?

Copy link
Contributor

@kirek007 kirek007 left a comment

Choose a reason for hiding this comment

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

Please remove all quarkus dependencies and then I'll be able to test it and merge finally.

</plugin>
</plugins>
</build>
<profiles>
Copy link
Contributor

@kirek007 kirek007 Nov 26, 2020

Choose a reason for hiding this comment

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

@psycho-ir, this should be removed, because we support only 11+ (it's already in master)

<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
<groupId>io.quarkus</groupId>
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove quarkus dependency, we'll add it in dedicated module


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@RegisterForReflection
Copy link
Contributor

Choose a reason for hiding this comment

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

This is related to quarkus dependency and should be removed



final TypeSpec typeSpec = TypeSpec.classBuilder(doneableClassName)
.addAnnotation(RegisterForReflection.class)
Copy link
Contributor

Choose a reason for hiding this comment

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

This annotation won't compile after removing quarkus-core

import io.fabric8.kubernetes.client.CustomResourceDoneable;
import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection
Copy link
Contributor

Choose a reason for hiding this comment

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

Won't compile after removing quarkus-core

@kirek007
Copy link
Contributor

Any idea of when this will be merged, @psycho-ir @csviri ?

As soon as all request changes will be resolved :)

@s-soroosh
Copy link
Contributor Author

I removed quarks dependency, practically means this changeset wouldn't be adequate to support Quarkus native builds.
There will be a new project to support Quarkus builds just like the spring boot starter that javaoperatorsdk already has.

@csviri
Copy link
Collaborator

csviri commented Nov 26, 2020

@psycho-ir You mean, there will be new maven module within this PR? Or you intend to do that a separate PR?

@kirek007
Copy link
Contributor

@psycho-ir You mean, there will be new maven module within this PR? Or you intend to do that a separate PR?

If you don't mind I would like to merge this one, and move quarkus work to separate branch

Copy link
Collaborator

@csviri csviri left a comment

Choose a reason for hiding this comment

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

@psycho-ir You mean, there will be new maven module within this PR? Or you intend to do that a separate PR?

If you don't mind I would like to merge this one, and move quarkus work to separate branch

Sure I'm fine with that.


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@RegisterForReflection
Copy link
Collaborator

Choose a reason for hiding this comment

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

So if somebody wan't to use quarkus, it can be added to the project. But if not its an unnecessary dependency on classpath.
However if there is no other way to do this, then we can let it here, since quarkus is a priority.

<profile>
<id>java8</id>
<activation>
<jdk>1.8</jdk>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this still valid? I guess this needs to be java 11


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@RegisterForReflection
Copy link
Collaborator

Choose a reason for hiding this comment

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

That would be great @psycho-ir

@s-soroosh
Copy link
Contributor Author

@psycho-ir You mean, there will be new maven module within this PR? Or you intend to do that a separate PR?

@csviri @kirek007 Sorry I wasn't clear, yes I meant a new module will be needed but not in the scope of this PR.
Feel free to merge the current changeset.

@s-soroosh
Copy link
Contributor Author

@csviri

So if somebody wan't to use quarkus, it can be added to the project. But if not its an unnecessary dependency on classpath.
However if there is no other way to do this, then we can let it here, since quarkus is a priority.

Keeping the annotation for sure makes the integration with Quarkus way simpler.
Without it, I can think of adding another annotation processor that will make reflection-config.json files.

Copy link
Collaborator

@csviri csviri left a comment

Choose a reason for hiding this comment

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

LGTM

@csviri csviri merged commit f0317c9 into operator-framework:master Nov 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove customResourceClass from @Controller
4 participants