Skip to content

Subscription Controller basics.#437

Merged
knative-prow-robot merged 11 commits into
knative:masterfrom
vaikas:subscription-controller
Sep 24, 2018
Merged

Subscription Controller basics.#437
knative-prow-robot merged 11 commits into
knative:masterfrom
vaikas:subscription-controller

Conversation

@vaikas
Copy link
Copy Markdown
Contributor

@vaikas vaikas commented Sep 19, 2018

Fixes #438

Proposed Changes

Add the barebones for getting a Subscription Controller wiring things into source channels, and call / sinkables using the duck types.

Release Note

@knative-prow-robot knative-prow-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Sep 19, 2018
@knative-prow-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: vaikas-google

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow-robot knative-prow-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 19, 2018
@evankanderson
Copy link
Copy Markdown
Member

/assign @neosab , who was also interested in this.

@vaikas-google, I don't know if there is a way that we could split this work or collaborate with @neosab ?

// target.
// +optional
Result *ResultStrategy `json:"result,omitempty"`
Sinkable string `json:"sinkable"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought the dispatcher acts upon the channel's resolved subscriptions to determine the target DNS [1] to send an event and optionally handle replies depending on whether the target was a Callable. With this change to a single Sinkable, I am failing to understand how the reply logic will be handled by the dispatcher?

[1]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's exactly right. But this is really for connecting Subscriptions together, well, really Sources to Channels. Say I have the following:
Source -> Call -> Result
Result is really a channel and if another subscription wants to connect to that channel, the model will look more like this:
Source -> Call -> Result (Now becomes a Source2) -> Call -> Result2
But, we need to be able to support multiple subscriptions to the channel, so it really looks more like this:
Source -> Call -> Result -> SourceChannel -> Call -> Result2
-> SourceChannel2 -> Call -> Result3

In this model, the "Result" Channel will only get SInkable, since they represent "input (or Source)" channels fronting Subscriptions and will allow for Fanout. We do not want the Dispatcher to be handling failures in fanouts.

Does that make more sense?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added both entries back there, but in the form of a fully resolved string. I still don't think that Channel should be in the business of resolving refs, etc. but I understand why we probably need both of them here from control plane side of things. I've added that to the pkg/apis repo.

Comment thread pkg/apis/eventing/v1alpha1/channel_types.go Outdated
Comment thread pkg/apis/eventing/v1alpha1/channel_types.go Outdated

// ChannelSubscriberSpec defines a single subscriber to a Channel. At least one
// of Call or Result must be present.
// ChannelSubscriberSpec defines a single subscriber to a Channel.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should add:

var _ = duck.VerifyType(&Channel{}, &duckv1alpha1.Channelable{})

For all implemented interfaces.

@vaikas vaikas force-pushed the subscription-controller branch from a194864 to 48774f4 Compare September 20, 2018 10:34
@vaikas
Copy link
Copy Markdown
Contributor Author

vaikas commented Sep 20, 2018

@neosab I'd like to get enough in so that we can then keep working in parallel in smaller chunks.

@neosab
Copy link
Copy Markdown
Contributor

neosab commented Sep 20, 2018

@neosab I'd like to get enough in so that we can then keep working in parallel in smaller chunks.

@vaikas-google 👍 Sounds good.

return apis.ErrMissingField("call", "result").ViaField(fmt.Sprintf("subscriber[%d]", i))
if cs.Channelable != nil {
for i, subscriber := range cs.Channelable.Subscribers {
if subscriber.SinkableDomain == "" {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should error if both CallableDomain and SinkableDomain are empty

for i, subscriber := range cs.Channelable.Subscribers {
if subscriber.SinkableDomain == "" && subscriber.CallableDomain == "" {
fe := apis.ErrMissingField("sinkableDomain", "callableDomain")
fe.Details = "expected at least one of, got none"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

cc @n3wscott I think there's a helper for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I couldn't find. I thought I found it but the name was a bit misleading (IMHO). I created one but didn't want to block this on it and instead would prefer to clean it up later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about this:

apis.ErrMissingField("sinkableDomain", "callableDomain").ViaField(fmt.Sprintf("subscribers[%d]", i))

Copy link
Copy Markdown
Contributor

@n3wscott n3wscott Sep 24, 2018

Choose a reason for hiding this comment

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

There is no helper for adding details to a Err* type method, there is a helper for setting the index.

it should be:

errs = errs.Also(apis.ErrMissingField("sinkableDomain", "callableDomain").ViaFieldIndex("subscribers", i))

Copy link
Copy Markdown
Contributor

@grantr grantr left a comment

Choose a reason for hiding this comment

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

/lgtm

Couple minor issues, but I'm 👍 to get this in to unblock experiments. Thanks @vaikas-google! The dynamic client stuff seems elegant to me.

for i, subscriber := range cs.Channelable.Subscribers {
if subscriber.SinkableDomain == "" && subscriber.CallableDomain == "" {
fe := apis.ErrMissingField("sinkableDomain", "callableDomain")
fe.Details = "expected at least one of, got none"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about this:

apis.ErrMissingField("sinkableDomain", "callableDomain").ViaField(fmt.Sprintf("subscribers[%d]", i))


// Subscription might be Subscribable. This depends if there's a Result channel
// In that case, this points to that resource.
Subscribable duckv1alpha1.Subscribable `json:"subscribable,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIUC, if a Subscription has a Result Channel, then chained Subscriptions are allowed. It would be possible to create another Subscription that looks like this:

from:
  ref:
    kind: Subscription
    name: some-sub
  call:
    // ...
  result:
    // ...

Is this the intent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

YES! :) That's exactly right.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

YES! That's exactly right, and only if a Subscription has a Result. Just need to fill the status up for that and Result.Status would then point to the resolved ResultChannel

}

const (
// SubscriptionConditionReady has status True when all subcondtions below have been set to True.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nonblocking typo nit: subconditions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

doen


// SubscriptionConditionFromReady has status True when controller has successfully added a subscription to From
// resource.
SubscriptionConditionFromReady duckv1alpha1.ConditionType = "Subscribed"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is the name of this FromReady internally but Subscribed externally?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

haha, when I was writing code it seemed like a better name. Forgot to change here, will do...

// converge the two. It then updates the Status block of the Subscription resource
// with the current status of the resource.
func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
glog.Infof("Reconciling subscription %v", request)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It can be a future PR, but this should probably use zap.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ack. Let's do in a followup so others can start experimenting / partying on this code as well :)

return nil
}

func (r *reconciler) CreateResourceInterface(namespace string, ref *corev1.ObjectReference) (dynamic.ResourceInterface, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure if this is useful, or even how it works, but controller-runtime just gained the ability to work with unstructured objects: kubernetes-sigs/controller-runtime#101

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Awesome! Let's investigate on a followup pr, ok?

// Add our subscription to the object
after := c.DeepCopyObject().(*duckv1alpha1.Channel)
after.Spec.Channelable = &duckv1alpha1.Channelable{
Subscribers: []duckv1alpha1.ChannelSubscriberSpec{{CallableDomain: "foobar"}},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this should probably use the given callableDomain and resultDomain

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

haha, yes :) Didn't get a push out before I had to go get to the plane and I lost wifi.

return resourceClient.Get(ref.Name, metav1.GetOptions{})
}

func (r *reconciler) reconcileFromChannel(namespace string, subscribable corev1.ObjectReference, callDomain string, resultDomain string, deleted bool) error {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How is deleted used in this method? Will that be a future enhancement?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, added todo.

return jsonpatch.CreatePatch(rawBefore, rawAfter)
}

const (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think all of these constants could be deleted - they don't seem to be used anywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

duckv1alpha1.AddToScheme(scheme.Scheme)
}

var injectDomainInternalMocks = controllertesting.Mocks{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @adamharwayne for writing the mock client for this!

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 21, 2018
@knative-prow-robot knative-prow-robot removed the lgtm Indicates that a PR is ready to be merged. label Sep 22, 2018
@vaikas
Copy link
Copy Markdown
Contributor Author

vaikas commented Sep 22, 2018

Thanks, sorry for the duplicate comments, sometimes I make a comment, then they seem to disappear just to come back. Hopefully the dupes don't contradict each other at least.
Things work on a real cluster, but the json patch is not working against the fake dynamic client in unit tests so I'll try to keep working on that some more, but if I can't figure it out, perhaps that can be picked up by somebody else so we can get experimentation and other things like channel controllers getting ramped up, provisioners and so forth with this moving forward.

@vaikas vaikas changed the title WIP: Subscription Controller Subscription Controller basics. Sep 22, 2018
@knative-prow-robot knative-prow-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Sep 22, 2018
@vaikas
Copy link
Copy Markdown
Contributor Author

vaikas commented Sep 22, 2018

Ok, pushed one more version and added more unit tests and set some rudimentary conditions. If it's not horribly wrong, please merge it and we'll continue after the merge. I'm turning into a pumpkin until Wednesday, but would be nice to see it land before then.

@knative-metrics-robot
Copy link
Copy Markdown

The following is the coverage report on pkg/.
Say /test pull-knative-eventing-go-coverage to run the coverage report again

File Old Coverage New Coverage Delta
pkg/apis/eventing/v1alpha1/subscription_defaults.go 0.0% 100.0% 100.0
pkg/apis/eventing/v1alpha1/subscription_types.go 0.0% 100.0% 100.0
pkg/controller/eventing/subscription/provider.go Do not exist 0.0%
pkg/controller/eventing/subscription/reconcile.go Do not exist 72.2%

Subscribable duckv1alpha1.Subscribable `json:"subscribable,omitempty"`
}

const (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You need to update line 173 with:

var subCondSet = duckv1alpha1.NewLivingConditionSet(SubscriptionConditionReferencesResolved, SubscriptionConditionFromReady)

)

// GetSpecJSON returns spec as json
func (s *Subscription) GetSpecJSON() ([]byte, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you can delete GetSpecJSON now that the duck work has gone in.


func isValidResultStrategy(r *ResultStrategy) *apis.FieldError {
return isValidObjectReference(*r.Target).ViaField("target")
func isValidResultStrategy(r ResultStrategy) *apis.FieldError {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

FYI, I am taking some of these and moving it to a common place to reuse the logic:

https://github.com/knative/eventing/pull/457/files#diff-96c67291a6d32860d990069d9d9d5cd3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n3wscott if this PR goes in first, can you fix up the duplication?


// SubscriptionConditionFromReady has status True when controller has successfully added a subscription to From
// resource.
SubscriptionConditionFromReady duckv1alpha1.ConditionType = "FromReady"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

After you add these, it is helpful to expose an IsReady method using the Conditions helper to be the judge.

https://github.com/knative/eventing/pull/457/files#diff-67a9c730f0d592911dfa317323fea9e5R131

Also a InitializeConditions

https://github.com/knative/eventing/pull/457/files#diff-67a9c730f0d592911dfa317323fea9e5R137

And then Mark* style methods as you need them.


func (r *reconciler) reconcile(subscription *v1alpha1.Subscription) error {
// TODO: Should this just also set up a defer call for subscription.SetConditions.
// No time right now as I'm turning into a pumpking but seems reasonable.
Copy link
Copy Markdown
Contributor

@grantr grantr Sep 24, 2018

Choose a reason for hiding this comment

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

I'll switch these to using Mark* methods in a followup PR.

}
// Everything went well, set the fact that subscriptions have been modified
conditions = append(conditions, duckv1alpha1.Condition{
Type: duckv1alpha1.ConditionReady,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Was this supposed to be setting ConditionFromReady?

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 24, 2018
Copy link
Copy Markdown
Contributor

@grantr grantr left a comment

Choose a reason for hiding this comment

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

I've got a followup PR on the way that addresses @n3wscott's comments.

/lgtm

@knative-prow-robot knative-prow-robot merged commit 1ac89e4 into knative:master Sep 24, 2018
@vaikas vaikas deleted the subscription-controller branch September 26, 2018 06:42
matzew added a commit to matzew/eventing that referenced this pull request Feb 26, 2020
…pagation

removing patch, b/c merged upstream
Cali0707 pushed a commit to Cali0707/eventing that referenced this pull request Nov 29, 2023
…t. This allows us to mount in custom ca bundles via ConfigMap/VolumeSource. (knative#437)

OCP documentation is here: https://docs.openshift.com/container-platform/4.14/networking/configuring-a-custom-pki.html#certificate-injection-using-operators_configuring-a-custom-pki

Signed-off-by: Matthias Wessendorf <mwessend@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants