Skip to content

Commit ed2b57a

Browse files
authored
Add join VNET call for every AZR NC unpublish call with fixed UTs (#3016)
* add join vnet call for every AZR nc unpublish call * add join vnet call for every AZR nc unpublish call * modify comment with explanation * declare vnet variable * linter fix * address comments
1 parent 64c6c11 commit ed2b57a

File tree

2 files changed

+82
-7
lines changed

2 files changed

+82
-7
lines changed

cns/restserver/api.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package restserver
55

66
import (
7+
"bytes"
78
"context"
89
"encoding/json"
910
"fmt"
@@ -20,6 +21,7 @@ import (
2021
"github.com/Azure/azure-container-networking/cns/types"
2122
"github.com/Azure/azure-container-networking/cns/wireserver"
2223
"github.com/Azure/azure-container-networking/common"
24+
"github.com/Azure/azure-container-networking/nmagent"
2325
"github.com/pkg/errors"
2426
)
2527

@@ -1029,7 +1031,28 @@ func (service *HTTPRestService) unpublishNetworkContainer(w http.ResponseWriter,
10291031

10301032
ctx := r.Context()
10311033

1032-
if !service.isNetworkJoined(req.NetworkID) {
1034+
var unpublishBody nmagent.DeleteContainerRequest
1035+
var azrNC bool
1036+
err = json.Unmarshal(req.DeleteNetworkContainerRequestBody, &unpublishBody)
1037+
if err != nil {
1038+
// If the body contains only `""\n`, it is non-AZR NC
1039+
// In this case, we should not return an error
1040+
// However, if the body is not `""\n`, it is invalid and therefore, we must return an error
1041+
// []byte{34, 34, 10} here represents []byte(`""`+"\n")
1042+
if !bytes.Equal(req.DeleteNetworkContainerRequestBody, []byte{34, 34, 10}) {
1043+
http.Error(w, fmt.Sprintf("could not unmarshal delete network container body: %v", err), http.StatusBadRequest)
1044+
return
1045+
}
1046+
} else {
1047+
// If unmarshalling was successful, it is an AZR NC
1048+
azrNC = true
1049+
}
1050+
1051+
/* For AZR scenarios, if NMAgent is restarted, it loses state and does not know what VNETs to subscribe to.
1052+
As it no longer has VNET state, delete nc calls would fail. We need to add join VNET call for all AZR
1053+
nc unpublish calls just like publish nc calls.
1054+
*/
1055+
if azrNC || !service.isNetworkJoined(req.NetworkID) {
10331056
joinResp, err := service.wsproxy.JoinNetwork(ctx, req.NetworkID) //nolint:govet // ok to shadow
10341057
if err != nil {
10351058
resp := cns.UnpublishNetworkContainerResponse{
@@ -1062,7 +1085,7 @@ func (service *HTTPRestService) unpublishNetworkContainer(w http.ResponseWriter,
10621085
}
10631086

10641087
service.setNetworkStateJoined(req.NetworkID)
1065-
logger.Printf("[Azure-CNS] joined vnet %s during nc %s unpublish. wireserver response: %v", req.NetworkID, req.NetworkContainerID, string(joinBytes))
1088+
logger.Printf("[Azure-CNS] joined vnet %s during nc %s unpublish. AZREnabled: %t, wireserver response: %v", req.NetworkID, req.NetworkContainerID, unpublishBody.AZREnabled, string(joinBytes))
10661089
}
10671090

10681091
publishResp, err := service.wsproxy.UnpublishNC(ctx, ncParams, req.DeleteNetworkContainerRequestBody)

cns/restserver/api_test.go

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ func TestUnpublishNCViaCNS(t *testing.T) {
10571057
"/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToke/" +
10581058
"8636c99d-7861-401f-b0d3-7e5b7dc8183c" +
10591059
"/api-version/1/method/DELETE"
1060-
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL)
1060+
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL, []byte(`""`+"\n"))
10611061
if err == nil {
10621062
t.Fatal("Expected a bad request error due to delete network url being incorrect")
10631063
}
@@ -1068,20 +1068,72 @@ func TestUnpublishNCViaCNS(t *testing.T) {
10681068
"/machine/plugins/?comp=nmagent&NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/" +
10691069
"8636c99d-7861-401f-b0d3-7e5b7dc8183c8636c99d-7861-401f-b0d3-7e5b7dc8183c" +
10701070
"/api-version/1/method/DELETE"
1071-
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL)
1071+
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL, []byte(`""`+"\n"))
10721072
if err == nil {
10731073
t.Fatal("Expected a bad request error due to create network url having more characters than permitted in auth token")
10741074
}
10751075

10761076
// now actually perform the deletion:
10771077
deleteNetworkContainerURL = "http://" + nmagentEndpoint +
10781078
"/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1/method/DELETE"
1079-
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL)
1079+
err = unpublishNCViaCNS("vnet1", "ethWebApp", deleteNetworkContainerURL, []byte(`""`+"\n"))
10801080
if err != nil {
10811081
t.Fatal(err)
10821082
}
10831083
}
10841084

1085+
func TestUnpublishViaCNSRequestBody(t *testing.T) {
1086+
createNetworkContainerURL := "http://" + nmagentEndpoint +
1087+
"/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1"
1088+
deleteNetworkContainerURL := "http://" + nmagentEndpoint +
1089+
"/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1/method/DELETE"
1090+
vnet := "vnet1"
1091+
wsProxy := fakes.WireserverProxyFake{}
1092+
cleanup := setWireserverProxy(svc, &wsProxy)
1093+
defer cleanup()
1094+
1095+
tests := []struct {
1096+
name string
1097+
ncID string
1098+
body []byte
1099+
requireError bool
1100+
}{
1101+
{
1102+
name: "Delete NC with invalid body",
1103+
ncID: "ncID1",
1104+
body: []byte(`invalid` + "\n"),
1105+
requireError: true,
1106+
},
1107+
{
1108+
name: "Delete NC with valid non-AZR body",
1109+
ncID: "ncID2",
1110+
body: []byte(`""` + "\n"),
1111+
requireError: false,
1112+
},
1113+
{
1114+
name: "Delete NC with valid AZR body",
1115+
ncID: "ncID3",
1116+
body: []byte(`{"azID":1,"azrEnabled":true}`),
1117+
requireError: false,
1118+
},
1119+
}
1120+
1121+
for _, tt := range tests {
1122+
tt := tt
1123+
t.Run(tt.name, func(t *testing.T) {
1124+
errPublish := publishNCViaCNS(vnet, tt.ncID, createNetworkContainerURL)
1125+
require.NoError(t, errPublish)
1126+
errUnpublish := unpublishNCViaCNS(vnet, tt.ncID, deleteNetworkContainerURL, tt.body)
1127+
if tt.requireError {
1128+
require.Error(t, errUnpublish)
1129+
require.Contains(t, errUnpublish.Error(), "error decoding json")
1130+
} else {
1131+
require.NoError(t, errUnpublish)
1132+
}
1133+
})
1134+
}
1135+
}
1136+
10851137
func TestUnpublishNCViaCNS401(t *testing.T) {
10861138
wsproxy := fakes.WireserverProxyFake{
10871139
UnpublishNCFunc: func(_ context.Context, _ cns.NetworkContainerParameters, i []byte) (*http.Response, error) {
@@ -1161,15 +1213,15 @@ func TestUnpublishNCViaCNS401(t *testing.T) {
11611213
}
11621214
}
11631215

1164-
func unpublishNCViaCNS(networkID, networkContainerID, deleteNetworkContainerURL string) error {
1216+
func unpublishNCViaCNS(networkID, networkContainerID, deleteNetworkContainerURL string, bodyBytes []byte) error {
11651217
joinNetworkURL := "http://" + nmagentEndpoint + "/dummyVnetURL"
11661218

11671219
unpublishNCRequest := &cns.UnpublishNetworkContainerRequest{
11681220
NetworkID: networkID,
11691221
NetworkContainerID: networkContainerID,
11701222
JoinNetworkURL: joinNetworkURL,
11711223
DeleteNetworkContainerURL: deleteNetworkContainerURL,
1172-
DeleteNetworkContainerRequestBody: []byte("{}"),
1224+
DeleteNetworkContainerRequestBody: bodyBytes,
11731225
}
11741226

11751227
var body bytes.Buffer

0 commit comments

Comments
 (0)