knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/testing/duck/testbindable.go (about) 1 /* 2 Copyright 2019 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package duck 18 19 import ( 20 "context" 21 22 corev1 "k8s.io/api/core/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/runtime" 25 "k8s.io/apimachinery/pkg/runtime/schema" 26 "knative.dev/pkg/apis" 27 "knative.dev/pkg/apis/duck" 28 duckv1 "knative.dev/pkg/apis/duck/v1" 29 duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" 30 "knative.dev/pkg/tracker" 31 ) 32 33 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 34 35 // TestBindable is a simple resource that's compatible with our webhook 36 type TestBindable struct { 37 metav1.TypeMeta `json:",inline"` 38 metav1.ObjectMeta `json:"metadata,omitempty"` 39 40 Spec TestBindableSpec `json:"spec,omitempty"` 41 Status TestBindableStatus `json:"status,omitempty"` 42 } 43 44 // Check that TestBindable may be validated and defaulted. 45 var ( 46 _ apis.Listable = (*TestBindable)(nil) 47 _ duck.Bindable = (*TestBindable)(nil) 48 ) 49 50 // TestBindableSpec represents test resource spec. 51 type TestBindableSpec struct { 52 duckv1alpha1.BindingSpec `json:",inline"` 53 54 Foo string `json:"foo"` 55 } 56 57 // TestBindableStatus represents the status of our test binding. 58 type TestBindableStatus struct { 59 duckv1.Status `json:",inline"` 60 } 61 62 // GetGroupVersionKind returns the GroupVersionKind. 63 func (tb *TestBindable) GetGroupVersionKind() schema.GroupVersionKind { 64 return SchemeGroupVersion.WithKind("TestBindable") 65 } 66 67 // GetUntypedSpec returns the spec of the resource. 68 func (tb *TestBindable) GetUntypedSpec() interface{} { 69 return tb.Spec 70 } 71 72 // GetListType implements apis.Listable 73 func (tb *TestBindable) GetListType() runtime.Object { 74 return &TestBindableList{} 75 } 76 77 // GetSubject implements psbinding.Bindable 78 func (tb *TestBindable) GetSubject() tracker.Reference { 79 return tb.Spec.Subject 80 } 81 82 // GetBindingStatus implements psbinding.Bindable 83 func (tb *TestBindable) GetBindingStatus() duck.BindableStatus { 84 return &tb.Status 85 } 86 87 // SetObservedGeneration implements psbinding.BindableStatus 88 func (tbs *TestBindableStatus) SetObservedGeneration(gen int64) { 89 tbs.ObservedGeneration = gen 90 } 91 92 // Do implements psbinding.Bindable 93 func (tb *TestBindable) Do(ctx context.Context, ps *duckv1.WithPod) { 94 // First undo so that we can just unconditionally append below. 95 tb.Undo(ctx, ps) 96 97 spec := ps.Spec.Template.Spec 98 for i := range spec.InitContainers { 99 spec.InitContainers[i].Env = append(spec.InitContainers[i].Env, corev1.EnvVar{ 100 Name: "FOO", 101 Value: tb.Spec.Foo, 102 }) 103 } 104 for i := range spec.Containers { 105 spec.Containers[i].Env = append(spec.Containers[i].Env, corev1.EnvVar{ 106 Name: "FOO", 107 Value: tb.Spec.Foo, 108 }) 109 } 110 } 111 112 func (tb *TestBindable) Undo(ctx context.Context, ps *duckv1.WithPod) { 113 spec := ps.Spec.Template.Spec 114 for i, c := range spec.InitContainers { 115 for j, ev := range c.Env { 116 if ev.Name == "FOO" { 117 spec.InitContainers[i].Env = append(spec.InitContainers[i].Env[:j], spec.InitContainers[i].Env[j+1:]...) 118 break 119 } 120 } 121 } 122 for i, c := range spec.Containers { 123 for j, ev := range c.Env { 124 if ev.Name == "FOO" { 125 spec.Containers[i].Env = append(spec.Containers[i].Env[:j], spec.Containers[i].Env[j+1:]...) 126 break 127 } 128 } 129 } 130 } 131 132 var tbCondSet = apis.NewLivingConditionSet() 133 134 // clearLTT clears the last transition time from our conditions because 135 // they are hard to ignore in the context of *unstructured.Unstructured, 136 // which is how psbinding updates statuses. 137 func (tbs *TestBindableStatus) clearLTT() { 138 for i := range tbs.Conditions { 139 tbs.Conditions[i].LastTransitionTime = apis.VolatileTime{} 140 } 141 } 142 143 // InitializeConditions populates the TestBindableStatus's conditions field 144 // with all of its conditions configured to Unknown. 145 func (tbs *TestBindableStatus) InitializeConditions() { 146 tbCondSet.Manage(tbs).InitializeConditions() 147 tbs.clearLTT() 148 } 149 150 // MarkBindingUnavailable marks the TestBindable's Ready condition to False with 151 // the provided reason and message. 152 func (tbs *TestBindableStatus) MarkBindingUnavailable(reason, message string) { 153 tbCondSet.Manage(tbs).MarkFalse(apis.ConditionReady, reason, message) 154 tbs.clearLTT() 155 } 156 157 // MarkBindingAvailable marks the TestBindable's Ready condition to True. 158 func (tbs *TestBindableStatus) MarkBindingAvailable() { 159 tbCondSet.Manage(tbs).MarkTrue(apis.ConditionReady) 160 tbs.clearLTT() 161 } 162 163 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 164 165 // TestBindableList is a list of TestBindable resources 166 type TestBindableList struct { 167 metav1.TypeMeta `json:",inline"` 168 metav1.ListMeta `json:"metadata"` 169 170 Items []TestBindable `json:"items"` 171 }