Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions cns/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var clientPaths = []string{
cns.NumberOfCPUCores,
cns.NMAgentSupportedAPIs,
cns.DeleteNetworkContainer,
cns.NetworkContainersURLPath,
}

type do interface {
Expand Down Expand Up @@ -751,3 +752,62 @@ func (c *Client) NMAgentSupportedAPIs(ctx context.Context) (*cns.NmAgentSupporte

return &out, nil
}

func (c *Client) GetAllNCsFromCns(ctx context.Context) (cns.GetAllNetworkContainersResponse, error) {
// Build the request
urlPath := c.routes[cns.NetworkContainersURLPath]
req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlPath.String(), http.NoBody)
if err != nil {
return cns.GetAllNetworkContainersResponse{}, errors.Wrap(err, "building HTTP request")
}

// Submit the request
resp, err := c.client.Do(req)
if err != nil {
return cns.GetAllNetworkContainersResponse{}, errors.Wrap(err, "sending HTTP request")
}
defer resp.Body.Close()

// Decode the response
var response cns.GetAllNetworkContainersResponse
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil || response.Response.ReturnCode != types.Success {
return cns.GetAllNetworkContainersResponse{}, errors.Wrap(err, "decoding GetAllNetworkContainersResponse as JSON")
}

return response, nil
}

func (c *Client) PostAllNetworkContainers(ctx context.Context, createNcRequest cns.PostNetworkContainersRequest) error {
if createNcRequest.CreateNetworkContainerRequests == nil || len(createNcRequest.CreateNetworkContainerRequests) == 0 {
return errors.New("empty request provided")
}

// Build the request
var body bytes.Buffer
err := json.NewEncoder(&body).Encode(createNcRequest)
if err != nil {
return errors.Wrap(err, "building HTTP request")
}
urlPath := c.routes[cns.NetworkContainersURLPath]
req, err := http.NewRequestWithContext(ctx, http.MethodPost, urlPath.String(), &body)
if err != nil {
return errors.Wrap(err, "building HTTP request")
}

// Submit the request
resp, err := c.client.Do(req)
if err != nil {
return errors.Wrap(err, "sending HTTP request")
}
defer resp.Body.Close()

// Decode the response
var response cns.PostNetworkContainersResponse
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil || response.Response.ReturnCode != types.Success {
return errors.Wrap(err, "decoding PostNetworkContainersResponse as JSON")
}

return nil
}
131 changes: 123 additions & 8 deletions cns/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/http"
"net/url"
"os"
"sort"
"strconv"
"testing"
"time"
Expand All @@ -30,11 +31,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
svc *restserver.HTTPRestService
errBadRequest = errors.New("bad request")
)

const (
primaryIp = "10.0.0.5"
gatewayIp = "10.0.0.1"
Expand All @@ -46,7 +42,11 @@ const (
initPoolSize = 10
)

var dnsservers = []string{"8.8.8.8", "8.8.4.4"}
var (
svc *restserver.HTTPRestService
dnsServers = []string{"8.8.8.8", "8.8.4.4"}
errBadRequest = errors.New("bad request")
)

type mockdo struct {
errToReturn error
Expand All @@ -66,7 +66,7 @@ func (m *mockdo) Do(req *http.Request) (*http.Response, error) {

func addTestStateToRestServer(t *testing.T, secondaryIps []string) {
var ipConfig cns.IPConfiguration
ipConfig.DNSServers = dnsservers
ipConfig.DNSServers = dnsServers
ipConfig.GatewayIPAddress = gatewayIp
var ipSubnet cns.IPSubnet
ipSubnet.IPAddress = primaryIp
Expand Down Expand Up @@ -277,7 +277,7 @@ func TestCNSClientRequestAndRelease(t *testing.T) {
assert.EqualValues(t, podIPInfo.NetworkContainerPrimaryIPConfig.IPSubnet.PrefixLength, subnetPrfixLength, "Primary IP Prefix length is not added as expected ipConfig")

// validate DnsServer and Gateway Ip as the same configured for Primary IP
assert.Equal(t, dnsservers, podIPInfo.NetworkContainerPrimaryIPConfig.DNSServers, "DnsServer is not added as expected ipConfig")
assert.Equal(t, dnsServers, podIPInfo.NetworkContainerPrimaryIPConfig.DNSServers, "DnsServer is not added as expected ipConfig")
assert.Equal(t, gatewayIp, podIPInfo.NetworkContainerPrimaryIPConfig.GatewayIPAddress, "Gateway is not added as expected ipConfig")

resultIPnet, err := getIPNetFromResponse(resp)
Expand Down Expand Up @@ -2145,3 +2145,118 @@ func TestNMASupportedAPIs(t *testing.T) {
})
}
}

func TestGetAllNCsFromCns(t *testing.T) {
emptyRoutes, _ := buildRoutes(defaultBaseURL, clientPaths)
exp := cns.GetAllNetworkContainersResponse{
NetworkContainers: nil,
Response: cns.Response{
ReturnCode: types.Success,
Message: "",
},
}
mockDo := &mockdo{
errToReturn: nil,
objToReturn: cns.GetAllNetworkContainersResponse{},
httpStatusCodeToReturn: http.StatusOK,
}
client := &Client{
client: mockDo,
routes: emptyRoutes,
}

got, err := client.GetAllNCsFromCns(context.TODO())
assert.NoError(t, err)
assert.Equal(t, exp.Response.ReturnCode, got.Response.ReturnCode)
}

func TestPostAllNetworkContainers(t *testing.T) {
postAllNcsRequests := cns.PostNetworkContainersRequest{
CreateNetworkContainerRequests: []cns.CreateNetworkContainerRequest{
{
Version: "12345",
NetworkContainerType: "type1",
NetworkContainerid: "nc1",
OrchestratorContext: json.RawMessage("null"),
},
{
Version: "12345",
NetworkContainerType: "type2",
NetworkContainerid: "nc2",
OrchestratorContext: json.RawMessage("null"),
},
},
}

testCases := []struct {
name string
client *RequestCapture
req cns.PostNetworkContainersRequest
expReq *cns.PostNetworkContainersRequest
shouldErr bool
}{
{
"Empty request",
&RequestCapture{
Next: &mockdo{},
},
cns.PostNetworkContainersRequest{},
nil,
true,
},
{
"Happy path",
&RequestCapture{
Next: &mockdo{},
},
postAllNcsRequests,
&postAllNcsRequests,
false,
},
}

emptyRoutes, _ := buildRoutes(defaultBaseURL, clientPaths)
for _, test := range testCases {
test := test
t.Run(test.name, func(t *testing.T) {
client := &Client{
client: test.client,
routes: emptyRoutes,
}

err := client.PostAllNetworkContainers(context.TODO(), test.req)
if err != nil && !test.shouldErr {
t.Fatal("unexpected error: err:", err)
}

if err == nil && test.shouldErr {
t.Fatal("expected an error but received none")
}

// Make sure if we expected a request, the correct one will be received
if test.expReq != nil {
// Make sure a request was actually received
if test.client.Request == nil {
t.Fatal("expected to receive a request, but none received")
}
// Decode the received request for later comparison
var gotReq cns.PostNetworkContainersRequest
err = json.NewDecoder(test.client.Request.Body).Decode(&gotReq)
if err != nil {
t.Fatal("error decoding received request: err:", err)
}

sort.Slice(test.expReq.CreateNetworkContainerRequests, func(i, j int) bool {
return test.expReq.CreateNetworkContainerRequests[i].NetworkContainerid < test.expReq.CreateNetworkContainerRequests[j].NetworkContainerid
})
sort.Slice(gotReq.CreateNetworkContainerRequests, func(i, j int) bool {
return gotReq.CreateNetworkContainerRequests[i].NetworkContainerid < gotReq.CreateNetworkContainerRequests[j].NetworkContainerid
})

for i := 0; i < len(test.expReq.CreateNetworkContainerRequests); i++ {
assert.Equal(t, test.expReq.CreateNetworkContainerRequests[i], gotReq.CreateNetworkContainerRequests[i])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this stable against different orderings of the elements of the slice? You may have to sort here first...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order will affect the results. So it needs to be sorted at first.

}
}
})
}
}