예제 #1
0
func meshageHandler() {
	for {
		m := <-meshageCommandChan
		go func() {
			mCmd := m.Body.(meshageCommand)

			cmd, err := minicli.CompileCommand(mCmd.Original)
			if err != nil {
				log.Error("invalid command from mesh: `%s`", mCmd.Original)
				return
			}

			resps := []minicli.Responses{}
			for resp := range runCommand(cmd, true) {
				resps = append(resps, resp)
			}

			if len(resps) > 1 || len(resps[0]) > 1 {
				// This should never happen because the only commands that
				// return multiple responses are `read` and `mesh send` which
				// aren't supposed to be sent across meshage.
				log.Error("unsure how to process multiple responses!!")
			}

			resp := meshageResponse{Response: *resps[0][0], TID: mCmd.TID}
			recipient := []string{m.Source}

			_, err = meshageNode.Set(recipient, resp)
			if err != nil {
				log.Errorln(err)
			}
		}()
	}
}
예제 #2
0
func cliRead(c *minicli.Command, respChan chan minicli.Responses) {
	resp := &minicli.Response{Host: hostname}

	file, err := os.Open(c.StringArgs["file"])
	if err != nil {
		resp.Error = err.Error()
		respChan <- minicli.Responses{resp}
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		var cmd *minicli.Command

		command := scanner.Text()
		log.Debug("read command: %v", command) // commands don't have their newlines removed

		cmd, err = minicli.CompileCommand(command)
		if err != nil {
			break
		}

		// 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
		}

		// HAX: Make sure we don't have a recursive read command
		if hasCommand(cmd, "read") {
			err = errors.New("cannot run nested `read` commands")
			break
		}

		for resp := range minicli.ProcessCommand(cmd, true) {
			respChan <- resp

			// Stop processing at the first error if there is one response.
			// TODO: What should we do if the command was mesh send and there
			// is a mixture of success and failure?
			if len(resp) == 1 && resp[0].Error != "" {
				break
			}
		}
	}

	if err != nil {
		resp.Error = err.Error()
		respChan <- minicli.Responses{resp}
	}

	if err := scanner.Err(); err != nil {
		resp.Error = err.Error()
		respChan <- minicli.Responses{resp}
	}
}
예제 #3
0
func readLocalCommand(dec *json.Decoder) (*minicli.Command, error) {
	var cmd minicli.Command
	err := dec.Decode(&cmd)
	if err != nil {
		return nil, err
	}

	log.Debug("got command over socket: %v", cmd)

	// HAX: Reprocess the original command since the Call target cannot be
	// serialized... is there a cleaner way to do this?
	return minicli.CompileCommand(cmd.Original)
}
예제 #4
0
func TestParseInject(t *testing.T) {
	for _, cmdStr := range validInjectCommands {
		cmd, err := minicli.CompileCommand(cmdStr)
		if err != nil {
			t.Fatalf("invalid command: %s", cmdStr)
		}

		inject := parseInject(cmd)
		if inject.err != nil {
			t.Errorf("unable to parse `%s`: %v", cmdStr, inject.err)
		}
	}
}
예제 #5
0
파일: cli.go 프로젝트: ITLivLab/minimega
// 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
}
예제 #6
0
파일: cli.go 프로젝트: ITLivLab/minimega
// local command line interface, wrapping readline
func cliLocal() {
	prompt := "minimega$ "

	for {
		line, err := goreadline.Rlwrap(prompt, true)
		if err != nil {
			break // EOF
		}
		command := string(line)
		log.Debug("got from stdin:", command)

		cmd, err := minicli.CompileCommand(command)
		if err != nil {
			log.Error("%v", err)
			//fmt.Printf("closest match: TODO\n")
			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
		}

		// HAX: Don't record the read command
		record := !hasCommand(cmd, "read")

		for resp := range runCommand(cmd, record) {
			// print the responses
			pageOutput(resp.String())

			errs := resp.Error()
			if errs != "" {
				fmt.Fprintln(os.Stderr, errs)
			}
		}
	}
}
예제 #7
0
파일: web.go 프로젝트: ITLivLab/minimega
func webHosts(w http.ResponseWriter, r *http.Request) {
	table := htmlTable{
		Header:  []string{},
		Tabular: [][]interface{}{},
		ID:      "example",
		Class:   "hover",
	}

	cmd, err := minicli.CompileCommand("host")
	if err != nil {
		// Should never happen
		log.Fatalln(err)
	}

	for resps := range runCommandGlobally(cmd, false) {
		for _, resp := range resps {
			if resp.Error != "" {
				log.Errorln(resp.Error)
				continue
			}

			if len(table.Header) == 0 && len(resp.Header) > 0 {
				table.Header = append(table.Header, resp.Header...)
			}

			for _, row := range resp.Tabular {
				res := []interface{}{}
				for _, v := range row {
					res = append(res, v)
				}
				table.Tabular = append(table.Tabular, res)
			}
		}
	}

	webRenderTemplate(w, "hosts.html", table)
}
예제 #8
0
파일: cli.go 프로젝트: ITLivLab/minimega
func localCommand() {
	a := flag.Args()

	log.Debugln("got args:", a)

	command := strings.Join(a, " ")

	// TODO: Need to escape?
	cmd, err := minicli.CompileCommand(command)
	if err != nil {
		log.Fatal(err.Error())
	}

	if cmd == nil {
		log.Debugln("cmd is nil")
		return
	}

	log.Infoln("got command:", cmd)

	mm, err := DialMinimega()
	if err != nil {
		log.Fatalln(err)
	}

	for resp := range mm.runCommand(cmd) {
		if resp.Rendered != "" {
			fmt.Println(resp.Rendered)
		}

		errs := resp.Resp.Error()
		if errs != "" {
			fmt.Fprintln(os.Stderr, errs)
		}
	}
}
예제 #9
0
파일: cli.go 프로젝트: ITLivLab/minimega
func cliAttach() {
	// try to connect to the local minimega
	mm, err := DialMinimega()
	if err != nil {
		log.Fatalln(err)
	}

	// set up signal handling
	sig := make(chan os.Signal, 1024)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-sig
		if *f_panic {
			panic("teardown")
		}
		log.Debug("caught signal, disconnecting")
		goreadline.Rlcleanup()
		os.Exit(0)
	}()

	// start our own rlwrap
	fmt.Println("CAUTION: calling 'quit' will cause the minimega daemon to exit")
	fmt.Println("use 'disconnect' or ^d to exit just the minimega command line")
	fmt.Println()
	defer goreadline.Rlcleanup()

	var exitNext bool
	for {
		prompt := fmt.Sprintf("minimega:%v$ ", mm.url)
		line, err := goreadline.Rlwrap(prompt, true)
		if err != nil {
			return
		}
		command := string(line)
		log.Debug("got from stdin: `%s`", line)

		// HAX: Shortcut some commands without using minicli
		if command == "disconnect" {
			log.Debugln("disconnecting")
			return
		} else if command == "quit" {
			if !exitNext {
				fmt.Println("CAUTION: calling 'quit' will cause the minimega daemon to exit")
				fmt.Println("If you really want to stop the minimega daemon, enter 'quit' again")
				exitNext = true
				continue
			}
		}

		exitNext = false

		cmd, err := minicli.CompileCommand(command)
		if err != nil {
			log.Error("%v", err)
			//fmt.Println("closest match: TODO")
			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 mm.runCommand(cmd) {
			pageOutput(resp.Rendered)

			errs := resp.Resp.Error()
			if errs != "" {
				fmt.Fprintln(os.Stderr, errs)
			}
		}

		if command == "quit" {
			return
		}
	}
}