Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: SWIFT v2 Middlewares #2390

Merged
merged 14 commits into from
Jan 19, 2024
15 changes: 7 additions & 8 deletions cns/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,16 @@ type HTTPService interface {
GetPendingReleaseIPConfigs() []IPConfigurationStatus
GetPodIPConfigState() map[string]IPConfigurationStatus
MarkIPAsPendingRelease(numberToMark int) (map[string]IPConfigurationStatus, error)
AttachSWIFTv2Middleware(middleware SWIFTv2Middleware)
AttachIPConfigsHandlerMiddleware(IPConfigsHandlerMiddleware)
}

// Middleware interface for testing later on
type SWIFTv2Middleware interface {
ValidateIPConfigsRequest(context.Context, *IPConfigsRequest) (types.ResponseCode, string)
GetIPConfig(context.Context, PodInfo) (PodIpInfo, error)
SetRoutes(*PodIpInfo) error
}
// IPConfigsHandlerFunc
type IPConfigsHandlerFunc func(context.Context, IPConfigsRequest) (*IPConfigsResponse, error)

type IPConfigsRequestValidator func(context.Context, *IPConfigsRequest) (types.ResponseCode, string)
// IPConfigsHandlerMiddleware
type IPConfigsHandlerMiddleware interface {
IPConfigsRequestHandlerWrapper(defaultHandler IPConfigsHandlerFunc, failureHandler IPConfigsHandlerFunc) IPConfigsHandlerFunc
}

// This is used for KubernetesCRD orchestrator Type where NC has multiple ips.
// This struct captures the state for SecondaryIPs associated to a given NC
Expand Down
7 changes: 7 additions & 0 deletions cns/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ import (
"github.com/pkg/errors"
)

type SWIFTV2Mode string

const (
// EnvCNSConfig is the CNS_CONFIGURATION_PATH env var key
EnvCNSConfig = "CNS_CONFIGURATION_PATH"
defaultConfigName = "cns_config.json"
// Service Fabric SWIFTV2 mode
SFSWIFTV2 SWIFTV2Mode = "SFSWIFTV2"
// K8s SWIFTV2 mode
K8sSWIFTV2 SWIFTV2Mode = "K8sSWIFTV2"
)

type CNSConfig struct {
ChannelMode string
EnablePprof bool
EnableSubnetScarcity bool
EnableSwiftV2 bool
SWIFTV2Mode string
nddq marked this conversation as resolved.
Show resolved Hide resolved
InitializeFromCNI bool
ManagedSettings ManagedSettings
MetricsBindAddress string
Expand Down
2 changes: 1 addition & 1 deletion cns/fakes/cnsfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,4 @@ func (fake *HTTPServiceFake) Init(*common.ServiceConfig) error {

func (fake *HTTPServiceFake) Stop() {}

func (fake *HTTPServiceFake) AttachSWIFTv2Middleware(cns.SWIFTv2Middleware) {}
func (fake *HTTPServiceFake) AttachIPConfigsHandlerMiddleware(cns.IPConfigsHandlerMiddleware) {}
kmurudi marked this conversation as resolved.
Show resolved Hide resolved
89 changes: 77 additions & 12 deletions cns/middlewares/swiftV2.go → cns/middlewares/k8sSwiftV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,89 @@ const (
overlayGatewayV6 = "fe80::1234:5678:9abc"
)

type SWIFTv2Middleware struct {
type K8sSWIFTv2Middleware struct {
Cli client.Client
}

// ValidateIPConfigsRequest validates if pod is multitenant by checking the pod labels, used in SWIFT V2 scenario.
// Verify interface compliance at compile time
var _ cns.IPConfigsHandlerMiddleware = (*K8sSWIFTv2Middleware)(nil)

// IPConfigsRequestHandlerWrapper is the middleware function for handling SWIFT v2 IP configs requests for AKS-SWIFT. This function wrapped the default SWIFT request
// and release IP configs handlers.
func (m *K8sSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(defaultHandler, failureHandler cns.IPConfigsHandlerFunc) cns.IPConfigsHandlerFunc {
kmurudi marked this conversation as resolved.
Show resolved Hide resolved
return func(ctx context.Context, req cns.IPConfigsRequest) (*cns.IPConfigsResponse, error) {
podInfo, respCode, message := m.validateIPConfigsRequest(ctx, &req)

if respCode != types.Success {
return &cns.IPConfigsResponse{
Response: cns.Response{
ReturnCode: respCode,
Message: message,
},
}, errors.New("failed to validate ip configs request")
}
ipConfigsResp, err := defaultHandler(ctx, req)
// If the pod is not v2, return the response from the handler
if !req.SecondaryInterfacesExist {
return ipConfigsResp, err
}
// If the pod is v2, get the infra IP configs from the handler first and then add the SWIFTv2 IP config
defer func() {
// Release the default IP config if there is an error
if err != nil {
_, err = failureHandler(ctx, req)
if err != nil {
logger.Errorf("failed to release default IP config : %v", err)
}
}
}()
if err != nil {
return ipConfigsResp, err
}
SWIFTv2PodIPInfo, err := m.getIPConfig(ctx, podInfo)
if err != nil {
return &cns.IPConfigsResponse{
Response: cns.Response{
ReturnCode: types.FailedToAllocateIPConfig,
Message: fmt.Sprintf("AllocateIPConfig failed: %v, IP config request is %v", err, req),
},
PodIPInfo: []cns.PodIpInfo{},
}, errors.Wrapf(err, "failed to get SWIFTv2 IP config : %v", req)
}
ipConfigsResp.PodIPInfo = append(ipConfigsResp.PodIPInfo, SWIFTv2PodIPInfo)
// Set routes for the pod
for i := range ipConfigsResp.PodIPInfo {
ipInfo := &ipConfigsResp.PodIPInfo[i]
err = m.setRoutes(ipInfo)
if err != nil {
return &cns.IPConfigsResponse{
Response: cns.Response{
ReturnCode: types.FailedToAllocateIPConfig,
Message: fmt.Sprintf("AllocateIPConfig failed: %v, IP config request is %v", err, req),
},
PodIPInfo: []cns.PodIpInfo{},
}, errors.Wrapf(err, "failed to set routes for pod %s", podInfo.Name())
}
}
return ipConfigsResp, nil
}
}

// validateIPConfigsRequest validates if pod is multitenant by checking the pod labels, used in SWIFT V2 AKS scenario.
// nolint
func (m *SWIFTv2Middleware) ValidateIPConfigsRequest(ctx context.Context, req *cns.IPConfigsRequest) (respCode types.ResponseCode, message string) {
func (m *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req *cns.IPConfigsRequest) (podInfo cns.PodInfo, respCode types.ResponseCode, message string) {
kmurudi marked this conversation as resolved.
Show resolved Hide resolved
// Retrieve the pod from the cluster
podInfo, err := cns.UnmarshalPodInfo(req.OrchestratorContext)
if err != nil {
errBuf := errors.Wrapf(err, "failed to unmarshalling pod info from ipconfigs request %+v", req)
return types.UnexpectedError, errBuf.Error()
return nil, types.UnexpectedError, errBuf.Error()
}
logger.Printf("[SWIFTv2Middleware] validate ipconfigs request for pod %s", podInfo.Name())
podNamespacedName := k8stypes.NamespacedName{Namespace: podInfo.Namespace(), Name: podInfo.Name()}
pod := v1.Pod{}
if err := m.Cli.Get(ctx, podNamespacedName, &pod); err != nil {
errBuf := errors.Wrapf(err, "failed to get pod %+v", podNamespacedName)
return types.UnexpectedError, errBuf.Error()
return nil, types.UnexpectedError, errBuf.Error()
}

// check the pod labels for Swift V2, set the request's SecondaryInterfaceSet flag to true and check if its MTPNC CRD is ready
Expand All @@ -58,19 +122,20 @@ func (m *SWIFTv2Middleware) ValidateIPConfigsRequest(ctx context.Context, req *c
mtpnc := v1alpha1.MultitenantPodNetworkConfig{}
mtpncNamespacedName := k8stypes.NamespacedName{Namespace: podInfo.Namespace(), Name: podInfo.Name()}
if err := m.Cli.Get(ctx, mtpncNamespacedName, &mtpnc); err != nil {
return types.UnexpectedError, fmt.Errorf("failed to get pod's mtpnc from cache : %w", err).Error()
return nil, types.UnexpectedError, fmt.Errorf("failed to get pod's mtpnc from cache : %w", err).Error()
}
// Check if the MTPNC CRD is ready. If one of the fields is empty, return error
if mtpnc.Status.PrimaryIP == "" || mtpnc.Status.MacAddress == "" || mtpnc.Status.NCID == "" || mtpnc.Status.GatewayIP == "" {
return types.UnexpectedError, errMTPNCNotReady.Error()
return nil, types.UnexpectedError, errMTPNCNotReady.Error()
}
}
logger.Printf("[SWIFTv2Middleware] pod %s has secondary interface : %v", podInfo.Name(), req.SecondaryInterfacesExist)
return types.Success, ""
// retrieve podinfo from orchestrator context
return podInfo, types.Success, ""
}

// GetIPConfig returns the pod's SWIFT V2 IP configuration.
func (m *SWIFTv2Middleware) GetIPConfig(ctx context.Context, podInfo cns.PodInfo) (cns.PodIpInfo, error) {
// getIPConfig returns the pod's SWIFT V2 IP configuration.
func (m *K8sSWIFTv2Middleware) getIPConfig(ctx context.Context, podInfo cns.PodInfo) (cns.PodIpInfo, error) {
// Check if the MTPNC CRD exists for the pod, if not, return error
mtpnc := v1alpha1.MultitenantPodNetworkConfig{}
mtpncNamespacedName := k8stypes.NamespacedName{Namespace: podInfo.Namespace(), Name: podInfo.Name()}
Expand Down Expand Up @@ -109,8 +174,8 @@ func (m *SWIFTv2Middleware) GetIPConfig(ctx context.Context, podInfo cns.PodInfo
return podIPInfo, nil
}

// SetRoutes sets the routes for podIPInfo used in SWIFT V2 scenario.
func (m *SWIFTv2Middleware) SetRoutes(podIPInfo *cns.PodIpInfo) error {
// setRoutes sets the routes for podIPInfo used in SWIFT V2 scenario.
func (m *K8sSWIFTv2Middleware) setRoutes(podIPInfo *cns.PodIpInfo) error {
logger.Printf("[SWIFTv2Middleware] set routes for pod with nic type : %s", podIPInfo.NICType)
podIPInfo.Routes = []cns.Route{}
switch podIPInfo.NICType {
Expand Down
Loading
Loading