func main() { flag.Parse() logSetup() log.Debug("using minimega: %v", *f_minimega) // invoke minimega and get the doc json doc, err := exec.Command(*f_minimega, "-cli").Output() if err != nil { log.Fatalln(err) } log.Debug("got doc: %v", string(doc)) // decode the JSON for our template if err := json.Unmarshal(doc, &handlers); err != nil { log.Fatalln(err) } exclude = strings.Split(*f_exclude, ",") values = strings.Split(*f_values, ",") for { if err := fuzz(); err != nil { log.Fatal("fuzz: %v", err) } if err := cleanup(); err != nil { log.Fatal("cleanup: %v", err) } } }
func main() { flag.Parse() logSetup() // register CLI handlers for i := range cliHandlers { err := minicli.Register(&cliHandlers[i]) if err != nil { log.Fatal("invalid handler, `%v` -- %v", cliHandlers[i].HelpShort, err) } } var err error hostname, err = os.Hostname() if err != nil { log.Fatal("unable to get hostname: %v", hostname) } rond, err = ron.NewServer(*f_port, *f_path) if err != nil { log.Fatal("unable to create server: %v", err) } for { line, err := goreadline.Readline("rond$ ", true) if err != nil { return } command := string(line) log.Debug("got from stdin: `%s`", line) cmd, err := minicli.Compile(command) if err != nil { log.Error("%v", err) continue } // No command was returned, must have been a blank line or a comment // line. Either way, don't try to run a nil command. if cmd == nil { continue } for resp := range minicli.ProcessCommand(cmd) { minipager.DefaultPager.Page(resp.String()) errs := resp.Error() if errs != "" { fmt.Fprintln(os.Stderr, errs) } } } }
func runTests() { mm, err := miniclient.Dial(*f_base) if err != nil { log.Fatal("%v", err) } if *f_preamble != "" { out, err := runCommands(mm, *f_preamble) if err != nil { log.Fatal("%v", err) } log.Info(out) } // TODO: Should we quit minimega and restart it between each test? //quit := mustCompile(t, "quit 2") files, err := ioutil.ReadDir(*f_testDir) if err != nil { log.Fatal("%v", err) } for _, info := range files { if strings.HasSuffix(info.Name(), ".want") || strings.HasSuffix(info.Name(), ".got") { continue } log.Info("Running commands from %s", info.Name()) fpath := path.Join(*f_testDir, info.Name()) got, err := runCommands(mm, fpath) if err != nil { log.Fatal("%v", err) } // Record the output for offline comparison if err := ioutil.WriteFile(fpath+".got", []byte(got), os.FileMode(0644)); err != nil { log.Error("unable to write `%s` -- %v", fpath+".got", err) } want, err := ioutil.ReadFile(fpath + ".want") if err != nil { log.Error("unable to read file `%s` -- %v", fpath+".want", err) continue } if got != string(want) { log.Error("got != want for %s", info.Name()) } //mm.runCommand(quit) } }
func main() { flag.Usage = usage flag.Parse() if *f_version { fmt.Println("miniccc", version.Revision, version.Date) fmt.Println(version.Copyright) os.Exit(0) } logSetup() if *f_tag { if runtime.GOOS == "windows" { log.Fatalln("tag updates are not available on windows miniccc clients") } if err := updateTag(); err != nil { log.Errorln(err) } return } // attempt to set up the base path if err := os.MkdirAll(*f_path, os.FileMode(0777)); err != nil { log.Fatal("mkdir base path: %v", err) } log.Debug("starting ron client with UUID: %v", Client.UUID) if err := dial(); err != nil { log.Fatal("unable to connect: %v", err) } go mux() go periodic() go commandHandler() heartbeat() // handshake is first heartbeat // create a listening domain socket for tag updates if runtime.GOOS != "windows" { go commandSocketStart() } // wait for SIGTERM sig := make(chan os.Signal, 1024) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig }
func cliVmConfigField(c *minicli.Command, field string) *minicli.Response { resp := &minicli.Response{Host: hostname} // 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 { log.Fatal("unknown config field: `%s`", field) } if nArgs == 0 { resp.Response = fns.Print(config) } else { if err := fns.Update(config, c); err != nil { resp.Error = err.Error() } } return resp }
func mustKVMConfig(val interface{}) *KVMConfig { if val, ok := val.(*KVMConfig); ok { return val } log.Fatal("`%#v` is not a KVMConfig", val) return nil }
func main() { flag.Usage = usage flag.Parse() if *f_version { fmt.Println("miniccc", version.Revision, version.Date) fmt.Println(version.Copyright) os.Exit(0) } logSetup() // signal handling sig := make(chan os.Signal, 1024) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) // start a ron client var err error c, err = ron.NewClient(*f_port, *f_parent, *f_serial, *f_path) if err != nil { log.Fatal("creating ron node: %v", err) } log.Debug("starting ron client with UUID: %v", c.UUID) go client() <-sig // terminate }
// Process a prepopulated Command func ProcessCommand(c *Command) <-chan Responses { if !c.noOp && c.Call == nil { log.Fatal("command %v has no callback!", c) } respChan := make(chan Responses) go func() { if !c.noOp { c.Call(c, respChan) } // Append the command to the history if c.Record { history = append(history, c.Original) if len(history) > HistoryLen && HistoryLen > 0 { if firstHistoryTruncate { log.Warn("history length exceeds limit, truncating to %v entries", HistoryLen) firstHistoryTruncate = false } history = history[len(history)-HistoryLen:] } } close(respChan) }() return respChan }
func mustContainerConfig(val interface{}) *ContainerConfig { if val, ok := val.(*ContainerConfig); ok { return val } log.Fatal("`%#v` is not a ContainerConfig", val) return nil }
func unmangleUUID(uuid string) string { // string must be in the form: // XXXXXXXX-XXXX-XXXX-YYYY-YYYYYYYYYYYY // the X characters are reversed at 2 byte intervals (big/little endian for a uuid?) var ret string re := regexp.MustCompile("[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}") u := re.FindString(strings.ToLower(uuid)) if uuid == "" { log.Fatal("uuid failed to match uuid format: %v", uuid) } log.Debug("found uuid: %v", u) if getOSVer() != "Windows XP" { return u } ret += u[6:8] ret += u[4:6] ret += u[2:4] ret += u[:2] ret += "-" ret += u[11:13] ret += u[9:11] ret += "-" ret += u[16:18] ret += u[14:16] ret += u[18:] log.Debug("mangled/unmangled uuid: %v %v", u, ret) return ret }
// Wrapper for minicli.ProcessCommand for commands that use meshage. // Specifically, for `mesh send all ...`, runs the subcommand locally and // across meshage, combining the results from the two channels into a single // channel. This is useful if you want to get the output of a command from all // nodes in the cluster without having to run a command locally and over // meshage. func runCommandGlobally(cmd *minicli.Command) chan minicli.Responses { // Keep the original CLI input original := cmd.Original record := cmd.Record cmd, err := minicli.Compilef("mesh send %s .record %t %s", Wildcard, record, original) if err != nil { log.Fatal("cannot run `%v` globally -- %v", original, err) } cmd.Record = record cmdLock.Lock() var wg sync.WaitGroup out := make(chan minicli.Responses) cmd, err = cliPreprocessor(cmd) if err != nil { log.Errorln(err) out <- minicli.Responses{ &minicli.Response{ Host: hostname, Error: err.Error(), }, } close(out) return out } // Run the command (should be `mesh send all ...` and the subcommand which // should run locally). ins := []chan minicli.Responses{ minicli.ProcessCommand(cmd), minicli.ProcessCommand(cmd.Subcommand), } // De-mux ins into out for _, in := range ins { wg.Add(1) go func(in chan minicli.Responses) { defer wg.Done() for v := range in { out <- v } }(in) } // Wait until everything has been read before closing the chan and // releasing the lock. go func() { defer cmdLock.Unlock() defer close(out) wg.Wait() }() return out }
// registerHandlers registers all the provided handlers with minicli, panicking // if any of the handlers fail to register. func registerHandlers(name string, handlers []minicli.Handler) { for i := range handlers { err := minicli.Register(&handlers[i]) if err != nil { log.Fatal("invalid handler, %s:%d -- %v", name, i, err) } } }
// MustCompile compiles the string, calling log.Fatal if the string is not a // valid command. Should be used when providing a known command rather than // processing user input. func MustCompile(input string) *Command { c, err := Compile(input) if err != nil { log.Fatal("unable to compile `%s` -- %v", input, err) } return c }
// register a transaction ID, adding a return channel to the mux func (t *Tunnel) registerTID(TID int32) chan *tunnelMessage { if _, ok := t.tids[TID]; ok { log.Fatal("tid %v already exists!", TID) } c := make(chan *tunnelMessage, 1024) t.tids[TID] = c return c }
// Run a command through a JSON pipe, hand back channel for responses. func (mm *Conn) Run(cmd *minicli.Command) chan *Response { if cmd == nil { // Language spec: "Receiving from a nil channel blocks forever." // Instead, make and immediately close the channel so that range // doesn't block and receives no values. out := make(chan *Response) close(out) return out } err := mm.enc.Encode(*cmd) if err != nil { log.Fatal("local command gob encode: %v", err) } log.Debugln("encoded command:", cmd) respChan := make(chan *Response) go func() { defer close(respChan) for { var r Response err = mm.dec.Decode(&r) if err != nil { if err == io.EOF { log.Fatal("server disconnected") } log.Fatal("local command gob decode: %v", err) } respChan <- &r if !r.More { log.Debugln("got last message") break } else { log.Debugln("expecting more data") } } }() return respChan }
// mustFindMask returns the index of the specified mask in vmMasks. If the // specified mask is not found, log.Fatal is called. func mustFindMask(mask string) int { for i, v := range vmMasks { if v == mask { return i } } log.Fatal("missing `%s` in vmMasks", mask) return -1 }
func getUUID() string { out, err := exec.Command("wmic", "path", "win32_computersystemproduct", "get", "uuid").CombinedOutput() if err != nil { log.Fatal("wmic run: %v", err) } uuid := unmangleUUID(strings.TrimSpace(string(out))) log.Debug("got UUID: %v", uuid) return uuid }
func getUUID() string { d, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/product_uuid") if err != nil { log.Fatal("unable to get UUID: %v", err) } uuid := strings.ToLower(strings.TrimSpace(string(d))) log.Debug("got UUID: %v", uuid) return uuid }
func main() { // flags flag.Parse() logSetup() if *f_u != "" { log.Debug("updating with file: %v", *f_u) err := update(filepath.Join(*f_path, "minirouter"), *f_u) if err != nil { log.Errorln(err) } return } // check for a running instance of minirouter _, err := os.Stat(filepath.Join(*f_path, "minirouter")) if err == nil { if !*f_force { log.Fatalln("minirouter appears to already be running, override with -force") } log.Warn("minirouter may already be running, proceed with caution") err = os.Remove(filepath.Join(*f_path, "minirouter")) if err != nil { log.Fatalln(err) } } log.Debug("using path: %v", *f_path) // attempt to set up the base path err = os.MkdirAll(*f_path, os.FileMode(0770)) if err != nil { log.Fatal("mkdir base path: %v", err) } // start the domain socket service go commandSocketStart() // signal handling sig := make(chan os.Signal, 1024) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig // cleanup err = os.Remove(filepath.Join(*f_path, "minirouter")) if err != nil { log.Fatalln(err) } }
func dnsServer() { log.Debugln("dnsServer") rand.Seed(time.Now().UnixNano()) dns.HandleFunc(".", handleDnsRequest) server := &dns.Server{Addr: addr, Net: proto} err := server.ListenAndServe() if err != nil { log.Fatal(err.Error()) } }
// broadcastListener listens for broadcast connection solicitations and connects to // soliciting nodes. func (n *Node) broadcastListener() { listenAddr := net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: n.port, } ln, err := net.ListenUDP("udp4", &listenAddr) if err != nil { log.Fatal("broadcastListener: %v", err) } for { d := make([]byte, 1024) read, _, err := ln.ReadFromUDP(d) if err != nil { log.Error("broadcastListener ReadFromUDP: %v", err) continue } data := strings.Split(string(d[:read]), ":") if len(data) != 3 { log.Warn("got malformed udp data: %v", data) continue } if data[0] != "meshage" { log.Warn("got malformed udp data: %v", data) continue } namespace := data[1] host := data[2] if namespace != n.namespace { log.Debug("got solicitation from namespace %v, dropping", namespace) continue } if host == n.name { log.Debugln("got solicitation from myself, dropping") continue } log.Debug("got solicitation from %v", host) // to avoid spamming the node with connections, only 1/8 of the // nodes should try to connect. If there are < 16 nodes, then // always try. if len(n.clients) > SOLICIT_LIMIT { s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) n := r.Intn(SOLICIT_RATIO) if n != 0 { log.Debugln("randomly skipping this solicitation") continue } } go n.dial(host, true) } }
func (c *chans) add(ID int) chan *tunnelMessage { c.Lock() defer c.Unlock() if _, ok := c.chans[ID]; ok { log.Fatal("ID %v already exists!", ID) } ch := make(chan *tunnelMessage, 1024) c.chans[ID] = ch return ch }
// runCommandGlobally runs the given command across all nodes on meshage, // including the local node and combines the results into a single channel. func runCommandGlobally(cmd *minicli.Command) <-chan minicli.Responses { // Keep the original CLI input original := cmd.Original record := cmd.Record cmd, err := minicli.Compilef("mesh send %s %s", Wildcard, original) if err != nil { log.Fatal("cannot run `%v` globally -- %v", original, err) } cmd.SetRecord(record) return runCommands(cmd, cmd.Subcommand) }
// create the default bridge struct and create a goroutine to generate // tap names for this host. func init() { bridges = make(map[string]*Bridge) tapNameChan = make(chan string) go func() { for tapCount := 0; ; tapCount++ { tapName := fmt.Sprintf("mega_tap%v", tapCount) fpath := filepath.Join("/sys/class/net", tapName) if _, err := os.Stat(fpath); os.IsNotExist(err) { tapNameChan <- tapName } else if err != nil { log.Fatal("unable to stat file -- %v %v", fpath, err) } log.Debug("tapCount: %v", tapCount) } }() }
func affinityUnselectCPU(vm *KvmVM) { // find and remove vm from its cpuset for k, v := range affinityCPUSets { for i, j := range v { if j.GetID() == vm.GetID() { if len(v) == 1 { affinityCPUSets[k] = []*KvmVM{} } else if i == 0 { affinityCPUSets[k] = v[1:] } else if i == len(v)-1 { affinityCPUSets[k] = v[:len(v)-1] } else { affinityCPUSets[k] = append(affinityCPUSets[k][:i], affinityCPUSets[k][i+1:]...) } return } } } log.Fatal("could not find vm %v in CPU set", vm.GetID()) }
func main() { flag.Parse() if !strings.HasSuffix(*f_minimega, "/") { *f_minimega += "/" } logSetup() err := initTemplates(*f_base) if err != nil { log.Fatal("failed to parse templates: %v", err) } if *f_exec { present.PlayEnabled = true http.Handle("/socket", NewSocketHandler()) } log.Fatalln(http.ListenAndServe(*f_server, nil)) }
// Wrapper for minicli.ProcessCommand for commands that use meshage. // Specifically, for `mesh send all ...`, runs the subcommand locally and // across meshage, combining the results from the two channels into a single // channel. This is useful if you want to get the output of a command from all // nodes in the cluster without having to run a command locally and over // meshage. func runCommandGlobally(cmd *minicli.Command, record bool) chan minicli.Responses { cmdStr := fmt.Sprintf("mesh send %s %s", Wildcard, cmd.Original) cmd, err := minicli.CompileCommand(cmdStr) if err != nil { log.Fatal("cannot run `%v` globally -- %v", cmd.Original, err) } cmdLock.Lock() defer cmdLock.Unlock() var wg sync.WaitGroup out := make(chan minicli.Responses) // Run the command (should be `mesh send all ...` and the subcommand which // should run locally). ins := []chan minicli.Responses{ minicli.ProcessCommand(cmd, record), minicli.ProcessCommand(cmd.Subcommand, record), } // De-mux ins into out for _, in := range ins { wg.Add(1) go func(in chan minicli.Responses) { defer wg.Done() for v := range in { out <- v } }(in) } // Wait until everything has been read before closing out go func() { wg.Wait() close(out) }() return out }
// Process a prepopulated Command func ProcessCommand(c *Command) chan Responses { if !c.noOp && c.Call == nil { log.Fatal("command %v has no callback!", c) } respChan := make(chan Responses) go func() { if !c.noOp { c.Call(c, respChan) } // Append the command to the history if c.Record { history = append(history, c.Original) } close(respChan) }() return respChan }
// NewBridges creates a new Bridges using d as the default bridge name and f as // the format string for the tap names (e.g. "mega_tap%v"). func NewBridges(d, f string) *Bridges { nameChan := make(chan string) // Start a goroutine to generate tap names for us go func() { defer close(nameChan) for tapCount := 0; ; tapCount++ { tapName := fmt.Sprintf(f, tapCount) fpath := filepath.Join("/sys/class/net", tapName) if _, err := os.Stat(fpath); os.IsNotExist(err) { nameChan <- tapName } else if err != nil { log.Fatal("unable to stat file -- %v %v", fpath, err) } log.Debug("tapCount: %v", tapCount) } }() b := &Bridges{ Default: d, nameChan: nameChan, bridges: map[string]*Bridge{}, } // Start a goroutine to collect bandwidth stats every 5 seconds go func() { for { time.Sleep(5 * time.Second) b.updateBandwidthStats() } }() return b }
func dial() error { Client.Lock() defer Client.Unlock() var err error for i := Retries; i > 0; i-- { if *f_serial == "" { log.Debug("dial: %v:%v:%v", *f_family, *f_parent, *f_port) var addr string switch *f_family { case "tcp": addr = fmt.Sprintf("%v:%v", *f_parent, *f_port) case "unix": addr = *f_parent default: log.Fatal("invalid ron dial network family: %v", *f_family) } Client.conn, err = net.Dial(*f_family, addr) } else { Client.conn, err = dialSerial(*f_serial) } if err == nil { Client.enc = gob.NewEncoder(Client.conn) Client.dec = gob.NewDecoder(Client.conn) return nil } log.Error("%v, retries = %v", err, i) time.Sleep(15 * time.Second) } return err }