@@ -17,22 +17,92 @@ limitations under the License.
17
17
package hooks
18
18
19
19
import (
20
+ "fmt"
21
+
20
22
"k8s.io/apimachinery/pkg/runtime/schema"
21
23
"k8s.io/klog/v2"
22
24
"sigs.k8s.io/kubebuilder-declarative-pattern/mockkubeapiserver/storage"
23
25
)
24
26
25
27
// CRDHook implements functionality for CRD objects (the definitions themselves, not instances of CRDs)
26
28
type CRDHook struct {
27
- storage storage.Storage
29
+ Storage storage.Storage
28
30
}
29
31
30
32
func (s * CRDHook ) OnWatchEvent (ev * storage.WatchEvent ) {
31
33
switch ev .GroupKind () {
32
34
case schema.GroupKind {Group : "apiextensions.k8s.io" , Kind : "CustomResourceDefinition" }:
33
35
// When a CRD is created, we notify the storage layer so it can store instances of the CRD
34
- if err := s .storage .UpdateCRD (ev ); err != nil {
36
+ if err := s .Storage .UpdateCRD (ev ); err != nil {
35
37
klog .Warningf ("crd change was invalid: %v" , err )
36
38
}
39
+
40
+ if err := s .updateCRDConditions (ev ); err != nil {
41
+ klog .Fatalf ("could not update crd status: %v" , err )
42
+ }
43
+ }
44
+ }
45
+ func (s * CRDHook ) updateCRDConditions (ev * storage.WatchEvent ) error {
46
+ u := ev .Unstructured ()
47
+
48
+ // So that CRDs become ready, we immediately update the status.
49
+ // We could do something better here, like e.g. a 1 second pause before changing the status
50
+ statusObj := u .Object ["status" ]
51
+ if statusObj == nil {
52
+ statusObj = make (map [string ]interface {})
53
+ u .Object ["status" ] = statusObj
37
54
}
55
+ status , ok := statusObj .(map [string ]interface {})
56
+ if ! ok {
57
+ return fmt .Errorf ("status was of unexpected type %T" , statusObj )
58
+ }
59
+
60
+ generation := u .GetGeneration ()
61
+ if generation == 0 {
62
+ generation = 1
63
+ u .SetGeneration (generation )
64
+ }
65
+
66
+ var conditions []interface {}
67
+ conditions = append (conditions , map [string ]interface {}{
68
+ "type" : "NamesAccepted" ,
69
+ "status" : "True" ,
70
+ "reason" : "NoConflicts" ,
71
+ "message" : "no conflicts found" ,
72
+ })
73
+ conditions = append (conditions , map [string ]interface {}{
74
+ "type" : "Established" ,
75
+ "status" : "True" ,
76
+ "reason" : "InitialNamesAccepted" ,
77
+ "message" : "the initial names have been accepted" ,
78
+ })
79
+ status ["conditions" ] = conditions
80
+
81
+ // TODO: More of status? Here is an example of the full status
82
+ // status:
83
+ // acceptedNames:
84
+ // kind: VolumeSnapshot
85
+ // listKind: VolumeSnapshotList
86
+ // plural: volumesnapshots
87
+ // singular: volumesnapshot
88
+ // conditions:
89
+ // - lastTransitionTime: "2023-09-21T01:04:36Z"
90
+ // message: no conflicts found
91
+ // reason: NoConflicts
92
+ // status: "True"
93
+ // type: NamesAccepted
94
+ // - lastTransitionTime: "2023-09-21T01:04:36Z"
95
+ // message: the initial names have been accepted
96
+ // reason: InitialNamesAccepted
97
+ // status: "True"
98
+ // type: Established
99
+ // - lastTransitionTime: "2023-09-21T01:04:36Z"
100
+ // message: approved in https://github.com/kubernetes-csi/external-snapshotter/pull/419
101
+ // reason: ApprovedAnnotation
102
+ // status: "True"
103
+ // type: KubernetesAPIApprovalPolicyConformant
104
+ // storedVersions:
105
+ // - v1
106
+
107
+ return nil
38
108
}
0 commit comments