mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #2544 from prattmic:runsc_do_cleanup
PiperOrigin-RevId: 308727526
This commit is contained in:
+64
-19
@@ -166,15 +166,33 @@ func (c *Do) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) su
|
||||
return Errorf("Error write spec: %v", err)
|
||||
}
|
||||
|
||||
runArgs := container.Args{
|
||||
containerArgs := container.Args{
|
||||
ID: cid,
|
||||
Spec: spec,
|
||||
BundleDir: tmpDir,
|
||||
Attached: true,
|
||||
}
|
||||
ws, err := container.Run(conf, runArgs)
|
||||
ct, err := container.New(conf, containerArgs)
|
||||
if err != nil {
|
||||
return Errorf("running container: %v", err)
|
||||
return Errorf("creating container: %v", err)
|
||||
}
|
||||
defer ct.Destroy()
|
||||
|
||||
if err := ct.Start(conf); err != nil {
|
||||
return Errorf("starting container: %v", err)
|
||||
}
|
||||
|
||||
// Forward signals to init in the container. Thus if we get SIGINT from
|
||||
// ^C, the container gracefully exit, and we can clean up.
|
||||
//
|
||||
// N.B. There is a still a window before this where a signal may kill
|
||||
// this process, skipping cleanup.
|
||||
stopForwarding := ct.ForwardSignals(0 /* pid */, false /* fgProcess */)
|
||||
defer stopForwarding()
|
||||
|
||||
ws, err := ct.Wait()
|
||||
if err != nil {
|
||||
return Errorf("waiting for container: %v", err)
|
||||
}
|
||||
|
||||
*waitStatus = ws
|
||||
@@ -237,20 +255,27 @@ func (c *Do) setupNet(cid string, spec *specs.Spec) (func(), error) {
|
||||
for _, cmd := range cmds {
|
||||
log.Debugf("Run %q", cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
c := exec.Command(args[0], args[1:]...)
|
||||
if err := c.Run(); err != nil {
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
if err := cmd.Run(); err != nil {
|
||||
c.cleanupNet(cid, dev, "", "", "")
|
||||
return nil, fmt.Errorf("failed to run %q: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := makeFile("/etc/resolv.conf", "nameserver 8.8.8.8\n", spec); err != nil {
|
||||
resolvPath, err := makeFile("/etc/resolv.conf", "nameserver 8.8.8.8\n", spec)
|
||||
if err != nil {
|
||||
c.cleanupNet(cid, dev, "", "", "")
|
||||
return nil, err
|
||||
}
|
||||
if err := makeFile("/etc/hostname", cid+"\n", spec); err != nil {
|
||||
hostnamePath, err := makeFile("/etc/hostname", cid+"\n", spec)
|
||||
if err != nil {
|
||||
c.cleanupNet(cid, dev, resolvPath, "", "")
|
||||
return nil, err
|
||||
}
|
||||
hosts := fmt.Sprintf("127.0.0.1\tlocalhost\n%s\t%s\n", c.ip, cid)
|
||||
if err := makeFile("/etc/hosts", hosts, spec); err != nil {
|
||||
hostsPath, err := makeFile("/etc/hosts", hosts, spec)
|
||||
if err != nil {
|
||||
c.cleanupNet(cid, dev, resolvPath, hostnamePath, "")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -263,19 +288,22 @@ func (c *Do) setupNet(cid string, spec *specs.Spec) (func(), error) {
|
||||
}
|
||||
spec.Linux.Namespaces = append(spec.Linux.Namespaces, netns)
|
||||
|
||||
return func() { c.cleanNet(cid, dev) }, nil
|
||||
return func() { c.cleanupNet(cid, dev, resolvPath, hostnamePath, hostsPath) }, nil
|
||||
}
|
||||
|
||||
func (c *Do) cleanNet(cid, dev string) {
|
||||
veth, peer := deviceNames(cid)
|
||||
// cleanupNet tries to cleanup the network setup in setupNet.
|
||||
//
|
||||
// It may be called when setupNet is only partially complete, in which case it
|
||||
// will cleanup as much as possible, logging warnings for the rest.
|
||||
//
|
||||
// Unfortunately none of this can be automatically cleaned up on process exit,
|
||||
// we must do so explicitly.
|
||||
func (c *Do) cleanupNet(cid, dev, resolvPath, hostnamePath, hostsPath string) {
|
||||
_, peer := deviceNames(cid)
|
||||
|
||||
cmds := []string{
|
||||
fmt.Sprintf("ip link delete %s", peer),
|
||||
fmt.Sprintf("ip netns delete %s", cid),
|
||||
|
||||
fmt.Sprintf("iptables -t nat -D POSTROUTING -s %s/24 -o %s -j MASQUERADE", c.ip, dev),
|
||||
fmt.Sprintf("iptables -D FORWARD -i %s -o %s -j ACCEPT", dev, veth),
|
||||
fmt.Sprintf("iptables -D FORWARD -o %s -i %s -j ACCEPT", dev, veth),
|
||||
}
|
||||
|
||||
for _, cmd := range cmds {
|
||||
@@ -286,6 +314,10 @@ func (c *Do) cleanNet(cid, dev string) {
|
||||
log.Warningf("Failed to run %q: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
|
||||
tryRemove(resolvPath)
|
||||
tryRemove(hostnamePath)
|
||||
tryRemove(hostsPath)
|
||||
}
|
||||
|
||||
func deviceNames(cid string) (string, string) {
|
||||
@@ -306,13 +338,16 @@ func defaultDevice() (string, error) {
|
||||
return parts[4], nil
|
||||
}
|
||||
|
||||
func makeFile(dest, content string, spec *specs.Spec) error {
|
||||
func makeFile(dest, content string, spec *specs.Spec) (string, error) {
|
||||
tmpFile, err := ioutil.TempFile("", filepath.Base(dest))
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if _, err := tmpFile.WriteString(content); err != nil {
|
||||
return err
|
||||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
log.Warningf("Failed to remove %q: %v", tmpFile, err)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
spec.Mounts = append(spec.Mounts, specs.Mount{
|
||||
Source: tmpFile.Name(),
|
||||
@@ -320,7 +355,17 @@ func makeFile(dest, content string, spec *specs.Spec) error {
|
||||
Type: "bind",
|
||||
Options: []string{"ro"},
|
||||
})
|
||||
return nil
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
func tryRemove(path string) {
|
||||
if path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.Remove(path); err != nil {
|
||||
log.Warningf("Failed to remove %q: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
func calculatePeerIP(ip string) (string, error) {
|
||||
|
||||
+1
-1
@@ -330,7 +330,7 @@ func main() {
|
||||
log.Infof("Exiting with status: %v", ws)
|
||||
if ws.Signaled() {
|
||||
// No good way to return it, emulate what the shell does. Maybe raise
|
||||
// signall to self?
|
||||
// signal to self?
|
||||
os.Exit(128 + int(ws.Signal()))
|
||||
}
|
||||
os.Exit(ws.ExitStatus())
|
||||
|
||||
Reference in New Issue
Block a user