77 "strings"
88
99 "github.com/Azure/azure-container-networking/cns"
10- "github.com/Azure/azure-container-networking/cns/logger"
11- "github.com/Azure/azure-container-networking/cns/restserver"
12- cnstypes "github.com/Azure/azure-container-networking/cns/types"
1310 "github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
1411 "github.com/pkg/errors"
1512)
2320 ErrUnsupportedNCQuantity = errors .New ("unsupported number of network containers" )
2421)
2522
26- type cnsClient interface {
27- CreateOrUpdateNetworkContainerInternal (* cns.CreateNetworkContainerRequest ) cnstypes.ResponseCode
28- }
29-
30- var _ nodeNetworkConfigListener = (NodeNetworkConfigListenerFunc )(nil ) //nolint:gocritic // clarity
31-
32- type NodeNetworkConfigListenerFunc func (* v1alpha.NodeNetworkConfig ) error
33-
34- func (f NodeNetworkConfigListenerFunc ) Update (nnc * v1alpha.NodeNetworkConfig ) error {
35- return f (nnc )
36- }
37-
38- // SwiftNodeNetworkConfigListener return a function which satisfies the NodeNetworkConfigListener
39- // interface. It accepts a CreateOrUpdateNetworkContainerInternal implementation, and when Update
40- // is called, transforms the NNC in to an NC Request and calls the CNS Service implementation with
41- // that request.
42- func SwiftNodeNetworkConfigListener (cnscli cnsClient ) NodeNetworkConfigListenerFunc {
43- return func (nnc * v1alpha.NodeNetworkConfig ) error {
44- // Create NC request and hand it off to CNS
45- ncRequest , err := CRDStatusToNCRequest (& nnc .Status )
46- if err != nil {
47- return errors .Wrap (err , "failed to convert NNC status to network container request" )
48- }
49- responseCode := cnscli .CreateOrUpdateNetworkContainerInternal (& ncRequest )
50- err = restserver .ResponseCodeToError (responseCode )
51- if err != nil {
52- logger .Errorf ("[cns-rc] Error creating or updating NC in reconcile: %v" , err )
53- return errors .Wrap (err , "failed to create or update network container" )
54- }
55-
56- // record assigned IPs metric
57- allocatedIPs .Set (float64 (len (nnc .Status .NetworkContainers [0 ].IPAssignments )))
58- return nil
59- }
60- }
61-
62- // CRDStatusToNCRequest translates a crd status to createnetworkcontainer request
63- func CRDStatusToNCRequest (status * v1alpha.NodeNetworkConfigStatus ) (cns.CreateNetworkContainerRequest , error ) {
64- // if NNC has no NC, return an empty request
65- if len (status .NetworkContainers ) == 0 {
66- return cns.CreateNetworkContainerRequest {}, nil
67- }
68-
69- // only support a single NC per node, error on more
70- if len (status .NetworkContainers ) > 1 {
71- return cns.CreateNetworkContainerRequest {}, errors .Wrapf (ErrUnsupportedNCQuantity , "count: %d" , len (status .NetworkContainers ))
72- }
73-
74- nc := status .NetworkContainers [0 ]
75-
23+ // CreateNCRequestFromDynamicNC generates a CreateNetworkContainerRequest from a dynamic NetworkContainer.
24+ //nolint:gocritic //ignore hugeparam
25+ func CreateNCRequestFromDynamicNC (nc v1alpha.NetworkContainer ) (* cns.CreateNetworkContainerRequest , error ) {
7626 primaryIP := nc .PrimaryIP
7727 // if the PrimaryIP is not a CIDR, append a /32
7828 if ! strings .Contains (primaryIP , "/" ) {
@@ -81,35 +31,75 @@ func CRDStatusToNCRequest(status *v1alpha.NodeNetworkConfigStatus) (cns.CreateNe
8131
8232 primaryPrefix , err := netip .ParsePrefix (primaryIP )
8333 if err != nil {
84- return cns. CreateNetworkContainerRequest {} , errors .Wrapf (err , "IP: %s" , primaryIP )
34+ return nil , errors .Wrapf (err , "IP: %s" , primaryIP )
8535 }
8636
87- secondaryPrefix , err := netip .ParsePrefix (nc .SubnetAddressSpace )
37+ subnetPrefix , err := netip .ParsePrefix (nc .SubnetAddressSpace )
8838 if err != nil {
89- return cns. CreateNetworkContainerRequest {} , errors .Wrapf (err , "invalid SubnetAddressSpace %s" , nc .SubnetAddressSpace )
39+ return nil , errors .Wrapf (err , "invalid SubnetAddressSpace %s" , nc .SubnetAddressSpace )
9040 }
9141
9242 subnet := cns.IPSubnet {
9343 IPAddress : primaryPrefix .Addr ().String (),
94- PrefixLength : uint8 (secondaryPrefix .Bits ()),
44+ PrefixLength : uint8 (subnetPrefix .Bits ()),
9545 }
9646
9747 secondaryIPConfigs := map [string ]cns.SecondaryIPConfig {}
9848 for _ , ipAssignment := range nc .IPAssignments {
9949 secondaryIP := net .ParseIP (ipAssignment .IP )
10050 if secondaryIP == nil {
101- return cns. CreateNetworkContainerRequest {} , errors .Wrapf (ErrInvalidSecondaryIP , "IP: %s" , ipAssignment .IP )
51+ return nil , errors .Wrapf (ErrInvalidSecondaryIP , "IP: %s" , ipAssignment .IP )
10252 }
10353 secondaryIPConfigs [ipAssignment .Name ] = cns.SecondaryIPConfig {
10454 IPAddress : secondaryIP .String (),
10555 NCVersion : int (nc .Version ),
10656 }
10757 }
108- return cns.CreateNetworkContainerRequest {
58+ return & cns.CreateNetworkContainerRequest {
59+ SecondaryIPConfigs : secondaryIPConfigs ,
60+ NetworkContainerid : nc .ID ,
61+ NetworkContainerType : cns .Docker ,
62+ Version : strconv .FormatInt (nc .Version , 10 ), //nolint:gomnd // it's decimal
63+ IPConfiguration : cns.IPConfiguration {
64+ IPSubnet : subnet ,
65+ GatewayIPAddress : nc .DefaultGateway ,
66+ },
67+ }, nil
68+ }
69+
70+ // CreateNCRequestFromStaticNC generates a CreateNetworkContainerRequest from a static NetworkContainer.
71+ //nolint:gocritic //ignore hugeparam
72+ func CreateNCRequestFromStaticNC (nc v1alpha.NetworkContainer ) (* cns.CreateNetworkContainerRequest , error ) {
73+ primaryPrefix , err := netip .ParsePrefix (nc .PrimaryIP )
74+ if err != nil {
75+ return nil , errors .Wrapf (err , "IP: %s" , nc .PrimaryIP )
76+ }
77+
78+ subnetPrefix , err := netip .ParsePrefix (nc .SubnetAddressSpace )
79+ if err != nil {
80+ return nil , errors .Wrapf (err , "invalid SubnetAddressSpace %s" , nc .SubnetAddressSpace )
81+ }
82+ subnet := cns.IPSubnet {
83+ IPAddress : primaryPrefix .Addr ().String (),
84+ PrefixLength : uint8 (subnetPrefix .Bits ()),
85+ }
86+
87+ secondaryIPConfigs := map [string ]cns.SecondaryIPConfig {}
88+
89+ // iterate through all IP addresses in the subnet described by primaryPrefix and
90+ // add them to the request as secondary IPConfigs.
91+ zeroAddr := primaryPrefix .Masked ().Addr () // the masked address is the 0th IP in the subnet
92+ for addr := zeroAddr .Next (); primaryPrefix .Contains (addr ); addr = addr .Next () {
93+ secondaryIPConfigs [addr .String ()] = cns.SecondaryIPConfig {
94+ IPAddress : addr .String (),
95+ NCVersion : int (nc .Version ),
96+ }
97+ }
98+ return & cns.CreateNetworkContainerRequest {
10999 SecondaryIPConfigs : secondaryIPConfigs ,
110100 NetworkContainerid : nc .ID ,
111101 NetworkContainerType : cns .Docker ,
112- Version : strconv .FormatInt (nc .Version , 10 ),
102+ Version : strconv .FormatInt (nc .Version , 10 ), //nolint:gomnd // it's decimal
113103 IPConfiguration : cns.IPConfiguration {
114104 IPSubnet : subnet ,
115105 GatewayIPAddress : nc .DefaultGateway ,
0 commit comments