Ejemplo n.º 1
0
func meshageHandler() {
	for {
		m := <-meshageCommandChan
		go func() {
			mCmd := m.Body.(meshageCommand)

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

			resps := []minicli.Responses{}
			for resp := range runCommand(cmd) {
				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)
			}
		}()
	}
}
Ejemplo n.º 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.Compile(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) {
			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}
	}
}
Ejemplo n.º 3
0
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)
			}
		}
	}
}
Ejemplo n.º 4
0
func readLocalCommand(dec *json.Decoder) (*minicli.Command, error) {
	var cmd minicli.Command

	if err := dec.Decode(&cmd); 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.Compile(cmd.Original)
}
Ejemplo n.º 5
0
func TestParseInject(t *testing.T) {
	for _, cmdStr := range validInjectCommands {
		cmd, err := minicli.Compile(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)
		}
	}
}
Ejemplo n.º 6
0
func meshageHandler() {
	for {
		m := <-meshageCommandChan
		go func() {
			mCmd := m.Body.(meshageCommand)

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

			// Copy the Record flag at each level of nested command
			for c, c2 := cmd, &mCmd.Command; c != nil && c2 != nil; {
				// could all be the post statement...
				c.Record = c2.Record
				c.Source = c2.Source
				c, c2 = c.Subcommand, c2.Subcommand
			}

			resps := []minicli.Responses{}
			for resp := range RunCommands(cmd) {
				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)
			}
		}()
	}
}
Ejemplo n.º 7
0
// local command line interface, wrapping readline
func cliLocal() {
	goreadline.FilenameCompleter = iomCompleter

	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.Compile(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
		if hasCommand(cmd, "read") {
			cmd.Record = false
		}

		for resp := range runCommand(cmd) {
			// print the responses
			miniclient.Pager(resp.String())

			errs := resp.Error()
			if errs != "" {
				fmt.Fprintln(os.Stderr, errs)
			}
		}
	}
}
Ejemplo n.º 8
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()

	// HACK: We *don't* want long-running read commands to cause all other
	// commands to block so we *unlock* the command lock here and *lock* it
	// again for each command that we read (well, `runCommand` handles the
	// locking for us).
	cmdLock.Unlock()
	defer cmdLock.Lock()

	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.Compile(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 runCommand(cmd) {
			respChan <- resp

			// Stop processing if any of the responses have an error.
			for _, r := range resp {
				if r.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}
	}
}
Ejemplo n.º 9
0
func cliRead(c *minicli.Command, respChan chan<- minicli.Responses) {
	resp := &minicli.Response{Host: hostname}

	check := c.BoolArgs["check"]

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

	// HACK: We *don't* want long-running read commands to cause all other
	// commands to block so we *unlock* the command lock here and *lock* it
	// again for each command that we read (well, `RunCommands` handles the
	// locking for us).
	cmdLock.Unlock()
	defer cmdLock.Lock()

	scanner := bufio.NewScanner(file)

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

		command := scanner.Text()
		log.Debug("read command: %v", command)

		cmd, err = minicli.Compile(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
		}

		// If we're checking the syntax, don't actually execute the command
		if check {
			continue
		}

		forward(RunCommands(cmd), respChan)
	}

	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}
	}
}
Ejemplo n.º 10
0
// local command line interface, wrapping readline
func cliLocal() {
	goreadline.FilenameCompleter = iomCompleter

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt)
	go func() {
		for range sig {
			goreadline.Signal()
		}
	}()
	defer signal.Stop(sig)

	for {
		namespace := GetNamespaceName()

		prompt := "minimega$ "
		if namespace != "" {
			prompt = fmt.Sprintf("minimega[%v]$ ", namespace)
		}

		line, err := goreadline.Readline(prompt, true)
		if err != nil {
			return
		}
		command := string(line)
		log.Debug("got from stdin: `%v`", command)

		cmd, err := minicli.Compile(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
		if hasCommand(cmd, "read") {
			cmd.SetRecord(false)
		}

		// The namespace changed between when we prompted the user (and could
		// still change before we actually run the command).
		if namespace != GetNamespaceName() {
			// TODO: should we abort the command?
			log.Warn("namespace changed between prompt and execution")
		}

		for resp := range RunCommands(cmd) {
			// print the responses
			minipager.DefaultPager.Page(resp.String())

			errs := resp.Error()
			if errs != "" {
				fmt.Fprintln(os.Stderr, errs)
			}
		}
	}
}
Ejemplo n.º 11
0
// Attach creates a CLI interface to the dialed minimega instance
func (mm *Conn) Attach() {
	// set up signal handling
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		for s := range sig {
			if s == os.Interrupt {
				goreadline.Signal()
			} else {
				log.Debug("caught term signal, disconnecting")
				goreadline.Rlcleanup()
				os.Exit(0)
			}
		}
	}()
	defer signal.Stop(sig)

	// 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.Readline(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.Compile(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
		}

		mm.RunAndPrint(cmd, true)

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