-
Notifications
You must be signed in to change notification settings - Fork 601
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 all 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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,169 @@ | ||
/* | ||
* 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/apis/duck" | ||
duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" | ||
"github.com/knative/pkg/webhook" | ||
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 is an abstract resource that implements the Subscribable and Sinkable | ||
// contracts. The Provisioner provisions infrastructure to accepts events and | ||
// deliver to 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) | ||
|
||
// Check that ConfigurationStatus may have its conditions managed. | ||
var _ duckv1alpha1.ConditionsAccessor = (*ChannelStatus)(nil) | ||
|
||
// Check that Channel implements the Conditions duck type. | ||
var _ = duck.VerifyType(&Channel{}, &duckv1alpha1.Conditions{}) | ||
|
||
// 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"` | ||
} | ||
|
||
var chanCondSet = duckv1alpha1.NewLivingConditionSet(ChannelConditionProvisioned) | ||
|
||
// 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 | ||
// 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 | ||
// TypeMeta. | ||
// +optional | ||
DomainInternal string `json:"domainInternal,omitempty"` | ||
|
||
// Represents the latest available observations of a channel's current state. | ||
// +optional | ||
// +patchMergeKey=type | ||
// +patchStrategy=merge | ||
Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` | ||
} | ||
|
||
const ( | ||
// ChannelConditionReady has status True when the Channel is ready to accept | ||
// traffic. | ||
ChannelConditionReady = duckv1alpha1.ConditionReady | ||
|
||
// ChannelConditionProvisioned has status True when the Channel's backing | ||
// resources have been provisioned. | ||
ChannelConditionProvisioned duckv1alpha1.ConditionType = "Provisioned" | ||
) | ||
|
||
func (c *Channel) GetSpecJSON() ([]byte, error) { | ||
return json.Marshal(c.Spec) | ||
} | ||
|
||
// GetCondition returns the condition currently associated with the given type, or nil. | ||
func (cs *ChannelStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { | ||
return chanCondSet.Manage(cs).GetCondition(t) | ||
} | ||
|
||
// GetConditions returns the Conditions array. This enables generic handling of | ||
// conditions by implementing the duckv1alpha1.Conditions interface. | ||
func (cs *ChannelStatus) GetConditions() duckv1alpha1.Conditions { | ||
return cs.Conditions | ||
} | ||
|
||
// SetConditions sets the Conditions array. This enables generic handling of | ||
// conditions by implementing the duckv1alpha1.Conditions interface. | ||
func (cs *ChannelStatus) SetConditions(conditions duckv1alpha1.Conditions) { | ||
cs.Conditions = conditions | ||
} | ||
|
||
// +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,120 @@ | ||
/* | ||
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" | ||
duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
var condReady = duckv1alpha1.Condition{ | ||
Type: ChannelConditionReady, | ||
Status: corev1.ConditionTrue, | ||
} | ||
|
||
var condUnprovisioned = duckv1alpha1.Condition{ | ||
Type: ChannelConditionProvisioned, | ||
Status: corev1.ConditionFalse, | ||
} | ||
|
||
func TestChannelGetCondition(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
cs *ChannelStatus | ||
condQuery duckv1alpha1.ConditionType | ||
want *duckv1alpha1.Condition | ||
}{{ | ||
name: "single condition", | ||
cs: &ChannelStatus{ | ||
Conditions: []duckv1alpha1.Condition{ | ||
condReady, | ||
}, | ||
}, | ||
condQuery: duckv1alpha1.ConditionReady, | ||
want: &condReady, | ||
}, { | ||
name: "multiple conditions", | ||
cs: &ChannelStatus{ | ||
Conditions: []duckv1alpha1.Condition{ | ||
condReady, | ||
condUnprovisioned, | ||
}, | ||
}, | ||
condQuery: ChannelConditionProvisioned, | ||
want: &condUnprovisioned, | ||
}, { | ||
name: "unknown condition", | ||
cs: &ChannelStatus{ | ||
Conditions: []duckv1alpha1.Condition{ | ||
condReady, | ||
condUnprovisioned, | ||
}, | ||
}, | ||
condQuery: duckv1alpha1.ConditionType("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 TestChannelSetConditions(t *testing.T) { | ||
c := &Channel{ | ||
Status: ChannelStatus{}, | ||
} | ||
want := duckv1alpha1.Conditions{condReady} | ||
c.Status.SetConditions(want) | ||
got := c.Status.GetConditions() | ||
if diff := cmp.Diff(want, got); diff != "" { | ||
t.Errorf("unexpected conditions (-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