@@ -17,20 +17,34 @@ limitations under the License.
17
17
package rest
18
18
19
19
import (
20
+ "fmt"
21
+ "time"
22
+
20
23
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
24
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
25
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26
+ "k8s.io/apimachinery/pkg/util/wait"
27
+ flowcontrolbootstrap "k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap"
21
28
"k8s.io/apiserver/pkg/registry/generic"
22
29
"k8s.io/apiserver/pkg/registry/rest"
23
30
genericapiserver "k8s.io/apiserver/pkg/server"
24
31
serverstorage "k8s.io/apiserver/pkg/server/storage"
32
+ flowcontrolclient "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1"
33
+ "k8s.io/klog"
25
34
"k8s.io/kubernetes/pkg/api/legacyscheme"
26
35
"k8s.io/kubernetes/pkg/apis/flowcontrol"
27
36
flowschemastore "k8s.io/kubernetes/pkg/registry/flowcontrol/flowschema/storage"
28
37
prioritylevelconfigurationstore "k8s.io/kubernetes/pkg/registry/flowcontrol/prioritylevelconfiguration/storage"
29
38
)
30
39
31
- // RESTStorageProvider implements
40
+ var _ genericapiserver.PostStartHookProvider = RESTStorageProvider {}
41
+
42
+ // RESTStorageProvider is a provider of REST storage
32
43
type RESTStorageProvider struct {}
33
44
45
+ // PostStartHookName is the name of the post-start-hook provided by flow-control storage
46
+ const PostStartHookName = "apiserver/bootstrap-system-flowcontrol-configuration"
47
+
34
48
// NewRESTStorage creates a new rest storage for flow-control api models.
35
49
func (p RESTStorageProvider ) NewRESTStorage (apiResourceConfigSource serverstorage.APIResourceConfigSource , restOptionsGetter generic.RESTOptionsGetter ) (genericapiserver.APIGroupInfo , bool , error ) {
36
50
apiGroupInfo := genericapiserver .NewDefaultAPIGroupInfo (flowcontrol .GroupName , legacyscheme .Scheme , legacyscheme .ParameterCodec , legacyscheme .Codecs )
@@ -71,3 +85,129 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstora
71
85
func (p RESTStorageProvider ) GroupName () string {
72
86
return flowcontrol .GroupName
73
87
}
88
+
89
+ func (p RESTStorageProvider ) PostStartHook () (string , genericapiserver.PostStartHookFunc , error ) {
90
+ return PostStartHookName , func (hookContext genericapiserver.PostStartHookContext ) error {
91
+ flowcontrolClientSet := flowcontrolclient .NewForConfigOrDie (hookContext .LoopbackClientConfig )
92
+ go func () {
93
+ const retryCreatingSuggestedSettingsInterval = time .Second
94
+ _ = wait .PollImmediateUntil (
95
+ retryCreatingSuggestedSettingsInterval ,
96
+ func () (bool , error ) {
97
+ shouldEnsureSuggested , err := shouldEnsureAllPredefined (flowcontrolClientSet )
98
+ if err != nil {
99
+ klog .Errorf ("failed getting exempt flow-schema, will retry later: %v" , err )
100
+ return false , nil
101
+ }
102
+ if shouldEnsureSuggested {
103
+ err := ensure (
104
+ flowcontrolClientSet ,
105
+ flowcontrolbootstrap .SuggestedFlowSchemas ,
106
+ flowcontrolbootstrap .SuggestedPriorityLevelConfigurations )
107
+ if err != nil {
108
+ klog .Errorf ("failed ensuring suggested settings, will retry later: %v" , err )
109
+ return false , nil
110
+ }
111
+ }
112
+ return true , nil
113
+ },
114
+ hookContext .StopCh )
115
+ const retryCreatingMandatorySettingsInterval = time .Minute
116
+ _ = wait .PollImmediateUntil (
117
+ retryCreatingMandatorySettingsInterval ,
118
+ func () (bool , error ) {
119
+ if err := upgrade (
120
+ flowcontrolClientSet ,
121
+ flowcontrolbootstrap .MandatoryFlowSchemas ,
122
+ // Note: the "exempt" priority-level is supposed tobe the last item in the pre-defined
123
+ // list, so that a crash in the midst of the first kube-apiserver startup does not prevent
124
+ // the full initial set of objects from being created.
125
+ flowcontrolbootstrap .MandatoryPriorityLevelConfigurations ,
126
+ ); err != nil {
127
+ klog .Errorf ("failed creating default flowcontrol settings: %v" , err )
128
+ return false , nil
129
+ }
130
+ return false , nil // always retry
131
+ },
132
+ hookContext .StopCh )
133
+ }()
134
+ return nil
135
+ }, nil
136
+
137
+ }
138
+
139
+ // Returns false if there's a "exempt" priority-level existing in the cluster, otherwise returns a true
140
+ // if the "exempt" priority-level is not found.
141
+ func shouldEnsureAllPredefined (flowcontrolClientSet flowcontrolclient.FlowcontrolV1alpha1Interface ) (bool , error ) {
142
+ if _ , err := flowcontrolClientSet .PriorityLevelConfigurations ().Get (flowcontrol .PriorityLevelConfigurationNameExempt , metav1.GetOptions {}); err != nil {
143
+ if apierrors .IsNotFound (err ) {
144
+ return true , nil
145
+ }
146
+ return false , err
147
+ }
148
+ return false , nil
149
+ }
150
+
151
+ func ensure (flowcontrolClientSet flowcontrolclient.FlowcontrolV1alpha1Interface , flowSchemas []* flowcontrolv1alpha1.FlowSchema , priorityLevels []* flowcontrolv1alpha1.PriorityLevelConfiguration ) error {
152
+ for _ , flowSchema := range flowSchemas {
153
+ _ , err := flowcontrolClientSet .FlowSchemas ().Create (flowSchema )
154
+ if apierrors .IsAlreadyExists (err ) {
155
+ klog .V (3 ).Infof ("system preset FlowSchema %s already exists, skipping creating" , flowSchema .Name )
156
+ continue
157
+ }
158
+ if err != nil {
159
+ return fmt .Errorf ("cannot create FlowSchema %s due to %v" , flowSchema .Name , err )
160
+ }
161
+ klog .V (3 ).Infof ("created system preset FlowSchema %s" , flowSchema .Name )
162
+ }
163
+ for _ , priorityLevelConfiguration := range priorityLevels {
164
+ _ , err := flowcontrolClientSet .PriorityLevelConfigurations ().Create (priorityLevelConfiguration )
165
+ if apierrors .IsAlreadyExists (err ) {
166
+ klog .V (3 ).Infof ("system preset PriorityLevelConfiguration %s already exists, skipping creating" , priorityLevelConfiguration .Name )
167
+ continue
168
+ }
169
+ if err != nil {
170
+ return fmt .Errorf ("cannot create PriorityLevelConfiguration %s due to %v" , priorityLevelConfiguration .Name , err )
171
+ }
172
+ klog .V (3 ).Infof ("created system preset PriorityLevelConfiguration %s" , priorityLevelConfiguration .Name )
173
+ }
174
+ return nil
175
+ }
176
+
177
+ func upgrade (flowcontrolClientSet flowcontrolclient.FlowcontrolV1alpha1Interface , flowSchemas []* flowcontrolv1alpha1.FlowSchema , priorityLevels []* flowcontrolv1alpha1.PriorityLevelConfiguration ) error {
178
+ for _ , flowSchema := range flowSchemas {
179
+ _ , err := flowcontrolClientSet .FlowSchemas ().Get (flowSchema .Name , metav1.GetOptions {})
180
+ if err != nil {
181
+ return fmt .Errorf ("failed getting FlowSchema %s due to %v, will retry later" , flowSchema .Name , err )
182
+ }
183
+ // TODO(yue9944882): extract existing version from label and compare
184
+ // TODO(yue9944882): create w/ version string attached
185
+ _ , err = flowcontrolClientSet .FlowSchemas ().Create (flowSchema )
186
+ if apierrors .IsAlreadyExists (err ) {
187
+ klog .V (3 ).Infof ("system preset FlowSchema %s already exists, skipping creating" , flowSchema .Name )
188
+ continue
189
+ }
190
+ if err != nil {
191
+ return fmt .Errorf ("cannot create FlowSchema %s due to %v" , flowSchema .Name , err )
192
+ }
193
+ klog .V (3 ).Infof ("created system preset FlowSchema %s" , flowSchema .Name )
194
+ }
195
+ for _ , priorityLevelConfiguration := range priorityLevels {
196
+ _ , err := flowcontrolClientSet .FlowSchemas ().Get (priorityLevelConfiguration .Name , metav1.GetOptions {})
197
+ if err != nil {
198
+ return fmt .Errorf ("failed getting PriorityLevelConfiguration %s due to %v, will retry later" , priorityLevelConfiguration .Name , err )
199
+ }
200
+ // TODO(yue9944882): extract existing version from label and compare
201
+ // TODO(yue9944882): create w/ version string attached
202
+ _ , err = flowcontrolClientSet .PriorityLevelConfigurations ().Create (priorityLevelConfiguration )
203
+ if apierrors .IsAlreadyExists (err ) {
204
+ klog .V (3 ).Infof ("system preset PriorityLevelConfiguration %s already exists, skipping creating" , priorityLevelConfiguration .Name )
205
+ continue
206
+ }
207
+ if err != nil {
208
+ return fmt .Errorf ("cannot create PriorityLevelConfiguration %s due to %v" , priorityLevelConfiguration .Name , err )
209
+ }
210
+ klog .V (3 ).Infof ("created system preset PriorityLevelConfiguration %s" , priorityLevelConfiguration .Name )
211
+ }
212
+ return nil
213
+ }
0 commit comments