func (c *profileCmd) doProfileRemove(client *lxd.Client, d string, p string) error { ct, err := client.ContainerInfo(d) if err != nil { return err } if !shared.StringInSlice(p, ct.Profiles) { return fmt.Errorf("Profile %s isn't currently applied to %s", p, d) } profiles := []string{} for _, profile := range ct.Profiles { if profile == p { continue } profiles = append(profiles, profile) } ct.Profiles = profiles err = client.UpdateContainerConfig(d, ct.Brief()) if err != nil { return err } fmt.Printf(i18n.G("Profile %s removed from %s")+"\n", p, d) return err }
func (c *networkCmd) doNetworkDetach(client *lxd.Client, name string, args []string) error { if len(args) < 1 || len(args) > 2 { return errArgs } containerName := args[0] devName := "" if len(args) > 1 { devName = args[1] } container, err := client.ContainerInfo(containerName) if err != nil { return err } if devName == "" { for n, d := range container.Devices { if d["type"] == "nic" && d["parent"] == name { if devName != "" { return fmt.Errorf(i18n.G("More than one device matches, specify the device name.")) } devName = n } } } if devName == "" { return fmt.Errorf(i18n.G("No device found for this network")) } device, ok := container.Devices[devName] if !ok { return fmt.Errorf(i18n.G("The specified device doesn't exist")) } if device["type"] != "nic" || device["parent"] != name { return fmt.Errorf(i18n.G("The specified device doesn't match the network")) } resp, err := client.ContainerDeviceDelete(containerName, devName) if err != nil { return err } return client.WaitForSuccess(resp.Operation) }
func (c *initCmd) checkNetwork(d *lxd.Client, name string) { ct, err := d.ContainerInfo(name) if err != nil { return } for _, d := range ct.ExpandedDevices { if d["type"] == "nic" { return } } fmt.Fprintf(os.Stderr, "\n"+i18n.G("The container you are starting doesn’t have any network attached to it.")+"\n") fmt.Fprintf(os.Stderr, " "+i18n.G("To create a new network, use: lxc network create")+"\n") fmt.Fprintf(os.Stderr, " "+i18n.G("To assign a network to a container, use: lxc network assign")+"\n\n") }
func (c *profileCmd) doProfileAdd(client *lxd.Client, d string, p string) error { ct, err := client.ContainerInfo(d) if err != nil { return err } ct.Profiles = append(ct.Profiles, p) err = client.UpdateContainerConfig(d, ct.Brief()) if err != nil { return err } fmt.Printf(i18n.G("Profile %s added to %s")+"\n", p, d) return err }
func (c *configCmd) doContainerConfigEdit(client *lxd.Client, cont string) error { // If stdin isn't a terminal, read text from it if !termios.IsTerminal(int(syscall.Stdin)) { contents, err := ioutil.ReadAll(os.Stdin) if err != nil { return err } newdata := shared.BriefContainerInfo{} err = yaml.Unmarshal(contents, &newdata) if err != nil { return err } return client.UpdateContainerConfig(cont, newdata) } // Extract the current value config, err := client.ContainerInfo(cont) if err != nil { return err } brief := config.Brief() data, err := yaml.Marshal(&brief) if err != nil { return err } // Spawn the editor content, err := shared.TextEditor("", []byte(c.configEditHelp()+"\n\n"+string(data))) if err != nil { return err } for { // Parse the text received from the editor newdata := shared.BriefContainerInfo{} err = yaml.Unmarshal(content, &newdata) if err == nil { err = client.UpdateContainerConfig(cont, newdata) } // Respawn the editor if err != nil { fmt.Fprintf(os.Stderr, i18n.G("Config parsing error: %s")+"\n", err) fmt.Println(i18n.G("Press enter to start the editor again")) _, err := os.Stdin.Read(make([]byte, 1)) if err != nil { return err } content, err = shared.TextEditor("", content) if err != nil { return err } continue } break } return nil }
func (c *infoCmd) containerInfo(d *lxd.Client, name string, showLog bool) error { ct, err := d.ContainerInfo(name) if err != nil { return err } cs, err := d.ContainerState(name) if err != nil { return err } const layout = "2006/01/02 15:04 UTC" fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name) fmt.Printf(i18n.G("Architecture: %s")+"\n", ct.Architecture) if ct.CreationDate.UTC().Unix() != 0 { fmt.Printf(i18n.G("Created: %s")+"\n", ct.CreationDate.UTC().Format(layout)) } fmt.Printf(i18n.G("Status: %s")+"\n", ct.Status) if ct.Ephemeral { fmt.Printf(i18n.G("Type: ephemeral") + "\n") } else { fmt.Printf(i18n.G("Type: persistent") + "\n") } fmt.Printf(i18n.G("Profiles: %s")+"\n", strings.Join(ct.Profiles, ", ")) if cs.Pid != 0 { fmt.Printf(i18n.G("Pid: %d")+"\n", cs.Pid) fmt.Printf(i18n.G("Processes: %d")+"\n", cs.Processes) ipInfo := "" for netName, net := range cs.Network { vethStr := "" if net.HostName != "" { vethStr = fmt.Sprintf("\t%s", net.HostName) } for _, addr := range net.Addresses { ipInfo += fmt.Sprintf(" %s:\t%s\t%s%s\n", netName, addr.Family, addr.Address, vethStr) } } if ipInfo != "" { fmt.Printf(i18n.G("Ips:") + "\n") fmt.Printf(ipInfo) } } // List snapshots first_snapshot := true snaps, err := d.ListSnapshots(name) if err != nil { return nil } for _, snap := range snaps { if first_snapshot { fmt.Println(i18n.G("Snapshots:")) } fmt.Printf(" %s", snap.Name) if snap.CreationDate.UTC().Unix() != 0 { fmt.Printf(" ("+i18n.G("taken at %s")+")", snap.CreationDate.UTC().Format(layout)) } if snap.Stateful { fmt.Printf(" (" + i18n.G("stateful") + ")") } else { fmt.Printf(" (" + i18n.G("stateless") + ")") } fmt.Printf("\n") first_snapshot = false } if showLog { log, err := d.GetLog(name, "lxc.log") if err != nil { return err } stuff, err := ioutil.ReadAll(log) if err != nil { return err } fmt.Printf("\n"+i18n.G("Log:")+"\n\n%s\n", string(stuff)) } return nil }
func (c *infoCmd) containerInfo(d *lxd.Client, name string, showLog bool) error { ct, err := d.ContainerInfo(name) if err != nil { return err } cs, err := d.ContainerState(name) if err != nil { return err } const layout = "2006/01/02 15:04 UTC" fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name) if d.Remote != nil && d.Remote.Addr != "" { fmt.Printf(i18n.G("Remote: %s")+"\n", d.Remote.Addr) } fmt.Printf(i18n.G("Architecture: %s")+"\n", ct.Architecture) if ct.CreationDate.UTC().Unix() != 0 { fmt.Printf(i18n.G("Created: %s")+"\n", ct.CreationDate.UTC().Format(layout)) } fmt.Printf(i18n.G("Status: %s")+"\n", ct.Status) if ct.Ephemeral { fmt.Printf(i18n.G("Type: ephemeral") + "\n") } else { fmt.Printf(i18n.G("Type: persistent") + "\n") } fmt.Printf(i18n.G("Profiles: %s")+"\n", strings.Join(ct.Profiles, ", ")) if cs.Pid != 0 { fmt.Printf(i18n.G("Pid: %d")+"\n", cs.Pid) // IP addresses ipInfo := "" if cs.Network != nil { for netName, net := range cs.Network { vethStr := "" if net.HostName != "" { vethStr = fmt.Sprintf("\t%s", net.HostName) } for _, addr := range net.Addresses { ipInfo += fmt.Sprintf(" %s:\t%s\t%s%s\n", netName, addr.Family, addr.Address, vethStr) } } } if ipInfo != "" { fmt.Println(i18n.G("Ips:")) fmt.Printf(ipInfo) } fmt.Println(i18n.G("Resources:")) // Processes fmt.Printf(" "+i18n.G("Processes: %d")+"\n", cs.Processes) // Disk usage diskInfo := "" if cs.Disk != nil { for entry, disk := range cs.Disk { if disk.Usage != 0 { diskInfo += fmt.Sprintf(" %s: %s\n", entry, shared.GetByteSizeString(disk.Usage)) } } } if diskInfo != "" { fmt.Println(i18n.G(" Disk usage:")) fmt.Printf(diskInfo) } // CPU usage cpuInfo := "" if cs.CPU.Usage != 0 { cpuInfo += fmt.Sprintf(" %s: %v\n", i18n.G("CPU usage (in seconds)"), cs.CPU.Usage/1000000000) } if cpuInfo != "" { fmt.Println(i18n.G(" CPU usage:")) fmt.Printf(cpuInfo) } // Memory usage memoryInfo := "" if cs.Memory.Usage != 0 { memoryInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Memory (current)"), shared.GetByteSizeString(cs.Memory.Usage)) } if cs.Memory.UsagePeak != 0 { memoryInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Memory (peak)"), shared.GetByteSizeString(cs.Memory.UsagePeak)) } if cs.Memory.SwapUsage != 0 { memoryInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Swap (current)"), shared.GetByteSizeString(cs.Memory.SwapUsage)) } if cs.Memory.SwapUsagePeak != 0 { memoryInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Swap (peak)"), shared.GetByteSizeString(cs.Memory.SwapUsagePeak)) } if memoryInfo != "" { fmt.Println(i18n.G(" Memory usage:")) fmt.Printf(memoryInfo) } // Network usage networkInfo := "" if cs.Network != nil { for netName, net := range cs.Network { networkInfo += fmt.Sprintf(" %s:\n", netName) networkInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Bytes received"), shared.GetByteSizeString(net.Counters.BytesReceived)) networkInfo += fmt.Sprintf(" %s: %s\n", i18n.G("Bytes sent"), shared.GetByteSizeString(net.Counters.BytesSent)) networkInfo += fmt.Sprintf(" %s: %d\n", i18n.G("Packets received"), net.Counters.PacketsReceived) networkInfo += fmt.Sprintf(" %s: %d\n", i18n.G("Packets sent"), net.Counters.PacketsSent) } } if networkInfo != "" { fmt.Println(i18n.G(" Network usage:")) fmt.Printf(networkInfo) } } // List snapshots first_snapshot := true snaps, err := d.ListSnapshots(name) if err != nil { return nil } for _, snap := range snaps { if first_snapshot { fmt.Println(i18n.G("Snapshots:")) } fields := strings.Split(snap.Name, shared.SnapshotDelimiter) fmt.Printf(" %s", fields[len(fields)-1]) if snap.CreationDate.UTC().Unix() != 0 { fmt.Printf(" ("+i18n.G("taken at %s")+")", snap.CreationDate.UTC().Format(layout)) } if snap.Stateful { fmt.Printf(" (" + i18n.G("stateful") + ")") } else { fmt.Printf(" (" + i18n.G("stateless") + ")") } fmt.Printf("\n") first_snapshot = false } if showLog { log, err := d.GetLog(name, "lxc.log") if err != nil { return err } stuff, err := ioutil.ReadAll(log) if err != nil { return err } fmt.Printf("\n"+i18n.G("Log:")+"\n\n%s\n", string(stuff)) } return nil }
func cmdCreate(c *lxd.Client, args []string) error { var wgBatch sync.WaitGroup // A path must be provided if len(args) < 1 { return fmt.Errorf("A path must be passed to create.") } // Load the simulation routersMap, err := importFromCSV(args[0]) if err != nil { return err } routers := []*Router{} for _, v := range routersMap { if v.Tier < 1 { continue } routers = append(routers, v) } // Clear any existing images fp := c.GetAlias("internet-router") if fp != "" { logf("Deleting the existing router image: %s", fp) err = c.DeleteImage(fp) if err != nil { return err } } // Load the image logf("Importing the router image") _, err = c.PostImage("image/image-meta.tar.xz", "image/image-rootfs.tar.xz", nil, false, []string{"internet-router"}, nil) if err != nil { return err } logf("New router image imported: %s", fp) // Create the profile _, err = c.ProfileConfig("internet-base") if err != nil { logf("Creating the profile") err := c.ProfileCreate("internet-base") if err != nil { return err } } // Helper function createContainer := func(router *Router) { defer wgBatch.Done() var interfaces string var bgpd string // Configuration config := map[string]string{} devices := map[string]map[string]string{} config["user.internet.type"] = "router" config["user.internet.organization"] = router.Organization config["user.internet.priority"] = fmt.Sprintf("%d", router.Priority) config["user.internet.tier"] = fmt.Sprintf("%d", router.Tier) config["user.internet.location"] = router.Location for i, r := range router.DNS { config[fmt.Sprintf("user.internet.dns.%d", i)] = r } config["user.internet.router.fqdn"] = router.Configuration.FQDN config["user.internet.router.asn"] = fmt.Sprintf("%d", router.Configuration.ASN) config["user.internet.router.password.login"] = router.Configuration.PasswordLogin config["user.internet.router.password.enable"] = router.Configuration.PasswordEnable if router.Configuration.RouterID != nil { config["user.internet.router.routerid"] = router.Configuration.RouterID.String() } if router.Internal { config["user.internet.internal"] = "true" } else { config["user.internet.internal"] = "false" } if router.Tier >= 1 && router.Tier <= 3 { interfaces = fmt.Sprintf(`auto lo iface lo inet loopback pre-up echo 0 > /proc/sys/net/ipv6/conf/all/accept_dad || true post-up echo 1 > /proc/sys/net/ipv6/conf/all/forwarding || true auto local iface local inet6 manual pre-up ip link add local type dummy || true pre-up ip link set local up || true `) } for i, r := range router.Configuration.Loopback.Addresses { config[fmt.Sprintf("user.internet.router.loopback.address.%d", i)] = r.String() if router.Tier >= 1 && router.Tier <= 3 { interfaces += fmt.Sprintf(" post-up ip -6 addr add dev local %s/128 || true\n", r.String()) } } for i, r := range router.Configuration.Loopback.Routes { config[fmt.Sprintf("user.internet.router.loopback.route.%d.subnet", i)] = r.Subnet.String() if router.Tier >= 1 && router.Tier <= 3 { interfaces += fmt.Sprintf(" post-up sleep 10 ; ip -6 route add dev local %s || true\n", r.Subnet.String()) } } if router.Tier >= 1 && router.Tier <= 3 { bgpd = fmt.Sprintf(fmt.Sprintf(`hostname %s password %s enable password %s router bgp %d bgp router-id %s no bgp default ipv4-unicast `, router.Name, router.Configuration.PasswordLogin, router.Configuration.PasswordEnable, router.Configuration.ASN, router.Configuration.RouterID.String())) } if router.Peers != nil { for _, p := range router.Peers { if strings.HasPrefix(p.Interface, "v") { device := map[string]string{ "type": "nic", "nictype": "physical", "name": p.Interface, "parent": p.Interface, "hwaddr": p.MAC, } devices[p.Interface] = device } else if strings.HasPrefix(p.Interface, "br") { device := map[string]string{ "type": "nic", "nictype": "bridged", "name": p.Interface, "parent": p.Interface, "hwaddr": p.MAC, } devices[p.Interface] = device } else { logf("Failed to configure container '%s': Bad interface name: %s", router.Name, p.Interface) return } if router.Tier >= 1 && router.Tier <= 3 { interfaces += fmt.Sprintf(` auto %s iface %s inet6 manual post-up tc qdisc add dev %s root netem delay %dms || true post-up tc qdisc add dev %s root netem rate %dmbit || true `, p.Interface, p.Interface, p.Interface, p.Delay, p.Interface, p.Speed) if p.ASN != 0 { bgpd += fmt.Sprintf(` neighbor %s remote-as %d neighbor %s weight %d neighbor %s interface %s `, p.Remote, p.ASN, p.Remote, p.Weight, p.Remote, p.Interface) } } config[fmt.Sprintf("user.internet.peer.%s.interface", p.Name)] = p.Interface config[fmt.Sprintf("user.internet.peer.%s.mac", p.Name)] = p.MAC config[fmt.Sprintf("user.internet.peer.%s.remote", p.Name)] = p.Remote config[fmt.Sprintf("user.internet.peer.%s.speed", p.Name)] = fmt.Sprintf("%d", p.Speed) config[fmt.Sprintf("user.internet.peer.%s.delay", p.Name)] = fmt.Sprintf("%d", p.Delay) config[fmt.Sprintf("user.internet.peer.%s.asn", p.Name)] = fmt.Sprintf("%d", p.ASN) config[fmt.Sprintf("user.internet.peer.%s.weight", p.Name)] = fmt.Sprintf("%d", p.Weight) if p.Routes != nil { for i, r := range p.Routes { config[fmt.Sprintf("user.internet.peer.%s.route.%d.subnet", p.Name, i)] = r.Subnet.String() if r.Gateway != nil { config[fmt.Sprintf("user.internet.peer.%s.route.%d.gateway", p.Name, i)] = r.Gateway.String() if router.Tier >= 1 && router.Tier <= 3 { interfaces += fmt.Sprintf(" post-up sleep 10 ; ip -6 route add dev %s %s via %s || true\n", p.Interface, r.Subnet.String(), r.Gateway.String()) } } else { if router.Tier >= 1 && router.Tier <= 3 { interfaces += fmt.Sprintf(" post-up sleep 10 ; ip -6 route add dev %s %s via %s || true\n", p.Interface, r.Subnet.String(), p.Remote) } } } } } } if router.Tier >= 1 && router.Tier <= 3 { bgpd += " address-family ipv6\n" if router.Peers != nil { for _, p := range router.Peers { if p.ASN != 0 { bgpd += fmt.Sprintf(" neighbor %s activate\n", p.Remote) } } } bgpd += ` redistribute connected redistribute kernel exit-address-family ` config["user.internet.config.interfaces"] = interfaces config["user.internet.config.bgpd"] = bgpd } // Config-only containers if router.Tier > 3 { ct, err := c.ContainerInfo(router.Name) if err != nil { logf("Failed to configure container '%s': %s", router.Name, err) return } for k, _ := range ct.Config { if strings.HasPrefix(k, "user.internet.") { delete(ct.Config, k) } } for k, v := range config { ct.Config[k] = v } err = c.UpdateContainerConfig(router.Name, ct.Writable()) if err != nil { logf("Failed to configure container '%s': %s", router.Name, err) return } return } // Create the container resp, err := c.Init(router.Name, "local", "internet-router", &[]string{"internet-base"}, config, nil, false) if err != nil { logf("Failed to create container '%s': %s", router.Name, err) return } err = c.WaitForSuccess(resp.Operation) if err != nil { logf("Failed to create container '%s': %s", router.Name, err) return } // Setup the devices ct, err := c.ContainerInfo(router.Name) if err != nil { logf("Failed to configure container '%s': %s", router.Name, err) return } for k, v := range devices { ct.Devices[k] = v } err = c.UpdateContainerConfig(router.Name, ct.Writable()) if err != nil { logf("Failed to configure container '%s': %s", router.Name, err) return } } // Create the containers batch := 8 batches := len(routers) / batch remainder := len(routers) % batch logf("Creating the containers") current := 0 for i := 0; i < batches; i++ { for j := 0; j < batch; j++ { wgBatch.Add(1) go createContainer(routers[current]) current += 1 } wgBatch.Wait() } for k := 0; k < remainder; k++ { wgBatch.Add(1) go createContainer(routers[current]) current += 1 } wgBatch.Wait() logf("%d containers created", len(routers)) return nil }