@@ -17,14 +17,23 @@ limitations under the License.
1717package integration
1818
1919import (
20+ "encoding/json"
21+ "io/ioutil"
22+ "os"
23+ "path/filepath"
24+ "strings"
2025 "testing"
2126 "time"
2227
2328 "github.com/containerd/containerd"
29+ runtimespec "github.com/opencontainers/runtime-spec/specs-go"
2430 "github.com/stretchr/testify/assert"
2531 "github.com/stretchr/testify/require"
2632 "golang.org/x/net/context"
33+ "golang.org/x/sys/unix"
2734 runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
35+
36+ "github.com/containerd/cri/pkg/server"
2837)
2938
3039func TestSandboxCleanRemove (t * testing.T ) {
@@ -66,3 +75,100 @@ func TestSandboxCleanRemove(t *testing.T) {
6675 assert .NoError (t , runtimeService .StopPodSandbox (sb ))
6776 assert .NoError (t , runtimeService .RemovePodSandbox (sb ))
6877}
78+
79+ func TestSandboxRemoveWithoutIPLeakage (t * testing.T ) {
80+ ctx := context .Background ()
81+ const hostLocalCheckpointDir = "/var/lib/cni"
82+
83+ t .Logf ("Make sure host-local ipam is in use" )
84+ config , err := CRIConfig ()
85+ require .NoError (t , err )
86+ fs , err := ioutil .ReadDir (config .NetworkPluginConfDir )
87+ require .NoError (t , err )
88+ require .NotEmpty (t , fs )
89+ f := filepath .Join (config .NetworkPluginConfDir , fs [0 ].Name ())
90+ cniConfig , err := ioutil .ReadFile (f )
91+ require .NoError (t , err )
92+ if ! strings .Contains (string (cniConfig ), "host-local" ) {
93+ t .Skip ("host-local ipam is not in use" )
94+ }
95+
96+ t .Logf ("Create a sandbox" )
97+ sbConfig := PodSandboxConfig ("sandbox" , "remove-without-ip-leakage" )
98+ sb , err := runtimeService .RunPodSandbox (sbConfig , * runtimeHandler )
99+ require .NoError (t , err )
100+ defer func () {
101+ // Make sure the sandbox is cleaned up in any case.
102+ runtimeService .StopPodSandbox (sb )
103+ runtimeService .RemovePodSandbox (sb )
104+ }()
105+
106+ t .Logf ("Get pod information" )
107+ client , err := RawRuntimeClient ()
108+ require .NoError (t , err )
109+ resp , err := client .PodSandboxStatus (ctx , & runtime.PodSandboxStatusRequest {
110+ PodSandboxId : sb ,
111+ Verbose : true ,
112+ })
113+ require .NoError (t , err )
114+ status := resp .GetStatus ()
115+ info := resp .GetInfo ()
116+ ip := status .GetNetwork ().GetIp ()
117+ require .NotEmpty (t , ip )
118+ var sbInfo server.SandboxInfo
119+ require .NoError (t , json .Unmarshal ([]byte (info ["info" ]), & sbInfo ))
120+ require .NotNil (t , sbInfo .RuntimeSpec .Linux )
121+ var netNS string
122+ for _ , n := range sbInfo .RuntimeSpec .Linux .Namespaces {
123+ if n .Type == runtimespec .NetworkNamespace {
124+ netNS = n .Path
125+ }
126+ }
127+ require .NotEmpty (t , netNS , "network namespace should be set" )
128+
129+ t .Logf ("Should be able to find the pod ip in host-local checkpoint" )
130+ checkIP := func (ip string ) bool {
131+ found := false
132+ filepath .Walk (hostLocalCheckpointDir , func (_ string , info os.FileInfo , _ error ) error {
133+ if info != nil && info .Name () == ip {
134+ found = true
135+ }
136+ return nil
137+ })
138+ return found
139+ }
140+ require .True (t , checkIP (ip ))
141+
142+ t .Logf ("Kill sandbox container" )
143+ require .NoError (t , KillPid (int (sbInfo .Pid )))
144+
145+ t .Logf ("Unmount network namespace" )
146+ // The umount will take effect after containerd is stopped.
147+ require .NoError (t , unix .Unmount (netNS , unix .MNT_DETACH ))
148+
149+ t .Logf ("Restart containerd" )
150+ RestartContainerd (t )
151+
152+ t .Logf ("Sandbox state should be NOTREADY" )
153+ assert .NoError (t , Eventually (func () (bool , error ) {
154+ status , err := runtimeService .PodSandboxStatus (sb )
155+ if err != nil {
156+ return false , err
157+ }
158+ return status .GetState () == runtime .PodSandboxState_SANDBOX_NOTREADY , nil
159+ }, time .Second , 30 * time .Second ), "sandbox state should become NOTREADY" )
160+
161+ t .Logf ("Network namespace should have been removed" )
162+ _ , err = os .Stat (netNS )
163+ assert .True (t , os .IsNotExist (err ))
164+
165+ t .Logf ("Should still be able to find the pod ip in host-local checkpoint" )
166+ assert .True (t , checkIP (ip ))
167+
168+ t .Logf ("Should be able to remove the sandbox after properly stopped" )
169+ assert .NoError (t , runtimeService .StopPodSandbox (sb ))
170+ assert .NoError (t , runtimeService .RemovePodSandbox (sb ))
171+
172+ t .Logf ("Should not be able to find the pod ip in host-local checkpoint" )
173+ assert .False (t , checkIP (ip ))
174+ }
0 commit comments