-
Notifications
You must be signed in to change notification settings - Fork 600
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
Add a new Channel CRD to the eventing group #430
Changes from 13 commits
6cdd708
5bd9843
9259abb
7a0586a
c56ca48
7b29db3
f767f48
34e6854
65f5b7e
e6f892d
01310b8
66cf283
7bb4c70
c6a8591
aebcad8
355ec67
940815b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Copyright 2018 The Knative Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
apiVersion: apiextensions.k8s.io/v1beta1 | ||
kind: CustomResourceDefinition | ||
metadata: | ||
name: channels.eventing.knative.dev | ||
spec: | ||
group: eventing.knative.dev | ||
version: v1alpha1 | ||
names: | ||
kind: Channel | ||
plural: channels | ||
singular: channel | ||
categories: | ||
- all | ||
- knative | ||
- eventing | ||
shortNames: | ||
- chan | ||
scope: Namespaced |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
Copyright 2018 The Knative Authors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package v1alpha1 | ||
|
||
//TODO replace this with openapi defaults when | ||
// https://github.com/kubernetes/features/issues/575 lands (scheduled for 1.13) | ||
func (c *Channel) SetDefaults() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason to keep this empty defaults file and others like it? It pulls down our coverage numbers unless we write no-op tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to removing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you need to keep The webhook validation code requires you implement Defaultable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you would like to change this, you will have to update GenericCRD interface and https://github.com/knative/pkg/blob/a3bc2db77a14d9ca6195172e81b4bf33e6190f85/webhook/webhook.go#L227 |
||
c.Spec.SetDefaults() | ||
} | ||
|
||
func (fs *ChannelSpec) SetDefaults() { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
Copyright 2018 The Knative Authors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package v1alpha1 | ||
|
||
import "testing" | ||
|
||
// No-op test because method does nothing. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does nothing yet :D |
||
func TestChannelSetDefaults(t *testing.T) { | ||
c := Channel{} | ||
c.SetDefaults() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/* | ||
* Copyright 2018 The Knative Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package v1alpha1 | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
"github.com/knative/pkg/apis" | ||
"github.com/knative/pkg/webhook" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
// +genclient | ||
// +genclient:noStatus | ||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||
|
||
// Channel represents a named endpoint on which a Bus accepts event delivery and | ||
// corresponds to the channels.channels.knative.dev CRD. The Bus handles | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. channels.channels.knative.dev -> channels.eventing.knative.dev? |
||
// provisioning channels, delivering events to Channels, and delivering events | ||
// from Channels to their Subscriptions. | ||
type Channel struct { | ||
metav1.TypeMeta `json:",inline"` | ||
// +optional | ||
metav1.ObjectMeta `json:"metadata,omitempty"` | ||
|
||
// Spec defines the desired state of the Channel. | ||
Spec ChannelSpec `json:"spec,omitempty"` | ||
|
||
// Status represents the current state of the Channel. This data may be out of | ||
// date. | ||
// +optional | ||
Status ChannelStatus `json:"status,omitempty"` | ||
} | ||
|
||
// Check that Channel can be validated, can be defaulted, and has immutable fields. | ||
var _ apis.Validatable = (*Channel)(nil) | ||
var _ apis.Defaultable = (*Channel)(nil) | ||
var _ apis.Immutable = (*Channel)(nil) | ||
var _ runtime.Object = (*Channel)(nil) | ||
var _ webhook.GenericCRD = (*Channel)(nil) | ||
|
||
// ChannelSpec specifies the Provisioner backing a channel and the configuration | ||
// arguments for a Channel. | ||
type ChannelSpec struct { | ||
// TODO: Generation does not work correctly with CRD. They are scrubbed | ||
// by the APIserver (https://github.com/kubernetes/kubernetes/issues/58778) | ||
// So, we add Generation here. Once that gets fixed, remove this and use | ||
// ObjectMeta.Generation instead. | ||
// +optional | ||
Generation int64 `json:"generation,omitempty"` | ||
|
||
// Provisioner defines the name of the Provisioner backing this channel. | ||
// TODO: +optional If missing, a default Provisioner may be selected for the Channel. | ||
Provisioner *ProvisionerReference `json:"provisioner,omitempty"` | ||
|
||
// Arguments defines the arguments to pass to the Provisioner which provisions | ||
// this Channel. | ||
// +optional | ||
Arguments *runtime.RawExtension `json:"arguments,omitempty"` | ||
|
||
// Subscribers is a list of the Subscribers to this channel. This is filled in | ||
// by the Subscriptions controller. Users should not mutate this field. | ||
Subscribers []ChannelSubscriberSpec `json:"subscribers,omitempty"` | ||
} | ||
|
||
// ChannelSubscriberSpec defines a single subscriber to a Channel. At least one | ||
// of Call or Result must be present. | ||
type ChannelSubscriberSpec struct { | ||
// Call is an optional reference to a function for processing events. | ||
// Events from the From channel will be delivered here and replies | ||
// are optionally handled by Result. | ||
// +optional | ||
Call *Callable `json:"call,omitempty"` | ||
|
||
// Result optionally specifies how to handle events received from the Call | ||
// target. | ||
// +optional | ||
Result *ResultStrategy `json:"result,omitempty"` | ||
} | ||
|
||
// ChannelStatus represents the current state of a Channel. | ||
type ChannelStatus struct { | ||
// ObservedGeneration is the most recent generation observed for this Channel. | ||
// It corresponds to the Channel's generation, which is updated on mutation by | ||
// the API Server. | ||
//TODO The above comment is only true once | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. malformed TODO. Should be:
|
||
// https://github.com/kubernetes/kubernetes/issues/58778 is fixed. | ||
// +optional | ||
ObservedGeneration int64 `json:"observedGeneration,omitempty"` | ||
|
||
// DomainInternal holds the top-level domain that will distribute traffic | ||
// over the provided targets from inside the cluster. It generally has the | ||
// form {channel}.{namespace}.svc.cluster.local | ||
//TODO move this to a struct that can be embedded similar to ObjectMeta and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. malformed TODO. See above |
||
// TypeMeta. | ||
// +optional | ||
DomainInternal string `json:"domainInternal,omitempty"` | ||
|
||
// Represents the latest available observations of a channel's current state. | ||
// +optional | ||
// +patchMergeKey=type | ||
// +patchStrategy=merge | ||
Conditions []ChannelCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you will want to update to the style of #434 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's get #434 in first, reviewing now :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is in now! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to use duck Conditions. |
||
} | ||
|
||
type ChannelConditionType string | ||
|
||
const ( | ||
// ChannelConditionReady has status True when the Channel is ready to accept | ||
// traffic. | ||
ChannelConditionReady ChannelConditionType = "Ready" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will turn into |
||
|
||
// ChannelConditionProvisioned has status True when the Channel's backing | ||
// resources have been provisioned. | ||
ChannelConditionProvisioned ChannelConditionType = "Provisioned" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
) | ||
|
||
// ChannelCondition describes the state of a channel at a point in time. | ||
type ChannelCondition struct { | ||
// Type of channel condition. | ||
Type ChannelConditionType `json:"type"` | ||
// Status of the condition, one of True, False, Unknown. | ||
Status corev1.ConditionStatus `json:"status"` | ||
// LastTransitionTime from one status to another. | ||
// We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic | ||
// differences (all other things held constant). | ||
LastTransitionTime apis.VolatileTime `json:"lastTransitionTime,omitempty"` | ||
// Reason for the condition's last transition. | ||
Reason string `json:"reason,omitempty"` | ||
// Message is a human readable message indicating details about the | ||
// last transition. | ||
Message string `json:"message,omitempty"` | ||
} | ||
|
||
func (cs *ChannelStatus) GetCondition(t ChannelConditionType) *ChannelCondition { | ||
for _, cond := range cs.Conditions { | ||
if cond.Type == t { | ||
return &cond | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (c *Channel) GetSpecJSON() ([]byte, error) { | ||
return json.Marshal(c.Spec) | ||
} | ||
|
||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||
|
||
// ChannelList is a collection of Channels. | ||
type ChannelList struct { | ||
metav1.TypeMeta `json:",inline"` | ||
// +optional | ||
metav1.ListMeta `json:"metadata,omitempty"` | ||
Items []Channel `json:"items"` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
Copyright 2018 The Knative Authors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package v1alpha1 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
var condReady = ChannelCondition{ | ||
Type: ChannelConditionReady, | ||
Status: corev1.ConditionTrue, | ||
} | ||
|
||
var condUnprovisioned = ChannelCondition{ | ||
Type: ChannelConditionProvisioned, | ||
Status: corev1.ConditionFalse, | ||
} | ||
|
||
func TestChannelGetCondition(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
cs *ChannelStatus | ||
condQuery ChannelConditionType | ||
want *ChannelCondition | ||
}{{ | ||
name: "single condition", | ||
cs: &ChannelStatus{ | ||
Conditions: []ChannelCondition{ | ||
condReady, | ||
}, | ||
}, | ||
condQuery: ChannelConditionReady, | ||
want: &condReady, | ||
}, { | ||
name: "multiple conditions", | ||
cs: &ChannelStatus{ | ||
Conditions: []ChannelCondition{ | ||
condReady, | ||
condUnprovisioned, | ||
}, | ||
}, | ||
condQuery: ChannelConditionProvisioned, | ||
want: &condUnprovisioned, | ||
}, { | ||
name: "unknown condition", | ||
cs: &ChannelStatus{ | ||
Conditions: []ChannelCondition{ | ||
condReady, | ||
condUnprovisioned, | ||
}, | ||
}, | ||
condQuery: ChannelConditionType("foo"), | ||
want: nil, | ||
}} | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
got := test.cs.GetCondition(test.condQuery) | ||
if diff := cmp.Diff(test.want, got); diff != "" { | ||
t.Errorf("unexpected condition (-want, +got) = %v", diff) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestChannelGetSpecJSON(t *testing.T) { | ||
c := &Channel{ | ||
Spec: ChannelSpec{ | ||
Provisioner: &ProvisionerReference{ | ||
Ref: &corev1.ObjectReference{ | ||
Name: "foo", | ||
}, | ||
}, | ||
Arguments: &runtime.RawExtension{ | ||
Raw: []byte(`{"foo":"baz"}`), | ||
}, | ||
}, | ||
} | ||
|
||
want := `{"provisioner":{"ref":{"name":"foo"}},"arguments":{"foo":"baz"}}` | ||
got, err := c.GetSpecJSON() | ||
if err != nil { | ||
t.Fatalf("unexpected spec JSON error: %v", err) | ||
} | ||
|
||
if diff := cmp.Diff(want, string(got)); diff != "" { | ||
t.Errorf("unexpected spec JSON (-want, +got) = %v", diff) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch