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
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ CNSFILES = \
$(wildcard cns/routes/*.go) \
$(wildcard cns/service/*.go) \
$(wildcard cns/networkcontainers/*.go) \
$(wildcard cns/requestcontroller/*.go) \
$(wildcard cns/requestcontroller/kubecontroller/*.go) \
$(COREFILES) \
$(CNMFILES)

Expand Down
14 changes: 5 additions & 9 deletions cns/NetworkContainerContract.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const (
Batch = "Batch"
DBforPostgreSQL = "DBforPostgreSQL"
AzureFirstParty = "AzureFirstParty"
KubernetesCRD = "KubernetesCRD"
// TODO: Add OrchastratorType as CRD: https://msazure.visualstudio.com/One/_workitems/edit/7711872
)

// Encap Types
Expand Down Expand Up @@ -98,6 +100,7 @@ type KubernetesPodInfo struct {
}

// GetOrchestratorContext will return the orchestratorcontext as a string
// TODO - should use a hashed name or can this be PODUid?
func (podinfo *KubernetesPodInfo) GetOrchestratorContextKey() string {
return podinfo.PodName + ":" + podinfo.PodNamespace
}
Expand All @@ -115,16 +118,9 @@ type IPConfiguration struct {
GatewayIPAddress string
}

// SecondaryIPConfig contains IP info of SecondaryIP
type SecondaryIPConfig struct {
IPConfig IPSubnet
}

type ContainerIPConfigState struct {
IPConfig IPSubnet
ID string //uuid
NCID string
State string
OrchestratorContext json.RawMessage
IPSubnet IPSubnet
}

// IPSubnet contains ip subnet.
Expand Down
95 changes: 65 additions & 30 deletions cns/cnsclient/cnsclient_test.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,68 @@
package cnsclient

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"reflect"
"strconv"
"testing"

"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/common"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/restserver"
"github.com/Azure/azure-container-networking/log"
"github.com/google/uuid"
)

var (
testNCID = "06867cf3-332d-409d-8819-ed70d2c116b0"
svc *restserver.HTTPRestService
)

testIP1 = "10.0.0.1"
testPod1GUID = "898fb8f1-f93e-4c96-9c31-6b89098949a3"
testPod1Info = cns.KubernetesPodInfo{
PodName: "testpod1",
PodNamespace: "testpod1namespace",
}
const (
primaryIp = "10.0.0.5"
gatewayIp = "10.0.0.1"
dockerContainerType = cns.Docker
)

// func addTestStateToRestServer(svc *restserver.HTTPRestService) {
// // set state as already allocated
// state1, _ := restserver.NewPodStateWithOrchestratorContext(testIP1, 24, testPod1GUID, testNCID, cns.Available, testPod1Info)
// ipconfigs := map[string]cns.SecondaryIPConfig{
// state1.ID: state1,
// }
// nc := cns.CreateNetworkContainerRequest{
// SecondaryIPConfigs: ipconfigs,
// }
func addTestStateToRestServer(t *testing.T, secondaryIps []string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Can you declare vars at the beginning of the function in one block like this?
var (
ipConfig cns.IPConfiguration
ipSubnet cns.IPSubnet
...
)

I picked this up from Mat's code and I think it makes for cleaner functions

var ipConfig cns.IPConfiguration
ipConfig.DNSServers = []string{"8.8.8.8", "8.8.4.4"}
ipConfig.GatewayIPAddress = gatewayIp
var ipSubnet cns.IPSubnet
ipSubnet.IPAddress = primaryIp
ipSubnet.PrefixLength = 32
ipConfig.IPSubnet = ipSubnet
secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig)

for _, secIpAddress := range secondaryIps {
secIpConfig := cns.SecondaryIPConfig{
IPSubnet: cns.IPSubnet{
IPAddress: secIpAddress,
PrefixLength: 32,
},
}
ipId := uuid.New()
secondaryIPConfigs[ipId.String()] = secIpConfig
}

// svc.CreateOrUpdateNetworkContainerWithSecondaryIPConfigs(nc)
// }
req := cns.CreateNetworkContainerRequest{
NetworkContainerType: dockerContainerType,
NetworkContainerid: "testNcId1",
IPConfiguration: ipConfig,
SecondaryIPConfigs: secondaryIPConfigs,
}

returnCode := svc.CreateOrUpdateNetworkContainerInternal(req)
if returnCode != 0 {
t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode)
}
}

func getIPConfigFromGetNetworkContainerResponse(resp *cns.GetIPConfigResponse) (net.IPNet, error) {
var (
Expand All @@ -52,11 +85,10 @@ func getIPConfigFromGetNetworkContainerResponse(resp *cns.GetIPConfigResponse) (
return resultIPnet, err
}

/*
func TestMain(m *testing.M) {
var (
info = &cns.SetOrchestratorTypeRequest{
OrchestratorType: cns.Kubernetes}
OrchestratorType: cns.KubernetesCRD}
body bytes.Buffer
res *http.Response
)
Expand All @@ -80,15 +112,13 @@ func TestMain(m *testing.M) {
config := common.ServiceConfig{}

httpRestService, err := restserver.NewHTTPRestService(&config)
svc := httpRestService.(*restserver.HTTPRestService)
svc = httpRestService.(*restserver.HTTPRestService)
svc.Name = "cns-test-server"
if err != nil {
logger.Errorf("Failed to create CNS object, err:%v.\n", err)
return
}

//addTestStateToRestServer(svc)

if httpRestService != nil {
err = httpRestService.Start(&config)
if err != nil {
Expand All @@ -111,31 +141,37 @@ func TestMain(m *testing.M) {
}
fmt.Println(res)

m.Run()
exitCode := m.Run()
os.Exit(exitCode)
}

func TestCNSClientRequestAndRelease(t *testing.T) {
podName := "testpodname"
podNamespace := "testpodnamespace"
ip := net.ParseIP("10.0.0.1")
_, ipnet, _ := net.ParseCIDR("10.0.0.1/24")
desiredIpAddress := "10.0.0.5"
ip := net.ParseIP(desiredIpAddress)
_, ipnet, _ := net.ParseCIDR("10.0.0.5/32")
desired := net.IPNet{
IP: ip,
Mask: ipnet.Mask,
}

secondaryIps := make([]string, 0)
secondaryIps = append(secondaryIps, desiredIpAddress)
cnsClient, _ := InitCnsClient("")

addTestStateToRestServer(t, secondaryIps)

podInfo := cns.KubernetesPodInfo{PodName: podName, PodNamespace: podNamespace}
orchestratorContext, err := json.Marshal(podInfo)
if err != nil {
t.Fatal(err)
}

// no IP reservation found with that context, expect fail
// no IP reservation found with that context, expect no failure.
err = cnsClient.ReleaseIPAddress(orchestratorContext)
if err == nil {
t.Fatalf("Expected failure to release when no IP reservation found with context: %+v", err)
if err != nil {
t.Fatalf("Release ip idempotent call failed: %+v", err)
}

// request IP address
Expand All @@ -156,4 +192,3 @@ func TestCNSClientRequestAndRelease(t *testing.T) {
t.Fatalf("Expected to not fail when releasing IP reservation found with context: %+v", err)
}
}
*/
23 changes: 7 additions & 16 deletions cns/cnsclient/httpapi/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package httpapi

import (
"fmt"

"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/restserver"
)
Expand All @@ -12,24 +14,13 @@ type Client struct {

// CreateOrUpdateNC updates cns state
func (client *Client) CreateOrUpdateNC(ncRequest *cns.CreateNetworkContainerRequest) error {
// var (
// ipConfigsToAdd []*cns.ContainerIPConfigState
// )

// //Lock to read ipconfigs
// client.RestService.Lock()
returnCode := client.RestService.CreateOrUpdateNetworkContainerInternal(*ncRequest)

// //Only add ipconfigs that don't exist in cns state already
// for _, ipConfig := range ipConfigs {
// if _, ok := client.RestService.PodIPConfigState[ipConfig.ID]; !ok {
// ipConfig.State = cns.Available
// ipConfigsToAdd = append(ipConfigsToAdd, ipConfig)
// }
// }
if returnCode != 0 {
return fmt.Errorf("Failed to Create NC request: %+v, errorCode: %d", *ncRequest, returnCode)
}

// client.RestService.Unlock()
// leave empty
return nil //client.RestService.AddIPConfigsToState(ipConfigsToAdd)
return nil
}

// InitCNSState initializes cns state
Expand Down
3 changes: 2 additions & 1 deletion cns/logger/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ func sendTraceInternal(msg string) {
Log.th.TrackLog(report)
}

// also logs in the AI telemetry
func Printf(format string, args ...interface{}) {
Log.logger.Printf(format, args...)
Log.logger.Logf(format, args...)

if Log.th == nil || Log.DisableTraceLogging {
return
Expand Down
2 changes: 2 additions & 0 deletions cns/restserver/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,8 @@ func (service *HTTPRestService) setOrchestratorType(w http.ResponseWriter, r *ht
fallthrough
case cns.Kubernetes:
fallthrough
case cns.KubernetesCRD:
fallthrough
case cns.WebApps:
fallthrough
case cns.Batch:
Expand Down
4 changes: 2 additions & 2 deletions cns/restserver/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type xmlDocument struct {

var (
service HTTPService
svc *HTTPRestService
mux *http.ServeMux
hostQueryForProgrammedVersionResponse = `{"httpStatusCode":"200","networkContainerId":"eab2470f-test-test-test-b3cd316979d5","version":"1"}`
hostQueryResponse = xmlDocument{
Expand Down Expand Up @@ -104,8 +105,7 @@ func TestMain(m *testing.M) {
fmt.Printf("Failed to create CNS object %v\n", err)
os.Exit(1)
}

svc := service.(*HTTPRestService)
svc = service.(*HTTPRestService)
Copy link
Member

Choose a reason for hiding this comment

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

new svc object is being created on line 110

svc.Name = "cns-test-server"
if err != nil {
logger.Errorf("Failed to create CNS object, err:%v.\n", err)
Expand Down
4 changes: 4 additions & 0 deletions cns/restserver/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const (
NetworkJoinFailed = 24
NetworkContainerPublishFailed = 25
NetworkContainerUnpublishFailed = 26
InvalidPrimaryIPConfig = 27
PrimaryCANotSame = 28
InconsistentIPConfigState = 29
InvalidSecondaryIPConfig = 30
UnexpectedError = 99
)

Expand Down
62 changes: 62 additions & 0 deletions cns/restserver/internalapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@

package restserver

import (
"reflect"

"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
)

// This file contains the internal functions called by either HTTP APIs (api.go) or
// internal APIs (definde in internalapi.go).
// This will be used internally (say by RequestController in case of AKS)
Expand All @@ -14,3 +21,58 @@ func (service *HTTPRestService) GetPartitionKey() (dncPartitionKey string) {
service.RUnlock()
return
}

// This API will be called by CNS RequestController on CRD update.
func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req cns.CreateNetworkContainerRequest) int {
if req.NetworkContainerid == "" {
logger.Errorf("[Azure CNS] Error. NetworkContainerid is empty")
return NetworkContainerNotSpecified
}

// For now only RequestController uses this API which will be initialized only for AKS scenario.
// Validate ContainerType is set as Docker
if service.state.OrchestratorType != cns.KubernetesCRD {
logger.Errorf("[Azure CNS] Error. Unsupported OrchestratorType: %s", service.state.OrchestratorType)
return UnsupportedOrchestratorType
}

// Validate PrimaryCA must never be empty
err := validateIPSubnet(req.IPConfiguration.IPSubnet)
if err != nil {
logger.Errorf("[Azure CNS] Error. PrimaryCA is invalid, NC Req: %v", req)
return InvalidPrimaryIPConfig
}

// Validate SecondaryIPConfig
for ipId, secIpconfig := range req.SecondaryIPConfigs {
// Validate Ipconfig
err := validateIPSubnet(secIpconfig.IPSubnet)
if err != nil {
logger.Errorf("[Azure CNS] Error. SecondaryIpConfig, Id:%s is invalid, SecondaryIPConfig: %v, ncId: %s", ipId, secIpconfig, req.NetworkContainerid)
return InvalidSecondaryIPConfig
}
}

// Validate if state exists already
existingNCInfo, ok := service.getNetworkContainerDetails(req.NetworkContainerid)

if ok {
existingReq := existingNCInfo.CreateNetworkContainerRequest
if reflect.DeepEqual(existingReq.IPConfiguration, req.IPConfiguration) != true {
logger.Errorf("[Azure CNS] Error. PrimaryCA is not same, NCId %s, old CA %s, new CA %s", req.NetworkContainerid, existingReq.PrimaryInterfaceIdentifier, req.PrimaryInterfaceIdentifier)
return PrimaryCANotSame
}
}

// This will Create Or Update the NC state.
returnCode, returnMessage := service.saveNetworkContainerGoalState(req)

// If the NC was created successfully, log NC snapshot.
if returnCode == 0 {
logNCSnapshot(req)
} else {
logger.Errorf(returnMessage)
}

return returnCode
}
Loading