-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create StatusManager - a centralized component responsible for updating
the centralized status of an object, based on zone-specific statuses. Created as a part of cluster manager, handles only apbroutepolicy objects for now. Remove updated policy check based on timestamp, since LastTransitionTime precision is in seconds, and the whole test takes less than a second to complete, therefore all timestamps will be the same for multiple updates. Just checking expected policy state is enough for that test. TODO: unit tests checking Status.Status won't work with the exisitng setup, since that field is set by cluster manager. Signed-off-by: Nadia Pinaeva <[email protected]>
- Loading branch information
Showing
9 changed files
with
228 additions
and
50 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
133 changes: 133 additions & 0 deletions
133
go-controller/pkg/clustermanager/status_manager/status_manager.go
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,133 @@ | ||
package status_manager | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
adminpolicybasedrouteapi "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/adminpolicybasedroute/v1" | ||
adminpolicybasedrouteclient "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/adminpolicybasedroute/v1/apis/clientset/versioned" | ||
adminpolicybasedinformers "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/adminpolicybasedroute/v1/apis/informers/externalversions/adminpolicybasedroute/v1" | ||
|
||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
ktypes "k8s.io/apimachinery/pkg/types" | ||
utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||
"k8s.io/client-go/tools/cache" | ||
utilpointer "k8s.io/utils/pointer" | ||
) | ||
|
||
// fieldManagerName should be different from any zone name | ||
const fieldManagerName = "cluster-manager" | ||
|
||
type typedStatusManager[T Object] struct { | ||
gvk schema.GroupVersionKind | ||
informer cache.SharedIndexInformer | ||
patch func(ctx context.Context, name string, pt ktypes.PatchType, data []byte, opts metav1.PatchOptions, | ||
subresources ...string) (T, error) | ||
// updateStatusFunc should handle nil in case of pointer type, and return (updatedObject, needsUpdate). | ||
// When possible, return a new object with just the right status set, this makes encoding faster. | ||
updateStatusFunc func(obj T) (T, bool) | ||
} | ||
|
||
type Object interface { | ||
runtime.Object | ||
} | ||
|
||
func (m *typedStatusManager[T]) updateStatus(oldObjInterface, newObjInterface interface{}) { | ||
oldObj, ok := oldObjInterface.(T) | ||
if !ok { | ||
utilruntime.HandleError(fmt.Errorf("expecting %T but received %T", *new(T), oldObj)) | ||
return | ||
} | ||
newObj, ok := newObjInterface.(T) | ||
if !ok { | ||
utilruntime.HandleError(fmt.Errorf("expecting %T but received %T", *new(T), newObj)) | ||
return | ||
} | ||
|
||
key, err := cache.MetaNamespaceKeyFunc(newObj) | ||
if err != nil { | ||
utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", newObj, err)) | ||
return | ||
} | ||
|
||
patchedObj, needsUpdate := m.updateStatusFunc(newObj) | ||
if !needsUpdate { | ||
return | ||
} | ||
patchedObj.GetObjectKind().SetGroupVersionKind(m.gvk) | ||
// Send the full object to be applied on the server side. | ||
data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, patchedObj) | ||
if err != nil { | ||
utilruntime.HandleError(fmt.Errorf("could not encode for patching: %w", err)) | ||
return | ||
} | ||
|
||
patchOptions := metav1.PatchOptions{ | ||
Force: utilpointer.Bool(true), | ||
FieldManager: fieldManagerName, | ||
} | ||
_, err = m.patch(context.TODO(), key, ktypes.ApplyPatchType, data, patchOptions, "status") | ||
|
||
if err != nil { | ||
utilruntime.HandleError(fmt.Errorf("could not patch: %w", err)) | ||
} | ||
} | ||
|
||
func (m *typedStatusManager[T]) Start() error { | ||
_, err := m.informer.AddEventHandler( | ||
cache.ResourceEventHandlerFuncs{ | ||
UpdateFunc: m.updateStatus, | ||
}) | ||
return err | ||
} | ||
|
||
type StatusManager struct { | ||
abpRouteManager typedStatusManager[*adminpolicybasedrouteapi.AdminPolicyBasedExternalRoute] | ||
// other types go here | ||
} | ||
|
||
func NewStatusManager(apbRouteInformer adminpolicybasedinformers.AdminPolicyBasedExternalRouteInformer, | ||
apbRoutePolicyClient adminpolicybasedrouteclient.Interface) *StatusManager { | ||
abpRouteManager := typedStatusManager[*adminpolicybasedrouteapi.AdminPolicyBasedExternalRoute]{ | ||
gvk: schema.GroupVersionKind{ | ||
Kind: "AdminPolicyBasedExternalRoute", | ||
Group: "k8s.ovn.org", | ||
Version: "v1", | ||
}, | ||
informer: apbRouteInformer.Informer(), | ||
patch: apbRoutePolicyClient.K8sV1().AdminPolicyBasedExternalRoutes().Patch, | ||
updateStatusFunc: updateStatusAPBRoute, | ||
} | ||
return &StatusManager{ | ||
abpRouteManager: abpRouteManager, | ||
} | ||
} | ||
|
||
func (sm *StatusManager) Start() error { | ||
return sm.abpRouteManager.Start() | ||
} | ||
|
||
// updateStatusAPBRoute returns if policy needs status update | ||
func updateStatusAPBRoute(route *adminpolicybasedrouteapi.AdminPolicyBasedExternalRoute) (*adminpolicybasedrouteapi.AdminPolicyBasedExternalRoute, bool) { | ||
if route == nil { | ||
return nil, false | ||
} | ||
newStatus := adminpolicybasedrouteapi.SuccessStatus | ||
for _, message := range route.Status.Messages { | ||
if strings.Contains(message, types.APBRouteErrorMsg) { | ||
newStatus = adminpolicybasedrouteapi.FailStatus | ||
break | ||
} | ||
} | ||
return &adminpolicybasedrouteapi.AdminPolicyBasedExternalRoute{ | ||
Status: adminpolicybasedrouteapi.AdminPolicyBasedRouteStatus{ | ||
LastTransitionTime: metav1.Now(), | ||
Status: newStatus, | ||
}, | ||
}, route.Status.Status != newStatus | ||
} |
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
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
Oops, something went wrong.