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

fix 3922: refining the behavior of adapt and isAdaptable #3955

Merged
merged 4 commits into from
Mar 22, 2022

Conversation

shawkins
Copy link
Contributor

@shawkins shawkins commented Mar 9, 2022

Description

The idea here is to consolidate all checking logic on the apigroups/apiresources methods that was added over the last few releases.

To this end isAdaptable and supportsApiPath have been deprecated. supports replaces isAdaptable and accepts either a Client or a KubernetesResource. When using a resource it reuses the same Handler logic that can consult the api server. All other extension checks have been consolidated to hasApiGroup that can check for a single apiGroup, or matching any apiGroup. The mock logic can override calls to hasApiGroup and supports and disable whatever is desired.

In subsequent releases we may deprecate asking about Client supports entirely - and instead have a targeted check just for openshift.

adapt will perform no check of support, it will simply change the class if needed/possible. If it seems like an undersirable breaking change we can introduce a new method for this purpose and still have adapt call isAdaptable/supports

How this looks:

@EnableKubernetesMockClient() // all extensions are supported, any calls to isAdaptable or supports return true.

@EnableKubernetesMockClient(unsupported = "openshift.io") // everything but the openshift extension will be supported.

Unsupported entries can use a * wildcard, or can be made specific to a single apiGroup/version.

I've stripped out a lot of the stuff from ExtensionAdapters to the point where most of them could be replaced by just a reference to the client class - except we don't support a do-nothing no arg constructor on clients. We could of course deprecate all of the direct usage of any client (built-in or extension) constructor.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change
  • Chore (non-breaking change which doesn't affect codebase;
    test, version modification, documentation, etc.)

Checklist

  • Code contributed by me aligns with current project license: Apache 2.0
  • I Added CHANGELOG entry regarding this change
  • I have implemented unit tests to cover my changes
  • I have added/updated the javadocs and other documentation accordingly
  • No new bugs, code smells, etc. in SonarCloud report
  • I tested my code in Kubernetes
  • I tested my code in OpenShift

changes the mock annotation to use exclusion patterns

assumes that we can change the behavior of adapt to skip checks
@shawkins
Copy link
Contributor Author

I think we probably need to make a few more refinements.

Before, and after this change, if you did something like isAdaptable(V1alpha1APIGroupClient.class) - it will always return true regardless of whether Tekton is installed. I put in the javadocs that you shouldn't use the supports call with Clients, but instead with KubernetesResources. It may make more sense to just separately have a supportsClient as a replacement for isAdaptable and have supports be on be only for KubernetesResources. Then change the exetensionadapter.isSupported to not just be a boolean, but to return something like unknown by default so that we can differentiate what is actually checking for support.

@shawkins
Copy link
Contributor Author

This next commit takes away the isSupported responsibility from ExtensionAdapters - since it wasn't really being used as intended. What I'm looking for moving forward is that users will mostly call supports or hasApiGroup to determine what is supported.

This makes ExtensionAdapters almost unnecessary - if we deprecate all no-arg client constructors, then eventually you could service load the clients directly (along with the ExtensibleResourceAdapters of which there are only a handful currently).

@sonarcloud
Copy link

sonarcloud bot commented Mar 12, 2022

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 16 Code Smells

38.1% 38.1% Coverage
5.4% 5.4% Duplication

@shawkins shawkins mentioned this pull request Mar 14, 2022
11 tasks
Comment on lines +134 to +142
public <C extends Client> Boolean isAdaptable(Class<C> type) {
// if type is an instanceof SupportTestingClient, then it's a proper
// test, otherwise it could be legacy support on an extension client
C toTest = adapt(type);
if (toTest instanceof SupportTestingClient) {
return ((SupportTestingClient) toTest).isSupported();
}
return true;
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused. My assumption was that isAdatpable in v6.0 would return true as long as a specific client implementation for that client class exists:

For example:

  • false if openshift-client-api dependency is present, openshift-client isn't and method is invoked with client.isAdaptable(OpenShiftClient.class)

However, here I'm unsure if we are also checking isSupported once the client is adapted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

adapt will no longer perform any checks - previously at least for the OpenShift it did, which caused problems in mock scenarios.

isAdaptable I'm proposing to deprecate, but leave functionally the same - for select extensions it will call isSupported, which will do a check of the apigroups (which used to be done against the rootapis).

5.x style:

if (client.isAdaptable(OpenShiftClient.class)) {
  client.adapt(OpenShiftClient.class);
  ...
}

That will still function the same with these changes.

6.x style:

OpenShiftClient osclient = client.adapt(OpenShiftClient.class);
if (osclient.isSupported()) {
  
}

Beyond that you are supposed to use:

client.supports(SomeResource.class); 

To determine down to a type level what is supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To determine down to a type level what is supported.

I should point out that we are effectively caching the results of those calls when the type is supported, because it backs into the same logic as client.resources(SomeResource.class) - and we never timeout those entries.

Copy link
Member

Choose a reason for hiding this comment

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

I should point out that we are effectively caching the results of those calls when the type is supported, because it backs into the same logic as client.resources(SomeResource.class) - and we never timeout those entries.

Yes, I saw that.

My question was more regarding a newer behavior for the isAdaptable method. So in the case I'm pointing out, what will be the result (I adapt to a non-existing client implementation ---> client.adapt(OpenShiftClient.class)

Copy link
Contributor Author

@shawkins shawkins Mar 22, 2022

Choose a reason for hiding this comment

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

If you have the api dependency, but not the client dependency for the OpenShiftClient, both a call to adapt and isAdaptable will now throw an illegalargumentexception. That is new situation - as before there was only a single dependency.

Beyond this, with more work beyond #3966 it's possible that we can merge the openshift api and client back together as it could be written to just depend upon the client.

@shawkins
Copy link
Contributor Author

One more thought on this pr. The XXXMockServer classes are still using their default logic to create clients - this will not construct a client with the overrides on the support checks, so they will not support isAdaptable calls - but that is not necessary because the test will already be referencing the client of the expected type.

*
* @return the list of unsupported patterns
*/
String[] unsupported() default {};
Copy link
Member

Choose a reason for hiding this comment

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

Do you have any use-case in mind for this?

@manusa manusa added this to the 6.0.0 milestone Mar 22, 2022
@manusa manusa merged commit bb6115a into fabric8io:master Mar 22, 2022
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.

None yet

2 participants