GithubHelp home page GithubHelp logo

Comments (10)

mikebryant avatar mikebryant commented on September 24, 2024

A possible implementation might be that the sync hook can return an additional field of "related" (better name?) that indicates objects it's interested in. This might be explicit objects, or label selectors / types. Then metacontroller can call the sync hook again, with the additional information included, to allow the hook to make the right decision.

An interesting consideration is that if metacontroller restarts, and thus forgets about which additional objects are required, the sync hook may be unable to return an appropriate response (i.e. it may now now know if some of the objects it's being told about it owns are needed or not). As it's recommended that the sync hook doesn't simply copy in existing objects verbatim, but only specifies the fields it cares about, this may be problematic. A possible solution is that the hook returns status code 510, which seems to match up. In such a case metacontroller should ignore the returned status and children fields and retry with the requested information.

from metacontroller.

mikebryant avatar mikebryant commented on September 24, 2024

Alternatively it might be better to focus on writing MutatingAdmissionWebhooks to add additional fields into certain objects based on our environment. I'm not sure which would be a more sensible approach.

(Certainly we're going to have to go with MutatingAdmissionWebhooks for say, adding a site: blah label to all of our Prometheus objects, for instance. The question is more whether we can make our own resources easier to use in that regard)

from metacontroller.

danisla avatar danisla commented on September 24, 2024

I am also interested in this behavior. My example is a CompositeController that generates a child Pod with values from an existing ConfigMap that it doesn't own. I would want to use the data from the ConfigMap as part of the pod definition and I want to update the pod if the ConfigMap contents change.

I've been working around this today by calling the k8s API from my webhook to fetch and sync the related objects. This doesn't scale though as one of the advantages of metacontroller is that it brokers requests to the apiserver...

One idea would be to have a related field in the CompositeController spec that is a list of object selectors. The sync request could then include those selected objects so they can be used in the webhook. This might not be the best solution as you may not know what the related object selectors are at the time you define the CompositeController.

Another idea that I'm playing with is using a DecoratorController as a child of a CompositeController. The decorator controller would select the related objects used by the CompositeController resource and communicate them to the webhook through a shared cache like Redis. This would at least prevent additional calls to the apiserver from the webhook, but it adds some complexity.

from metacontroller.

danisla avatar danisla commented on September 24, 2024

I was thinking about this a little more and it might be possible to enhance metacontroller to provide the related objects in the CompositeController webhook sync request using a sidecar CRD, similar to how the BackendConfig resource for the Google Cloud Load Balancer works.

For example, you could claim a child object in your controller that instructs the metacontroller on the related objects you are interested in:

apiVersion: metacontroller.k8s.io/v1alpha1
kind: RelatedObjects
metadata:
  name: my-objects
spec:
  resources:
  - apiVersion: v1
    resource: pods
    annotationSelector:
      matchExpressions:
      - {key: pod-name-label, operator: Exists}

The owner reference would then be set to the parent object by metacontroller because it's a child resource. Metacontroller could then configure the informers and caches to observe and include the complete objects for the selected resources in the parent webhook sync request.

from metacontroller.

enisoc avatar enisoc commented on September 24, 2024

@mikebryant wrote:

The desired outcome would be that a CompositeController can indicate in some fashion that it's interested in the state of some related objects, and be called whenever those change as well.

This sounds similar to the "Friend Resources" alternative described in a proposal I wrote about another pattern for handling "related resources":

https://metacontroller.app/design/map-controller/#friend-resources

I ended up not exploring friend resources further, but if it fits your use case better we can always reconsider modifications to address the downsides listed in the proposal. Please take a look at the other thoughts in that proposal and let me know if anything resonates with you.

@danisla wrote:

My example is a CompositeController that generates a child Pod with values from an existing ConfigMap that it doesn't own. I would want to use the data from the ConfigMap as part of the pod definition and I want to update the pod if the ConfigMap contents change.

If there's a 1:1 correspondence between ConfigMap -> Pod, then I think you can do this with the proposed MapController pattern. Can you take a look at that and let me know if you agree?

For example, you could claim a child object in your controller that instructs the metacontroller on the related objects you are interested in [...] Metacontroller could then configure the informers and caches to observe and include the complete objects for the selected resources in the parent webhook sync request.

This would mean that the set of resources you watch could change from one sync to the next. Is that really a requirement for the use case? We could certainly support that, but it would be a significant added layer of complexity. Is there a reason you couldn't know what resources you need at the time of writing the CompositeController spec?

from metacontroller.

danisla avatar danisla commented on September 24, 2024

If there's a 1:1 correspondence between ConfigMap -> Pod, then I think you can do this with the proposed MapController pattern. Can you take a look at that and let me know if you agree?

In my case it could be a many-to-one relationship. My composite controller may need to know about the content of multiple ConfigMaps and Secrets before it can generate the child Pod. It sounds like MapController would operate on a single input non-owned resource.

Is there a reason you couldn't know what resources you need at the time of writing the CompositeController spec?

I could define some convention in my CompositeController spec that would dictate a set of annotations or labels for related resources but then every instance of the parent would receive every matching object. In my case, users would be providing say a list of specific ConfigMap selectors for that particular instance of a parent, which is why I don't necessarily know exactly what related objects I want at the time I create the CompositeController spec.

from metacontroller.

mikebryant avatar mikebryant commented on September 24, 2024

I've been running into this more when trying to design an operator for PagerDuty.

I want to have a resource PagerDutyAccount, which has a secretRef to where the account key is held.

And then several other types that all have a pagerDutyAccountRef, which the operator can use to contact the API. At the moment this is problematic, as the hook doesn't send the related object, or notify on changes etc.

from metacontroller.

enisoc avatar enisoc commented on September 24, 2024

@mikebryant wrote:

A possible implementation might be that the sync hook can return an additional field of "related" (better name?) that indicates objects it's interested in. This might be explicit objects, or label selectors / types. Then metacontroller can call the sync hook again, with the additional information included, to allow the hook to make the right decision.

After thinking about this some more, I'm coming around to this idea.

An interesting consideration is that if metacontroller restarts, and thus forgets about which additional objects are required, the sync hook may be unable to return an appropriate response (i.e. it may now now know if some of the objects it's being told about it owns are needed or not).

I'm thinking this can be avoided if we split the new question ("which related objects do you need?") into its own hook, which we would call prior to sync. That would mean an extra round trip, but the actual number of such extra calls could be much lower than the number of sync calls if we restrict you to only deciding which objects you need based on the parent spec. That is, you can't change your answer based on the states of children, nor on the states of objects you previously specified were related.

In concrete terms, the related hook will send you only the parent spec (no children, no related objects), and it will only get called again if the parent spec changes. In most cases, I'd expect the majority of sync calls to be triggered by changes in the child objects; the number of syncs triggered by changes to the parent is usually much lower.

This keeps the sync request/response contract clean: we'll send you everything you need, and you should always return a real desired state (as opposed to a special error code that means some parts of the response are valid but not others).

from metacontroller.

mikebryant avatar mikebryant commented on September 24, 2024

Having a separate hook would be fine. All the use-cases I'm imagining depend only on the .spec

from metacontroller.

AmitKumarDas avatar AmitKumarDas commented on September 24, 2024

FYI. I have tried to implement this as GenericController in a forked version of MetaController. This is a completely new meta controller on the lines of existing Composite & Decorator controllers.

refer - https://github.com/AmitKumarDas/metac/
api - https://github.com/AmitKumarDas/metac/blob/master/apis/metacontroller/v1alpha1/types_generic.go

from metacontroller.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.