Skip to content

Commit fda89d0

Browse files
authored
[CNI] Update CNI to pass IP address on delete (#875)
* release with ip address * CNI contract update * update contract * pass endpoint info to invoker delete * update test * fix merge artifacts
1 parent 1fa243e commit fda89d0

File tree

7 files changed

+49
-32
lines changed

7 files changed

+49
-32
lines changed

cni/network/invoker.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"net"
55

66
"github.com/Azure/azure-container-networking/cni"
7+
"github.com/Azure/azure-container-networking/network"
78
cniTypesCurr "github.com/containernetworking/cni/pkg/types/current"
89
)
910

@@ -16,5 +17,5 @@ type IPAMInvoker interface {
1617
Add(nwCfg *cni.NetworkConfig, subnetPrefix *net.IPNet, options map[string]interface{}) (*cniTypesCurr.Result, *cniTypesCurr.Result, error)
1718

1819
//Delete calls to the invoker source, and returns error. Returning an error here will fail the CNI Delete call.
19-
Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, options map[string]interface{}) error
20+
Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, epInfo *network.EndpointInfo, options map[string]interface{}) error
2021
}

cni/network/invoker_azure.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (invoker *AzureIPAMInvoker) Add(nwCfg *cni.NetworkConfig, subnetPrefix *net
5050
defer func() {
5151
if err != nil {
5252
if len(result.IPs) > 0 {
53-
invoker.plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, options)
53+
invoker.plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, nil, options)
5454
} else {
5555
err = fmt.Errorf("No IP's to delete on error: %v", err)
5656
}
@@ -79,7 +79,7 @@ func (invoker *AzureIPAMInvoker) Add(nwCfg *cni.NetworkConfig, subnetPrefix *net
7979
return result, resultV6, err
8080
}
8181

82-
func (invoker *AzureIPAMInvoker) Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, options map[string]interface{}) error {
82+
func (invoker *AzureIPAMInvoker) Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, _ *network.EndpointInfo, options map[string]interface{}) error {
8383

8484
if nwCfg == nil {
8585
return invoker.plugin.Errorf("nil nwCfg passed to CNI ADD, stack: %+v", string(debug.Stack()))

cni/network/invoker_cns.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func setHostOptions(nwCfg *cni.NetworkConfig, hostSubnetPrefix *net.IPNet, ncSub
168168
}
169169

170170
// Delete calls into the releaseipconfiguration API in CNS
171-
func (invoker *CNSIPAMInvoker) Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, options map[string]interface{}) error {
171+
func (invoker *CNSIPAMInvoker) Delete(address *net.IPNet, nwCfg *cni.NetworkConfig, epInfo *network.EndpointInfo, options map[string]interface{}) error {
172172

173173
// Parse Pod arguments.
174174
podInfo := cns.KubernetesPodInfo{PodName: invoker.podName, PodNamespace: invoker.podNamespace}
@@ -178,5 +178,22 @@ func (invoker *CNSIPAMInvoker) Delete(address *net.IPNet, nwCfg *cni.NetworkConf
178178
return err
179179
}
180180

181-
return invoker.cnsClient.ReleaseIPAddress(orchestratorContext)
181+
req := cns.IPConfigRequest{
182+
OrchestratorContext: orchestratorContext,
183+
}
184+
185+
if address != nil {
186+
req.DesiredIPAddress = address.IP.String()
187+
} else {
188+
log.Printf("CNS invoker called with empty IP address")
189+
}
190+
191+
if epInfo != nil {
192+
req.PodInterfaceID = epInfo.Id
193+
req.InfraContainerID = epInfo.ContainerID
194+
} else {
195+
log.Printf("CNS invoker called with empty endpoint information")
196+
}
197+
198+
return invoker.cnsClient.ReleaseIPAddress(&req)
182199
}

cni/network/network.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,10 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) error {
482482
defer func() {
483483
if err != nil {
484484
if result != nil && len(result.IPs) > 0 {
485-
plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, options)
485+
plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, epInfo, options)
486486
}
487487
if resultV6 != nil && len(resultV6.IPs) > 0 {
488-
plugin.ipamInvoker.Delete(&resultV6.IPs[0].Address, nwCfg, options)
488+
plugin.ipamInvoker.Delete(&resultV6.IPs[0].Address, nwCfg, epInfo, options)
489489
}
490490
}
491491
}()
@@ -586,10 +586,10 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) error {
586586
defer func() {
587587
if err != nil {
588588
if result != nil && len(result.IPs) > 0 {
589-
plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, nwInfo.Options)
589+
plugin.ipamInvoker.Delete(&result.IPs[0].Address, nwCfg, epInfo, nwInfo.Options)
590590
}
591591
if resultV6 != nil && len(resultV6.IPs) > 0 {
592-
plugin.ipamInvoker.Delete(&resultV6.IPs[0].Address, nwCfg, nwInfo.Options)
592+
plugin.ipamInvoker.Delete(&resultV6.IPs[0].Address, nwCfg, epInfo, nwInfo.Options)
593593
}
594594
}
595595
}()
@@ -889,7 +889,7 @@ func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
889889
if !nwCfg.MultiTenancy {
890890
// attempt to release address associated with this Endpoint id
891891
// This is to ensure clean up is done even in failure cases
892-
err = plugin.ipamInvoker.Delete(nil, nwCfg, nwInfo.Options)
892+
err = plugin.ipamInvoker.Delete(nil, nwCfg, epInfo, nwInfo.Options)
893893
if err != nil {
894894
log.Printf("Network not found, attempted to release address with error: %v", err)
895895
}
@@ -908,7 +908,7 @@ func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
908908
// attempt to release address associated with this Endpoint id
909909
// This is to ensure clean up is done even in failure cases
910910
log.Printf("release ip ep not found")
911-
if err = plugin.ipamInvoker.Delete(nil, nwCfg, nwInfo.Options); err != nil {
911+
if err = plugin.ipamInvoker.Delete(nil, nwCfg, epInfo, nwInfo.Options); err != nil {
912912
log.Printf("Endpoint not found, attempted to release address with error: %v", err)
913913
}
914914
}
@@ -931,7 +931,7 @@ func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
931931
// Call into IPAM plugin to release the endpoint's addresses.
932932
for _, address := range epInfo.IPAddresses {
933933
log.Printf("release ip:%s", address.IP.String())
934-
err = plugin.ipamInvoker.Delete(&address, nwCfg, nwInfo.Options)
934+
err = plugin.ipamInvoker.Delete(&address, nwCfg, epInfo, nwInfo.Options)
935935
if err != nil {
936936
err = plugin.Errorf("Failed to release address %v with error: %v", address, err)
937937
return err
@@ -940,7 +940,7 @@ func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
940940
} else if epInfo.EnableInfraVnet {
941941
nwCfg.Ipam.Subnet = nwInfo.Subnets[0].Prefix.String()
942942
nwCfg.Ipam.Address = epInfo.InfraVnetIP.IP.String()
943-
err = plugin.ipamInvoker.Delete(nil, nwCfg, nwInfo.Options)
943+
err = plugin.ipamInvoker.Delete(nil, nwCfg, epInfo, nwInfo.Options)
944944
if err != nil {
945945
log.Printf("Failed to release address: %v", err)
946946
err = plugin.Errorf("Failed to release address %v with error: %v", nwCfg.Ipam.Address, err)

cns/NetworkContainerContract.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,14 @@ type HostIPInfo struct {
218218

219219
type IPConfigRequest struct {
220220
DesiredIPAddress string
221+
PodInterfaceID string
222+
InfraContainerID string
221223
OrchestratorContext json.RawMessage
222224
}
223225

224226
func (i IPConfigRequest) String() string {
225-
return fmt.Sprintf("[IPConfigRequest: DesiredIPAddress %s, OrchestratorContext %s]",
226-
i.DesiredIPAddress, string(i.OrchestratorContext))
227+
return fmt.Sprintf("[IPConfigRequest: DesiredIPAddress %s, PodInterfaceID %s, InfraContainerID %s, OrchestratorContext %s]",
228+
i.DesiredIPAddress, i.PodInterfaceID, i.InfraContainerID, string(i.OrchestratorContext))
227229
}
228230

229231
// IPConfigResponse is used in CNS IPAM mode as a response to CNI ADD

cns/cnsclient/cnsclient.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,6 @@ func (cnsClient *CNSClient) RequestIPAddress(orchestratorContext []byte) (*cns.I
218218
response *cns.IPConfigResponse
219219
)
220220

221-
defer func() {
222-
if err != nil {
223-
cnsClient.ReleaseIPAddress(orchestratorContext)
224-
}
225-
}()
226-
227221
var body bytes.Buffer
228222

229223
url := cnsClient.connectionURL + cns.RequestIPConfig
@@ -232,6 +226,12 @@ func (cnsClient *CNSClient) RequestIPAddress(orchestratorContext []byte) (*cns.I
232226
OrchestratorContext: orchestratorContext,
233227
}
234228

229+
defer func() {
230+
if err != nil {
231+
cnsClient.ReleaseIPAddress(payload)
232+
}
233+
}()
234+
235235
err = json.NewEncoder(&body).Encode(payload)
236236
if err != nil {
237237
log.Errorf("encoding json failed with %v", err)
@@ -266,27 +266,24 @@ func (cnsClient *CNSClient) RequestIPAddress(orchestratorContext []byte) (*cns.I
266266
return response, err
267267
}
268268

269-
// ReleaseIPAddress calls releaseIPAddress on CNS
270-
func (cnsClient *CNSClient) ReleaseIPAddress(orchestratorContext []byte) error {
269+
// ReleaseIPAddress calls releaseIPAddress on CNS, ipaddress ex: (10.0.0.1)
270+
func (cnsClient *CNSClient) ReleaseIPAddress(ipconfig *cns.IPConfigRequest) error {
271271
var (
272272
err error
273273
res *http.Response
274274
body bytes.Buffer
275275
)
276276

277277
url := cnsClient.connectionURL + cns.ReleaseIPConfig
278-
log.Printf("ReleaseIPAddress url %v", url)
279-
280-
payload := &cns.IPConfigRequest{
281-
OrchestratorContext: orchestratorContext,
282-
}
283278

284-
err = json.NewEncoder(&body).Encode(payload)
279+
err = json.NewEncoder(&body).Encode(ipconfig)
285280
if err != nil {
286281
log.Errorf("encoding json failed with %v", err)
287282
return err
288283
}
289284

285+
log.Printf("Releasing ipconfig %s", string(body.Bytes()))
286+
290287
res, err = cnsClient.httpc.Post(url, contentTypeJSON, &body)
291288
if err != nil {
292289
log.Errorf("[Azure CNSClient] HTTP Post returned error %v", err.Error())

cns/cnsclient/cnsclient_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func TestCNSClientRequestAndRelease(t *testing.T) {
227227
}
228228

229229
// no IP reservation found with that context, expect no failure.
230-
err = cnsClient.ReleaseIPAddress(orchestratorContext)
230+
err = cnsClient.ReleaseIPAddress(&cns.IPConfigRequest{OrchestratorContext: orchestratorContext})
231231
if err != nil {
232232
t.Fatalf("Release ip idempotent call failed: %+v", err)
233233
}
@@ -278,7 +278,7 @@ func TestCNSClientRequestAndRelease(t *testing.T) {
278278
t.Log(ipaddresses)
279279

280280
// release requested IP address, expect success
281-
err = cnsClient.ReleaseIPAddress(orchestratorContext)
281+
err = cnsClient.ReleaseIPAddress(&cns.IPConfigRequest{DesiredIPAddress: ipaddresses[0].IPAddress, OrchestratorContext: orchestratorContext})
282282
if err != nil {
283283
t.Fatalf("Expected to not fail when releasing IP reservation found with context: %+v", err)
284284
}
@@ -318,7 +318,7 @@ func TestCNSClientPodContextApi(t *testing.T) {
318318
t.Log(podcontext)
319319

320320
// release requested IP address, expect success
321-
err = cnsClient.ReleaseIPAddress(orchestratorContext)
321+
err = cnsClient.ReleaseIPAddress(&cns.IPConfigRequest{OrchestratorContext: orchestratorContext})
322322
if err != nil {
323323
t.Fatalf("Expected to not fail when releasing IP reservation found with context: %+v", err)
324324
}

0 commit comments

Comments
 (0)