@@ -2,10 +2,14 @@ package crd
2
2
3
3
import (
4
4
"fmt"
5
+ "k8s.io/apimachinery/pkg/runtime"
5
6
"strings"
6
7
7
8
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8
9
"k8s.io/apimachinery/pkg/util/yaml"
10
+
11
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
12
+ apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
9
13
)
10
14
11
15
// V1Beta1 refers to the deprecated v1beta1 APIVersion of CRD objects
@@ -39,3 +43,130 @@ func Version(manifest *string) (string, error) {
39
43
return v , nil
40
44
}
41
45
46
+ // Versions returns all resource versions present in the CRD. Compatible with both v1beta1 and v1 CRDs.
47
+ func ResourceVersions (obj runtime.Object ) (map [string ]struct {}, error ) {
48
+ versions := make (map [string ]struct {})
49
+
50
+ switch crd := obj .(type ) {
51
+ case * apiextensionsv1.CustomResourceDefinition :
52
+ for _ , version := range crd .Spec .Versions {
53
+ versions [version .Name ] = struct {}{}
54
+ }
55
+ return versions , nil
56
+ case * apiextensionsv1beta1.CustomResourceDefinition :
57
+ for _ , version := range crd .Spec .Versions {
58
+ versions [version .Name ] = struct {}{}
59
+ }
60
+ if crd .Spec .Version != "" {
61
+ versions [crd .Spec .Version ] = struct {}{}
62
+ }
63
+ return versions , nil
64
+ default :
65
+ return nil , fmt .Errorf ("could not find all versions present in CRD" )
66
+ }
67
+ }
68
+
69
+ func StoredVersions (obj runtime.Object ) []string {
70
+ switch crd := obj .(type ) {
71
+ case * apiextensionsv1.CustomResourceDefinition :
72
+ return crd .Status .StoredVersions
73
+ case * apiextensionsv1beta1.CustomResourceDefinition :
74
+ return crd .Status .StoredVersions
75
+ }
76
+ return nil
77
+ }
78
+
79
+ // RunStorageMigration determines whether the new CRD changes the storage version of the existing CRD.
80
+ // If true, OLM must run a migration process to ensure all CRs can be stored at the new version.
81
+ // See https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning/#upgrade-existing-objects-to-a-new-stored-version
82
+ func RunStorageMigration (oldCRD runtime.Object , newCRD runtime.Object ) bool {
83
+ newStoredVersions , oldStoredVersions := getStoredVersions (oldCRD , newCRD )
84
+
85
+ for name := range oldStoredVersions {
86
+ if _ , ok := newStoredVersions [name ]; ok {
87
+ // new storage version exists in old CRD present on the cluster
88
+ // no need to run migration
89
+ return false
90
+ }
91
+ }
92
+ return true
93
+ }
94
+
95
+ func getStoredVersions (oldCRD runtime.Object , newCRD runtime.Object ) (newStoredVersions map [string ]struct {}, oldStoredVersions map [string ]struct {}) {
96
+ oldStoredVersions = make (map [string ]struct {})
97
+ newStoredVersions = make (map [string ]struct {})
98
+
99
+ // find old storage versions by inspect the status field of the existing on-cluster CRD
100
+ switch crd := oldCRD .(type ) {
101
+ case * apiextensionsv1.CustomResourceDefinition :
102
+ for _ , version := range crd .Status .StoredVersions {
103
+ oldStoredVersions [version ] = struct {}{}
104
+ }
105
+ case * apiextensionsv1beta1.CustomResourceDefinition :
106
+ for _ , version := range crd .Status .StoredVersions {
107
+ oldStoredVersions [version ] = struct {}{}
108
+ }
109
+ }
110
+
111
+ switch crd := newCRD .(type ) {
112
+ case * apiextensionsv1.CustomResourceDefinition :
113
+ for _ , version := range crd .Spec .Versions {
114
+ if version .Storage {
115
+ newStoredVersions [version .Name ] = struct {}{}
116
+ }
117
+ }
118
+ case * apiextensionsv1beta1.CustomResourceDefinition :
119
+ for _ , version := range crd .Spec .Versions {
120
+ if version .Storage {
121
+ newStoredVersions [version .Name ] = struct {}{}
122
+ }
123
+ }
124
+ }
125
+
126
+ return newStoredVersions , oldStoredVersions
127
+ }
128
+
129
+ // GetNewStorageVersion returns the storage version defined in the CRD.
130
+ // Only one version may be specified as the storage version.
131
+ func GetNewStorageVersion (crd runtime.Object ) string {
132
+ switch crd := crd .(type ) {
133
+ case * apiextensionsv1.CustomResourceDefinition :
134
+ for _ , version := range crd .Spec .Versions {
135
+ if version .Storage {
136
+ return version .Name
137
+ }
138
+ }
139
+ case * apiextensionsv1beta1.CustomResourceDefinition :
140
+ for _ , version := range crd .Spec .Versions {
141
+ if version .Storage {
142
+ return version .Name
143
+ }
144
+ }
145
+ }
146
+ return ""
147
+ }
148
+
149
+ // GetDeprecatedStorageVersion returns the storage version that is being deprecated
150
+ func GetDeprecatedStorageVersion (oldCRD runtime.Object , newCRD runtime.Object ) string {
151
+ newStoredVersions , oldStoredVersions := getStoredVersions (oldCRD , newCRD )
152
+
153
+ for name := range oldStoredVersions {
154
+ if _ , ok := newStoredVersions [name ]; ! ok {
155
+ // old storage version does not exist in new CRD - this is the deprecated version
156
+ return name
157
+ }
158
+ }
159
+
160
+ return ""
161
+ }
162
+
163
+ func RemoveStorageVersion (versions []string , deprecated string ) []string {
164
+ for i , v := range versions {
165
+ if v == deprecated {
166
+ return append (versions [:i ], versions [i + 1 :]... )
167
+ }
168
+ return versions
169
+ }
170
+ return nil
171
+ }
172
+
0 commit comments