diff --git a/Gopkg.lock b/Gopkg.lock index e8fbbd82acd..70c22c23a49 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -360,6 +360,17 @@ revision = "f611eb38b3875cc3bd991ca91c51d06446afa14c" version = "v1.3.0" +[[projects]] + branch = "master" + digest = "1:314c9403866f4451d4fd13ec823f559e4b576c4272fd0c771991ab5d17f7fa41" + name = "github.com/knative/pkg" + packages = [ + "apis/duck", + "apis/duck/v1alpha1", + ] + pruneopts = "NUT" + revision = "c27053214044899c369bfd6e4d51bbf8cc7ccca2" + [[projects]] branch = "master" digest = "1:927762c6729b4e72957ba3310e485ed09cf8451c5a637a52fd016a9fe09e7936" @@ -1314,6 +1325,8 @@ "github.com/google/mako/go/quickstore", "github.com/google/uuid", "github.com/kelseyhightower/envconfig", + "github.com/knative/pkg/apis/duck", + "github.com/knative/pkg/apis/duck/v1alpha1", "github.com/pkg/errors", "github.com/robfig/cron", "github.com/tsenart/vegeta/lib", diff --git a/config/200-source-resolvers-clusterrole.yaml b/config/200-source-resolvers-clusterrole.yaml new file mode 100644 index 00000000000..958599fed68 --- /dev/null +++ b/config/200-source-resolvers-clusterrole.yaml @@ -0,0 +1,79 @@ +# Copyright 2019 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. + +# Use this aggregated ClusterRole when you need readonly access to "Sources" +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: source-resolver + labels: + eventing.knative.dev/release: devel +aggregationRule: + clusterRoleSelectors: + - matchLabels: + duck.knative.dev/sourceObserver: "true" +rules: [] # Rules are automatically filled in by the controller manager. + +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: eventing-source-resolver + labels: + eventing.knative.dev/release: devel + duck.knative.dev/sourceObserver: "true" +# Do not use this role directly. These rules will be added to the "source-resolver" role. +# For resources "awssqssources", "camelsources", "kafkasources", "githubsources", +# These should eventually be moved to config directories in https://github.com/knative/eventing-contrib. +# TODO After https://github.com/knative/eventing-contrib/issues/583 gets done, remove "awssqssources", "camelsources", "kafkasources", "githubsources" in resources and modified config/201-clusterrolebinding.yaml +rules: +- apiGroups: + - "sources.eventing.knative.dev" + resources: + - "cronjobsources" + - "containersources" + - "apiserversources" + - "awssqssources" + - "camelsources" + - "kafkasources" + - "githubsources" + verbs: + - get + - list + - watch +--- + +# These should eventually be moved to config directories in https://github.com/google/knative-gcp. +# TODO After https://github.com/google/knative-gcp/issues/252 gets done, remove this ClusterRole and modified config/201-clusterrolebinding.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: knative-gcp-source-resolver + labels: + eventing.knative.dev/release: devel + duck.knative.dev/sourceObserver: "true" +# Do not use this role directly. These rules will be added to the "source-resolver" role. +rules: + - apiGroups: + - "pubsub.cloud.run" + - "events.cloud.run" + resources: + - "pullsubscriptions" + - "storages" + verbs: + - get + - list + - watch +--- diff --git a/config/201-clusterrolebinding.yaml b/config/201-clusterrolebinding.yaml index 141874a0cb8..903e5668b06 100644 --- a/config/201-clusterrolebinding.yaml +++ b/config/201-clusterrolebinding.yaml @@ -46,6 +46,23 @@ roleRef: --- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: eventing-controller-source-resolver + labels: + eventing.knative.dev/release: devel +subjects: + - kind: ServiceAccount + name: eventing-controller + namespace: knative-eventing +roleRef: + kind: ClusterRole + name: source-resolver + apiGroup: rbac.authorization.k8s.io + +--- + apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: diff --git a/pkg/apis/eventing/v1alpha1/trigger_lifecycle.go b/pkg/apis/eventing/v1alpha1/trigger_lifecycle.go index eb38b7d91fb..05cbdc40226 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_lifecycle.go +++ b/pkg/apis/eventing/v1alpha1/trigger_lifecycle.go @@ -17,11 +17,12 @@ package v1alpha1 import ( + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" "knative.dev/pkg/apis" ) -var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed) +var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency) const ( // TriggerConditionReady has status True when all subconditions below have been set to True. @@ -31,6 +32,8 @@ const ( TriggerConditionSubscribed apis.ConditionType = "Subscribed" + TriggerConditionDependency apis.ConditionType = "Dependency" + // TriggerAnyFilter Constant to represent that we should allow anything. TriggerAnyFilter = "" ) @@ -85,3 +88,28 @@ func (ts *TriggerStatus) MarkNotSubscribed(reason, messageFormat string, message func (ts *TriggerStatus) MarkSubscriptionNotOwned(sub *messagingv1alpha1.Subscription) { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscribed, "SubscriptionNotOwned", "Subscription %q is not owned by this Trigger.", sub.Name) } + +func (ts *TriggerStatus) MarkDependencySucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionDependency) +} + +func (ts *TriggerStatus) MarkDependencyFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) PropagateDependencyStatus(ks *duckv1alpha1.KResource) { + kc := ks.Status.GetCondition(duckv1alpha1.ConditionReady) + if kc != nil && kc.IsTrue() { + ts.MarkDependencySucceeded() + } else { + msg := "nil" + if kc != nil { + msg = kc.Message + } + ts.MarkDependencyFailed("DependencyNotReady", "Dependency is not ready: %s", msg) + } +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_lifecycle_test.go b/pkg/apis/eventing/v1alpha1/trigger_lifecycle_test.go index 7982c664ad5..21f6cb6a815 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_lifecycle_test.go +++ b/pkg/apis/eventing/v1alpha1/trigger_lifecycle_test.go @@ -41,6 +41,11 @@ var ( Status: corev1.ConditionTrue, } + triggerConditionDependency = apis.Condition{ + Type: TriggerConditionDependency, + Status: corev1.ConditionTrue, + } + triggerConditionSubscribed = apis.Condition{ Type: TriggerConditionSubscribed, Status: corev1.ConditionFalse, @@ -71,6 +76,7 @@ func TestTriggerGetCondition(t *testing.T) { Conditions: []apis.Condition{ triggerConditionBroker, triggerConditionSubscribed, + triggerConditionDependency, }, }, }, @@ -83,6 +89,7 @@ func TestTriggerGetCondition(t *testing.T) { Conditions: []apis.Condition{ triggerConditionBroker, triggerConditionSubscribed, + triggerConditionDependency, }, }, }, @@ -124,13 +131,17 @@ func TestTriggerInitializeConditions(t *testing.T) { Conditions: []apis.Condition{{ Type: TriggerConditionBroker, Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, }, { Type: TriggerConditionReady, Status: corev1.ConditionUnknown, }, { Type: TriggerConditionSubscribed, Status: corev1.ConditionUnknown, - }}, + }, + }, }, }, }, { @@ -149,12 +160,17 @@ func TestTriggerInitializeConditions(t *testing.T) { Type: TriggerConditionBroker, Status: corev1.ConditionFalse, }, { - Type: TriggerConditionReady, - Status: corev1.ConditionUnknown, - }, { - Type: TriggerConditionSubscribed, + Type: TriggerConditionDependency, Status: corev1.ConditionUnknown, - }}, + }, + { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, + }, }, }, }, { @@ -172,13 +188,17 @@ func TestTriggerInitializeConditions(t *testing.T) { Conditions: []apis.Condition{{ Type: TriggerConditionBroker, Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, }, { Type: TriggerConditionReady, Status: corev1.ConditionUnknown, }, { Type: TriggerConditionSubscribed, Status: corev1.ConditionTrue, - }}, + }, + }, }, }, }} @@ -201,6 +221,8 @@ func TestTriggerIsReady(t *testing.T) { markVirtualServiceExists bool subscriptionOwned bool subscriptionStatus *messagingv1alpha1.SubscriptionStatus + dependencyAnnotationExists bool + dependencyStatusReady bool wantReady bool }{{ name: "all happy", @@ -209,6 +231,7 @@ func TestTriggerIsReady(t *testing.T) { markVirtualServiceExists: true, subscriptionOwned: true, subscriptionStatus: TestHelper.ReadySubscriptionStatus(), + dependencyAnnotationExists: false, wantReady: true, }, { name: "broker sad", @@ -217,6 +240,7 @@ func TestTriggerIsReady(t *testing.T) { markVirtualServiceExists: true, subscriptionOwned: true, subscriptionStatus: TestHelper.ReadySubscriptionStatus(), + dependencyAnnotationExists: false, wantReady: false, }, { name: "subscribed sad", @@ -225,6 +249,7 @@ func TestTriggerIsReady(t *testing.T) { markVirtualServiceExists: true, subscriptionOwned: true, subscriptionStatus: TestHelper.NotReadySubscriptionStatus(), + dependencyAnnotationExists: false, wantReady: false, }, { name: "subscription not owned", @@ -233,16 +258,30 @@ func TestTriggerIsReady(t *testing.T) { markVirtualServiceExists: true, subscriptionOwned: false, subscriptionStatus: TestHelper.ReadySubscriptionStatus(), + dependencyAnnotationExists: false, wantReady: false, }, { - name: "all sad", - brokerStatus: TestHelper.NotReadyBrokerStatus(), - markKubernetesServiceExists: false, - markVirtualServiceExists: false, - subscriptionOwned: false, - subscriptionStatus: TestHelper.NotReadySubscriptionStatus(), + name: "dependency not ready", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionOwned: true, + subscriptionStatus: TestHelper.ReadySubscriptionStatus(), + dependencyAnnotationExists: true, + dependencyStatusReady: false, wantReady: false, - }} + }, + { + name: "all sad", + brokerStatus: TestHelper.NotReadyBrokerStatus(), + markKubernetesServiceExists: false, + markVirtualServiceExists: false, + subscriptionOwned: false, + subscriptionStatus: TestHelper.NotReadySubscriptionStatus(), + dependencyAnnotationExists: true, + dependencyStatusReady: false, + wantReady: false, + }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { ts := &TriggerStatus{} @@ -254,6 +293,11 @@ func TestTriggerIsReady(t *testing.T) { } else if test.subscriptionStatus != nil { ts.PropagateSubscriptionStatus(test.subscriptionStatus) } + if test.dependencyAnnotationExists && !test.dependencyStatusReady { + ts.MarkDependencyFailed("Dependency is not ready", "Dependency is not ready") + } else { + ts.MarkDependencySucceeded() + } got := ts.IsReady() if test.wantReady != got { t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 6d5e98f1d8d..38d18d6e34e 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -27,6 +27,12 @@ import ( "knative.dev/pkg/webhook" ) +const ( + // DependencyAnnotation is the annotation key used to mark the sources that the Trigger depends on. + // This will be used when the kn client creates an importer and trigger pair for the user such that the trigger only receives events produced by the paired importer. + DependencyAnnotation = "knative.dev/dependency" +) + // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 0b873e78e0d..3755a8bcbe2 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -18,12 +18,14 @@ package v1alpha1 import ( "context" + "encoding/json" "fmt" "regexp" "knative.dev/pkg/apis" "knative.dev/pkg/kmp" + corev1 "k8s.io/api/core/v1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" ) @@ -34,7 +36,13 @@ var ( // Validate the Trigger. func (t *Trigger) Validate(ctx context.Context) *apis.FieldError { - return t.Spec.Validate(ctx).ViaField("spec") + errs := t.Spec.Validate(ctx).ViaField("spec") + dependencyAnnotation, ok := t.GetAnnotations()[DependencyAnnotation] + if ok { + dependencyAnnotationPrefix := fmt.Sprintf("metadata.annotations[%s]", DependencyAnnotation) + errs = errs.Also(t.validateDependencyAnnotation(dependencyAnnotation).ViaField(dependencyAnnotationPrefix)) + } + return errs } // Validate the TriggerSpec. @@ -70,7 +78,7 @@ func (ts *TriggerSpec) Validate(ctx context.Context) *apis.FieldError { for attr := range attrs { if !validAttributeName.MatchString(attr) { fe := &apis.FieldError{ - Message: fmt.Sprintf("Invalid attribute name: %s", attr), + Message: fmt.Sprintf("Invalid attribute name: %q", attr), Paths: []string{"filter.attributes"}, } errs = errs.Also(fe) @@ -121,3 +129,43 @@ func (t *Trigger) CheckImmutableFields(ctx context.Context, og apis.Immutable) * } return nil } + +func GetObjRefFromDependencyAnnotation(dependencyAnnotation string) (corev1.ObjectReference, error) { + var objectRef corev1.ObjectReference + if err := json.Unmarshal([]byte(dependencyAnnotation), &objectRef); err != nil { + return objectRef, err + } + return objectRef, nil +} + +func (t *Trigger) validateDependencyAnnotation(dependencyAnnotation string) *apis.FieldError { + depObjRef, err := GetObjRefFromDependencyAnnotation(dependencyAnnotation) + if err != nil { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided annotation was not a corev1.ObjectReference: %q", dependencyAnnotation), + Details: err.Error(), + Paths: []string{""}, + } + } + var errs *apis.FieldError + if depObjRef.Namespace != "" && depObjRef.Namespace != t.GetNamespace() { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Namespace must be empty or equal to the trigger namespace %q", t.GetNamespace()), + Paths: []string{"namespace"}, + } + errs = errs.Also(fe) + } + if depObjRef.Kind == "" { + fe := apis.ErrMissingField("kind") + errs = errs.Also(fe) + } + if depObjRef.Name == "" { + fe := apis.ErrMissingField("name") + errs = errs.Also(fe) + } + if depObjRef.APIVersion == "" { + fe := apis.ErrMissingField("apiVersion") + errs = errs.Also(fe) + } + return errs +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation_test.go b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go index 86f74d0d17a..0466e8c8c3a 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go @@ -18,14 +18,14 @@ package v1alpha1 import ( "context" + "fmt" "testing" - "knative.dev/pkg/apis" - - messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" - "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + "knative.dev/pkg/apis" ) var ( @@ -55,23 +55,158 @@ var ( APIVersion: "serving.knative.dev/v1alpha1", }, } + validDependencyAnnotation = "{\"kind\":\"CronJobSource\",\"name\":\"test-cronjob-source\",\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"}" + invalidDependencyAnnotation = "invalid dependency annotation" + dependencyAnnotationPath = fmt.Sprintf("metadata.annotations[%s]", DependencyAnnotation) ) func TestTriggerValidation(t *testing.T) { - name := "invalid trigger spec" - trigger := &Trigger{Spec: TriggerSpec{}} - - want := &apis.FieldError{ - Paths: []string{"spec.broker", "spec.filter", "spec.subscriber"}, - Message: "missing field(s)", + tests := []struct { + name string + t *Trigger + want *apis.FieldError + }{{ + name: "invalid trigger spec", + t: &Trigger{Spec: TriggerSpec{}}, + want: &apis.FieldError{ + Paths: []string{"spec.broker", "spec.filter", "spec.subscriber"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, not a corev1.ObjectReference", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Annotations: map[string]string{ + DependencyAnnotation: invalidDependencyAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath}, + Message: "The provided annotation was not a corev1.ObjectReference: \"invalid dependency annotation\"", + Details: "invalid character 'i' looking for beginning of value", + }, + }, { + name: "invalid dependency annotation, trigger namespace is not equal to dependency namespace)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns-1", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"CronJobSource\",\"namespace\":\"test-ns-2\", \"name\":\"test-cronjob-source\",\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "namespace"}, + Message: "Namespace must be empty or equal to the trigger namespace \"test-ns-1\"", + }, + }, + { + name: "invalid dependency annotation, missing kind)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"name\":\"test-cronjob-source\",\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "kind"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing name", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"CronJobSource\",\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "name"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"CronJobSource\",\"name\":\"test-cronjob-source\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing kind, name, apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{ + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, + { + name: "invalid trigger spec, invalid dependency annotation(missing kind, name, apiVersion)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{}}, + want: &apis.FieldError{ + Paths: []string{ + "spec.broker", "spec.filter", "spec.subscriber", + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, } - t.Run(name, func(t *testing.T) { - got := trigger.Validate(context.TODO()) - if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { - t.Errorf("Trigger.Validate (-want, +got) = %v", diff) - } - }) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.t.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("Trigger.Validate (-want, +got) = %v", diff) + } + }) + } } func TestTriggerSpecValidation(t *testing.T) { @@ -132,7 +267,7 @@ func TestTriggerSpecValidation(t *testing.T) { Subscriber: validSubscriber, }, want: &apis.FieldError{ - Message: "Invalid attribute name: 0invalid", + Message: "Invalid attribute name: \"0invalid\"", Paths: []string{"filter.attributes"}, }, }, { @@ -147,7 +282,7 @@ func TestTriggerSpecValidation(t *testing.T) { Subscriber: validSubscriber, }, want: &apis.FieldError{ - Message: "Invalid attribute name: invALID", + Message: "Invalid attribute name: \"invALID\"", Paths: []string{"filter.attributes"}, }, }, { diff --git a/pkg/reconciler/testing/cronjobsource.go b/pkg/reconciler/testing/cronjobsource.go index ff69a98ef36..16c278a3d8c 100644 --- a/pkg/reconciler/testing/cronjobsource.go +++ b/pkg/reconciler/testing/cronjobsource.go @@ -93,3 +93,9 @@ func WithCronJobSourceSpec(spec v1alpha1.CronJobSourceSpec) CronJobSourceOption c.Spec = spec } } + +func WithCronJobApiVersion(apiVersion string) CronJobSourceOption { + return func(c *v1alpha1.CronJobSource) { + c.APIVersion = apiVersion + } +} diff --git a/pkg/reconciler/testing/trigger.go b/pkg/reconciler/testing/trigger.go index bae8059f3f3..4fbb861629f 100644 --- a/pkg/reconciler/testing/trigger.go +++ b/pkg/reconciler/testing/trigger.go @@ -28,6 +28,14 @@ import ( messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" ) +const ( + unmarshalFailedDependencyAnnotation = "{" + + "\"kind\":{CronJobSource}, " + + "\"name\":\"test-cronjob-source\"," + + "\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"" + + "}" +) + // TriggerOption enables further configuration of a Trigger. type TriggerOption func(*v1alpha1.Trigger) @@ -104,6 +112,42 @@ func WithTriggerStatusSubscriberURI(uri string) TriggerOption { } } +func WithUnmarshalFailedDependencyAnnotation() TriggerOption { + return func(t *v1alpha1.Trigger) { + if t.Annotations == nil { + t.Annotations = make(map[string]string) + } + t.Annotations[v1alpha1.DependencyAnnotation] = unmarshalFailedDependencyAnnotation + } +} + +func WithDependencyAnnotation(dependencyAnnotation string) TriggerOption { + return func(t *v1alpha1.Trigger) { + if t.Annotations == nil { + t.Annotations = make(map[string]string) + } + t.Annotations[v1alpha1.DependencyAnnotation] = dependencyAnnotation + } +} + +func WithTriggerDependencyReady() TriggerOption { + return func(t *v1alpha1.Trigger) { + t.Status.MarkDependencySucceeded() + } +} + +func WithTriggerDependencyFailed(reason, message string) TriggerOption { + return func(t *v1alpha1.Trigger) { + t.Status.MarkDependencyFailed(reason, message) + } +} + +func WithTriggerDependencyUnknown(reason, message string) TriggerOption { + return func(t *v1alpha1.Trigger) { + t.Status.MarkDependencyUnknown(reason, message) + } +} + // TODO: this can be a runtime object func WithTriggerDeleted(t *v1alpha1.Trigger) { deleteTime := metav1.NewTime(time.Unix(1e9, 0)) diff --git a/pkg/reconciler/trigger/controller.go b/pkg/reconciler/trigger/controller.go index f9929be7676..ae7e4811444 100644 --- a/pkg/reconciler/trigger/controller.go +++ b/pkg/reconciler/trigger/controller.go @@ -26,12 +26,15 @@ import ( "knative.dev/eventing/pkg/apis/eventing/v1alpha1" "knative.dev/eventing/pkg/duck" "knative.dev/eventing/pkg/reconciler" + apisduck "knative.dev/pkg/apis/duck" "knative.dev/pkg/injection/informers/kubeinformers/corev1/service" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/broker" "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/trigger" "knative.dev/eventing/pkg/client/injection/informers/messaging/v1alpha1/subscription" + "knative.dev/pkg/injection/clients/dynamicclient" ) const ( @@ -71,6 +74,7 @@ func NewController( // Tracker is used to notify us that a Trigger's Broker has changed so that // we can reconcile. r.resourceTracker = resourceInformer.NewTracker(impl.EnqueueKey, controller.GetTrackerLease(ctx)) + r.kresourceInformerFactory = KResourceTypedInformerFactory(ctx) subscriptionInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ FilterFunc: controller.Filter(v1alpha1.SchemeGroupVersion.WithKind("Trigger")), @@ -78,3 +82,12 @@ func NewController( }) return impl } + +func KResourceTypedInformerFactory(ctx context.Context) apisduck.InformerFactory { + return &apisduck.TypedInformerFactory{ + Client: dynamicclient.Get(ctx), + Type: &duckv1alpha1.KResource{}, + ResyncPeriod: controller.GetResyncPeriod(ctx), + StopChannel: ctx.Done(), + } +} diff --git a/pkg/reconciler/trigger/trigger.go b/pkg/reconciler/trigger/trigger.go index cde289d68e6..1177116037f 100644 --- a/pkg/reconciler/trigger/trigger.go +++ b/pkg/reconciler/trigger/trigger.go @@ -24,15 +24,17 @@ import ( "reflect" "time" + apisduck "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" corev1listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" - "knative.dev/pkg/controller" - "knative.dev/eventing/pkg/apis/eventing/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" listers "knative.dev/eventing/pkg/client/listers/eventing/v1alpha1" @@ -44,6 +46,7 @@ import ( "knative.dev/eventing/pkg/reconciler/names" "knative.dev/eventing/pkg/reconciler/trigger/path" "knative.dev/eventing/pkg/reconciler/trigger/resources" + "knative.dev/pkg/controller" ) const ( @@ -63,11 +66,12 @@ const ( type Reconciler struct { *reconciler.Base - triggerLister listers.TriggerLister - subscriptionLister messaginglisters.SubscriptionLister - brokerLister listers.BrokerLister - serviceLister corev1listers.ServiceLister - resourceTracker duck.ResourceTracker + triggerLister listers.TriggerLister + subscriptionLister messaginglisters.SubscriptionLister + brokerLister listers.BrokerLister + serviceLister corev1listers.ServiceLister + resourceTracker duck.ResourceTracker + kresourceInformerFactory apisduck.InformerFactory } var brokerGVK = v1alpha1.SchemeGroupVersion.WithKind("Broker") @@ -131,21 +135,23 @@ func (r *Reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { // 3. Find the Subscriber's URI. // 4. Creates a Subscription from the Broker's Trigger Channel to this Trigger via the Broker's // Filter Service with a specific path, and reply set to the Broker's Ingress Channel. + // 5. Find whether there is annotation with key "knative.dev/dependency". + // If not, mark Dependency to be succeeded, else figure out whether the dependency is ready and mark Dependency correspondingly if t.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. return nil } + track := r.resourceTracker.TrackInNamespace(t) // Tell resourceTracker to reconcile this Trigger whenever the Broker changes. - objRef := corev1.ObjectReference{ + brokerObjRef := corev1.ObjectReference{ Kind: brokerGVK.Kind, APIVersion: brokerGVK.GroupVersion().String(), Name: t.Spec.Broker, Namespace: t.Namespace, } - track := r.resourceTracker.TrackInNamespace(t) - if err := track(objRef); err != nil { + if err := track(brokerObjRef); err != nil { logging.FromContext(ctx).Error("Unable to track changes to Broker", zap.Error(err)) return err } @@ -204,6 +210,66 @@ func (r *Reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { } t.Status.PropagateSubscriptionStatus(&sub.Status) + if err := r.checkDependencyAnnotation(t, track, ctx); err != nil { + return err + } + + return nil +} + +func (r *Reconciler) checkDependencyAnnotation(t *v1alpha1.Trigger, track func(corev1.ObjectReference) error, ctx context.Context) error { + if dependencyAnnotation, ok := t.GetAnnotations()[v1alpha1.DependencyAnnotation]; ok { + dependencyObjRef, err := v1alpha1.GetObjRefFromDependencyAnnotation(dependencyAnnotation) + if err != nil { + t.Status.MarkDependencyFailed("ReferenceError", "Unable to unmarshal objectReference from dependency annotation of trigger: %v", err) + return fmt.Errorf("getting object ref from dependency annotation %q: %v", dependencyAnnotation, err) + } + //trigger and its dependency importer are in the same namespace, we already did the validation when we in the trigger webhook + if err := track(dependencyObjRef); err != nil { + return fmt.Errorf("tracking dependency: %v", err) + } + if err := r.propagateDependencyReadiness(dependencyObjRef, ctx, t); err != nil { + return fmt.Errorf("propagating dependency readiness: %v", err) + + } + } else { + t.Status.MarkDependencySucceeded() + } + return nil +} + +func (r *Reconciler) propagateDependencyReadiness(dependencyObjRef corev1.ObjectReference, ctx context.Context, t *v1alpha1.Trigger) error { + gvk := schema.GroupVersionKind{ + Group: dependencyObjRef.GroupVersionKind().Group, + Version: dependencyObjRef.GroupVersionKind().Version, + Kind: dependencyObjRef.Kind, + } + gvr, _ := meta.UnsafeGuessKindToResource(gvk) + _, lister, err := r.kresourceInformerFactory.Get(gvr) + if err != nil { + t.Status.MarkDependencyUnknown("FailedToListResource", "Failed to list resource: %v", err) + return fmt.Errorf("creating lister: %v", err) + } + dependencyObj, err := lister.ByNamespace(t.GetNamespace()).Get(dependencyObjRef.Name) + if err != nil { + if apierrs.IsNotFound(err) { + t.Status.MarkDependencyUnknown("DependencyDoesNotExist", "Dependency does not exist: %v", err) + } else { + t.Status.MarkDependencyUnknown("DependencyGetFailed", "Failed to get dependency: %v", err) + } + return fmt.Errorf("getting the dependency: %v", err) + } + dependency := dependencyObj.(*duckv1alpha1.KResource) + // Temporarily comment it until we figure out whether we update Status.ObservedGeneration when KResource changes + // From manual testing, it looks like we never update Status.ObservedGeneration + //if dependency.GetGeneration() != dependency.Status.ObservedGeneration { + // logging.FromContext(ctx).Error("The ObjectMeta Generation of dependency is not equal to the observedGeneration of status", + // zap.Any("ObjectMeta Generation of dependency", dependency.GetGeneration()), + // zap.Any("ObservedGeneration of status", dependency.Status.ObservedGeneration)) + // t.Status.MarkDependencyUnknown("GenerationNotEqual", "The ObjectMeta Generation of dependency %d is not equal to the ObservedGeneration of status %d", dependency.GetGeneration(), dependency.Status.ObservedGeneration) + // return nil + //} + t.Status.PropagateDependencyStatus(dependency) return nil } diff --git a/pkg/reconciler/trigger/trigger_test.go b/pkg/reconciler/trigger/trigger_test.go index 644888a00f4..49ce62d4346 100644 --- a/pkg/reconciler/trigger/trigger_test.go +++ b/pkg/reconciler/trigger/trigger_test.go @@ -35,6 +35,7 @@ import ( "knative.dev/eventing/pkg/apis/eventing/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" "knative.dev/eventing/pkg/reconciler" brokerresources "knative.dev/eventing/pkg/reconciler/broker/resources" reconciletesting "knative.dev/eventing/pkg/reconciler/testing" @@ -46,6 +47,21 @@ import ( . "knative.dev/eventing/pkg/reconciler/testing" ) +var ( + sinkRef = corev1.ObjectReference{ + Name: sinkName, + Kind: "Channel", + APIVersion: "messaging.knative.dev/v1alpha1", + } + brokerRef = corev1.ObjectReference{ + Name: sinkName, + Kind: "Broker", + APIVersion: "eventing.knative.dev/v1alpha1", + } + sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() + sinkURI = "http://" + sinkDNS +) + const ( testNS = "test-namespace" triggerName = "test-trigger" @@ -56,6 +72,13 @@ const ( subscriberKind = "Service" subscriberName = "subscriberName" subscriberURI = "http://example.com/subscriber" + + dependencyAnnotation = "{\"kind\":\"CronJobSource\",\"name\":\"test-cronjob-source\",\"apiVersion\":\"sources.eventing.knative.dev/v1alpha1\"}" + cronJobSourceName = "test-cronjob-source" + cronJobSourceAPIVersion = "sources.eventing.knative.dev/v1alpha1" + testSchedule = "*/2 * * * *" + testData = "data" + sinkName = "testsink" ) var ( @@ -383,6 +406,7 @@ func TestAllCases(t *testing.T) { reconciletesting.WithTriggerBrokerReady(), reconciletesting.WithTriggerNotSubscribed("SubscriptionNotReady", "Subscription is not ready: nil"), reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyReady(), ), }}, WantDeletes: []clientgotesting.DeleteActionImpl{{ @@ -416,6 +440,7 @@ func TestAllCases(t *testing.T) { reconciletesting.WithTriggerBrokerReady(), reconciletesting.WithTriggerNotSubscribed("SubscriptionNotReady", "Subscription is not ready: nil"), reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyReady(), ), }}, WantCreates: []runtime.Object{ @@ -447,6 +472,7 @@ func TestAllCases(t *testing.T) { reconciletesting.WithTriggerBrokerReady(), reconciletesting.WithTriggerNotSubscribed("SubscriptionNotReady", "Subscription is not ready: test induced [error]"), reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyReady(), ), }}, }, { @@ -476,6 +502,101 @@ func TestAllCases(t *testing.T) { reconciletesting.WithTriggerBrokerReady(), reconciletesting.WithTriggerSubscribed(), reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyReady(), + ), + }}, + }, { + Name: "Dependency doesn't exist", + Key: triggerKey, + Objects: []runtime.Object{ + makeReadyBroker(), + makeBrokerFilterService(), + makeReadySubscription(), + reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + ), + }, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "TriggerReconcileFailed", "Trigger reconciliation failed: propagating dependency readiness: getting the dependency: cronjobsources.sources.eventing.knative.dev \"test-cronjob-source\" not found"), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + // The first reconciliation will initialize the status conditions. + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + reconciletesting.WithTriggerBrokerReady(), + reconciletesting.WithTriggerSubscribed(), + reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyUnknown("DependencyDoesNotExist", "Dependency does not exist: cronjobsources.sources.eventing.knative.dev \"test-cronjob-source\" not found"), + ), + }}, + }, { + Name: "Dependency not ready", + Key: triggerKey, + Objects: []runtime.Object{ + makeReadyBroker(), + makeBrokerFilterService(), + makeReadySubscription(), + makeNotReadyCronJobSource(), + reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + ), + }, + WantErr: false, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "TriggerReconciled", "Trigger reconciled")}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + // The first reconciliation will initialize the status conditions. + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + reconciletesting.WithTriggerBrokerReady(), + reconciletesting.WithTriggerSubscribed(), + reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyFailed("DependencyNotReady", "Dependency is not ready: "), + ), + }}, + }, { + Name: "Dependency ready", + Key: triggerKey, + Objects: []runtime.Object{ + makeReadyBroker(), + makeBrokerFilterService(), + makeReadySubscription(), + makeReadyCronJobSource(), + reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + ), + }, + WantErr: false, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "TriggerReconciled", "Trigger reconciled"), + Eventf(corev1.EventTypeNormal, "TriggerReadinessChanged", `Trigger "test-trigger" became ready`)}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: reconciletesting.NewTrigger(triggerName, testNS, brokerName, + reconciletesting.WithTriggerUID(triggerUID), + reconciletesting.WithTriggerSubscriberURI(subscriberURI), + // The first reconciliation will initialize the status conditions. + reconciletesting.WithInitTriggerConditions, + reconciletesting.WithDependencyAnnotation(dependencyAnnotation), + reconciletesting.WithTriggerBrokerReady(), + reconciletesting.WithTriggerSubscribed(), + reconciletesting.WithTriggerStatusSubscriberURI(subscriberURI), + reconciletesting.WithTriggerDependencyReady(), ), }}, }, @@ -484,12 +605,13 @@ func TestAllCases(t *testing.T) { defer logtesting.ClearAll() table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler { return &Reconciler{ - Base: reconciler.NewBase(ctx, controllerAgentName, cmw), - triggerLister: listers.GetTriggerLister(), - subscriptionLister: listers.GetSubscriptionLister(), - brokerLister: listers.GetBrokerLister(), - serviceLister: listers.GetK8sServiceLister(), - resourceTracker: &MockResourceTracker{}, + Base: reconciler.NewBase(ctx, controllerAgentName, cmw), + triggerLister: listers.GetTriggerLister(), + subscriptionLister: listers.GetSubscriptionLister(), + brokerLister: listers.GetBrokerLister(), + serviceLister: listers.GetK8sServiceLister(), + resourceTracker: &MockResourceTracker{}, + kresourceInformerFactory: KResourceTypedInformerFactory(ctx), } }, false, @@ -635,6 +757,27 @@ func makeNotReadySubscription() *messagingv1alpha1.Subscription { return s } +func makeNotReadyCronJobSource() *sourcesv1alpha1.CronJobSource { + return NewCronJobSource(cronJobSourceName, testNS, WithCronJobApiVersion(cronJobSourceAPIVersion), WithCronJobSourceSinkNotFound) +} + +func makeReadyCronJobSource() *sourcesv1alpha1.CronJobSource { + return NewCronJobSource(cronJobSourceName, testNS, + WithCronJobApiVersion(cronJobSourceAPIVersion), + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &brokerRef, + }), + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithValidCronJobSourceResources, + WithCronJobSourceDeployed, + WithCronJobSourceEventType, + WithCronJobSourceSink(sinkURI), + ) +} + func getOwnerReference() metav1.OwnerReference { return metav1.OwnerReference{ APIVersion: v1alpha1.SchemeGroupVersion.String(), diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index 639ecdddf43..f7367890cae 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -3725,6 +3725,213 @@ SOFTWARE. +=========================================================== +Import: knative.dev/eventing/vendor/github.com/knative/pkg + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + =========================================================== Import: knative.dev/eventing/vendor/github.com/mailru/easyjson diff --git a/vendor/github.com/knative/pkg/LICENSE b/vendor/github.com/knative/pkg/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/knative/pkg/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/knative/pkg/apis/duck/cached.go b/vendor/github.com/knative/pkg/apis/duck/cached.go new file mode 100644 index 00000000000..6696bd0bb65 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/cached.go @@ -0,0 +1,72 @@ +/* +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 duck + +import ( + "sync" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" +) + +// CachedInformerFactory implements InformerFactory by delegating to another +// InformerFactory, but memoizing the results. +type CachedInformerFactory struct { + Delegate InformerFactory + + m sync.Mutex + cache map[schema.GroupVersionResource]*result +} + +// Check that CachedInformerFactory implements InformerFactory. +var _ InformerFactory = (*CachedInformerFactory)(nil) + +// Get implements InformerFactory. +func (cif *CachedInformerFactory) Get(gvr schema.GroupVersionResource) (cache.SharedIndexInformer, cache.GenericLister, error) { + cif.m.Lock() + if cif.cache == nil { + cif.cache = make(map[schema.GroupVersionResource]*result) + } + elt, ok := cif.cache[gvr] + if !ok { + elt = &result{} + elt.init = func() { + elt.inf, elt.lister, elt.err = cif.Delegate.Get(gvr) + } + cif.cache[gvr] = elt + } + // If this were done via "defer", then TestDifferentGVRs will fail. + cif.m.Unlock() + + // The call to the delegate could be slow because it syncs informers, so do + // this outside of the main lock. + return elt.Get() +} + +type result struct { + sync.Once + init func() + + inf cache.SharedIndexInformer + lister cache.GenericLister + err error +} + +func (t *result) Get() (cache.SharedIndexInformer, cache.GenericLister, error) { + t.Do(t.init) + return t.inf, t.lister, t.err +} diff --git a/vendor/github.com/knative/pkg/apis/duck/doc.go b/vendor/github.com/knative/pkg/apis/duck/doc.go new file mode 100644 index 00000000000..9188bd29c4e --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/doc.go @@ -0,0 +1,23 @@ +/* +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 duck defines logic for defining and consuming "duck typed" +// Kubernetes resources. Producers define partial resource definitions +// that resource authors may choose to implement to interoperate with +// consumers of these "duck typed" interfaces. +// For more information see: +// https://docs.google.com/document/d/16j8C91jML4fQRQPhnHihNJUJDcbvW0RM1YAX2REHgyY/edit# +package duck diff --git a/vendor/github.com/knative/pkg/apis/duck/enqueue.go b/vendor/github.com/knative/pkg/apis/duck/enqueue.go new file mode 100644 index 00000000000..1ef966ec741 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/enqueue.go @@ -0,0 +1,44 @@ +/* +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 duck + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" +) + +// EnqueueInformerFactory implements InformerFactory by delegating to another +// InformerFactory, but attaching a ResourceEventHandler to the informer. +type EnqueueInformerFactory struct { + Delegate InformerFactory + + EventHandler cache.ResourceEventHandler +} + +// Check that EnqueueInformerFactory implements InformerFactory. +var _ InformerFactory = (*EnqueueInformerFactory)(nil) + +// Get implements InformerFactory. +func (cif *EnqueueInformerFactory) Get(gvr schema.GroupVersionResource) (cache.SharedIndexInformer, cache.GenericLister, error) { + inf, lister, err := cif.Delegate.Get(gvr) + if err != nil { + return nil, nil, err + } + // If there is an informer, attach our event handler. + inf.AddEventHandler(cif.EventHandler) + return inf, lister, nil +} diff --git a/vendor/github.com/knative/pkg/apis/duck/interface.go b/vendor/github.com/knative/pkg/apis/duck/interface.go new file mode 100644 index 00000000000..f99a636339e --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/interface.go @@ -0,0 +1,28 @@ +/* +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 duck + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" +) + +// InformerFactory is used to create Informer/Lister pairs for a schema.GroupVersionResource +type InformerFactory interface { + // Get returns a synced Informer/Lister pair for the provided schema.GroupVersionResource. + Get(schema.GroupVersionResource) (cache.SharedIndexInformer, cache.GenericLister, error) +} diff --git a/vendor/github.com/knative/pkg/apis/duck/patch.go b/vendor/github.com/knative/pkg/apis/duck/patch.go new file mode 100644 index 00000000000..386aa1f32eb --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/patch.go @@ -0,0 +1,60 @@ +/* +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 duck + +import ( + "encoding/json" + + jsonmergepatch "github.com/evanphx/json-patch" + "github.com/mattbaird/jsonpatch" +) + +func marshallBeforeAfter(before, after interface{}) ([]byte, []byte, error) { + rawBefore, err := json.Marshal(before) + if err != nil { + return nil, nil, err + } + + rawAfter, err := json.Marshal(after) + if err != nil { + return rawBefore, nil, err + } + + return rawBefore, rawAfter, nil +} + +func CreateMergePatch(before, after interface{}) ([]byte, error) { + rawBefore, rawAfter, err := marshallBeforeAfter(before, after) + if err != nil { + return nil, err + } + return jsonmergepatch.CreateMergePatch(rawBefore, rawAfter) +} + +func CreatePatch(before, after interface{}) (JSONPatch, error) { + rawBefore, rawAfter, err := marshallBeforeAfter(before, after) + if err != nil { + return nil, err + } + return jsonpatch.CreatePatch(rawBefore, rawAfter) +} + +type JSONPatch []jsonpatch.JsonPatchOperation + +func (p JSONPatch) MarshalJSON() ([]byte, error) { + return json.Marshal([]jsonpatch.JsonPatchOperation(p)) +} diff --git a/vendor/github.com/knative/pkg/apis/duck/proxy.go b/vendor/github.com/knative/pkg/apis/duck/proxy.go new file mode 100644 index 00000000000..85a795c361a --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/proxy.go @@ -0,0 +1,74 @@ +/* +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 duck + +import ( + "sync" + + "k8s.io/apimachinery/pkg/watch" +) + +// NewProxyWatcher is based on the same concept from Kubernetes apimachinery in 1.12 here: +// https://github.com/kubernetes/apimachinery/blob/c6dd271be/pkg/watch/watch.go#L272 +// Replace this copy once we've update our client libraries. + +// proxyWatcher lets you wrap your channel in watch.Interface. Threadsafe. +type proxyWatcher struct { + result chan watch.Event + stopCh chan struct{} + + mutex sync.Mutex + stopped bool +} + +var _ watch.Interface = (*proxyWatcher)(nil) + +// NewProxyWatcher creates new proxyWatcher by wrapping a channel +func NewProxyWatcher(ch chan watch.Event) watch.Interface { + return &proxyWatcher{ + result: ch, + stopCh: make(chan struct{}), + stopped: false, + } +} + +// Stop implements Interface +func (pw *proxyWatcher) Stop() { + pw.mutex.Lock() + defer pw.mutex.Unlock() + if !pw.stopped { + pw.stopped = true + close(pw.stopCh) + } +} + +// Stopping returns true if Stop() has been called +func (pw *proxyWatcher) Stopping() bool { + pw.mutex.Lock() + defer pw.mutex.Unlock() + return pw.stopped +} + +// ResultChan implements watch.Interface +func (pw *proxyWatcher) ResultChan() <-chan watch.Event { + return pw.result +} + +// StopChan returns stop channel +func (pw *proxyWatcher) StopChan() <-chan struct{} { + return pw.stopCh +} diff --git a/vendor/github.com/knative/pkg/apis/duck/register.go b/vendor/github.com/knative/pkg/apis/duck/register.go new file mode 100644 index 00000000000..d10adc21ce7 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/register.go @@ -0,0 +1,21 @@ +/* +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 duck + +const ( + GroupName = "duck.knative.dev" +) diff --git a/vendor/github.com/knative/pkg/apis/duck/typed.go b/vendor/github.com/knative/pkg/apis/duck/typed.go new file mode 100644 index 00000000000..8931866366e --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/typed.go @@ -0,0 +1,133 @@ +/* +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 duck + +import ( + "fmt" + "net/http" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/tools/cache" + + "knative.dev/pkg/apis" +) + +// TypedInformerFactory implements InformerFactory such that the elements +// tracked by the informer/lister have the type of the canonical "obj". +type TypedInformerFactory struct { + Client dynamic.Interface + Type apis.Listable + ResyncPeriod time.Duration + StopChannel <-chan struct{} +} + +// Check that TypedInformerFactory implements InformerFactory. +var _ InformerFactory = (*TypedInformerFactory)(nil) + +// Get implements InformerFactory. +func (dif *TypedInformerFactory) Get(gvr schema.GroupVersionResource) (cache.SharedIndexInformer, cache.GenericLister, error) { + listObj := dif.Type.GetListType() + lw := &cache.ListWatch{ + ListFunc: asStructuredLister(dif.Client.Resource(gvr).List, listObj), + WatchFunc: AsStructuredWatcher(dif.Client.Resource(gvr).Watch, dif.Type), + } + inf := cache.NewSharedIndexInformer(lw, dif.Type, dif.ResyncPeriod, cache.Indexers{ + cache.NamespaceIndex: cache.MetaNamespaceIndexFunc, + }) + + lister := cache.NewGenericLister(inf.GetIndexer(), gvr.GroupResource()) + + go inf.Run(dif.StopChannel) + + if ok := cache.WaitForCacheSync(dif.StopChannel, inf.HasSynced); !ok { + return nil, nil, fmt.Errorf("failed starting shared index informer for %v with type %T", gvr, dif.Type) + } + + return inf, lister, nil +} + +type unstructuredLister func(metav1.ListOptions) (*unstructured.UnstructuredList, error) + +func asStructuredLister(ulist unstructuredLister, listObj runtime.Object) cache.ListFunc { + return func(opts metav1.ListOptions) (runtime.Object, error) { + ul, err := ulist(opts) + if err != nil { + return nil, err + } + res := listObj.DeepCopyObject() + if err := FromUnstructured(ul, res); err != nil { + return nil, err + } + return res, nil + } +} + +// AsStructuredWatcher is public for testing only. +// TODO(mattmoor): Move tests for this to `package duck` and make private. +func AsStructuredWatcher(wf cache.WatchFunc, obj runtime.Object) cache.WatchFunc { + return func(lo metav1.ListOptions) (watch.Interface, error) { + uw, err := wf(lo) + if err != nil { + return nil, err + } + structuredCh := make(chan watch.Event) + go func() { + defer close(structuredCh) + unstructuredCh := uw.ResultChan() + for ue := range unstructuredCh { + unstructuredObj, ok := ue.Object.(*unstructured.Unstructured) + if !ok { + // If it isn't an unstructured object, then forward the + // event as-is. This is likely to happen when the event's + // Type is an Error. + structuredCh <- ue + continue + } + structuredObj := obj.DeepCopyObject() + + err := FromUnstructured(unstructuredObj, structuredObj) + if err != nil { + // Pass back an error indicating that the object we got + // was invalid. + structuredCh <- watch.Event{ + Type: watch.Error, + Object: &metav1.Status{ + Status: metav1.StatusFailure, + Code: http.StatusUnprocessableEntity, + Reason: metav1.StatusReasonInvalid, + Message: err.Error(), + }, + } + continue + } + // Send the structured event. + structuredCh <- watch.Event{ + Type: ue.Type, + Object: structuredObj, + } + } + }() + + return NewProxyWatcher(structuredCh), nil + } +} diff --git a/vendor/github.com/knative/pkg/apis/duck/unstructured.go b/vendor/github.com/knative/pkg/apis/duck/unstructured.go new file mode 100644 index 00000000000..98b3cef9469 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/unstructured.go @@ -0,0 +1,37 @@ +/* +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 duck + +import ( + "encoding/json" +) + +// Marshallable is implementated by the Unstructured K8s types. +type Marshalable interface { + MarshalJSON() ([]byte, error) +} + +// FromUnstructured takes unstructured object from (say from client-go/dynamic) and +// converts it into our duck types. +func FromUnstructured(obj Marshalable, target interface{}) error { + // Use the unstructured marshaller to ensure it's proper JSON + raw, err := obj.MarshalJSON() + if err != nil { + return err + } + return json.Unmarshal(raw, &target) +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/addressable_types.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/addressable_types.go new file mode 100644 index 00000000000..2b5fcbd9e2e --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/addressable_types.go @@ -0,0 +1,113 @@ +/* +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/v1beta1" +) + +// Addressable provides a generic mechanism for a custom resource +// definition to indicate a destination for message delivery. + +// Addressable is the schema for the destination information. This is +// typically stored in the object's `status`, as this information may +// be generated by the controller. +type Addressable struct { + v1beta1.Addressable `json:",omitempty"` + + Hostname string `json:"hostname,omitempty"` +} + +// Addressable is an Implementable "duck type". +var _ duck.Implementable = (*Addressable)(nil) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AddressableType is a skeleton type wrapping Addressable in the manner we expect +// resource writers defining compatible resources to embed it. We will +// typically use this type to deserialize Addressable ObjectReferences and +// access the Addressable data. This is not a real resource. +type AddressableType struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status AddressStatus `json:"status"` +} + +// AddressStatus shows how we expect folks to embed Addressable in +// their Status field. +type AddressStatus struct { + Address *Addressable `json:"address,omitempty"` +} + +var ( + // Verify AddressableType resources meet duck contracts. + _ duck.Populatable = (*AddressableType)(nil) + _ apis.Listable = (*AddressableType)(nil) +) + +// GetFullType implements duck.Implementable +func (*Addressable) GetFullType() duck.Populatable { + return &AddressableType{} +} + +// Populate implements duck.Populatable +func (t *AddressableType) Populate() { + t.Status = AddressStatus{ + &Addressable{ + // Populate ALL fields + Addressable: v1beta1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "foo.bar.svc.cluster.local", + }, + }, + Hostname: "this is not empty", + }, + } +} + +func (a Addressable) GetURL() apis.URL { + if a.URL != nil { + return *a.URL + } + return apis.URL{ + Scheme: "http", + Host: a.Hostname, + } +} + +// GetListType implements apis.Listable +func (*AddressableType) GetListType() runtime.Object { + return &AddressableTypeList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AddressableTypeList is a list of AddressableType resources +type AddressableTypeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []AddressableType `json:"items"` +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/condition_set.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/condition_set.go new file mode 100644 index 00000000000..04c1c7317d5 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/condition_set.go @@ -0,0 +1,384 @@ +/* +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 ( + "reflect" + "sort" + "time" + + "fmt" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +// Conditions is the interface for a Resource that implements the getter and +// setter for accessing a Condition collection. +// +k8s:deepcopy-gen=true +type ConditionsAccessor interface { + GetConditions() Conditions + SetConditions(Conditions) +} + +// ConditionSet is an abstract collection of the possible ConditionType values +// that a particular resource might expose. It also holds the "happy condition" +// for that resource, which we define to be one of Ready or Succeeded depending +// on whether it is a Living or Batch process respectively. +// +k8s:deepcopy-gen=false +type ConditionSet struct { + happy ConditionType + dependents []ConditionType +} + +// ConditionManager allows a resource to operate on its Conditions using higher +// order operations. +type ConditionManager interface { + // IsHappy looks at the happy condition and returns true if that condition is + // set to true. + IsHappy() bool + + // GetCondition finds and returns the Condition that matches the ConditionType + // previously set on Conditions. + GetCondition(t ConditionType) *Condition + + // SetCondition sets or updates the Condition on Conditions for Condition.Type. + // If there is an update, Conditions are stored back sorted. + SetCondition(new Condition) + + // MarkTrue sets the status of t to true, and then marks the happy condition to + // true if all dependents are true. + MarkTrue(t ConditionType) + + // MarkUnknown sets the status of t to Unknown and also sets the happy condition + // to Unknown if no other dependent condition is in an error state. + MarkUnknown(t ConditionType, reason, messageFormat string, messageA ...interface{}) + + // MarkFalse sets the status of t and the happy condition to False. + MarkFalse(t ConditionType, reason, messageFormat string, messageA ...interface{}) + + // InitializeConditions updates all Conditions in the ConditionSet to Unknown + // if not set. + InitializeConditions() + + // InitializeCondition updates a Condition to Unknown if not set. + InitializeCondition(t ConditionType) +} + +// NewLivingConditionSet returns a ConditionSet to hold the conditions for the +// living resource. ConditionReady is used as the happy condition. +// The set of condition types provided are those of the terminal subconditions. +func NewLivingConditionSet(d ...ConditionType) ConditionSet { + return newConditionSet(ConditionReady, d...) +} + +// NewBatchConditionSet returns a ConditionSet to hold the conditions for the +// batch resource. ConditionSucceeded is used as the happy condition. +// The set of condition types provided are those of the terminal subconditions. +func NewBatchConditionSet(d ...ConditionType) ConditionSet { + return newConditionSet(ConditionSucceeded, d...) +} + +// newConditionSet returns a ConditionSet to hold the conditions that are +// important for the caller. The first ConditionType is the overarching status +// for that will be used to signal the resources' status is Ready or Succeeded. +func newConditionSet(happy ConditionType, dependents ...ConditionType) ConditionSet { + var deps []ConditionType + for _, d := range dependents { + // Skip duplicates + if d == happy || contains(deps, d) { + continue + } + deps = append(deps, d) + } + return ConditionSet{ + happy: happy, + dependents: deps, + } +} + +func contains(ct []ConditionType, t ConditionType) bool { + for _, c := range ct { + if c == t { + return true + } + } + return false +} + +// Check that conditionsImpl implements ConditionManager. +var _ ConditionManager = (*conditionsImpl)(nil) + +// conditionsImpl implements the helper methods for evaluating Conditions. +// +k8s:deepcopy-gen=false +type conditionsImpl struct { + ConditionSet + accessor ConditionsAccessor +} + +// Manage creates a ConditionManager from a accessor object using the original +// ConditionSet as a reference. Status must be or point to a struct. +func (r ConditionSet) Manage(status interface{}) ConditionManager { + + // First try to see if status implements ConditionsAccessor + ca, ok := status.(ConditionsAccessor) + if ok { + return conditionsImpl{ + accessor: ca, + ConditionSet: r, + } + } + + // Next see if we can use reflection to gain access to Conditions + ca = NewReflectedConditionsAccessor(status) + if ca != nil { + return conditionsImpl{ + accessor: ca, + ConditionSet: r, + } + } + + // We tried. This object is not understood by the condition manager. + //panic(fmt.Sprintf("Error converting %T into a ConditionsAccessor", status)) + // TODO: not sure which way. using panic above means passing nil status panics the system. + return conditionsImpl{ + ConditionSet: r, + } +} + +// IsHappy looks at the happy condition and returns true if that condition is +// set to true. +func (r conditionsImpl) IsHappy() bool { + if c := r.GetCondition(r.happy); c == nil || !c.IsTrue() { + return false + } + return true +} + +// GetCondition finds and returns the Condition that matches the ConditionType +// previously set on Conditions. +func (r conditionsImpl) GetCondition(t ConditionType) *Condition { + if r.accessor == nil { + return nil + } + + for _, c := range r.accessor.GetConditions() { + if c.Type == t { + return &c + } + } + return nil +} + +// SetCondition sets or updates the Condition on Conditions for Condition.Type. +// If there is an update, Conditions are stored back sorted. +func (r conditionsImpl) SetCondition(new Condition) { + if r.accessor == nil { + return + } + t := new.Type + var conditions Conditions + for _, c := range r.accessor.GetConditions() { + if c.Type != t { + conditions = append(conditions, c) + } else { + // If we'd only update the LastTransitionTime, then return. + new.LastTransitionTime = c.LastTransitionTime + if reflect.DeepEqual(&new, &c) { + return + } + } + } + new.LastTransitionTime = apis.VolatileTime{Inner: metav1.NewTime(time.Now())} + conditions = append(conditions, new) + // Sorted for convenience of the consumer, i.e. kubectl. + sort.Slice(conditions, func(i, j int) bool { return conditions[i].Type < conditions[j].Type }) + r.accessor.SetConditions(conditions) +} + +func (r conditionsImpl) isTerminal(t ConditionType) bool { + for _, cond := range r.dependents { + if cond == t { + return true + } + } + + return t == r.happy +} + +func (r conditionsImpl) severity(t ConditionType) ConditionSeverity { + if r.isTerminal(t) { + return ConditionSeverityError + } + return ConditionSeverityInfo +} + +// MarkTrue sets the status of t to true, and then marks the happy condition to +// true if all other dependents are also true. +func (r conditionsImpl) MarkTrue(t ConditionType) { + // set the specified condition + r.SetCondition(Condition{ + Type: t, + Status: corev1.ConditionTrue, + Severity: r.severity(t), + }) + + // check the dependents. + for _, cond := range r.dependents { + c := r.GetCondition(cond) + // Failed or Unknown conditions trump true conditions + if !c.IsTrue() { + return + } + } + + // set the happy condition + r.SetCondition(Condition{ + Type: r.happy, + Status: corev1.ConditionTrue, + Severity: r.severity(r.happy), + }) +} + +// MarkUnknown sets the status of t to Unknown and also sets the happy condition +// to Unknown if no other dependent condition is in an error state. +func (r conditionsImpl) MarkUnknown(t ConditionType, reason, messageFormat string, messageA ...interface{}) { + // set the specified condition + r.SetCondition(Condition{ + Type: t, + Status: corev1.ConditionUnknown, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + Severity: r.severity(t), + }) + + // check the dependents. + isDependent := false + for _, cond := range r.dependents { + c := r.GetCondition(cond) + // Failed conditions trump Unknown conditions + if c.IsFalse() { + // Double check that the happy condition is also false. + happy := r.GetCondition(r.happy) + if !happy.IsFalse() { + r.MarkFalse(r.happy, reason, messageFormat, messageA...) + } + return + } + if cond == t { + isDependent = true + } + } + + if isDependent { + // set the happy condition, if it is one of our dependent subconditions. + r.SetCondition(Condition{ + Type: r.happy, + Status: corev1.ConditionUnknown, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + Severity: r.severity(r.happy), + }) + } +} + +// MarkFalse sets the status of t and the happy condition to False. +func (r conditionsImpl) MarkFalse(t ConditionType, reason, messageFormat string, messageA ...interface{}) { + types := []ConditionType{t} + for _, cond := range r.dependents { + if cond == t { + types = append(types, r.happy) + } + } + + for _, t := range types { + r.SetCondition(Condition{ + Type: t, + Status: corev1.ConditionFalse, + Reason: reason, + Message: fmt.Sprintf(messageFormat, messageA...), + Severity: r.severity(t), + }) + } +} + +// InitializeConditions updates all Conditions in the ConditionSet to Unknown +// if not set. +func (r conditionsImpl) InitializeConditions() { + for _, t := range r.dependents { + r.InitializeCondition(t) + } + r.InitializeCondition(r.happy) +} + +// InitializeCondition updates a Condition to Unknown if not set. +func (r conditionsImpl) InitializeCondition(t ConditionType) { + if c := r.GetCondition(t); c == nil { + r.SetCondition(Condition{ + Type: t, + Status: corev1.ConditionUnknown, + Severity: r.severity(t), + }) + } +} + +// NewReflectedConditionsAccessor uses reflection to return a ConditionsAccessor +// to access the field called "Conditions". +func NewReflectedConditionsAccessor(status interface{}) ConditionsAccessor { + statusValue := reflect.Indirect(reflect.ValueOf(status)) + + // If status is not a struct, don't even try to use it. + if statusValue.Kind() != reflect.Struct { + return nil + } + + conditionsField := statusValue.FieldByName("Conditions") + + if conditionsField.IsValid() && conditionsField.CanInterface() && conditionsField.CanSet() { + if _, ok := conditionsField.Interface().(Conditions); ok { + return &reflectedConditionsAccessor{ + conditions: conditionsField, + } + } + } + return nil +} + +// reflectedConditionsAccessor is an internal wrapper object to act as the +// ConditionsAccessor for status objects that do not implement ConditionsAccessor +// directly, but do expose the field using the "Conditions" field name. +type reflectedConditionsAccessor struct { + conditions reflect.Value +} + +// GetConditions uses reflection to return Conditions from the held status object. +func (r *reflectedConditionsAccessor) GetConditions() Conditions { + if r != nil && r.conditions.IsValid() && r.conditions.CanInterface() { + if conditions, ok := r.conditions.Interface().(Conditions); ok { + return conditions + } + } + return Conditions(nil) +} + +// SetConditions uses reflection to set Conditions on the held status object. +func (r *reflectedConditionsAccessor) SetConditions(conditions Conditions) { + if r != nil && r.conditions.IsValid() && r.conditions.CanSet() { + r.conditions.Set(reflect.ValueOf(conditions)) + } +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/conditions_types.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/conditions_types.go new file mode 100644 index 00000000000..12003a58633 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/conditions_types.go @@ -0,0 +1,202 @@ +/* +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 ( + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" +) + +// Conditions is the schema for the conditions portion of the payload +type Conditions []Condition + +// ConditionType is a camel-cased condition type. +type ConditionType string + +const ( + // ConditionReady specifies that the resource is ready. + // For long-running resources. + ConditionReady ConditionType = "Ready" + // ConditionSucceeded specifies that the resource has finished. + // For resource which run to completion. + ConditionSucceeded ConditionType = "Succeeded" +) + +// ConditionSeverity expresses the severity of a Condition Type failing. +type ConditionSeverity string + +const ( + // ConditionSeverityError specifies that a failure of a condition type + // should be viewed as an error. As "Error" is the default for conditions + // we use the empty string (coupled with omitempty) to avoid confusion in + // the case where the condition is in state "True" (aka nothing is wrong). + ConditionSeverityError ConditionSeverity = "" + // ConditionSeverityWarning specifies that a failure of a condition type + // should be viewed as a warning, but that things could still work. + ConditionSeverityWarning ConditionSeverity = "Warning" + // ConditionSeverityInfo specifies that a failure of a condition type + // should be viewed as purely informational, and that things could still work. + ConditionSeverityInfo ConditionSeverity = "Info" +) + +// Conditions defines a readiness condition for a Knative resource. +// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties +// +k8s:deepcopy-gen=true +type Condition struct { + // Type of condition. + // +required + Type ConditionType `json:"type" description:"type of status condition"` + + // Status of the condition, one of True, False, Unknown. + // +required + Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` + + // Severity with which to treat failures of this type of condition. + // When this is not specified, it defaults to Error. + // +optional + Severity ConditionSeverity `json:"severity,omitempty" description:"how to interpret failures of this condition, one of Error, Warning, Info"` + + // LastTransitionTime is the last time the condition transitioned 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). + // +optional + LastTransitionTime apis.VolatileTime `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"` + + // The reason for the condition's last transition. + // +optional + Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"` + + // A human readable message indicating details about the transition. + // +optional + Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"` +} + +// IsTrue is true if the condition is True +func (c *Condition) IsTrue() bool { + if c == nil { + return false + } + return c.Status == corev1.ConditionTrue +} + +// IsFalse is true if the condition is False +func (c *Condition) IsFalse() bool { + if c == nil { + return false + } + return c.Status == corev1.ConditionFalse +} + +// IsUnknown is true if the condition is Unknown +func (c *Condition) IsUnknown() bool { + if c == nil { + return true + } + return c.Status == corev1.ConditionUnknown +} + +// Conditions is an Implementable "duck type". +var _ duck.Implementable = (*Conditions)(nil) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KResource is a skeleton type wrapping Conditions in the manner we expect +// resource writers defining compatible resources to embed it. We will +// typically use this type to deserialize Conditions ObjectReferences and +// access the Conditions data. This is not a real resource. +type KResource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status Status `json:"status"` +} + +// Status shows how we expect folks to embed Conditions in +// their Status field. +// WARNING: Adding fields to this struct will add them to all Knative resources. +type Status struct { + // ObservedGeneration is the 'Generation' of the Service that + // was last processed by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions the latest available observations of a resource's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +// TODO: KResourceStatus is added for backwards compatibility for <= 0.4.0 releases. Remove later. +// KResourceStatus [Deprecated] use Status directly. Will be deleted ~0.6.0 release. +type KResourceStatus Status + +// In order for Conditions to be Implementable, KResource must be Populatable. +var _ duck.Populatable = (*KResource)(nil) + +// Ensure KResource satisfies apis.Listable +var _ apis.Listable = (*KResource)(nil) + +// GetFullType implements duck.Implementable +func (*Conditions) GetFullType() duck.Populatable { + return &KResource{} +} + +// GetCondition fetches the condition of the specified type. +func (s *Status) GetCondition(t ConditionType) *Condition { + for _, cond := range s.Conditions { + if cond.Type == t { + return &cond + } + } + return nil +} + +// Populate implements duck.Populatable +func (t *KResource) Populate() { + t.Status.ObservedGeneration = 42 + t.Status.Conditions = Conditions{{ + // Populate ALL fields + Type: "Birthday", + Status: corev1.ConditionTrue, + LastTransitionTime: apis.VolatileTime{Inner: metav1.NewTime(time.Date(1984, 02, 28, 18, 52, 00, 00, time.UTC))}, + Reason: "Celebrate", + Message: "n3wScott, find your party hat :tada:", + }} +} + +// GetListType implements apis.Listable +func (*KResource) GetListType() runtime.Object { + return &KResourceList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KResourceList is a list of KResource resources +type KResourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []KResource `json:"items"` +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/doc.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/doc.go new file mode 100644 index 00000000000..3638eb7a308 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/doc.go @@ -0,0 +1,23 @@ +/* +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. +*/ + +// Api versions allow the api contract for a resource to be changed while keeping +// backward compatibility by support multiple concurrent versions +// of the same resource + +// +k8s:deepcopy-gen=package +// +groupName=duck.knative.dev +package v1alpha1 diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/legacy_targetable_types.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/legacy_targetable_types.go new file mode 100644 index 00000000000..27e7c3daaae --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/legacy_targetable_types.go @@ -0,0 +1,95 @@ +/* +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" +) + +// LegacyTargetable left around until we migrate to Addressable in the +// dependent resources. Addressable has more structure in the way it +// defines the fields. LegacyTargetable only assumed a single string +// in the Status field and we're moving towards defining proper structs +// under Status rather than strings. +// This is to support existing resources until they migrate. +// +// Do not use this for anything new, use Addressable + +// LegacyTargetable is the old schema for the addressable portion +// of the payload +// +// For new resources use Addressable. +type LegacyTargetable struct { + DomainInternal string `json:"domainInternal,omitempty"` +} + +// LegacyTargetable is an Implementable "duck type". +var _ duck.Implementable = (*LegacyTargetable)(nil) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// LegacyTarget is a skeleton type wrapping LegacyTargetable in the manner we +// want to support unless they get migrated into supporting Legacy. +// We will typically use this type to deserialize LegacyTargetable +// ObjectReferences and access the LegacyTargetable data. This is not a +// real resource. +// ** Do not use this for any new resources ** +type LegacyTarget struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status LegacyTargetable `json:"status"` +} + +// In order for LegacyTargetable to be Implementable, LegacyTarget must be Populatable. +var _ duck.Populatable = (*LegacyTarget)(nil) + +// Ensure LegacyTarget satisfies apis.Listable +var _ apis.Listable = (*LegacyTarget)(nil) + +// GetFullType implements duck.Implementable +func (*LegacyTargetable) GetFullType() duck.Populatable { + return &LegacyTarget{} +} + +// Populate implements duck.Populatable +func (t *LegacyTarget) Populate() { + t.Status = LegacyTargetable{ + // Populate ALL fields + DomainInternal: "this is not empty", + } +} + +// GetListType implements apis.Listable +func (*LegacyTarget) GetListType() runtime.Object { + return &LegacyTargetList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// LegacyTargetList is a list of LegacyTarget resources +type LegacyTargetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []LegacyTarget `json:"items"` +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/register.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/register.go new file mode 100644 index 00000000000..a66a2c38d48 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/register.go @@ -0,0 +1,59 @@ +/* +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis/duck" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: duck.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes( + SchemeGroupVersion, + &KResource{}, + (&KResource{}).GetListType(), + &AddressableType{}, + (&AddressableType{}).GetListType(), + &Target{}, + (&Target{}).GetListType(), + &LegacyTarget{}, + (&LegacyTarget{}).GetListType(), + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/retired_targetable_types.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/retired_targetable_types.go new file mode 100644 index 00000000000..9306336d277 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/retired_targetable_types.go @@ -0,0 +1,99 @@ +/* +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" +) + +// Targetable is an earlier version of the Callable interface. +// Callable is a higher-level interface which implements Addressable +// but further promises that the destination may synchronously return +// response messages in reply to a message. +// +// Targetable implementations should instead implement Addressable and +// include an `eventing.knative.dev/returns=any` annotation. + +// Targetable is retired; implement Addressable for now. +type Targetable struct { + DomainInternal string `json:"domainInternal,omitempty"` +} + +// Targetable is an Implementable "duck type". +var _ duck.Implementable = (*Targetable)(nil) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Target is a skeleton type wrapping Targetable in the manner we expect +// resource writers defining compatible resources to embed it. We will +// typically use this type to deserialize Targetable ObjectReferences and +// access the Targetable data. This is not a real resource. +type Target struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status TargetStatus `json:"status"` +} + +// TargetStatus shows how we expect folks to embed Targetable in +// their Status field. +type TargetStatus struct { + Targetable *Targetable `json:"targetable,omitempty"` +} + +var ( + // In order for Targetable to be Implementable, Target must be Populatable. + _ duck.Populatable = (*Target)(nil) + + // Ensure Target satisfies apis.Listable + _ apis.Listable = (*Target)(nil) +) + +// GetFullType implements duck.Implementable +func (*Targetable) GetFullType() duck.Populatable { + return &Target{} +} + +// Populate implements duck.Populatable +func (t *Target) Populate() { + t.Status = TargetStatus{ + &Targetable{ + // Populate ALL fields + DomainInternal: "this is not empty", + }, + } +} + +// GetListType implements apis.Listable +func (*Target) GetListType() runtime.Object { + return &TargetList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TargetList is a list of Target resources +type TargetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Target `json:"items"` +} diff --git a/vendor/github.com/knative/pkg/apis/duck/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..a59e67ce3f1 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,441 @@ +// +build !ignore_autogenerated + +/* +Copyright 2019 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressStatus) DeepCopyInto(out *AddressStatus) { + *out = *in + if in.Address != nil { + in, out := &in.Address, &out.Address + *out = new(Addressable) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressStatus. +func (in *AddressStatus) DeepCopy() *AddressStatus { + if in == nil { + return nil + } + out := new(AddressStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Addressable) DeepCopyInto(out *Addressable) { + *out = *in + in.Addressable.DeepCopyInto(&out.Addressable) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Addressable. +func (in *Addressable) DeepCopy() *Addressable { + if in == nil { + return nil + } + out := new(Addressable) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressableType) DeepCopyInto(out *AddressableType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressableType. +func (in *AddressableType) DeepCopy() *AddressableType { + if in == nil { + return nil + } + out := new(AddressableType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressableType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AddressableTypeList) DeepCopyInto(out *AddressableTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AddressableType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressableTypeList. +func (in *AddressableTypeList) DeepCopy() *AddressableTypeList { + if in == nil { + return nil + } + out := new(AddressableTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AddressableTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Condition) DeepCopyInto(out *Condition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. +func (in *Condition) DeepCopy() *Condition { + if in == nil { + return nil + } + out := new(Condition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Conditions) DeepCopyInto(out *Conditions) { + { + in := &in + *out = make(Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions. +func (in Conditions) DeepCopy() Conditions { + if in == nil { + return nil + } + out := new(Conditions) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KResource) DeepCopyInto(out *KResource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KResource. +func (in *KResource) DeepCopy() *KResource { + if in == nil { + return nil + } + out := new(KResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KResource) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KResourceList) DeepCopyInto(out *KResourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KResource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KResourceList. +func (in *KResourceList) DeepCopy() *KResourceList { + if in == nil { + return nil + } + out := new(KResourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KResourceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KResourceStatus) DeepCopyInto(out *KResourceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KResourceStatus. +func (in *KResourceStatus) DeepCopy() *KResourceStatus { + if in == nil { + return nil + } + out := new(KResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LegacyTarget) DeepCopyInto(out *LegacyTarget) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LegacyTarget. +func (in *LegacyTarget) DeepCopy() *LegacyTarget { + if in == nil { + return nil + } + out := new(LegacyTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LegacyTarget) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LegacyTargetList) DeepCopyInto(out *LegacyTargetList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LegacyTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LegacyTargetList. +func (in *LegacyTargetList) DeepCopy() *LegacyTargetList { + if in == nil { + return nil + } + out := new(LegacyTargetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LegacyTargetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LegacyTargetable) DeepCopyInto(out *LegacyTargetable) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LegacyTargetable. +func (in *LegacyTargetable) DeepCopy() *LegacyTargetable { + if in == nil { + return nil + } + out := new(LegacyTargetable) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Target) DeepCopyInto(out *Target) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. +func (in *Target) DeepCopy() *Target { + if in == nil { + return nil + } + out := new(Target) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Target) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetList) DeepCopyInto(out *TargetList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Target, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetList. +func (in *TargetList) DeepCopy() *TargetList { + if in == nil { + return nil + } + out := new(TargetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TargetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetStatus) DeepCopyInto(out *TargetStatus) { + *out = *in + if in.Targetable != nil { + in, out := &in.Targetable, &out.Targetable + *out = new(Targetable) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetStatus. +func (in *TargetStatus) DeepCopy() *TargetStatus { + if in == nil { + return nil + } + out := new(TargetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Targetable) DeepCopyInto(out *Targetable) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Targetable. +func (in *Targetable) DeepCopy() *Targetable { + if in == nil { + return nil + } + out := new(Targetable) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/knative/pkg/apis/duck/verify.go b/vendor/github.com/knative/pkg/apis/duck/verify.go new file mode 100644 index 00000000000..236a392c7e4 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/verify.go @@ -0,0 +1,110 @@ +/* +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 duck + +import ( + "encoding/json" + "fmt" + + "knative.dev/pkg/kmp" +) + +// Implementable is implemented by the Fooable duck type that consumers +// are expected to embed as a `.status.fooable` field. +type Implementable interface { + // GetFullType returns an instance of a full resource wrapping + // an instance of this Implementable that can populate its fields + // to verify json roundtripping. + GetFullType() Populatable +} + +// Populatable is implemented by a skeleton resource wrapping an Implementable +// duck type. It will generally have TypeMeta, ObjectMeta, and a Status field +// wrapping a Fooable field. +type Populatable interface { + // Populate fills in all possible fields, so that we can verify that + // they roundtrip properly through JSON. + Populate() +} + +// VerifyType verifies that a particular concrete resource properly implements +// the provided Implementable duck type. It is expected that under the resource +// definition implementing a particular "Fooable" that one would write: +// +// type ConcreteResource struct { ... } +// +// // Check that ConcreteResource properly implement Fooable. +// err := duck.VerifyType(&ConcreteResource{}, &something.Fooable{}) +// +// This will return an error if the duck typing is not satisfied. +func VerifyType(instance interface{}, iface Implementable) error { + // Create instances of the full resource for our input and ultimate result + // that we will compare at the end. + input, output := iface.GetFullType(), iface.GetFullType() + + if err := roundTrip(instance, input, output); err != nil { + return err + } + + // Now verify that we were able to roundtrip all of our fields through the type + // we are checking. + if diff, err := kmp.SafeDiff(input, output); err != nil { + return err + } else if diff != "" { + return fmt.Errorf("%T does not implement the duck type %T, the following fields were lost: %s", + instance, iface, diff) + } + return nil +} + +// ConformsToType will return true or false depending on whether a +// concrete resource properly implements the provided Implementable +// duck type. +// +// It will return an error if marshal/unmarshalling fails +func ConformsToType(instance interface{}, iface Implementable) (bool, error) { + input, output := iface.GetFullType(), iface.GetFullType() + + if err := roundTrip(instance, input, output); err != nil { + return false, err + } + + return kmp.SafeEqual(input, output) +} + +func roundTrip(instance interface{}, input, output Populatable) error { + // Populate our input resource with values we will roundtrip. + input.Populate() + + // Serialize the input to JSON and deserialize that into the provided instance + // of the type that we are checking. + if before, err := json.Marshal(input); err != nil { + return fmt.Errorf("error serializing duck type %T error: %s", input, err) + } else if err := json.Unmarshal(before, instance); err != nil { + return fmt.Errorf("error deserializing duck type %T into %T error: %s", input, instance, err) + } + + // Serialize the instance we are checking to JSON and deserialize that into the + // output resource. + if after, err := json.Marshal(instance); err != nil { + return fmt.Errorf("error serializing %T error: %s", instance, err) + } else if err := json.Unmarshal(after, output); err != nil { + return fmt.Errorf("error deserializing %T into duck type %T error: %s", instance, output, err) + } + + return nil +} diff --git a/vendor/github.com/knative/pkg/third_party/mako/LICENSE b/vendor/github.com/knative/pkg/third_party/mako/LICENSE new file mode 100644 index 00000000000..fef7d967815 --- /dev/null +++ b/vendor/github.com/knative/pkg/third_party/mako/LICENSE @@ -0,0 +1,204 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + \ No newline at end of file