Skip to content
21 changes: 19 additions & 2 deletions cns/healthserver/healthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import (

"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
"github.com/pkg/errors"
meta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
apiutil "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/healthz"
)

Expand All @@ -21,6 +24,7 @@ func init() {

type Config struct {
PingAPIServer bool
Mapper meta.RESTMapper
}

// NewHealthzHandlerWithChecks will return a [http.Handler] for CNS's /healthz endpoint.
Expand All @@ -30,12 +34,25 @@ type Config struct {
func NewHealthzHandlerWithChecks(cfg *Config) (http.Handler, error) {
checks := make(map[string]healthz.Checker)
if cfg.PingAPIServer {
cfg, err := ctrl.GetConfig()
restCfg, err := ctrl.GetConfig()
if err != nil {
return nil, errors.Wrap(err, "failed to get kubeconfig")
}
cli, err := client.New(cfg, client.Options{
// Use the provided (test) RESTMapper when present; otherwise fall back to a dynamic, discovery-based mapper for production.
mapper := cfg.Mapper
if mapper == nil {
httpClient, httpErr := rest.HTTPClientFor(restCfg)
if httpErr != nil {
return nil, errors.Wrap(httpErr, "build http client for REST mapper")
}
mapper, err = apiutil.NewDynamicRESTMapper(restCfg, httpClient)
if err != nil {
return nil, errors.Wrap(err, "build rest mapper")
}
}
cli, err := client.New(restCfg, client.Options{
Scheme: scheme,
Mapper: mapper,
})
if err != nil {
return nil, errors.Wrap(err, "failed to build client")
Expand Down
12 changes: 12 additions & 0 deletions cns/healthserver/healthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"testing"

"github.com/stretchr/testify/require"
meta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
)

const nncCRD = `{
Expand Down Expand Up @@ -158,6 +160,13 @@ const nncResult = `{
}
}`

func staticNNCMapper() meta.RESTMapper {
gv := schema.GroupVersion{Group: "acn.azure.com", Version: "v1alpha"}
m := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv})
m.Add(schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: "NodeNetworkConfig"}, meta.RESTScopeNamespace)
return m
}

func TestNewHealthzHandlerWithChecks(t *testing.T) {
tests := []struct {
name string
Expand All @@ -169,6 +178,7 @@ func TestNewHealthzHandlerWithChecks(t *testing.T) {
name: "list NNC gives 200 should indicate healthy",
config: &Config{
PingAPIServer: true,
Mapper: staticNNCMapper(),
},
apiStatusCode: http.StatusOK,
expectedHealthy: true,
Expand All @@ -177,6 +187,7 @@ func TestNewHealthzHandlerWithChecks(t *testing.T) {
name: "unauthorized (401) from apiserver should be unhealthy",
config: &Config{
PingAPIServer: true,
Mapper: staticNNCMapper(),
},
apiStatusCode: http.StatusUnauthorized,
expectedHealthy: false,
Expand All @@ -185,6 +196,7 @@ func TestNewHealthzHandlerWithChecks(t *testing.T) {
name: "channel nodesubnet should not call apiserver so it doesn't matter if the status code is a 401",
config: &Config{
PingAPIServer: false,
Mapper: staticNNCMapper(),
},
apiStatusCode: http.StatusUnauthorized,
expectedHealthy: true,
Expand Down
20 changes: 10 additions & 10 deletions cns/middlewares/k8sSwiftV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@ import (
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/kubelet"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
prefixLength = 32
overlayGatewayv4 = "169.254.1.1"
virtualGW = "169.254.2.1"
overlayGatewayV6 = "fe80::1234:5678:9abc"
NetworkNotReadyErrorMsg = "network is not ready"
)

var (
errMTPNCNotReady = errors.New(kubelet.NetworkNotReadyErrorMsg + " - mtpnc is not ready")
errGetMTPNC = errors.New(kubelet.NetworkNotReadyErrorMsg + " - failed to get MTPNC")
errMTPNCNotReady = errors.New(NetworkNotReadyErrorMsg + " - mtpnc is not ready")
errGetMTPNC = errors.New(NetworkNotReadyErrorMsg + " - failed to get MTPNC")
errInvalidSWIFTv2NICType = errors.New("invalid NIC type for SWIFT v2 scenario")
errInvalidMTPNCPrefixLength = errors.New("invalid prefix length for MTPNC primaryIP, must be 32")
)

const (
prefixLength = 32
overlayGatewayv4 = "169.254.1.1"
virtualGW = "169.254.2.1"
overlayGatewayV6 = "fe80::1234:5678:9abc"
)

type K8sSWIFTv2Middleware struct {
Cli client.Client
}
Expand Down
9 changes: 4 additions & 5 deletions cns/middlewares/k8sSwiftV2_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/Azure/azure-container-networking/crd/multitenancy/api/v1alpha1"
"github.com/google/go-cmp/cmp"
"gotest.tools/v3/assert"
"k8s.io/kubernetes/pkg/kubelet"
)

var (
Expand Down Expand Up @@ -210,14 +209,14 @@ func TestValidateMultitenantIPConfigsRequestFailure(t *testing.T) {
failReq.OrchestratorContext = b
_, respCode, msg := middleware.GetPodInfoForIPConfigsRequest(context.TODO(), failReq)
assert.Equal(t, respCode, types.UnexpectedError)
assert.Assert(t, strings.Contains(msg, kubelet.NetworkNotReadyErrorMsg), "expected error message to contain '%s', got '%s'", kubelet.NetworkNotReadyErrorMsg, msg)
assert.Assert(t, strings.Contains(msg, NetworkNotReadyErrorMsg), "expected error message to contain '%s', got '%s'", NetworkNotReadyErrorMsg, msg)

// MTPNC not ready
b, _ = testPod4Info.OrchestratorContext()
failReq.OrchestratorContext = b
_, respCode, msg = middleware.GetPodInfoForIPConfigsRequest(context.TODO(), failReq)
assert.Equal(t, respCode, types.UnexpectedError)
assert.Assert(t, strings.Contains(msg, kubelet.NetworkNotReadyErrorMsg), "expected error message to contain '%s', got '%s'", kubelet.NetworkNotReadyErrorMsg, msg)
assert.Assert(t, strings.Contains(msg, NetworkNotReadyErrorMsg), "expected error message to contain '%s', got '%s'", NetworkNotReadyErrorMsg, msg)
}

func TestGetSWIFTv2IPConfigSuccess(t *testing.T) {
Expand All @@ -242,12 +241,12 @@ func TestGetSWIFTv2IPConfigFailure(t *testing.T) {
// Pod's MTPNC doesn't exist in cache test
_, err := middleware.getIPConfig(context.TODO(), testPod3Info)
assert.Assert(t, strings.Contains(err.Error(), errGetMTPNC.Error()), "expected error to wrap errMTPNCNotFound, got: %v", err)
assert.ErrorContains(t, err, kubelet.NetworkNotReadyErrorMsg)
assert.ErrorContains(t, err, NetworkNotReadyErrorMsg)

// Pod's MTPNC is not ready test
_, err = middleware.getIPConfig(context.TODO(), testPod4Info)
assert.Assert(t, errors.Is(err, errMTPNCNotReady), "expected error to wrap errMTPNCNotReady, got: %v", err)
assert.ErrorContains(t, err, kubelet.NetworkNotReadyErrorMsg)
assert.ErrorContains(t, err, NetworkNotReadyErrorMsg)
}

func TestSetRoutesSuccess(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ import (
. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

type clientWithApply struct{ *mockclients.MockClient }

// Satisfy controller-runtime v0.22.1 Writer.Apply:
func (c clientWithApply) Apply(_ context.Context, _ runtime.ApplyConfiguration, _ ...client.ApplyOption) error {
return nil // not used in these tests
}

var _ = Describe("multiTenantCrdReconciler", func() {
var kubeClient *mockclients.MockClient
var cnsRestService *mockclients.MockcnsRESTservice
Expand All @@ -43,7 +51,7 @@ var _ = Describe("multiTenantCrdReconciler", func() {
cnsRestService = mockclients.NewMockcnsRESTservice(mockCtl)
statusWriter = mockclients.NewMockSubResourceWriter(mockCtl)
reconciler = &multiTenantCrdReconciler{
KubeClient: kubeClient,
KubeClient: clientWithApply{kubeClient},
NodeName: mockNodeName,
CNSRestService: cnsRestService,
}
Expand Down
Loading
Loading