diff --git a/crd/apis/network/v1/network.go b/crd/apis/network/v1/network.go index 9beecd5147..7e4fe5ede0 100644 --- a/crd/apis/network/v1/network.go +++ b/crd/apis/network/v1/network.go @@ -1,5 +1,12 @@ package v1 +import "C" +import ( + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + // DefaultNetworkIfEmpty takes a string corresponding to a network name and makes // sure that if it is empty then it is set to the default network. This comes // from the idea that a network is like a namespace, where an empty network is @@ -26,3 +33,39 @@ func (n *Network) InUse() bool { val, ok := n.Annotations[NetworkInUseAnnotationKey] return ok && val == NetworkInUseAnnotationValTrue } + +// GetCondition returns the "condType" condition from the obj. Only Network and +// GKENetworkParamSet types are supported. Returns nil when not found. +func GetCondition(obj interface{}, condType NetworkConditionType) (*metav1.Condition, error) { + var conditions []metav1.Condition + + switch v := obj.(type) { + case *Network: + conditions = obj.(*Network).Status.Conditions + _ = fmt.Errorf("type %v", v) + case *GKENetworkParamSet: + conditions = obj.(*GKENetworkParamSet).Status.Conditions + default: + return nil, fmt.Errorf("unsupported type: %s", v) + } + + for _, cond := range conditions { + if cond.Type == string(condType) { + return cond.DeepCopy(), nil + } + } + return nil, nil +} + +// IsReady returns true when the specified obj Ready condition is True. +// Only Network and GKENetworkParamSet types are supported. +func IsReady(obj interface{}) (bool, error) { + cond, err := GetCondition(obj, NetworkConditionStatusReady) + if err != nil { + return false, err + } + if cond != nil { + return cond.Status == metav1.ConditionTrue, nil + } + return false, nil +} diff --git a/crd/apis/network/v1/network_test.go b/crd/apis/network/v1/network_test.go index 510ac5b00c..201bc4f445 100644 --- a/crd/apis/network/v1/network_test.go +++ b/crd/apis/network/v1/network_test.go @@ -3,6 +3,7 @@ package v1 import ( "testing" + "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -118,3 +119,171 @@ func TestDefaultNetworkIfEmpty(t *testing.T) { }) } } + +func TestIsReady(t *testing.T) { + makeNetwork := func(cond []metav1.Condition) *Network { + return &Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Status: NetworkStatus{ + Conditions: cond, + }, + } + } + + tests := []struct { + name string + input interface{} + want bool + expectedErr bool + }{ + { + name: "nil condition", + input: &Network{}, + want: false, + }, + { + name: "true condition", + input: makeNetwork([]metav1.Condition{ + { + Type: string(NetworkConditionStatusParamsReady), + Status: metav1.ConditionFalse, + }, + { + Type: string(NetworkConditionStatusReady), + Status: metav1.ConditionTrue, + }, + }), + want: true, + }, + { + name: "false condition", + input: makeNetwork([]metav1.Condition{ + { + Type: string(NetworkConditionStatusReady), + Status: metav1.ConditionFalse, + }, + { + Type: string(NetworkConditionStatusParamsReady), + Status: metav1.ConditionTrue, + }, + }), + want: false, + }, + { + name: "missing ready condition", + input: makeNetwork([]metav1.Condition{ + { + Type: string(NetworkConditionStatusParamsReady), + Status: metav1.ConditionTrue, + }, + }), + want: false, + }, + { + name: "unsupported type", + input: metav1.APIGroup{}, + want: false, + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got, err := IsReady(tc.input) + if tc.expectedErr && err == nil { + t.Fatalf("IsReady(%+v) expected error but got nil", tc.input) + } else if !tc.expectedErr && err != nil { + t.Fatalf("IsReady(%+v) unexpected error %v", tc.input, err) + } + if tc.expectedErr { + return + } + if got != tc.want { + t.Fatalf("IsReady(%+v) returns %v but want %v", tc.input, got, tc.want) + } + }) + } +} + +func TestGetCondition(t *testing.T) { + makeNetwork := func(cond []metav1.Condition) *Network { + return &Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Status: NetworkStatus{ + Conditions: cond, + }, + } + } + + tests := []struct { + name string + input interface{} + condType NetworkConditionType + want *metav1.Condition + expectedErr bool + }{ + { + name: "nil condition", + input: &Network{}, + condType: NetworkConditionStatusReady, + want: nil, + }, + { + name: "condition present", + input: makeNetwork([]metav1.Condition{ + { + Type: string(NetworkConditionStatusParamsReady), + Status: metav1.ConditionFalse, + }, + { + Type: string(NetworkConditionStatusReady), + Status: metav1.ConditionTrue, + }, + }), + condType: NetworkConditionStatusReady, + want: &metav1.Condition{ + Type: string(NetworkConditionStatusReady), + Status: metav1.ConditionTrue, + }, + }, + { + name: "condition not present", + input: makeNetwork([]metav1.Condition{ + { + Type: string(NetworkConditionStatusParamsReady), + Status: metav1.ConditionFalse, + }, + }), + condType: NetworkConditionStatusReady, + want: nil, + }, + { + name: "unsupported type", + input: metav1.APIGroup{}, + condType: NetworkConditionStatusReady, + want: nil, + expectedErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got, err := GetCondition(tc.input, tc.condType) + if tc.expectedErr && err == nil { + t.Fatalf("GetCondition(%+v) expected error but got nil", tc.input) + } else if !tc.expectedErr && err != nil { + t.Fatalf("GetCondition(%+v) unexpected error %v", tc.input, err) + } + if tc.expectedErr { + return + } + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Fatalf("GetCondition() has diff (-want +got):\n%s", diff) + } + }) + } +} diff --git a/crd/apis/network/v1/network_types.go b/crd/apis/network/v1/network_types.go index 927acfa49f..ac42a46be4 100644 --- a/crd/apis/network/v1/network_types.go +++ b/crd/apis/network/v1/network_types.go @@ -165,11 +165,11 @@ type Route struct { type NetworkConditionType string const ( - // NetworkStatusReady is the condition type that holds + // NetworkConditionStatusReady is the condition type that holds // if the Network object is validated NetworkConditionStatusReady NetworkConditionType = "Ready" - // NetworkStatusParamsReady is the condition type that holds + // NetworkConditionStatusParamsReady is the condition type that holds // if the params object referenced by Network is validated NetworkConditionStatusParamsReady NetworkConditionType = "ParamsReady" )