func commandSocketHandle(c net.Conn) { defer c.Close() enc := json.NewEncoder(c) dec := json.NewDecoder(c) var err error for err == nil { var cmd *minicli.Command cmd, err = readLocalCommand(dec) if err != nil { break } if cmd == nil { err = sendLocalResp(enc, nil, false) continue } // HAX: Don't record the read command if hasCommand(cmd, "read") { cmd.SetRecord(false) } // HAX: Work around so that we can add the more boolean. var prev minicli.Responses // Keep sending until we hit the first error, then just consume the // channel to ensure that we release any locks acquired by cmd. for resp := range RunCommands(cmd) { if prev != nil && err == nil { err = sendLocalResp(enc, prev, true) } else if err != nil && len(resp) > 0 { log.Info("dropping resp from %v", resp[0].Host) } prev = resp } if err == nil { err = sendLocalResp(enc, prev, false) } } // finally, log the error, if there was one if err == nil || err == io.EOF { log.Infoln("command client disconnected") } else if err != nil && strings.Contains(err.Error(), "write: broken pipe") { log.Infoln("command client disconnected without waiting for responses") } else if err != nil { log.Errorln(err) } }
func commandSocketHandle(c net.Conn) { var err error enc := json.NewEncoder(c) dec := json.NewDecoder(c) outer: for err == nil { var cmd *minicli.Command cmd, err = readLocalCommand(dec) if err != nil { if err != io.EOF { // Must be incompatible versions of minimega... F*** log.Errorln(err) } break } err = nil var prevResp minicli.Responses if cmd != nil { // HAX: Don't record the read command if hasCommand(cmd, "read") { cmd.Record = false } // HAX: Work around so that we can add the more boolean for resp := range runCommand(cmd) { if prevResp != nil { err = sendLocalResp(enc, prevResp, true) if err != nil { break outer } } prevResp = resp } } if err == nil { err = sendLocalResp(enc, prevResp, false) } } if err != nil { if err == io.EOF { log.Infoln("command client disconnected") } else { log.Errorln(err) } } }
// 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) }
// 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 }
func cliHistoryClear(c *minicli.Command, resp *minicli.Response) error { minicli.ClearHistory() c.Record = false return nil }