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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -500,11 +500,11 @@ COVER_PKG ?= .
test-all: ## run all unit tests.
@$(eval COVER_FILTER=`go list --tags ignore_uncovered,ignore_autogenerated $(COVER_PKG)/... | tr '\n' ','`)
@echo Test coverpkg: $(COVER_FILTER)
go test -buildvcs=false -tags "unit" -coverpkg=$(COVER_FILTER) -v -race -covermode atomic -failfast -coverprofile=coverage.out $(COVER_PKG)/...
go test -buildvcs=false -tags "unit" -coverpkg=$(COVER_FILTER) -race -covermode atomic -failfast -coverprofile=coverage.out $(COVER_PKG)/...


test-integration: ## run all integration tests.
go test -buildvcs=false -timeout 1h -coverpkg=./... -v -race -covermode atomic -coverprofile=coverage.out -tags=integration ./test/integration...
go test -buildvcs=false -timeout 1h -coverpkg=./... -race -covermode atomic -coverprofile=coverage.out -tags=integration ./test/integration...

test-cyclonus: ## run the cyclonus test for npm.
cd test/cyclonus && bash ./test-cyclonus.sh
Expand Down
2 changes: 1 addition & 1 deletion cns/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func addTestStateToRestServer(t *testing.T, secondaryIps []string) {
t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode)
}

svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
_ = svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
Spec: v1alpha.NodeNetworkConfigSpec{
RequestedIPCount: 16,
IPsNotInUse: []string{"abc"},
Expand Down
2 changes: 1 addition & 1 deletion cns/fakes/requestcontrollerfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (rc *RequestControllerFake) Reconcile(removePendingReleaseIPs bool) error {
}

// update
rc.cnscli.PoolMonitor.Update(rc.NNC)
_ = rc.cnscli.PoolMonitor.Update(rc.NNC)
return nil
}

Expand Down
4 changes: 2 additions & 2 deletions cns/restserver/internalapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ func createAndValidateNCRequest(t *testing.T, secondaryIPConfigs map[string]cns.
if returnCode != 0 {
t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode)
}
svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
_ = svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
Expand Down Expand Up @@ -598,7 +598,7 @@ func createNCReqInternal(t *testing.T, secondaryIPConfigs map[string]cns.Seconda
if returnCode != 0 {
t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode)
}
svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
_ = svc.IPAMPoolMonitor.Update(&v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
Expand Down
30 changes: 17 additions & 13 deletions cns/service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,19 +865,23 @@ func reconcileInitialCNSState(ctx context.Context, cli nodeNetworkConfigGetter,
}

// Convert to CreateNetworkContainerRequest
ncRequest, err := kubecontroller.CRDStatusToNCRequest(&nnc.Status)
if err != nil {
return errors.Wrap(err, "failed to convert NNC status to network container request")
}
// rebuild CNS state
podInfoByIP, err := podInfoByIPProvider.PodInfoByIP()
if err != nil {
return errors.Wrap(err, "provider failed to provide PodInfoByIP")
}
for i := range nnc.Status.NetworkContainers {
ncRequest, err := kubecontroller.CreateNCRequestFromDynamicNC(nnc.Status.NetworkContainers[i])
Copy link
Member

Choose a reason for hiding this comment

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

shall we change the API name back to CRDStatusToNCRequest?

Copy link
Collaborator Author

@rbtr rbtr Apr 18, 2022

Choose a reason for hiding this comment

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

no, we're creating the NC Request(s) from the NC(s), not from the Status

if err != nil {
return errors.Wrap(err, "failed to convert NNC status to network container request")
}
// rebuild CNS state
podInfoByIP, err := podInfoByIPProvider.PodInfoByIP()
if err != nil {
return errors.Wrap(err, "provider failed to provide PodInfoByIP")
}

// Call cnsclient init cns passing those two things.
err = restserver.ResponseCodeToError(ncReconciler.ReconcileNCState(&ncRequest, podInfoByIP, nnc))
return errors.Wrap(err, "failed to reconcile NC state")
// Call cnsclient init cns passing those two things.
if err := restserver.ResponseCodeToError(ncReconciler.ReconcileNCState(ncRequest, podInfoByIP, nnc)); err != nil {
return errors.Wrap(err, "failed to reconcile NC state")
}
}
return nil
}

// InitializeCRDState builds and starts the CRD controllers.
Expand Down Expand Up @@ -1010,7 +1014,7 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
return errors.Wrapf(err, "failed to get node %s", nodeName)
}

reconciler := kubecontroller.NewReconciler(nnccli, kubecontroller.SwiftNodeNetworkConfigListener(httpRestServiceImplementation), poolMonitor)
reconciler := kubecontroller.NewReconciler(httpRestServiceImplementation, nnccli, poolMonitor)
// pass Node to the Reconciler for Controller xref
if err := reconciler.SetupWithManager(manager, node); err != nil {
return errors.Wrapf(err, "failed to setup reconciler with manager")
Expand Down
110 changes: 50 additions & 60 deletions cns/singletenantcontroller/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import (
"strings"

"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/restserver"
cnstypes "github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
"github.com/pkg/errors"
)
Expand All @@ -23,56 +20,9 @@ var (
ErrUnsupportedNCQuantity = errors.New("unsupported number of network containers")
)

type cnsClient interface {
CreateOrUpdateNetworkContainerInternal(*cns.CreateNetworkContainerRequest) cnstypes.ResponseCode
}

var _ nodeNetworkConfigListener = (NodeNetworkConfigListenerFunc)(nil) //nolint:gocritic // clarity

type NodeNetworkConfigListenerFunc func(*v1alpha.NodeNetworkConfig) error

func (f NodeNetworkConfigListenerFunc) Update(nnc *v1alpha.NodeNetworkConfig) error {
return f(nnc)
}

// SwiftNodeNetworkConfigListener return a function which satisfies the NodeNetworkConfigListener
// interface. It accepts a CreateOrUpdateNetworkContainerInternal implementation, and when Update
// is called, transforms the NNC in to an NC Request and calls the CNS Service implementation with
// that request.
func SwiftNodeNetworkConfigListener(cnscli cnsClient) NodeNetworkConfigListenerFunc {
return func(nnc *v1alpha.NodeNetworkConfig) error {
// Create NC request and hand it off to CNS
ncRequest, err := CRDStatusToNCRequest(&nnc.Status)
if err != nil {
return errors.Wrap(err, "failed to convert NNC status to network container request")
}
responseCode := cnscli.CreateOrUpdateNetworkContainerInternal(&ncRequest)
err = restserver.ResponseCodeToError(responseCode)
if err != nil {
logger.Errorf("[cns-rc] Error creating or updating NC in reconcile: %v", err)
return errors.Wrap(err, "failed to create or update network container")
}

// record assigned IPs metric
allocatedIPs.Set(float64(len(nnc.Status.NetworkContainers[0].IPAssignments)))
return nil
}
}

// CRDStatusToNCRequest translates a crd status to createnetworkcontainer request
func CRDStatusToNCRequest(status *v1alpha.NodeNetworkConfigStatus) (cns.CreateNetworkContainerRequest, error) {
// if NNC has no NC, return an empty request
if len(status.NetworkContainers) == 0 {
return cns.CreateNetworkContainerRequest{}, nil
}

// only support a single NC per node, error on more
if len(status.NetworkContainers) > 1 {
return cns.CreateNetworkContainerRequest{}, errors.Wrapf(ErrUnsupportedNCQuantity, "count: %d", len(status.NetworkContainers))
}

nc := status.NetworkContainers[0]

// CreateNCRequestFromDynamicNC generates a CreateNetworkContainerRequest from a dynamic NetworkContainer.
//nolint:gocritic //ignore hugeparam
func CreateNCRequestFromDynamicNC(nc v1alpha.NetworkContainer) (*cns.CreateNetworkContainerRequest, error) {
primaryIP := nc.PrimaryIP
// if the PrimaryIP is not a CIDR, append a /32
if !strings.Contains(primaryIP, "/") {
Expand All @@ -81,35 +31,75 @@ func CRDStatusToNCRequest(status *v1alpha.NodeNetworkConfigStatus) (cns.CreateNe

primaryPrefix, err := netip.ParsePrefix(primaryIP)
if err != nil {
return cns.CreateNetworkContainerRequest{}, errors.Wrapf(err, "IP: %s", primaryIP)
return nil, errors.Wrapf(err, "IP: %s", primaryIP)
}

secondaryPrefix, err := netip.ParsePrefix(nc.SubnetAddressSpace)
subnetPrefix, err := netip.ParsePrefix(nc.SubnetAddressSpace)
if err != nil {
return cns.CreateNetworkContainerRequest{}, errors.Wrapf(err, "invalid SubnetAddressSpace %s", nc.SubnetAddressSpace)
return nil, errors.Wrapf(err, "invalid SubnetAddressSpace %s", nc.SubnetAddressSpace)
}

subnet := cns.IPSubnet{
IPAddress: primaryPrefix.Addr().String(),
PrefixLength: uint8(secondaryPrefix.Bits()),
PrefixLength: uint8(subnetPrefix.Bits()),
}

secondaryIPConfigs := map[string]cns.SecondaryIPConfig{}
for _, ipAssignment := range nc.IPAssignments {
secondaryIP := net.ParseIP(ipAssignment.IP)
if secondaryIP == nil {
return cns.CreateNetworkContainerRequest{}, errors.Wrapf(ErrInvalidSecondaryIP, "IP: %s", ipAssignment.IP)
return nil, errors.Wrapf(ErrInvalidSecondaryIP, "IP: %s", ipAssignment.IP)
}
secondaryIPConfigs[ipAssignment.Name] = cns.SecondaryIPConfig{
IPAddress: secondaryIP.String(),
NCVersion: int(nc.Version),
}
}
return cns.CreateNetworkContainerRequest{
return &cns.CreateNetworkContainerRequest{
SecondaryIPConfigs: secondaryIPConfigs,
NetworkContainerid: nc.ID,
NetworkContainerType: cns.Docker,
Version: strconv.FormatInt(nc.Version, 10), //nolint:gomnd // it's decimal
IPConfiguration: cns.IPConfiguration{
IPSubnet: subnet,
GatewayIPAddress: nc.DefaultGateway,
},
}, nil
}

// CreateNCRequestFromStaticNC generates a CreateNetworkContainerRequest from a static NetworkContainer.
//nolint:gocritic //ignore hugeparam
func CreateNCRequestFromStaticNC(nc v1alpha.NetworkContainer) (*cns.CreateNetworkContainerRequest, error) {
primaryPrefix, err := netip.ParsePrefix(nc.PrimaryIP)
if err != nil {
return nil, errors.Wrapf(err, "IP: %s", nc.PrimaryIP)
}

subnetPrefix, err := netip.ParsePrefix(nc.SubnetAddressSpace)
if err != nil {
return nil, errors.Wrapf(err, "invalid SubnetAddressSpace %s", nc.SubnetAddressSpace)
}
subnet := cns.IPSubnet{
IPAddress: primaryPrefix.Addr().String(),
PrefixLength: uint8(subnetPrefix.Bits()),
}

secondaryIPConfigs := map[string]cns.SecondaryIPConfig{}

// iterate through all IP addresses in the subnet described by primaryPrefix and
// add them to the request as secondary IPConfigs.
zeroAddr := primaryPrefix.Masked().Addr() // the masked address is the 0th IP in the subnet
for addr := zeroAddr.Next(); primaryPrefix.Contains(addr); addr = addr.Next() {
secondaryIPConfigs[addr.String()] = cns.SecondaryIPConfig{
IPAddress: addr.String(),
NCVersion: int(nc.Version),
}
}
return &cns.CreateNetworkContainerRequest{
SecondaryIPConfigs: secondaryIPConfigs,
NetworkContainerid: nc.ID,
NetworkContainerType: cns.Docker,
Version: strconv.FormatInt(nc.Version, 10),
Version: strconv.FormatInt(nc.Version, 10), //nolint:gomnd // it's decimal
IPConfiguration: cns.IPConfiguration{
IPSubnet: subnet,
GatewayIPAddress: nc.DefaultGateway,
Expand Down
Loading