-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
monitor the bootstrap kubeconfig and restart immediately when changes
Signed-off-by: haoqing0110 <[email protected]>
- Loading branch information
1 parent
e683e8c
commit bd7e9d7
Showing
11 changed files
with
286 additions
and
241 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package spoke | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"reflect" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||
"k8s.io/client-go/tools/cache" | ||
"k8s.io/klog/v2" | ||
) | ||
|
||
type bootstrapKubeconfigEventHandler struct { | ||
bootstrapKubeconfigSecretName *string | ||
cancel context.CancelFunc | ||
} | ||
|
||
func (hc *bootstrapKubeconfigEventHandler) Name() string { | ||
return "bootstrap-hub-kubeconfig" | ||
} | ||
|
||
// implement cache.ResourceEventHandler.OnAdd | ||
func (hc *bootstrapKubeconfigEventHandler) OnAdd(obj interface{}, isInInitialList bool) { | ||
} | ||
|
||
// implement cache.ResourceEventHandler.OnUpdate | ||
func (hc *bootstrapKubeconfigEventHandler) OnUpdate(oldObj, newObj interface{}) { | ||
newSecret, ok := newObj.(*corev1.Secret) | ||
if !ok { | ||
utilruntime.HandleError(fmt.Errorf("invalid secret object: %v", newObj)) | ||
return | ||
} | ||
|
||
if newSecret.Name != *hc.bootstrapKubeconfigSecretName { | ||
return | ||
} | ||
|
||
oldSecret, ok := oldObj.(*corev1.Secret) | ||
if !ok { | ||
utilruntime.HandleError(fmt.Errorf("invalid secret object: %v", oldObj)) | ||
return | ||
} | ||
|
||
if !reflect.DeepEqual(newSecret.Data, oldSecret.Data) { | ||
// Restart immediately if the bootstrap kubeconfig changes. Otherwise, in the backup restore scenario, | ||
// the work agent may resync a wrong bootstrap kubeconfig from the cache to overwrite the restored one. | ||
klog.Info("the bootstrap kubeconfig changes and rebootstrap is required, cancel the context") | ||
hc.cancel() | ||
} | ||
} | ||
|
||
// implement cache.ResourceEventHandler.OnDelete | ||
func (hc *bootstrapKubeconfigEventHandler) OnDelete(obj interface{}) { | ||
switch t := obj.(type) { | ||
case *corev1.Secret: | ||
if t.Name == *hc.bootstrapKubeconfigSecretName { | ||
klog.Info("the bootstrap kubeconfig deletes and rebootstrap is required, cancel the context") | ||
hc.cancel() | ||
} | ||
case cache.DeletedFinalStateUnknown: | ||
secret, ok := t.Obj.(*corev1.Secret) | ||
if ok && secret.Name == *hc.bootstrapKubeconfigSecretName { | ||
klog.Info("the bootstrap kubeconfig deletes and rebootstrap is required, cancel the context") | ||
hc.cancel() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package spoke | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func TestBootstrapKubeconfigEventHandler(t *testing.T) { | ||
//#nosec G101 | ||
defaultSecretName := "bootstrap-hub-kubeconfig" | ||
cases := []struct { | ||
name string | ||
secretName string | ||
originalBootstrapKubeconfigSecret interface{} | ||
bootstrapKubeconfigSecret interface{} | ||
add bool | ||
update bool | ||
delete bool | ||
expectCancel bool | ||
}{ | ||
{ | ||
name: "add", | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, map[string][]byte{ | ||
"kubeconfig": []byte("invalid-kubeconfig"), | ||
}), | ||
expectCancel: false, | ||
}, | ||
{ | ||
name: "label changes", | ||
originalBootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, map[string][]byte{ | ||
"kubeconfig": []byte("invalid-kubeconfig"), | ||
}), | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, map[string]string{ | ||
"test": "true", | ||
}, map[string][]byte{ | ||
"kubeconfig": []byte("invalid-kubeconfig"), | ||
}), | ||
update: true, | ||
expectCancel: false, | ||
}, | ||
{ | ||
name: "spec changes", | ||
originalBootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, map[string][]byte{ | ||
"kubeconfig": []byte("invalid-kubeconfig"), | ||
}), | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, map[string][]byte{ | ||
"kubeconfig": []byte("another-invalid-kubeconfig"), | ||
}), | ||
update: true, | ||
expectCancel: true, | ||
}, | ||
{ | ||
name: "invalid new object type - update", | ||
bootstrapKubeconfigSecret: struct{}{}, | ||
update: true, | ||
expectCancel: false, | ||
}, | ||
{ | ||
name: "invalid old object type - update", | ||
originalBootstrapKubeconfigSecret: struct{}{}, | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, map[string][]byte{ | ||
"kubeconfig": []byte("another-invalid-kubeconfig"), | ||
}), | ||
update: true, | ||
expectCancel: false, | ||
}, | ||
{ | ||
name: "delete", | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret(defaultSecretName, nil, nil), | ||
delete: true, | ||
expectCancel: true, | ||
}, | ||
{ | ||
name: "delete other secret", | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret("other-secret", nil, nil), | ||
delete: true, | ||
expectCancel: false, | ||
}, | ||
{ | ||
name: "custom secret name", | ||
secretName: "other-secret", | ||
bootstrapKubeconfigSecret: newBootstrapKubeconfigSecret("other-secret", nil, nil), | ||
delete: true, | ||
expectCancel: true, | ||
}, | ||
{ | ||
name: "invalid type - delete", | ||
secretName: "other-secret", | ||
bootstrapKubeconfigSecret: struct{}{}, | ||
delete: true, | ||
expectCancel: false, | ||
}, | ||
} | ||
for _, c := range cases { | ||
t.Run(c.name, func(t *testing.T) { | ||
secretName := defaultSecretName | ||
bootstrapKubeconfigSecretName := &secretName | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
|
||
hc := &bootstrapKubeconfigEventHandler{ | ||
bootstrapKubeconfigSecretName: bootstrapKubeconfigSecretName, | ||
cancel: cancel, | ||
} | ||
|
||
if len(c.secretName) > 0 { | ||
*bootstrapKubeconfigSecretName = c.secretName | ||
} | ||
|
||
if c.add { | ||
hc.OnAdd(c.bootstrapKubeconfigSecret, false) | ||
} | ||
|
||
if c.update { | ||
hc.OnUpdate(c.originalBootstrapKubeconfigSecret, c.bootstrapKubeconfigSecret) | ||
select { | ||
case <-ctx.Done(): | ||
// context should be cancelled | ||
if c.expectCancel == false { | ||
t.Errorf("expected context to be not cancelled, but it was not") | ||
} | ||
default: | ||
if c.expectCancel == true { | ||
t.Errorf("expected context to be cancelled, but it was not") | ||
} | ||
} | ||
} | ||
|
||
if c.delete { | ||
hc.OnDelete(c.bootstrapKubeconfigSecret) | ||
select { | ||
case <-ctx.Done(): | ||
// context should be cancelled | ||
if c.expectCancel == false { | ||
t.Errorf("expected context to be not cancelled, but it was not") | ||
} | ||
default: | ||
if c.expectCancel == true { | ||
t.Errorf("expected context to be cancelled, but it was not") | ||
} | ||
} | ||
} | ||
|
||
}) | ||
} | ||
} | ||
|
||
func newBootstrapKubeconfigSecret(name string, labels map[string]string, data map[string][]byte, others ...string) *corev1.Secret { | ||
return &corev1.Secret{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
Namespace: "open-cluster-management-agent", | ||
Labels: labels, | ||
}, | ||
Data: data, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.