Skip to content

Commit b9b8627

Browse files
kmuruditamilmani1989paulyufan2
authored
Add swiftv2 middleware support for standalone service fabric scenario (windows) (#2634)
* feature: add sfswiftv2 middleware support for standalone service fabric swiftv2 windows path * feat: add switch case for middlewaretype * review: address comments * pkg: move swiftv2mode for cnsconfig from configuration to cns package to avoid import-cycle * address review comment * linter: context check, wrap error * linter: fix errors wrap return static err * review: address comments: * refactor: keep old variable enableswiftv2, initialization pattern * address pr comments * rename the middleware to standaloneswiftv2middleware * remove HostSecondaryIPInfo from podIpInfo * address review comments-1 * address review comments-2 * Update cns/service/main.go Co-authored-by: tamilmani1989 <[email protected]> Signed-off-by: Kshitija Murudi <[email protected]> * fix an linter issue * rename the IPConfigRequest func * fix a comment linter issue * fix a comment linter issue * remove checking hnsTransparent network mdoe * remove orchestrator checker --------- Signed-off-by: Kshitija Murudi <[email protected]> Co-authored-by: tamilmani1989 <[email protected]> Co-authored-by: Paul Yu <[email protected]> Co-authored-by: paulyufan2 <[email protected]>
1 parent 0a36997 commit b9b8627

File tree

8 files changed

+137
-26
lines changed

8 files changed

+137
-26
lines changed

cns/api.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ const (
3535
V1Prefix = "/v0.1"
3636
V2Prefix = "/v0.2"
3737
EndpointPath = "/network/endpoints/"
38+
// Service Fabric SWIFTV2 mode
39+
StandaloneSWIFTV2 SWIFTV2Mode = "StandaloneSWIFTV2"
40+
// K8s SWIFTV2 mode
41+
K8sSWIFTV2 SWIFTV2Mode = "K8sSWIFTV2"
3842
)
3943

4044
// HTTPService describes the min API interface that every service should have.
@@ -59,8 +63,12 @@ type IPConfigsHandlerFunc func(context.Context, IPConfigsRequest) (*IPConfigsRes
5963
// IPConfigsHandlerMiddleware
6064
type IPConfigsHandlerMiddleware interface {
6165
IPConfigsRequestHandlerWrapper(defaultHandler IPConfigsHandlerFunc, failureHandler IPConfigsHandlerFunc) IPConfigsHandlerFunc
66+
Type() SWIFTV2Mode
6267
}
6368

69+
// SWIFTV2Mode describes the orchestrator-related scenario for swiftv2 flow, used in CNSConfig
70+
type SWIFTV2Mode string
71+
6472
// This is used for KubernetesCRD orchestrator Type where NC has multiple ips.
6573
// This struct captures the state for SecondaryIPs associated to a given NC
6674
type IPConfigurationStatus struct {

cns/configuration/configuration.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,10 @@ import (
1313
"github.com/pkg/errors"
1414
)
1515

16-
type SWIFTV2Mode string
17-
1816
const (
1917
// EnvCNSConfig is the CNS_CONFIGURATION_PATH env var key
2018
EnvCNSConfig = "CNS_CONFIGURATION_PATH"
2119
defaultConfigName = "cns_config.json"
22-
// Service Fabric SWIFTV2 mode
23-
SFSWIFTV2 SWIFTV2Mode = "SFSWIFTV2"
24-
// K8s SWIFTV2 mode
25-
K8sSWIFTV2 SWIFTV2Mode = "K8sSWIFTV2"
2620
)
2721

2822
type CNSConfig struct {
@@ -46,7 +40,6 @@ type CNSConfig struct {
4640
MellanoxMonitorIntervalSecs int
4741
MetricsBindAddress string
4842
ProgramSNATIPTables bool
49-
SWIFTV2Mode SWIFTV2Mode
5043
SyncHostNCTimeoutMs int
5144
SyncHostNCVersionIntervalMs int
5245
TLSCertificatePath string

cns/middlewares/k8sSwiftV2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,7 @@ func (k *K8sSWIFTv2Middleware) getIPConfig(ctx context.Context, podInfo cns.PodI
245245

246246
return podIPInfos, nil
247247
}
248+
249+
func (k *K8sSWIFTv2Middleware) Type() cns.SWIFTV2Mode {
250+
return cns.K8sSWIFTV2
251+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package middlewares
2+
3+
import (
4+
"context"
5+
6+
"github.com/Azure/azure-container-networking/cns"
7+
"github.com/Azure/azure-container-networking/cns/types"
8+
"github.com/pkg/errors"
9+
)
10+
11+
type StandaloneSWIFTv2Middleware struct{}
12+
13+
// IPConfigsRequestHandlerWrapper is the middleware function for handling SWIFT v2 IP config requests for SF standalone scenario. This function wraps the default SWIFT request
14+
// and release IP configs handlers.
15+
func (m *StandaloneSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(ipRequestHandler, _ cns.IPConfigsHandlerFunc) cns.IPConfigsHandlerFunc {
16+
return func(ctx context.Context, req cns.IPConfigsRequest) (*cns.IPConfigsResponse, error) {
17+
ipConfigsResp, err := ipRequestHandler(ctx, req)
18+
if err != nil {
19+
ipConfigsResp.Response.ReturnCode = types.UnexpectedError
20+
return ipConfigsResp, errors.Wrapf(err, "Failed to requestIPConfigs for Standalone-SwiftV2 from IPConfigsRequest %v", req)
21+
}
22+
23+
return ipConfigsResp, nil
24+
}
25+
}
26+
27+
func (m *StandaloneSWIFTv2Middleware) Type() cns.SWIFTV2Mode {
28+
return cns.StandaloneSWIFTV2
29+
}

cns/restserver/ipam.go

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var (
2727
ErrNoNCs = errors.New("no NCs found in the CNS internal state")
2828
ErrOptManageEndpointState = errors.New("CNS is not set to manage the endpoint state")
2929
ErrEndpointStateNotFound = errors.New("endpoint state could not be found in the statefile")
30+
ErrGetAllNCResponseEmpty = errors.New("failed to get NC responses from statefile")
3031
)
3132

3233
const (
@@ -113,6 +114,81 @@ func (service *HTTPRestService) requestIPConfigHandlerHelper(ctx context.Context
113114
}, nil
114115
}
115116

117+
// requestIPConfigHandlerHelperStandalone validates the request, assign IPs and return the IPConfigs
118+
func (service *HTTPRestService) requestIPConfigHandlerHelperStandalone(ctx context.Context, ipconfigsRequest cns.IPConfigsRequest) (*cns.IPConfigsResponse, error) {
119+
// For SWIFT v2 scenario, the validator function will also modify the ipconfigsRequest.
120+
podInfo, returnCode, returnMessage := service.validateIPConfigsRequest(ctx, ipconfigsRequest)
121+
if returnCode != types.Success {
122+
return &cns.IPConfigsResponse{
123+
Response: cns.Response{
124+
ReturnCode: returnCode,
125+
Message: returnMessage,
126+
},
127+
}, errors.New("failed to validate ip config request or unmarshal orchestratorContext")
128+
}
129+
130+
orchestratorContext, err := podInfo.OrchestratorContext()
131+
if err != nil {
132+
return &cns.IPConfigsResponse{}, fmt.Errorf("error getting orchestrator context from PodInfo %w", err)
133+
}
134+
cnsRequest := cns.GetNetworkContainerRequest{OrchestratorContext: orchestratorContext}
135+
resp := service.getAllNetworkContainerResponses(cnsRequest) //nolint:contextcheck // not passed in any methods, appease linter
136+
// return err if returned list has no NCs
137+
if len(resp) == 0 {
138+
return &cns.IPConfigsResponse{
139+
Response: cns.Response{
140+
ReturnCode: types.FailedToAllocateIPConfig,
141+
Message: fmt.Sprintf("AllocateIPConfig failed due to not getting NC Response from statefile, IP config request is %v", ipconfigsRequest),
142+
},
143+
}, ErrGetAllNCResponseEmpty
144+
}
145+
146+
podIPInfoList := make([]cns.PodIpInfo, 0, len(resp))
147+
for i := range resp {
148+
podIPInfo := cns.PodIpInfo{
149+
PodIPConfig: resp[i].IPConfiguration.IPSubnet,
150+
MacAddress: resp[i].NetworkInterfaceInfo.MACAddress,
151+
NICType: resp[i].NetworkInterfaceInfo.NICType,
152+
NetworkContainerPrimaryIPConfig: resp[i].IPConfiguration,
153+
}
154+
podIPInfoList = append(podIPInfoList, podIPInfo)
155+
}
156+
157+
ipConfigsResp := &cns.IPConfigsResponse{
158+
Response: cns.Response{
159+
ReturnCode: types.Success,
160+
},
161+
PodIPInfo: podIPInfoList,
162+
}
163+
164+
err = service.updatePodInfoWithInterfaces(ctx, ipConfigsResp)
165+
if err != nil {
166+
return &cns.IPConfigsResponse{
167+
Response: cns.Response{
168+
ReturnCode: types.FailedToAllocateIPConfig,
169+
Message: fmt.Sprintf("AllocateIPConfig failed while updating pod with interfaces: %v, IP config request is %v", err, ipconfigsRequest),
170+
},
171+
}, err
172+
}
173+
return ipConfigsResp, nil
174+
}
175+
176+
func (service *HTTPRestService) updatePodInfoWithInterfaces(ctx context.Context, ipconfigResponse *cns.IPConfigsResponse) error {
177+
// fetching primary host interface to use below for updating IPConfigsResponse
178+
hostPrimaryInterface, err := service.getPrimaryHostInterface(ctx)
179+
if err != nil {
180+
return err
181+
}
182+
for i := range ipconfigResponse.PodIPInfo {
183+
ipconfigResponse.PodIPInfo[i].HostPrimaryIPInfo = cns.HostIPInfo{
184+
Gateway: hostPrimaryInterface.Gateway,
185+
PrimaryIP: hostPrimaryInterface.PrimaryIP,
186+
Subnet: hostPrimaryInterface.Subnet,
187+
}
188+
}
189+
return nil
190+
}
191+
116192
// RequestIPConfigHandler requests an IPConfig from the CNS state
117193
func (service *HTTPRestService) RequestIPConfigHandler(w http.ResponseWriter, r *http.Request) {
118194
var ipconfigRequest cns.IPConfigRequest
@@ -201,8 +277,16 @@ func (service *HTTPRestService) RequestIPConfigsHandler(w http.ResponseWriter, r
201277

202278
// Check if IPConfigsHandlerMiddleware is set
203279
if service.IPConfigsHandlerMiddleware != nil {
204-
// Wrap the default datapath handlers with the middleware
205-
wrappedHandler := service.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(service.requestIPConfigHandlerHelper, service.ReleaseIPConfigHandlerHelper)
280+
// Wrap the default datapath handlers with the middleware depending on middleware type
281+
var wrappedHandler cns.IPConfigsHandlerFunc
282+
switch service.IPConfigsHandlerMiddleware.Type() {
283+
case cns.K8sSWIFTV2:
284+
wrappedHandler = service.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(service.requestIPConfigHandlerHelper, service.ReleaseIPConfigHandlerHelper)
285+
// this middleware is used for standalone swiftv2 secenario where a different helper is invoked as the PodInfo is read from cns state
286+
case cns.StandaloneSWIFTV2:
287+
wrappedHandler = service.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(service.requestIPConfigHandlerHelperStandalone, nil)
288+
}
289+
206290
ipConfigsResp, err = wrappedHandler(r.Context(), ipconfigsRequest)
207291
} else {
208292
ipConfigsResp, err = service.requestIPConfigHandlerHelper(r.Context(), ipconfigsRequest) // nolint:contextcheck // appease linter

cns/restserver/util.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -786,12 +786,8 @@ func (service *HTTPRestService) SendNCSnapShotPeriodically(ctx context.Context,
786786
}
787787

788788
func (service *HTTPRestService) validateIPConfigsRequest(ctx context.Context, ipConfigsRequest cns.IPConfigsRequest) (cns.PodInfo, types.ResponseCode, string) {
789-
if service.state.OrchestratorType != cns.KubernetesCRD && service.state.OrchestratorType != cns.Kubernetes {
790-
return nil, types.UnsupportedOrchestratorType, "ReleaseIPConfig API supported only for kubernetes orchestrator"
791-
}
792-
793789
if ipConfigsRequest.OrchestratorContext == nil {
794-
return nil, types.EmptyOrchestratorContext, fmt.Sprintf("OrchastratorContext is not set in the req: %+v", ipConfigsRequest)
790+
return nil, types.EmptyOrchestratorContext, fmt.Sprintf("OrchestratorContext is not set in the req: %+v", ipConfigsRequest)
795791
}
796792

797793
// retrieve podinfo from orchestrator context

cns/service/main.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,12 @@ func main() {
814814
if platform.HasMellanoxAdapter() {
815815
go platform.MonitorAndSetMellanoxRegKeyPriorityVLANTag(rootCtx, cnsconfig.MellanoxMonitorIntervalSecs)
816816
}
817+
818+
// if swiftv2 scenario is enabled, we need to initialize the ServiceFabric(standalone) swiftv2 middleware to process IPConfigsRequests
819+
// RequestIPConfigs() will be invoked only for swiftv2 or swiftv1 k8s scenarios. For swiftv1 direct mode different api will be invoked.
820+
// So initializing this middleware always under direct mode should not affect any other scenarios
821+
swiftV2Middleware := &middlewares.StandaloneSWIFTv2Middleware{}
822+
httpRemoteRestService.AttachIPConfigsHandlerMiddleware(swiftV2Middleware)
817823
}
818824

819825
// Initialze state in if CNS is running in CRD mode
@@ -1486,17 +1492,8 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
14861492
return errors.Wrapf(err, "failed to setup mtpnc reconciler with manager")
14871493
}
14881494
// if SWIFT v2 is enabled on CNS, attach multitenant middleware to rest service
1489-
// switch here for different type of swift v2 middleware (k8s or SF)
1490-
var swiftV2Middleware cns.IPConfigsHandlerMiddleware
1491-
switch cnsconfig.SWIFTV2Mode {
1492-
case configuration.K8sSWIFTV2:
1493-
swiftV2Middleware = &middlewares.K8sSWIFTv2Middleware{Cli: manager.GetClient()}
1494-
case configuration.SFSWIFTV2:
1495-
default:
1496-
// default to K8s middleware for now, in a later changes we where start to pass in
1497-
// SWIFT v2 mode in CNS config, this should throw an error if the mode is not set.
1498-
swiftV2Middleware = &middlewares.K8sSWIFTv2Middleware{Cli: manager.GetClient()}
1499-
}
1495+
// switch here for AKS(K8s) swiftv2 middleware to process IP configs requests
1496+
swiftV2Middleware := &middlewares.K8sSWIFTv2Middleware{Cli: manager.GetClient()}
15001497
httpRestService.AttachIPConfigsHandlerMiddleware(swiftV2Middleware)
15011498
}
15021499

cns/wireserver/net.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
var (
10-
// ErrNoPrimaryInterface indicates the wireserver respnose does not have a primary interface indicated.
10+
// ErrNoPrimaryInterface indicates the wireserver response does not have a primary interface indicated.
1111
ErrNoPrimaryInterface = errors.New("no primary interface found")
1212
// ErrInsufficientAddressSpace indicates that the CIDR space is too small to include a gateway IP; it is 1 IP.
1313
ErrInsufficientAddressSpace = errors.New("insufficient address space to generate gateway IP")

0 commit comments

Comments
 (0)