Skip to content

Commit 31a0906

Browse files
authored
Fix inability to unmarshal nmagent request (#1695)
* Fix inability to unmarshal nmagent request During the previous switchover to using the client from the `nmagent` client (as opposed to the `cns/nmagent` client), an assumption was made that "proxied" requests to NMAgent were provided by clients as nested JSON. This assumption was wrong--they are Base64-encoded strings of JSON. Even though they're ultimately similar, they're very different from the perspective of the JSON unmarshaler. Consequently, this restores the nested request body back to a []byte and performs the second-stage decoding manually (similarly to how it was previously done). Fixes #1694 * Fix swallowed error when body is not JSON In one instance, an error was accidentally swallowed because the existing code does not return errors (it sets variables instead). This makes controlling the flow of execution difficult. To fix this, the offending code has been moved to a separate function where returns can be used effectively.
1 parent 3c08f86 commit 31a0906

File tree

4 files changed

+103
-25
lines changed

4 files changed

+103
-25
lines changed

cns/NetworkContainerContract.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"strings"
99

1010
"github.com/Azure/azure-container-networking/cns/types"
11-
"github.com/Azure/azure-container-networking/nmagent"
1211
"github.com/pkg/errors"
1312
corev1 "k8s.io/api/core/v1"
1413
)
@@ -497,7 +496,7 @@ type PublishNetworkContainerRequest struct {
497496
NetworkContainerID string
498497
JoinNetworkURL string
499498
CreateNetworkContainerURL string
500-
CreateNetworkContainerRequestBody nmagent.PutNetworkContainerRequest
499+
CreateNetworkContainerRequestBody []byte
501500
}
502501

503502
// NetworkContainerParameters parameters available in network container operations

cns/client/client_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"github.com/Azure/azure-container-networking/cns/types"
2525
"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
2626
"github.com/Azure/azure-container-networking/log"
27-
"github.com/Azure/azure-container-networking/nmagent"
2827
"github.com/google/go-cmp/cmp"
2928
"github.com/google/uuid"
3029
"github.com/stretchr/testify/assert"
@@ -1033,14 +1032,14 @@ func TestPublishNC(t *testing.T) {
10331032
NetworkContainerID: "frob",
10341033
JoinNetworkURL: "http://example.com",
10351034
CreateNetworkContainerURL: "http://example.com",
1036-
CreateNetworkContainerRequestBody: nmagent.PutNetworkContainerRequest{},
1035+
CreateNetworkContainerRequestBody: []byte("{}"),
10371036
},
10381037
&cns.PublishNetworkContainerRequest{
10391038
NetworkID: "foo",
10401039
NetworkContainerID: "frob",
10411040
JoinNetworkURL: "http://example.com",
10421041
CreateNetworkContainerURL: "http://example.com",
1043-
CreateNetworkContainerRequestBody: nmagent.PutNetworkContainerRequest{},
1042+
CreateNetworkContainerRequestBody: []byte("{}"),
10441043
},
10451044
false,
10461045
},
@@ -1062,14 +1061,14 @@ func TestPublishNC(t *testing.T) {
10621061
NetworkContainerID: "frob",
10631062
JoinNetworkURL: "http://example.com",
10641063
CreateNetworkContainerURL: "http://example.com",
1065-
CreateNetworkContainerRequestBody: nmagent.PutNetworkContainerRequest{},
1064+
CreateNetworkContainerRequestBody: []byte("{}"),
10661065
},
10671066
&cns.PublishNetworkContainerRequest{
10681067
NetworkID: "foo",
10691068
NetworkContainerID: "frob",
10701069
JoinNetworkURL: "http://example.com",
10711070
CreateNetworkContainerURL: "http://example.com",
1072-
CreateNetworkContainerRequestBody: nmagent.PutNetworkContainerRequest{},
1071+
CreateNetworkContainerRequestBody: []byte("{}"),
10731072
},
10741073
true,
10751074
},

cns/restserver/api.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package restserver
55

66
import (
77
"context"
8+
"encoding/json"
89
"fmt"
910
"net"
1011
"net/http"
@@ -18,7 +19,7 @@ import (
1819
"github.com/Azure/azure-container-networking/cns/logger"
1920
"github.com/Azure/azure-container-networking/cns/types"
2021
"github.com/Azure/azure-container-networking/cns/wireserver"
21-
nma "github.com/Azure/azure-container-networking/nmagent"
22+
"github.com/Azure/azure-container-networking/nmagent"
2223
"github.com/Azure/azure-container-networking/platform"
2324
"github.com/pkg/errors"
2425
)
@@ -1110,6 +1111,34 @@ func getAuthTokenAndInterfaceIDFromNcURL(networkContainerURL string) (*cns.Netwo
11101111
return &cns.NetworkContainerParameters{AssociatedInterfaceID: matches[1], AuthToken: matches[3]}, nil
11111112
}
11121113

1114+
//nolint:revive // the previous receiver naming "service" is bad, this is correct:
1115+
func (h *HTTPRestService) doPublish(ctx context.Context, req cns.PublishNetworkContainerRequest, ncParameters *cns.NetworkContainerParameters) (string, types.ResponseCode) {
1116+
innerReqBytes := req.CreateNetworkContainerRequestBody
1117+
1118+
var innerReq nmagent.PutNetworkContainerRequest
1119+
err := json.Unmarshal(innerReqBytes, &innerReq)
1120+
if err != nil {
1121+
returnMessage := fmt.Sprintf("Failed to publish Network Container: %s", req.NetworkContainerID)
1122+
returnCode := types.NetworkContainerPublishFailed
1123+
logger.Errorf("[Azure-CNS] %s", returnMessage)
1124+
return returnMessage, returnCode
1125+
}
1126+
1127+
innerReq.AuthenticationToken = ncParameters.AuthToken
1128+
innerReq.PrimaryAddress = ncParameters.AssociatedInterfaceID
1129+
1130+
err = h.nma.PutNetworkContainer(ctx, &innerReq)
1131+
// nolint:bodyclose // existing code needs refactoring
1132+
if err != nil {
1133+
returnMessage := fmt.Sprintf("Failed to publish Network Container: %s", req.NetworkContainerID)
1134+
returnCode := types.NetworkContainerPublishFailed
1135+
logger.Errorf("[Azure-CNS] %s", returnMessage)
1136+
return returnMessage, returnCode
1137+
}
1138+
1139+
return "", types.Success
1140+
}
1141+
11131142
// Publish Network Container by calling nmagent
11141143
func (service *HTTPRestService) publishNetworkContainer(w http.ResponseWriter, r *http.Request) {
11151144
logger.Printf("[Azure-CNS] PublishNetworkContainer")
@@ -1177,7 +1206,7 @@ func (service *HTTPRestService) publishNetworkContainer(w http.ResponseWriter, r
11771206
returnCode = types.NetworkJoinFailed
11781207
publishErrorStr = err.Error()
11791208

1180-
var nmaErr nma.Error
1209+
var nmaErr nmagent.Error
11811210
if errors.As(err, &nmaErr) {
11821211
publishStatusCode = nmaErr.StatusCode()
11831212
}
@@ -1187,21 +1216,10 @@ func (service *HTTPRestService) publishNetworkContainer(w http.ResponseWriter, r
11871216

11881217
if isNetworkJoined {
11891218
// Publish Network Container
1190-
1191-
pncr := req.CreateNetworkContainerRequestBody
1192-
pncr.AuthenticationToken = ncParameters.AuthToken
1193-
pncr.PrimaryAddress = ncParameters.AssociatedInterfaceID
1194-
1195-
err = service.nma.PutNetworkContainer(ctx, &pncr)
1196-
// nolint:bodyclose // existing code needs refactoring
1197-
if err != nil {
1198-
returnMessage = fmt.Sprintf("Failed to publish Network Container: %s", req.NetworkContainerID)
1199-
returnCode = types.NetworkContainerPublishFailed
1200-
logger.Errorf("[Azure-CNS] %s", returnMessage)
1201-
}
1219+
returnMessage, returnCode = service.doPublish(ctx, req, ncParameters)
12021220
}
12031221

1204-
req := nma.NCVersionRequest{
1222+
req := nmagent.NCVersionRequest{
12051223
AuthToken: ncParameters.AuthToken,
12061224
NetworkContainerID: req.NetworkContainerID,
12071225
PrimaryAddress: ncParameters.AssociatedInterfaceID,
@@ -1292,7 +1310,7 @@ func (service *HTTPRestService) unpublishNetworkContainer(w http.ResponseWriter,
12921310
returnCode = types.NetworkJoinFailed
12931311
unpublishErrorStr = err.Error()
12941312

1295-
var nmaErr nma.Error
1313+
var nmaErr nmagent.Error
12961314
if errors.As(err, &nmaErr) {
12971315
unpublishStatusCode = nmaErr.StatusCode()
12981316
}
@@ -1303,7 +1321,7 @@ func (service *HTTPRestService) unpublishNetworkContainer(w http.ResponseWriter,
13031321
}
13041322

13051323
if isNetworkJoined {
1306-
dcr := nma.DeleteContainerRequest{
1324+
dcr := nmagent.DeleteContainerRequest{
13071325
NCID: req.NetworkContainerID,
13081326
PrimaryAddress: ncParameters.AssociatedInterfaceID,
13091327
AuthenticationToken: ncParameters.AuthToken,

cns/restserver/api_test.go

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,68 @@ func TestPublishNCViaCNS(t *testing.T) {
747747
}
748748
}
749749

750+
func TestPublishNCBadBody(t *testing.T) {
751+
mnma := &fakes.NMAgentClientFake{
752+
PutNetworkContainerF: func(_ context.Context, _ *nmagent.PutNetworkContainerRequest) error {
753+
return nil
754+
},
755+
JoinNetworkF: func(_ context.Context, _ nmagent.JoinNetworkRequest) error {
756+
return nil
757+
},
758+
}
759+
760+
cleanup := setMockNMAgent(svc, mnma)
761+
t.Cleanup(cleanup)
762+
763+
joinNetworkURL := "http://" + nmagentEndpoint + "/dummyVnetURL"
764+
765+
createNetworkContainerURL := "http://" + nmagentEndpoint +
766+
"/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1"
767+
publishNCRequest := &cns.PublishNetworkContainerRequest{
768+
NetworkID: "foo",
769+
NetworkContainerID: "bar",
770+
JoinNetworkURL: joinNetworkURL,
771+
CreateNetworkContainerURL: createNetworkContainerURL,
772+
CreateNetworkContainerRequestBody: []byte("this is not even remotely JSON"),
773+
}
774+
775+
var body bytes.Buffer
776+
err := json.NewEncoder(&body).Encode(publishNCRequest)
777+
if err != nil {
778+
t.Fatal("error encoding json: err:", err)
779+
}
780+
781+
//nolint:noctx // also just a test
782+
req, err := http.NewRequest(http.MethodPost, cns.PublishNetworkContainer, &body)
783+
if err != nil {
784+
t.Fatal("error creating new HTTP request: err:", err)
785+
}
786+
787+
w := httptest.NewRecorder()
788+
mux.ServeHTTP(w, req)
789+
790+
// the request should fail because the inner request body was incorrectly
791+
// formatted
792+
expStatus := http.StatusOK
793+
gotStatus := w.Code
794+
if expStatus != gotStatus {
795+
t.Error("unexpected http status code: exp:", expStatus, "got:", gotStatus)
796+
}
797+
798+
var resp cns.PublishNetworkContainerResponse
799+
//nolint:bodyclose // unnnecessary in a test
800+
err = json.NewDecoder(w.Result().Body).Decode(&resp)
801+
if err != nil {
802+
t.Fatal("unexpected error decoding JSON: err:", err)
803+
}
804+
805+
expCode := types.NetworkContainerPublishFailed
806+
gotCode := resp.Response.ReturnCode
807+
if expCode != gotCode {
808+
t.Error("unexpected return code: exp:", expCode, "got:", gotCode)
809+
}
810+
}
811+
750812
func publishNCViaCNS(
751813
networkID,
752814
networkContainerID,
@@ -764,7 +826,7 @@ func publishNCViaCNS(
764826
NetworkContainerID: networkContainerID,
765827
JoinNetworkURL: joinNetworkURL,
766828
CreateNetworkContainerURL: createNetworkContainerURL,
767-
CreateNetworkContainerRequestBody: nmagent.PutNetworkContainerRequest{},
829+
CreateNetworkContainerRequestBody: []byte("{}"),
768830
}
769831

770832
json.NewEncoder(&body).Encode(publishNCRequest)

0 commit comments

Comments
 (0)