func importFromLXD(c *lxd.Client) (Routers, error) { // Load the LXD container list containers, err := c.ListContainers() if err != nil { return nil, err } // Build the routers map routers := Routers{} for _, ctn := range containers { // Skip the container we don't care about if ctn.ExpandedConfig["user.internet.type"] != "router" { continue } config := ctn.ExpandedConfig // Generate the new record router := Router{} router.Configuration = &RouterConfiguration{} // Text fields router.Organization = config["user.internet.organization"] router.Name = ctn.Name router.Location = config["user.internet.location"] router.Configuration.PasswordLogin = config["user.internet.router.password.login"] router.Configuration.PasswordEnable = config["user.internet.router.password.enable"] router.Configuration.FQDN = config["user.internet.router.fqdn"] routerid := net.ParseIP(config["user.internet.router.routerid"]) router.Configuration.RouterID = &routerid // Integers tier, err := strconv.Atoi(config["user.internet.tier"]) if err != nil { return nil, fmt.Errorf("Invalid tier: %s\n", config["user.internet.tier"]) } router.Tier = tier asn, err := strconv.Atoi(config["user.internet.router.asn"]) if err != nil { return nil, fmt.Errorf("Invalid ASN: %s\n", config["user.internet.router.asn"]) } router.Configuration.ASN = asn priority, err := strconv.Atoi(config["user.internet.priority"]) if err != nil { return nil, fmt.Errorf("Invalid priority: %s\n", config["user.internet.priority"]) } router.Priority = priority // Booleans if config["user.internet.internal"] == "true" { router.Internal = true } // DNS dns := []string{} for k, v := range config { if !strings.HasPrefix(k, "user.internet.dns.") { continue } dns = append(dns, v) } router.DNS = dns // Loopback addresses := []net.IP{} routes := []RouterInterfaceRoute{} for k, v := range config { if strings.HasPrefix(k, "user.internet.router.loopback.address.") { addresses = append(addresses, net.ParseIP(v)) continue } if strings.HasPrefix(k, "user.internet.router.loopback.route.") { _, subnet, err := net.ParseCIDR(v) if err != nil { return nil, err } routes = append(routes, RouterInterfaceRoute{Subnet: subnet}) continue } } // Peers peersMap := map[string]*Peer{} for k, v := range config { if !strings.HasPrefix(k, "user.internet.peer.") { continue } fields := strings.Split(k, ".") name := fields[3] key := fields[4] peer, ok := peersMap[name] if !ok { peer = &Peer{Name: name} } switch key { case "interface": peer.Interface = v case "mac": peer.MAC = v case "remote": peer.Remote = v case "speed": speed, err := strconv.Atoi(v) if err != nil { return nil, err } peer.Speed = speed case "delay": delay, err := strconv.Atoi(v) if err != nil { return nil, err } peer.Delay = delay case "asn": asn, err := strconv.Atoi(v) if err != nil { return nil, err } peer.ASN = asn case "weight": weight, err := strconv.Atoi(v) if err != nil { return nil, err } peer.Weight = weight } peersMap[name] = peer } peers := []Peer{} for _, p := range peersMap { i := 0 routes := []RouterInterfaceRoute{} for { found := false route := RouterInterfaceRoute{} v, ok := config[fmt.Sprintf("user.internet.peer.%s.route.%d.subnet", p.Name, i)] if ok { found = true _, subnet, err := net.ParseCIDR(v) if err != nil { return nil, err } route.Subnet = subnet } v, ok = config[fmt.Sprintf("user.internet.peer.%s.route.%d.gateway", p.Name, i)] if ok { found = true gateway := net.ParseIP(v) route.Gateway = &gateway } if !found { break } i += 1 routes = append(routes, route) } p.Routes = routes peers = append(peers, *p) } router.Peers = peers routers[router.Name] = &router } return routers, nil }
func deleteContainers(c *lxd.Client) error { batch := *argParallel if batch < 1 { // Detect the number of parallel actions cpus, err := ioutil.ReadDir("/sys/bus/cpu/devices") if err != nil { return err } batch = len(cpus) } // List all the containers allContainers, err := c.ListContainers() if err != nil { return err } containers := []shared.ContainerInfo{} for _, container := range allContainers { if container.Config["user.lxd-benchmark"] != "true" { continue } containers = append(containers, container) } // Delete them all count := len(containers) logf("%d containers to delete", count) batches := count / batch deletedCount := 0 wgBatch := sync.WaitGroup{} nextStat := batch deleteContainer := func(ct shared.ContainerInfo) { defer wgBatch.Done() // Stop if ct.IsActive() { resp, err := c.Action(ct.Name, "stop", -1, true, false) if err != nil { logf("Failed to delete container: %s", ct.Name) return } err = c.WaitForSuccess(resp.Operation) if err != nil { logf("Failed to delete container: %s", ct.Name) return } } // Delete resp, err := c.Delete(ct.Name) if err != nil { logf("Failed to delete container: %s", ct.Name) return } err = c.WaitForSuccess(resp.Operation) if err != nil { logf("Failed to delete container: %s", ct.Name) return } } logf("Starting the cleanup") timeStart := time.Now() for i := 0; i < batches; i++ { for j := 0; j < batch; j++ { wgBatch.Add(1) go deleteContainer(containers[deletedCount]) deletedCount = deletedCount + 1 } wgBatch.Wait() if deletedCount >= nextStat { interval := time.Since(timeStart).Seconds() logf("Deleted %d containers in %.3fs (%.3f/s)", deletedCount, interval, float64(deletedCount)/interval) nextStat = nextStat * 2 } } for k := deletedCount; k < count; k++ { wgBatch.Add(1) go deleteContainer(containers[deletedCount]) deletedCount = deletedCount + 1 } wgBatch.Wait() logf("Cleanup completed") return nil }
func cmdDestroy(c *lxd.Client, args []string) error { var wgBatch sync.WaitGroup if os.Getuid() != 0 { return fmt.Errorf("Container destruction must be run as root.") } // Load the simulation routersMap, err := importFromLXD(c) if err != nil { return err } routers := []*Router{} for _, v := range routersMap { if v.Tier < 1 || v.Tier > 3 { continue } routers = append(routers, v) } // Load the LXD container list containers, err := c.ListContainers() if err != nil { return err } containersMap := map[string]api.Container{} for _, ctn := range containers { containersMap[ctn.Name] = ctn } // Helper function deleteContainer := func(name string) { defer wgBatch.Done() ct, ok := containersMap[name] if !ok { logf("Failed to delete container: %s: Doesn't exist", ct.Name) return } // Stop if ct.IsActive() { resp, err := c.Action(ct.Name, "stop", -1, true, false) if err != nil { logf("Failed to delete container: %s: %s", ct.Name, err) return } err = c.WaitForSuccess(resp.Operation) if err != nil { logf("Failed to delete container: %s: %s", ct.Name, err) return } } // Delete resp, err := c.Delete(ct.Name) if err != nil { logf("Failed to delete container: %s: %s", ct.Name, err) return } err = c.WaitForSuccess(resp.Operation) if err != nil { logf("Failed to delete container: %s: %s", ct.Name, err) return } } // Delete all the containers batch := 8 batches := len(routers) / batch remainder := len(routers) % batch current := 0 for i := 0; i < batches; i++ { for j := 0; j < batch; j++ { wgBatch.Add(1) go deleteContainer(routers[current].Name) current += 1 } wgBatch.Wait() } for k := 0; k < remainder; k++ { wgBatch.Add(1) go deleteContainer(routers[current].Name) current += 1 } wgBatch.Wait() // Destroy all the interfaces err = networkDestroy(routersMap) if err != nil { return err } return nil }