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

Question: Primary to DR many-to-one & many-to-many relationships possible? #2159

Closed
Huldula opened this issue Dec 13, 2023 · 12 comments · Fixed by #2161
Closed

Question: Primary to DR many-to-one & many-to-many relationships possible? #2159

Huldula opened this issue Dec 13, 2023 · 12 comments · Fixed by #2161

Comments

@Huldula
Copy link

Huldula commented Dec 13, 2023

I have a usecase, where I need to create, update and delete Resources, depending on multiple primary resources.
Here is a little example:
My primary custom resource is UserGroup. Let's say I have 2 of those:

apiVersion: example
kind: UserGroup
metadata:
  name: read-group
spec:
  permissions:
    - "Read"
apiVersion: example
kind: UserGroup
metadata:
  name: write-group
spec:
  permissions:
    - "Write"

From this I want to generate User custom resources. If a User in both the read-group and the write-group, he should get both permissions:

apiVersion: example
kind: User
metadata:
  name: alice
spec:
  permissions:
    - "Read"
    - "Write"

Changes like updates and deletion on the UserGroup should also trigger updates on the User

I wanted to avoid using the KubernetesClient directly because just specifying a simple desired state like with AbstractDependentResource::desired seems to be less complicated.
Is something like this possible in java-operator-sdk?

@csviri
Copy link
Collaborator

csviri commented Dec 13, 2023

Hi, pls check:

https://javaoperatorsdk.io/docs/features#managing-relation-between-primary-and-secondary-resources

There are samples how to do many-to-many relations, if you want to access those with getSecondaryResources(...)

There are however cases when this isn’t sufficient and you need to provide an explicit mapping between a primary resource and its associated secondary resources using an implementation of the PrimaryToSecondaryMapper interface. This is typically needed when there are many-to-one or many-to-many relationships between primary and secondary resources, e.g. when the primary resource is referencing secondary resources. See [PrimaryToSecondaryIT](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/PrimaryToSecondaryIT.java) integration test for a sample.

@Huldula
Copy link
Author

Huldula commented Dec 13, 2023

Thank you for your quick answer!

Do I understand this correctly:
many-to-many relationships are possible with DRs, but only if they are read only see the comment
If I want to update my secondary resource I cannot use DRs and must create/update/delete them using the KubernetesClient?

@csviri
Copy link
Collaborator

csviri commented Dec 13, 2023

In short no, you can update the resource. This sample show to use is as read only, what we saw in practice usually,. Thus there is a ConfigMap that serves as input for multiple custom resources (share some paramters). But it is possible to update it normally, that should work. But then multiple resources might compete for that.

In your case the read-group and write-group probably won't be modified by the UserController neither. (Or whatever controller that creates the user)

@Huldula
Copy link
Author

Huldula commented Dec 14, 2023

I did some testing and it actually works, thank you for your help! There is still one problem left though: The reconcile method is only called for one UserGroup, not all of them. Because of this only this "primary" UserGroup can update its status. Is there any way to solve this issue?

@csviri
Copy link
Collaborator

csviri commented Dec 14, 2023

Glad to hear it works!

Because auf this only this "primary" UserGroup can update its status. Is there any way to solve this issue?

How is the User associated with the UserGroup?

@Huldula
Copy link
Author

Huldula commented Dec 14, 2023

User is the DR, UserGroup the primary resource

@csviri
Copy link
Collaborator

csviri commented Dec 14, 2023

Hmm, but where alice value comes from then?

That is a bit tricky situation, it should be the case that User have 2 owner references, for each UserGroup. Can you check if this is the case?

@Huldula
Copy link
Author

Huldula commented Dec 14, 2023

alice comes from a 3rd party source, but that shouldn't relevant

Yes User has 2 owner references due to my kotlin code here (desiredResources in my UserDR extends BulkDependentResource:

user.metadata.ownerReferences = groups.map { group ->
                OwnerReferenceBuilder()
                    .withUid(group.metadata.uid)
                    .withApiVersion(group.apiVersion)
                    .withName(group.metadata.name)
                    .withKind(group.kind)
                    .build()
            }

@csviri
Copy link
Collaborator

csviri commented Dec 14, 2023

Ok, thx, it seems this could be improved:
See:
https://github.com/java-operator-sdk/java-operator-sdk/blob/f00dd5ec36d5afb87de65f4d5713b482010f7f5f/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java#L56-L56

Currently only the first owner reference is taken into account.
Will fix this in the core so it will be more generic.

What you can do is to fix it in your code is to implement SecondaryToPrimaryMapper by the dependent resource, and create resource id for all owner referneces.

see also:
https://github.com/java-operator-sdk/java-operator-sdk/blob/f00dd5ec36d5afb87de65f4d5713b482010f7f5f/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L87-L87

@csviri
Copy link
Collaborator

csviri commented Dec 14, 2023

Just some rational why was not like this for now:

The owner references does not have always the same type, thus your use case. And the target type is not available when the mapper is created. But IMHO is reasonable to have this behavior as default. And if does not fit ones use case still can be changed as show above.

@csviri csviri linked a pull request Dec 14, 2023 that will close this issue
@Huldula
Copy link
Author

Huldula commented Dec 14, 2023

Thanks a lot, it works now!
I didn't know I could also implement the SecondaryToPrimaryMapper in the DR.
Also thank you for implementing this default behaviour right away, I'm looking forward to using it.

@Huldula Huldula closed this as completed Dec 14, 2023
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 a pull request may close this issue.

2 participants