// clients func cliCCClients(c *minicli.Command, resp *minicli.Response) error { resp.Header = []string{ "UUID", "hostname", "arch", "OS", "IP", "MAC", } resp.Tabular = [][]string{} clients := ccNode.GetActiveClients() var uuids []string for k, _ := range clients { uuids = append(uuids, k) } sort.Strings(uuids) for _, i := range uuids { v := clients[i] row := []string{ v.UUID, v.Hostname, v.Arch, v.OS, fmt.Sprintf("%v", v.IPs), fmt.Sprintf("%v", v.MACs), } resp.Tabular = append(resp.Tabular, row) } return nil }
func cliVmMigrate(c *minicli.Command, resp *minicli.Response) error { if _, ok := c.StringArgs["vm"]; !ok { // report current migrations resp.Header = []string{"id", "name", "status", "%% complete"} for _, vm := range vms.FindKvmVMs() { status, complete, err := vm.QueryMigrate() if err != nil { return err } if status == "" { continue } resp.Tabular = append(resp.Tabular, []string{ fmt.Sprintf("%v", vm.GetID()), vm.GetName(), status, fmt.Sprintf("%.2f", complete)}) } return nil } vm, err := vms.FindKvmVM(c.StringArgs["vm"]) if err != nil { return err } return vm.Migrate(c.StringArgs["filename"]) }
func cliHost(c *minicli.Command, resp *minicli.Response) error { // If they selected one of the fields to display for k := range c.BoolArgs { val, err := hostInfoFns[k]() if err != nil { return err } resp.Response = val return nil } // Must want all fields resp.Header = hostInfoKeys row := []string{} for _, k := range resp.Header { val, err := hostInfoFns[k]() if err != nil { return err } row = append(row, val) } resp.Tabular = [][]string{row} return nil }
func cliCC(c *minicli.Command, resp *minicli.Response) error { // Ensure that cc is running before proceeding if ccNode == nil { return errors.New("cc service not running") } if len(c.BoolArgs) > 0 { // Invoke a particular handler for k, fn := range ccCliSubHandlers { if c.BoolArgs[k] { log.Debug("cc handler %v", k) return fn(c, resp) } } return errors.New("unreachable") } // Getting status clients := ccNode.GetActiveClients() resp.Header = []string{"number of clients"} resp.Tabular = [][]string{ []string{ fmt.Sprintf("%v", len(clients)), }, } return nil }
func cliCapture(c *minicli.Command, resp *minicli.Response) error { if c.BoolArgs["netflow"] { // Capture to netflow return cliCaptureNetflow(c, resp) } else if c.BoolArgs["pcap"] { // Capture to pcap return cliCapturePcap(c, resp) } // Print capture info resp.Header = []string{ "ID", "Type", "Bridge", "VM/interface", "Path", "Mode", "Compress", } resp.Tabular = [][]string{} for _, v := range captureEntries { row := []string{ strconv.Itoa(v.ID), v.Type, v.Bridge, fmt.Sprintf("%v/%v", v.VM, v.Interface), v.Path, v.Mode, strconv.FormatBool(v.Compress), } resp.Tabular = append(resp.Tabular, row) } return nil // TODO: How does this fit in? // // get netflow stats for each bridge //var nfstats string //b := enumerateBridges() //for _, v := range b { // nf, err := getNetflowFromBridge(v) // if err != nil { // if !strings.Contains(err.Error(), "has no netflow object") { // return cliResponse{ // Error: err.Error(), // } // } // continue // } // nfstats += fmt.Sprintf("Bridge %v:\n", v) // nfstats += fmt.Sprintf("minimega listening on port: %v\n", nf.GetPort()) // nfstats += nf.GetStats() //} //out := o.String() + "\n" + nfstats }
func cliShell(c *minicli.Command, resp *minicli.Response, background bool) error { var sOut bytes.Buffer var sErr bytes.Buffer p, err := exec.LookPath(c.ListArgs["command"][0]) if err != nil { return err } args := []string{p} if len(c.ListArgs["command"]) > 1 { args = append(args, c.ListArgs["command"][1:]...) } cmd := &exec.Cmd{ Path: p, Args: args, Env: nil, Dir: "", Stdout: &sOut, Stderr: &sErr, } log.Info("starting: %v", args) if err := cmd.Start(); err != nil { return err } if background { go func() { if err := cmd.Wait(); err != nil { log.Error(err.Error()) return } log.Info("command %v exited", args) if out := sOut.String(); out != "" { log.Info(out) } if err := sErr.String(); err != "" { log.Info(err) } }() return nil } if err = cmd.Wait(); err != nil { return err } resp.Response = sOut.String() resp.Error = sErr.String() return nil }
// process func cliCCProcess(c *minicli.Command, resp *minicli.Response) error { if c.BoolArgs["kill"] { return cliCCProcessKill(c, resp) } else if c.BoolArgs["killall"] { return cliCCProcessKillAll(c, resp) } // list processes v := c.StringArgs["vm"] var activeVms []string if v == Wildcard { clients := ccNode.GetActiveClients() for _, client := range clients { activeVms = append(activeVms, client.UUID) } } else { // get the vm uuid vm := vms.FindVM(v) if vm == nil { return vmNotFound(v) } log.Debug("got vm: %v %v", vm.GetID(), vm.GetName()) activeVms = []string{vm.GetUUID()} } resp.Header = []string{"name", "uuid", "pid", "command"} for _, uuid := range activeVms { vm := vms.FindVM(uuid) if vm == nil { return vmNotFound(v) } processes, err := ccNode.GetProcesses(uuid) if err != nil { return err } for _, p := range processes { resp.Tabular = append(resp.Tabular, []string{ vm.GetName(), vm.GetUUID(), fmt.Sprintf("%v", p.PID), strings.Join(p.Command, " "), }) } } return nil }
func cliVmConfig(c *minicli.Command, resp *minicli.Response) error { if c.BoolArgs["save"] { // Save the current config savedInfo[c.StringArgs["name"]] = vmConfig.Copy() return nil } else if c.BoolArgs["restore"] { if name, ok := c.StringArgs["name"]; ok { // Try to restore an existing config if _, ok := savedInfo[name]; !ok { return fmt.Errorf("config %v does not exist", name) } vmConfig = savedInfo[name].Copy() return nil } else if len(savedInfo) == 0 { return errors.New("no vm configs saved") } // List the save configs for k := range savedInfo { resp.Response += fmt.Sprintln(k) } return nil } else if c.BoolArgs["clone"] { // Clone the config of an existing vm vm := vms.FindVM(c.StringArgs["vm"]) if vm == nil { return vmNotFound(c.StringArgs["vm"]) } switch vm := vm.(type) { case *KvmVM: vmConfig.BaseConfig = vm.BaseConfig.Copy() vmConfig.KVMConfig = vm.KVMConfig.Copy() case *ContainerVM: vmConfig.BaseConfig = vm.BaseConfig.Copy() vmConfig.ContainerConfig = vm.ContainerConfig.Copy() } return nil } // Print the config resp.Response = vmConfig.String() return nil }
func hostTapList(resp *minicli.Response) { resp.Header = []string{"bridge", "tap", "vlan"} resp.Tabular = [][]string{} // find all the host taps first for k, b := range bridges { for name, tap := range b.Taps { if tap.host { resp.Tabular = append(resp.Tabular, []string{ k, name, strconv.Itoa(tap.lan), }) } } } }
func cliBridge(c *minicli.Command, resp *minicli.Response) error { iface := c.StringArgs["interface"] remoteIP := c.StringArgs["remote"] // Get the specifed bridge. If we're listing the bridges, we'll get the // default bridge which should be fine. br, err := getBridge(c.StringArgs["bridge"]) if err != nil { return err } if c.BoolArgs["trunk"] { return br.AddTrunk(iface) } else if c.BoolArgs["notrunk"] { return br.RemoveTrunk(iface) } else if c.BoolArgs["tunnel"] { t := bridge.TunnelVXLAN if c.BoolArgs["gre"] { t = bridge.TunnelGRE } return br.AddTunnel(t, remoteIP) } else if c.BoolArgs["notunnel"] { return br.RemoveTunnel(iface) } // Must want to list bridges resp.Header = []string{"Bridge", "Existed before minimega", "Active VLANs", "Trunk ports", "Tunnels"} resp.Tabular = [][]string{} for _, info := range bridges.Info() { vlans := []string{} for k, _ := range info.VLANs { vlans = append(vlans, printVLAN(k)) } sort.Strings(vlans) row := []string{ info.Name, strconv.FormatBool(info.PreExist), fmt.Sprintf("%v", vlans), fmt.Sprintf("%v", info.Trunks), fmt.Sprintf("%v", info.Tunnels)} resp.Tabular = append(resp.Tabular, row) } return nil }
func cliVmConfigField(c *minicli.Command, resp *minicli.Response, field string) error { // If there are no args it means that we want to display the current value nArgs := len(c.StringArgs) + len(c.ListArgs) + len(c.BoolArgs) var ok bool var fns VMConfigFns var config interface{} // Find the right config functions, baseConfigFns has highest priority if fns, ok = baseConfigFns[field]; ok { config = &vmConfig.BaseConfig } else if fns, ok = kvmConfigFns[field]; ok { config = &vmConfig.KVMConfig } else if fns, ok = containerConfigFns[field]; ok { config = &vmConfig.ContainerConfig } else { return fmt.Errorf("unknown config field: `%s`", field) } if nArgs == 0 { resp.Response = fns.Print(config) return nil } return fns.Update(config, c) }
func cliLogFile(c *minicli.Command, resp *minicli.Response) error { if len(c.StringArgs) == 0 { // Print true or false depending on whether file is enabled if logFile != nil { resp.Response = logFile.Name() } return nil } // Enable logging to file if it's not already enabled level, _ := log.LevelInt(*f_loglevel) if logFile != nil { if err := stopFileLogger(); err != nil { return err } } err := os.MkdirAll(filepath.Dir(c.StringArgs["file"]), 0755) if err != nil { return err } flags := os.O_WRONLY | os.O_APPEND | os.O_CREATE logFile, err = os.OpenFile(c.StringArgs["file"], flags, 0660) if err != nil { return err } log.AddLogger("file", logFile, level, false) return nil }
func cliVmConfigTag(c *minicli.Command, resp *minicli.Response) error { k := c.StringArgs["key"] if v, ok := c.StringArgs["value"]; ok { // Setting a new value vmConfig.Tags[k] = v } else if k != "" { // Printing a single tag resp.Response = vmConfig.Tags[k] } else { // Printing all configured tags resp.Response = vmConfig.TagsString() } return nil }
func hostTapList(resp *minicli.Response) { resp.Header = []string{"bridge", "tap", "vlan", "option"} resp.Tabular = [][]string{} // find all the host taps first for k, v := range bridges { for lan, t := range v.lans { for tap, ti := range t.Taps { if ti.host { resp.Tabular = append(resp.Tabular, []string{ k, tap, strconv.Itoa(lan), ti.hostOption, }) } } } } }
func cliMeshageStatus(c *minicli.Command, resp *minicli.Response) error { mesh := meshageNode.Mesh() degree := meshageNode.GetDegree() nodes := len(mesh) resp.Header = []string{"mesh size", "degree", "peers", "context", "port"} resp.Tabular = [][]string{ []string{ strconv.Itoa(nodes), strconv.FormatUint(uint64(degree), 10), strconv.Itoa(len(mesh[hostname])), *f_context, strconv.Itoa(*f_port), }, } return nil }
// prefix func cliCCPrefix(c *minicli.Command, resp *minicli.Response) error { if prefix, ok := c.StringArgs["prefix"]; ok { ccPrefix = prefix return nil } resp.Response = ccPrefix return nil }
func cliHelp(c *minicli.Command, resp *minicli.Response) error { input := "" if args, ok := c.ListArgs["command"]; ok { input = strings.Join(args, " ") } resp.Response = minicli.Help(input) return nil }
// routines for interfacing bridge mechanisms with the cli func cliHostTap(c *minicli.Command, resp *minicli.Response) error { if c.BoolArgs["create"] { b := c.StringArgs["bridge"] tap, err := hostTapCreate(b, c.StringArgs["tap"], c.StringArgs["vlan"]) if err != nil { return err } if c.BoolArgs["dhcp"] { log.Debug("obtaining dhcp on tap %v", tap) var out string out, err = processWrapper("dhcp", tap) if err != nil { err = fmt.Errorf("dhcp error %v: `%v`", err, out) } } else if c.StringArgs["ip"] != "" { ip := c.StringArgs["ip"] log.Debug("setting ip on tap %v: %v", tap, ip) var out string out, err = processWrapper("ip", "addr", "add", "dev", tap, ip) if err != nil { err = fmt.Errorf("ip error %v: `%v`", err, out) } } if err != nil { // One of the above cases failed, try to clean up the tap if err := hostTapDelete(tap); err != nil { // Welp, we're boned log.Error("zombie tap -- %v %v", tap, err) } return err } // Success! if ns := GetNamespace(); ns != nil { // TODO: probably need lock... ns.Taps[tap] = true } resp.Response = tap return nil } else if c.BoolArgs["delete"] { return hostTapDelete(c.StringArgs["id"]) } // Must be the list command hostTapList(resp) return nil }
func cliVLANs(c *minicli.Command, resp *minicli.Response) error { // Look for matching subhandler if len(c.BoolArgs) > 0 { for k, fn := range vlansCLISubHandlers { if c.BoolArgs[k] { log.Debug("vlan handler %v", k) return fn(c, resp) } } } namespace := GetNamespaceName() // No match, must want to just print resp.Header = []string{"namespace", "alias", "vlan"} resp.Tabular = allocatedVLANs.Tabular(namespace) return nil }
// List all active recordings and playbacks func cliVNCList(c *minicli.Command, resp *minicli.Response) error { resp.Header = []string{"name", "type", "time", "filename"} resp.Tabular = [][]string{} vncRecordingLock.RLock() for _, v := range vncKBRecording { resp.Tabular = append(resp.Tabular, []string{ v.VM.Name, "record kb", time.Since(v.start).String(), v.file.Name(), }) } vncRecordingLock.RUnlock() vncRecordingLock.RLock() for _, v := range vncFBRecording { resp.Tabular = append(resp.Tabular, []string{ v.VM.Name, "record fb", time.Since(v.start).String(), v.file.Name(), }) } vncRecordingLock.RUnlock() vncPlayingLock.RLock() for _, v := range vncPlaying { var r string if v.state == Pause { r = "PAUSED" } else { r = v.timeRemaining() + " remaining" } resp.Tabular = append(resp.Tabular, []string{ v.VM.Name, "playback kb", r, v.file.Name(), }) } vncPlayingLock.RUnlock() return nil }
func cliMeshageList(c *minicli.Command, resp *minicli.Response) error { mesh := meshageNode.Mesh() var keys []string for k, _ := range mesh { keys = append(keys, k) } sort.Strings(keys) for _, key := range keys { v := mesh[key] resp.Response += fmt.Sprintf("%s\n", key) sort.Strings(v) for _, x := range v { resp.Response += fmt.Sprintf(" |--%s\n", x) } } return nil }
func cliDnsmasq(c *minicli.Command, resp *minicli.Response) error { if c.StringArgs["id"] == Wildcard { // Must be "kill all" return dnsmasqKillAll() } else if c.StringArgs["id"] != "" { // Must be "kill <id>" id, err := strconv.Atoi(c.StringArgs["id"]) if err != nil { return err } return dnsmasqKill(id) } else if c.StringArgs["listen"] != "" || c.StringArgs["config"] != "" { // Must be "start" // We don't need to differentiate between the two start commands // because dnsmasqStart expects the zero string value when values // are not specified. return dnsmasqStart( c.StringArgs["listen"], c.StringArgs["low"], c.StringArgs["high"], c.StringArgs["config"]) } // Must be "list" resp.Header = []string{"ID", "Listening Address", "Min", "Max", "Path", "PID"} resp.Tabular = [][]string{} for id, c := range dnsmasqServers { pid := dnsmasqPID(id) resp.Tabular = append(resp.Tabular, []string{ strconv.Itoa(id), c.Addr, c.MinRange, c.MaxRange, c.Path, strconv.Itoa(pid)}) } return nil }
func dnsmasqDNSInfo(c *minicli.Command, resp *minicli.Response) { // print info resp.Header = []string{"ID", "IP", "Hostname"} resp.Tabular = [][]string{} if c.StringArgs["ID"] == Wildcard { for id, v := range dnsmasqServers { for ip, host := range v.Hostnames { resp.Tabular = append(resp.Tabular, []string{strconv.Itoa(id), ip, host}) } } } else { id, err := strconv.Atoi(c.StringArgs["ID"]) if err != nil { resp.Error = "Invalid dnsmasq ID" return } if _, ok := dnsmasqServers[id]; ok { for ip, host := range dnsmasqServers[id].Hostnames { resp.Tabular = append(resp.Tabular, []string{strconv.Itoa(id), ip, host}) } } else { resp.Error = "Invalid dnsmasq ID" } } }
func dnsmasqHostInfo(c *minicli.Command, resp *minicli.Response) { // print info about the mapping resp.Header = []string{"ID", "MAC", "IP"} resp.Tabular = [][]string{} if c.StringArgs["ID"] == Wildcard { for id, v := range dnsmasqServers { for mac, ip := range v.DHCPhosts { resp.Tabular = append(resp.Tabular, []string{strconv.Itoa(id), mac, ip}) } } } else { id, err := strconv.Atoi(c.StringArgs["ID"]) if err != nil { resp.Error = "Invalid dnsmasq ID" return } if _, ok := dnsmasqServers[id]; ok { for mac, ip := range dnsmasqServers[id].DHCPhosts { resp.Tabular = append(resp.Tabular, []string{strconv.Itoa(id), mac, ip}) } } else { resp.Error = "Invalid dnsmasq ID" } } }
func cliVmTag(c *minicli.Command, resp *minicli.Response) error { target := c.StringArgs["target"] key := c.StringArgs["key"] if key == "" { // If they didn't specify a key then they probably want all the tags // for a given VM key = Wildcard } value, write := c.StringArgs["value"] if write { if key == Wildcard { return errors.New("cannot assign to wildcard") } vms.SetTag(target, key, value) return nil } if key == Wildcard { resp.Header = []string{"ID", "Tag", "Value"} } else { resp.Header = []string{"ID", "Value"} } for _, tag := range vms.GetTags(target, key) { row := []string{strconv.Itoa(tag.ID)} if key == Wildcard { row = append(row, tag.Key) } row = append(row, tag.Value) resp.Tabular = append(resp.Tabular, row) } return nil }
// hostTapList populates resp with information about all the host taps. func hostTapList(resp *minicli.Response) { resp.Header = []string{"bridge", "tap", "vlan"} resp.Tabular = [][]string{} // no namespace active => add an extra column ns := GetNamespace() if ns == nil { resp.Header = append(resp.Header, "namespace") } // find all the host taps first for _, tap := range bridges.HostTaps() { // skip taps that don't belong to the active namespace if ns != nil && !ns.HasTap(tap.Name) { continue } row := []string{ tap.Bridge, tap.Name, printVLAN(tap.VLAN), } // no namespace active => find namespace tap belongs to so that we can // populate that column if ns == nil { v := "" for _, n := range ListNamespaces() { if ns := GetOrCreateNamespace(n); ns.HasTap(tap.Name) { v = ns.Name break } } row = append(row, v) } resp.Tabular = append(resp.Tabular, row) } }
// cli commands for meshage control func cliMeshageDegree(c *minicli.Command, resp *minicli.Response) error { if c.StringArgs["degree"] != "" { degree, err := strconv.ParseUint(c.StringArgs["degree"], 0, 10) if err != nil { return err } meshageNode.SetDegree(uint(degree)) return nil } resp.Response = fmt.Sprintf("%d", meshageNode.GetDegree()) return nil }
func cliVmQmp(c *minicli.Command, resp *minicli.Response) error { vm, err := vms.FindKvmVM(c.StringArgs["vm"]) if err != nil { return err } out, err := vm.QMPRaw(c.StringArgs["qmp"]) if err != nil { return err } resp.Response = out return nil }
// command func cliCCCommand(c *minicli.Command, resp *minicli.Response) error { resp.Header = []string{ "ID", "prefix", "command", "responses", "background", "send files", "receive files", "filter", } resp.Tabular = [][]string{} var commandIDs []int commands := ccNode.GetCommands() for k, v := range commands { // only show commands for the active namespace if !ccMatchNamespace(v) { continue } commandIDs = append(commandIDs, k) } sort.Ints(commandIDs) for _, i := range commandIDs { v := commands[i] row := []string{ strconv.Itoa(v.ID), ccPrefixMap[i], fmt.Sprintf("%v", v.Command), strconv.Itoa(len(v.CheckedIn)), strconv.FormatBool(v.Background), fmt.Sprintf("%v", v.FilesSend), fmt.Sprintf("%v", v.FilesRecv), filterString(v.Filter), } resp.Tabular = append(resp.Tabular, row) } return nil }
// Info populates resp with info about the VMs running in the active namespace. func (vms VMs) Info(masks []string, resp *minicli.Response) { vmLock.Lock() defer vmLock.Unlock() resp.Header = masks res := VMs{} // for res.Data for _, vm := range vms { if !inNamespace(vm) { continue } // Update dynamic fields before querying info vm.UpdateNetworks() // Copy the VM and use the copy from here on. This ensures that the // Tabular info matches the Data field. vm := vm.Copy() res[vm.GetID()] = vm row := []string{} for _, mask := range masks { if v, err := vm.Info(mask); err != nil { // Field most likely not set for VM type row = append(row, "N/A") } else { row = append(row, v) } } resp.Tabular = append(resp.Tabular, row) } resp.Data = res }