 894af07e37
			
		
	
	894af07e37
	
	
	
		
			
			Adds an equivalent TestSandboxRemoveWithoutIPLeakage for Windows, in which we assert that the IPs are not leaked when a Pod's HNS namespace dissapears and the Pod is deleted afterwards. Signed-off-by: Claudiu Belu <cbelu@cloudbasesolutions.com>
		
			
				
	
	
		
			150 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build windows
 | |
| // +build windows
 | |
| 
 | |
| /*
 | |
|    Copyright The containerd Authors.
 | |
| 
 | |
|    Licensed under the Apache License, Version 2.0 (the "License");
 | |
|    you may not use this file except in compliance with the License.
 | |
|    You may obtain a copy of the License at
 | |
| 
 | |
|        http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|    Unless required by applicable law or agreed to in writing, software
 | |
|    distributed under the License is distributed on an "AS IS" BASIS,
 | |
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|    See the License for the specific language governing permissions and
 | |
|    limitations under the License.
 | |
| */
 | |
| 
 | |
| package integration
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | |
| )
 | |
| 
 | |
| func TestSandboxRemoveWithoutIPLeakage(t *testing.T) {
 | |
| 	t.Logf("Make sure host-local ipam is in use")
 | |
| 	config, err := CRIConfig()
 | |
| 	require.NoError(t, err)
 | |
| 	fs, err := os.ReadDir(config.NetworkPluginConfDir)
 | |
| 	require.NoError(t, err)
 | |
| 	require.NotEmpty(t, fs)
 | |
| 	f := filepath.Join(config.NetworkPluginConfDir, fs[0].Name())
 | |
| 	cniConfig, err := os.ReadFile(f)
 | |
| 	require.NoError(t, err)
 | |
| 	if !strings.Contains(string(cniConfig), "azure-vnet-ipam") {
 | |
| 		t.Skip("azure-vnet ipam is not in use")
 | |
| 	}
 | |
| 
 | |
| 	t.Logf("Create a sandbox")
 | |
| 	sbConfig := PodSandboxConfig("sandbox", "remove-without-ip-leakage")
 | |
| 	sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
 | |
| 	require.NoError(t, err)
 | |
| 	defer func() {
 | |
| 		// Make sure the sandbox is cleaned up in any case.
 | |
| 		runtimeService.StopPodSandbox(sb)
 | |
| 		runtimeService.RemovePodSandbox(sb)
 | |
| 	}()
 | |
| 
 | |
| 	t.Logf("Get pod information")
 | |
| 	status, info, err := SandboxInfo(sb)
 | |
| 	require.NoError(t, err)
 | |
| 	ip := status.GetNetwork().GetIp()
 | |
| 	require.NotEmpty(t, ip)
 | |
| 	require.NotNil(t, info.RuntimeSpec.Windows)
 | |
| 	netNS := info.RuntimeSpec.Windows.Network.NetworkNamespace
 | |
| 	require.NotEmpty(t, netNS, "network namespace should be set")
 | |
| 
 | |
| 	t.Logf("Should be able to find the pod ip in host-local checkpoint")
 | |
| 	checkIP := func(ip string) bool {
 | |
| 		f, err := os.Open("azure-vnet-ipam.json")
 | |
| 		require.NoError(t, err)
 | |
| 		defer f.Close()
 | |
| 
 | |
| 		data, err := ioutil.ReadAll(f)
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		var jsonData map[string]interface{}
 | |
| 		err = json.Unmarshal(data, &jsonData)
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		walkJSON := func(initial map[string]interface{}, elementNames ...string) map[string]interface{} {
 | |
| 			element := initial
 | |
| 			for _, name := range elementNames {
 | |
| 				element = element[name].(map[string]interface{})
 | |
| 			}
 | |
| 
 | |
| 			return element
 | |
| 		}
 | |
| 
 | |
| 		pools := walkJSON(jsonData, "IPAM", "AddressSpaces", "local", "Pools")
 | |
| 
 | |
| 		ipAddr := net.ParseIP(ip)
 | |
| 		var ipPool map[string]interface{}
 | |
| 		for poolID, pool := range pools {
 | |
| 			// Each pool will contain its key as its subnet.
 | |
| 			_, ipnet, _ := net.ParseCIDR(poolID)
 | |
| 			if ipnet.Contains(ipAddr) {
 | |
| 				ipPool = pool.(map[string]interface{})
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Search in the IP Pool and see if it's in use or not.
 | |
| 		for address, details := range walkJSON(ipPool, "Addresses") {
 | |
| 			if address == ip {
 | |
| 				d := details.(map[string]interface{})
 | |
| 				return d["InUse"].(bool)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return false
 | |
| 	}
 | |
| 	require.True(t, checkIP(ip))
 | |
| 
 | |
| 	t.Logf("Kill sandbox container")
 | |
| 	require.NoError(t, KillPid(int(info.Pid)))
 | |
| 
 | |
| 	t.Logf("Delete network namespace")
 | |
| 	cmd := exec.Command("hnsdiag.exe", "delete", "namespaces", netNS)
 | |
| 	require.NoError(t, cmd.Run())
 | |
| 
 | |
| 	t.Logf("Network namespace should be closed")
 | |
| 	_, info, err = SandboxInfo(sb)
 | |
| 	require.NoError(t, err)
 | |
| 	assert.True(t, info.NetNSClosed)
 | |
| 
 | |
| 	t.Logf("Sandbox state should be NOTREADY")
 | |
| 	assert.NoError(t, Eventually(func() (bool, error) {
 | |
| 		status, err := runtimeService.PodSandboxStatus(sb)
 | |
| 		if err != nil {
 | |
| 			return false, err
 | |
| 		}
 | |
| 		return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil
 | |
| 	}, time.Second, 30*time.Second), "sandbox state should become NOTREADY")
 | |
| 
 | |
| 	t.Logf("Should still be able to find the pod ip in host-local checkpoint")
 | |
| 	assert.True(t, checkIP(ip))
 | |
| 
 | |
| 	t.Logf("Should be able to stop and remove the sandbox")
 | |
| 	assert.NoError(t, runtimeService.StopPodSandbox(sb))
 | |
| 	assert.NoError(t, runtimeService.RemovePodSandbox(sb))
 | |
| 
 | |
| 	t.Logf("Should not be able to find the pod ip in host-local checkpoint")
 | |
| 	assert.False(t, checkIP(ip), fmt.Sprintf("The IP: %s is still in use in azure-vnet-ipam.json", ip))
 | |
| }
 |