From b26fee385f149bb7cdc87d570228fb38cb27f25c Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 4 Nov 2024 09:03:55 +0100 Subject: [PATCH] Add "down" command to remove an existing lab --- main.go | 7 +++++++ setup.go | 62 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index 9ca00ad..700afd9 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,13 @@ func main() { cfg := loadConfig() mustUp(cfg) + case "down": + if len(os.Args) != 3 { + log.Fatalf("invalid arguments; expected: \"down\" ") + } + cfg := loadConfig() + mustDown(cfg) + case "dot": // Write dot file showing the network architecture if len(os.Args) != 4 { diff --git a/setup.go b/setup.go index 7d17520..80b3276 100644 --- a/setup.go +++ b/setup.go @@ -26,15 +26,7 @@ func mustUp(cfg *Config) { ns := node.Name if netnsExists(ns) { // Terminate processes in old namespaces - for _, x := range netnsPids(ns) { - log.Printf(" Killing old PID %d", x) - err := syscall.Kill(x, syscall.SIGTERM) - if err != nil { - log.Fatalf("failed to kill %d: %v", x, err) - } - // Also try SIGHUP to terminate shells which ignore SIGTERM - _ = syscall.Kill(x, syscall.SIGHUP) - } + netnsKillPids(ns) // Prevent any conflicts with existing data ip("netns", "del", ns) // Don't remove anything in /etc/netns/ as the user might store @@ -43,10 +35,9 @@ func mustUp(cfg *Config) { ip("netns", "add", ns) // Write /etc/netns/$netns/hosts with all known hosts - nsCfgPath := filepath.Join("/etc/netns", ns) - nsHostsPath := filepath.Join(nsCfgPath, "hosts") + nsHostsPath := netnsHostsPath(ns) log.Printf(" Writing %q", nsHostsPath) - err := os.MkdirAll(nsCfgPath, 0755) + err := os.MkdirAll(netnsCfgPath(ns), 0755) if err != nil { log.Fatal(err) } @@ -117,6 +108,33 @@ func mustUp(cfg *Config) { } } +func mustDown(cfg *Config) { + for _, node := range cfg.Nodes { + log.Printf("Removing node %q ...", node.Name) + + ns := node.Name + if !netnsExists(ns) { + log.Printf(" netns doesn't exist, skipping cleanup") + continue + } + + netnsKillPids(ns) + ip("netns", "del", ns) + + // Delete files we created in /etc/netns/. Keep the rest as the user + // might store configuration there! + nsHostsPath := netnsHostsPath(ns) + log.Printf(" Removing %q (including parent directory if empty)", + nsHostsPath) + err := os.Remove(nsHostsPath) + if err != nil && !os.IsNotExist(err) { + log.Fatal(err) + } + // Ignore error as /etc/netns// might not be empty + _ = os.Remove(netnsCfgPath(ns)) + } +} + func ip(args ...string) { xargs := append([]string{"ip"}, args...) log.Printf(" Running %q", xargs) @@ -167,6 +185,26 @@ func netnsPids(netns string) []int { return res } +func netnsKillPids(netns string) { + for _, x := range netnsPids(netns) { + log.Printf(" Killing old PID %d", x) + err := syscall.Kill(x, syscall.SIGTERM) + if err != nil { + log.Fatalf("failed to kill %d: %v", x, err) + } + // Also try SIGHUP to terminate shells which ignore SIGTERM + _ = syscall.Kill(x, syscall.SIGHUP) + } +} + +func netnsCfgPath(netns string) string { + return filepath.Join("/etc/netns", netns) +} + +func netnsHostsPath(netns string) string { + return filepath.Join(netnsCfgPath(netns), "hosts") +} + func ifaceExists(netns, name string) bool { args := []string{"-n", netns, "-json", "link"} xargs := append([]string{"ip"}, args...) -- 2.45.2