Skip to content

Commit 894af07

Browse files
committed
integration: Adds Windows equivalent for TestSandboxRemoveWithoutIPLeakage
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 <[email protected]>
1 parent ff7fd4e commit 894af07

2 files changed

Lines changed: 155 additions & 2 deletions

File tree

integration/main_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,12 @@ func KillProcess(name string) error {
377377
}
378378

379379
// KillPid kills the process by pid. kill is used.
380-
func KillPid(pid int) error { //nolint:unused
381-
output, err := exec.Command("kill", strconv.Itoa(pid)).CombinedOutput()
380+
func KillPid(pid int) error {
381+
command := "kill"
382+
if goruntime.GOOS == "windows" {
383+
command = "tskill"
384+
}
385+
output, err := exec.Command(command, strconv.Itoa(pid)).CombinedOutput()
382386
if err != nil {
383387
return errors.Errorf("failed to kill %d - error: %v, output: %q", pid, err, output)
384388
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright The containerd Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package integration
21+
22+
import (
23+
"encoding/json"
24+
"fmt"
25+
"io/ioutil"
26+
"net"
27+
"os"
28+
"os/exec"
29+
"path/filepath"
30+
"strings"
31+
"testing"
32+
"time"
33+
34+
"github.com/stretchr/testify/assert"
35+
"github.com/stretchr/testify/require"
36+
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
37+
)
38+
39+
func TestSandboxRemoveWithoutIPLeakage(t *testing.T) {
40+
t.Logf("Make sure host-local ipam is in use")
41+
config, err := CRIConfig()
42+
require.NoError(t, err)
43+
fs, err := os.ReadDir(config.NetworkPluginConfDir)
44+
require.NoError(t, err)
45+
require.NotEmpty(t, fs)
46+
f := filepath.Join(config.NetworkPluginConfDir, fs[0].Name())
47+
cniConfig, err := os.ReadFile(f)
48+
require.NoError(t, err)
49+
if !strings.Contains(string(cniConfig), "azure-vnet-ipam") {
50+
t.Skip("azure-vnet ipam is not in use")
51+
}
52+
53+
t.Logf("Create a sandbox")
54+
sbConfig := PodSandboxConfig("sandbox", "remove-without-ip-leakage")
55+
sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
56+
require.NoError(t, err)
57+
defer func() {
58+
// Make sure the sandbox is cleaned up in any case.
59+
runtimeService.StopPodSandbox(sb)
60+
runtimeService.RemovePodSandbox(sb)
61+
}()
62+
63+
t.Logf("Get pod information")
64+
status, info, err := SandboxInfo(sb)
65+
require.NoError(t, err)
66+
ip := status.GetNetwork().GetIp()
67+
require.NotEmpty(t, ip)
68+
require.NotNil(t, info.RuntimeSpec.Windows)
69+
netNS := info.RuntimeSpec.Windows.Network.NetworkNamespace
70+
require.NotEmpty(t, netNS, "network namespace should be set")
71+
72+
t.Logf("Should be able to find the pod ip in host-local checkpoint")
73+
checkIP := func(ip string) bool {
74+
f, err := os.Open("azure-vnet-ipam.json")
75+
require.NoError(t, err)
76+
defer f.Close()
77+
78+
data, err := ioutil.ReadAll(f)
79+
require.NoError(t, err)
80+
81+
var jsonData map[string]interface{}
82+
err = json.Unmarshal(data, &jsonData)
83+
require.NoError(t, err)
84+
85+
walkJSON := func(initial map[string]interface{}, elementNames ...string) map[string]interface{} {
86+
element := initial
87+
for _, name := range elementNames {
88+
element = element[name].(map[string]interface{})
89+
}
90+
91+
return element
92+
}
93+
94+
pools := walkJSON(jsonData, "IPAM", "AddressSpaces", "local", "Pools")
95+
96+
ipAddr := net.ParseIP(ip)
97+
var ipPool map[string]interface{}
98+
for poolID, pool := range pools {
99+
// Each pool will contain its key as its subnet.
100+
_, ipnet, _ := net.ParseCIDR(poolID)
101+
if ipnet.Contains(ipAddr) {
102+
ipPool = pool.(map[string]interface{})
103+
break
104+
}
105+
}
106+
107+
// Search in the IP Pool and see if it's in use or not.
108+
for address, details := range walkJSON(ipPool, "Addresses") {
109+
if address == ip {
110+
d := details.(map[string]interface{})
111+
return d["InUse"].(bool)
112+
}
113+
}
114+
115+
return false
116+
}
117+
require.True(t, checkIP(ip))
118+
119+
t.Logf("Kill sandbox container")
120+
require.NoError(t, KillPid(int(info.Pid)))
121+
122+
t.Logf("Delete network namespace")
123+
cmd := exec.Command("hnsdiag.exe", "delete", "namespaces", netNS)
124+
require.NoError(t, cmd.Run())
125+
126+
t.Logf("Network namespace should be closed")
127+
_, info, err = SandboxInfo(sb)
128+
require.NoError(t, err)
129+
assert.True(t, info.NetNSClosed)
130+
131+
t.Logf("Sandbox state should be NOTREADY")
132+
assert.NoError(t, Eventually(func() (bool, error) {
133+
status, err := runtimeService.PodSandboxStatus(sb)
134+
if err != nil {
135+
return false, err
136+
}
137+
return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil
138+
}, time.Second, 30*time.Second), "sandbox state should become NOTREADY")
139+
140+
t.Logf("Should still be able to find the pod ip in host-local checkpoint")
141+
assert.True(t, checkIP(ip))
142+
143+
t.Logf("Should be able to stop and remove the sandbox")
144+
assert.NoError(t, runtimeService.StopPodSandbox(sb))
145+
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
146+
147+
t.Logf("Should not be able to find the pod ip in host-local checkpoint")
148+
assert.False(t, checkIP(ip), fmt.Sprintf("The IP: %s is still in use in azure-vnet-ipam.json", ip))
149+
}

0 commit comments

Comments
 (0)